From: Archit Taneja <architt@codeaurora.org>
To: Stephen Boyd <sboyd@codeaurora.org>
Cc: dehrenberg@google.com, linux-arm-msm@vger.kernel.org,
cernekee@gmail.com, linux-kernel@vger.kernel.org,
linux-mtd@lists.infradead.org, agross@codeaurora.org,
computersforpeace@gmail.com
Subject: Re: [PATCH v3 2/5] mtd: nand: Qualcomm NAND controller driver
Date: Tue, 04 Aug 2015 20:34:35 +0530 [thread overview]
Message-ID: <55C0D483.7020405@codeaurora.org> (raw)
In-Reply-To: <20150803233852.GA20229@codeaurora.org>
On 8/4/2015 5:08 AM, Stephen Boyd wrote:
> On 08/03, Archit Taneja wrote:
>> The Qualcomm NAND controller is found in SoCs like IPQ806x, MSM7xx,
>> MDM9x15 series.
>
> There are some checker errors and le32 usage is not correct:
>
> drivers/mtd/nand/qcom_nandc.c:383:13: warning: mixing different enum types
> drivers/mtd/nand/qcom_nandc.c:383:13: int enum dma_transfer_direction versus
> drivers/mtd/nand/qcom_nandc.c:383:13: int enum dma_data_direction
> drivers/mtd/nand/qcom_nandc.c:741:17: warning: mixing different enum types
> drivers/mtd/nand/qcom_nandc.c:741:17: int enum dma_transfer_direction versus
> drivers/mtd/nand/qcom_nandc.c:741:17: int enum dma_data_direction
> /
> drivers/mtd/nand/qcom_nandc.c:1828:20: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
>
> You can find the le32 problems with
>
> make C=2 CF="-D__CHECK_ENDIAN__" drivers/mtd/nand/qcom_nandc.o
>
> Feel free to squash the following in:
Thanks for fixing these issues. I'll squash them in.
>
> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
> ---8<----
>
> diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c
> index e1f15766e63d..6cc1df1a6df0 100644
> --- a/drivers/mtd/nand/qcom_nandc.c
> +++ b/drivers/mtd/nand/qcom_nandc.c
> @@ -173,7 +173,7 @@
> struct desc_info {
> struct list_head list;
>
> - enum dma_transfer_direction dir;
> + enum dma_data_direction dir;
> struct scatterlist sgl;
> struct dma_async_tx_descriptor *dma_desc;
> };
> @@ -264,7 +264,7 @@ struct qcom_nandc_data {
> int buf_start;
>
> /* local buffer to read back registers */
> - u32 *reg_read_buf;
> + __le32 *reg_read_buf;
> int reg_read_pos;
>
> /* required configs */
> @@ -366,6 +366,7 @@ static int prep_dma_desc(struct qcom_nandc_data *this, bool read, int reg_off,
> struct dma_async_tx_descriptor *dma_desc;
> struct scatterlist *sgl;
> struct dma_slave_config slave_conf;
> + enum dma_transfer_direction dir_eng;
> int r;
>
> desc = kzalloc(sizeof(*desc), GFP_KERNEL);
> @@ -378,7 +379,13 @@ static int prep_dma_desc(struct qcom_nandc_data *this, bool read, int reg_off,
>
> sg_init_one(sgl, vaddr, size);
>
> - desc->dir = read ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV;
> + if (read) {
> + dir_eng = DMA_DEV_TO_MEM;
> + desc->dir = DMA_FROM_DEVICE;
> + } else {
> + dir_eng = DMA_MEM_TO_DEV;
> + desc->dir = DMA_TO_DEVICE;
> + }
>
> r = dma_map_sg(this->dev, sgl, 1, desc->dir);
> if (r == 0) {
> @@ -405,7 +412,7 @@ static int prep_dma_desc(struct qcom_nandc_data *this, bool read, int reg_off,
> goto err;
> }
>
> - dma_desc = dmaengine_prep_slave_sg(this->chan, sgl, 1, desc->dir, 0);
> + dma_desc = dmaengine_prep_slave_sg(this->chan, sgl, 1, dir_eng, 0);
> if (!dma_desc) {
> dev_err(this->dev, "failed to prepare desc\n");
> r = -EINVAL;
> @@ -775,7 +782,7 @@ static void parse_erase_write_errors(struct qcom_nandc_data *this, int command)
> num_cw = command == NAND_CMD_PAGEPROG ? ecc->steps : 1;
>
> for (i = 0; i < num_cw; i++) {
> - __le32 flash_status = le32_to_cpu(this->reg_read_buf[i]);
> + u32 flash_status = le32_to_cpu(this->reg_read_buf[i]);
>
> if (flash_status & FS_MPU_ERR)
> this->status &= ~NAND_STATUS_WP;
> @@ -902,7 +909,7 @@ static bool empty_page_fixup(struct qcom_nandc_data *this, u8 *data_buf)
>
> for (i = 0; i < cwperpage; i++) {
> u8 *empty1, *empty2;
> - __le32 flash_status = le32_to_cpu(this->reg_read_buf[3 * i]);
> + u32 flash_status = le32_to_cpu(this->reg_read_buf[3 * i]);
>
> /*
> * an erased page flags an error in NAND_FLASH_STATUS, check if
> @@ -968,37 +975,37 @@ static int parse_read_errors(struct qcom_nandc_data *this, bool erased_page)
> int cwperpage = ecc->steps;
> unsigned int max_bitflips = 0;
> int i;
> + struct read_stats *buf;
>
> - for (i = 0; i < cwperpage; i++) {
> - int stat;
> - struct read_stats *buf;
> -
> - buf = (struct read_stats *) (this->reg_read_buf + 3 * i);
> + buf = (struct read_stats *)this->reg_read_buf;
> + for (i = 0; i < cwperpage; i++, buf++) {
> + unsigned int stat;
> + u32 flash, buffer, erased_cw;
>
> - buf->flash = le32_to_cpu(buf->flash);
> - buf->buffer = le32_to_cpu(buf->buffer);
> - buf->erased_cw = le32_to_cpu(buf->erased_cw);
> + flash = le32_to_cpu(buf->flash);
> + buffer = le32_to_cpu(buf->buffer);
> + erased_cw = le32_to_cpu(buf->erased_cw);
>
> - if (buf->flash & (FS_OP_ERR | FS_MPU_ERR)) {
> + if (flash & (FS_OP_ERR | FS_MPU_ERR)) {
>
> /* ignore erased codeword errors */
> if (this->bch_enabled) {
> - if ((buf->erased_cw & ERASED_CW) == ERASED_CW)
> + if ((erased_cw & ERASED_CW) == ERASED_CW)
> continue;
> } else if (erased_page) {
> continue;
> }
>
> - if (buf->buffer & BS_UNCORRECTABLE_BIT) {
> + if (buffer & BS_UNCORRECTABLE_BIT) {
> mtd->ecc_stats.failed++;
> continue;
> }
> }
>
> - stat = buf->buffer & BS_CORRECTABLE_ERR_MSK;
> + stat = buffer & BS_CORRECTABLE_ERR_MSK;
> mtd->ecc_stats.corrected += stat;
>
> - max_bitflips = max_t(unsigned int, max_bitflips, stat);
> + max_bitflips = max(max_bitflips, stat);
> }
>
> return max_bitflips;
> @@ -1825,7 +1832,7 @@ static int qcom_nandc_probe(struct platform_device *pdev)
> return -ENODEV;
> }
>
> - this->ecc_modes = (u32) dev_data;
> + this->ecc_modes = (unsigned long)dev_data;
>
> this->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> this->base = devm_ioremap_resource(&pdev->dev, this->res);
>
>> diff --git a/drivers/mtd/nand/qcom_nandc.c b/drivers/mtd/nand/qcom_nandc.c
>> new file mode 100644
>> index 0000000..e1f1576
>> --- /dev/null
>> +++ b/drivers/mtd/nand/qcom_nandc.c
>> @@ -0,0 +1,1913 @@
>> +struct qcom_nandc_data {
>> + struct platform_device *pdev;
>> + struct device *dev;
>> +
>> + void __iomem *base;
>> + struct resource *res;
>> +
>> + struct clk *core_clk;
>> + struct clk *aon_clk;
>> +
>> + /* DMA stuff */
>> + struct dma_chan *chan;
>> + struct dma_slave_config slave_conf;
>> + unsigned int cmd_crci;
>> + unsigned int data_crci;
>> + struct list_head list;
>> + struct completion dma_done;
>> +
>> + /* MTD stuff */
>> + struct nand_chip chip;
>> + struct mtd_info mtd;
>> +
>> + /* local data buffer and markers */
>> + u8 *data_buffer;
>> + int buf_size;
>> + int buf_count;
>> + int buf_start;
>> +
>> + /* local buffer to read back registers */
>> + u32 *reg_read_buf;
>> + int reg_read_pos;
>> +
>> + /* required configs */
>> + u32 cfg0, cfg1;
>> + u32 cfg0_raw, cfg1_raw;
>> + u32 ecc_buf_cfg;
>> + u32 ecc_bch_cfg;
>> + u32 clrflashstatus;
>> + u32 clrreadstatus;
>> + u32 sflashc_burst_cfg;
>> + u32 cmd1, vld;
>> +
>> + /* register state */
>> + struct nandc_regs *regs;
>
> I also wonder if this is little endian? It looks like some sort
> of in memory register map that we point DMA to so that it can
> write the values to the actual hardware registers?
Yes, that's what it's supposed to do. I kept it in the form above
so that updating the register map is as easy as assigning a new
value to the member.
I've tried to fix it for endianness in the diff below. I created
some funcs to not flood the driver with cpu_to_le32() calls. Does
it look okay?
--- a/drivers/mtd/nand/qcom_nandc.c
+++ b/drivers/mtd/nand/qcom_nandc.c
@@ -183,26 +183,26 @@ struct desc_info {
* chunk of memory which we use to write the controller registers
through DMA.
*/
struct nandc_regs {
- u32 cmd;
- u32 addr0;
- u32 addr1;
- u32 chip_sel;
- u32 exec;
-
- u32 cfg0;
- u32 cfg1;
- u32 ecc_bch_cfg;
+ __le32 cmd;
+ __le32 addr0;
+ __le32 addr1;
+ __le32 chip_sel;
+ __le32 exec;
- u32 clrflashstatus;
- u32 clrreadstatus;
+ __le32 cfg0;
+ __le32 cfg1;
+ __le32 ecc_bch_cfg;
- u32 cmd1;
- u32 vld;
+ __le32 clrflashstatus;
+ __le32 clrreadstatus;
- u32 orig_cmd1;
- u32 orig_vld;
+ __le32 cmd1;
+ __le32 vld;
- u32 ecc_buf_cfg;
+ __le32 orig_cmd1;
+ __le32 orig_vld;
+
+ __le32 ecc_buf_cfg;
};
/*
@@ -306,17 +306,65 @@ static inline void nandc_write(struct
qcom_nandc_data *this, int offset,
iowrite32(val, this->base + offset);
}
+static __le32 *offset_to_nandc_reg(struct nandc_regs *regs, int offset)
+{
+ switch (offset) {
+ case NAND_FLASH_CMD:
+ return ®s->cmd;
+ case NAND_ADDR0:
+ return ®s->addr0;
+ case NAND_ADDR1:
+ return ®s->addr1;
+ case NAND_FLASH_CHIP_SELECT:
+ return ®s->chip_sel;
+ case NAND_EXEC_CMD:
+ return ®s->exec;
+ case NAND_FLASH_STATUS:
+ return ®s->clrflashstatus;
+ case NAND_DEV0_CFG0:
+ return ®s->cfg0;
+ case NAND_DEV0_CFG1:
+ return ®s->cfg1;
+ case NAND_DEV0_ECC_CFG:
+ return ®s->ecc_bch_cfg;
+ case NAND_READ_STATUS:
+ return ®s->clrreadstatus;
+ case NAND_DEV_CMD1:
+ return ®s->cmd1;
+ case NAND_DEV_CMD1_RESTORE:
+ return ®s->orig_cmd1;
+ case NAND_DEV_CMD_VLD:
+ return ®s->vld;
+ case NAND_DEV_CMD_VLD_RESTORE:
+ return ®s->orig_vld;
+ case NAND_EBI2_ECC_BUF_CFG:
+ return ®s->ecc_buf_cfg;
+ default:
+ return NULL;
+ }
+}
+
+static void set_nandc_reg(struct qcom_nandc_data *this, int offset, u32
val)
+{
+ struct nandc_regs *regs = this->regs;
+ __le32 *reg;
+
+ reg = offset_to_nandc_reg(regs, offset);
+
+ if (reg)
+ *reg = cpu_to_le32(val);
+}
+
/* helper to configure address register values */
static void set_address(struct qcom_nandc_data *this, u16 column, int
page)
{
struct nand_chip *chip = &this->chip;
- struct nandc_regs *regs = this->regs;
if (chip->options & NAND_BUSWIDTH_16)
column >>= 1;
- regs->addr0 = page << 16 | column;
- regs->addr1 = page >> 16 & 0xff;
+ set_nandc_reg(this, NAND_ADDR0, page << 16 | column);
+ set_nandc_reg(this, NAND_ADDR1, page >> 16 & 0xff);
}
/*
@@ -328,35 +376,39 @@ static void set_address(struct qcom_nandc_data
*this, u16 column, int page)
*/
static void update_rw_regs(struct qcom_nandc_data *this, int num_cw,
bool read)
{
- struct nandc_regs *regs = this->regs;
+ u32 cmd, cfg0, cfg1, ecc_bch_cfg;
if (read) {
if (this->use_ecc)
- regs->cmd = PAGE_READ_WITH_ECC | PAGE_ACC | LAST_PAGE;
+ cmd = PAGE_READ_WITH_ECC | PAGE_ACC | LAST_PAGE;
else
- regs->cmd = PAGE_READ | PAGE_ACC | LAST_PAGE;
+ cmd = PAGE_READ | PAGE_ACC | LAST_PAGE;
} else {
- regs->cmd = PROGRAM_PAGE | PAGE_ACC | LAST_PAGE;
+ cmd = PROGRAM_PAGE | PAGE_ACC | LAST_PAGE;
}
if (this->use_ecc) {
- regs->cfg0 = (this->cfg0 & ~(7U << CW_PER_PAGE)) |
+ cfg0 = (this->cfg0 & ~(7U << CW_PER_PAGE)) |
(num_cw - 1) << CW_PER_PAGE;
- regs->cfg1 = this->cfg1;
- regs->ecc_bch_cfg = this->ecc_bch_cfg;
+ cfg1 = this->cfg1;
+ ecc_bch_cfg = this->ecc_bch_cfg;
} else {
- regs->cfg0 = (this->cfg0_raw & ~(7U << CW_PER_PAGE)) |
+ cfg0 = (this->cfg0_raw & ~(7U << CW_PER_PAGE)) |
(num_cw - 1) << CW_PER_PAGE;
- regs->cfg1 = this->cfg1_raw;
- regs->ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE;
+ cfg1 = this->cfg1_raw;
+ ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE;
}
- regs->ecc_buf_cfg = this->ecc_buf_cfg;
- regs->clrflashstatus = this->clrflashstatus;
- regs->clrreadstatus = this->clrreadstatus;
- regs->exec = 1;
+ set_nandc_reg(this, NAND_FLASH_CMD, cmd);
+ set_nandc_reg(this, NAND_DEV0_CFG0, cfg0);
+ set_nandc_reg(this, NAND_DEV0_CFG1, cfg1);
+ set_nandc_reg(this, NAND_DEV0_ECC_CFG, ecc_bch_cfg);
+ set_nandc_reg(this, NAND_EBI2_ECC_BUF_CFG, this->ecc_buf_cfg);
+ set_nandc_reg(this, NAND_FLASH_STATUS, this->clrflashstatus);
+ set_nandc_reg(this, NAND_READ_STATUS, this->clrreadstatus);
+ set_nandc_reg(this, NAND_EXEC_CMD, 1);
}
static int prep_dma_desc(struct qcom_nandc_data *this, bool read, int
reg_off,
@@ -465,44 +517,16 @@ static int write_reg_dma(struct qcom_nandc_data
*this, int first, int num_regs)
void *vaddr;
int size;
- switch (first) {
- case NAND_FLASH_CMD:
- vaddr = ®s->cmd;
+ vaddr = offset_to_nandc_reg(regs, first);
+
+ if (first == NAND_FLASH_CMD)
flow_control = true;
- break;
- case NAND_EXEC_CMD:
- vaddr = ®s->exec;
- break;
- case NAND_FLASH_STATUS:
- vaddr = ®s->clrflashstatus;
- break;
- case NAND_DEV0_CFG0:
- vaddr = ®s->cfg0;
- break;
- case NAND_READ_STATUS:
- vaddr = ®s->clrreadstatus;
- break;
- case NAND_DEV_CMD1:
- vaddr = ®s->cmd1;
- break;
- case NAND_DEV_CMD1_RESTORE:
+
+ if (first == NAND_DEV_CMD1_RESTORE)
first = NAND_DEV_CMD1;
- vaddr = ®s->orig_cmd1;
- break;
- case NAND_DEV_CMD_VLD:
- vaddr = ®s->vld;
- break;
- case NAND_DEV_CMD_VLD_RESTORE:
+
+ if (first == NAND_DEV_CMD_VLD_RESTORE)
first = NAND_DEV_CMD_VLD;
- vaddr = ®s->orig_vld;
- break;
- case NAND_EBI2_ECC_BUF_CFG:
- vaddr = ®s->ecc_buf_cfg;
- break;
- default:
- dev_err(this->dev, "invalid starting register\n");
- return -EINVAL;
- }
size = num_regs * sizeof(u32);
@@ -582,42 +606,40 @@ static void config_cw_write_post(struct
qcom_nandc_data *this)
/* sets up descriptors for NAND_CMD_PARAM */
static int nandc_param(struct qcom_nandc_data *this)
{
- struct nandc_regs *regs = this->regs;
-
/*
* NAND_CMD_PARAM is called before we know much about the FLASH chip
* in use. we configure the controller to perform a raw read of 512
* bytes to read onfi params
*/
- regs->cmd = PAGE_READ | PAGE_ACC | LAST_PAGE;
- regs->addr0 = 0;
- regs->addr1 = 0;
- regs->cfg0 = 0 << CW_PER_PAGE
- | 512 << UD_SIZE_BYTES
- | 5 << NUM_ADDR_CYCLES
- | 0 << SPARE_SIZE_BYTES;
-
- regs->cfg1 = 7 << NAND_RECOVERY_CYCLES
- | 0 << CS_ACTIVE_BSY
- | 17 << BAD_BLOCK_BYTE_NUM
- | 1 << BAD_BLOCK_IN_SPARE_AREA
- | 2 << WR_RD_BSY_GAP
- | 0 << WIDE_FLASH
- | 1 << DEV0_CFG1_ECC_DISABLE;
-
- regs->ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE;
+ set_nandc_reg(this, NAND_FLASH_CMD, PAGE_READ | PAGE_ACC | LAST_PAGE);
+ set_nandc_reg(this, NAND_ADDR0, 0);
+ set_nandc_reg(this, NAND_ADDR1, 0);
+ set_nandc_reg(this, NAND_DEV0_CFG0, 0 << CW_PER_PAGE
+ | 512 << UD_SIZE_BYTES
+ | 5 << NUM_ADDR_CYCLES
+ | 0 << SPARE_SIZE_BYTES);
+ set_nandc_reg(this, NAND_DEV0_CFG1, 7 << NAND_RECOVERY_CYCLES
+ | 0 << CS_ACTIVE_BSY
+ | 17 << BAD_BLOCK_BYTE_NUM
+ | 1 << BAD_BLOCK_IN_SPARE_AREA
+ | 2 << WR_RD_BSY_GAP
+ | 0 << WIDE_FLASH
+ | 1 << DEV0_CFG1_ECC_DISABLE);
+ set_nandc_reg(this, NAND_EBI2_ECC_BUF_CFG, 1 << ECC_CFG_ECC_DISABLE);
- /* configure CMD1 and VLD for ONFI param probing */
- regs->vld = (this->vld & ~(1 << READ_START_VLD))
- | 0 << READ_START_VLD;
- regs->cmd1 = (this->cmd1 & ~(0xFF << READ_ADDR))
- | NAND_CMD_PARAM << READ_ADDR;
+ /* configure CMD1 and VLD for ONFI param probing */
+ set_nandc_reg(this, NAND_DEV_CMD_VLD,
+ (this->vld & ~(1 << READ_START_VLD))
+ | 0 << READ_START_VLD);
+ set_nandc_reg(this, NAND_DEV_CMD1,
+ (this->cmd1 & ~(0xFF << READ_ADDR))
+ | NAND_CMD_PARAM << READ_ADDR);
- regs->exec = 1;
+ set_nandc_reg(this, NAND_EXEC_CMD, 1);
- regs->orig_cmd1 = this->cmd1;
- regs->orig_vld = this->vld;
+ set_nandc_reg(this, NAND_DEV_CMD1_RESTORE, this->cmd1);
+ set_nandc_reg(this, NAND_DEV_CMD_VLD_RESTORE, this->vld);
write_reg_dma(this, NAND_DEV_CMD_VLD, 1);
write_reg_dma(this, NAND_DEV_CMD1, 1);
@@ -639,16 +661,15 @@ static int nandc_param(struct qcom_nandc_data *this)
/* sets up descriptors for NAND_CMD_ERASE1 */
static int erase_block(struct qcom_nandc_data *this, int page_addr)
{
- struct nandc_regs *regs = this->regs;
-
- regs->cmd = BLOCK_ERASE | PAGE_ACC | LAST_PAGE;
- regs->addr0 = page_addr;
- regs->addr1 = 0;
- regs->cfg0 = this->cfg0_raw & ~(7 << CW_PER_PAGE);
- regs->cfg1 = this->cfg1_raw;
- regs->exec = 1;
- regs->clrflashstatus = this->clrflashstatus;
- regs->clrreadstatus = this->clrreadstatus;
+ set_nandc_reg(this, NAND_FLASH_CMD, BLOCK_ERASE | PAGE_ACC | LAST_PAGE);
+ set_nandc_reg(this, NAND_ADDR0, page_addr);
+ set_nandc_reg(this, NAND_ADDR1, 0);
+ set_nandc_reg(this, NAND_DEV0_CFG0,
+ this->cfg0_raw & ~(7 << CW_PER_PAGE));
+ set_nandc_reg(this, NAND_DEV0_CFG1, this->cfg1_raw);
+ set_nandc_reg(this, NAND_EXEC_CMD, 1);
+ set_nandc_reg(this, NAND_FLASH_STATUS, this->clrflashstatus);
+ set_nandc_reg(this, NAND_READ_STATUS, this->clrreadstatus);
write_reg_dma(this, NAND_FLASH_CMD, 3);
write_reg_dma(this, NAND_DEV0_CFG0, 2);
@@ -665,16 +686,14 @@ static int erase_block(struct qcom_nandc_data
*this, int page_addr)
/* sets up descriptors for NAND_CMD_READID */
static int read_id(struct qcom_nandc_data *this, int column)
{
- struct nandc_regs *regs = this->regs;
-
if (column == -1)
return 0;
- regs->cmd = FETCH_ID;
- regs->addr0 = column;
- regs->addr1 = 0;
- regs->chip_sel = DM_EN;
- regs->exec = 1;
+ set_nandc_reg(this, NAND_FLASH_CMD, FETCH_ID);
+ set_nandc_reg(this, NAND_ADDR0, column);
+ set_nandc_reg(this, NAND_ADDR1, 0);
+ set_nandc_reg(this, NAND_FLASH_CHIP_SELECT, DM_EN);
+ set_nandc_reg(this, NAND_EXEC_CMD, 1);
write_reg_dma(this, NAND_FLASH_CMD, 4);
write_reg_dma(this, NAND_EXEC_CMD, 1);
@@ -687,10 +706,8 @@ static int read_id(struct qcom_nandc_data *this,
int column)
/* sets up descriptors for NAND_CMD_RESET */
static int reset(struct qcom_nandc_data *this)
{
- struct nandc_regs *regs = this->regs;
-
- regs->cmd = RESET_DEVICE;
- regs->exec = 1;
+ set_nandc_reg(this, NAND_FLASH_CMD, RESET_DEVICE);
+ set_nandc_reg(this, NAND_EXEC_CMD, 1);
write_reg_dma(this, NAND_FLASH_CMD, 1);
write_reg_dma(this, NAND_EXEC_CMD, 1);
>
>> +
>> + /* things we get from DT */
>> + int ecc_strength;
>> + int bus_width;
>> +
>> + u32 ecc_modes;
>> +
>> + /* misc params */
>> + int cw_size;
>> + int cw_data;
>> + bool use_ecc;
>> + bool bch_enabled;
>> + u8 status;
>> + int last_command;
>> +};
> [...]
>> +
>> +static int prep_dma_desc(struct qcom_nandc_data *this, bool read, int reg_off,
>> + const void *vaddr, int size, bool flow_control)
>> +{
>> + struct desc_info *desc;
>> + struct dma_async_tx_descriptor *dma_desc;
>> + struct scatterlist *sgl;
>> + struct dma_slave_config slave_conf;
>> + int r;
>> +
>> + desc = kzalloc(sizeof(*desc), GFP_KERNEL);
>> + if (!desc)
>> + return -ENOMEM;
>> +
>> + list_add_tail(&desc->list, &this->list);
>
> Should we move this list add to at least after the dma_map_sg()?
> It looks like on the error path (which is only checked sometimes)
> we always call dma_unmap_sg() and so this may have not been
> mapped in the first place.
The error path isn't checked by the callers of this func, so, it's
best to keep it later as you suggested.
>
>> +
>> + sgl = &desc->sgl;
>> +
>> + sg_init_one(sgl, vaddr, size);
>> +
>> + desc->dir = read ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV;
>> +
>> + r = dma_map_sg(this->dev, sgl, 1, desc->dir);
>> + if (r == 0) {
>> + r = -ENOMEM;
>> + goto err;
>> + }
>> +
>> + memset(&slave_conf, 0x00, sizeof(slave_conf));
>> +
>> + slave_conf.device_fc = flow_control;
>> + if (read) {
>> + slave_conf.src_maxburst = 16;
>> + slave_conf.src_addr = this->res->start + reg_off;
>> + slave_conf.slave_id = this->data_crci;
>> + } else {
>> + slave_conf.dst_maxburst = 16;
>> + slave_conf.dst_addr = this->res->start + reg_off;
>> + slave_conf.slave_id = this->cmd_crci;
>> + }
>> +
>> + r = dmaengine_slave_config(this->chan, &slave_conf);
>> + if (r) {
>> + dev_err(this->dev, "failed to configure dma channel\n");
>> + goto err;
>> + }
>> +
>> + dma_desc = dmaengine_prep_slave_sg(this->chan, sgl, 1, desc->dir, 0);
>> + if (!dma_desc) {
>> + dev_err(this->dev, "failed to prepare desc\n");
>> + r = -EINVAL;
>> + goto err;
>> + }
>> +
>> + desc->dma_desc = dma_desc;
>> +
>> + return 0;
>> +err:
>> + kfree(desc);
>> +
>> + return r;
>> +}
> [...]
>> +
>> +static int submit_descs(struct qcom_nandc_data *this)
>> +{
>> + struct completion *c = &this->dma_done;
>> + struct desc_info *desc;
>> + int r;
>> +
>> + init_completion(c);
>> +
>> + list_for_each_entry(desc, &this->list, list) {
>> + /*
>> + * we add a callback to the last descriptor in our list to
>> + * notify completion of command
>> + */
>> + if (list_is_last(&desc->list, &this->list)) {
>> + desc->dma_desc->callback = dma_callback;
>> + desc->dma_desc->callback_param = this;
>> + }
>> +
>> + dmaengine_submit(desc->dma_desc);
>> + }
>> +
>> + dma_async_issue_pending(this->chan);
>> +
>> + r = wait_for_completion_timeout(c, msecs_to_jiffies(500));
>> + if (!r)
>> + return -ETIMEDOUT;
>
> Any reason this can't all be done with dma_sync_wait()? The
> timeout is a little different (5 seconds instead of .5 seconds)
> but otherwise it looks like we could keep track of the last
> cookie we got from dmaengine_submit() and then call
> dma_sync_wait() with that:
>
> list_for_each_entry(desc, &this->list, list)
> cookie = dmaengine_submit(desc->dma_desc);
>
> if (dma_sync_wait(this->chan, cookie) != DMA_COMPLETE)
> return -ETIMEDOUT;
I didn't know about this function, will give it a try.
>
>> +
>> + return 0;
>> +}
>> +
> [...]
>> +
>> +/*
>> + * this is called after NAND_CMD_PAGEPROG and NAND_CMD_ERASE1 to set our
>> + * privately maintained status byte, this status byte can be read after
>> + * NAND_CMD_STATUS is called
>> + */
>> +static void parse_erase_write_errors(struct qcom_nandc_data *this, int command)
>> +{
>> + struct nand_chip *chip = &this->chip;
>> + struct nand_ecc_ctrl *ecc = &chip->ecc;
>> + int num_cw;
>> + int i;
>> +
>> + num_cw = command == NAND_CMD_PAGEPROG ? ecc->steps : 1;
>> +
>> + for (i = 0; i < num_cw; i++) {
>> + __le32 flash_status = le32_to_cpu(this->reg_read_buf[i]);
>
> So this doesn't need the i * 3 thing? If it does, perhaps
> reg_read_buf needs to be of type struct read_stats instead.
We just read back one register per codeword here, so we can't do
the read_stats thing as before. I could read back the extra registers
and discrading them, but I'd I'll leave that for later.
Archit
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
next prev parent reply other threads:[~2015-08-04 15:04 UTC|newest]
Thread overview: 127+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-01-16 14:48 [PATCH 0/5] mtd: Qualcomm NAND controller driver Archit Taneja
2015-01-16 14:48 ` [PATCH 1/5] clk: qcom: Add EBI2 clocks for IPQ806x Archit Taneja
2015-01-16 21:56 ` Stephen Boyd
2015-01-19 10:32 ` Archit Taneja
2015-01-29 22:21 ` Stephen Boyd
2015-01-16 14:48 ` [PATCH 2/5] mtd: nand: Add qcom nand controller driver Archit Taneja
2015-01-21 0:54 ` Daniel Ehrenberg
2015-01-22 6:36 ` Archit Taneja
2015-01-26 21:05 ` Kevin Cernekee
2015-01-27 3:56 ` Archit Taneja
[not found] ` <1421419702-17812-1-git-send-email-architt-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2015-01-16 14:48 ` [PATCH 3/5] Documentaion: dt: add DT bindings for Qualcomm NAND controller Archit Taneja
2015-01-16 14:48 ` [PATCH 4/5] arm: qcom: dts: Add NAND controller node for ipq806x Archit Taneja
2015-01-16 14:48 ` [PATCH 5/5] arm: qcom: dts: Enale NAND node on IPQ8064 AP148 pplatform Archit Taneja
2015-02-18 6:03 ` [PATCH 0/5] mtd: Qualcomm NAND controller driver Archit Taneja
2015-07-21 10:34 ` [PATCH v2 " Archit Taneja
2015-07-21 10:34 ` [PATCH v2 1/5] mtd: nand: Create a BBT flag to access bad block markers in raw mode Archit Taneja
2015-07-24 19:01 ` Andy Gross
2015-07-21 10:34 ` [PATCH v2 2/5] mtd: nand: Qualcomm NAND controller driver Archit Taneja
2015-07-24 19:39 ` Andy Gross
2015-07-25 0:51 ` Stephen Boyd
2015-07-28 4:34 ` Archit Taneja
2015-07-29 1:48 ` Stephen Boyd
2015-07-29 5:14 ` Archit Taneja
2015-07-29 18:33 ` Stephen Boyd
2015-07-30 6:53 ` Archit Taneja
2015-07-21 10:34 ` [PATCH v2 3/5] dt/bindings: qcom_nandc: Add DT bindings Archit Taneja
2015-07-24 18:57 ` Andy Gross
2015-07-24 19:37 ` Stephen Boyd
2015-07-21 10:34 ` [PATCH v2 4/5] arm: qcom: dts: Add NAND controller node for ipq806x Archit Taneja
2015-07-24 19:01 ` Andy Gross
2015-07-21 10:34 ` [PATCH v2 5/5] arm: qcom: dts: Enale NAND node on IPQ8064 AP148 platform Archit Taneja
2015-07-24 18:58 ` Andy Gross
2015-07-24 18:59 ` Andy Gross
2015-08-03 5:08 ` [PATCH v3 0/5] mtd: Qualcomm NAND controller driver Archit Taneja
2015-08-03 5:08 ` [PATCH v3 1/5] mtd: nand: Create a BBT flag to access bad block markers in raw mode Archit Taneja
2015-08-03 5:08 ` [PATCH v3 2/5] mtd: nand: Qualcomm NAND controller driver Archit Taneja
2015-08-03 23:38 ` Stephen Boyd
2015-08-04 15:04 ` Archit Taneja [this message]
2015-08-04 17:53 ` Stephen Boyd
2015-08-03 5:08 ` [PATCH v3 3/5] dt/bindings: qcom_nandc: Add DT bindings Archit Taneja
2015-08-03 5:08 ` [PATCH v3 4/5] arm: qcom: dts: Add NAND controller node for ipq806x Archit Taneja
[not found] ` <1438578498-32254-1-git-send-email-architt-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
2015-08-03 5:08 ` [PATCH v3 5/5] arm: qcom: dts: Enable NAND node on IPQ8064 AP148 platform Archit Taneja
2015-08-03 19:35 ` Andy Gross
2015-08-04 15:05 ` Archit Taneja
2015-08-03 20:58 ` Stephen Boyd
2015-08-04 15:06 ` Archit Taneja
2015-08-19 4:49 ` [PATCH v4 0/5] mtd: Qualcomm NAND controller driver Archit Taneja
2015-08-19 4:49 ` [PATCH v4 1/5] mtd: nand: Create a BBT flag to access bad block markers in raw mode Archit Taneja
2015-10-02 2:44 ` Brian Norris
2015-10-02 6:27 ` Boris Brezillon
2015-10-11 20:03 ` Brian Norris
2015-11-10 5:13 ` Archit Taneja
2015-08-19 4:49 ` [PATCH v4 2/5] mtd: nand: Qualcomm NAND controller driver Archit Taneja
2015-08-26 23:37 ` Stephen Boyd
2015-09-13 13:42 ` Archit Taneja
2015-10-02 3:05 ` Brian Norris
2015-10-05 6:51 ` Archit Taneja
2015-10-06 9:17 ` Brian Norris
2015-10-07 4:11 ` Archit Taneja
2015-10-02 17:31 ` Brian Norris
2015-12-16 9:15 ` Boris Brezillon
2015-12-16 11:57 ` Archit Taneja
2015-12-16 14:18 ` Boris Brezillon
2015-12-17 9:48 ` Archit Taneja
2015-12-18 18:48 ` Boris Brezillon
2015-12-16 19:16 ` Brian Norris
2015-08-19 4:49 ` [PATCH v4 3/5] dt/bindings: qcom_nandc: Add DT bindings Archit Taneja
2015-12-16 6:33 ` Boris Brezillon
2015-12-16 8:11 ` Archit Taneja
2015-08-19 4:49 ` [PATCH v4 4/5] arm: qcom: dts: Add NAND controller node for ipq806x Archit Taneja
2015-08-19 4:49 ` [PATCH v4 5/5] arm: qcom: dts: Enable NAND node on IPQ8064 AP148 platform Archit Taneja
2016-01-05 5:24 ` [PATCH v5 0/3] mtd: Qualcomm NAND controller driver Archit Taneja
2016-01-05 5:24 ` [PATCH v5 1/3] mtd: nand: don't select chip in nand_chip's block_bad op Archit Taneja
2016-01-06 16:05 ` Boris Brezillon
2016-01-07 4:27 ` Archit Taneja
2016-01-05 5:25 ` [PATCH v5 2/3] mtd: nand: Qualcomm NAND controller driver Archit Taneja
2016-01-06 17:05 ` Boris Brezillon
2016-01-08 6:33 ` Archit Taneja
2016-01-08 8:01 ` Boris Brezillon
2016-01-08 10:23 ` Archit Taneja
2016-01-08 10:31 ` Boris Brezillon
2016-01-08 10:42 ` Archit Taneja
2016-01-05 5:25 ` [PATCH v5 3/3] dt/bindings: qcom_nandc: Add DT bindings Archit Taneja
2016-01-06 15:05 ` Boris Brezillon
2016-01-06 15:14 ` Rob Herring
2016-01-06 15:37 ` Boris Brezillon
2016-01-06 16:13 ` Rob Herring
2016-01-06 16:36 ` Boris Brezillon
2016-01-18 9:50 ` [PATCH v6 0/3] mtd: Qualcomm NAND controller driver Archit Taneja
2016-01-18 9:50 ` [PATCH v6 1/3] mtd: nand: don't select chip in nand_chip's block_bad op Archit Taneja
2016-01-18 10:29 ` Boris Brezillon
2016-01-18 10:47 ` Archit Taneja
2016-01-18 9:50 ` [PATCH v6 2/3] mtd: nand: Qualcomm NAND controller driver Archit Taneja
2016-01-18 11:01 ` Boris Brezillon
2016-01-18 11:14 ` Archit Taneja
2016-01-18 9:50 ` [PATCH v6 3/3] dt/bindings: qcom_nandc: Add DT bindings Archit Taneja
2016-01-20 14:46 ` Rob Herring
2016-01-21 7:13 ` [PATCH v7 0/3] mtd: Qualcomm NAND controller driver Archit Taneja
2016-01-21 7:13 ` [PATCH v7 1/3] mtd: nand: don't select chip in nand_chip's block_bad op Archit Taneja
2016-01-21 8:33 ` Boris Brezillon
2016-01-21 7:13 ` [PATCH v7 2/3] mtd: nand: Qualcomm NAND controller driver Archit Taneja
2016-01-21 8:51 ` Boris Brezillon
2016-01-21 9:52 ` Archit Taneja
2016-01-21 10:13 ` Boris Brezillon
2016-01-21 11:00 ` Archit Taneja
2016-01-21 12:36 ` Boris Brezillon
2016-01-21 13:08 ` Archit Taneja
2016-01-21 13:25 ` Boris Brezillon
2016-01-25 7:43 ` Archit Taneja
2016-01-21 7:13 ` [PATCH v7 3/3] dt/bindings: qcom_nandc: Add DT bindings Archit Taneja
2016-01-21 7:23 ` Archit Taneja
2016-02-03 8:59 ` [PATCH v8 0/3] mtd: Qualcomm NAND controller driver Archit Taneja
2016-02-03 8:59 ` [PATCH v8 1/3] mtd: nand: don't select chip in nand_chip's block_bad op Archit Taneja
2016-02-03 8:59 ` [PATCH v8 2/3] mtd: nand: Qualcomm NAND controller driver Archit Taneja
2016-02-04 10:39 ` Boris Brezillon
2016-02-04 16:13 ` Archit Taneja
2016-02-16 6:50 ` Archit Taneja
2016-03-08 10:13 ` Archit Taneja
2016-03-18 15:49 ` Boris Brezillon
2016-03-18 16:48 ` Boris Brezillon
2016-03-19 10:14 ` Archit Taneja
2016-03-19 10:34 ` Boris Brezillon
2016-03-22 13:10 ` Archit Taneja
2016-03-22 14:05 ` Boris Brezillon
2016-02-03 8:59 ` [PATCH v8 3/3] dt/bindings: qcom_nandc: Add DT bindings Archit Taneja
2016-03-10 19:47 ` [PATCH v8 0/3] mtd: Qualcomm NAND controller driver Brian Norris
2016-03-16 5:43 ` Archit Taneja
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=55C0D483.7020405@codeaurora.org \
--to=architt@codeaurora.org \
--cc=agross@codeaurora.org \
--cc=cernekee@gmail.com \
--cc=computersforpeace@gmail.com \
--cc=dehrenberg@google.com \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mtd@lists.infradead.org \
--cc=sboyd@codeaurora.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).