* [PATCH 02/19] mmc: mmci: merge qcom dml feature into mmci dma
From: Ludovic Barre @ 2018-06-12 13:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1528809280-31116-1-git-send-email-ludovic.Barre@st.com>
From: Ludovic Barre <ludovic.barre@st.com>
This patch integrates qcom dml feature into mmci_dma file.
Qualcomm Data Mover lite/local is already a variant of mmci dmaengine.
Signed-off-by: Ludovic Barre <ludovic.barre@st.com>
---
drivers/mmc/host/Makefile | 1 -
drivers/mmc/host/mmci.c | 1 -
drivers/mmc/host/mmci.h | 35 ++++++++
drivers/mmc/host/mmci_dma.c | 135 ++++++++++++++++++++++++++++-
drivers/mmc/host/mmci_qcom_dml.c | 177 ---------------------------------------
drivers/mmc/host/mmci_qcom_dml.h | 31 -------
6 files changed, 169 insertions(+), 211 deletions(-)
delete mode 100644 drivers/mmc/host/mmci_qcom_dml.c
delete mode 100644 drivers/mmc/host/mmci_qcom_dml.h
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index daecaa98..608a020 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -5,7 +5,6 @@
obj-$(CONFIG_MMC_ARMMMCI) += armmmci.o
armmmci-y := mmci.o mmci_dma.o
-armmmci-$(CONFIG_MMC_QCOM_DML) += mmci_qcom_dml.o
obj-$(CONFIG_MMC_PXA) += pxamci.o
obj-$(CONFIG_MMC_MXC) += mxcmmc.o
obj-$(CONFIG_MMC_MXS) += mxs-mmc.o
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 8868be0..7a15afd 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -43,7 +43,6 @@
#include "mmci.h"
#include "mmci_dma.h"
-#include "mmci_qcom_dml.h"
#define DRIVER_NAME "mmci-pl18x"
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index a73bb98..f7cba35 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -194,6 +194,41 @@
#define MMCI_PINCTRL_STATE_OPENDRAIN "opendrain"
+/* QCOM DML Registers */
+#define DML_CONFIG 0x00
+#define PRODUCER_CRCI_MSK GENMASK(1, 0)
+#define PRODUCER_CRCI_DISABLE 0
+#define PRODUCER_CRCI_X_SEL BIT(0)
+#define PRODUCER_CRCI_Y_SEL BIT(1)
+#define CONSUMER_CRCI_MSK GENMASK(3, 2)
+#define CONSUMER_CRCI_DISABLE 0
+#define CONSUMER_CRCI_X_SEL BIT(2)
+#define CONSUMER_CRCI_Y_SEL BIT(3)
+#define PRODUCER_TRANS_END_EN BIT(4)
+#define BYPASS BIT(16)
+#define DIRECT_MODE BIT(17)
+#define INFINITE_CONS_TRANS BIT(18)
+
+#define DML_SW_RESET 0x08
+#define DML_PRODUCER_START 0x0c
+#define DML_CONSUMER_START 0x10
+#define DML_PRODUCER_PIPE_LOGICAL_SIZE 0x14
+#define DML_CONSUMER_PIPE_LOGICAL_SIZE 0x18
+#define DML_PIPE_ID 0x1c
+#define PRODUCER_PIPE_ID_SHFT 0
+#define PRODUCER_PIPE_ID_MSK GENMASK(4, 0)
+#define CONSUMER_PIPE_ID_SHFT 16
+#define CONSUMER_PIPE_ID_MSK GENMASK(20, 16)
+
+#define DML_PRODUCER_BAM_BLOCK_SIZE 0x24
+#define DML_PRODUCER_BAM_TRANS_SIZE 0x28
+
+/* other definitions */
+#define PRODUCER_PIPE_LOGICAL_SIZE 4096
+#define CONSUMER_PIPE_LOGICAL_SIZE 4096
+
+#define DML_OFFSET 0x800
+
struct clk;
struct dma_chan;
diff --git a/drivers/mmc/host/mmci_dma.c b/drivers/mmc/host/mmci_dma.c
index 98a542d..dd7dae5 100644
--- a/drivers/mmc/host/mmci_dma.c
+++ b/drivers/mmc/host/mmci_dma.c
@@ -8,11 +8,11 @@
#include <linux/dmaengine.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
+#include <linux/of.h>
#include <linux/scatterlist.h>
#include "mmci.h"
#include "mmci_dma.h"
-#include "mmci_qcom_dml.h"
int mmci_dma_setup(struct mmci_host *host)
{
@@ -101,6 +101,139 @@ struct dmaengine_priv {
#define dma_inprogress(dmae) ((dmae)->dma_in_progress)
+#ifdef CONFIG_MMC_QCOM_DML
+void dml_start_xfer(struct mmci_host *host, struct mmc_data *data)
+{
+ u32 config;
+ void __iomem *base = host->base + DML_OFFSET;
+
+ if (data->flags & MMC_DATA_READ) {
+ /* Read operation: configure DML for producer operation */
+ /* Set producer CRCI-x and disable consumer CRCI */
+ config = readl_relaxed(base + DML_CONFIG);
+ config = (config & ~PRODUCER_CRCI_MSK) | PRODUCER_CRCI_X_SEL;
+ config = (config & ~CONSUMER_CRCI_MSK) | CONSUMER_CRCI_DISABLE;
+ writel_relaxed(config, base + DML_CONFIG);
+
+ /* Set the Producer BAM block size */
+ writel_relaxed(data->blksz, base + DML_PRODUCER_BAM_BLOCK_SIZE);
+
+ /* Set Producer BAM Transaction size */
+ writel_relaxed(data->blocks * data->blksz,
+ base + DML_PRODUCER_BAM_TRANS_SIZE);
+ /* Set Producer Transaction End bit */
+ config = readl_relaxed(base + DML_CONFIG);
+ config |= PRODUCER_TRANS_END_EN;
+ writel_relaxed(config, base + DML_CONFIG);
+ /* Trigger producer */
+ writel_relaxed(1, base + DML_PRODUCER_START);
+ } else {
+ /* Write operation: configure DML for consumer operation */
+ /* Set consumer CRCI-x and disable producer CRCI*/
+ config = readl_relaxed(base + DML_CONFIG);
+ config = (config & ~CONSUMER_CRCI_MSK) | CONSUMER_CRCI_X_SEL;
+ config = (config & ~PRODUCER_CRCI_MSK) | PRODUCER_CRCI_DISABLE;
+ writel_relaxed(config, base + DML_CONFIG);
+ /* Clear Producer Transaction End bit */
+ config = readl_relaxed(base + DML_CONFIG);
+ config &= ~PRODUCER_TRANS_END_EN;
+ writel_relaxed(config, base + DML_CONFIG);
+ /* Trigger consumer */
+ writel_relaxed(1, base + DML_CONSUMER_START);
+ }
+
+ /* make sure the dml is configured before dma is triggered */
+ wmb();
+}
+
+static int of_get_dml_pipe_index(struct device_node *np, const char *name)
+{
+ int index;
+ struct of_phandle_args dma_spec;
+
+ index = of_property_match_string(np, "dma-names", name);
+
+ if (index < 0)
+ return -ENODEV;
+
+ if (of_parse_phandle_with_args(np, "dmas", "#dma-cells", index,
+ &dma_spec))
+ return -ENODEV;
+
+ if (dma_spec.args_count)
+ return dma_spec.args[0];
+
+ return -ENODEV;
+}
+
+/* Initialize the dml hardware connected to SD Card controller */
+int dml_hw_init(struct mmci_host *host, struct device_node *np)
+{
+ u32 config;
+ void __iomem *base;
+ int consumer_id, producer_id;
+
+ consumer_id = of_get_dml_pipe_index(np, "tx");
+ producer_id = of_get_dml_pipe_index(np, "rx");
+
+ if (producer_id < 0 || consumer_id < 0)
+ return -ENODEV;
+
+ base = host->base + DML_OFFSET;
+
+ /* Reset the DML block */
+ writel_relaxed(1, base + DML_SW_RESET);
+
+ /* Disable the producer and consumer CRCI */
+ config = (PRODUCER_CRCI_DISABLE | CONSUMER_CRCI_DISABLE);
+ /*
+ * Disable the bypass mode. Bypass mode will only be used
+ * if data transfer is to happen in PIO mode and don't
+ * want the BAM interface to connect with SDCC-DML.
+ */
+ config &= ~BYPASS;
+ /*
+ * Disable direct mode as we don't DML to MASTER the AHB bus.
+ * BAM connected with DML should MASTER the AHB bus.
+ */
+ config &= ~DIRECT_MODE;
+ /*
+ * Disable infinite mode transfer as we won't be doing any
+ * infinite size data transfers. All data transfer will be
+ * of finite data size.
+ */
+ config &= ~INFINITE_CONS_TRANS;
+ writel_relaxed(config, base + DML_CONFIG);
+
+ /*
+ * Initialize the logical BAM pipe size for producer
+ * and consumer.
+ */
+ writel_relaxed(PRODUCER_PIPE_LOGICAL_SIZE,
+ base + DML_PRODUCER_PIPE_LOGICAL_SIZE);
+ writel_relaxed(CONSUMER_PIPE_LOGICAL_SIZE,
+ base + DML_CONSUMER_PIPE_LOGICAL_SIZE);
+
+ /* Initialize Producer/consumer pipe id */
+ writel_relaxed(producer_id | (consumer_id << CONSUMER_PIPE_ID_SHFT),
+ base + DML_PIPE_ID);
+
+ /* Make sure dml initialization is finished */
+ mb();
+
+ return 0;
+}
+#else
+static inline int dml_hw_init(struct mmci_host *host, struct device_node *np)
+{
+ return -EINVAL;
+}
+
+static inline void dml_start_xfer(struct mmci_host *host, struct mmc_data *data)
+{
+}
+#endif /* CONFIG_MMC_QCOM_DML */
+
static int dmaengine_setup(struct mmci_host *host)
{
const char *rxname, *txname;
diff --git a/drivers/mmc/host/mmci_qcom_dml.c b/drivers/mmc/host/mmci_qcom_dml.c
deleted file mode 100644
index 00750c9..0000000
--- a/drivers/mmc/host/mmci_qcom_dml.c
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- *
- * Copyright (c) 2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-#include <linux/of.h>
-#include <linux/of_dma.h>
-#include <linux/bitops.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/card.h>
-#include "mmci.h"
-
-/* Registers */
-#define DML_CONFIG 0x00
-#define PRODUCER_CRCI_MSK GENMASK(1, 0)
-#define PRODUCER_CRCI_DISABLE 0
-#define PRODUCER_CRCI_X_SEL BIT(0)
-#define PRODUCER_CRCI_Y_SEL BIT(1)
-#define CONSUMER_CRCI_MSK GENMASK(3, 2)
-#define CONSUMER_CRCI_DISABLE 0
-#define CONSUMER_CRCI_X_SEL BIT(2)
-#define CONSUMER_CRCI_Y_SEL BIT(3)
-#define PRODUCER_TRANS_END_EN BIT(4)
-#define BYPASS BIT(16)
-#define DIRECT_MODE BIT(17)
-#define INFINITE_CONS_TRANS BIT(18)
-
-#define DML_SW_RESET 0x08
-#define DML_PRODUCER_START 0x0c
-#define DML_CONSUMER_START 0x10
-#define DML_PRODUCER_PIPE_LOGICAL_SIZE 0x14
-#define DML_CONSUMER_PIPE_LOGICAL_SIZE 0x18
-#define DML_PIPE_ID 0x1c
-#define PRODUCER_PIPE_ID_SHFT 0
-#define PRODUCER_PIPE_ID_MSK GENMASK(4, 0)
-#define CONSUMER_PIPE_ID_SHFT 16
-#define CONSUMER_PIPE_ID_MSK GENMASK(20, 16)
-
-#define DML_PRODUCER_BAM_BLOCK_SIZE 0x24
-#define DML_PRODUCER_BAM_TRANS_SIZE 0x28
-
-/* other definitions */
-#define PRODUCER_PIPE_LOGICAL_SIZE 4096
-#define CONSUMER_PIPE_LOGICAL_SIZE 4096
-
-#define DML_OFFSET 0x800
-
-void dml_start_xfer(struct mmci_host *host, struct mmc_data *data)
-{
- u32 config;
- void __iomem *base = host->base + DML_OFFSET;
-
- if (data->flags & MMC_DATA_READ) {
- /* Read operation: configure DML for producer operation */
- /* Set producer CRCI-x and disable consumer CRCI */
- config = readl_relaxed(base + DML_CONFIG);
- config = (config & ~PRODUCER_CRCI_MSK) | PRODUCER_CRCI_X_SEL;
- config = (config & ~CONSUMER_CRCI_MSK) | CONSUMER_CRCI_DISABLE;
- writel_relaxed(config, base + DML_CONFIG);
-
- /* Set the Producer BAM block size */
- writel_relaxed(data->blksz, base + DML_PRODUCER_BAM_BLOCK_SIZE);
-
- /* Set Producer BAM Transaction size */
- writel_relaxed(data->blocks * data->blksz,
- base + DML_PRODUCER_BAM_TRANS_SIZE);
- /* Set Producer Transaction End bit */
- config = readl_relaxed(base + DML_CONFIG);
- config |= PRODUCER_TRANS_END_EN;
- writel_relaxed(config, base + DML_CONFIG);
- /* Trigger producer */
- writel_relaxed(1, base + DML_PRODUCER_START);
- } else {
- /* Write operation: configure DML for consumer operation */
- /* Set consumer CRCI-x and disable producer CRCI*/
- config = readl_relaxed(base + DML_CONFIG);
- config = (config & ~CONSUMER_CRCI_MSK) | CONSUMER_CRCI_X_SEL;
- config = (config & ~PRODUCER_CRCI_MSK) | PRODUCER_CRCI_DISABLE;
- writel_relaxed(config, base + DML_CONFIG);
- /* Clear Producer Transaction End bit */
- config = readl_relaxed(base + DML_CONFIG);
- config &= ~PRODUCER_TRANS_END_EN;
- writel_relaxed(config, base + DML_CONFIG);
- /* Trigger consumer */
- writel_relaxed(1, base + DML_CONSUMER_START);
- }
-
- /* make sure the dml is configured before dma is triggered */
- wmb();
-}
-
-static int of_get_dml_pipe_index(struct device_node *np, const char *name)
-{
- int index;
- struct of_phandle_args dma_spec;
-
- index = of_property_match_string(np, "dma-names", name);
-
- if (index < 0)
- return -ENODEV;
-
- if (of_parse_phandle_with_args(np, "dmas", "#dma-cells", index,
- &dma_spec))
- return -ENODEV;
-
- if (dma_spec.args_count)
- return dma_spec.args[0];
-
- return -ENODEV;
-}
-
-/* Initialize the dml hardware connected to SD Card controller */
-int dml_hw_init(struct mmci_host *host, struct device_node *np)
-{
- u32 config;
- void __iomem *base;
- int consumer_id, producer_id;
-
- consumer_id = of_get_dml_pipe_index(np, "tx");
- producer_id = of_get_dml_pipe_index(np, "rx");
-
- if (producer_id < 0 || consumer_id < 0)
- return -ENODEV;
-
- base = host->base + DML_OFFSET;
-
- /* Reset the DML block */
- writel_relaxed(1, base + DML_SW_RESET);
-
- /* Disable the producer and consumer CRCI */
- config = (PRODUCER_CRCI_DISABLE | CONSUMER_CRCI_DISABLE);
- /*
- * Disable the bypass mode. Bypass mode will only be used
- * if data transfer is to happen in PIO mode and don't
- * want the BAM interface to connect with SDCC-DML.
- */
- config &= ~BYPASS;
- /*
- * Disable direct mode as we don't DML to MASTER the AHB bus.
- * BAM connected with DML should MASTER the AHB bus.
- */
- config &= ~DIRECT_MODE;
- /*
- * Disable infinite mode transfer as we won't be doing any
- * infinite size data transfers. All data transfer will be
- * of finite data size.
- */
- config &= ~INFINITE_CONS_TRANS;
- writel_relaxed(config, base + DML_CONFIG);
-
- /*
- * Initialize the logical BAM pipe size for producer
- * and consumer.
- */
- writel_relaxed(PRODUCER_PIPE_LOGICAL_SIZE,
- base + DML_PRODUCER_PIPE_LOGICAL_SIZE);
- writel_relaxed(CONSUMER_PIPE_LOGICAL_SIZE,
- base + DML_CONSUMER_PIPE_LOGICAL_SIZE);
-
- /* Initialize Producer/consumer pipe id */
- writel_relaxed(producer_id | (consumer_id << CONSUMER_PIPE_ID_SHFT),
- base + DML_PIPE_ID);
-
- /* Make sure dml initialization is finished */
- mb();
-
- return 0;
-}
diff --git a/drivers/mmc/host/mmci_qcom_dml.h b/drivers/mmc/host/mmci_qcom_dml.h
deleted file mode 100644
index 6e405d0..0000000
--- a/drivers/mmc/host/mmci_qcom_dml.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- *
- * Copyright (c) 2011, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-#ifndef __MMC_QCOM_DML_H__
-#define __MMC_QCOM_DML_H__
-
-#ifdef CONFIG_MMC_QCOM_DML
-int dml_hw_init(struct mmci_host *host, struct device_node *np);
-void dml_start_xfer(struct mmci_host *host, struct mmc_data *data);
-#else
-static inline int dml_hw_init(struct mmci_host *host, struct device_node *np)
-{
- return -ENOSYS;
-}
-static inline void dml_start_xfer(struct mmci_host *host, struct mmc_data *data)
-{
-}
-#endif /* CONFIG_MMC_QCOM_DML */
-
-#endif /* __MMC_QCOM_DML_H__ */
--
2.7.4
^ permalink raw reply related
* [PATCH 01/19] mmc: mmci: regroup and define dma operations
From: Ludovic Barre @ 2018-06-12 13:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1528809280-31116-1-git-send-email-ludovic.Barre@st.com>
From: Ludovic Barre <ludovic.barre@st.com>
Prepare mmci driver to manage dma interface by new property.
This patch defines and regroups dma operations for mmci drivers.
mmci_dma_XX prototypes are added to call member of mmci_dma_ops
if not null. Based on legacy need, a mmci dma interface has been
defined with:
-mmci_dma_setup
-mmci_dma_release
-mmci_dma_pre_req
-mmci_dma_start
-mmci_dma_finalize
-mmci_dma_post_req
-mmci_dma_error
-mmci_dma_get_next_data
A dma_priv is added to host structure to contain private dma needs.
Legacy dmaengine functions have been moved with just some adaptation on:
-dma_in_progress moves to dmaengine_priv structure, called in
dmaengine_error and dmaengine_finalize.
-centralized dma_unmap_sg into dmaengine_unmap, called by
dmaengine_error and dmaengine_finalize.
Signed-off-by: Ludovic Barre <ludovic.barre@st.com>
---
drivers/mmc/host/Makefile | 2 +-
drivers/mmc/host/mmci.c | 437 ++----------------------------------------
drivers/mmc/host/mmci.h | 95 ++++++++--
drivers/mmc/host/mmci_dma.c | 450 ++++++++++++++++++++++++++++++++++++++++++++
drivers/mmc/host/mmci_dma.h | 31 +++
5 files changed, 579 insertions(+), 436 deletions(-)
create mode 100644 drivers/mmc/host/mmci_dma.c
create mode 100644 drivers/mmc/host/mmci_dma.h
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index 85dc132..daecaa98 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -4,7 +4,7 @@
#
obj-$(CONFIG_MMC_ARMMMCI) += armmmci.o
-armmmci-y := mmci.o
+armmmci-y := mmci.o mmci_dma.o
armmmci-$(CONFIG_MMC_QCOM_DML) += mmci_qcom_dml.o
obj-$(CONFIG_MMC_PXA) += pxamci.o
obj-$(CONFIG_MMC_MXC) += mxcmmc.o
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index f184977..8868be0 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -42,84 +42,13 @@
#include <asm/io.h>
#include "mmci.h"
+#include "mmci_dma.h"
#include "mmci_qcom_dml.h"
#define DRIVER_NAME "mmci-pl18x"
static unsigned int fmax = 515633;
-/**
- * struct variant_data - MMCI variant-specific quirks
- * @clkreg: default value for MCICLOCK register
- * @clkreg_enable: enable value for MMCICLOCK register
- * @clkreg_8bit_bus_enable: enable value for 8 bit bus
- * @clkreg_neg_edge_enable: enable value for inverted data/cmd output
- * @datalength_bits: number of bits in the MMCIDATALENGTH register
- * @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY
- * is asserted (likewise for RX)
- * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY
- * is asserted (likewise for RX)
- * @data_cmd_enable: enable value for data commands.
- * @st_sdio: enable ST specific SDIO logic
- * @st_clkdiv: true if using a ST-specific clock divider algorithm
- * @datactrl_mask_ddrmode: ddr mode mask in datactrl register.
- * @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl register
- * @blksz_datactrl4: true if Block size is at b4..b16 position in datactrl
- * register
- * @datactrl_mask_sdio: SDIO enable mask in datactrl register
- * @pwrreg_powerup: power up value for MMCIPOWER register
- * @f_max: maximum clk frequency supported by the controller.
- * @signal_direction: input/out direction of bus signals can be indicated
- * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock
- * @busy_detect: true if the variant supports busy detection on DAT0.
- * @busy_dpsm_flag: bitmask enabling busy detection in the DPSM
- * @busy_detect_flag: bitmask identifying the bit in the MMCISTATUS register
- * indicating that the card is busy
- * @busy_detect_mask: bitmask identifying the bit in the MMCIMASK0 to mask for
- * getting busy end detection interrupts
- * @pwrreg_nopower: bits in MMCIPOWER don't controls ext. power supply
- * @explicit_mclk_control: enable explicit mclk control in driver.
- * @qcom_fifo: enables qcom specific fifo pio read logic.
- * @qcom_dml: enables qcom specific dma glue for dma transfers.
- * @reversed_irq_handling: handle data irq before cmd irq.
- * @mmcimask1: true if variant have a MMCIMASK1 register.
- * @start_err: bitmask identifying the STARTBITERR bit inside MMCISTATUS
- * register.
- * @opendrain: bitmask identifying the OPENDRAIN bit inside MMCIPOWER register
- */
-struct variant_data {
- unsigned int clkreg;
- unsigned int clkreg_enable;
- unsigned int clkreg_8bit_bus_enable;
- unsigned int clkreg_neg_edge_enable;
- unsigned int datalength_bits;
- unsigned int fifosize;
- unsigned int fifohalfsize;
- unsigned int data_cmd_enable;
- unsigned int datactrl_mask_ddrmode;
- unsigned int datactrl_mask_sdio;
- bool st_sdio;
- bool st_clkdiv;
- bool blksz_datactrl16;
- bool blksz_datactrl4;
- u32 pwrreg_powerup;
- u32 f_max;
- bool signal_direction;
- bool pwrreg_clkgate;
- bool busy_detect;
- u32 busy_dpsm_flag;
- u32 busy_detect_flag;
- u32 busy_detect_mask;
- bool pwrreg_nopower;
- bool explicit_mclk_control;
- bool qcom_fifo;
- bool qcom_dml;
- bool reversed_irq_handling;
- bool mmcimask1;
- u32 start_err;
- u32 opendrain;
-};
-
static struct variant_data variant_arm = {
.fifosize = 16 * 4,
.fifohalfsize = 8 * 4,
@@ -130,6 +59,7 @@ static struct variant_data variant_arm = {
.mmcimask1 = true,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_ROD,
+ .mmci_dma = &dmaengine,
};
static struct variant_data variant_arm_extended_fifo = {
@@ -141,6 +71,7 @@ static struct variant_data variant_arm_extended_fifo = {
.mmcimask1 = true,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_ROD,
+ .mmci_dma = &dmaengine,
};
static struct variant_data variant_arm_extended_fifo_hwfc = {
@@ -153,6 +84,7 @@ static struct variant_data variant_arm_extended_fifo_hwfc = {
.mmcimask1 = true,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_ROD,
+ .mmci_dma = &dmaengine,
};
static struct variant_data variant_u300 = {
@@ -171,6 +103,7 @@ static struct variant_data variant_u300 = {
.mmcimask1 = true,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_OD,
+ .mmci_dma = &dmaengine,
};
static struct variant_data variant_nomadik = {
@@ -190,6 +123,7 @@ static struct variant_data variant_nomadik = {
.mmcimask1 = true,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_OD,
+ .mmci_dma = &dmaengine,
};
static struct variant_data variant_ux500 = {
@@ -215,6 +149,7 @@ static struct variant_data variant_ux500 = {
.mmcimask1 = true,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_OD,
+ .mmci_dma = &dmaengine,
};
static struct variant_data variant_ux500v2 = {
@@ -242,6 +177,7 @@ static struct variant_data variant_ux500v2 = {
.mmcimask1 = true,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_OD,
+ .mmci_dma = &dmaengine,
};
static struct variant_data variant_stm32 = {
@@ -259,6 +195,7 @@ static struct variant_data variant_stm32 = {
.f_max = 48000000,
.pwrreg_clkgate = true,
.pwrreg_nopower = true,
+ .mmci_dma = &dmaengine,
};
static struct variant_data variant_qcom = {
@@ -280,6 +217,7 @@ static struct variant_data variant_qcom = {
.mmcimask1 = true,
.start_err = MCI_STARTBITERR,
.opendrain = MCI_ROD,
+ .mmci_dma = &dmaengine,
};
/* Busy detection for the ST Micro variant */
@@ -355,7 +293,7 @@ static void mmci_write_pwrreg(struct mmci_host *host, u32 pwr)
/*
* This must be called with host->lock held
*/
-static void mmci_write_datactrlreg(struct mmci_host *host, u32 datactrl)
+void mmci_write_datactrlreg(struct mmci_host *host, u32 datactrl)
{
/* Keep busy mode in DPSM if enabled */
datactrl |= host->datactrl_reg & host->variant->busy_dpsm_flag;
@@ -480,281 +418,10 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)
sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
}
-/*
- * All the DMA operation mode stuff goes inside this ifdef.
- * This assumes that you have a generic DMA device interface,
- * no custom DMA interfaces are supported.
- */
-#ifdef CONFIG_DMA_ENGINE
-static void mmci_dma_setup(struct mmci_host *host)
-{
- const char *rxname, *txname;
- struct variant_data *variant = host->variant;
-
- host->dma_rx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "rx");
- host->dma_tx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "tx");
-
- /* initialize pre request cookie */
- host->next_data.cookie = 1;
-
- /*
- * If only an RX channel is specified, the driver will
- * attempt to use it bidirectionally, however if it is
- * is specified but cannot be located, DMA will be disabled.
- */
- if (host->dma_rx_channel && !host->dma_tx_channel)
- host->dma_tx_channel = host->dma_rx_channel;
-
- if (host->dma_rx_channel)
- rxname = dma_chan_name(host->dma_rx_channel);
- else
- rxname = "none";
-
- if (host->dma_tx_channel)
- txname = dma_chan_name(host->dma_tx_channel);
- else
- txname = "none";
-
- dev_info(mmc_dev(host->mmc), "DMA channels RX %s, TX %s\n",
- rxname, txname);
-
- /*
- * Limit the maximum segment size in any SG entry according to
- * the parameters of the DMA engine device.
- */
- if (host->dma_tx_channel) {
- struct device *dev = host->dma_tx_channel->device->dev;
- unsigned int max_seg_size = dma_get_max_seg_size(dev);
-
- if (max_seg_size < host->mmc->max_seg_size)
- host->mmc->max_seg_size = max_seg_size;
- }
- if (host->dma_rx_channel) {
- struct device *dev = host->dma_rx_channel->device->dev;
- unsigned int max_seg_size = dma_get_max_seg_size(dev);
-
- if (max_seg_size < host->mmc->max_seg_size)
- host->mmc->max_seg_size = max_seg_size;
- }
-
- if (variant->qcom_dml && host->dma_rx_channel && host->dma_tx_channel)
- if (dml_hw_init(host, host->mmc->parent->of_node))
- variant->qcom_dml = false;
-}
-
-/*
- * This is used in or so inline it
- * so it can be discarded.
- */
-static inline void mmci_dma_release(struct mmci_host *host)
-{
- if (host->dma_rx_channel)
- dma_release_channel(host->dma_rx_channel);
- if (host->dma_tx_channel)
- dma_release_channel(host->dma_tx_channel);
- host->dma_rx_channel = host->dma_tx_channel = NULL;
-}
-
-static void mmci_dma_data_error(struct mmci_host *host)
-{
- dev_err(mmc_dev(host->mmc), "error during DMA transfer!\n");
- dmaengine_terminate_all(host->dma_current);
- host->dma_in_progress = false;
- host->dma_current = NULL;
- host->dma_desc_current = NULL;
- host->data->host_cookie = 0;
-}
-
-static void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data)
-{
- struct dma_chan *chan;
-
- if (data->flags & MMC_DATA_READ)
- chan = host->dma_rx_channel;
- else
- chan = host->dma_tx_channel;
-
- dma_unmap_sg(chan->device->dev, data->sg, data->sg_len,
- mmc_get_dma_dir(data));
-}
-
-static void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data)
-{
- u32 status;
- int i;
-
- /* Wait up to 1ms for the DMA to complete */
- for (i = 0; ; i++) {
- status = readl(host->base + MMCISTATUS);
- if (!(status & MCI_RXDATAAVLBLMASK) || i >= 100)
- break;
- udelay(10);
- }
-
- /*
- * Check to see whether we still have some data left in the FIFO -
- * this catches DMA controllers which are unable to monitor the
- * DMALBREQ and DMALSREQ signals while allowing us to DMA to non-
- * contiguous buffers. On TX, we'll get a FIFO underrun error.
- */
- if (status & MCI_RXDATAAVLBLMASK) {
- mmci_dma_data_error(host);
- if (!data->error)
- data->error = -EIO;
- }
-
- if (!data->host_cookie)
- mmci_dma_unmap(host, data);
-
- /*
- * Use of DMA with scatter-gather is impossible.
- * Give up with DMA and switch back to PIO mode.
- */
- if (status & MCI_RXDATAAVLBLMASK) {
- dev_err(mmc_dev(host->mmc), "buggy DMA detected. Taking evasive action.\n");
- mmci_dma_release(host);
- }
-
- host->dma_in_progress = false;
- host->dma_current = NULL;
- host->dma_desc_current = NULL;
-}
-
-/* prepares DMA channel and DMA descriptor, returns non-zero on failure */
-static int __mmci_dma_prep_data(struct mmci_host *host, struct mmc_data *data,
- struct dma_chan **dma_chan,
- struct dma_async_tx_descriptor **dma_desc)
-{
- struct variant_data *variant = host->variant;
- struct dma_slave_config conf = {
- .src_addr = host->phybase + MMCIFIFO,
- .dst_addr = host->phybase + MMCIFIFO,
- .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
- .dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
- .src_maxburst = variant->fifohalfsize >> 2, /* # of words */
- .dst_maxburst = variant->fifohalfsize >> 2, /* # of words */
- .device_fc = false,
- };
- struct dma_chan *chan;
- struct dma_device *device;
- struct dma_async_tx_descriptor *desc;
- int nr_sg;
- unsigned long flags = DMA_CTRL_ACK;
-
- if (data->flags & MMC_DATA_READ) {
- conf.direction = DMA_DEV_TO_MEM;
- chan = host->dma_rx_channel;
- } else {
- conf.direction = DMA_MEM_TO_DEV;
- chan = host->dma_tx_channel;
- }
-
- /* If there's no DMA channel, fall back to PIO */
- if (!chan)
- return -EINVAL;
-
- /* If less than or equal to the fifo size, don't bother with DMA */
- if (data->blksz * data->blocks <= variant->fifosize)
- return -EINVAL;
-
- device = chan->device;
- nr_sg = dma_map_sg(device->dev, data->sg, data->sg_len,
- mmc_get_dma_dir(data));
- if (nr_sg == 0)
- return -EINVAL;
-
- if (host->variant->qcom_dml)
- flags |= DMA_PREP_INTERRUPT;
-
- dmaengine_slave_config(chan, &conf);
- desc = dmaengine_prep_slave_sg(chan, data->sg, nr_sg,
- conf.direction, flags);
- if (!desc)
- goto unmap_exit;
-
- *dma_chan = chan;
- *dma_desc = desc;
-
- return 0;
-
- unmap_exit:
- dma_unmap_sg(device->dev, data->sg, data->sg_len,
- mmc_get_dma_dir(data));
- return -ENOMEM;
-}
-
-static inline int mmci_dma_prep_data(struct mmci_host *host,
- struct mmc_data *data)
-{
- /* Check if next job is already prepared. */
- if (host->dma_current && host->dma_desc_current)
- return 0;
-
- /* No job were prepared thus do it now. */
- return __mmci_dma_prep_data(host, data, &host->dma_current,
- &host->dma_desc_current);
-}
-
-static inline int mmci_dma_prep_next(struct mmci_host *host,
- struct mmc_data *data)
-{
- struct mmci_host_next *nd = &host->next_data;
- return __mmci_dma_prep_data(host, data, &nd->dma_chan, &nd->dma_desc);
-}
-
-static int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)
-{
- int ret;
- struct mmc_data *data = host->data;
-
- ret = mmci_dma_prep_data(host, host->data);
- if (ret)
- return ret;
-
- /* Okay, go for it. */
- dev_vdbg(mmc_dev(host->mmc),
- "Submit MMCI DMA job, sglen %d blksz %04x blks %04x flags %08x\n",
- data->sg_len, data->blksz, data->blocks, data->flags);
- host->dma_in_progress = true;
- dmaengine_submit(host->dma_desc_current);
- dma_async_issue_pending(host->dma_current);
-
- if (host->variant->qcom_dml)
- dml_start_xfer(host, data);
-
- datactrl |= MCI_DPSM_DMAENABLE;
-
- /* Trigger the DMA transfer */
- mmci_write_datactrlreg(host, datactrl);
-
- /*
- * Let the MMCI say when the data is ended and it's time
- * to fire next DMA request. When that happens, MMCI will
- * call mmci_data_end()
- */
- writel(readl(host->base + MMCIMASK0) | MCI_DATAENDMASK,
- host->base + MMCIMASK0);
- return 0;
-}
-
-static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data)
-{
- struct mmci_host_next *next = &host->next_data;
-
- WARN_ON(data->host_cookie && data->host_cookie != next->cookie);
- WARN_ON(!data->host_cookie && (next->dma_desc || next->dma_chan));
-
- host->dma_desc_current = next->dma_desc;
- host->dma_current = next->dma_chan;
- next->dma_desc = NULL;
- next->dma_chan = NULL;
-}
-
static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct mmci_host *host = mmc_priv(mmc);
struct mmc_data *data = mrq->data;
- struct mmci_host_next *nd = &host->next_data;
if (!data)
return;
@@ -764,8 +431,7 @@ static void mmci_pre_request(struct mmc_host *mmc, struct mmc_request *mrq)
if (mmci_validate_data(host, data))
return;
- if (!mmci_dma_prep_next(host, data))
- data->host_cookie = ++nd->cookie < 0 ? 1 : nd->cookie;
+ mmci_dma_pre_req(host, data);
}
static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq,
@@ -777,67 +443,9 @@ static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq,
if (!data || !data->host_cookie)
return;
- mmci_dma_unmap(host, data);
-
- if (err) {
- struct mmci_host_next *next = &host->next_data;
- struct dma_chan *chan;
- if (data->flags & MMC_DATA_READ)
- chan = host->dma_rx_channel;
- else
- chan = host->dma_tx_channel;
- dmaengine_terminate_all(chan);
-
- if (host->dma_desc_current == next->dma_desc)
- host->dma_desc_current = NULL;
-
- if (host->dma_current == next->dma_chan) {
- host->dma_in_progress = false;
- host->dma_current = NULL;
- }
-
- next->dma_desc = NULL;
- next->dma_chan = NULL;
- data->host_cookie = 0;
- }
-}
-
-#else
-/* Blank functions if the DMA engine is not available */
-static void mmci_get_next_data(struct mmci_host *host, struct mmc_data *data)
-{
-}
-static inline void mmci_dma_setup(struct mmci_host *host)
-{
-}
-
-static inline void mmci_dma_release(struct mmci_host *host)
-{
-}
-
-static inline void mmci_dma_unmap(struct mmci_host *host, struct mmc_data *data)
-{
-}
-
-static inline void mmci_dma_finalize(struct mmci_host *host,
- struct mmc_data *data)
-{
-}
-
-static inline void mmci_dma_data_error(struct mmci_host *host)
-{
-}
-
-static inline int mmci_dma_start_data(struct mmci_host *host, unsigned int datactrl)
-{
- return -ENOSYS;
+ mmci_dma_post_req(host, data, err);
}
-#define mmci_pre_request NULL
-#define mmci_post_request NULL
-
-#endif
-
static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
{
struct variant_data *variant = host->variant;
@@ -904,7 +512,7 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
* Attempt to use DMA operation mode, if this
* should fail, fall back to PIO mode
*/
- if (!mmci_dma_start_data(host, datactrl))
+ if (!mmci_dma_start(host, datactrl))
return;
/* IRQ mode, map the SG list for CPU reading/writing */
@@ -979,10 +587,7 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
u32 remain, success;
/* Terminate the DMA transfer */
- if (dma_inprogress(host)) {
- mmci_dma_data_error(host);
- mmci_dma_unmap(host, data);
- }
+ mmci_dma_error(host);
/*
* Calculate how far we are into the transfer. Note that
@@ -1020,8 +625,8 @@ mmci_data_irq(struct mmci_host *host, struct mmc_data *data,
dev_err(mmc_dev(host->mmc), "stray MCI_DATABLOCKEND interrupt\n");
if (status & MCI_DATAEND || data->error) {
- if (dma_inprogress(host))
- mmci_dma_finalize(host, data);
+ mmci_dma_finalize(host, data);
+
mmci_stop_data(host);
if (!data->error)
@@ -1128,10 +733,8 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
if ((!sbc && !cmd->data) || cmd->error) {
if (host->data) {
/* Terminate the DMA transfer */
- if (dma_inprogress(host)) {
- mmci_dma_data_error(host);
- mmci_dma_unmap(host, host->data);
- }
+ mmci_dma_error(host);
+
mmci_stop_data(host);
}
mmci_request_end(host, host->mrq);
@@ -1399,7 +1002,7 @@ static void mmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
host->mrq = mrq;
if (mrq->data)
- mmci_get_next_data(host, mrq->data);
+ mmci_dma_get_next_data(host, mrq->data);
if (mrq->data && mrq->data->flags & MMC_DATA_READ)
mmci_start_data(host, mrq->data);
diff --git a/drivers/mmc/host/mmci.h b/drivers/mmc/host/mmci.h
index f91cdf7..a73bb98 100644
--- a/drivers/mmc/host/mmci.h
+++ b/drivers/mmc/host/mmci.h
@@ -195,13 +195,81 @@
#define MMCI_PINCTRL_STATE_OPENDRAIN "opendrain"
struct clk;
-struct variant_data;
struct dma_chan;
-struct mmci_host_next {
- struct dma_async_tx_descriptor *dma_desc;
- struct dma_chan *dma_chan;
- s32 cookie;
+/**
+ * struct variant_data - MMCI variant-specific quirks
+ * @clkreg: default value for MCICLOCK register
+ * @clkreg_enable: enable value for MMCICLOCK register
+ * @clkreg_8bit_bus_enable: enable value for 8 bit bus
+ * @clkreg_neg_edge_enable: enable value for inverted data/cmd output
+ * @datalength_bits: number of bits in the MMCIDATALENGTH register
+ * @fifosize: number of bytes that can be written when MMCI_TXFIFOEMPTY
+ * is asserted (likewise for RX)
+ * @fifohalfsize: number of bytes that can be written when MCI_TXFIFOHALFEMPTY
+ * is asserted (likewise for RX)
+ * @data_cmd_enable: enable value for data commands.
+ * @st_sdio: enable ST specific SDIO logic
+ * @st_clkdiv: true if using a ST-specific clock divider algorithm
+ * @datactrl_mask_ddrmode: ddr mode mask in datactrl register.
+ * @blksz_datactrl16: true if Block size is at b16..b30 position in datactrl
+ * register
+ * @blksz_datactrl4: true if Block size is at b4..b16 position in datactrl
+ * register
+ * @datactrl_mask_sdio: SDIO enable mask in datactrl register
+ * @pwrreg_powerup: power up value for MMCIPOWER register
+ * @f_max: maximum clk frequency supported by the controller.
+ * @signal_direction: input/out direction of bus signals can be indicated
+ * @pwrreg_clkgate: MMCIPOWER register must be used to gate the clock
+ * @busy_detect: true if the variant supports busy detection on DAT0.
+ * @busy_dpsm_flag: bitmask enabling busy detection in the DPSM
+ * @busy_detect_flag: bitmask identifying the bit in the MMCISTATUS register
+ * indicating that the card is busy
+ * @busy_detect_mask: bitmask identifying the bit in the MMCIMASK0 to mask for
+ * getting busy end detection interrupts
+ * @pwrreg_nopower: bits in MMCIPOWER don't controls ext. power supply
+ * @explicit_mclk_control: enable explicit mclk control in driver.
+ * @qcom_fifo: enables qcom specific fifo pio read logic.
+ * @qcom_dml: enables qcom specific dma glue for dma transfers.
+ * @reversed_irq_handling: handle data irq before cmd irq.
+ * @mmcimask1: true if variant have a MMCIMASK1 register.
+ * @start_err: bitmask identifying the STARTBITERR bit inside MMCISTATUS
+ * register.
+ * @opendrain: bitmask identifying the OPENDRAIN bit inside MMCIPOWER register
+ * @mmci_dma: Pointer to platform-specific DMA callbacks.
+ */
+struct variant_data {
+ unsigned int clkreg;
+ unsigned int clkreg_enable;
+ unsigned int clkreg_8bit_bus_enable;
+ unsigned int clkreg_neg_edge_enable;
+ unsigned int datalength_bits;
+ unsigned int fifosize;
+ unsigned int fifohalfsize;
+ unsigned int data_cmd_enable;
+ unsigned int datactrl_mask_ddrmode;
+ unsigned int datactrl_mask_sdio;
+ bool st_sdio;
+ bool st_clkdiv;
+ bool blksz_datactrl16;
+ bool blksz_datactrl4;
+ u32 pwrreg_powerup;
+ u32 f_max;
+ bool signal_direction;
+ bool pwrreg_clkgate;
+ bool busy_detect;
+ u32 busy_dpsm_flag;
+ u32 busy_detect_flag;
+ u32 busy_detect_mask;
+ bool pwrreg_nopower;
+ bool explicit_mclk_control;
+ bool qcom_fifo;
+ bool qcom_dml;
+ bool reversed_irq_handling;
+ bool mmcimask1;
+ u32 start_err;
+ u32 opendrain;
+ struct mmci_dma_ops *mmci_dma;
};
struct mmci_host {
@@ -244,18 +312,9 @@ struct mmci_host {
unsigned int size;
int (*get_rx_fifocnt)(struct mmci_host *h, u32 status, int remain);
-#ifdef CONFIG_DMA_ENGINE
- /* DMA stuff */
- struct dma_chan *dma_current;
- struct dma_chan *dma_rx_channel;
- struct dma_chan *dma_tx_channel;
- struct dma_async_tx_descriptor *dma_desc_current;
- struct mmci_host_next next_data;
- bool dma_in_progress;
-
-#define dma_inprogress(host) ((host)->dma_in_progress)
-#else
-#define dma_inprogress(host) (0)
-#endif
+ void *dma_priv;
};
+extern struct mmci_dma_ops dmaengine;
+
+void mmci_write_datactrlreg(struct mmci_host *host, u32 datactrl);
diff --git a/drivers/mmc/host/mmci_dma.c b/drivers/mmc/host/mmci_dma.c
new file mode 100644
index 0000000..98a542d
--- /dev/null
+++ b/drivers/mmc/host/mmci_dma.c
@@ -0,0 +1,450 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: Ludovic.barre at st.com for STMicroelectronics.
+ */
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/card.h>
+#include <linux/scatterlist.h>
+
+#include "mmci.h"
+#include "mmci_dma.h"
+#include "mmci_qcom_dml.h"
+
+int mmci_dma_setup(struct mmci_host *host)
+{
+ struct mmci_dma_ops *mmci_dma = host->variant->mmci_dma;
+
+ if (mmci_dma && mmci_dma->setup)
+ return mmci_dma->setup(host);
+
+ return 0;
+}
+
+void mmci_dma_release(struct mmci_host *host)
+{
+ struct mmci_dma_ops *mmci_dma = host->variant->mmci_dma;
+
+ if (mmci_dma && mmci_dma->release)
+ mmci_dma->release(host);
+}
+
+void mmci_dma_pre_req(struct mmci_host *host, struct mmc_data *data)
+{
+ struct mmci_dma_ops *mmci_dma = host->variant->mmci_dma;
+
+ if (mmci_dma && mmci_dma->pre_req)
+ mmci_dma->pre_req(host, data);
+}
+
+int mmci_dma_start(struct mmci_host *host, unsigned int datactrl)
+{
+ struct mmci_dma_ops *mmci_dma = host->variant->mmci_dma;
+
+ if (mmci_dma && mmci_dma->start)
+ return mmci_dma->start(host, datactrl);
+
+ return -EINVAL;
+}
+
+void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data)
+{
+ struct mmci_dma_ops *mmci_dma = host->variant->mmci_dma;
+
+ if (mmci_dma && mmci_dma->finalize)
+ mmci_dma->finalize(host, data);
+}
+
+void mmci_dma_post_req(struct mmci_host *host,
+ struct mmc_data *data, int err)
+{
+ struct mmci_dma_ops *mmci_dma = host->variant->mmci_dma;
+
+ if (mmci_dma && mmci_dma->post_req)
+ mmci_dma->post_req(host, data, err);
+}
+
+void mmci_dma_error(struct mmci_host *host)
+{
+ struct mmci_dma_ops *mmci_dma = host->variant->mmci_dma;
+
+ if (mmci_dma && mmci_dma->error)
+ mmci_dma->error(host);
+}
+
+void mmci_dma_get_next_data(struct mmci_host *host, struct mmc_data *data)
+{
+ struct mmci_dma_ops *mmci_dma = host->variant->mmci_dma;
+
+ if (mmci_dma && mmci_dma->get_next_data)
+ mmci_dma->get_next_data(host, data);
+}
+
+#ifdef CONFIG_DMA_ENGINE
+struct dmaengine_next {
+ struct dma_async_tx_descriptor *dma_desc;
+ struct dma_chan *dma_chan;
+ s32 cookie;
+};
+
+struct dmaengine_priv {
+ struct dma_chan *dma_current;
+ struct dma_chan *dma_rx_channel;
+ struct dma_chan *dma_tx_channel;
+ struct dma_async_tx_descriptor *dma_desc_current;
+ struct dmaengine_next next_data;
+ bool dma_in_progress;
+};
+
+#define dma_inprogress(dmae) ((dmae)->dma_in_progress)
+
+static int dmaengine_setup(struct mmci_host *host)
+{
+ const char *rxname, *txname;
+ struct variant_data *variant = host->variant;
+ struct dmaengine_priv *dmae;
+
+ dmae = devm_kzalloc(mmc_dev(host->mmc), sizeof(*dmae), GFP_KERNEL);
+ if (!dmae)
+ return -ENOMEM;
+
+ host->dma_priv = dmae;
+
+ dmae->dma_rx_channel = dma_request_slave_channel(mmc_dev(host->mmc),
+ "rx");
+ dmae->dma_tx_channel = dma_request_slave_channel(mmc_dev(host->mmc),
+ "tx");
+
+ /* initialize pre request cookie */
+ dmae->next_data.cookie = 1;
+
+ /*
+ * If only an RX channel is specified, the driver will
+ * attempt to use it bidirectionally, however if it is
+ * is specified but cannot be located, DMA will be disabled.
+ */
+ if (dmae->dma_rx_channel && !dmae->dma_tx_channel)
+ dmae->dma_tx_channel = dmae->dma_rx_channel;
+
+ if (dmae->dma_rx_channel)
+ rxname = dma_chan_name(dmae->dma_rx_channel);
+ else
+ rxname = "none";
+
+ if (dmae->dma_tx_channel)
+ txname = dma_chan_name(dmae->dma_tx_channel);
+ else
+ txname = "none";
+
+ dev_info(mmc_dev(host->mmc), "DMA channels RX %s, TX %s\n",
+ rxname, txname);
+
+ /*
+ * Limit the maximum segment size in any SG entry according to
+ * the parameters of the DMA engine device.
+ */
+ if (dmae->dma_tx_channel) {
+ struct device *dev = dmae->dma_tx_channel->device->dev;
+ unsigned int max_seg_size = dma_get_max_seg_size(dev);
+
+ if (max_seg_size < host->mmc->max_seg_size)
+ host->mmc->max_seg_size = max_seg_size;
+ }
+ if (dmae->dma_rx_channel) {
+ struct device *dev = dmae->dma_rx_channel->device->dev;
+ unsigned int max_seg_size = dma_get_max_seg_size(dev);
+
+ if (max_seg_size < host->mmc->max_seg_size)
+ host->mmc->max_seg_size = max_seg_size;
+ }
+
+ if (variant->qcom_dml && dmae->dma_rx_channel && dmae->dma_tx_channel)
+ if (dml_hw_init(host, host->mmc->parent->of_node))
+ variant->qcom_dml = false;
+
+ return 0;
+}
+
+static inline void dmaengine_release(struct mmci_host *host)
+{
+ struct dmaengine_priv *dmae = host->dma_priv;
+
+ if (dmae->dma_rx_channel)
+ dma_release_channel(dmae->dma_rx_channel);
+ if (dmae->dma_tx_channel)
+ dma_release_channel(dmae->dma_tx_channel);
+
+ dmae->dma_rx_channel = dmae->dma_tx_channel = NULL;
+}
+
+static void dmaengine_unmap(struct mmci_host *host, struct mmc_data *data)
+{
+ struct dmaengine_priv *dmae = host->dma_priv;
+ struct dma_chan *chan;
+
+ if (data->flags & MMC_DATA_READ)
+ chan = dmae->dma_rx_channel;
+ else
+ chan = dmae->dma_tx_channel;
+
+ dma_unmap_sg(chan->device->dev, data->sg, data->sg_len,
+ mmc_get_dma_dir(data));
+}
+
+static void dmaengine_error(struct mmci_host *host)
+{
+ struct dmaengine_priv *dmae = host->dma_priv;
+
+ if (!dma_inprogress(dmae))
+ return;
+
+ dev_err(mmc_dev(host->mmc), "error during DMA transfer!\n");
+ dmaengine_terminate_all(dmae->dma_current);
+ dmae->dma_in_progress = false;
+ dmae->dma_current = NULL;
+ dmae->dma_desc_current = NULL;
+ host->data->host_cookie = 0;
+
+ dmaengine_unmap(host, host->data);
+}
+
+static void dmaengine_finalize(struct mmci_host *host, struct mmc_data *data)
+{
+ struct dmaengine_priv *dmae = host->dma_priv;
+ u32 status;
+ int i;
+
+ if (!dma_inprogress(dmae))
+ return;
+
+ /* Wait up to 1ms for the DMA to complete */
+ for (i = 0; ; i++) {
+ status = readl(host->base + MMCISTATUS);
+ if (!(status & MCI_RXDATAAVLBLMASK) || i >= 100)
+ break;
+ udelay(10);
+ }
+
+ /*
+ * Check to see whether we still have some data left in the FIFO -
+ * this catches DMA controllers which are unable to monitor the
+ * DMALBREQ and DMALSREQ signals while allowing us to DMA to non-
+ * contiguous buffers. On TX, we'll get a FIFO underrun error.
+ */
+ if (status & MCI_RXDATAAVLBLMASK) {
+ dmaengine_error(host);
+ if (!data->error)
+ data->error = -EIO;
+ }
+
+ if (!data->host_cookie)
+ dmaengine_unmap(host, data);
+
+ /*
+ * Use of DMA with scatter-gather is impossible.
+ * Give up with DMA and switch back to PIO mode.
+ */
+ if (status & MCI_RXDATAAVLBLMASK) {
+ dev_err(mmc_dev(host->mmc),
+ "buggy DMA detected. Taking evasive action.\n");
+ dmaengine_release(host);
+ }
+
+ dmae->dma_in_progress = false;
+ dmae->dma_current = NULL;
+ dmae->dma_desc_current = NULL;
+}
+
+/* prepares DMA channel and DMA descriptor, returns non-zero on failure */
+static int __dmaengine_prep_data(struct mmci_host *host, struct mmc_data *data,
+ struct dma_chan **dma_chan,
+ struct dma_async_tx_descriptor **dma_desc)
+{
+ struct dmaengine_priv *dmae = host->dma_priv;
+ struct variant_data *variant = host->variant;
+ struct dma_slave_config conf = {
+ .src_addr = host->phybase + MMCIFIFO,
+ .dst_addr = host->phybase + MMCIFIFO,
+ .src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
+ .dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES,
+ .src_maxburst = variant->fifohalfsize >> 2, /* # of words */
+ .dst_maxburst = variant->fifohalfsize >> 2, /* # of words */
+ .device_fc = false,
+ };
+ struct dma_chan *chan;
+ struct dma_device *device;
+ struct dma_async_tx_descriptor *desc;
+ int nr_sg;
+ unsigned long flags = DMA_CTRL_ACK;
+
+ if (data->flags & MMC_DATA_READ) {
+ conf.direction = DMA_DEV_TO_MEM;
+ chan = dmae->dma_rx_channel;
+ } else {
+ conf.direction = DMA_MEM_TO_DEV;
+ chan = dmae->dma_tx_channel;
+ }
+
+ /* If there's no DMA channel, fall back to PIO */
+ if (!chan)
+ return -EINVAL;
+
+ /* If less than or equal to the fifo size, don't bother with DMA */
+ if (data->blksz * data->blocks <= variant->fifosize)
+ return -EINVAL;
+
+ device = chan->device;
+ nr_sg = dma_map_sg(device->dev, data->sg, data->sg_len,
+ mmc_get_dma_dir(data));
+ if (nr_sg == 0)
+ return -EINVAL;
+
+ if (host->variant->qcom_dml)
+ flags |= DMA_PREP_INTERRUPT;
+
+ dmaengine_slave_config(chan, &conf);
+ desc = dmaengine_prep_slave_sg(chan, data->sg, nr_sg,
+ conf.direction, flags);
+ if (!desc)
+ goto unmap_exit;
+
+ *dma_chan = chan;
+ *dma_desc = desc;
+
+ return 0;
+
+ unmap_exit:
+ dmaengine_unmap(host, data);
+ return -ENOMEM;
+}
+
+static inline int dmaengine_prep_data(struct mmci_host *host,
+ struct mmc_data *data)
+{
+ struct dmaengine_priv *dmae = host->dma_priv;
+
+ /* Check if next job is already prepared. */
+ if (dmae->dma_current && dmae->dma_desc_current)
+ return 0;
+
+ /* No job were prepared thus do it now. */
+ return __dmaengine_prep_data(host, data, &dmae->dma_current,
+ &dmae->dma_desc_current);
+}
+
+static inline int dmaengine_prep_next(struct mmci_host *host,
+ struct mmc_data *data)
+{
+ struct dmaengine_priv *dmae = host->dma_priv;
+ struct dmaengine_next *nd = &dmae->next_data;
+
+ return __dmaengine_prep_data(host, data, &nd->dma_chan, &nd->dma_desc);
+}
+
+static int dmaengine_start(struct mmci_host *host, unsigned int datactrl)
+{
+ struct dmaengine_priv *dmae = host->dma_priv;
+ struct mmc_data *data = host->data;
+ int ret;
+
+ ret = dmaengine_prep_data(host, host->data);
+ if (ret)
+ return ret;
+
+ /* Okay, go for it. */
+ dev_vdbg(mmc_dev(host->mmc),
+ "Submit MMCI DMA job, sglen %d blksz %04x blks %04x flags %08x\n",
+ data->sg_len, data->blksz, data->blocks, data->flags);
+ dmae->dma_in_progress = true;
+ dmaengine_submit(dmae->dma_desc_current);
+ dma_async_issue_pending(dmae->dma_current);
+
+ if (host->variant->qcom_dml)
+ dml_start_xfer(host, data);
+
+ datactrl |= MCI_DPSM_DMAENABLE;
+
+ /* Trigger the DMA transfer */
+ mmci_write_datactrlreg(host, datactrl);
+
+ /*
+ * Let the MMCI say when the data is ended and it's time
+ * to fire next DMA request. When that happens, MMCI will
+ * call mmci_data_end()
+ */
+ writel(readl(host->base + MMCIMASK0) | MCI_DATAENDMASK,
+ host->base + MMCIMASK0);
+ return 0;
+}
+
+static void dmaengine_get_next_data(struct mmci_host *host,
+ struct mmc_data *data)
+{
+ struct dmaengine_priv *dmae = host->dma_priv;
+ struct dmaengine_next *next = &dmae->next_data;
+
+ WARN_ON(data->host_cookie && data->host_cookie != next->cookie);
+ WARN_ON(!data->host_cookie && (next->dma_desc || next->dma_chan));
+
+ dmae->dma_desc_current = next->dma_desc;
+ dmae->dma_current = next->dma_chan;
+ next->dma_desc = NULL;
+ next->dma_chan = NULL;
+}
+
+static void dmaengine_pre_req(struct mmci_host *host, struct mmc_data *data)
+{
+ struct dmaengine_priv *dmae = host->dma_priv;
+ struct dmaengine_next *nd = &dmae->next_data;
+
+ if (!dmaengine_prep_next(host, data))
+ data->host_cookie = ++nd->cookie < 0 ? 1 : nd->cookie;
+}
+
+static void dmaengine_post_req(struct mmci_host *host,
+ struct mmc_data *data, int err)
+{
+ struct dmaengine_priv *dmae = host->dma_priv;
+
+ dmaengine_unmap(host, data);
+
+ if (err) {
+ struct dmaengine_next *next = &dmae->next_data;
+ struct dma_chan *chan;
+
+ if (data->flags & MMC_DATA_READ)
+ chan = dmae->dma_rx_channel;
+ else
+ chan = dmae->dma_tx_channel;
+ dmaengine_terminate_all(chan);
+
+ if (dmae->dma_desc_current == next->dma_desc)
+ dmae->dma_desc_current = NULL;
+
+ if (dmae->dma_current == next->dma_chan) {
+ dmae->dma_in_progress = false;
+ dmae->dma_current = NULL;
+ }
+
+ next->dma_desc = NULL;
+ next->dma_chan = NULL;
+ data->host_cookie = 0;
+ }
+}
+
+struct mmci_dma_ops dmaengine = {
+ .setup = dmaengine_setup,
+ .release = dmaengine_release,
+ .pre_req = dmaengine_pre_req,
+ .start = dmaengine_start,
+ .finalize = dmaengine_finalize,
+ .post_req = dmaengine_post_req,
+ .error = dmaengine_error,
+ .get_next_data = dmaengine_get_next_data,
+};
+#else
+struct mmci_dma_ops dmaengine = {};
+#endif
diff --git a/drivers/mmc/host/mmci_dma.h b/drivers/mmc/host/mmci_dma.h
new file mode 100644
index 0000000..33e4e8a
--- /dev/null
+++ b/drivers/mmc/host/mmci_dma.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: Ludovic.barre at st.com for STMicroelectronics.
+ */
+#ifndef __MMC_DMA_H__
+#define __MMC_DMA_H__
+
+struct mmci_dma_ops {
+ int (*setup)(struct mmci_host *host);
+ void (*release)(struct mmci_host *host);
+ void (*pre_req)(struct mmci_host *host, struct mmc_data *data);
+ int (*start)(struct mmci_host *host, unsigned int datactrl);
+ void (*finalize)(struct mmci_host *host, struct mmc_data *data);
+ void (*post_req)(struct mmci_host *host,
+ struct mmc_data *data, int err);
+ void (*error)(struct mmci_host *host);
+ void (*get_next_data)(struct mmci_host *host, struct mmc_data *data);
+};
+
+int mmci_dma_setup(struct mmci_host *host);
+int mmci_dma_start(struct mmci_host *host, unsigned int datactrl);
+void mmci_dma_release(struct mmci_host *host);
+void mmci_dma_pre_req(struct mmci_host *host, struct mmc_data *data);
+void mmci_dma_finalize(struct mmci_host *host, struct mmc_data *data);
+void mmci_dma_post_req(struct mmci_host *host,
+ struct mmc_data *data, int err);
+void mmci_dma_error(struct mmci_host *host);
+void mmci_dma_get_next_data(struct mmci_host *host, struct mmc_data *data);
+
+#endif /* __MMC_DMA_H__ */
--
2.7.4
^ permalink raw reply related
* [PATCH 00/19] mmc: mmci: add stm32 sdmmc variant
From: Ludovic Barre @ 2018-06-12 13:14 UTC (permalink / raw)
To: linux-arm-kernel
From: Ludovic Barre <ludovic.barre@st.com>
This patch series adapts mmci driver to add support for stm32
sdmmc variant. stm32h7 SoC integrates the first revision of
stm32 sdmmc.
This series is composed of 3 parts:
-Prepare mmci driver to manage dma interfaces by adding property.
New mmci dma API is defined according to the legacy needs.
-Adapt mmci driver to dedicated constraints of stm32 sdmmc variant,
defined under some specific properties.
-Add stm32 sdmmc variant. As Internal DMA way satisfies data
transfer, the mmci driver hasn't been modified for pio_read/write.
Specific adds-ons to stm32 sdmmc:
+ registers
+ clk/power functions
+ idma interface
Ludovic Barre (19):
mmc: mmci: regroup and define dma operations
mmc: mmci: merge qcom dml feature into mmci dma
mmc: mmci: add datactrl block size variant property
mmc: mmci: expand startbiterr to irqmask and error check
mmc: mmci: allow to overwrite clock/power procedure to specific
variant
mmc: mmci: add variant properties to define cpsm & cmdresp bits
mmc: mmci: add variant property to define dpsm bit
mmc: mmci: add variant property to define irq pio mask
mmc: mmci: add variant property to write datactrl before command
mmc: mmci: add variant property to allow remain data
mmc: mmci: add variant property to check specific data constraint
mmc: mmci: add variant property to request a reset
mmc: mmci: send stop cmd if a data command fail
mmc: mmci: add clock divider for stm32 sdmmc
mmc: mmci: add stm32 sdmmc registers
mmc: mmci: add DT bindings for STM32 sdmmc
mmc: mmci: add stm32 sdmmc idma support
mmc: mmci: add specific clk/pwr procedure for stm32 sdmmc
mmc: mmci: add stm32 sdmmc variant
Documentation/devicetree/bindings/mmc/mmci.txt | 11 +
drivers/mmc/host/Makefile | 3 +-
drivers/mmc/host/mmci.c | 846 +++++++++++--------------
drivers/mmc/host/mmci.h | 237 ++++++-
drivers/mmc/host/mmci_dma.c | 780 +++++++++++++++++++++++
drivers/mmc/host/mmci_dma.h | 33 +
drivers/mmc/host/mmci_qcom_dml.c | 177 ------
drivers/mmc/host/mmci_qcom_dml.h | 31 -
8 files changed, 1410 insertions(+), 708 deletions(-)
create mode 100644 drivers/mmc/host/mmci_dma.c
create mode 100644 drivers/mmc/host/mmci_dma.h
delete mode 100644 drivers/mmc/host/mmci_qcom_dml.c
delete mode 100644 drivers/mmc/host/mmci_qcom_dml.h
--
2.7.4
^ permalink raw reply
* [PATCH RESEND v4 2/2] arm/arm64: KVM: Add KVM_GET/SET_VCPU_EVENTS
From: gengdongjiu @ 2018-06-12 13:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <86zi04875t.wl-marc.zyngier@arm.com>
Hi Marc
thanks for the review.
On 2018/6/9 20:40, Marc Zyngier wrote:
> On Fri, 08 Jun 2018 20:48:40 +0100,
> Dongjiu Geng wrote:
>>
>> For the migrating VMs, user space may need to know the exception
>> state. For example, in the machine A, KVM make an SError pending,
>> when migrate to B, KVM also needs to pend an SError.
>>
>> This new IOCTL exports user-invisible states related to SError.
>> Together with appropriate user space changes, user space can get/set
>> the SError exception state to do migrate/snapshot/suspend.
>>
>> Signed-off-by: Dongjiu Geng <gengdongjiu@huawei.com>
>> ---
>> change since v3:
>> 1. Fix the memset() issue in the kvm_arm_vcpu_get_events()
>>
>> change since v2:
>> 1. Add kvm_vcpu_events structure definition for arm platform to avoid the build errors.
>>
>> change since v1:
>> Address Marc's comments, thanks Marc's review
>> 1. serror_has_esr always true when ARM64_HAS_RAS_EXTN is set
>> 2. remove Spurious blank line in kvm_arm_vcpu_set_events()
>> 3. rename pend_guest_serror() to kvm_set_sei_esr()
>> 4. Make kvm_arm_vcpu_get_events() did all the work rather than having this split responsibility.
>> 5. using sizeof(events) instead of sizeof(struct kvm_vcpu_events)
>>
>> this series patch is separated from https://www.spinics.net/lists/kvm/msg168917.html
>> The user space patch is here: https://lists.gnu.org/archive/html/qemu-devel/2018-05/msg06965.html
>>
>> change since V12:
>> 1. change (vcpu->arch.hcr_el2 & HCR_VSE) to !!(vcpu->arch.hcr_el2 & HCR_VSE) in kvm_arm_vcpu_get_events()
>>
>> Change since V11:
>> Address James's comments, thanks James
>> 1. Align the struct of kvm_vcpu_events to 64 bytes
>> 2. Avoid exposing the stale ESR value in the kvm_arm_vcpu_get_events()
>> 3. Change variables 'injected' name to 'serror_pending' in the kvm_arm_vcpu_set_events()
>> 4. Change to sizeof(events) from sizeof(struct kvm_vcpu_events) in kvm_arch_vcpu_ioctl()
>>
>> Change since V10:
>> Address James's comments, thanks James
>> 1. Merge the helper function with the user.
>> 2. Move the ISS_MASK into pend_guest_serror() to clear top bits
>> 3. Make kvm_vcpu_events struct align to 4 bytes
>> 4. Add something check in the kvm_arm_vcpu_set_events()
>> 5. Check kvm_arm_vcpu_get/set_events()'s return value.
>> 6. Initialise kvm_vcpu_events to 0 so that padding transferred to user-space doesn't
>> contain kernel stack.
>> ---
>> Documentation/virtual/kvm/api.txt | 31 ++++++++++++++++++++++++++++---
>> arch/arm/include/asm/kvm_host.h | 6 ++++++
>> arch/arm/include/uapi/asm/kvm.h | 12 ++++++++++++
>> arch/arm/kvm/guest.c | 12 ++++++++++++
>> arch/arm64/include/asm/kvm_emulate.h | 5 +++++
>> arch/arm64/include/asm/kvm_host.h | 7 +++++++
>> arch/arm64/include/uapi/asm/kvm.h | 13 +++++++++++++
>> arch/arm64/kvm/guest.c | 36 ++++++++++++++++++++++++++++++++++++
>> arch/arm64/kvm/inject_fault.c | 6 +++---
>> arch/arm64/kvm/reset.c | 1 +
>> virt/kvm/arm/arm.c | 19 +++++++++++++++++++
>> 11 files changed, 142 insertions(+), 6 deletions(-)
>>
>> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
>> index fdac969..8896737 100644
>> --- a/Documentation/virtual/kvm/api.txt
>> +++ b/Documentation/virtual/kvm/api.txt
>> @@ -835,11 +835,13 @@ struct kvm_clock_data {
>>
>> Capability: KVM_CAP_VCPU_EVENTS
>> Extended by: KVM_CAP_INTR_SHADOW
>> -Architectures: x86
>> +Architectures: x86, arm, arm64
>> Type: vm ioctl
>> Parameters: struct kvm_vcpu_event (out)
>> Returns: 0 on success, -1 on error
>>
>> +X86:
>> +
>> Gets currently pending exceptions, interrupts, and NMIs as well as related
>> states of the vcpu.
>>
>> @@ -881,15 +883,32 @@ Only two fields are defined in the flags field:
>> - KVM_VCPUEVENT_VALID_SMM may be set in the flags field to signal that
>> smi contains a valid state.
>>
>> +ARM, ARM64:
>> +
>> +Gets currently pending SError exceptions as well as related states of the vcpu.
>> +
>> +struct kvm_vcpu_events {
>> + struct {
>> + __u8 serror_pending;
>> + __u8 serror_has_esr;
>> + /* Align it to 8 bytes */
>> + __u8 pad[6];
>> + __u64 serror_esr;
>> + } exception;
>> + __u32 reserved[12];
>> +};
>> +
>> 4.32 KVM_SET_VCPU_EVENTS
>>
>> -Capability: KVM_CAP_VCPU_EVENTS
>> +Capebility: KVM_CAP_VCPU_EVENTS
>> Extended by: KVM_CAP_INTR_SHADOW
>> -Architectures: x86
>> +Architectures: x86, arm, arm64
>> Type: vm ioctl
>> Parameters: struct kvm_vcpu_event (in)
>> Returns: 0 on success, -1 on error
>>
>> +X86:
>> +
>> Set pending exceptions, interrupts, and NMIs as well as related states of the
>> vcpu.
>>
>> @@ -910,6 +929,12 @@ shall be written into the VCPU.
>>
>> KVM_VCPUEVENT_VALID_SMM can only be set if KVM_CAP_X86_SMM is available.
>>
>> +ARM, ARM64:
>> +
>> +Set pending SError exceptions as well as related states of the vcpu.
>> +
>> +See KVM_GET_VCPU_EVENTS for the data structure.
>> +
>>
>> 4.33 KVM_GET_DEBUGREGS
>>
>> diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
>> index c7c28c8..39f9901 100644
>> --- a/arch/arm/include/asm/kvm_host.h
>> +++ b/arch/arm/include/asm/kvm_host.h
>> @@ -213,6 +213,12 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);
>> int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
>> int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
>> int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
>> +int kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu,
>> + struct kvm_vcpu_events *events);
>> +
>> +int kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,
>> + struct kvm_vcpu_events *events);
>> +
>> unsigned long kvm_call_hyp(void *hypfn, ...);
>> void force_vm_exit(const cpumask_t *mask);
>>
>> diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
>> index caae484..c3e6975 100644
>> --- a/arch/arm/include/uapi/asm/kvm.h
>> +++ b/arch/arm/include/uapi/asm/kvm.h
>> @@ -124,6 +124,18 @@ struct kvm_sync_regs {
>> struct kvm_arch_memory_slot {
>> };
>>
>> +/* for KVM_GET/SET_VCPU_EVENTS */
>> +struct kvm_vcpu_events {
>> + struct {
>> + __u8 serror_pending;
>> + __u8 serror_has_esr;
>> + /* Align it to 8 bytes */
>> + __u8 pad[6];
>> + __u64 serror_esr;
>> + } exception;
>> + __u32 reserved[12];
>> +};
>> +
>> /* If you need to interpret the index values, here is the key: */
>> #define KVM_REG_ARM_COPROC_MASK 0x000000000FFF0000
>> #define KVM_REG_ARM_COPROC_SHIFT 16
>> diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c
>> index a18f33e..c685f0e 100644
>> --- a/arch/arm/kvm/guest.c
>> +++ b/arch/arm/kvm/guest.c
>> @@ -261,6 +261,18 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
>> return -EINVAL;
>> }
>>
>> +int kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu,
>> + struct kvm_vcpu_events *events)
>> +{
>> + return -EINVAL;
>> +}
>> +
>> +int kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,
>> + struct kvm_vcpu_events *events)
>> +{
>> + return -EINVAL;
>> +}
>> +
>> int __attribute_const__ kvm_target_cpu(void)
>> {
>> switch (read_cpuid_part()) {
>> diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
>> index 1dab3a9..18f61ff 100644
>> --- a/arch/arm64/include/asm/kvm_emulate.h
>> +++ b/arch/arm64/include/asm/kvm_emulate.h
>> @@ -81,6 +81,11 @@ static inline unsigned long *vcpu_hcr(struct kvm_vcpu *vcpu)
>> return (unsigned long *)&vcpu->arch.hcr_el2;
>> }
>>
>> +static inline unsigned long vcpu_get_vsesr(struct kvm_vcpu *vcpu)
>> +{
>> + return vcpu->arch.vsesr_el2;
>> +}
>> +
>> static inline void vcpu_set_vsesr(struct kvm_vcpu *vcpu, u64 vsesr)
>> {
>> vcpu->arch.vsesr_el2 = vsesr;
>> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
>> index 469de8a..357304a 100644
>> --- a/arch/arm64/include/asm/kvm_host.h
>> +++ b/arch/arm64/include/asm/kvm_host.h
>> @@ -335,6 +335,11 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);
>> int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
>> int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
>> int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
>> +int kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu,
>> + struct kvm_vcpu_events *events);
>> +
>> +int kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,
>> + struct kvm_vcpu_events *events);
>>
>> #define KVM_ARCH_WANT_MMU_NOTIFIER
>> int kvm_unmap_hva(struct kvm *kvm, unsigned long hva);
>> @@ -363,6 +368,8 @@ void handle_exit_early(struct kvm_vcpu *vcpu, struct kvm_run *run,
>> int kvm_perf_init(void);
>> int kvm_perf_teardown(void);
>>
>> +void kvm_set_sei_esr(struct kvm_vcpu *vcpu, u64 syndrome);
>> +
>> struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr);
>>
>> void __kvm_set_tpidr_el2(u64 tpidr_el2);
>> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
>> index 04b3256..df4faee 100644
>> --- a/arch/arm64/include/uapi/asm/kvm.h
>> +++ b/arch/arm64/include/uapi/asm/kvm.h
>> @@ -39,6 +39,7 @@
>> #define __KVM_HAVE_GUEST_DEBUG
>> #define __KVM_HAVE_IRQ_LINE
>> #define __KVM_HAVE_READONLY_MEM
>> +#define __KVM_HAVE_VCPU_EVENTS
>>
>> #define KVM_COALESCED_MMIO_PAGE_OFFSET 1
>>
>> @@ -153,6 +154,18 @@ struct kvm_sync_regs {
>> struct kvm_arch_memory_slot {
>> };
>>
>> +/* for KVM_GET/SET_VCPU_EVENTS */
>> +struct kvm_vcpu_events {
>> + struct {
>> + __u8 serror_pending;
>> + __u8 serror_has_esr;
>> + /* Align it to 8 bytes */
>> + __u8 pad[6];
>> + __u64 serror_esr;
>> + } exception;
>> + __u32 reserved[12];
>> +};
>> +
>> /* If you need to interpret the index values, here is the key: */
>> #define KVM_REG_ARM_COPROC_MASK 0x000000000FFF0000
>> #define KVM_REG_ARM_COPROC_SHIFT 16
>> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
>> index 56a0260..4426915 100644
>> --- a/arch/arm64/kvm/guest.c
>> +++ b/arch/arm64/kvm/guest.c
>> @@ -289,6 +289,42 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
>> return -EINVAL;
>> }
>>
>> +int kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu,
>> + struct kvm_vcpu_events *events)
>> +{
>> + memset(events, 0, sizeof(*events));
>> +
>> + events->exception.serror_pending = !!(vcpu->arch.hcr_el2 & HCR_VSE);
>> + events->exception.serror_has_esr =
>> + cpus_have_const_cap(ARM64_HAS_RAS_EXTN);
>> +
>> + if (events->exception.serror_pending &&
>> + events->exception.serror_has_esr)
>> + events->exception.serror_esr = vcpu_get_vsesr(vcpu);
>> + else
>> + events->exception.serror_esr = 0;
>
> Other than the alignment issues that Christoffer already commented on,
> you can perfectly remove the "else" clause altogether (we've just
> zeroed the whole structure).
yes, you are right. it should be moved, thanks for the pointing out.
>
>> +
>> + return 0;
>> +}
>> +
>> +int kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,
>> + struct kvm_vcpu_events *events)
>> +{
>> + bool serror_pending = events->exception.serror_pending;
>> + bool has_esr = events->exception.serror_has_esr;
>> +
>> + if (serror_pending && has_esr) {
>> + if (!cpus_have_const_cap(ARM64_HAS_RAS_EXTN))
>> + return -EINVAL;
>> +
>> + kvm_set_sei_esr(vcpu, events->exception.serror_esr);
>> + } else if (serror_pending) {
>> + kvm_inject_vabt(vcpu);
>> + }
>> +
>> + return 0;
>
> There was an earlier request to check that all the padding is set to
> zero. I still think this makes sense.
previously I think it may be not needed to check that all the padding is set to
zero. so not added it. but now I consider it again, it should be make sense to check that.
so I will added them. thanks for the mention again.
>
> Thanks,
>
> M.
>
^ permalink raw reply
* [GIT PULL 2/4] ARM: Device-tree updates
From: Heiko Stuebner @ 2018-06-12 13:04 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CA+55aFy2sOHqcO-6LaKOZ5omyAow15gq+=Z7aOTZisrDihoecw@mail.gmail.com>
Am Dienstag, 12. Juni 2018, 03:04:34 CEST schrieb Linus Torvalds:
> On Mon, Jun 11, 2018 at 5:02 PM Olof Johansson <olof@lixom.net> wrote:
> >
> > - Qualcomm:
> > + SDM845, a.k.a Snapdragon 845, an 4+4-core Kryo 385/845
> > (Cortex-A75/A55 derivative) SoC that's one of the current high-end
> > mobile SoCs.
> >
> > It's great to see mainline support for it. So far, you
> > can't do much with it, since a lot of peripherals are not yet in the
> > DTs but driver support for USB, GPU and other pieces are starting to
> > trickle in. This might end up being a well-supported SoC upstream if
> > the momentum keeps up.
>
> Isn't the Qualcomm 845 also the SoC in some of the new WARM laptops?
>
> I asked one person that had an older one (ASUS NovaGo - Qualcomm 835),
> and apparently you can actually disable secure boot on that thing and
> boot from USB.
>
> In other words, it might _actually_ act like a normal laptop.
>
> I'd love to have something that is actually a real honest-to-goodness
> ARM laptop finally. Are we getting at all close to that?
I guess the Samsung Chromebook Plus (Rockchip RK3399-based [branded
OP1 though]) also is somewhat close to that target - even with a nice
high-res display and everything except the 32kb BootRom being replaceable.
Of course Qualcomm-based devices have the Adreno/Freedreno bonus,
but even in that area we're seeing some progress for Mali (Midgard)
this year [0].
[0] https://rosenzweig.io/blog/a-moving-mesa-midgard-cube.html
^ permalink raw reply
* [PATCH v2 1/6] arm64: KVM: Add support for Stage-2 control of memory types and cacheability
From: Marc Zyngier @ 2018-06-12 12:55 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <6675e8b0-7c34-ce1f-99e2-1f63566b3426@arm.com>
On 31/05/18 13:38, Marc Zyngier wrote:
> On 31/05/18 12:49, Mark Rutland wrote:
>> On Wed, May 30, 2018 at 01:47:01PM +0100, Marc Zyngier wrote:
>>> Up to ARMv8.3, the combinaison of Stage-1 and Stage-2 attributes
>>> results in the strongest attribute of the two stages. This means
>>> that the hypervisor has to perform quite a lot of cache maintenance
>>> just in case the guest has some non-cacheable mappings around.
>>>
>>> ARMv8.4 solves this problem by offering a different mode (FWB) where
>>> Stage-2 has total control over the memory attribute (this is limited
>>> to systems where both I/O and instruction caches are coherent with
>>
>> s/caches/fetches/ -- the I-caches themselves aren't coherent with the
>> D-caches (or we could omit I-cache maintenance).
>>
>> i.e. this implies IDC, but not DIC.
>
> It may imply IDC behaviour, but not quite IDC itself. I agree, this
> looks dodgy. I've asked for clarification on the spec.
I've now received confirmation that FWB implies the IDC behaviour. It
doesn't guarantee that CTR_EL0.IDC will be set though, only that
CLIDR_EL1.LOU{U,IS} are both 0.
>
>>
>>> the dcache). This is achieved by having a different set of memory
>>> attributes in the page tables, and a new bit set in HCR_EL2.
>>>
>>> On such a system, we can then safely sidestep any form of dcache
>>> management.
>>>
>>> Acked-by: Catalin Marinas <catalin.marinas@arm.com>
>>> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
>>> ---
>>
>>> static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
>>> {
>>> @@ -268,7 +269,10 @@ static inline void __clean_dcache_guest_page(kvm_pfn_t pfn, unsigned long size)
>>> {
>>> void *va = page_address(pfn_to_page(pfn));
>>>
>>> - kvm_flush_dcache_to_poc(va, size);
>>> + if (!cpus_have_const_cap(ARM64_HAS_STAGE2_FWB))
>>> + kvm_flush_dcache_to_poc(va, size);
>>> + else
>>> + kvm_flush_dcache_to_pou(va, size);
>>> }
>>
>> Te commit message said instruction fetches were coherent, and that no
>> D-cache maintenance was necessary, so why do we need maintenance to the
>> PoU?
>
> That maintenance will be elided if we actually have IDC set. I'm happy
> to drop it once I have confirmation that we have an identical behaviour.
Given the above, I'll drop the clean to PoU.
>
>>
>>> +static void cpu_has_fwb(const struct arm64_cpu_capabilities *__unused)
>>> +{
>>> + u64 val = read_sysreg_s(SYS_CLIDR_EL1);
>>> +
>>> + /* Check that CLIDR_EL1.LOU{U,IS} are both 0 */
>>> + WARN_ON(val & (7 << 27 | 7 << 21));
>>> +}
>>
>> What about CTR_EL0.IDC?
>
> Again, that depends on whether FWB implies IDC or not.
The spec doesn't seem to guarantee IDC, but does mandate that
CLIDR_EL1.LOU{U,IS} are set 0.
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply
* [PATCH RESEND v4 2/2] arm/arm64: KVM: Add KVM_GET/SET_VCPU_EVENTS
From: gengdongjiu @ 2018-06-12 12:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180609111745.GJ5097@C02W217FHV2R.local>
Christoffer,
Thanks for the review.
On 2018/6/9 19:17, Christoffer Dall wrote:
> On Sat, Jun 09, 2018 at 03:48:40AM +0800, Dongjiu Geng wrote:
>> For the migrating VMs, user space may need to know the exception
>> state. For example, in the machine A, KVM make an SError pending,
>> when migrate to B, KVM also needs to pend an SError.
>>
>> This new IOCTL exports user-invisible states related to SError.
>> Together with appropriate user space changes, user space can get/set
>> the SError exception state to do migrate/snapshot/suspend.
>>
>> Signed-off-by: Dongjiu Geng <gengdongjiu@huawei.com>
>> ---
>> change since v3:
>> 1. Fix the memset() issue in the kvm_arm_vcpu_get_events()
>>
>> change since v2:
>> 1. Add kvm_vcpu_events structure definition for arm platform to avoid the build errors.
>>
>> change since v1:
>> Address Marc's comments, thanks Marc's review
>> 1. serror_has_esr always true when ARM64_HAS_RAS_EXTN is set
>> 2. remove Spurious blank line in kvm_arm_vcpu_set_events()
>> 3. rename pend_guest_serror() to kvm_set_sei_esr()
>> 4. Make kvm_arm_vcpu_get_events() did all the work rather than having this split responsibility.
>> 5. using sizeof(events) instead of sizeof(struct kvm_vcpu_events)
>>
>> this series patch is separated from https://www.spinics.net/lists/kvm/msg168917.html
>> The user space patch is here: https://lists.gnu.org/archive/html/qemu-devel/2018-05/msg06965.html
>>
>> change since V12:
>> 1. change (vcpu->arch.hcr_el2 & HCR_VSE) to !!(vcpu->arch.hcr_el2 & HCR_VSE) in kvm_arm_vcpu_get_events()
>>
>> Change since V11:
>> Address James's comments, thanks James
>> 1. Align the struct of kvm_vcpu_events to 64 bytes
>> 2. Avoid exposing the stale ESR value in the kvm_arm_vcpu_get_events()
>> 3. Change variables 'injected' name to 'serror_pending' in the kvm_arm_vcpu_set_events()
>> 4. Change to sizeof(events) from sizeof(struct kvm_vcpu_events) in kvm_arch_vcpu_ioctl()
>>
>> Change since V10:
>> Address James's comments, thanks James
>> 1. Merge the helper function with the user.
>> 2. Move the ISS_MASK into pend_guest_serror() to clear top bits
>> 3. Make kvm_vcpu_events struct align to 4 bytes
>> 4. Add something check in the kvm_arm_vcpu_set_events()
>> 5. Check kvm_arm_vcpu_get/set_events()'s return value.
>> 6. Initialise kvm_vcpu_events to 0 so that padding transferred to user-space doesn't
>> contain kernel stack.
>> ---
>> Documentation/virtual/kvm/api.txt | 31 ++++++++++++++++++++++++++++---
>> arch/arm/include/asm/kvm_host.h | 6 ++++++
>> arch/arm/include/uapi/asm/kvm.h | 12 ++++++++++++
>> arch/arm/kvm/guest.c | 12 ++++++++++++
>> arch/arm64/include/asm/kvm_emulate.h | 5 +++++
>> arch/arm64/include/asm/kvm_host.h | 7 +++++++
>> arch/arm64/include/uapi/asm/kvm.h | 13 +++++++++++++
>> arch/arm64/kvm/guest.c | 36 ++++++++++++++++++++++++++++++++++++
>> arch/arm64/kvm/inject_fault.c | 6 +++---
>> arch/arm64/kvm/reset.c | 1 +
>> virt/kvm/arm/arm.c | 19 +++++++++++++++++++
>> 11 files changed, 142 insertions(+), 6 deletions(-)
>>
>> diff --git a/Documentation/virtual/kvm/api.txt b/Documentation/virtual/kvm/api.txt
>> index fdac969..8896737 100644
>> --- a/Documentation/virtual/kvm/api.txt
>> +++ b/Documentation/virtual/kvm/api.txt
>> @@ -835,11 +835,13 @@ struct kvm_clock_data {
>>
>> Capability: KVM_CAP_VCPU_EVENTS
>> Extended by: KVM_CAP_INTR_SHADOW
>> -Architectures: x86
>> +Architectures: x86, arm, arm64
>> Type: vm ioctl
>> Parameters: struct kvm_vcpu_event (out)
>> Returns: 0 on success, -1 on error
>>
>> +X86:
>> +
>> Gets currently pending exceptions, interrupts, and NMIs as well as related
>> states of the vcpu.
>>
>> @@ -881,15 +883,32 @@ Only two fields are defined in the flags field:
>> - KVM_VCPUEVENT_VALID_SMM may be set in the flags field to signal that
>> smi contains a valid state.
>>
>> +ARM, ARM64:
>> +
>> +Gets currently pending SError exceptions as well as related states of the vcpu.
>> +
>> +struct kvm_vcpu_events {
>> + struct {
>> + __u8 serror_pending;
>> + __u8 serror_has_esr;
>> + /* Align it to 8 bytes */
>> + __u8 pad[6];
>> + __u64 serror_esr;
>> + } exception;
>> + __u32 reserved[12];
>> +};
>> +
>> 4.32 KVM_SET_VCPU_EVENTS
>>
>> -Capability: KVM_CAP_VCPU_EVENTS
>> +Capebility: KVM_CAP_VCPU_EVENTS
>
> nit: unintended change?
>
>> Extended by: KVM_CAP_INTR_SHADOW
>> -Architectures: x86
>> +Architectures: x86, arm, arm64
>> Type: vm ioctl
>> Parameters: struct kvm_vcpu_event (in)
>> Returns: 0 on success, -1 on error
>>
>> +X86:
>> +
>> Set pending exceptions, interrupts, and NMIs as well as related states of the
>> vcpu.
>>
>> @@ -910,6 +929,12 @@ shall be written into the VCPU.
>>
>> KVM_VCPUEVENT_VALID_SMM can only be set if KVM_CAP_X86_SMM is available.
>>
>> +ARM, ARM64:
>> +
>> +Set pending SError exceptions as well as related states of the vcpu.
>> +
>> +See KVM_GET_VCPU_EVENTS for the data structure.
>> +
>>
>> 4.33 KVM_GET_DEBUGREGS
>>
>> diff --git a/arch/arm/include/asm/kvm_host.h b/arch/arm/include/asm/kvm_host.h
>> index c7c28c8..39f9901 100644
>> --- a/arch/arm/include/asm/kvm_host.h
>> +++ b/arch/arm/include/asm/kvm_host.h
>> @@ -213,6 +213,12 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);
>> int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
>> int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
>> int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
>> +int kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu,
>> + struct kvm_vcpu_events *events);
>> +
>> +int kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,
>> + struct kvm_vcpu_events *events);
>> +
>> unsigned long kvm_call_hyp(void *hypfn, ...);
>> void force_vm_exit(const cpumask_t *mask);
>>
>> diff --git a/arch/arm/include/uapi/asm/kvm.h b/arch/arm/include/uapi/asm/kvm.h
>> index caae484..c3e6975 100644
>> --- a/arch/arm/include/uapi/asm/kvm.h
>> +++ b/arch/arm/include/uapi/asm/kvm.h
>> @@ -124,6 +124,18 @@ struct kvm_sync_regs {
>> struct kvm_arch_memory_slot {
>> };
>>
>> +/* for KVM_GET/SET_VCPU_EVENTS */
>> +struct kvm_vcpu_events {
>> + struct {
>> + __u8 serror_pending;
>> + __u8 serror_has_esr;
>> + /* Align it to 8 bytes */
>> + __u8 pad[6];
>> + __u64 serror_esr;
>> + } exception;
>> + __u32 reserved[12];
>> +};
>> +
>> /* If you need to interpret the index values, here is the key: */
>> #define KVM_REG_ARM_COPROC_MASK 0x000000000FFF0000
>> #define KVM_REG_ARM_COPROC_SHIFT 16
>> diff --git a/arch/arm/kvm/guest.c b/arch/arm/kvm/guest.c
>> index a18f33e..c685f0e 100644
>> --- a/arch/arm/kvm/guest.c
>> +++ b/arch/arm/kvm/guest.c
>> @@ -261,6 +261,18 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
>> return -EINVAL;
>> }
>>
>> +int kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu,
>> + struct kvm_vcpu_events *events)
>> +{
>> + return -EINVAL;
>> +}
>> +
>> +int kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,
>> + struct kvm_vcpu_events *events)
>> +{
>> + return -EINVAL;
>> +}
>> +
>> int __attribute_const__ kvm_target_cpu(void)
>> {
>> switch (read_cpuid_part()) {
>> diff --git a/arch/arm64/include/asm/kvm_emulate.h b/arch/arm64/include/asm/kvm_emulate.h
>> index 1dab3a9..18f61ff 100644
>> --- a/arch/arm64/include/asm/kvm_emulate.h
>> +++ b/arch/arm64/include/asm/kvm_emulate.h
>> @@ -81,6 +81,11 @@ static inline unsigned long *vcpu_hcr(struct kvm_vcpu *vcpu)
>> return (unsigned long *)&vcpu->arch.hcr_el2;
>> }
>>
>> +static inline unsigned long vcpu_get_vsesr(struct kvm_vcpu *vcpu)
>> +{
>> + return vcpu->arch.vsesr_el2;
>> +}
>> +
>> static inline void vcpu_set_vsesr(struct kvm_vcpu *vcpu, u64 vsesr)
>> {
>> vcpu->arch.vsesr_el2 = vsesr;
>> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
>> index 469de8a..357304a 100644
>> --- a/arch/arm64/include/asm/kvm_host.h
>> +++ b/arch/arm64/include/asm/kvm_host.h
>> @@ -335,6 +335,11 @@ unsigned long kvm_arm_num_regs(struct kvm_vcpu *vcpu);
>> int kvm_arm_copy_reg_indices(struct kvm_vcpu *vcpu, u64 __user *indices);
>> int kvm_arm_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
>> int kvm_arm_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg);
>> +int kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu,
>> + struct kvm_vcpu_events *events);
>> +
>> +int kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,
>> + struct kvm_vcpu_events *events);
>>
>> #define KVM_ARCH_WANT_MMU_NOTIFIER
>> int kvm_unmap_hva(struct kvm *kvm, unsigned long hva);
>> @@ -363,6 +368,8 @@ void handle_exit_early(struct kvm_vcpu *vcpu, struct kvm_run *run,
>> int kvm_perf_init(void);
>> int kvm_perf_teardown(void);
>>
>> +void kvm_set_sei_esr(struct kvm_vcpu *vcpu, u64 syndrome);
>> +
>> struct kvm_vcpu *kvm_mpidr_to_vcpu(struct kvm *kvm, unsigned long mpidr);
>>
>> void __kvm_set_tpidr_el2(u64 tpidr_el2);
>> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
>> index 04b3256..df4faee 100644
>> --- a/arch/arm64/include/uapi/asm/kvm.h
>> +++ b/arch/arm64/include/uapi/asm/kvm.h
>> @@ -39,6 +39,7 @@
>> #define __KVM_HAVE_GUEST_DEBUG
>> #define __KVM_HAVE_IRQ_LINE
>> #define __KVM_HAVE_READONLY_MEM
>> +#define __KVM_HAVE_VCPU_EVENTS
>>
>> #define KVM_COALESCED_MMIO_PAGE_OFFSET 1
>>
>> @@ -153,6 +154,18 @@ struct kvm_sync_regs {
>> struct kvm_arch_memory_slot {
>> };
>>
>> +/* for KVM_GET/SET_VCPU_EVENTS */
>> +struct kvm_vcpu_events {
>> + struct {
>> + __u8 serror_pending;
>> + __u8 serror_has_esr;
>> + /* Align it to 8 bytes */
>> + __u8 pad[6];
>> + __u64 serror_esr;
>> + } exception;
>> + __u32 reserved[12];
>> +};
>> +
>> /* If you need to interpret the index values, here is the key: */
>> #define KVM_REG_ARM_COPROC_MASK 0x000000000FFF0000
>> #define KVM_REG_ARM_COPROC_SHIFT 16
>> diff --git a/arch/arm64/kvm/guest.c b/arch/arm64/kvm/guest.c
>> index 56a0260..4426915 100644
>> --- a/arch/arm64/kvm/guest.c
>> +++ b/arch/arm64/kvm/guest.c
>> @@ -289,6 +289,42 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
>> return -EINVAL;
>> }
>>
>> +int kvm_arm_vcpu_get_events(struct kvm_vcpu *vcpu,
>> + struct kvm_vcpu_events *events)
>> +{
>> + memset(events, 0, sizeof(*events));
>> +
>> + events->exception.serror_pending = !!(vcpu->arch.hcr_el2 & HCR_VSE);
>> + events->exception.serror_has_esr =
>> + cpus_have_const_cap(ARM64_HAS_RAS_EXTN);
>
> nit: no need to wrap this line so strangely, just keep it on a single
> line (regardless of going slightly over the 80 chars limit).
Ok, will fix it.
>
>> +
>> + if (events->exception.serror_pending &&
>> + events->exception.serror_has_esr)
>
> same here
OK, will fix it.
>
>> + events->exception.serror_esr = vcpu_get_vsesr(vcpu);
>> + else
>> + events->exception.serror_esr = 0;
>> +
>> + return 0;
>> +}
>> +
>> +int kvm_arm_vcpu_set_events(struct kvm_vcpu *vcpu,
>> + struct kvm_vcpu_events *events)
>> +{
>> + bool serror_pending = events->exception.serror_pending;
>> + bool has_esr = events->exception.serror_has_esr;
>> +
>> + if (serror_pending && has_esr) {
>> + if (!cpus_have_const_cap(ARM64_HAS_RAS_EXTN))
>> + return -EINVAL;
>> +
>> + kvm_set_sei_esr(vcpu, events->exception.serror_esr);
>> + } else if (serror_pending) {
>> + kvm_inject_vabt(vcpu);
>> + }
>> +
>> + return 0;
>> +}
>> +
>> int __attribute_const__ kvm_target_cpu(void)
>> {
>> unsigned long implementor = read_cpuid_implementor();
>> diff --git a/arch/arm64/kvm/inject_fault.c b/arch/arm64/kvm/inject_fault.c
>> index d8e7165..a55e91d 100644
>> --- a/arch/arm64/kvm/inject_fault.c
>> +++ b/arch/arm64/kvm/inject_fault.c
>> @@ -164,9 +164,9 @@ void kvm_inject_undefined(struct kvm_vcpu *vcpu)
>> inject_undef64(vcpu);
>> }
>>
>> -static void pend_guest_serror(struct kvm_vcpu *vcpu, u64 esr)
>> +void kvm_set_sei_esr(struct kvm_vcpu *vcpu, u64 esr)
>> {
>> - vcpu_set_vsesr(vcpu, esr);
>> + vcpu_set_vsesr(vcpu, esr & ESR_ELx_ISS_MASK);
>> *vcpu_hcr(vcpu) |= HCR_VSE;
>> }
>>
>> @@ -184,5 +184,5 @@ static void pend_guest_serror(struct kvm_vcpu *vcpu, u64 esr)
>> */
>> void kvm_inject_vabt(struct kvm_vcpu *vcpu)
>> {
>> - pend_guest_serror(vcpu, ESR_ELx_ISV);
>> + kvm_set_sei_esr(vcpu, ESR_ELx_ISV);
>> }
>> diff --git a/arch/arm64/kvm/reset.c b/arch/arm64/kvm/reset.c
>> index 38c8a64..20e919a 100644
>> --- a/arch/arm64/kvm/reset.c
>> +++ b/arch/arm64/kvm/reset.c
>> @@ -82,6 +82,7 @@ int kvm_arch_dev_ioctl_check_extension(struct kvm *kvm, long ext)
>> break;
>> case KVM_CAP_SET_GUEST_DEBUG:
>> case KVM_CAP_VCPU_ATTRIBUTES:
>> + case KVM_CAP_VCPU_EVENTS:
>> r = 1;
>> break;
>> default:
>> diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
>> index a4c1b76..79ecba9 100644
>> --- a/virt/kvm/arm/arm.c
>> +++ b/virt/kvm/arm/arm.c
>> @@ -1107,6 +1107,25 @@ long kvm_arch_vcpu_ioctl(struct file *filp,
>> r = kvm_arm_vcpu_has_attr(vcpu, &attr);
>> break;
>> }
>> + case KVM_GET_VCPU_EVENTS: {
>> + struct kvm_vcpu_events events;
>> +
>> + if (kvm_arm_vcpu_get_events(vcpu, &events))
>> + return -EINVAL;
>> +
>> + if (copy_to_user(argp, &events, sizeof(events)))
>> + return -EFAULT;
>> +
>> + return 0;
>> + }
>> + case KVM_SET_VCPU_EVENTS: {
>> + struct kvm_vcpu_events events;
>> +
>> + if (copy_from_user(&events, argp, sizeof(events)))
>> + return -EFAULT;
>> +
>> + return kvm_arm_vcpu_set_events(vcpu, &events);
>> + }
>> default:
>> r = -EINVAL;
>> }
>> --
>> 2.7.4
>>
>
> I'll leave it to James to comment on the specifics of the RAS
> interaction, but I think the two patches should be re-ordered, so that
> the capability patch comes last, after the functionality has been
> introduced.
ok, I will reorder them in the next version.
>
> Otherwise this looks reasonable enough.
>
> Thanks,
> -Christoffer
>
> .
>
^ permalink raw reply
* [PATCH v7 3/6] kernel/reboot.c: export pm_power_off_prepare
From: Oleksij Rempel @ 2018-06-12 12:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180517055014.6607-4-o.rempel@pengutronix.de>
Hi Rafael,
Last version of this patch was send at 17.05.2018. No other comment was
provided and this patch is a blocker for other patches in this serie.
Can you please give some feedback on it.
On 17.05.2018 07:50, Oleksij Rempel wrote:
> Export pm_power_off_prepare. It is needed to implement power off on
> Freescale/NXP iMX6 based boards with external power management
> integrated circuit (PMIC).
>
> Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de>
> ---
> kernel/reboot.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/kernel/reboot.c b/kernel/reboot.c
> index e4ced883d8de..83810d726f3e 100644
> --- a/kernel/reboot.c
> +++ b/kernel/reboot.c
> @@ -49,6 +49,7 @@ int reboot_force;
> */
>
> void (*pm_power_off_prepare)(void);
> +EXPORT_SYMBOL_GPL(pm_power_off_prepare);
>
> /**
> * emergency_restart - reboot the system
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180612/cf8a0197/attachment.sig>
^ permalink raw reply
* handling voice calls in ALSA soc (on Droid 4)
From: Pavel Machek @ 2018-06-12 12:18 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180611121548.GB11580@sirena.org.uk>
Hi!
Sebastian, would you have pointer to original Motorola sources you
used for inspiration?
> > With setup like that, how does userland tell kernel that the baseband
> > <-> microphone/speaker connection should be activated?
>
> Audio routing should be done as normal, and ideally the driver for the
> modem will be able to figure out if there's an active call or not. If
> userspace has to enable the input and output manually then you can set
> up SOC_DAPM_PIN_SWITCH()es as normal.
Modem talks AT commands, so the driver is in userspace for now.
I tried SOC_DAPM_PIN_SWITCH(), but it results in alsamixer oopsing, I
guess I'm doing something wrong.
Message from syslogd at devuan at Jun 12 13:51:31 ...
kernel:[ 743.678588] BUG: spinlock bad magic on CPU#1,
alsamixer/2217
Message from syslogd at devuan at Jun 12 13:51:31 ...
kernel:[ 743.684417] lock: 0xede423a0, .magic: eee2a6a4, .owner:
<none>/-1, .owner_cpu: -287136604
I'm trying to understand how it is supposed to work, but
https://www.alsa-project.org/main/index.php/DAPM has TODO's at
critical places. If there's better source of information, let me know.
Best regards,
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 181 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180612/2a174be2/attachment.sig>
^ permalink raw reply
* [PATCH v2] ARM: DTS: imx53: Add support for imx53 HSC/DDC boards from K+P
From: Lukasz Majewski @ 2018-06-12 11:28 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180611051357.GA16091@dragon>
Hi Shawn,
Thanks for you review.
> On Sat, May 19, 2018 at 02:15:06PM +0200, Lukasz Majewski wrote:
> > This commit provides support for HSC and DDC boards from
> > Kieback&Peter GmbH vendor.
> >
> > Signed-off-by: Lukasz Majewski <lukma@denx.de>
> > ---
> > Changes for v2:
> >
> > - Remove not needed #address-cells and #size-cells in
> > the gpio_buttons node to pass make W=1
> > - Rename button@{12} to button_{kalt|pwr} nodes to pass make W=1
> > - Include #include <dt-bindings/input/input.h> to use KEY_F6|F7
> > directly
> >
> > ---
> > arch/arm/boot/dts/Makefile | 2 +
> > arch/arm/boot/dts/imx53-kp-ddc.dts | 146
> > ++++++++++++++++++++++++++++ arch/arm/boot/dts/imx53-kp-hsc.dts |
> > 51 ++++++++++ arch/arm/boot/dts/imx53-kp.dtsi | 190
> > +++++++++++++++++++++++++++++++++++++ 4 files changed, 389
> > insertions(+) create mode 100644 arch/arm/boot/dts/imx53-kp-ddc.dts
> > create mode 100644 arch/arm/boot/dts/imx53-kp-hsc.dts
> > create mode 100644 arch/arm/boot/dts/imx53-kp.dtsi
> >
> > diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
> > index fbc04b0db781..00854a5b6ac4 100644
> > --- a/arch/arm/boot/dts/Makefile
> > +++ b/arch/arm/boot/dts/Makefile
> > @@ -360,6 +360,8 @@ dtb-$(CONFIG_SOC_IMX51) += \
> > dtb-$(CONFIG_SOC_IMX53) += \
> > imx53-ard.dtb \
> > imx53-cx9020.dtb \
> > + imx53-kp-ddc.dtb \
> > + imx53-kp-hsc.dtb \
> > imx53-m53evk.dtb \
> > imx53-mba53.dtb \
> > imx53-ppd.dtb \
> > diff --git a/arch/arm/boot/dts/imx53-kp-ddc.dts
> > b/arch/arm/boot/dts/imx53-kp-ddc.dts new file mode 100644
> > index 000000000000..acaf477a52c5
> > --- /dev/null
> > +++ b/arch/arm/boot/dts/imx53-kp-ddc.dts
> > @@ -0,0 +1,146 @@
> > +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> > +/*
> > + * Copyright 2018
> > + * Lukasz Majewski, DENX Software Engineering, lukma at denx.de
> > + */
> > +
> > +/dts-v1/;
> > +#include "imx53-kp.dtsi"
> > +
> > +/ {
> > + model = "K+P imx53 DDC";
> > + compatible = "kiebackpeter,imx53-ddc", "fsl,imx53";
> > +
> > + backlight_lcd: backlight {
> > + compatible = "pwm-backlight";
> > + pwms = <&pwm2 0 50000>;
> > + power-supply = <®_backlight>;
> > + brightness-levels = <0 24 28 32 36
> > + 40 44 48 52 56
> > + 60 64 68 72 76
> > + 80 84 88 92 96 100>;
> > + default-brightness-level = <20>;
> > + };
> > +
> > + lcd_display: disp1 {
>
> display for node node.
I assume that I shall change disp1 -> display ?
>
> > + compatible = "fsl,imx-parallel-display";
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > + interface-pix-fmt = "rgb24";
> > + pinctrl-names = "default";
> > + pinctrl-0 = <&pinctrl_disp>;
> > +
> > + port at 0 {
> > + reg = <0>;
> > +
> > + display1_in: endpoint {
> > + remote-endpoint = <&ipu_di1_disp1>;
> > + };
> > + };
> > +
> > + port at 1 {
> > + reg = <1>;
> > +
> > + lcd_display_out: endpoint {
> > + remote-endpoint = <&lcd_panel_in>;
> > + };
> > + };
> > + };
> > +
> > + lcd_panel: lcd-panel {
> > + compatible = "koe,tx14d24vm1bpa";
>
> Undefined compatible?
The display's in question "koe,tx14d24vm1bpa" compatible has been
ack'ed by Rob Herring and Thierry promised to apply it to his tree:
https://patchwork.kernel.org/patch/10391589/
The v2 of this patch:
https://patchwork.kernel.org/patch/10436007/
>
> > + backlight = <&backlight_lcd>;
> > + power-supply = <®_3v3>;
> > +
> > + port {
> > + lcd_panel_in: endpoint {
> > + remote-endpoint =
> > <&lcd_display_out>;
> > + };
> > + };
> > + };
> > +
> > + reg_backlight: regulator-backlight {
> > + compatible = "regulator-fixed";
> > + regulator-name = "backlight-supply";
> > + regulator-min-microvolt = <15000000>;
> > + regulator-max-microvolt = <15000000>;
> > + regulator-always-on;
> > + };
> > +};
> > +
> > +&i2c3 {
> > + adc at 48 {
> > + compatible = "ti,ads1015";
> > + reg = <0x48>;
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > +
> > + channel at 4 {
> > + reg = <4>;
> > + ti,gain = <2>;
> > + ti,datarate = <4>;
> > + };
> > +
> > + channel at 6 {
> > + reg = <6>;
> > + ti,gain = <2>;
> > + ti,datarate = <4>;
> > + };
> > + };
> > +
> > + gpio_expander2 at 21 {
>
> Use hyphen instead of underscore in node name.
Ok. I will change this globally. And send v3.
>
> > + compatible = "nxp,pcf8574";
> > + reg = <0x21>;
> > + interrupts = <109>;
> > + #gpio-cells = <2>;
> > + gpio-controller;
> > + };
> > +};
> > +
> > +&iomuxc {
> > + imx53-kp-ddc {
> > + pinctrl_disp: dispgrp {
> > + fsl,pins = <
> > +
> > MX53_PAD_EIM_A16__IPU_DI1_DISP_CLK 0x4
> > +
> > MX53_PAD_EIM_DA10__IPU_DI1_PIN15 0x4
> > +
> > MX53_PAD_EIM_DA9__IPU_DISP1_DAT_0 0x4
> > +
> > MX53_PAD_EIM_DA8__IPU_DISP1_DAT_1 0x4
> > +
> > MX53_PAD_EIM_DA7__IPU_DISP1_DAT_2 0x4
> > +
> > MX53_PAD_EIM_DA6__IPU_DISP1_DAT_3 0x4
> > +
> > MX53_PAD_EIM_DA5__IPU_DISP1_DAT_4 0x4
> > +
> > MX53_PAD_EIM_DA4__IPU_DISP1_DAT_5 0x4
> > +
> > MX53_PAD_EIM_DA3__IPU_DISP1_DAT_6 0x4
> > +
> > MX53_PAD_EIM_DA2__IPU_DISP1_DAT_7 0x4
> > +
> > MX53_PAD_EIM_DA1__IPU_DISP1_DAT_8 0x4
> > +
> > MX53_PAD_EIM_DA0__IPU_DISP1_DAT_9 0x4
> > +
> > MX53_PAD_EIM_EB1__IPU_DISP1_DAT_10 0x4
> > +
> > MX53_PAD_EIM_EB0__IPU_DISP1_DAT_11 0x4
> > +
> > MX53_PAD_EIM_A17__IPU_DISP1_DAT_12 0x4
> > +
> > MX53_PAD_EIM_A18__IPU_DISP1_DAT_13 0x4
> > +
> > MX53_PAD_EIM_A19__IPU_DISP1_DAT_14 0x4
> > +
> > MX53_PAD_EIM_A20__IPU_DISP1_DAT_15 0x4
> > +
> > MX53_PAD_EIM_A21__IPU_DISP1_DAT_16 0x4
> > +
> > MX53_PAD_EIM_A22__IPU_DISP1_DAT_17 0x4
> > +
> > MX53_PAD_EIM_A23__IPU_DISP1_DAT_18 0x4
> > +
> > MX53_PAD_EIM_A24__IPU_DISP1_DAT_19 0x4
> > +
> > MX53_PAD_EIM_D31__IPU_DISP1_DAT_20 0x4
> > +
> > MX53_PAD_EIM_D30__IPU_DISP1_DAT_21 0x4
> > +
> > MX53_PAD_EIM_D26__IPU_DISP1_DAT_22 0x4
> > +
> > MX53_PAD_EIM_D27__IPU_DISP1_DAT_23 0x4
> > + MX53_PAD_GPIO_1__PWM2_PWMO 0x4
> > + >;
> > + };
> > + };
> > +};
> > +
> > +&ipu_di1_disp1 {
> > + remote-endpoint = <&display1_in>;
> > +};
> > +
> > +&fec {
> > + status = "okay";
> > +};
>
> Sort the labeled nodes alphabetically in label name.
>
> > +
> > +&pmic {
> > + fsl,mc13xxx-uses-touch;
> > +};
> > diff --git a/arch/arm/boot/dts/imx53-kp-hsc.dts
> > b/arch/arm/boot/dts/imx53-kp-hsc.dts new file mode 100644
> > index 000000000000..d68cdd5da819
> > --- /dev/null
> > +++ b/arch/arm/boot/dts/imx53-kp-hsc.dts
> > @@ -0,0 +1,51 @@
> > +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> > +/*
> > + * Copyright 2018
> > + * Lukasz Majewski, DENX Software Engineering, lukma at denx.de
> > + */
> > +
> > +/dts-v1/;
> > +#include "imx53-kp.dtsi"
> > +
> > +/ {
> > + model = "K+P imx53 HSC";
> > + compatible = "kiebackpeter,imx53-hsc", "fsl,imx53";
> > +};
> > +
> > +&fec {
> > + status = "okay";
>
> Have a newline between property list and child node.
>
> > + fixed-link { /* RMII fixed link to LAN9303 */
> > + speed = <100>;
> > + full-duplex;
> > + };
> > +};
> > +
> > +&i2c3 {
> > + switch: switch at a {
> > + compatible = "smsc,lan9303-i2c";
> > + reg = <0xa>;
> > + reset-gpios = <&gpio7 6 GPIO_ACTIVE_LOW>;
> > + reset-duration = <400>;
> > +
> > + ports {
> > + #address-cells = <1>;
> > + #size-cells = <0>;
> > +
> > + port at 0 { /* RMII fixed link to master */
> > + reg = <0>;
> > + label = "cpu";
> > + ethernet = <&fec>;
> > + };
> > +
> > + port at 1 { /* external port 1 */
> > + reg = <1>;
> > + label = "lan1";
> > + };
> > +
> > + port at 2 { /* external port 2 */
> > + reg = <2>;
> > + label = "lan2";
> > + };
> > + };
> > + };
> > +};
> > diff --git a/arch/arm/boot/dts/imx53-kp.dtsi
> > b/arch/arm/boot/dts/imx53-kp.dtsi new file mode 100644
> > index 000000000000..f87266843842
> > --- /dev/null
> > +++ b/arch/arm/boot/dts/imx53-kp.dtsi
> > @@ -0,0 +1,190 @@
> > +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> > +/*
> > + * Copyright 2018
> > + * Lukasz Majewski, DENX Software Engineering, lukma at denx.de
> > + */
> > +
> > +/dts-v1/;
> > +#include "imx53-tqma53.dtsi"
> > +#include <dt-bindings/input/input.h>
> > +
> > +/ {
> > + buzzer {
> > + compatible = "pwm-beeper";
> > + pinctrl-names = "default";
> > + pinctrl-0 = <&pinctrl_buzzer>;
> > +
>
> Drop this newline.
>
> > + pwms = <&pwm1 0 500000>;
> > + };
> > +
> > + gpio_buttons {
>
> Use hyphen.
>
> > + compatible = "gpio-keys";
> > + pinctrl-names = "default";
> > + pinctrl-0 = <&pinctrl_gpiobuttons>;
> > +
> > + button_kalt {
>
> Ditto
>
> > + label = "Kaltstart";
> > + linux,code = <KEY_F6>;
> > + gpios = <&gpio2 26 GPIO_ACTIVE_HIGH>;
> > + };
> > +
> > + button_pwr {
>
> Ditto
>
> > + label = "PowerFailInterrupt";
> > + linux,code = <KEY_F7>;
> > + gpios = <&gpio3 22 GPIO_ACTIVE_HIGH>;
> > + };
> > + };
> > +
> > + leds {
> > + compatible = "gpio-leds";
> > + pinctrl-names = "default";
> > + pinctrl-0 = <&pinctrl_leds>;
> > +
> > + led_bus {
>
> Ditto
>
> > + label = "bus";
> > + gpios = <&gpio2 30 GPIO_ACTIVE_HIGH>;
> > + linux,default-trigger = "gpio";
> > + default-state = "off";
> > + };
> > +
> > + led_error {
>
> Ditto
>
> > + label = "error";
> > + gpios = <&gpio3 28 GPIO_ACTIVE_HIGH>;
> > + linux,default-trigger = "gpio";
> > + default-state = "off";
> > + };
> > +
> > + led_flash {
>
> Ditto
>
> > + label = "flash";
> > + gpios = <&gpio5 0 GPIO_ACTIVE_HIGH>;
> > + linux,default-trigger = "heartbeat";
> > + };
> > + };
> > +
> > + reg_3v3: regulator-3v3 {
> > + compatible = "regulator-fixed";
> > + regulator-name = "3V3";
> > + regulator-min-microvolt = <3300000>;
> > + regulator-max-microvolt = <3300000>;
> > + regulator-always-on;
> > + };
> > +};
> > +
> > +&can1 {
> > + status = "okay";
> > +};
> > +
> > +&can2 {
> > + status = "okay";
> > +};
> > +
> > +&i2c3 {
> > + status = "okay";
> > +
> > + gpio_expander1 at 22 {
>
> Ditto
>
> Shawn
>
> > + compatible = "nxp,pcf8574";
> > + reg = <0x22>;
> > + interrupts = <109>;
> > + #gpio-cells = <2>;
> > + gpio-controller;
> > + };
> > +
> > + rtc at 51 {
> > + compatible = "nxp,pcf8563";
> > + reg = <0x51>;
> > + };
> > +};
> > +
> > +&iomuxc {
> > + pinctrl-names = "default";
> > + pinctrl-0 = <&pinctrl_kp_common>;
> > +
> > + imx53-kp-common {
> > + pinctrl_buzzer: buzzergrp {
> > + fsl,pins = <
> > + MX53_PAD_SD1_DATA3__PWM1_PWMO 0x1e4
> > + >;
> > + };
> > +
> > + pinctrl_gpiobuttons: gpiobuttonsgrp {
> > + fsl,pins = <
> > + MX53_PAD_EIM_RW__GPIO2_26 0x1e4
> > + MX53_PAD_EIM_D22__GPIO3_22 0x1e4
> > + >;
> > + };
> > +
> > + pinctrl_kp_common: kpcommongrp {
> > + fsl,pins = <
> > + MX53_PAD_EIM_CS0__GPIO2_23 0x1e4
> > + MX53_PAD_GPIO_19__GPIO4_5 0x1e4
> > + MX53_PAD_PATA_DATA6__GPIO2_6 0x1e4
> > + MX53_PAD_PATA_DATA7__GPIO2_7 0xe0
> > + MX53_PAD_CSI0_DAT14__GPIO6_0 0x1e4
> > + MX53_PAD_CSI0_DAT16__GPIO6_2 0x1e4
> > + MX53_PAD_CSI0_DAT18__GPIO6_4 0x1e4
> > + MX53_PAD_EIM_D17__GPIO3_17 0x1e4
> > + MX53_PAD_EIM_D18__GPIO3_18 0x1e4
> > + MX53_PAD_EIM_D21__GPIO3_21 0x1e4
> > + MX53_PAD_EIM_D29__GPIO3_29 0x1e4
> > + MX53_PAD_EIM_DA11__GPIO3_11 0x1e4
> > + MX53_PAD_EIM_DA13__GPIO3_13 0x1e4
> > + MX53_PAD_EIM_DA14__GPIO3_14 0x1e4
> > + MX53_PAD_SD1_DATA0__GPIO1_16 0x1e4
> > + MX53_PAD_SD1_CMD__GPIO1_18 0x1e4
> > + MX53_PAD_SD1_CLK__GPIO1_20 0x1e4
> > + >;
> > + };
> > +
> > + pinctrl_leds: ledgrp {
> > + fsl,pins = <
> > + MX53_PAD_EIM_EB2__GPIO2_30 0x1d4
> > + MX53_PAD_EIM_D28__GPIO3_28 0x1d4
> > + MX53_PAD_EIM_WAIT__GPIO5_0 0x1d4
> > + >;
> > + };
> > +
> > + pinctrl_uart4: uart4grp {
> > + fsl,pins = <
> > + MX53_PAD_CSI0_DAT12__UART4_TXD_MUX
> > 0x1e4
> > + MX53_PAD_CSI0_DAT13__UART4_RXD_MUX
> > 0x1e4
> > + >;
> > + };
> > + };
> > +};
> > +
> > +&pinctrl_uart1 {
> > + fsl,pins = <
> > + MX53_PAD_EIM_D23__GPIO3_23 0x1e4
> > + MX53_PAD_EIM_EB3__GPIO2_31 0x1e4
> > + MX53_PAD_EIM_D24__GPIO3_24 0x1e4
> > + MX53_PAD_EIM_D25__GPIO3_25 0x1e4
> > + MX53_PAD_EIM_D19__GPIO3_19 0x1e4
> > + MX53_PAD_EIM_D20__GPIO3_20 0x1e4
> > + >;
> > +};
> > +
> > +&uart1 {
> > + status = "okay";
> > +};
> > +
> > +&uart2 {
> > + status = "okay";
> > +};
> > +
> > +&uart3 {
> > + status = "okay";
> > +};
> > +
> > +&uart4 {
> > + pinctrl-names = "default";
> > + pinctrl-0 = <&pinctrl_uart4>;
> > + status = "okay";
> > +};
> > +
> > +&usbh1 {
> > + status = "okay";
> > +};
> > +
> > +&usbphy0 {
> > + status = "disabled";
> > +};
> > --
> > 2.11.0
> >
Best regards,
Lukasz Majewski
--
DENX Software Engineering GmbH, Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 488 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180612/dbdb4b81/attachment-0001.sig>
^ permalink raw reply
* [PATCH v2] arm64: dma-mapping: clear buffers allocated with FORCE_CONTIGUOUS flag
From: Marek Szyprowski @ 2018-06-12 11:08 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CGME20180612110857eucas1p1f5e3b6d984d4fd7e3b3ce31418df546e@eucas1p1.samsung.com>
dma_alloc_*() buffers might be exposed to userspace via mmap() call, so
they should be cleared on allocation. In case of IOMMU-based dma-mapping
implementation such buffer clearing was missing in the code path for
DMA_ATTR_FORCE_CONTIGUOUS flag handling, because dma_alloc_from_contiguous()
doesn't honor __GFP_ZERO flag. This patch fixes this issue. For more
information on clearing buffers allocated by dma_alloc_* functions,
see commit 6829e274a623 ("arm64: dma-mapping: always clear allocated
buffers").
Fixes: 44176bb38fa4 ("arm64: Add support for DMA_ATTR_FORCE_CONTIGUOUS to IOMMU")
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
v2:
- fixed incorrect commit id in commit body (thanks to Geert)
- extended description with information that dma_alloc_from_contiguous()
lacks __GFP_ZERO support
---
arch/arm64/mm/dma-mapping.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
index 632d32109755..aa0037a3185f 100644
--- a/arch/arm64/mm/dma-mapping.c
+++ b/arch/arm64/mm/dma-mapping.c
@@ -629,13 +629,14 @@ static void *__iommu_alloc_attrs(struct device *dev, size_t size,
size >> PAGE_SHIFT);
return NULL;
}
- if (!coherent)
- __dma_flush_area(page_to_virt(page), iosize);
-
addr = dma_common_contiguous_remap(page, size, VM_USERMAP,
prot,
__builtin_return_address(0));
- if (!addr) {
+ if (addr) {
+ memset(addr, 0, size);
+ if (!coherent)
+ __dma_flush_area(page_to_virt(page), iosize);
+ } else {
iommu_dma_unmap_page(dev, *handle, iosize, 0, attrs);
dma_release_from_contiguous(dev, page,
size >> PAGE_SHIFT);
--
2.17.1
^ permalink raw reply related
* [GIT PULL 2/4] ARM: Device-tree updates
From: Kalle Valo @ 2018-06-12 10:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180612000142.28883-3-olof@lixom.net>
Olof Johansson <olof@lixom.net> writes:
> - Qualcomm:
> + SDM845, a.k.a Snapdragon 845, an 4+4-core Kryo 385/845
> (Cortex-A75/A55 derivative) SoC that's one of the current high-end
> mobile SoCs.
>
> It's great to see mainline support for it. So far, you
> can't do much with it, since a lot of peripherals are not yet in the
> DTs but driver support for USB, GPU and other pieces are starting to
> trickle in. This might end up being a well-supported SoC upstream if
> the momentum keeps up.
The wifi chip is called wcn3990 and we are working on supporting that in
ath10k. I'm hoping to get it ready for v4.19.
--
Kalle Valo
^ permalink raw reply
* [PATCH v2 2/5] dt: qcom: 8996: thermal: Move to DT initialisation
From: Amit Kucheria @ 2018-06-12 10:54 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cover.1528799892.git.amit.kucheria@linaro.org>
We also split up the regmap address space into two, one for the TM
registers, the other for the SROT registers. This was required to deal with
different address offsets for the TM and SROT registers across different
SoC families.
Since tsens-common.c/init_common() currently only registers one address space, the order is important (TM before SROT).This is OK since the code doesn't really use the SROT functionality yet.
Signed-off-by: Amit Kucheria <amit.kucheria@linaro.org>
---
arch/arm64/boot/dts/qcom/msm8996.dtsi | 12 +++++++++++-
drivers/thermal/qcom/tsens-8996.c | 1 -
2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/boot/dts/qcom/msm8996.dtsi b/arch/arm64/boot/dts/qcom/msm8996.dtsi
index 410ae78..b4aab18 100644
--- a/arch/arm64/boot/dts/qcom/msm8996.dtsi
+++ b/arch/arm64/boot/dts/qcom/msm8996.dtsi
@@ -451,7 +451,17 @@
tsens0: thermal-sensor at 4a8000 {
compatible = "qcom,msm8996-tsens";
- reg = <0x4a8000 0x2000>;
+ reg = <0x4a9000 0x1000>, /* TM */
+ <0x4a8000 0x1000>; /* SROT */
+ #qcom,sensors = <13>;
+ #thermal-sensor-cells = <1>;
+ };
+
+ tsens1: thermal-sensor at 4ac000 {
+ compatible = "qcom,msm8996-tsens";
+ reg = <0x4ad000 0x1000>, /* TM */
+ <0x4ac000 0x1000>; /* SROT */
+ #qcom,sensors = <8>;
#thermal-sensor-cells = <1>;
};
diff --git a/drivers/thermal/qcom/tsens-8996.c b/drivers/thermal/qcom/tsens-8996.c
index e1f7781..6e59078 100644
--- a/drivers/thermal/qcom/tsens-8996.c
+++ b/drivers/thermal/qcom/tsens-8996.c
@@ -79,6 +79,5 @@ static const struct tsens_ops ops_8996 = {
};
const struct tsens_data data_8996 = {
- .num_sensors = 13,
.ops = &ops_8996,
};
--
2.7.4
^ permalink raw reply related
* [PATCH v2 0/5] thermal: tsens: Prepare for version 2 of TSENS IP
From: Amit Kucheria @ 2018-06-12 10:54 UTC (permalink / raw)
To: linux-arm-kernel
This series is a mixed bag: Some code moves to deal with version 2 of the
TSENS IP in common functions, new platform support (sdm845), a cleanup
patch and a DT change to have a common way to deal with the SROT and TM
registers despite slightly different features across the IP family and
different register offsets.
I can merge the tsens-8996.c and tsens-sdm845.c files into a tsens-v2.c if
desired.
Changes since v1:
- Move get_temp() from tsens-8996 to tsens-common and rename
- Change 8996 DT entry to allow init_common() to work across sdm845 and
8996 due to different offsets
Amit Kucheria (5):
thermal: tsens: Get rid of unused fields in structure
dt: qcom: 8996: thermal: Move to DT initialisation
thermal: tsens: Move 8996 get_temp() to common code for reuse
thermal: tsens: Add support for SDM845
thermal: tsens: Check if we have valid data before reading
.../devicetree/bindings/thermal/qcom-tsens.txt | 1 +
arch/arm64/boot/dts/qcom/msm8996.dtsi | 12 +++-
drivers/thermal/qcom/Makefile | 2 +-
drivers/thermal/qcom/tsens-8996.c | 74 +-------------------
drivers/thermal/qcom/tsens-common.c | 78 +++++++++++++++++++---
drivers/thermal/qcom/tsens-sdm845.c | 15 +++++
drivers/thermal/qcom/tsens.c | 3 +
drivers/thermal/qcom/tsens.h | 8 ++-
8 files changed, 107 insertions(+), 86 deletions(-)
create mode 100644 drivers/thermal/qcom/tsens-sdm845.c
--
2.7.4
^ permalink raw reply
* [PATCH] pwm: stm32: fix build warning with CONFIG_DMA_ENGINE disabled
From: Arnd Bergmann @ 2018-06-12 10:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAMuHMdXJg0mYbs=e0QJMDb=A+bRbPsNF=TJzSumSjjOK3yJw2Q@mail.gmail.com>
On Tue, Jun 12, 2018 at 9:25 AM, Geert Uytterhoeven
<geert@linux-m68k.org> wrote:
>> --- a/drivers/pwm/pwm-stm32.c
>> +++ b/drivers/pwm/pwm-stm32.c
>> @@ -484,9 +484,7 @@ static int stm32_pwm_apply_locked(struct pwm_chip *chip, struct pwm_device *pwm,
>> static const struct pwm_ops stm32pwm_ops = {
>> .owner = THIS_MODULE,
>> .apply = stm32_pwm_apply_locked,
>> -#if IS_ENABLED(CONFIG_DMA_ENGINE)
>> - .capture = stm32_pwm_capture,
>> -#endif
>> + .capture = IS_ENABLED(CONFIG_DMA_ENGINE) ? stm32_pwm_capture : NULL,
>
> Cool, I didn't know IS_ENABLED() can be used in static initializers.
> I guess it's too late/much work to use this trick in e.g. SET_*_PM_OPS(),
> as there are lots of places protecting the functions by #ifdefs?
It's one of those things I've been planning to do for a long time, but as
you noticed, we can't just change the macro but have to come up with a
replacement that works without those #ifdefs. Unfortunately, nobody has
come up with a good /name/ for those macros, which is still the main blocker ;-)
Arnd
^ permalink raw reply
* [PATCH 10/20] dts: juno: Update coresight bindings for hw port
From: Sudeep Holla @ 2018-06-12 10:42 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CANLsYkxNakRGCWT6O0JRKz+N1OTU3-XreC_FiB8Fiv+jEoPEbQ@mail.gmail.com>
On Fri, Jun 08, 2018 at 03:52:58PM -0600, Mathieu Poirier wrote:
> On 8 June 2018 at 15:49, Mathieu Poirier <mathieu.poirier@linaro.org> wrote:
> > On Tue, Jun 05, 2018 at 10:43:21PM +0100, Suzuki K Poulose wrote:
> >> Switch to updated coresight bindings for hw ports.
> >>
> >> Cc: Sudeep Holla <sudeep.holla@arm.com>
> >> Cc: Liviu Dudau <liviu.dudau@arm.com>
> >> Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
> >> Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
> >> ---
> >> Changes since V1:
> >> - Add support Juno for r1 & r2.
> >> ---
> >
> > Reviewed-by: Mathieu Poirier <mathieu.poirier@linaro.org>
>
> Sudeep please hold on before applying this as there is more work to be
> done on this set.
>
Sure, I plan to apply the DT changes only after the driver changes are
queued by you or whichever tree it's channelled through. I was already
told the same to Suzuki.
--
Regards,
Sudeep
^ permalink raw reply
* [PATCH 0/4] Fix suspend resume on at91sam9261 and at91sam9263
From: Nicolas Ferre @ 2018-06-12 10:24 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180607084107.4461-1-alexandre.belloni@bootlin.com>
On 07/06/2018 at 10:41, Alexandre Belloni wrote:
> USB clock detection may not work properly on at91sam9261 and at91sam9263
> because they currently use the same bit mask as at91rm9200 instead of
> the one for at91sam9260.
>
> Take the opportunity to also change the PMC compatible strings for all
> the other SoCs in preparation for the new clock bindings.
>
> Alexandre Belloni (4):
> dt-bindings: arm: remove PMC bindings
> dt-bindings: clk: at91: Document all the PMC compatibles
> ARM: at91: fix USB clock detection handling
> ARM: dts: fix PMC compatible
To the whole series:
Acked-by: Nicolas Ferre <nicolas.ferre@microchip.com>
Thanks, best regards.
> .../devicetree/bindings/arm/atmel-pmc.txt | 14 --------------
> .../devicetree/bindings/clock/at91-clock.txt | 9 ++++-----
> arch/arm/boot/dts/at91sam9261.dtsi | 2 +-
> arch/arm/boot/dts/at91sam9263.dtsi | 2 +-
> arch/arm/boot/dts/at91sam9rl.dtsi | 2 +-
> arch/arm/boot/dts/sama5d4.dtsi | 2 +-
> arch/arm/mach-at91/pm.c | 5 +++++
> 7 files changed, 13 insertions(+), 23 deletions(-)
> delete mode 100644 Documentation/devicetree/bindings/arm/atmel-pmc.txt
>
--
Nicolas Ferre
^ permalink raw reply
* [PATCH] arm64/mm: Introduce a variable to hold base address of linear region
From: James Morse @ 2018-06-12 10:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CACi5LpNdg=Enp66BybNNuj5tQOp3ggyX=tm_SVzr8v2qCRteDw@mail.gmail.com>
Hi Bhupesh, Ard,
On 12/06/18 09:25, Bhupesh Sharma wrote:
> On Tue, Jun 12, 2018 at 12:23 PM, Ard Biesheuvel
> <ard.biesheuvel@linaro.org> wrote:
>> On 12 June 2018 at 08:36, Bhupesh Sharma <bhsharma@redhat.com> wrote:
>>> The start of the linear region map on a KASLR enabled ARM64 machine -
>>> which supports a compatible EFI firmware (with EFI_RNG_PROTOCOL
>>> support), is no longer correctly represented by the PAGE_OFFSET macro,
>>> since it is defined as:
>>>
>>> (UL(1) << (VA_BITS - 1)) + 1)
>> PAGE_OFFSET is the VA of the start of the linear map. The linear map
>> can be sparsely populated with actual memory, regardless of whether
>> KASLR is in effect or not. The only difference in the presence of
>> KASLR is that there may be such a hole at the beginning, but that does
>> not mean the linear map has moved, or that the value of PAGE_OFFSET is
>> now wrong.
>>> So taking an example of a platform with VA_BITS=48, this gives a static
>>> value of:
>>> PAGE_OFFSET = 0xffff800000000000
>>>
>>> However, for the KASLR case, we use the 'memstart_offset_seed'
>>> to randomize the linear region - since 'memstart_addr' indicates the
>>> start of physical RAM, we randomize the same on basis
>>> of 'memstart_offset_seed' value.
>>>
>>> As the PAGE_OFFSET value is used presently by several user space
>>> tools (for e.g. makedumpfile and crash tools) to determine the start
>>> of linear region and hence to read addresses (like PT_NOTE fields) from
>>> '/proc/kcore' for the non-KASLR boot cases, so it would be better to
>>> use 'memblock_start_of_DRAM()' value (converted to virtual) as
>>> the start of linear region for the KASLR cases and default to
>>> the PAGE_OFFSET value for non-KASLR cases to indicate the start of
>>> linear region.
>> Userland code that assumes that the linear map cannot have a hole at
>> the beginning should be fixed.
> That is a separate case (although that needs fixing as well via a
> kernel patch probably as the user-space tools rely on '/proc/iomem'
> contents to determine the first System RAM/reserved range).
This is for kexec-tools generating the kdump vmcore ELF headers in user-space?
> 1. In that particular case (see [1]) the EFI firmware sets the first
> EFI block as EfiReservedMemType:
>
> Region1: 0x000000000000-0x000000200000 [EfiReservedMemType]
> Region2: 0x000000200000-0x00000021fffff [EfiRuntimeServiceData]
>
> Since EFI firmware won't return the "EfiReservedMemType" memory to
> Linux kernel,
(Its linux that makes this choice in
drivers/firmware/efi/arm-init.c::is_usable_memory())
> so the kernel can't get any info about the first mem
> block, and kernel can only see region2 as below:
>
> efi: Processing EFI memory map:
> efi: 0x000000200000-0x00000021ffff [Runtime Data |RUN| | |
> | | | | |WB|WT|WC|UC]
>
> # head -1 /proc/iomem
> 00200000-0021ffff : reserved
>
> 2a. If we add debug prints to 'arch/arm64/mm/init.c' to print the
> kernel Virtual map we can see that the memory node is set to:
>
> # dmesg | grep memory
> ..........
> memory : 0xffff800000200000 - 0xffff801800000000
>
> 2b. Now if we use kexec-tools to obtain a crash vmcore we can see that
> if we use 'readelf' to get the last program Header from vmcore (logs
> below are for the non-kaslr case):
>
> # readelf -l vmcore
>
> ELF Header:
> ........................
>
> Program Headers:
> Type Offset VirtAddr PhysAddr
> FileSiz MemSiz Flags Align
> ..............................................................................................................................................................
> LOAD 0x0000000076d40000 0xffff80017fe00000 0x0000000180000000
> 0x0000001680000000 0x0000001680000000 RWE 0
>
> 3. So if we do a simple calculation:
>
> (VirtAddr + MemSiz) = 0xffff80017fe00000 + 0x0000001680000000 =
> 0xFFFF8017FFE00000 != 0xffff801800000000.
>
> which indicates that the end virtual memory nodes are not the same
> between vmlinux and vmcore.
If I've followed this properly: the problem is that to generate the ELF headers
in the post-kdump vmcore, at kdump-load-time kexec-tools has to guess the
virtual addresses of the 'System RAM' regions it can see in /proc/iomem.
The problem you are hitting is an invisible hole at the beginning of RAM,
meaning user-space's guess_phys_to_virt() is off by the size of this hole.
Isn't KASLR a special case for this? You must have to correct for that after
kdump has happened, based on an elf-note in the vmcore. Can't we always do this?
> This happens because the kexec-tools rely on 'proc/iomem' contents
> while 'memstart_addr' is computed as 0 by kernel (as value of
> memblock_start_of_DRAM() < ARM64_MEMSTART_ALIGN).
> Returning back to this patch, this is a generic requirement where we
> need the linear region start/base addresses in user-space applications
> which is used to read addresses which lie in the linear region (for
> e.g. when we read /proc/kcore contents).
>>> I tested this on my qualcomm (which supports EFI_RNG_PROTOCOL)
>>> and apm mustang (which does not support EFI_RNG_PROTOCOL) arm64 boards
>>> and was able to use a modified user space utility (like kexec-tools and
>>> makedumpfile) to determine the start of linear region correctly for
>>> both the KASLR and non-KASLR boot cases.
>>>
>>
>> Can you explain the nature of the changes to the userland code?
>
> The changes are not to rely on the fixed PAGE_OFFSET macro value for
> determining the base address of the linear region, but rather read the
> ' linear_reg_start_addr' symbol from kernel and use the same both in
> case of KASLR and non-KASLR boots to determine the base of the linear
> region (in [2], I have implemented a test change to kexec-tools to
> read the 'linear_reg_start_addr' symbol which is available on my
Don't use /dev/mem.
> public github tree, I have a similar change available in makedumpfile
> which I have not yet pushed to github, as it implements other features
> as well)
>>> diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
>>> index 49d99214f43c..bfd0915ecaf8 100644
>>> --- a/arch/arm64/include/asm/memory.h
>>> +++ b/arch/arm64/include/asm/memory.h
>>> @@ -178,6 +178,9 @@ extern s64 memstart_addr;
>>> /* PHYS_OFFSET - the physical address of the start of memory. */
>>> #define PHYS_OFFSET ({ VM_BUG_ON(memstart_addr & 1); memstart_addr; })
>>>
>>> +/* the virtual base of the linear region. */
>>> +extern s64 linear_reg_start_addr;
>>> +
>>> /* the virtual base of the kernel image (minus TEXT_OFFSET) */
>>> extern u64 kimage_vaddr;
>>>
>>> diff --git a/arch/arm64/kernel/arm64ksyms.c b/arch/arm64/kernel/arm64ksyms.c
>>> index d894a20b70b2..a92238ea45ff 100644
>>> --- a/arch/arm64/kernel/arm64ksyms.c
>>> +++ b/arch/arm64/kernel/arm64ksyms.c
>>> @@ -42,6 +42,7 @@ EXPORT_SYMBOL(__arch_copy_in_user);
>>>
>>> /* physical memory */
>>> EXPORT_SYMBOL(memstart_addr);
>>> +EXPORT_SYMBOL(linear_reg_start_addr);
>>>
>>> /* string / mem functions */
>>> EXPORT_SYMBOL(strchr);
>>> diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
>>> index 325cfb3b858a..29447adb0eef 100644
>>> --- a/arch/arm64/mm/init.c
>>> +++ b/arch/arm64/mm/init.c
>>> @@ -60,6 +60,7 @@
>>> * that cannot be mistaken for a real physical address.
>>> */
>>> s64 memstart_addr __ro_after_init = -1;
>>> +s64 linear_reg_start_addr __ro_after_init = PAGE_OFFSET;
>>> phys_addr_t arm64_dma_phys_limit __ro_after_init;
>>>
>>> #ifdef CONFIG_BLK_DEV_INITRD
>>> @@ -452,6 +453,8 @@ void __init arm64_memblock_init(void)
>>> }
>>> }
>>>
>>> + linear_reg_start_addr = __phys_to_virt(memblock_start_of_DRAM());
This patch adds a variable that nothing uses, its going to be removed. You can't
depend on reading this via /dev/mem.
Could you add the information you need as an elf-note to the vmcore instead? You
must already pick these up to handle kaslr. (from memory, this is where the
kaslr-offset is described to user-space after we kdump).
Thanks,
James
^ permalink raw reply
* [PATCH v2 4/7] Bluetooth: Add new quirk for non-persistent setup settings
From: Sean Wang @ 2018-06-12 9:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <DC3FE66E-C3FD-455F-8592-E927604086CD@holtmann.org>
On Wed, 2018-05-30 at 08:26 +0200, Marcel Holtmann wrote:
> Hi Sean,
>
> >>>>>>
[ ... ]
> >>> * Unknown packet (code 14 len 30) 0.641509
> >>> 01 00 00 00 02 00 01 0e 00 01 00 00 00 10 62 6c ..............bl
> >>> 75 65 74 6f 6f 74 68 64 00 00 00 00 00 00 uetoothd......
> >>> * Unknown packet (code 14 len 30) 0.641592
> >>> 02 00 00 00 02 00 01 0e 00 01 00 00 00 10 62 74 ..............bt
> >>> 6d 6f 6e 00 00 00 00 00 00 00 00 00 00 00 mon...........
> >>> * Unknown packet (code 16 len 7) [hci0] 6.536771
> >>> 01 00 00 00 05 00 01 .......
> >>> = Open Index: 00:00:46:76:22:01 [hci0] 6.717019
> >>> = Index Info: 00:00:46:76:22:01 (MediaTek, Inc.) [hci0] 6.717030
> >>
> >> can you try with the latest BlueZ 5.49 or git version. Seems it actually stumbles over the extra packet here. Fun fact is that I can not get a backtrace to pin-point the issue in btmon and why it crashes.
> >>
> >
> > I had less experience updating user land BlueZ, but I can try it as possible and see whether Unknown packets still are present at newest version BlueZ. Hopefully I don't misunderstand your point here.
>
> please use the latest btmon and check if it can read your trace.
>
sure, I'll have a try with the latest btmon.
> >>>> HCI Event: Unknown (0xe4) plen 5 [hci0] 6.741093
> >>> 02 01 01 00 00 .....
> >>>> HCI Event: Unknown (0xe4) plen 5 [hci0] 6.742088
> >>> 02 01 01 00 00 .....
> >>>> HCI Event: Unknown (0xe4) plen 5 [hci0] 6.743102
> >>> 02 01 01 00 00 .....
[ ... ]
> >>>> HCI Event: Unknown (0xe4) plen 5 [hci0] 6.814708
> >>> 02 01 01 00 00 .....
> >>>> HCI Event: Unknown (0xe4) plen 5 [hci0] 6.815705
> >>> 02 01 01 00 00 .....
> >>>> HCI Event: Unknown (0xe4) plen 5 [hci0] 6.816378
> >>> 02 01 01 00 00 .....
> >>
> >> Why do I see only HCI events here? Is this event conveying any useful information. It is kinda complicated that this is 0xe4 event code which is actually reserved for future use by the Bluetooth SIG. Are there any accompanying HCI commands for this and they just not make it into btmon?
> >>
> >
> > I have made all vendor HCI commands go through BlueZ core in v2 patch.
> >
> > And for these HCI events, they are all corresponding to vendor ACL data, applied only to firmware setup packets, but they're not being sent via BlueZ core, so they are not being logged in btmon.
> >
> > As for its event, where heading 0xe4 refers to a vendor event and is used on notification of that either vendor ACL data or vendor HCI command have been done.
>
> I would prefer if everything goes via the Bluetooth core since then we have it all properly scheduled. Sending things down the ACL data path however if kinda funky. Does your hardware accept sending command both via ACL data and as HCI command? If so, then I would prefer sending them as HCI commands since the speed improvement you think you are getting is neglectable on Linux (I have been down that path). This seems to be a pure optimization when Windows is driving the device.
>
firmware people said the device can support firmware download as HCI commands. According to my test, this way indeed works so I will improve the part in the next version.
> And the vendor event 0xe4 is really only received during firmware download? It is not ever received during normal operation?
>
0xe4 is only received during chip initialization.
I also thought 0xe4 is a poor definition for vendor event and already have notified firmware people should pick 0xff as its vendor event id in the future.
but for now, unfortunately, 0xe4 cannot be changed on the device, the only way is to add a workaround in RX path as below to allow btmon can recognize these bad events properly.
int mtk_btuart_hci_frame(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_event_hdr *hdr = (void *)skb->data;
/* Fix up the vendor event id with HCI_VENDOR_PKT instead of
* 0xe4 so that btmon can parse the kind of vendor event properly.
*/
if (hdr->evt == 0xe4)
hdr->evt = HCI_VENDOR_PKT;
/* Each HCI event would go through the core. */
return hci_recv_frame(hdev, skb);
}
> >
> >>
> >>
> >>> < HCI Command: Vendor (0x3f|0x006f) plen 5 [hci0] 6.816413
> >>> 01 07 01 00 04 .....
> >>>> HCI Event: Unknown (0xe4) plen 5 [hci0] 6.816536
> >>> 02 07 01 00 00 .....
[ ... ]
> >>> Encapsulated PDU
> >>> Erroneous Data Reporting
> >>> Non-flushable Packet Boundary Flag
> >>> Link Supervision Timeout Changed Event
> >>> Inquiry TX Power Level
> >>> Enhanced Power Control
> >>> Extended features
> >>> < HCI Command: Read Local Version Info.. (0x04|0x0001) plen 0 [hci0] 10.865987
> >>>> HCI Event: Vendor (0xff) plen 9 [hci0] 10.866259
> >>> 29 19 09 17 20 48 07 11 00 )... H?
> >>
> >> Is this meant to happen here?
> >>
> >
> > If event received is not expected as the specification defines, I think it's probably incorrect.
> >
> > But it requires more discussion with firmware people to make it clearer.
>
> Please check and let them decode what this event means.
>
it's just debugging purpose information listing built-time something
like that and will be removed in the firmware.
> >
> >>>> HCI Event: Command Complete (0x0e) plen 12 [hci0] 10.866372
> >>> Read Local Version Information (0x04|0x0001) ncmd 1
> >>> Status: Success (0x00)
> >>> HCI version: Bluetooth 4.2 (0x08) - Revision 4359 (0x1107)
> >>> LMP version: Bluetooth 4.2 (0x08) - Subversion 2329 (0x0919)
> >>> Manufacturer: MediaTek, Inc. (70)
> >>> < HCI Command: Read BD ADDR (0x04|0x0009) plen 0 [hci0] 10.866391
> >>>> HCI Event: Command Complete (0x0e) plen 10 [hci0] 10.866539
[ ... ]
> >>> LE Add Device To Resolving List (Octet 34 - Bit 3)
> >>> LE Remove Device From Resolving List (Octet 34 - Bit 4)
> >>> LE Clear Resolving List (Octet 34 - Bit 5)
> >>> LE Read Resolving List Size (Octet 34 - Bit 6)
> >>> LE Read Peer Resolvable Address (Octet 34 - Bit 7)
> >>> LE Read Local Resolvable Address (Octet 35 - Bit 0)
> >>> LE Set Address Resolution Enable (Octet 35 - Bit 1)
> >>> LE Set Resolvable Private Address Timeout (Octet 35 - Bit 2)
> >>> LE Read Maximum Data Length (Octet 35 - Bit 3)
> >>> Octet 35 - Bit 4
> >>> Octet 35 - Bit 5
> >>> Octet 35 - Bit 6
> >>> Octet 35 - Bit 7
> >>> Octet 36 - Bit 0
> >>
> >> So you support the PHY commands, but do not indicate support LE 2M or LE Coded? Also these are Bluetooth 5.0 commands.
> >>
> >
> > To be honest. When I ported the device into Bluez core, a unexpected event for LE read local feature would cause a fail at Bluez core, so I made a hack on Bluez core
> >
> > to allow that I can keeping bring up the device without be blocked by the issue most probably from firmware.
> >
> > Below code snippet is the only thing I added to avoid a fail at Bluez core to bring up the device.
> >
> > @@ -927,6 +927,8 @@ static void hci_cc_le_read_local_features(struct hci_dev *hdev,
> > return;
> >
> > memcpy(hdev->le_features, rp->features, 8);
> > + hdev->le_features[0] = 0;
> > + hdev->le_features[1] = 0;
> > }
>
> Send me the trace where you didn?t clear the feature bits and I check what is going on. I doubt that we have a bug, but maybe some of the commands are optional and we should add an appropriate check. Or you guys need to fix your firmware. A new btmon should decode all bits properly.
>
okay, I'll have a follow-up.
> Regards
>
> Marcel
>
^ permalink raw reply
* [PATCH 10/20] dts: juno: Update coresight bindings for hw port
From: Suzuki K Poulose @ 2018-06-12 9:50 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CANLsYkxNakRGCWT6O0JRKz+N1OTU3-XreC_FiB8Fiv+jEoPEbQ@mail.gmail.com>
On 08/06/18 22:52, Mathieu Poirier wrote:
> On 8 June 2018 at 15:49, Mathieu Poirier <mathieu.poirier@linaro.org> wrote:
>> On Tue, Jun 05, 2018 at 10:43:21PM +0100, Suzuki K Poulose wrote:
>>> Switch to updated coresight bindings for hw ports.
>>>
>>> Cc: Sudeep Holla <sudeep.holla@arm.com>
>>> Cc: Liviu Dudau <liviu.dudau@arm.com>
>>> Cc: Mathieu Poirier <mathieu.poirier@linaro.org>
>>> Signed-off-by: Suzuki K Poulose <suzuki.poulose@arm.com>
>>> ---
>>> Changes since V1:
>>> - Add support Juno for r1 & r2.
>>> ---
>>
>> Reviewed-by: Mathieu Poirier <mathieu.poirier@linaro.org>
>
> Sudeep please hold on before applying this as there is more work to be
> done on this set.
Mathieu,
I will wait for Rob / Frank to have a say on the bindings before I post the
next update.
Cheers
Suzuki
^ permalink raw reply
* [PATCH] arm64: make secondary_start_kernel() notrace
From: Suzuki K Poulose @ 2018-06-12 9:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1528794457-14129-1-git-send-email-zhizhouzhang@asrmicro.com>
On 12/06/18 10:07, Zhizhou Zhang wrote:
> We can't call function trace hook before setup percpu offset.
> When entering secondary_start_kernel(), percpu offset has not
> been initialized. So this lead hotplug malfunction.
> Here is the flow to reproduce this bug:
>
> echo 0 > /sys/devices/system/cpu/cpu1/online
> echo function > /sys/kernel/debug/tracing/current_tracer
> echo 1 > /sys/kernel/debug/tracing/tracing_on
> echo 1 > /sys/devices/system/cpu/cpu1/online
>
> Signed-off-by: Zhizhou Zhang <zhizhouzhang@asrmicro.com>
> ---
> arch/arm64/kernel/smp.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
> index f3e2e3ae..11b0f30 100644
> --- a/arch/arm64/kernel/smp.c
> +++ b/arch/arm64/kernel/smp.c
> @@ -179,7 +179,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
> * This is the secondary CPU boot entry. We're using this CPUs
> * idle thread stack, but a set of temporary page tables.
> */
> -asmlinkage void secondary_start_kernel(void)
> +notrace asmlinkage void secondary_start_kernel(void)
> {
> u64 mpidr = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
> struct mm_struct *mm = &init_mm;
>
Tested-by: Suzuki K Poulose <suzuki.poulose@arm.com>
I think this should go to stable releases as well.
Suzuki
^ permalink raw reply
* [PATCH] arm64: make secondary_start_kernel() notrace
From: Mark Rutland @ 2018-06-12 9:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1528794457-14129-1-git-send-email-zhizhouzhang@asrmicro.com>
On Tue, Jun 12, 2018 at 05:07:37PM +0800, Zhizhou Zhang wrote:
> We can't call function trace hook before setup percpu offset.
> When entering secondary_start_kernel(), percpu offset has not
> been initialized. So this lead hotplug malfunction.
> Here is the flow to reproduce this bug:
>
> echo 0 > /sys/devices/system/cpu/cpu1/online
> echo function > /sys/kernel/debug/tracing/current_tracer
> echo 1 > /sys/kernel/debug/tracing/tracing_on
> echo 1 > /sys/devices/system/cpu/cpu1/online
>
> Signed-off-by: Zhizhou Zhang <zhizhouzhang@asrmicro.com>
> ---
> arch/arm64/kernel/smp.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
> index f3e2e3ae..11b0f30 100644
> --- a/arch/arm64/kernel/smp.c
> +++ b/arch/arm64/kernel/smp.c
> @@ -179,7 +179,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
> * This is the secondary CPU boot entry. We're using this CPUs
> * idle thread stack, but a set of temporary page tables.
> */
> -asmlinkage void secondary_start_kernel(void)
> +notrace asmlinkage void secondary_start_kernel(void)
Minor nit: can we please keep asmlinkage first, e.g.
asmlinkage notrace void secondary_start_kernel(void)
Either way:
Acked-by: Mark Rutland <mark.rutland@arm.com>
Thanks,
Mark.
> {
> u64 mpidr = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
> struct mm_struct *mm = &init_mm;
> --
> 1.9.1
>
^ permalink raw reply
* [PATCH] arm64: make secondary_start_kernel() notrace
From: Zhizhou Zhang @ 2018-06-12 9:07 UTC (permalink / raw)
To: linux-arm-kernel
We can't call function trace hook before setup percpu offset.
When entering secondary_start_kernel(), percpu offset has not
been initialized. So this lead hotplug malfunction.
Here is the flow to reproduce this bug:
echo 0 > /sys/devices/system/cpu/cpu1/online
echo function > /sys/kernel/debug/tracing/current_tracer
echo 1 > /sys/kernel/debug/tracing/tracing_on
echo 1 > /sys/devices/system/cpu/cpu1/online
Signed-off-by: Zhizhou Zhang <zhizhouzhang@asrmicro.com>
---
arch/arm64/kernel/smp.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index f3e2e3ae..11b0f30 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -179,7 +179,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
* This is the secondary CPU boot entry. We're using this CPUs
* idle thread stack, but a set of temporary page tables.
*/
-asmlinkage void secondary_start_kernel(void)
+notrace asmlinkage void secondary_start_kernel(void)
{
u64 mpidr = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
struct mm_struct *mm = &init_mm;
--
1.9.1
^ permalink raw reply related
* [PATCH 0/5] arm64: numa/topology/smp: fix the cpumasks for CPU hotplug
From: Sudeep Holla @ 2018-06-12 9:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <23796631-312b-82a0-fe03-cb7985433727@huawei.com>
On 12/06/18 02:14, Hanjun Guo wrote:
> Hi Sudeep,
>
> On 2018/6/4 18:39, Sudeep Holla wrote:
>> Hi Will, Catalin, Jeremy, Morten,
>>
>> This is the fix I could come up for the issues we are seeing with arm64
>> for-next branch, in particular with commit 37c3ec2d810f ("arm64: topology:
>> divorce MC scheduling domain from core_siblings").
>>
>> The solution is to update the CPU topology during CPU hotplug operations
>> similar to other architectures like x86 and PPC. This is also inline
>> with the expection from the scheduler.
>>
>> I have cc-ed few Cavium and Huawei guys as they seem to have added or
>> modified the numa related code in the past.
>
> Sorry for the late response, I can test on ARM64 NUMA systems
> with PPTT enabled, before I'm doing that, could you give some
> suggestion of the testing? what specific test case should I
> test? doing CPU offline/online when PPTT is enabled?
>
Thanks for the response. I plan to post v2 after -rc1 which will have
some delta from this. So don't test this for now. Yes CPU hotplug tests
will be good. Also some NUMA based(numactl) assignments and try
hotplugging all CPUs in a node and similar tests with PPTT would be good.
--
Regards,
Sudeep
^ permalink raw reply
* [PATCH v3 0/6] add virt-dma support for imx-sdma
From: Robin Gong @ 2018-06-12 8:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1528714877.2842.3.camel@pengutronix.de>
Hi Lucas,
Is the below DEAD LOCK issue same as your side? If yes, then
I'm afraid that we have to make another patch for uart to split dma
functions in uart driver out of the code area which protected by
port.lock. The warning make sense since allocate sdma bd memory
dynamically in virt-dma instead of static allocated as before. I'll
make another uart patch into my next version patchset.
[???46.155406] =====================================================
[???46.161503] WARNING: HARDIRQ-safe -> HARDIRQ-unsafe lock order
detected
[???46.168122] 4.17.0-rc6-00008-g7caafa3-dirty #48 Not tainted
[???46.173696] -----------------------------------------------------
[???46.179795] mxc_uart_stress/419 [HC0[0]:SC0[0]:HE0:SE1] is trying to
acquire:
[???46.186934] fa7c1440 (fs_reclaim){+.+.}, at:
fs_reclaim_acquire.part.3+0x0/0x48
[???46.194270]
[???46.194270] and this task is already holding:
[???46.200106] 09a17fda (&port_lock_key){-.-.}, at:
uart_write+0x84/0x190
[???46.206658] which would create a new lock dependency:
[???46.211710]??(&port_lock_key){-.-.} -> (fs_reclaim){+.+.}
[???46.217132]
[???46.217132] but this new dependency connects a HARDIRQ-irq-safe
lock:
[???46.225051]??(&port_lock_key){-.-.}
[???46.225062]
[???46.225062] ... which became HARDIRQ-irq-safe at:
[???46.234740]???lock_acquire+0x70/0x90
[???46.238326]???_raw_spin_lock_irqsave+0x40/0x54
[???46.242777]???imx_uart_console_write+0x1bc/0x1e0
[???46.247402]???console_unlock+0x320/0x5f0
[???46.251329]???vprintk_emit+0x22c/0x3fc
[???46.255082]???vprintk_default+0x28/0x30
[???46.258923]???vprintk_func+0x78/0xcc
[???46.262503]???printk+0x34/0x54
[???46.265566]???crng_fast_load+0xf8/0x138
[???46.269407]???add_interrupt_randomness+0x21c/0x24c
[???46.274204]???handle_irq_event_percpu+0x40/0x84
[???46.278739]???handle_irq_event+0x40/0x64
[???46.282667]???handle_fasteoi_irq+0xbc/0x178
[???46.286854]???generic_handle_irq+0x28/0x3c
[???46.290954]???__handle_domain_irq+0x6c/0xe8
[???46.295148]???gic_handle_irq+0x64/0xc4
[???46.298904]???__irq_svc+0x70/0x98
[???46.302225]???_raw_spin_unlock_irq+0x30/0x34
[???46.306505]???finish_task_switch+0xc0/0x27c
[???46.310693]???__schedule+0x2c0/0x79c
[???46.314272]???schedule_idle+0x40/0x84
[???46.317941]???do_idle+0x178/0x2b4
[???46.321259]???cpu_startup_entry+0x20/0x24
[???46.325278]???rest_init+0x214/0x264
[???46.328775]???start_kernel+0x39c/0x424
[???46.332527]?????(null)
[???46.334891]
[???46.334891] to a HARDIRQ-irq-unsafe lock:
[???46.340379]??(fs_reclaim){+.+.}
[???46.340391]
[???46.340391] ... which became HARDIRQ-irq-unsafe at:
[???46.349885] ...
[???46.349895]???lock_acquire+0x70/0x90
[???46.355225]???fs_reclaim_acquire.part.3+0x38/0x48
[???46.359933]???fs_reclaim_acquire+0x1c/0x20
[???46.364036]???kmem_cache_alloc+0x2c/0x174
[???46.368051]???alloc_worker.constprop.10+0x1c/0x58
[???46.372759]???init_rescuer.part.4+0x18/0xa4
[???46.376952]???workqueue_init+0xc0/0x210
[???46.380793]???kernel_init_freeable+0x58/0x1d8
[???46.385156]???kernel_init+0x10/0x11c
[???46.388736]???ret_from_fork+0x14/0x20
[???46.392399]?????(null)
[???46.394762]
[???46.394762] other info that might help us debug this:
[???46.394762]
[???46.402769]??Possible interrupt unsafe locking scenario:
[???46.402769]
[???46.409560]????????CPU0????????????????????CPU1
[???46.414092]????????----????????????????????----
[???46.418622]???lock(fs_reclaim);
[???46.421772]????????????????????????????????local_irq_disable();
[???46.427693]????????????????????????????????lock(&port_lock_key);
[???46.433707]????????????????????????????????lock(fs_reclaim);
[???46.439372]???<Interrupt>
[???46.441993]?????lock(&port_lock_key);
[???46.445661]
[???46.445661]??*** DEADLOCK ***
[???46.445661]
On ?, 2018-06-11 at 13:01 +0200, Lucas Stach wrote:
> Hi Robin,
>
> this series breaks serial DMA for me. I wasn't able to dig in deeper
> yet. Please let me know if you can test/reproduce at your side, if
> not
> I'll try to find some time to collect some more debug info.
>
> Regards,
> Lucas
>
> Am Montag, den 11.06.2018, 22:59 +0800 schrieb Robin Gong:
> >
> > The legacy sdma driver has below limitations or drawbacks:
> > ? 1. Hardcode the max BDs number as "PAGE_SIZE / sizeof(*)", and
> > alloc
> > ?????one page size for one channel regardless of only few BDs
> > needed
> > ?????most time. But in few cases, the max PAGE_SIZE maybe not
> > enough.
> > ? 2. One SDMA channel can't stop immediatley once channel disabled
> > which
> > ?????means SDMA interrupt may come in after this channel
> > terminated.There
> > ?????are some patches for this corner case such as commit
> > "2746e2c389f9",
> > ?????but not cover non-cyclic.
> >
> > The common virt-dma overcomes the above limitations. It can alloc
> > bd
> > dynamically and free bd once this tx transfer done. No memory
> > wasted or
> > maximum limititation here, only depends on how many memory can be
> > requested
> > from kernel. For No.2, such issue can be workaround by checking if
> > there
> > is available descript("sdmac->desc") now once the unwanted
> > interrupt
> > coming. At last the common virt-dma is easier for sdma driver
> > maintain.
> >
> > Change from v2:
> > ? 1. include Sascha's patch to make the main patch easier to
> > review.
> > ?????Thanks Sacha.
> > ? 2. remove useless 'desc'/'chan' in struct sdma_channe.
> >
> > Change from v1:
> > ? 1. split v1 patch into 5 patches.
> > ? 2. remove some unnecessary condition check.
> > ? 3. remove unnecessary 'pending' list.
> >
> > Robin Gong (5):
> > ? dmaengine: imx-sdma: add virt-dma support
> > ? Revert "dmaengine: imx-sdma: fix pagefault when channel is
> > disabled
> > ????during interrupt"
> > ? dmaengine: imx-sdma: remove usless lock
> > ? dmaengine: imx-sdma: remove the maximum limation for bd numbers
> > ? dmaengine: imx-sdma: add sdma_transfer_init to decrease code
> > overlap
> >
> > ?drivers/dma/Kconfig????|???1 +
> > ?drivers/dma/imx-sdma.c | 392 ++++++++++++++++++++++++++++---------
> > ------------
> > ?2 files changed, 227 insertions(+), 166 deletions(-)
> >
> > --?
> > 2.7.4
> >
> > Robin Gong (5):
> > ? dmaengine: imx-sdma: add virt-dma support
> > ? Revert "dmaengine: imx-sdma: fix pagefault when channel is
> > disabled
> > ????during interrupt"
> > ? dmaengine: imx-sdma: remove usless lock
> > ? dmaengine: imx-sdma: remove the maximum limation for bd numbers
> > ? dmaengine: imx-sdma: add sdma_transfer_init to decrease code
> > overlap
> >
> > Sascha Hauer (1):
> > ? dmaengine: imx-sdma: factor out a struct sdma_desc from struct
> > ????sdma_channel
> >
> > ?drivers/dma/Kconfig????|???1 +
> > ?drivers/dma/imx-sdma.c | 391 ++++++++++++++++++++++++++++---------
> > ------------
> > ?2 files changed, 226 insertions(+), 166 deletions(-)
> >
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox