[v5,11/16] mtd: nand: qcom: support for command descriptor formation

Message ID 1502971674-13810-12-git-send-email-absahu@codeaurora.org
State Superseded
Delegated to: Boris Brezillon
Headers show

Commit Message

Abhishek Sahu Aug. 17, 2017, 12:07 p.m.
1. Add the function for command descriptor preparation which will
   be used only by BAM DMA and it will form the DMA descriptors
   containing command elements
2. DMA_PREP_CMD flag should be used for forming command DMA
   descriptors

Reviewed-by: Archit Taneja <architt@codeaurora.org>
Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
---

* Changes from v4: None

* BUILD DEPENDENCY:

 This PATCH has build dependency over following BAM command descriptor
 patch posted in DMA engine mailing list

 http://www.spinics.net/lists/dmaengine/msg13665.html

 drivers/mtd/nand/qcom_nandc.c | 108 +++++++++++++++++++++++++++++++++++-------
 1 file changed, 92 insertions(+), 16 deletions(-)

Comments

Abhishek Sahu Aug. 19, 2017, 9:47 a.m. | #1
On 2017-08-17 17:37, Abhishek Sahu wrote:
> 1. Add the function for command descriptor preparation which will
>    be used only by BAM DMA and it will form the DMA descriptors
>    containing command elements
> 2. DMA_PREP_CMD flag should be used for forming command DMA
>    descriptors
> 
> Reviewed-by: Archit Taneja <architt@codeaurora.org>
> Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
> ---
> 
> * Changes from v4: None
> 
> * BUILD DEPENDENCY:
> 
>  This PATCH has build dependency over following BAM command descriptor
>  patch posted in DMA engine mailing list
> 
>  http://www.spinics.net/lists/dmaengine/msg13665.html
> 

  Hi Boris,

  These patch has build dependency over DMA engine patch
  http://www.spinics.net/lists/dmaengine/msg13665.html

  but this patch has been applied in your github
  https://github.com/bbrezillon/linux-0day/commits/nand/next

  The DMA change has not merged yet so could we drop this and
  previous patch alone till the the DMA change is merged to prevent
  build error.

  Rest of the patch can go without any build or functionality
  failure.

