From d6a3f0176fe03c33f2853dfef33e15547e357dd0 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sun, 9 Nov 2014 07:21:13 -0500 Subject: mtd: block2mtd: wait until block devices are presented Ensures that block2mtd is triggered after the block devices are enumerated at boot time. This issue is seen on BCM2835 (Raspberry Pi) systems when mounting JFFS2 block2mtd filesystems, probably because of the delay on enumerating a USB MMC card reader. Signed-off-by: Felix Fietkau Signed-off-by: Rodrigo Freire Signed-off-by: Herton Krzesinski Signed-off-by: Brian Norris --- drivers/mtd/devices/block2mtd.c | 58 ++++++++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c index 66f0405f7e53..b16f3cda97ff 100644 --- a/drivers/mtd/devices/block2mtd.c +++ b/drivers/mtd/devices/block2mtd.c @@ -9,7 +9,15 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +/* + * When the first attempt at device initialization fails, we may need to + * wait a little bit and retry. This timeout, by default 3 seconds, gives + * device time to start up. Required on BCM2708 and a few other chipsets. + */ +#define MTD_DEFAULT_TIMEOUT 3 + #include +#include #include #include #include @@ -209,10 +217,14 @@ static void block2mtd_free_device(struct block2mtd_dev *dev) } -static struct block2mtd_dev *add_device(char *devname, int erase_size) +static struct block2mtd_dev *add_device(char *devname, int erase_size, + int timeout) { +#ifndef MODULE + int i; +#endif const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL; - struct block_device *bdev; + struct block_device *bdev = ERR_PTR(-ENODEV); struct block2mtd_dev *dev; char *name; @@ -225,15 +237,28 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size) /* Get a handle on the device */ bdev = blkdev_get_by_path(devname, mode, dev); -#ifndef MODULE - if (IS_ERR(bdev)) { - - /* We might not have rootfs mounted at this point. Try - to resolve the device name by other means. */ - dev_t devt = name_to_dev_t(devname); - if (devt) - bdev = blkdev_get_by_dev(devt, mode, dev); +#ifndef MODULE + /* + * We might not have the root device mounted at this point. + * Try to resolve the device name by other means. + */ + for (i = 0; IS_ERR(bdev) && i <= timeout; i++) { + dev_t devt; + + if (i) + /* + * Calling wait_for_device_probe in the first loop + * was not enough, sleep for a bit in subsequent + * go-arounds. + */ + msleep(1000); + wait_for_device_probe(); + + devt = name_to_dev_t(devname); + if (!devt) + continue; + bdev = blkdev_get_by_dev(devt, mode, dev); } #endif @@ -280,6 +305,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size) /* Device didn't get added, so free the entry */ goto err_destroy_mutex; } + list_add(&dev->list, &blkmtd_device_list); pr_info("mtd%d: [%s] erase_size = %dKiB [%d]\n", dev->mtd.index, @@ -348,16 +374,19 @@ static inline void kill_final_newline(char *str) #ifndef MODULE static int block2mtd_init_called = 0; -static char block2mtd_paramline[80 + 12]; /* 80 for device, 12 for erase size */ +/* 80 for device, 12 for erase size */ +static char block2mtd_paramline[80 + 12]; #endif static int block2mtd_setup2(const char *val) { - char buf[80 + 12]; /* 80 for device, 12 for erase size */ + /* 80 for device, 12 for erase size, 80 for name, 8 for timeout */ + char buf[80 + 12 + 80 + 8]; char *str = buf; char *token[2]; char *name; size_t erase_size = PAGE_SIZE; + unsigned long timeout = MTD_DEFAULT_TIMEOUT; int i, ret; if (strnlen(val, sizeof(buf)) >= sizeof(buf)) { @@ -395,7 +424,7 @@ static int block2mtd_setup2(const char *val) } } - add_device(name, erase_size); + add_device(name, erase_size, timeout); return 0; } @@ -463,8 +492,7 @@ static void block2mtd_exit(void) } } - -module_init(block2mtd_init); +late_initcall(block2mtd_init); module_exit(block2mtd_exit); MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 24542257a3b987025d4b998ec2d15e556c98ad3f Mon Sep 17 00:00:00 2001 From: Robert Jarzmik Date: Fri, 20 Feb 2015 19:36:43 +0100 Subject: mtd: pxa3xx-nand: handle PIO in threaded interrupt Change the handling of the data stage in the driver : don't pump data in the top-half interrupt, but rather schedule a thread for non dma cases. This will enable latencies in the data pumping, especially if delays are required. Moreover platform shall be more reactive as other interrupts can be served while pumping data. No throughput degradation was observed, at least on the zylonite platform, while a slight degradation was being expected. Signed-off-by: Robert Jarzmik Tested-by: Maxime Ripard Signed-off-by: Brian Norris --- drivers/mtd/nand/pxa3xx_nand.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index bc677362bc73..3f09f2e9aeb4 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -605,11 +605,24 @@ static void start_data_dma(struct pxa3xx_nand_info *info) {} #endif +static irqreturn_t pxa3xx_nand_irq_thread(int irq, void *data) +{ + struct pxa3xx_nand_info *info = data; + + handle_data_pio(info); + + info->state = STATE_CMD_DONE; + nand_writel(info, NDSR, NDSR_WRDREQ | NDSR_RDDREQ); + + return IRQ_HANDLED; +} + static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) { struct pxa3xx_nand_info *info = devid; unsigned int status, is_completed = 0, is_ready = 0; unsigned int ready, cmd_done; + irqreturn_t ret = IRQ_HANDLED; if (info->cs == 0) { ready = NDSR_FLASH_RDY; @@ -651,7 +664,8 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) } else { info->state = (status & NDSR_RDDREQ) ? STATE_PIO_READING : STATE_PIO_WRITING; - handle_data_pio(info); + ret = IRQ_WAKE_THREAD; + goto NORMAL_IRQ_EXIT; } } if (status & cmd_done) { @@ -692,7 +706,7 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid) if (is_ready) complete(&info->dev_ready); NORMAL_IRQ_EXIT: - return IRQ_HANDLED; + return ret; } static inline int is_buf_blank(uint8_t *buf, size_t len) @@ -1708,7 +1722,9 @@ static int alloc_nand_resource(struct platform_device *pdev) /* initialize all interrupts to be disabled */ disable_int(info, NDSR_MASK); - ret = request_irq(irq, pxa3xx_nand_irq, 0, pdev->name, info); + ret = request_threaded_irq(irq, pxa3xx_nand_irq, + pxa3xx_nand_irq_thread, IRQF_ONESHOT, + pdev->name, info); if (ret < 0) { dev_err(&pdev->dev, "failed to request IRQ\n"); goto fail_free_buf; -- cgit v1.2.3 From 7c2f717668af10ab6d4aaed22a5d29f06812ee62 Mon Sep 17 00:00:00 2001 From: Antoine Ténart Date: Thu, 12 Feb 2015 15:53:27 +0100 Subject: mtd: pxa3xx_nand: initialiaze pxa3xx_flash_ids to 0 pxa3xx_flash_ids wasn't initialized to 0, which in certain cases could end up containing corrupted values in its members. Fix this to avoid possible issues. Signed-off-by: Antoine Tenart Signed-off-by: Brian Norris --- drivers/mtd/nand/pxa3xx_nand.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index 57562c85cc8c..b1ecb570d154 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -1522,6 +1522,8 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd) return ret; } + memset(pxa3xx_flash_ids, 0, sizeof(pxa3xx_flash_ids)); + pxa3xx_flash_ids[0].name = f->name; pxa3xx_flash_ids[0].dev_id = (f->chip_id >> 8) & 0xffff; pxa3xx_flash_ids[0].pagesize = f->page_size; -- cgit v1.2.3 From a05973a79efe9152391065c87c12d5c1e146a736 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 6 Feb 2015 03:25:28 -0800 Subject: mtd: s3c2410: drop useless / misspelled debug prints s3c2410_nand_probe is not the name of the function. These prints have little utility, so let's just kill them. Reported-by: Julia Lawall Signed-off-by: Brian Norris --- drivers/mtd/nand/s3c2410.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c index 35aef5edb588..0e02be47ce1d 100644 --- a/drivers/mtd/nand/s3c2410.c +++ b/drivers/mtd/nand/s3c2410.c @@ -948,8 +948,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev) cpu_type = platform_get_device_id(pdev)->driver_data; - pr_debug("s3c2410_nand_probe(%p)\n", pdev); - info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); if (info == NULL) { err = -ENOMEM; @@ -1045,7 +1043,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev) s3c2410_nand_clk_set_state(info, CLOCK_SUSPEND); } - pr_debug("initialised ok\n"); return 0; exit_error: -- cgit v1.2.3 From 393d23c4e22996ad0c694577927bcf13ba31beda Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 28 Feb 2015 20:27:56 +0000 Subject: mtd: atmel_nand: fix typo in dev_err error message Fix typo, "Unkown" -> "Unknown" Signed-off-by: Colin Ian King Acked-by: Josh Wu Signed-off-by: Brian Norris --- drivers/mtd/nand/atmel_nand.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index d93c849b70b5..13104507da63 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -1719,7 +1719,7 @@ static int nfc_wait_interrupt(struct atmel_nand_host *host, u32 flag) comp[index++] = &host->nfc->comp_cmd_done; if (index == 0) { - dev_err(host->dev, "Unkown interrupt flag: 0x%08x\n", flag); + dev_err(host->dev, "Unknown interrupt flag: 0x%08x\n", flag); return -EINVAL; } -- cgit v1.2.3 From 111573ccd89b67fdef64d945cc0e611df85a6ac8 Mon Sep 17 00:00:00 2001 From: Boris Brezillon Date: Thu, 22 Jan 2015 18:21:30 +0800 Subject: mtd: atmel_nand: check NFC busy flag by HSMC_SR instead of NFC cmd regs Currently the driver read NFC command registers to get NFC busy flag. Actually this flag also can be get by reading HSMC_SR register. Use the read NFC command registers need mapping a huge memory region. To save the mapped memory region, we change to check NFC busy flag by reading HSMC_SR register. Signed-off-by: Boris Brezillon Signed-off-by: Josh Wu Signed-off-by: Brian Norris --- drivers/mtd/nand/atmel_nand.c | 5 ++--- drivers/mtd/nand/atmel_nand_nfc.h | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 13104507da63..feaac9099bb9 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -1752,11 +1752,10 @@ static int nfc_send_command(struct atmel_nand_host *host, cmd, addr, cycle0); timeout = jiffies + msecs_to_jiffies(NFC_TIME_OUT_MS); - while (nfc_cmd_readl(NFCADDR_CMD_NFCBUSY, host->nfc->base_cmd_regs) - & NFCADDR_CMD_NFCBUSY) { + while (nfc_readl(host->nfc->hsmc_regs, SR) & NFC_SR_BUSY) { if (time_after(jiffies, timeout)) { dev_err(host->dev, - "Time out to wait CMD_NFCBUSY ready!\n"); + "Time out to wait for NFC ready!\n"); return -ETIMEDOUT; } } diff --git a/drivers/mtd/nand/atmel_nand_nfc.h b/drivers/mtd/nand/atmel_nand_nfc.h index 85b8ca6af7d2..4d5d26221a7e 100644 --- a/drivers/mtd/nand/atmel_nand_nfc.h +++ b/drivers/mtd/nand/atmel_nand_nfc.h @@ -35,6 +35,7 @@ #define NFC_CTRL_DISABLE (1 << 1) #define ATMEL_HSMC_NFC_SR 0x08 /* NFC Status Register */ +#define NFC_SR_BUSY (1 << 8) #define NFC_SR_XFR_DONE (1 << 16) #define NFC_SR_CMD_DONE (1 << 17) #define NFC_SR_DTOE (1 << 20) -- cgit v1.2.3 From e35d1d8a1d16e9f56a9b54c96d0cb85ed621bb89 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 10 Feb 2015 19:59:55 +0100 Subject: mtd: mxc-nand: Add a timeout when waiting for interrupt MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit While extending the mxc-nand driver it happend to me a few times that the device was stuck and this made the machine hang during boot. So implement a timeout and print a stack trace the first time this happens to make it debuggable. The return type of the waiting function is also changed to int to be able to handle the timeout in the caller. Signed-off-by: Uwe Kleine-König Signed-off-by: Brian Norris --- drivers/mtd/nand/mxc_nand.c | 47 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 36 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index a8f550fec35e..27ba07c07966 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -386,26 +386,51 @@ static irqreturn_t mxc_nfc_irq(int irq, void *dev_id) /* This function polls the NANDFC to wait for the basic operation to * complete by checking the INT bit of config2 register. */ -static void wait_op_done(struct mxc_nand_host *host, int useirq) +static int wait_op_done(struct mxc_nand_host *host, int useirq) { - int max_retries = 8000; + int ret = 0; + + /* + * If operation is already complete, don't bother to setup an irq or a + * loop. + */ + if (host->devtype_data->check_int(host)) + return 0; if (useirq) { - if (!host->devtype_data->check_int(host)) { - reinit_completion(&host->op_completion); - irq_control(host, 1); - wait_for_completion(&host->op_completion); + unsigned long timeout; + + reinit_completion(&host->op_completion); + + irq_control(host, 1); + + timeout = wait_for_completion_timeout(&host->op_completion, HZ); + if (!timeout && !host->devtype_data->check_int(host)) { + dev_dbg(host->dev, "timeout waiting for irq\n"); + ret = -ETIMEDOUT; } } else { - while (max_retries-- > 0) { - if (host->devtype_data->check_int(host)) - break; + int max_retries = 8000; + int done; + do { udelay(1); + + done = host->devtype_data->check_int(host); + if (done) + break; + + } while (--max_retries); + + if (!done) { + dev_dbg(host->dev, "timeout polling for completion\n"); + ret = -ETIMEDOUT; } - if (max_retries < 0) - pr_debug("%s: INT not set\n", __func__); } + + WARN_ONCE(ret < 0, "timeout! useirq=%d\n", useirq); + + return ret; } static void send_cmd_v3(struct mxc_nand_host *host, uint16_t cmd, int useirq) -- cgit v1.2.3 From 1f42adc8880d0692c3cb7b6adb247f17c4983081 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 10 Feb 2015 19:59:56 +0100 Subject: mtd: mxc-nand: Only enable hardware checksumming for fully detected flashes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit At least on i.MX25 (i.e. NFCv2) preset_v2 is called with mtd->writesize == 0 that is before the connect flash chip is detected. It then configures for 8 bit ECC mode which needs 26 bytes of OOB per 512 bytes main section. For flashes with a smaller OOB area issuing a read page command makes the controller stuck with this config. Note that this currently doesn't hurt because the first read page command is issued only after detection is complete and preset is called once more. Signed-off-by: Uwe Kleine-König Signed-off-by: Brian Norris --- drivers/mtd/nand/mxc_nand.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 27ba07c07966..d9637ae34719 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -928,7 +928,7 @@ static void preset_v1(struct mtd_info *mtd) struct mxc_nand_host *host = nand_chip->priv; uint16_t config1 = 0; - if (nand_chip->ecc.mode == NAND_ECC_HW) + if (nand_chip->ecc.mode == NAND_ECC_HW && mtd->writesize) config1 |= NFC_V1_V2_CONFIG1_ECC_EN; if (!host->devtype_data->irqpending_quirk) @@ -956,9 +956,6 @@ static void preset_v2(struct mtd_info *mtd) struct mxc_nand_host *host = nand_chip->priv; uint16_t config1 = 0; - if (nand_chip->ecc.mode == NAND_ECC_HW) - config1 |= NFC_V1_V2_CONFIG1_ECC_EN; - config1 |= NFC_V2_CONFIG1_FP_INT; if (!host->devtype_data->irqpending_quirk) @@ -967,6 +964,9 @@ static void preset_v2(struct mtd_info *mtd) if (mtd->writesize) { uint16_t pages_per_block = mtd->erasesize / mtd->writesize; + if (nand_chip->ecc.mode == NAND_ECC_HW) + config1 |= NFC_V1_V2_CONFIG1_ECC_EN; + host->eccsize = get_eccsize(mtd); if (host->eccsize == 4) config1 |= NFC_V2_CONFIG1_ECC_MODE_4; @@ -1024,9 +1024,6 @@ static void preset_v3(struct mtd_info *mtd) NFC_V3_CONFIG2_INT_MSK | NFC_V3_CONFIG2_NUM_ADDR_PHASE0; - if (chip->ecc.mode == NAND_ECC_HW) - config2 |= NFC_V3_CONFIG2_ECC_EN; - addr_phases = fls(chip->pagemask) >> 3; if (mtd->writesize == 2048) { @@ -1041,6 +1038,9 @@ static void preset_v3(struct mtd_info *mtd) } if (mtd->writesize) { + if (chip->ecc.mode == NAND_ECC_HW) + config2 |= NFC_V3_CONFIG2_ECC_EN; + config2 |= NFC_V3_CONFIG2_PPB( ffs(mtd->erasesize / mtd->writesize) - 6, host->devtype_data->ppb_shift); -- cgit v1.2.3 From 3f410690f511f9531fdc0865a931522b049d7b29 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 10 Feb 2015 19:59:57 +0100 Subject: mtd: mxc-nand: Do the word to byte mangling in the read_byte callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the hardware operates in 16 bit mode it always reads 16 bits even for operations that only have the lower 8 bits defined. So the upper bits must be discarded. Do this in the read_byte callback instead of when reading the NAND id to support reading byte wise more than 5 bytes and at other occations (like reading the ONFI parameter page). Signed-off-by: Uwe Kleine-König Signed-off-by: Brian Norris --- drivers/mtd/nand/mxc_nand.c | 34 ++++++++++------------------------ 1 file changed, 10 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index d9637ae34719..aa98a0dddcfb 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -552,30 +552,17 @@ static void send_page_v1(struct mtd_info *mtd, unsigned int ops) static void send_read_id_v3(struct mxc_nand_host *host) { - struct nand_chip *this = &host->nand; - /* Read ID into main buffer */ writel(NFC_ID, NFC_V3_LAUNCH); wait_op_done(host, true); memcpy32_fromio(host->data_buf, host->main_area0, 16); - - if (this->options & NAND_BUSWIDTH_16) { - /* compress the ID info */ - host->data_buf[1] = host->data_buf[2]; - host->data_buf[2] = host->data_buf[4]; - host->data_buf[3] = host->data_buf[6]; - host->data_buf[4] = host->data_buf[8]; - host->data_buf[5] = host->data_buf[10]; - } } /* Request the NANDFC to perform a read of the NAND device ID. */ static void send_read_id_v1_v2(struct mxc_nand_host *host) { - struct nand_chip *this = &host->nand; - /* NANDFC buffer 0 is used for device ID output */ writew(host->active_cs << 4, NFC_V1_V2_BUF_ADDR); @@ -585,15 +572,6 @@ static void send_read_id_v1_v2(struct mxc_nand_host *host) wait_op_done(host, true); memcpy32_fromio(host->data_buf, host->main_area0, 16); - - if (this->options & NAND_BUSWIDTH_16) { - /* compress the ID info */ - host->data_buf[1] = host->data_buf[2]; - host->data_buf[2] = host->data_buf[4]; - host->data_buf[3] = host->data_buf[6]; - host->data_buf[4] = host->data_buf[8]; - host->data_buf[5] = host->data_buf[10]; - } } static uint16_t get_dev_status_v3(struct mxc_nand_host *host) @@ -719,9 +697,17 @@ static u_char mxc_nand_read_byte(struct mtd_info *mtd) if (host->status_request) return host->devtype_data->get_dev_status(host) & 0xFF; - ret = *(uint8_t *)(host->data_buf + host->buf_start); - host->buf_start++; + if (nand_chip->options & NAND_BUSWIDTH_16) { + /* only take the lower byte of each word */ + ret = *(uint16_t *)(host->data_buf + host->buf_start); + + host->buf_start += 2; + } else { + ret = *(uint8_t *)(host->data_buf + host->buf_start); + host->buf_start++; + } + pr_debug("%s: ret=0x%hhx (start=%u)\n", __func__, ret, host->buf_start); return ret; } -- cgit v1.2.3 From c4ca3997ef954bcba009cce0e325f3155bdde01a Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 10 Feb 2015 19:59:58 +0100 Subject: mtd: mxc-nand: Allow to use column addresses different from 0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mxc-nand controller works pagewise and so usually only sends commands to the flash chip with column == 0. A request with column != 0 from the upper layer is then fulfilled by indexing appropriately into the device's RAM buffer. To be able to access the ONFI marker at offset 0x20 in reply to the READID command however it's invalid to read 32 bytes starting from column 0. So let the function used to send the address cycles send the column address actually passed instead of 0 and fix all callers to pass 0 instead appropriately. Also add some warnings in case this patch changes the drivers semantics. Signed-off-by: Uwe Kleine-König Signed-off-by: Brian Norris --- drivers/mtd/nand/mxc_nand.c | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index aa98a0dddcfb..0afe5904a337 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -836,6 +836,12 @@ static void copy_spare(struct mtd_info *mtd, bool bfrom) } } +/* + * MXC NANDFC can only perform full page+spare or spare-only read/write. When + * the upper layers perform a read/write buf operation, the saved column address + * is used to index into the full page. So usually this function is called with + * column == 0 (unless no column cycle is needed indicated by column == -1) + */ static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr) { struct nand_chip *nand_chip = mtd->priv; @@ -843,16 +849,13 @@ static void mxc_do_addr_cycle(struct mtd_info *mtd, int column, int page_addr) /* Write out column address, if necessary */ if (column != -1) { - /* - * MXC NANDFC can only perform full page+spare or - * spare-only read/write. When the upper layers - * perform a read/write buf operation, the saved column - * address is used to index into the full page. - */ - host->devtype_data->send_addr(host, 0, page_addr == -1); + host->devtype_data->send_addr(host, column & 0xff, + page_addr == -1); if (mtd->writesize > 512) /* another col addr cycle for 2k page */ - host->devtype_data->send_addr(host, 0, false); + host->devtype_data->send_addr(host, + (column >> 8) & 0xff, + false); } /* Write out page address, if necessary */ @@ -1077,6 +1080,9 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, host->status_request = true; host->devtype_data->send_cmd(host, command, true); + WARN_ONCE(column != -1 || page_addr != -1, + "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n", + command, column, page_addr); mxc_do_addr_cycle(mtd, column, page_addr); break; @@ -1090,7 +1096,10 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, command = NAND_CMD_READ0; /* only READ0 is valid */ host->devtype_data->send_cmd(host, command, false); - mxc_do_addr_cycle(mtd, column, page_addr); + WARN_ONCE(column < 0, + "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n", + command, column, page_addr); + mxc_do_addr_cycle(mtd, 0, page_addr); if (mtd->writesize > 512) host->devtype_data->send_cmd(host, @@ -1111,7 +1120,10 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, host->buf_start = column; host->devtype_data->send_cmd(host, command, false); - mxc_do_addr_cycle(mtd, column, page_addr); + WARN_ONCE(column < -1, + "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n", + command, column, page_addr); + mxc_do_addr_cycle(mtd, 0, page_addr); break; case NAND_CMD_PAGEPROG: @@ -1119,6 +1131,9 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, copy_spare(mtd, false); host->devtype_data->send_page(mtd, NFC_INPUT); host->devtype_data->send_cmd(host, command, true); + WARN_ONCE(column != -1 || page_addr != -1, + "Unexpected column/row value (cmd=%u, col=%d, row=%d)\n", + command, column, page_addr); mxc_do_addr_cycle(mtd, column, page_addr); break; @@ -1126,12 +1141,15 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, host->devtype_data->send_cmd(host, command, true); mxc_do_addr_cycle(mtd, column, page_addr); host->devtype_data->send_read_id(host); - host->buf_start = column; + host->buf_start = 0; break; case NAND_CMD_ERASE1: case NAND_CMD_ERASE2: host->devtype_data->send_cmd(host, command, false); + WARN_ONCE(column != -1, + "Unexpected column value (cmd=%u, col=%d)\n", + command, column); mxc_do_addr_cycle(mtd, column, page_addr); break; -- cgit v1.2.3 From 3d6e81c0c9827c86fd3fe4bcbc44155b1401f80e Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 10 Feb 2015 19:59:59 +0100 Subject: mtd: mxc-nand: Implement support for PARAM command MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mxc-nand driver never supported the PARAM command to read out the ONFI parameter page and so always relied on probing my manufacturer and device id (as provided by the READID command). This patch implements reading out the first parameter page copy at least which should be good enough in practise. This makes the boot log change from nand: device found, Manufacturer ID: 0x2c, Chip ID: 0xb1 nand: Micron NAND 128MiB 1,8V 16-bit to nand: device found, Manufacturer ID: 0x2c, Chip ID: 0xb1 nand: Micron MT29F1G16ABBDAH4 on my machine. Signed-off-by: Uwe Kleine-König Signed-off-by: Brian Norris --- drivers/mtd/nand/mxc_nand.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 0afe5904a337..0083b4ee4f33 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -1152,6 +1152,13 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, command, column); mxc_do_addr_cycle(mtd, column, page_addr); + break; + case NAND_CMD_PARAM: + host->devtype_data->send_cmd(host, command, false); + mxc_do_addr_cycle(mtd, column, page_addr); + host->devtype_data->send_page(mtd, NFC_OUTPUT); + memcpy32_fromio(host->data_buf, host->main_area0, 512); + host->buf_start = 0; break; } } -- cgit v1.2.3 From 98ebb521096f2d90c3e903ba79412cd92064795b Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 10 Feb 2015 20:00:00 +0100 Subject: mtd: mxc-nand: Warn on unimplemented commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The PARAM command was long unimplemented and it probably wasn't noticed because chip probing using only the few bytes returned by the READID command are good enough in most cases to determine the chip in use. Still to notice such a shortcoming earlier in the future would be nice in case it's something more vital. Signed-off-by: Uwe Kleine-König Signed-off-by: Brian Norris --- drivers/mtd/nand/mxc_nand.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/nand/mxc_nand.c b/drivers/mtd/nand/mxc_nand.c index 0083b4ee4f33..372e0e38f59b 100644 --- a/drivers/mtd/nand/mxc_nand.c +++ b/drivers/mtd/nand/mxc_nand.c @@ -1160,6 +1160,10 @@ static void mxc_nand_command(struct mtd_info *mtd, unsigned command, memcpy32_fromio(host->data_buf, host->main_area0, 512); host->buf_start = 0; break; + default: + WARN_ONCE(1, "Unimplemented command (cmd=%u)\n", + command); + break; } } -- cgit v1.2.3 From dc52499e7f2d9812cfa4aa3b8d84a3f2c97e068b Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Mon, 9 Mar 2015 10:18:16 -0700 Subject: mtd: docg3: drop dead code If no devices were found, we would already have skipped over this code. Detected by Coverity, CID #744270 Signed-off-by: Brian Norris Acked-by: Robert Jarzmik --- drivers/mtd/devices/docg3.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index 448ce42f951e..0310f9174dcc 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -2033,7 +2033,7 @@ static int __init docg3_probe(struct platform_device *pdev) struct mtd_info *mtd; struct resource *ress; void __iomem *base; - int ret, floor, found = 0; + int ret, floor; struct docg3_cascade *cascade; ret = -ENXIO; @@ -2073,14 +2073,11 @@ static int __init docg3_probe(struct platform_device *pdev) 0); if (ret) goto err_probe; - found++; } ret = doc_register_sysfs(pdev, cascade); if (ret) goto err_probe; - if (!found) - goto notfound; platform_set_drvdata(pdev, cascade); doc_dbg_register(cascade->floors[0]->priv); -- cgit v1.2.3 From 7f2a7ce17dcd381e366a65b6643239338a987715 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Sat, 28 Feb 2015 02:02:25 -0800 Subject: mtd: onenand: drop dead code 'ret' is always zero, so this is all dead code. This should quiet Coverity CID #1226739. Signed-off-by: Brian Norris Cc: Kyungmin Park --- drivers/mtd/onenand/onenand_base.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/onenand/onenand_base.c b/drivers/mtd/onenand/onenand_base.c index 635ee0027691..43b3392ffee7 100644 --- a/drivers/mtd/onenand/onenand_base.c +++ b/drivers/mtd/onenand/onenand_base.c @@ -1743,7 +1743,6 @@ static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len, struct onenand_chip *this = mtd->priv; int column, subpage; int written = 0; - int ret = 0; if (this->state == FL_PM_SUSPENDED) return -EBUSY; @@ -1786,15 +1785,10 @@ static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len, onenand_panic_wait(mtd); /* In partial page write we don't update bufferram */ - onenand_update_bufferram(mtd, to, !ret && !subpage); + onenand_update_bufferram(mtd, to, !subpage); if (ONENAND_IS_2PLANE(this)) { ONENAND_SET_BUFFERRAM1(this); - onenand_update_bufferram(mtd, to + this->writesize, !ret && !subpage); - } - - if (ret) { - printk(KERN_ERR "%s: write failed %d\n", __func__, ret); - break; + onenand_update_bufferram(mtd, to + this->writesize, !subpage); } written += thislen; @@ -1808,7 +1802,7 @@ static int onenand_panic_write(struct mtd_info *mtd, loff_t to, size_t len, } *retlen = written; - return ret; + return 0; } /** -- cgit v1.2.3 From b9da8bae416efda5ad61c7c92edbb30de15ff7ee Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Sat, 28 Feb 2015 02:02:26 -0800 Subject: mtd: tests: fix more potential integer overflows Caught by Coverity (CID #200625 and others) Signed-off-by: Brian Norris Cc: Akinobu Mita --- drivers/mtd/tests/oobtest.c | 2 +- drivers/mtd/tests/speedtest.c | 2 +- drivers/mtd/tests/stresstest.c | 4 ++-- drivers/mtd/tests/subpagetest.c | 4 ++-- drivers/mtd/tests/torturetest.c | 8 ++++---- 5 files changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/tests/oobtest.c b/drivers/mtd/tests/oobtest.c index 5e061186eab1..64390ab88a80 100644 --- a/drivers/mtd/tests/oobtest.c +++ b/drivers/mtd/tests/oobtest.c @@ -70,7 +70,7 @@ static int write_eraseblock(int ebnum) int i; struct mtd_oob_ops ops; int err = 0; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; prandom_bytes_state(&rnd_state, writebuf, use_len_max * pgcnt); for (i = 0; i < pgcnt; ++i, addr += mtd->writesize) { diff --git a/drivers/mtd/tests/speedtest.c b/drivers/mtd/tests/speedtest.c index 5ee9f7021020..a77019cb5510 100644 --- a/drivers/mtd/tests/speedtest.c +++ b/drivers/mtd/tests/speedtest.c @@ -185,7 +185,7 @@ static long calc_speed(void) (finish.tv_usec - start.tv_usec) / 1000; if (ms == 0) return 0; - k = goodebcnt * (mtd->erasesize / 1024) * 1000; + k = (uint64_t)goodebcnt * (mtd->erasesize / 1024) * 1000; do_div(k, ms); return k; } diff --git a/drivers/mtd/tests/stresstest.c b/drivers/mtd/tests/stresstest.c index c9d42cc2df1b..d90c1c01dac6 100644 --- a/drivers/mtd/tests/stresstest.c +++ b/drivers/mtd/tests/stresstest.c @@ -96,7 +96,7 @@ static int do_read(void) if (offs + len > mtd->erasesize) len = mtd->erasesize - offs; } - addr = eb * mtd->erasesize + offs; + addr = (loff_t)eb * mtd->erasesize + offs; return mtdtest_read(mtd, addr, len, readbuf); } @@ -124,7 +124,7 @@ static int do_write(void) offsets[eb + 1] = 0; } } - addr = eb * mtd->erasesize + offs; + addr = (loff_t)eb * mtd->erasesize + offs; err = mtdtest_write(mtd, addr, len, writebuf); if (unlikely(err)) return err; diff --git a/drivers/mtd/tests/subpagetest.c b/drivers/mtd/tests/subpagetest.c index 7b59ef522d5e..0b835c631f91 100644 --- a/drivers/mtd/tests/subpagetest.c +++ b/drivers/mtd/tests/subpagetest.c @@ -95,7 +95,7 @@ static int write_eraseblock2(int ebnum) loff_t addr = (loff_t)ebnum * mtd->erasesize; for (k = 1; k < 33; ++k) { - if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize) + if (addr + (subpgsize * k) > (loff_t)(ebnum + 1) * mtd->erasesize) break; prandom_bytes_state(&rnd_state, writebuf, subpgsize * k); err = mtd_write(mtd, addr, subpgsize * k, &written, writebuf); @@ -195,7 +195,7 @@ static int verify_eraseblock2(int ebnum) loff_t addr = (loff_t)ebnum * mtd->erasesize; for (k = 1; k < 33; ++k) { - if (addr + (subpgsize * k) > (ebnum + 1) * mtd->erasesize) + if (addr + (subpgsize * k) > (loff_t)(ebnum + 1) * mtd->erasesize) break; prandom_bytes_state(&rnd_state, writebuf, subpgsize * k); clear_data(readbuf, subpgsize * k); diff --git a/drivers/mtd/tests/torturetest.c b/drivers/mtd/tests/torturetest.c index b55bc52a1340..5045cf1b3160 100644 --- a/drivers/mtd/tests/torturetest.c +++ b/drivers/mtd/tests/torturetest.c @@ -101,11 +101,11 @@ static inline int check_eraseblock(int ebnum, unsigned char *buf) { int err, retries = 0; size_t read; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; size_t len = mtd->erasesize; if (pgcnt) { - addr = (ebnum + 1) * mtd->erasesize - pgcnt * pgsize; + addr = (loff_t)(ebnum + 1) * mtd->erasesize - pgcnt * pgsize; len = pgcnt * pgsize; } @@ -155,11 +155,11 @@ static inline int write_pattern(int ebnum, void *buf) { int err; size_t written; - loff_t addr = ebnum * mtd->erasesize; + loff_t addr = (loff_t)ebnum * mtd->erasesize; size_t len = mtd->erasesize; if (pgcnt) { - addr = (ebnum + 1) * mtd->erasesize - pgcnt * pgsize; + addr = (loff_t)(ebnum + 1) * mtd->erasesize - pgcnt * pgsize; len = pgcnt * pgsize; } err = mtd_write(mtd, addr, len, &written, buf); -- cgit v1.2.3 From b1a2348a1ac1380adf429035dbf3fdad0d5367bc Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Sat, 28 Feb 2015 02:02:27 -0800 Subject: mtd: nand: fixup bounds checks for nand_{lock,unlock}() Coverity noticed that these 'ret' assignments weren't being used. Let's use them. Note that nand_lock() and nand_unlock() are still not officially used by any drivers. Coverity CIDs #1227054 and #1227037 Signed-off-by: Brian Norris --- drivers/mtd/nand/nand_base.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index df7eb4ff07d1..5488a7ad63e7 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -968,7 +968,7 @@ int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) __func__, (unsigned long long)ofs, len); if (check_offs_len(mtd, ofs, len)) - ret = -EINVAL; + return -EINVAL; /* Align to last block address if size addresses end of the device */ if (ofs + len == mtd->size) @@ -1031,7 +1031,7 @@ int nand_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) __func__, (unsigned long long)ofs, len); if (check_offs_len(mtd, ofs, len)) - ret = -EINVAL; + return -EINVAL; nand_get_device(mtd, FL_LOCKING); -- cgit v1.2.3 From 99f6d50dc81ef713f64abbb5ec6b94167203d8c5 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Sat, 28 Feb 2015 02:02:28 -0800 Subject: mtd: nand: denali: drop dead code TclsRising is always 1. Caught by Coverity. Signed-off-by: Brian Norris Cc: Masahiro Yamada --- drivers/mtd/nand/denali.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index f44c6061536a..09f51395f2c0 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -225,7 +225,6 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, uint16_t Twhr[6] = {120, 80, 80, 60, 60, 60}; uint16_t Tcs[6] = {70, 35, 25, 25, 20, 15}; - uint16_t TclsRising = 1; uint16_t data_invalid_rhoh, data_invalid_rloh, data_invalid; uint16_t dv_window = 0; uint16_t en_lo, en_hi; @@ -276,8 +275,6 @@ static void nand_onfi_timing_set(struct denali_nand_info *denali, re_2_re = CEIL_DIV(Trhz[mode], CLK_X); we_2_re = CEIL_DIV(Twhr[mode], CLK_X); cs_cnt = CEIL_DIV((Tcs[mode] - Trp[mode]), CLK_X); - if (!TclsRising) - cs_cnt = CEIL_DIV(Tcs[mode], CLK_X); if (cs_cnt == 0) cs_cnt = 1; -- cgit v1.2.3 From e22b7651ef23ad90eed4bdbe75f12194f47d7a4f Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Sat, 28 Feb 2015 02:02:29 -0800 Subject: mtd: blkdevs: remove dead code The only exit (break) from the preceding loop is nested within a condition which yields req == NULL. This code is dead. Coverity CID #752669 Signed-off-by: Brian Norris --- drivers/mtd/mtd_blkdevs.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c index d08229eb44d8..2b0c52870999 100644 --- a/drivers/mtd/mtd_blkdevs.c +++ b/drivers/mtd/mtd_blkdevs.c @@ -171,9 +171,6 @@ static void mtd_blktrans_work(struct work_struct *work) background_done = 0; } - if (req) - __blk_end_request_all(req, -EIO); - spin_unlock_irq(rq->queue_lock); } -- cgit v1.2.3 From 0ec56dc4a1489d5b1d23d1c019b76a69ce153805 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Sat, 28 Feb 2015 02:02:30 -0800 Subject: mtd: nand: fully initialize mtd_oob_ops We're not initializing the ooblen field. Our users don't care, since they check that oobbuf == NULL first, but it's good practice to zero unused fields out. We can drop the NULL initializations since we're memset()ing the whole thing. Noticed by Coverity, CID #200821, #200822 Signed-off-by: Brian Norris --- drivers/mtd/nand/nand_base.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 5488a7ad63e7..d4cec2f8a016 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -386,7 +386,7 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs) uint8_t buf[2] = { 0, 0 }; int ret = 0, res, i = 0; - ops.datbuf = NULL; + memset(&ops, 0, sizeof(ops)); ops.oobbuf = buf; ops.ooboffs = chip->badblockpos; if (chip->options & NAND_BUSWIDTH_16) { @@ -1716,9 +1716,9 @@ static int nand_read(struct mtd_info *mtd, loff_t from, size_t len, int ret; nand_get_device(mtd, FL_READING); + memset(&ops, 0, sizeof(ops)); ops.len = len; ops.datbuf = buf; - ops.oobbuf = NULL; ops.mode = MTD_OPS_PLACE_OOB; ret = nand_do_read_ops(mtd, from, &ops); *retlen = ops.retlen; @@ -2508,9 +2508,9 @@ static int panic_nand_write(struct mtd_info *mtd, loff_t to, size_t len, /* Grab the device */ panic_nand_get_device(chip, mtd, FL_WRITING); + memset(&ops, 0, sizeof(ops)); ops.len = len; ops.datbuf = (uint8_t *)buf; - ops.oobbuf = NULL; ops.mode = MTD_OPS_PLACE_OOB; ret = nand_do_write_ops(mtd, to, &ops); @@ -2536,9 +2536,9 @@ static int nand_write(struct mtd_info *mtd, loff_t to, size_t len, int ret; nand_get_device(mtd, FL_WRITING); + memset(&ops, 0, sizeof(ops)); ops.len = len; ops.datbuf = (uint8_t *)buf; - ops.oobbuf = NULL; ops.mode = MTD_OPS_PLACE_OOB; ret = nand_do_write_ops(mtd, to, &ops); *retlen = ops.retlen; -- cgit v1.2.3 From 73c8aaf43629e83541332f66fd08699e20ea87bc Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Sat, 28 Feb 2015 02:04:18 -0800 Subject: mtd: nand: fix spelling of REPLACEABLE Signed-off-by: Brian Norris --- drivers/mtd/nand/nand_base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index d4cec2f8a016..ff5652211607 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2124,7 +2124,7 @@ static int nand_write_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip, /** - * nand_write_subpage_hwecc - [REPLACABLE] hardware ECC based subpage write + * nand_write_subpage_hwecc - [REPLACEABLE] hardware ECC based subpage write * @mtd: mtd info structure * @chip: nand chip info structure * @offset: column address of subpage within the page -- cgit v1.2.3 From 8cc7f33aadc8fb37b5a3f4c46f5fa83748a92a01 Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 13 Mar 2015 00:38:39 -0700 Subject: mtd: spi-nor: factor out replace-able flash_{lock,unlock} Flash lock/unlock is a flash-specific operations. Factor out a callback for it to more readily support other vendors. Signed-off-by: Brian Norris Tested-by: VIET NGA DAO --- drivers/mtd/spi-nor/spi-nor.c | 57 ++++++++++++++++++++++++++++--------------- include/linux/mtd/spi-nor.h | 5 ++++ 2 files changed, 43 insertions(+), 19 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index b6a5a0c269e1..60bf3caf1ead 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -369,17 +369,13 @@ erase_err: return ret; } -static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +static int stm_lock(struct spi_nor *nor, loff_t ofs, uint64_t len) { - struct spi_nor *nor = mtd_to_spi_nor(mtd); + struct mtd_info *mtd = nor->mtd; uint32_t offset = ofs; uint8_t status_old, status_new; int ret = 0; - ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_LOCK); - if (ret) - return ret; - status_old = read_sr(nor); if (offset < mtd->size - (mtd->size / 2)) @@ -402,26 +398,18 @@ static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) (status_old & (SR_BP2 | SR_BP1 | SR_BP0))) { write_enable(nor); ret = write_sr(nor, status_new); - if (ret) - goto err; } -err: - spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK); return ret; } -static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +static int stm_unlock(struct spi_nor *nor, loff_t ofs, uint64_t len) { - struct spi_nor *nor = mtd_to_spi_nor(mtd); + struct mtd_info *mtd = nor->mtd; uint32_t offset = ofs; uint8_t status_old, status_new; int ret = 0; - ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_UNLOCK); - if (ret) - return ret; - status_old = read_sr(nor); if (offset+len > mtd->size - (mtd->size / 64)) @@ -444,15 +432,41 @@ static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) (status_old & (SR_BP2 | SR_BP1 | SR_BP0))) { write_enable(nor); ret = write_sr(nor, status_new); - if (ret) - goto err; } -err: + return ret; +} + +static int spi_nor_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +{ + struct spi_nor *nor = mtd_to_spi_nor(mtd); + int ret; + + ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_LOCK); + if (ret) + return ret; + + ret = nor->flash_lock(nor, ofs, len); + spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_UNLOCK); return ret; } +static int spi_nor_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len) +{ + struct spi_nor *nor = mtd_to_spi_nor(mtd); + int ret; + + ret = spi_nor_lock_and_prep(nor, SPI_NOR_OPS_UNLOCK); + if (ret) + return ret; + + ret = nor->flash_unlock(nor, ofs, len); + + spi_nor_unlock_and_unprep(nor, SPI_NOR_OPS_LOCK); + return ret; +} + /* Used when the "_ext_id" is two bytes at most */ #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags) \ ((kernel_ulong_t)&(struct flash_info) { \ @@ -1045,6 +1059,11 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode) /* nor protection support for STmicro chips */ if (JEDEC_MFR(info) == CFI_MFR_ST) { + nor->flash_lock = stm_lock; + nor->flash_unlock = stm_unlock; + } + + if (nor->flash_lock && nor->flash_unlock) { mtd->_lock = spi_nor_lock; mtd->_unlock = spi_nor_unlock; } diff --git a/include/linux/mtd/spi-nor.h b/include/linux/mtd/spi-nor.h index 4720b86ee73d..e5409524bb0a 100644 --- a/include/linux/mtd/spi-nor.h +++ b/include/linux/mtd/spi-nor.h @@ -155,6 +155,8 @@ enum spi_nor_option_flags { * @write: [DRIVER-SPECIFIC] write data to the SPI NOR * @erase: [DRIVER-SPECIFIC] erase a sector of the SPI NOR * at the offset @offs + * @lock: [FLASH-SPECIFIC] lock a region of the SPI NOR + * @unlock: [FLASH-SPECIFIC] unlock a region of the SPI NOR * @priv: the private data */ struct spi_nor { @@ -189,6 +191,9 @@ struct spi_nor { size_t len, size_t *retlen, const u_char *write_buf); int (*erase)(struct spi_nor *nor, loff_t offs); + int (*flash_lock)(struct spi_nor *nor, loff_t ofs, uint64_t len); + int (*flash_unlock)(struct spi_nor *nor, loff_t ofs, uint64_t len); + void *priv; }; -- cgit v1.2.3 From 60c70d66cdd39eb560bba5a95c429bf2ad5294d0 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Mon, 23 Feb 2015 17:26:39 +0200 Subject: mtd: nand: Prevent possible kernel lockup in nand_command() If a NAND device is not really present or pin muxes are not correctly configured we can lock up the kernel waiting infinitely for NAND_STATUS to be ready. This can be easily reproduced on TI's DRA7-evm board by booting it without NAND support in u-boot and disabling NAND pin muxes in the kernel. Add timeout when waiting for NAND_CMD_RESET completion. As per ONFi v4.0 tRST can be upto 250ms for EZ-NAND and 5ms for raw NAND. Signed-off-by: Roger Quadros Tested-by: Nishanth Menon Signed-off-by: Brian Norris --- drivers/mtd/nand/nand_base.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index ff5652211607..c2e1232cd45c 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -565,6 +565,25 @@ void nand_wait_ready(struct mtd_info *mtd) } EXPORT_SYMBOL_GPL(nand_wait_ready); +/** + * nand_wait_status_ready - [GENERIC] Wait for the ready status after commands. + * @mtd: MTD device structure + * @timeo: Timeout in ms + * + * Wait for status ready (i.e. command done) or timeout. + */ +static void nand_wait_status_ready(struct mtd_info *mtd, unsigned long timeo) +{ + register struct nand_chip *chip = mtd->priv; + + timeo = jiffies + msecs_to_jiffies(timeo); + do { + if ((chip->read_byte(mtd) & NAND_STATUS_READY)) + break; + touch_softlockup_watchdog(); + } while (time_before(jiffies, timeo)); +}; + /** * nand_command - [DEFAULT] Send command to NAND device * @mtd: MTD device structure @@ -643,8 +662,8 @@ static void nand_command(struct mtd_info *mtd, unsigned int command, NAND_CTRL_CLE | NAND_CTRL_CHANGE); chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) - ; + /* EZ-NAND can take upto 250ms as per ONFi v4.0 */ + nand_wait_status_ready(mtd, 250); return; /* This applies to read commands */ @@ -740,8 +759,8 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command, NAND_NCE | NAND_CLE | NAND_CTRL_CHANGE); chip->cmd_ctrl(mtd, NAND_CMD_NONE, NAND_NCE | NAND_CTRL_CHANGE); - while (!(chip->read_byte(mtd) & NAND_STATUS_READY)) - ; + /* EZ-NAND can take upto 250ms as per ONFi v4.0 */ + nand_wait_status_ready(mtd, 250); return; case NAND_CMD_RNDOUT: -- cgit v1.2.3 From 62b57f4c1475a4c452000192e5cad2ae86164be5 Mon Sep 17 00:00:00 2001 From: Stefan Roese Date: Thu, 19 Mar 2015 14:34:29 +0100 Subject: mtd: fsmc_nand.c: Use default timings if none are provided in the dts Without this patch the timings are all set to 0 if not specified in the dts. With this patch the driver falls back to use the defaults that are already present in the driver and are known to work okay for some (older) boards. Tested on a custom SPEAr600 based board. Signed-off-by: Stefan Roese Acked-by: Linus Walleij Cc: Viresh Kumar Cc: Mian Yousaf Kaukab Signed-off-by: Brian Norris --- drivers/mtd/nand/fsmc_nand.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/fsmc_nand.c b/drivers/mtd/nand/fsmc_nand.c index edfaa21b1817..e58af4bfa8c8 100644 --- a/drivers/mtd/nand/fsmc_nand.c +++ b/drivers/mtd/nand/fsmc_nand.c @@ -873,6 +873,7 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev, { struct fsmc_nand_platform_data *pdata = dev_get_platdata(&pdev->dev); u32 val; + int ret; /* Set default NAND width to 8 bits */ pdata->width = 8; @@ -891,8 +892,12 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev, sizeof(*pdata->nand_timings), GFP_KERNEL); if (!pdata->nand_timings) return -ENOMEM; - of_property_read_u8_array(np, "timings", (u8 *)pdata->nand_timings, + ret = of_property_read_u8_array(np, "timings", (u8 *)pdata->nand_timings, sizeof(*pdata->nand_timings)); + if (ret) { + dev_info(&pdev->dev, "No timings in dts specified, using default timings!\n"); + pdata->nand_timings = NULL; + } /* Set default NAND bank to 0 */ pdata->bank = 0; -- cgit v1.2.3 From 318157ab1fc843b7e08b7bf1fc2c431c4da9f3ff Mon Sep 17 00:00:00 2001 From: Christophe Leroy Date: Thu, 12 Mar 2015 16:24:04 +0100 Subject: mtd: replace CONFIG_8xx by CONFIG_PPC_8xx Two config options exist to define powerpc MPC8xx: * CONFIG_PPC_8xx * CONFIG_8xx In addition, CONFIG_PPC_8xx also defines CONFIG_CPM1 as communication co-processor arch/powerpc/platforms/Kconfig.cputype has contained the following comment about CONFIG_8xx item for some years: "# this is temp to handle compat with arch=ppc" It looks like not many places still have that old CONFIG_8xx used, so it is likely to be a good time to get rid of it completely ? Signed-off-by: Christophe Leroy Signed-off-by: Brian Norris --- drivers/mtd/maps/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig index ba801d2c6dcc..e715ae90632f 100644 --- a/drivers/mtd/maps/Kconfig +++ b/drivers/mtd/maps/Kconfig @@ -242,7 +242,7 @@ config MTD_L440GX config MTD_CFI_FLAGADM tristate "CFI Flash device mapping on FlagaDM" - depends on 8xx && MTD_CFI + depends on PPC_8xx && MTD_CFI help Mapping for the Flaga digital module. If you don't have one, ignore this setting. -- cgit v1.2.3 From 271afb4c96b70292c5eae0744e08bc2d2b5f4fae Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 9 Mar 2015 11:10:41 -0700 Subject: mtd: maps: sa1100-flash: remove incorrect __exit markups Even if bus is not hot-pluggable, the devices can be unbound from the driver via sysfs, so we should not be using __exit annotations on remove() methods. The only exception is drivers registered with platform_driver_probe() which specifically disables sysfs bind/unbind attributes. Signed-off-by: Dmitry Torokhov Signed-off-by: Brian Norris --- drivers/mtd/maps/sa1100-flash.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c index ea697202935a..892ad6ac63f2 100644 --- a/drivers/mtd/maps/sa1100-flash.c +++ b/drivers/mtd/maps/sa1100-flash.c @@ -274,7 +274,7 @@ static int sa1100_mtd_probe(struct platform_device *pdev) return err; } -static int __exit sa1100_mtd_remove(struct platform_device *pdev) +static int sa1100_mtd_remove(struct platform_device *pdev) { struct sa_info *info = platform_get_drvdata(pdev); struct flash_platform_data *plat = dev_get_platdata(&pdev->dev); @@ -286,7 +286,7 @@ static int __exit sa1100_mtd_remove(struct platform_device *pdev) static struct platform_driver sa1100_mtd_driver = { .probe = sa1100_mtd_probe, - .remove = __exit_p(sa1100_mtd_remove), + .remove = sa1100_mtd_remove, .driver = { .name = "sa1100-mtd", }, -- cgit v1.2.3 From 35cc3337b6d5bb71ec80daaaf268bf25514fb6a2 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 25 Feb 2015 16:15:58 +0300 Subject: mtd: cfi: clean up some indenting These lines were all indented one tab more than they should be. Signed-off-by: Dan Carpenter Signed-off-by: Brian Norris --- drivers/mtd/chips/cfi_cmdset_0020.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c index 423666b51efb..9a1a6ffd16b8 100644 --- a/drivers/mtd/chips/cfi_cmdset_0020.c +++ b/drivers/mtd/chips/cfi_cmdset_0020.c @@ -206,23 +206,23 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map) mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum; } offset += (ersize * ernum); - } + } - if (offset != devsize) { - /* Argh */ - printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize); - kfree(mtd->eraseregions); - kfree(cfi->cmdset_priv); - kfree(mtd); - return NULL; - } + if (offset != devsize) { + /* Argh */ + printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize); + kfree(mtd->eraseregions); + kfree(cfi->cmdset_priv); + kfree(mtd); + return NULL; + } - for (i=0; inumeraseregions;i++){ - printk(KERN_DEBUG "%d: offset=0x%llx,size=0x%x,blocks=%d\n", - i, (unsigned long long)mtd->eraseregions[i].offset, - mtd->eraseregions[i].erasesize, - mtd->eraseregions[i].numblocks); - } + for (i=0; inumeraseregions;i++){ + printk(KERN_DEBUG "%d: offset=0x%llx,size=0x%x,blocks=%d\n", + i, (unsigned long long)mtd->eraseregions[i].offset, + mtd->eraseregions[i].erasesize, + mtd->eraseregions[i].numblocks); + } /* Also select the correct geometry setup too */ mtd->_erase = cfi_staa_erase_varsize; -- cgit v1.2.3 From dc6525c61f0fc1e41611d91134f56ed2c297feac Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 9 Feb 2015 10:07:19 -0200 Subject: mtd: fsl-quadspi: Print the error value When displaying dev_err() messages it is useful to print the error value. Signed-off-by: Fabio Estevam Acked-by: Han Xu [Brian: fix up "can not" at the same time] Signed-off-by: Brian Norris --- drivers/mtd/spi-nor/fsl-quadspi.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index 1c7308c2c77d..c01dd1611888 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -830,27 +830,27 @@ static int fsl_qspi_probe(struct platform_device *pdev) ret = clk_prepare_enable(q->clk_en); if (ret) { - dev_err(dev, "can not enable the qspi_en clock\n"); + dev_err(dev, "cannot enable the qspi_en clock: %d\n", ret); return ret; } ret = clk_prepare_enable(q->clk); if (ret) { - dev_err(dev, "can not enable the qspi clock\n"); + dev_err(dev, "cannot enable the qspi clock: %d\n", ret); goto clk_failed; } /* find the irq */ ret = platform_get_irq(pdev, 0); if (ret < 0) { - dev_err(dev, "failed to get the irq\n"); + dev_err(dev, "failed to get the irq: %d\n", ret); goto irq_failed; } ret = devm_request_irq(dev, ret, fsl_qspi_irq_handler, 0, pdev->name, q); if (ret) { - dev_err(dev, "failed to request irq.\n"); + dev_err(dev, "failed to request irq: %d\n", ret); goto irq_failed; } -- cgit v1.2.3 From 219a8d13dd2bd0536e359405d046bdce9cc9d134 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Sun, 1 Feb 2015 06:15:46 -0500 Subject: mtd: fsl-quadspi: cleanup wait_for_completion return handling return type of wait_for_completion_timeout is unsigned long not int, this patch uses the return value of wait_for_completion_timeout in the condition directly rather than adding a additional appropriately typed variable. Signed-off-by: Nicholas Mc Guire Acked-by: Han Xu Signed-off-by: Brian Norris --- drivers/mtd/spi-nor/fsl-quadspi.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c index c01dd1611888..5d5d36272bb5 100644 --- a/drivers/mtd/spi-nor/fsl-quadspi.c +++ b/drivers/mtd/spi-nor/fsl-quadspi.c @@ -460,8 +460,7 @@ fsl_qspi_runcmd(struct fsl_qspi *q, u8 cmd, unsigned int addr, int len) writel((seqid << QUADSPI_IPCR_SEQID_SHIFT) | len, base + QUADSPI_IPCR); /* Wait for the interrupt. */ - err = wait_for_completion_timeout(&q->c, msecs_to_jiffies(1000)); - if (!err) { + if (!wait_for_completion_timeout(&q->c, msecs_to_jiffies(1000))) { dev_err(q->dev, "cmd 0x%.2x timeout, addr@%.8x, FR:0x%.8x, SR:0x%.8x\n", cmd, addr, readl(base + QUADSPI_FR), -- cgit v1.2.3 From 706d5b289924678de9d8af67bcb00e28c1a5000c Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Sun, 8 Feb 2015 11:37:33 -0500 Subject: mtd: nand: gpmi: fixup return type of wait_for_completion_timeout return type of wait_for_completion_timeout is unsigned long not int. The return variable is renamed to reflect its use and the type adjusted to unsigned long. Signed-off-by: Nicholas Mc Guire Reviewed-by: Boris Brezillon Acked-by: Huang Shijie Signed-off-by: Brian Norris --- drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index 33f3c3c54dbc..6e44d3268fcb 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -446,7 +446,7 @@ int start_dma_without_bch_irq(struct gpmi_nand_data *this, struct dma_async_tx_descriptor *desc) { struct completion *dma_c = &this->dma_done; - int err; + unsigned long timeout; init_completion(dma_c); @@ -456,8 +456,8 @@ int start_dma_without_bch_irq(struct gpmi_nand_data *this, dma_async_issue_pending(get_dma_chan(this)); /* Wait for the interrupt from the DMA block. */ - err = wait_for_completion_timeout(dma_c, msecs_to_jiffies(1000)); - if (!err) { + timeout = wait_for_completion_timeout(dma_c, msecs_to_jiffies(1000)); + if (!timeout) { dev_err(this->dev, "DMA timeout, last DMA :%d\n", this->last_dma_type); gpmi_dump_info(this); @@ -477,7 +477,7 @@ int start_dma_with_bch_irq(struct gpmi_nand_data *this, struct dma_async_tx_descriptor *desc) { struct completion *bch_c = &this->bch_done; - int err; + unsigned long timeout; /* Prepare to receive an interrupt from the BCH block. */ init_completion(bch_c); @@ -486,8 +486,8 @@ int start_dma_with_bch_irq(struct gpmi_nand_data *this, start_dma_without_bch_irq(this, desc); /* Wait for the interrupt from the BCH block. */ - err = wait_for_completion_timeout(bch_c, msecs_to_jiffies(1000)); - if (!err) { + timeout = wait_for_completion_timeout(bch_c, msecs_to_jiffies(1000)); + if (!timeout) { dev_err(this->dev, "BCH timeout, last DMA :%d\n", this->last_dma_type); gpmi_dump_info(this); -- cgit v1.2.3 From 899b834a462921a087f92f705d9f85def5892242 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 9 Feb 2015 19:22:33 -0200 Subject: mtd: nand: gpmi: Check for scan_bbt() error In case of scan_bbt() failure, we should better propagate it. Signed-off-by: Fabio Estevam Acked-by: Huang Shijie Signed-off-by: Brian Norris --- drivers/mtd/nand/gpmi-nand/gpmi-nand.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c index 6e44d3268fcb..1b8f3500e6d2 100644 --- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c +++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c @@ -1950,7 +1950,9 @@ static int gpmi_nand_init(struct gpmi_nand_data *this) ret = nand_boot_init(this); if (ret) goto err_out; - chip->scan_bbt(mtd); + ret = chip->scan_bbt(mtd); + if (ret) + goto err_out; ppdata.of_node = this->pdev->dev.of_node; ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0); -- cgit v1.2.3 From e5860c18e68606446a10c3e926a2a0162c385cbf Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Sun, 1 Feb 2015 11:55:37 -0500 Subject: mtd: pxa3xx_nand: cleanup wait_for_completion handling return type of wait_for_completion_timeout is unsigned long not int, this patch uses the return value of wait_for_completion_timeout in the condition directly rather than assigning it to an incorrect type variable. The variable used for handling the return of wait_for_cmpletion_timeout was int but should be unsigned long, where it was not in use for anything else and the return value in case of completion (>0) is not used it was removed and wait_for_completion_timeout() used directly in the if condition. To make the timeout values a bit simpler to read and also handle all of the corner cases correctly the declarations are moved to msecs_to_jiffies(). The timeout declaration cleanup is just for readability Signed-off-by: Nicholas Mc Guire Signed-off-by: Brian Norris --- drivers/mtd/nand/pxa3xx_nand.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/pxa3xx_nand.c b/drivers/mtd/nand/pxa3xx_nand.c index b1ecb570d154..a4615fcc3d00 100644 --- a/drivers/mtd/nand/pxa3xx_nand.c +++ b/drivers/mtd/nand/pxa3xx_nand.c @@ -38,8 +38,8 @@ #include -#define CHIP_DELAY_TIMEOUT (2 * HZ/10) -#define NAND_STOP_DELAY (2 * HZ/50) +#define CHIP_DELAY_TIMEOUT msecs_to_jiffies(200) +#define NAND_STOP_DELAY msecs_to_jiffies(40) #define PAGE_CHUNK_SIZE (2048) /* @@ -965,7 +965,7 @@ static void nand_cmdfunc(struct mtd_info *mtd, unsigned command, { struct pxa3xx_nand_host *host = mtd->priv; struct pxa3xx_nand_info *info = host->info_data; - int ret, exec_cmd; + int exec_cmd; /* * if this is a x16 device ,then convert the input @@ -997,9 +997,8 @@ static void nand_cmdfunc(struct mtd_info *mtd, unsigned command, info->need_wait = 1; pxa3xx_nand_start(info); - ret = wait_for_completion_timeout(&info->cmd_complete, - CHIP_DELAY_TIMEOUT); - if (!ret) { + if (!wait_for_completion_timeout(&info->cmd_complete, + CHIP_DELAY_TIMEOUT)) { dev_err(&info->pdev->dev, "Wait time out!!!\n"); /* Stop State Machine for next command cycle */ pxa3xx_nand_stop(info); @@ -1014,7 +1013,7 @@ static void nand_cmdfunc_extended(struct mtd_info *mtd, { struct pxa3xx_nand_host *host = mtd->priv; struct pxa3xx_nand_info *info = host->info_data; - int ret, exec_cmd, ext_cmd_type; + int exec_cmd, ext_cmd_type; /* * if this is a x16 device then convert the input @@ -1077,9 +1076,8 @@ static void nand_cmdfunc_extended(struct mtd_info *mtd, init_completion(&info->cmd_complete); pxa3xx_nand_start(info); - ret = wait_for_completion_timeout(&info->cmd_complete, - CHIP_DELAY_TIMEOUT); - if (!ret) { + if (!wait_for_completion_timeout(&info->cmd_complete, + CHIP_DELAY_TIMEOUT)) { dev_err(&info->pdev->dev, "Wait time out!!!\n"); /* Stop State Machine for next command cycle */ pxa3xx_nand_stop(info); @@ -1212,13 +1210,11 @@ static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this) { struct pxa3xx_nand_host *host = mtd->priv; struct pxa3xx_nand_info *info = host->info_data; - int ret; if (info->need_wait) { - ret = wait_for_completion_timeout(&info->dev_ready, - CHIP_DELAY_TIMEOUT); info->need_wait = 0; - if (!ret) { + if (!wait_for_completion_timeout(&info->dev_ready, + CHIP_DELAY_TIMEOUT)) { dev_err(&info->pdev->dev, "Ready time out!!!\n"); return NAND_STATUS_FAIL; } -- cgit v1.2.3 From d99d72829ec00a96d2d71f30a704b901c198a673 Mon Sep 17 00:00:00 2001 From: Graham Moore Date: Wed, 14 Jan 2015 09:38:50 -0600 Subject: mtd: denali: Disable sub-page writes in Denali NAND driver The Denali Controller IP does not support sub-page writes. Signed-off-by: Graham Moore Signed-off-by: Dinh Nguyen Signed-off-by: Brian Norris --- drivers/mtd/nand/denali.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers') diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c index 09f51395f2c0..870c7fc0f759 100644 --- a/drivers/mtd/nand/denali.c +++ b/drivers/mtd/nand/denali.c @@ -1533,6 +1533,9 @@ int denali_init(struct denali_nand_info *denali) denali->nand.options |= NAND_SKIP_BBTSCAN; denali->nand.ecc.mode = NAND_ECC_HW_SYNDROME; + /* no subpage writes on denali */ + denali->nand.options |= NAND_NO_SUBPAGE_WRITE; + /* * Denali Controller only support 15bit and 8bit ECC in MRST, * so just let controller do 15bit ECC for MLC and 8bit ECC for -- cgit v1.2.3 From 9cd5196ed25979a3760f97225aae3e17caf21512 Mon Sep 17 00:00:00 2001 From: Masanari Iida Date: Mon, 30 Mar 2015 19:06:22 +0900 Subject: mtd: ts5500_flash: Fix typo in MODULE_DESCRIPTION in ts5500_flash.c This patch fixes a spelling typo in MODULE_DESCRIPTION in ts5500_flash.c. Signed-off-by: Masanari Iida [ Brian: fixed grammar in a spelling patch :) ] Signed-off-by: Brian Norris --- drivers/mtd/maps/ts5500_flash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/mtd/maps/ts5500_flash.c b/drivers/mtd/maps/ts5500_flash.c index d1d671daf235..9969fedb1f13 100644 --- a/drivers/mtd/maps/ts5500_flash.c +++ b/drivers/mtd/maps/ts5500_flash.c @@ -117,5 +117,5 @@ module_exit(cleanup_ts5500_map); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Sean Young "); -MODULE_DESCRIPTION("MTD map driver for Techology Systems TS-5500 board"); +MODULE_DESCRIPTION("MTD map driver for Technology Systems TS-5500 board"); -- cgit v1.2.3 From 727dc612c46b8f3858537ea23805b3e897cf127e Mon Sep 17 00:00:00 2001 From: Dan Ehrenberg Date: Thu, 2 Apr 2015 15:15:10 -0700 Subject: mtd: part: Create the master device node when partitioned For many use cases, it helps to have a device node for the entire MTD device as well as device nodes for the individual partitions. For example, this allows querying the entire device's properties. A common idiom is to create an additional partition which spans over the whole device. This patch makes a config option, CONFIG_MTD_PARTITIONED_MASTER, which makes the master partition present even when the device is partitioned. This isn't turned on by default since it presents a backwards-incompatible device numbering. The patch also makes the parent of a partition device be the master, if the config flag is set, now that the master is a full device. Signed-off-by: Dan Ehrenberg Signed-off-by: Brian Norris --- drivers/mtd/Kconfig | 13 +++++++++++++ drivers/mtd/mtdcore.c | 52 +++++++++++++++++++++++++++++++++++---------------- drivers/mtd/mtdpart.c | 18 +++++++++++++----- 3 files changed, 62 insertions(+), 21 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig index 71fea895ce38..a03ad2951c7b 100644 --- a/drivers/mtd/Kconfig +++ b/drivers/mtd/Kconfig @@ -309,6 +309,19 @@ config MTD_SWAP The driver provides wear leveling by storing erase counter into the OOB. +config MTD_PARTITIONED_MASTER + bool "Retain master device when partitioned" + default n + depends on MTD + help + For historical reasons, by default, either a master is present or + several partitions are present, but not both. The concern was that + data listed in multiple partitions was dangerous; however, SCSI does + this and it is frequently useful for applications. This config option + leaves the master in even if the device is partitioned. It also makes + the parent of the partition device be the master device, rather than + what lies behind the master. + source "drivers/mtd/chips/Kconfig" source "drivers/mtd/maps/Kconfig" diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c index 11883bd26d9d..d172195fbd15 100644 --- a/drivers/mtd/mtdcore.c +++ b/drivers/mtd/mtdcore.c @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -501,6 +502,29 @@ out_error: return ret; } +static int mtd_add_device_partitions(struct mtd_info *mtd, + struct mtd_partition *real_parts, + int nbparts) +{ + int ret; + + if (nbparts == 0 || IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) { + ret = add_mtd_device(mtd); + if (ret == 1) + return -ENODEV; + } + + if (nbparts > 0) { + ret = add_mtd_partitions(mtd, real_parts, nbparts); + if (ret && IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER)) + del_mtd_device(mtd); + return ret; + } + + return 0; +} + + /** * mtd_device_parse_register - parse partitions and register an MTD device. * @@ -523,7 +547,8 @@ out_error: * found this functions tries to fallback to information specified in * @parts/@nr_parts. * * If any partitioning info was found, this function registers the found - * partitions. + * partitions. If the MTD_PARTITIONED_MASTER option is set, then the device + * as a whole is registered first. * * If no partitions were found this function just registers the MTD device * @mtd and exits. * @@ -534,27 +559,21 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types, const struct mtd_partition *parts, int nr_parts) { - int err; - struct mtd_partition *real_parts; + int ret; + struct mtd_partition *real_parts = NULL; - err = parse_mtd_partitions(mtd, types, &real_parts, parser_data); - if (err <= 0 && nr_parts && parts) { + ret = parse_mtd_partitions(mtd, types, &real_parts, parser_data); + if (ret <= 0 && nr_parts && parts) { real_parts = kmemdup(parts, sizeof(*parts) * nr_parts, GFP_KERNEL); if (!real_parts) - err = -ENOMEM; + ret = -ENOMEM; else - err = nr_parts; + ret = nr_parts; } - if (err > 0) { - err = add_mtd_partitions(mtd, real_parts, err); - kfree(real_parts); - } else if (err == 0) { - err = add_mtd_device(mtd); - if (err == 1) - err = -ENODEV; - } + if (ret >= 0) + ret = mtd_add_device_partitions(mtd, real_parts, ret); /* * FIXME: some drivers unfortunately call this function more than once. @@ -569,7 +588,8 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types, register_reboot_notifier(&mtd->reboot_notifier); } - return err; + kfree(real_parts); + return ret; } EXPORT_SYMBOL_GPL(mtd_device_parse_register); diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index e779de315ade..a19ec5a4e409 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "mtdcore.h" @@ -379,10 +380,17 @@ static struct mtd_part *allocate_partition(struct mtd_info *master, slave->mtd.name = name; slave->mtd.owner = master->owner; - /* NOTE: we don't arrange MTDs as a tree; it'd be error-prone - * to have the same data be in two different partitions. + /* NOTE: Historically, we didn't arrange MTDs as a tree out of + * concern for showing the same data in multiple partitions. + * However, it is very useful to have the master node present, + * so the MTD_PARTITIONED_MASTER option allows that. The master + * will have device nodes etc only if this is set, so make the + * parent conditional on that option. Note, this is a way to + * distinguish between the master and the partition in sysfs. */ - slave->mtd.dev.parent = master->dev.parent; + slave->mtd.dev.parent = IS_ENABLED(CONFIG_MTD_PARTITIONED_MASTER) ? + &master->dev : + master->dev.parent; slave->mtd._read = part_read; slave->mtd._write = part_write; @@ -631,8 +639,8 @@ EXPORT_SYMBOL_GPL(mtd_del_partition); * and registers slave MTD objects which are bound to the master according to * the partition definitions. * - * We don't register the master, or expect the caller to have done so, - * for reasons of data integrity. + * For historical reasons, this function's caller only registers the master + * if the MTD_PARTITIONED_MASTER config option is set. */ int add_mtd_partitions(struct mtd_info *master, -- cgit v1.2.3 From a62c24d75529118d10c45350c3b75715d52ff574 Mon Sep 17 00:00:00 2001 From: Dan Ehrenberg Date: Thu, 2 Apr 2015 15:15:11 -0700 Subject: mtd: part: Add sysfs variable for offset of partition This patch makes a sysfs variable called 'offset' on each partition which contains the offset in bytes from the beginning of the master device that the partition starts. Signed-off-by: Dan Ehrenberg Signed-off-by: Brian Norris --- Documentation/ABI/testing/sysfs-class-mtd | 10 ++++++++++ drivers/mtd/mtdpart.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) (limited to 'drivers') diff --git a/Documentation/ABI/testing/sysfs-class-mtd b/Documentation/ABI/testing/sysfs-class-mtd index 76ee192f80a0..3b5c3bca9186 100644 --- a/Documentation/ABI/testing/sysfs-class-mtd +++ b/Documentation/ABI/testing/sysfs-class-mtd @@ -222,3 +222,13 @@ Description: The number of blocks that are marked as reserved, if any, in this partition. These are typically used to store the in-flash bad block table (BBT). + +What: /sys/class/mtd/mtdX/offset +Date: March 2015 +KernelVersion: 4.1 +Contact: linux-mtd@lists.infradead.org +Description: + For a partition, the offset of that partition from the start + of the master device in bytes. This attribute is absent on + main devices, so it can be used to distinguish between + partitions and devices that aren't partitions. diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index a19ec5a4e409..be8034086701 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -554,6 +554,30 @@ out_register: return slave; } +static ssize_t mtd_partition_offset_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mtd_info *mtd = dev_get_drvdata(dev); + struct mtd_part *part = PART(mtd); + return snprintf(buf, PAGE_SIZE, "%lld\n", part->offset); +} + +static DEVICE_ATTR(offset, S_IRUGO, mtd_partition_offset_show, NULL); + +static const struct attribute *mtd_partition_attrs[] = { + &dev_attr_offset.attr, + NULL +}; + +static int mtd_add_partition_attrs(struct mtd_part *new) +{ + int ret = sysfs_create_files(&new->mtd.dev.kobj, mtd_partition_attrs); + if (ret) + printk(KERN_WARNING + "mtd: failed to create partition attrs, err=%d\n", ret); + return ret; +} + int mtd_add_partition(struct mtd_info *master, const char *name, long long offset, long long length) { @@ -603,6 +627,8 @@ int mtd_add_partition(struct mtd_info *master, const char *name, add_mtd_device(&new->mtd); + mtd_add_partition_attrs(new); + return ret; err_inv: mutex_unlock(&mtd_partitions_mutex); @@ -620,6 +646,8 @@ int mtd_del_partition(struct mtd_info *master, int partno) list_for_each_entry_safe(slave, next, &mtd_partitions, list) if ((slave->master == master) && (slave->mtd.index == partno)) { + sysfs_remove_files(&slave->mtd.dev.kobj, + mtd_partition_attrs); ret = del_mtd_device(&slave->mtd); if (ret < 0) break; @@ -663,6 +691,7 @@ int add_mtd_partitions(struct mtd_info *master, mutex_unlock(&mtd_partitions_mutex); add_mtd_device(&slave->mtd); + mtd_add_partition_attrs(slave); cur_offset = slave->offset + slave->mtd.size; } -- cgit v1.2.3 From 3a434f66e6dab645d74a59c95651cdbe16497a50 Mon Sep 17 00:00:00 2001 From: Dan Ehrenberg Date: Thu, 2 Apr 2015 15:15:12 -0700 Subject: mtd: part: Remove partition overlap checks This patch makes MTD dynamic partitioning more flexible by removing overlap checks for dynamic partitions. I don't see any particular reason why overlapping dynamic partitions should be prohibited while static partitions are allowed to overlap freely. The checks previously had an off-by-one error, where 'end' should be one less than what it is currently set at, and adding partitions out of increasing order will fail. Disabling the checks resolves this issue. Signed-off-by: Dan Ehrenberg Signed-off-by: Brian Norris --- drivers/mtd/mtdpart.c | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c index be8034086701..cafdb8855a79 100644 --- a/drivers/mtd/mtdpart.c +++ b/drivers/mtd/mtdpart.c @@ -582,8 +582,7 @@ int mtd_add_partition(struct mtd_info *master, const char *name, long long offset, long long length) { struct mtd_partition part; - struct mtd_part *p, *new; - uint64_t start, end; + struct mtd_part *new; int ret = 0; /* the direct offset is expected */ @@ -607,21 +606,7 @@ int mtd_add_partition(struct mtd_info *master, const char *name, if (IS_ERR(new)) return PTR_ERR(new); - start = offset; - end = offset + length; - mutex_lock(&mtd_partitions_mutex); - list_for_each_entry(p, &mtd_partitions, list) - if (p->master == master) { - if ((start >= p->offset) && - (start < (p->offset + p->mtd.size))) - goto err_inv; - - if ((end >= p->offset) && - (end < (p->offset + p->mtd.size))) - goto err_inv; - } - list_add(&new->list, &mtd_partitions); mutex_unlock(&mtd_partitions_mutex); @@ -630,10 +615,6 @@ int mtd_add_partition(struct mtd_info *master, const char *name, mtd_add_partition_attrs(new); return ret; -err_inv: - mutex_unlock(&mtd_partitions_mutex); - free_partition(new); - return -EINVAL; } EXPORT_SYMBOL_GPL(mtd_add_partition); -- cgit v1.2.3 From 477478aedc8bdf1925785835609bc7e790f69aef Mon Sep 17 00:00:00 2001 From: Josh Wu Date: Thu, 2 Apr 2015 14:12:33 +0800 Subject: mtd: atmel_nand: add a definition for the oob reserved bytes It's better to use a macro instead of just a number. Signed-off-by: Josh Wu Signed-off-by: Brian Norris --- drivers/mtd/nand/atmel_nand.c | 5 +++-- drivers/mtd/nand/atmel_nand_ecc.h | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index feaac9099bb9..0361c1992673 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -485,7 +485,7 @@ static void pmecc_config_ecc_layout(struct nand_ecclayout *layout, for (i = 0; i < ecc_len; i++) layout->eccpos[i] = oobsize - ecc_len + i; - layout->oobfree[0].offset = 2; + layout->oobfree[0].offset = PMECC_OOB_RESERVED_BYTES; layout->oobfree[0].length = oobsize - ecc_len - layout->oobfree[0].offset; } @@ -1254,7 +1254,8 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, nand_chip->ecc.steps = mtd->writesize / sector_size; nand_chip->ecc.total = nand_chip->ecc.bytes * nand_chip->ecc.steps; - if (nand_chip->ecc.total > mtd->oobsize - 2) { + if (nand_chip->ecc.total > + mtd->oobsize - PMECC_OOB_RESERVED_BYTES) { dev_err(host->dev, "No room for ECC bytes\n"); err_no = -EINVAL; goto err; diff --git a/drivers/mtd/nand/atmel_nand_ecc.h b/drivers/mtd/nand/atmel_nand_ecc.h index d4035e335ad8..668e7358f19b 100644 --- a/drivers/mtd/nand/atmel_nand_ecc.h +++ b/drivers/mtd/nand/atmel_nand_ecc.h @@ -152,4 +152,7 @@ /* Time out value for reading PMECC status register */ #define PMECC_MAX_TIMEOUT_MS 100 +/* Reserved bytes in oob area */ +#define PMECC_OOB_RESERVED_BYTES 2 + #endif -- cgit v1.2.3 From 41c7540d0c4e362212845aa2258c15aaa878665f Mon Sep 17 00:00:00 2001 From: "Wu, Josh" Date: Thu, 2 Apr 2015 14:13:47 +0800 Subject: mtd: atmel_nand: don't map the ROM table if no pmecc table offset in DT if atmel,pmecc-lookup-table-offset is not found in DT node, we don't need to map the ROM table as we will build a runtime gf table anyway. Reported-by: Nicolas Ferre Signed-off-by: Josh Wu Acked-by: Nicolas Ferre Signed-off-by: Brian Norris --- drivers/mtd/nand/atmel_nand.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c index 0361c1992673..46010bd895b1 100644 --- a/drivers/mtd/nand/atmel_nand.c +++ b/drivers/mtd/nand/atmel_nand.c @@ -1204,14 +1204,14 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev, goto err; } - regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3); - host->pmecc_rom_base = devm_ioremap_resource(&pdev->dev, regs_rom); - if (IS_ERR(host->pmecc_rom_base)) { - if (!host->has_no_lookup_table) - /* Don't display the information again */ + if (!host->has_no_lookup_table) { + regs_rom = platform_get_resource(pdev, IORESOURCE_MEM, 3); + host->pmecc_rom_base = devm_ioremap_resource(&pdev->dev, + regs_rom); + if (IS_ERR(host->pmecc_rom_base)) { dev_err(host->dev, "Can not get I/O resource for ROM, will build a lookup table in runtime!\n"); - - host->has_no_lookup_table = true; + host->has_no_lookup_table = true; + } } if (host->has_no_lookup_table) { -- cgit v1.2.3 From 95d706657311f24407d0f7a0cf79b55904ec6524 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Fri, 13 Mar 2015 07:23:47 -0400 Subject: mtd: fsl_ifc_nand: use msecs_to_jiffies for time conversion This is only an API consolidation and should make things more readable it replaces var * HZ / 1000 by msecs_to_jiffies(var) which helps readability and also handles all corner-cases properly. Signed-off-by: Nicholas Mc Guire Signed-off-by: Brian Norris --- drivers/mtd/nand/fsl_ifc_nand.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/nand/fsl_ifc_nand.c b/drivers/mtd/nand/fsl_ifc_nand.c index 4c05f4f6a5c6..51394e59901b 100644 --- a/drivers/mtd/nand/fsl_ifc_nand.c +++ b/drivers/mtd/nand/fsl_ifc_nand.c @@ -317,7 +317,7 @@ static void fsl_ifc_run_command(struct mtd_info *mtd) /* wait for command complete flag or timeout */ wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat, - IFC_TIMEOUT_MSECS * HZ/1000); + msecs_to_jiffies(IFC_TIMEOUT_MSECS)); /* ctrl->nand_stat will be updated from IRQ context */ if (!ctrl->nand_stat) @@ -860,7 +860,7 @@ static void fsl_ifc_sram_init(struct fsl_ifc_mtd *priv) /* wait for command complete flag or timeout */ wait_event_timeout(ctrl->nand_wait, ctrl->nand_stat, - IFC_TIMEOUT_MSECS * HZ/1000); + msecs_to_jiffies(IFC_TIMEOUT_MSECS)); if (ctrl->nand_stat != IFC_NAND_EVTER_STAT_OPC) printk(KERN_ERR "fsl-ifc: Failed to Initialise SRAM\n"); -- cgit v1.2.3 From 45fd357a491ecc56c0f9bb110bd05d9caf28889f Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Tue, 31 Mar 2015 09:53:37 -0700 Subject: mtd: docg3: remove invalid __exit annotations The .remove callback may be used when detaching a device via sysfs, so we can't expect to free up this memory. Signed-off-by: Brian Norris Acked-by: Robert Jarzmik --- drivers/mtd/devices/docg3.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/devices/docg3.c b/drivers/mtd/devices/docg3.c index 0310f9174dcc..866d31904475 100644 --- a/drivers/mtd/devices/docg3.c +++ b/drivers/mtd/devices/docg3.c @@ -1805,7 +1805,7 @@ static int __init doc_dbg_register(struct docg3 *docg3) } } -static void __exit doc_dbg_unregister(struct docg3 *docg3) +static void doc_dbg_unregister(struct docg3 *docg3) { debugfs_remove_recursive(docg3->debugfs_root); } @@ -2100,7 +2100,7 @@ err_probe: * * Returns 0 */ -static int __exit docg3_release(struct platform_device *pdev) +static int docg3_release(struct platform_device *pdev) { struct docg3_cascade *cascade = platform_get_drvdata(pdev); struct docg3 *docg3 = cascade->floors[0]->priv; @@ -2131,7 +2131,7 @@ static struct platform_driver g3_driver = { }, .suspend = docg3_suspend, .resume = docg3_resume, - .remove = __exit_p(docg3_release), + .remove = docg3_release, }; module_platform_driver_probe(g3_driver, docg3_probe); -- cgit v1.2.3 From d2b51c808745ca93c020ba34a3cf256ad52adc63 Mon Sep 17 00:00:00 2001 From: Roger Quadros Date: Fri, 5 Dec 2014 17:18:39 +0200 Subject: mtd: mtd_oobtest: Fix bitflip_limit usage in test case 3 In test case 3, we set vary_offset to write at different offsets and lengths in the OOB available area. We need to do the bitflip_limit check while checking for 0xff outside the OOB offset + length area that we didn't modify during write. Signed-off-by: Roger Quadros [Brian: whitespace fixup] Signed-off-by: Brian Norris --- drivers/mtd/tests/oobtest.c | 62 +++++++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 27 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/tests/oobtest.c b/drivers/mtd/tests/oobtest.c index 64390ab88a80..c6b35644a10f 100644 --- a/drivers/mtd/tests/oobtest.c +++ b/drivers/mtd/tests/oobtest.c @@ -141,6 +141,31 @@ static size_t memcmpshow(loff_t addr, const void *cs, const void *ct, size_t cou return bitflips; } +/* + * Compare with 0xff and show the address, offset and data bytes at + * comparison failure. Return number of bitflips encountered. + */ +static size_t memffshow(loff_t addr, loff_t offset, const void *cs, + size_t count) +{ + const unsigned char *su1; + int res; + size_t i = 0; + size_t bitflips = 0; + + for (su1 = cs; 0 < count; ++su1, count--, i++) { + res = *su1 ^ 0xff; + if (res) { + pr_info("error @addr[0x%lx:0x%lx] 0x%x -> 0xff diff 0x%x\n", + (unsigned long)addr, (unsigned long)offset + i, + *su1, res); + bitflips += hweight8(res); + } + } + + return bitflips; +} + static int verify_eraseblock(int ebnum) { int i; @@ -203,6 +228,15 @@ static int verify_eraseblock(int ebnum) bitflips = memcmpshow(addr, readbuf + use_offset, writebuf + (use_len_max * i) + use_offset, use_len); + + /* verify pre-offset area for 0xff */ + bitflips += memffshow(addr, 0, readbuf, use_offset); + + /* verify post-(use_offset + use_len) area for 0xff */ + k = use_offset + use_len; + bitflips += memffshow(addr, k, readbuf + k, + mtd->ecclayout->oobavail - k); + if (bitflips > bitflip_limit) { pr_err("error: verify failed at %#llx\n", (long long)addr); @@ -212,34 +246,8 @@ static int verify_eraseblock(int ebnum) return -1; } } else if (bitflips) { - pr_info("ignoring error as within bitflip_limit\n"); + pr_info("ignoring errors as within bitflip limit\n"); } - - for (k = 0; k < use_offset; ++k) - if (readbuf[k] != 0xff) { - pr_err("error: verify 0xff " - "failed at %#llx\n", - (long long)addr); - errcnt += 1; - if (errcnt > 1000) { - pr_err("error: too " - "many errors\n"); - return -1; - } - } - for (k = use_offset + use_len; - k < mtd->ecclayout->oobavail; ++k) - if (readbuf[k] != 0xff) { - pr_err("error: verify 0xff " - "failed at %#llx\n", - (long long)addr); - errcnt += 1; - if (errcnt > 1000) { - pr_err("error: too " - "many errors\n"); - return -1; - } - } } if (vary_offset) do_vary_offset(); -- cgit v1.2.3 From 2a6a28e7922c07c116ba8f2aa3682c03ef8be678 Mon Sep 17 00:00:00 2001 From: Richard Weinberger Date: Sun, 29 Mar 2015 21:52:06 +0200 Subject: mtd: Make MTD tests cancelable I always go nuts when I start an MTD test on a slow device and have to wait forever until it finishes. From the debug output I already know what the issue is but I have to wait or reset the board hard. Resetting is often not an option (remote access, you don't want lose the current state, etc...). The solution is easy, check for pending signals at key positions in the code. Using that one can even stop a test by pressing CTRL-C as insmod/modprobe have SIGINT pending. Signed-off-by: Richard Weinberger Signed-off-by: Brian Norris --- drivers/mtd/tests/mtd_nandecctest.c | 6 ++++++ drivers/mtd/tests/mtd_test.h | 12 ++++++++++++ drivers/mtd/tests/nandbiterrs.c | 4 ++++ drivers/mtd/tests/oobtest.c | 26 +++++++++++++++++++++----- drivers/mtd/tests/pagetest.c | 10 ++++++++-- drivers/mtd/tests/readtest.c | 5 ++++- drivers/mtd/tests/speedtest.c | 36 +++++++++++++++++++++++++++++------- drivers/mtd/tests/stresstest.c | 5 ++++- drivers/mtd/tests/subpagetest.c | 25 ++++++++++++++++++++----- drivers/mtd/tests/torturetest.c | 15 ++++++++++++--- 10 files changed, 120 insertions(+), 24 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/tests/mtd_nandecctest.c b/drivers/mtd/tests/mtd_nandecctest.c index e579f9027c47..79316159eec6 100644 --- a/drivers/mtd/tests/mtd_nandecctest.c +++ b/drivers/mtd/tests/mtd_nandecctest.c @@ -9,6 +9,8 @@ #include #include +#include "mtd_test.h" + /* * Test the implementation for software ECC * @@ -274,6 +276,10 @@ static int nand_ecc_test_run(const size_t size) } pr_info("ok - %s-%zd\n", nand_ecc_test[i].name, size); + + err = mtdtest_relax(); + if (err) + break; } error: kfree(error_data); diff --git a/drivers/mtd/tests/mtd_test.h b/drivers/mtd/tests/mtd_test.h index f437c776c54f..4b7bee17c924 100644 --- a/drivers/mtd/tests/mtd_test.h +++ b/drivers/mtd/tests/mtd_test.h @@ -1,4 +1,16 @@ #include +#include + +static inline int mtdtest_relax(void) +{ + cond_resched(); + if (signal_pending(current)) { + pr_info("aborting test due to pending signal!\n"); + return -EINTR; + } + + return 0; +} int mtdtest_erase_eraseblock(struct mtd_info *mtd, unsigned int ebnum); int mtdtest_scan_for_bad_eraseblocks(struct mtd_info *mtd, unsigned char *bbt, diff --git a/drivers/mtd/tests/nandbiterrs.c b/drivers/mtd/tests/nandbiterrs.c index 273f7e553954..09a4ccac53a2 100644 --- a/drivers/mtd/tests/nandbiterrs.c +++ b/drivers/mtd/tests/nandbiterrs.c @@ -320,6 +320,10 @@ static int overwrite_test(void) break; } + err = mtdtest_relax(); + if (err) + break; + opno++; } diff --git a/drivers/mtd/tests/oobtest.c b/drivers/mtd/tests/oobtest.c index c6b35644a10f..8e8525f0202f 100644 --- a/drivers/mtd/tests/oobtest.c +++ b/drivers/mtd/tests/oobtest.c @@ -112,7 +112,10 @@ static int write_whole_device(void) return err; if (i % 256 == 0) pr_info("written up to eraseblock %u\n", i); - cond_resched(); + + err = mtdtest_relax(); + if (err) + return err; } pr_info("written %u eraseblocks\n", i); return 0; @@ -318,7 +321,10 @@ static int verify_all_eraseblocks(void) return err; if (i % 256 == 0) pr_info("verified up to eraseblock %u\n", i); - cond_resched(); + + err = mtdtest_relax(); + if (err) + return err; } pr_info("verified %u eraseblocks\n", i); return 0; @@ -429,7 +435,10 @@ static int __init mtd_oobtest_init(void) goto out; if (i % 256 == 0) pr_info("verified up to eraseblock %u\n", i); - cond_resched(); + + err = mtdtest_relax(); + if (err) + goto out; } pr_info("verified %u eraseblocks\n", i); @@ -642,7 +651,11 @@ static int __init mtd_oobtest_init(void) goto out; if (i % 256 == 0) pr_info("written up to eraseblock %u\n", i); - cond_resched(); + + err = mtdtest_relax(); + if (err) + goto out; + addr += mtd->writesize; } } @@ -680,7 +693,10 @@ static int __init mtd_oobtest_init(void) } if (i % 256 == 0) pr_info("verified up to eraseblock %u\n", i); - cond_resched(); + + err = mtdtest_relax(); + if (err) + goto out; } pr_info("verified %u eraseblocks\n", i); diff --git a/drivers/mtd/tests/pagetest.c b/drivers/mtd/tests/pagetest.c index 88296e888e9d..ba1890d5632c 100644 --- a/drivers/mtd/tests/pagetest.c +++ b/drivers/mtd/tests/pagetest.c @@ -407,7 +407,10 @@ static int __init mtd_pagetest_init(void) goto out; if (i % 256 == 0) pr_info("written up to eraseblock %u\n", i); - cond_resched(); + + err = mtdtest_relax(); + if (err) + goto out; } pr_info("written %u eraseblocks\n", i); @@ -422,7 +425,10 @@ static int __init mtd_pagetest_init(void) goto out; if (i % 256 == 0) pr_info("verified up to eraseblock %u\n", i); - cond_resched(); + + err = mtdtest_relax(); + if (err) + goto out; } pr_info("verified %u eraseblocks\n", i); diff --git a/drivers/mtd/tests/readtest.c b/drivers/mtd/tests/readtest.c index a54cf1511114..a3196b750a22 100644 --- a/drivers/mtd/tests/readtest.c +++ b/drivers/mtd/tests/readtest.c @@ -190,7 +190,10 @@ static int __init mtd_readtest_init(void) if (!err) err = ret; } - cond_resched(); + + err = mtdtest_relax(); + if (err) + goto out; } if (err) diff --git a/drivers/mtd/tests/speedtest.c b/drivers/mtd/tests/speedtest.c index a77019cb5510..5a6f31af06f9 100644 --- a/drivers/mtd/tests/speedtest.c +++ b/drivers/mtd/tests/speedtest.c @@ -269,7 +269,10 @@ static int __init mtd_speedtest_init(void) err = write_eraseblock(i); if (err) goto out; - cond_resched(); + + err = mtdtest_relax(); + if (err) + goto out; } stop_timing(); speed = calc_speed(); @@ -284,7 +287,10 @@ static int __init mtd_speedtest_init(void) err = read_eraseblock(i); if (err) goto out; - cond_resched(); + + err = mtdtest_relax(); + if (err) + goto out; } stop_timing(); speed = calc_speed(); @@ -303,7 +309,10 @@ static int __init mtd_speedtest_init(void) err = write_eraseblock_by_page(i); if (err) goto out; - cond_resched(); + + err = mtdtest_relax(); + if (err) + goto out; } stop_timing(); speed = calc_speed(); @@ -318,7 +327,10 @@ static int __init mtd_speedtest_init(void) err = read_eraseblock_by_page(i); if (err) goto out; - cond_resched(); + + err = mtdtest_relax(); + if (err) + goto out; } stop_timing(); speed = calc_speed(); @@ -337,7 +349,10 @@ static int __init mtd_speedtest_init(void) err = write_eraseblock_by_2pages(i); if (err) goto out; - cond_resched(); + + err = mtdtest_relax(); + if (err) + goto out; } stop_timing(); speed = calc_speed(); @@ -352,7 +367,10 @@ static int __init mtd_speedtest_init(void) err = read_eraseblock_by_2pages(i); if (err) goto out; - cond_resched(); + + err = mtdtest_relax(); + if (err) + goto out; } stop_timing(); speed = calc_speed(); @@ -385,7 +403,11 @@ static int __init mtd_speedtest_init(void) err = multiblock_erase(i, j); if (err) goto out; - cond_resched(); + + err = mtdtest_relax(); + if (err) + goto out; + i += j; } stop_timing(); diff --git a/drivers/mtd/tests/stresstest.c b/drivers/mtd/tests/stresstest.c index d90c1c01dac6..e509f8aa9a7e 100644 --- a/drivers/mtd/tests/stresstest.c +++ b/drivers/mtd/tests/stresstest.c @@ -221,7 +221,10 @@ static int __init mtd_stresstest_init(void) err = do_operation(); if (err) goto out; - cond_resched(); + + err = mtdtest_relax(); + if (err) + goto out; } pr_info("finished, %d operations done\n", op); diff --git a/drivers/mtd/tests/subpagetest.c b/drivers/mtd/tests/subpagetest.c index 0b835c631f91..aecc6ce5a9e1 100644 --- a/drivers/mtd/tests/subpagetest.c +++ b/drivers/mtd/tests/subpagetest.c @@ -269,7 +269,10 @@ static int verify_all_eraseblocks_ff(void) return err; if (i % 256 == 0) pr_info("verified up to eraseblock %u\n", i); - cond_resched(); + + err = mtdtest_relax(); + if (err) + return err; } pr_info("verified %u eraseblocks\n", i); return 0; @@ -346,7 +349,10 @@ static int __init mtd_subpagetest_init(void) goto out; if (i % 256 == 0) pr_info("written up to eraseblock %u\n", i); - cond_resched(); + + err = mtdtest_relax(); + if (err) + goto out; } pr_info("written %u eraseblocks\n", i); @@ -360,7 +366,10 @@ static int __init mtd_subpagetest_init(void) goto out; if (i % 256 == 0) pr_info("verified up to eraseblock %u\n", i); - cond_resched(); + + err = mtdtest_relax(); + if (err) + goto out; } pr_info("verified %u eraseblocks\n", i); @@ -383,7 +392,10 @@ static int __init mtd_subpagetest_init(void) goto out; if (i % 256 == 0) pr_info("written up to eraseblock %u\n", i); - cond_resched(); + + err = mtdtest_relax(); + if (err) + goto out; } pr_info("written %u eraseblocks\n", i); @@ -398,7 +410,10 @@ static int __init mtd_subpagetest_init(void) goto out; if (i % 256 == 0) pr_info("verified up to eraseblock %u\n", i); - cond_resched(); + + err = mtdtest_relax(); + if (err) + goto out; } pr_info("verified %u eraseblocks\n", i); diff --git a/drivers/mtd/tests/torturetest.c b/drivers/mtd/tests/torturetest.c index 5045cf1b3160..e5d6e6d9532f 100644 --- a/drivers/mtd/tests/torturetest.c +++ b/drivers/mtd/tests/torturetest.c @@ -279,7 +279,10 @@ static int __init tort_init(void) " for 0xFF... pattern\n"); goto out; } - cond_resched(); + + err = mtdtest_relax(); + if (err) + goto out; } } @@ -294,7 +297,10 @@ static int __init tort_init(void) err = write_pattern(i, patt); if (err) goto out; - cond_resched(); + + err = mtdtest_relax(); + if (err) + goto out; } /* Verify what we wrote */ @@ -314,7 +320,10 @@ static int __init tort_init(void) "0x55AA55..." : "0xAA55AA..."); goto out; } - cond_resched(); + + err = mtdtest_relax(); + if (err) + goto out; } } -- cgit v1.2.3 From 1103b8517041b08286cae0da8481bef9164c961a Mon Sep 17 00:00:00 2001 From: Brian Norris Date: Fri, 27 Mar 2015 10:29:50 -0700 Subject: mtd: m25p80: bind to "nor-jedec" ID, for auto-detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use the new 'nor-jedec' binding to provide automatic detection of flash that use the 0x9F READ ID opcode. This can help for use cases where platforms just specify compatibility with "m25p80", and then see messages like this: m25p80 spi32766.0: found s25fl256s1, expected m25p80 Instead, they can just specify the generic string and see this: m25p80 spi32766.0: s25fl256s1 (32768 Kbytes) Also, update the language about m25p_ids[] to straighten out the expectations here. We should no longer need to continuously grow the m25p_ids[] table, and in fact, we might want to start removing entries which are not used in device trees so far, so we can just default to auto-detection as much as possible in the future. Signed-off-by: Brian Norris Cc: Rafał Miłecki --- drivers/mtd/devices/m25p80.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'drivers') diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index 85e35467fba6..7c8b1694a134 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c @@ -223,6 +223,8 @@ static int m25p_probe(struct spi_device *spi) */ if (data && data->type) flash_name = data->type; + else if (!strcmp(spi->modalias, "nor-jedec")) + flash_name = NULL; /* auto-detect */ else flash_name = spi->modalias; @@ -247,9 +249,16 @@ static int m25p_remove(struct spi_device *spi) } /* - * XXX This needs to be kept in sync with spi_nor_ids. We can't share - * it with spi-nor, because if this is built as a module then modpost - * won't be able to read it and add appropriate aliases. + * Do NOT add to this array without reading the following: + * + * Historically, many flash devices are bound to this driver by their name. But + * since most of these flash are compatible to some extent, and their + * differences can often be differentiated by the JEDEC read-ID command, we + * encourage new users to add support to the spi-nor library, and simply bind + * against a generic string here (e.g., "nor-jedec"). + * + * Many flash names are kept here in this list (as well as in spi-nor.c) to + * keep them available as module aliases for existing platforms. */ static const struct spi_device_id m25p_ids[] = { {"at25fs010"}, {"at25fs040"}, {"at25df041a"}, {"at25df321a"}, @@ -291,6 +300,12 @@ static const struct spi_device_id m25p_ids[] = { {"w25x64"}, {"w25q64"}, {"w25q80"}, {"w25q80bl"}, {"w25q128"}, {"w25q256"}, {"cat25c11"}, {"cat25c03"}, {"cat25c09"}, {"cat25c17"}, {"cat25128"}, + + /* + * Generic support for SPI NOR that can be identified by the JEDEC READ + * ID opcode (0x9F). Use this, if possible. + */ + {"nor-jedec"}, { }, }; MODULE_DEVICE_TABLE(spi, m25p_ids); -- cgit v1.2.3 From 072b56ab86d2bb2eb6aea4a810cebfa9f105b732 Mon Sep 17 00:00:00 2001 From: Shengzhou Liu Date: Fri, 27 Mar 2015 17:38:30 +0800 Subject: mtd: spi-nor: support en25s64 device Add support for EON en25s64 SPI flash. Signed-off-by: Shengzhou Liu Signed-off-by: Brian Norris --- drivers/mtd/spi-nor/spi-nor.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 60bf3caf1ead..bdd2937a8553 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -538,6 +538,7 @@ static const struct spi_device_id spi_nor_ids[] = { { "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) }, { "en25qh128", INFO(0x1c7018, 0, 64 * 1024, 256, 0) }, { "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) }, + { "en25s64", INFO(0x1c3817, 0, 64 * 1024, 128, 0) }, /* ESMT */ { "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K) }, -- cgit v1.2.3 From 40d19ab69c79da373cdf561a444fbb9778a2ab7d Mon Sep 17 00:00:00 2001 From: Gabor Juhos Date: Thu, 26 Mar 2015 23:58:02 +0100 Subject: mtd: spi-nor: add support for the Winbond W25X05 flash Signed-off-by: Gabor Juhos Signed-off-by: Luka Perkov Signed-off-by: Brian Norris --- drivers/mtd/spi-nor/spi-nor.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index bdd2937a8553..6a5e7cc01056 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -663,6 +663,7 @@ static const struct spi_device_id spi_nor_ids[] = { { "m25px80", INFO(0x207114, 0, 64 * 1024, 16, 0) }, /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */ + { "w25x05", INFO(0xef3010, 0, 64 * 1024, 1, SECT_4K) }, { "w25x10", INFO(0xef3011, 0, 64 * 1024, 2, SECT_4K) }, { "w25x20", INFO(0xef3012, 0, 64 * 1024, 4, SECT_4K) }, { "w25x40", INFO(0xef3013, 0, 64 * 1024, 8, SECT_4K) }, -- cgit v1.2.3 From e88e567f15a26fc62da8e4e0c56d5319b40f628b Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 5 Feb 2015 18:39:02 +0200 Subject: mtd: spi-nor: Add support for Winbond w25q64dw serial flash Add Winbond (w25q64dw) 8MB flash to the list of supported chips. Signed-off-by: Mika Westerberg Signed-off-by: Brian Norris --- drivers/mtd/spi-nor/spi-nor.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 6a5e7cc01056..6a1df02b1999 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -674,6 +674,7 @@ static const struct spi_device_id spi_nor_ids[] = { { "w25q32dw", INFO(0xef6016, 0, 64 * 1024, 64, SECT_4K) }, { "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) }, { "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) }, + { "w25q64dw", INFO(0xef6017, 0, 64 * 1024, 128, SECT_4K) }, { "w25q80", INFO(0xef5014, 0, 64 * 1024, 16, SECT_4K) }, { "w25q80bl", INFO(0xef4014, 0, 64 * 1024, 16, SECT_4K) }, { "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) }, -- cgit v1.2.3 From 81a1209c90914cbf5639a2bc9a325d9821f89faa Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Thu, 5 Feb 2015 18:39:03 +0200 Subject: mtd: spi-nor: Add support for Macronix mx25u6435f serial flash Add Macronix (mx25u6435f) 8MB flash to the list of supported chips. Signed-off-by: Mika Westerberg Signed-off-by: Brian Norris --- drivers/mtd/spi-nor/spi-nor.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c index 6a1df02b1999..14a5d2325dac 100644 --- a/drivers/mtd/spi-nor/spi-nor.c +++ b/drivers/mtd/spi-nor/spi-nor.c @@ -568,6 +568,7 @@ static const struct spi_device_id spi_nor_ids[] = { { "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, 0) }, { "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64, SECT_4K) }, { "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, 0) }, + { "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) }, { "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) }, { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) }, { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) }, -- cgit v1.2.3