>  drivers/mtd/nand/qcom_nandc.c | 108 
> +++++++++++++++++++++++++++++++++++-------
>  1 file changed, 92 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/mtd/nand/qcom_nandc.c 
> b/drivers/mtd/nand/qcom_nandc.c
> index b0a4734..52d9fae 100644
> --- a/drivers/mtd/nand/qcom_nandc.c
> +++ b/drivers/mtd/nand/qcom_nandc.c
> @@ -200,6 +200,14 @@
>   */
>  #define dev_cmd_reg_addr(nandc, reg)
> ((nandc)->props->dev_cmd_reg_start + (reg))
> 
> +/* Returns the NAND register physical address */
> +#define nandc_reg_phys(chip, offset) ((chip)->base_phys + (offset))
> +
> +/* Returns the dma address for reg read buffer */
> +#define reg_buf_dma_addr(chip, vaddr) \
> +	((chip)->reg_read_dma + \
> +	((uint8_t *)(vaddr) - (uint8_t *)(chip)->reg_read_buf))
> +
>  #define QPIC_PER_CW_CMD_ELEMENTS	32
>  #define QPIC_PER_CW_CMD_SGL		32
>  #define QPIC_PER_CW_DATA_SGL		8
> @@ -317,7 +325,8 @@ struct nandc_regs {
>   *				controller
>   * @dev:			parent device
>   * @base:			MMIO base
> - * @base_dma:			physical base address of controller registers
> + * @base_phys:			physical base address of controller registers
> + * @base_dma:			dma base address of controller registers
>   * @core_clk:			controller clock
>   * @aon_clk:			another controller clock
>   *
> @@ -350,6 +359,7 @@ struct qcom_nand_controller {
>  	struct device *dev;
> 
>  	void __iomem *base;
> +	phys_addr_t base_phys;
>  	dma_addr_t base_dma;
> 
>  	struct clk *core_clk;
> @@ -751,6 +761,66 @@ static int prepare_bam_async_desc(struct
> qcom_nand_controller *nandc,
>  }
> 
>  /*
> + * Prepares the command descriptor for BAM DMA which will be used for 
> NAND
> + * register reads and writes. The command descriptor requires the 
> command
> + * to be formed in command element type so this function uses the 
> command
> + * element from bam transaction ce array and fills the same with 
> required
> + * data. A single SGL can contain multiple command elements so
> + * NAND_BAM_NEXT_SGL will be used for starting the separate SGL
> + * after the current command element.
> + */
> +static int prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, 
> bool read,
> +				 int reg_off, const void *vaddr,
> +				 int size, unsigned int flags)
> +{
> +	int bam_ce_size;
> +	int i, ret;
> +	struct bam_cmd_element *bam_ce_buffer;
> +	struct bam_transaction *bam_txn = nandc->bam_txn;
> +
> +	bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_pos];
> +
> +	/* fill the command desc */
> +	for (i = 0; i < size; i++) {
> +		if (read)
> +			bam_prep_ce(&bam_ce_buffer[i],
> +				    nandc_reg_phys(nandc, reg_off + 4 * i),
> +				    BAM_READ_COMMAND,
> +				    reg_buf_dma_addr(nandc,
> +						     (__le32 *)vaddr + i));
> +		else
> +			bam_prep_ce_le32(&bam_ce_buffer[i],
> +					 nandc_reg_phys(nandc, reg_off + 4 * i),
> +					 BAM_WRITE_COMMAND,
> +					 *((__le32 *)vaddr + i));
> +	}
> +
> +	bam_txn->bam_ce_pos += size;
> +
> +	/* use the separate sgl after this command */
> +	if (flags & NAND_BAM_NEXT_SGL) {
> +		bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_start];
> +		bam_ce_size = (bam_txn->bam_ce_pos -
> +				bam_txn->bam_ce_start) *
> +				sizeof(struct bam_cmd_element);
> +		sg_set_buf(&bam_txn->cmd_sgl[bam_txn->cmd_sgl_pos],
> +			   bam_ce_buffer, bam_ce_size);
> +		bam_txn->cmd_sgl_pos++;
> +		bam_txn->bam_ce_start = bam_txn->bam_ce_pos;
> +
> +		if (flags & NAND_BAM_NWD) {
> +			ret = prepare_bam_async_desc(nandc, nandc->cmd_chan,
> +						     DMA_PREP_FENCE |
> +						     DMA_PREP_CMD);
> +			if (ret)
> +				return ret;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +/*
>   * Prepares the data descriptor for BAM DMA which will be used for 
> NAND
>   * data reads and writes.
>   */
> @@ -868,19 +938,22 @@ static int read_reg_dma(struct
> qcom_nand_controller *nandc, int first,
>  {
>  	bool flow_control = false;
>  	void *vaddr;
> -	int size;
> 
> -	if (first == NAND_READ_ID || first == NAND_FLASH_STATUS)
> -		flow_control = true;
> +	vaddr = nandc->reg_read_buf + nandc->reg_read_pos;
> +	nandc->reg_read_pos += num_regs;
> 
>  	if (first == NAND_DEV_CMD_VLD || first == NAND_DEV_CMD1)
>  		first = dev_cmd_reg_addr(nandc, first);
> 
> -	size = num_regs * sizeof(u32);
> -	vaddr = nandc->reg_read_buf + nandc->reg_read_pos;
> -	nandc->reg_read_pos += num_regs;
> +	if (nandc->props->is_bam)
> +		return prep_bam_dma_desc_cmd(nandc, true, first, vaddr,
> +					     num_regs, flags);
> 
> -	return prep_adm_dma_desc(nandc, true, first, vaddr, size, 
> flow_control);
> +	if (first == NAND_READ_ID || first == NAND_FLASH_STATUS)
> +		flow_control = true;
> +
> +	return prep_adm_dma_desc(nandc, true, first, vaddr,
> +				 num_regs * sizeof(u32), flow_control);
>  }
> 
>  /*
> @@ -897,13 +970,9 @@ static int write_reg_dma(struct
> qcom_nand_controller *nandc, int first,
>  	bool flow_control = false;
>  	struct nandc_regs *regs = nandc->regs;
>  	void *vaddr;
> -	int size;
> 
>  	vaddr = offset_to_nandc_reg(regs, first);
> 
> -	if (first == NAND_FLASH_CMD)
> -		flow_control = true;
> -
>  	if (first == NAND_ERASED_CW_DETECT_CFG) {
>  		if (flags & NAND_ERASED_CW_SET)
>  			vaddr = &regs->erased_cw_detect_cfg_set;
> @@ -920,10 +989,15 @@ static int write_reg_dma(struct
> qcom_nand_controller *nandc, int first,
>  	if (first == NAND_DEV_CMD_VLD_RESTORE || first == NAND_DEV_CMD_VLD)
>  		first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD);
> 
> -	size = num_regs * sizeof(u32);
> +	if (nandc->props->is_bam)
> +		return prep_bam_dma_desc_cmd(nandc, false, first, vaddr,
> +					     num_regs, flags);
> +
> +	if (first == NAND_FLASH_CMD)
> +		flow_control = true;
> 
> -	return prep_adm_dma_desc(nandc, false, first, vaddr, size,
> -				 flow_control);
> +	return prep_adm_dma_desc(nandc, false, first, vaddr,
> +				 num_regs * sizeof(u32), flow_control);
>  }
> 
>  /*
> @@ -1187,7 +1261,8 @@ static int submit_descs(struct
> qcom_nand_controller *nandc)
>  		}
> 
>  		if (bam_txn->cmd_sgl_pos > bam_txn->cmd_sgl_start) {
> -			r = prepare_bam_async_desc(nandc, nandc->cmd_chan, 0);
> +			r = prepare_bam_async_desc(nandc, nandc->cmd_chan,
> +						   DMA_PREP_CMD);
>  			if (r)
>  				return r;
>  		}
> @@ -2722,6 +2797,7 @@ static int qcom_nandc_probe(struct 
> platform_device *pdev)
>  	if (IS_ERR(nandc->base))
>  		return PTR_ERR(nandc->base);
> 
> +	nandc->base_phys = res->start;
>  	nandc->base_dma = phys_to_dma(dev, (phys_addr_t)res->start);
> 
>  	nandc->core_clk = devm_clk_get(dev, "core");
Boris Brezillon Aug. 19, 2017, 8:38 p.m. | #2
Le Sat, 19 Aug 2017 15:17:13 +0530,
Abhishek Sahu <absahu@codeaurora.org> a écrit :

> On 2017-08-17 17:37, Abhishek Sahu wrote:
> > 1. Add the function for command descriptor preparation which will
> >    be used only by BAM DMA and it will form the DMA descriptors
> >    containing command elements
> > 2. DMA_PREP_CMD flag should be used for forming command DMA
> >    descriptors
> > 
> > Reviewed-by: Archit Taneja <architt@codeaurora.org>
> > Signed-off-by: Abhishek Sahu <absahu@codeaurora.org>
> > ---
> > 
> > * Changes from v4: None
> > 
> > * BUILD DEPENDENCY:
> > 
> >  This PATCH has build dependency over following BAM command descriptor
> >  patch posted in DMA engine mailing list
> > 
> >  http://www.spinics.net/lists/dmaengine/msg13665.html
> >   
> 
>   Hi Boris,
> 
>   These patch has build dependency over DMA engine patch
>   http://www.spinics.net/lists/dmaengine/msg13665.html
> 
>   but this patch has been applied in your github
>   https://github.com/bbrezillon/linux-0day/commits/nand/next
> 
>   The DMA change has not merged yet so could we drop this and
>   previous patch alone till the the DMA change is merged to prevent
>   build error.

Oops. I saw this note when reviewing previous version of this and
completely forgot when applying v5. I dropped it from my nand/next
branch.
;
Note that the linux-0day repo is just a personal repo I use to let
Fenguang's robots test things before I push then to l2-mtd/nand/next.

Anyway, thanks for the heads up.

Boris

Patch

diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c
index b0a4734..52d9fae 100644
--- a/drivers/mtd/nand/qcom_nandc.c
+++ b/drivers/mtd/nand/qcom_nandc.c
@@ -200,6 +200,14 @@ 
  */
 #define dev_cmd_reg_addr(nandc, reg) ((nandc)->props->dev_cmd_reg_start + (reg))
 
+/* Returns the NAND register physical address */
+#define nandc_reg_phys(chip, offset) ((chip)->base_phys + (offset))
+
+/* Returns the dma address for reg read buffer */
+#define reg_buf_dma_addr(chip, vaddr) \
+	((chip)->reg_read_dma + \
+	((uint8_t *)(vaddr) - (uint8_t *)(chip)->reg_read_buf))
+
 #define QPIC_PER_CW_CMD_ELEMENTS	32
 #define QPIC_PER_CW_CMD_SGL		32
 #define QPIC_PER_CW_DATA_SGL		8
@@ -317,7 +325,8 @@  struct nandc_regs {
  *				controller
  * @dev:			parent device
  * @base:			MMIO base
- * @base_dma:			physical base address of controller registers
+ * @base_phys:			physical base address of controller registers
+ * @base_dma:			dma base address of controller registers
  * @core_clk:			controller clock
  * @aon_clk:			another controller clock
  *
@@ -350,6 +359,7 @@  struct qcom_nand_controller {
 	struct device *dev;
 
 	void __iomem *base;
+	phys_addr_t base_phys;
 	dma_addr_t base_dma;
 
 	struct clk *core_clk;
@@ -751,6 +761,66 @@  static int prepare_bam_async_desc(struct qcom_nand_controller *nandc,
 }
 
 /*
+ * Prepares the command descriptor for BAM DMA which will be used for NAND
+ * register reads and writes. The command descriptor requires the command
+ * to be formed in command element type so this function uses the command
+ * element from bam transaction ce array and fills the same with required
+ * data. A single SGL can contain multiple command elements so
+ * NAND_BAM_NEXT_SGL will be used for starting the separate SGL
+ * after the current command element.
+ */
+static int prep_bam_dma_desc_cmd(struct qcom_nand_controller *nandc, bool read,
+				 int reg_off, const void *vaddr,
+				 int size, unsigned int flags)
+{
+	int bam_ce_size;
+	int i, ret;
+	struct bam_cmd_element *bam_ce_buffer;
+	struct bam_transaction *bam_txn = nandc->bam_txn;
+
+	bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_pos];
+
+	/* fill the command desc */
+	for (i = 0; i < size; i++) {
+		if (read)
+			bam_prep_ce(&bam_ce_buffer[i],
+				    nandc_reg_phys(nandc, reg_off + 4 * i),
+				    BAM_READ_COMMAND,
+				    reg_buf_dma_addr(nandc,
+						     (__le32 *)vaddr + i));
+		else
+			bam_prep_ce_le32(&bam_ce_buffer[i],
+					 nandc_reg_phys(nandc, reg_off + 4 * i),
+					 BAM_WRITE_COMMAND,
+					 *((__le32 *)vaddr + i));
+	}
+
+	bam_txn->bam_ce_pos += size;
+
+	/* use the separate sgl after this command */
+	if (flags & NAND_BAM_NEXT_SGL) {
+		bam_ce_buffer = &bam_txn->bam_ce[bam_txn->bam_ce_start];
+		bam_ce_size = (bam_txn->bam_ce_pos -
+				bam_txn->bam_ce_start) *
+				sizeof(struct bam_cmd_element);
+		sg_set_buf(&bam_txn->cmd_sgl[bam_txn->cmd_sgl_pos],
+			   bam_ce_buffer, bam_ce_size);
+		bam_txn->cmd_sgl_pos++;
+		bam_txn->bam_ce_start = bam_txn->bam_ce_pos;
+
+		if (flags & NAND_BAM_NWD) {
+			ret = prepare_bam_async_desc(nandc, nandc->cmd_chan,
+						     DMA_PREP_FENCE |
+						     DMA_PREP_CMD);
+			if (ret)
+				return ret;
+		}
+	}
+
+	return 0;
+}
+
+/*
  * Prepares the data descriptor for BAM DMA which will be used for NAND
  * data reads and writes.
  */
@@ -868,19 +938,22 @@  static int read_reg_dma(struct qcom_nand_controller *nandc, int first,
 {
 	bool flow_control = false;
 	void *vaddr;
-	int size;
 
-	if (first == NAND_READ_ID || first == NAND_FLASH_STATUS)
-		flow_control = true;
+	vaddr = nandc->reg_read_buf + nandc->reg_read_pos;
+	nandc->reg_read_pos += num_regs;
 
 	if (first == NAND_DEV_CMD_VLD || first == NAND_DEV_CMD1)
 		first = dev_cmd_reg_addr(nandc, first);
 
-	size = num_regs * sizeof(u32);
-	vaddr = nandc->reg_read_buf + nandc->reg_read_pos;
-	nandc->reg_read_pos += num_regs;
+	if (nandc->props->is_bam)
+		return prep_bam_dma_desc_cmd(nandc, true, first, vaddr,
+					     num_regs, flags);
 
-	return prep_adm_dma_desc(nandc, true, first, vaddr, size, flow_control);
+	if (first == NAND_READ_ID || first == NAND_FLASH_STATUS)
+		flow_control = true;
+
+	return prep_adm_dma_desc(nandc, true, first, vaddr,
+				 num_regs * sizeof(u32), flow_control);
 }
 
 /*
@@ -897,13 +970,9 @@  static int write_reg_dma(struct qcom_nand_controller *nandc, int first,
 	bool flow_control = false;
 	struct nandc_regs *regs = nandc->regs;
 	void *vaddr;
-	int size;
 
 	vaddr = offset_to_nandc_reg(regs, first);
 
-	if (first == NAND_FLASH_CMD)
-		flow_control = true;
-
 	if (first == NAND_ERASED_CW_DETECT_CFG) {
 		if (flags & NAND_ERASED_CW_SET)
 			vaddr = &regs->erased_cw_detect_cfg_set;
@@ -920,10 +989,15 @@  static int write_reg_dma(struct qcom_nand_controller *nandc, int first,
 	if (first == NAND_DEV_CMD_VLD_RESTORE || first == NAND_DEV_CMD_VLD)
 		first = dev_cmd_reg_addr(nandc, NAND_DEV_CMD_VLD);
 
-	size = num_regs * sizeof(u32);
+	if (nandc->props->is_bam)
+		return prep_bam_dma_desc_cmd(nandc, false, first, vaddr,
+					     num_regs, flags);
+
+	if (first == NAND_FLASH_CMD)
+		flow_control = true;
 
-	return prep_adm_dma_desc(nandc, false, first, vaddr, size,
-				 flow_control);
+	return prep_adm_dma_desc(nandc, false, first, vaddr,
+				 num_regs * sizeof(u32), flow_control);
 }
 
 /*
@@ -1187,7 +1261,8 @@  static int submit_descs(struct qcom_nand_controller *nandc)
 		}
 
 		if (bam_txn->cmd_sgl_pos > bam_txn->cmd_sgl_start) {
-			r = prepare_bam_async_desc(nandc, nandc->cmd_chan, 0);
+			r = prepare_bam_async_desc(nandc, nandc->cmd_chan,
+						   DMA_PREP_CMD);
 			if (r)
 				return r;
 		}
@@ -2722,6 +2797,7 @@  static int qcom_nandc_probe(struct platform_device *pdev)
 	if (IS_ERR(nandc->base))
 		return PTR_ERR(nandc->base);
 
+	nandc->base_phys = res->start;
 	nandc->base_dma = phys_to_dma(dev, (phys_addr_t)res->start);
 
 	nandc->core_clk = devm_clk_get(dev, "core");