Commit f4e70c2e authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'mtd/for-4.18' of git://git.infradead.org/linux-mtd

Pull MTD updates from Boris Brezillon:
 "Core changes:
   - Add a sysfs attribute to expose available OOB size

  Driver changes:
   - Remove HAS_DMA dependency on various drivers
   - Use dev_get_drvdata() instead of platform_get_drvdata() in docg3
   - Replace msleep by usleep_range() in the dataflash driver
   - Avoid VLA usage in nftl layers
   - Remove useless .owner assignment in pismo
   - Fix various issues in the CFI driver
   - Improve TRX partition handling expose a DT compat for this part
     parser
   - Clarify OFFSET_CONTINUOUS meaning

  NAND core changes:
   - Add Miquel as a NAND maintainer
   - Add access mode to the nand_page_io_req struct
   - Fix kernel-doc in rawnand.h
   - Support bit-wise majority to recover from corrupted ONFI parameter
     pages
   - Stop checking FAIL bit after a SET_FEATURES, as documented in the
     ONFI spec

  Raw NAND Driver changes:
   - Fix and cleanup the error path of many NAND controller drivers
   - GPMI:
      + Cleanup/simplification of a few aspects in the driver
      + Take ECC setup specified in the DT into account
   - sunxi: remove support for GPIO-based R/B polling
   - MTK:
      + Use of_device_get_match_data() instead of of_match_device()
      + Add an entry in MAINTAINERS for this driver
      + Fix nand-ecc-step-size and nand-ecc-strength description in the
        DT bindings doc
   - fsl_ifc: fix ->cmdfunc() to read more than one ONFI parameter page

  OneNAND driver changes:
   - samsung: use dev_get_drvdata() instead of platform_get_drvdata()

  SPI NOR core changes:
   - Add support for a bunch of SPI NOR chips
   - Clear EAR reg when switching to 3-byte addressing mode on Winbond
     chips

  SPI NOR controller driver changes:
   - cadence: Add DMA support for direct mode reads
   - hisi: Prefix a few functions with hisi_
   - intel:
      + Mark the driver as "dangerous" in Kconfig
      + Fix atomic sequence handling
      + Pass a 40us delay (instead of 0us) to readl_poll_timeout()
   - fsl:
      + fix a typo in a function name
      + add support for IP variants embedded in the ls2080a and ls1080a
        SoCs
   - stm32: request exclusive control of the reset line"

* tag 'mtd/for-4.18' of git://git.infradead.org/linux-mtd: (66 commits)
  mtd: nand: Pass mode information to nand_page_io_req
  mtd: cfi_cmdset_0002: Change erase one block to enable XIP once
  mtd: cfi_cmdset_0002: Change erase functions to check chip good only
  mtd: cfi_cmdset_0002: Change erase functions to retry for error
  mtd: cfi_cmdset_0002: Change definition naming to retry write operation
  mtd: cfi_cmdset_0002: Change write buffer to check correct value
  mtd: cmdlinepart: Update comment for introduction of OFFSET_CONTINUOUS
  mtd: bcm47xxpart: add of_match_table with a new DT binding
  dt-bindings: mtd: document Broadcom's BCM47xx partitions
  mtd: spi-nor: Add support for EN25QH32
  mtd: spi-nor: Add support for is25wp series chips
  mtd: spi-nor: Add Winbond w25q32jv support
  mtd: spi-nor: fsl-quadspi: add support for ls2080a/ls1080a
  mtd: spi-nor: stm32-quadspi: explicitly request exclusive reset control
  mtd: spi-nor: intel: provide a range for poll_timout
  mtd: spi-nor: fsl-quadspi: fix api naming typo _init_ahb_read
  mtd: spi-nor: intel-spi: Explicitly mark the driver as dangerous in Kconfig
  mtd: spi-nor: intel-spi: Fix atomic sequence handling
  mtd: rawnand: Do not check FAIL bit when executing a SET_FEATURES op
  mtd: rawnand: use bit-wise majority to recover the ONFI param page
  ...
parents ea125ded b771327a
......@@ -232,3 +232,11 @@ Description:
of the parent (another partition or a flash device) in bytes.
This attribute is absent on flash devices, so it can be used
to distinguish them from partitions.
What: /sys/class/mtd/mtdX/oobavail
Date: April 2018
KernelVersion: 4.16
Contact: linux-mtd@lists.infradead.org
Description:
Number of bytes available for a client to place data into
the out of band area.
......@@ -47,6 +47,11 @@ Optional properties:
partitions written from Linux with this feature
turned on may not be accessible by the BootROM
code.
- nand-ecc-strength: integer representing the number of bits to correct
per ECC step. Needs to be a multiple of 2.
- nand-ecc-step-size: integer representing the number of data bytes
that are covered by a single ECC step. The driver
supports 512 and 1024.
The device tree may optionally contain sub-nodes describing partitions of the
address space. See partition.txt for more detail.
......
......@@ -48,14 +48,19 @@ Optional:
- nand-on-flash-bbt: Store BBT on NAND Flash.
- nand-ecc-mode: the NAND ecc mode (check driver for supported modes)
- nand-ecc-step-size: Number of data bytes covered by a single ECC step.
valid values: 512 and 1024.
valid values:
512 and 1024 on mt2701 and mt2712.
512 only on mt7622.
1024 is recommended for large page NANDs.
- nand-ecc-strength: Number of bits to correct per ECC step.
The valid values that the controller supports are: 4, 6,
8, 10, 12, 14, 16, 18, 20, 22, 24, 28, 32, 36, 40, 44,
48, 52, 56, 60.
The valid values that each controller supports:
mt2701: 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 28,
32, 36, 40, 44, 48, 52, 56, 60.
mt2712: 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 28,
32, 36, 40, 44, 48, 52, 56, 60, 68, 72, 80.
mt7622: 4, 6, 8, 10, 12, 14, 16.
The strength should be calculated as follows:
E = (S - F) * 8 / 14
E = (S - F) * 8 / B
S = O / (P / Q)
E : nand-ecc-strength.
S : spare size per sector.
......@@ -64,6 +69,15 @@ Optional:
O : oob size.
P : page size.
Q : nand-ecc-step-size.
B : number of parity bits needed to correct
1 bitflip.
According to MTK NAND controller design,
this number depends on max ecc step size
that MTK NAND controller supports.
If max ecc step size supported is 1024,
then it should be always 14. And if max
ecc step size is 512, then it should be
always 13.
If the result does not match any one of the listed
choices above, please select the smaller valid value from
the list.
......
......@@ -14,7 +14,7 @@ method is used for a given flash device. To describe the method there should be
a subnode of the flash device that is named 'partitions'. It must have a
'compatible' property, which is used to identify the method to use.
We currently only document a binding for fixed layouts.
Available bindings are listed in the "partitions" subdirectory.
Fixed Partitions
......
Broadcom BCM47xx Partitions
===========================
Broadcom is one of hardware manufacturers providing SoCs (BCM47xx) used in
home routers. Their BCM947xx boards using CFE bootloader have several partitions
without any on-flash partition table. On some devices their sizes and/or
meanings can also vary so fixed partitioning can't be used.
Discovering partitions on these devices is possible thanks to having a special
header and/or magic signature at the beginning of each of them. They are also
block aligned which is important for determinig a size.
Most of partitions use ASCII text based magic for determining a type. More
complex partitions (like TRX with its HDR0 magic) may include extra header
containing some details, including a length.
A list of supported partitions includes:
1) Bootloader with Broadcom's CFE (Common Firmware Environment)
2) NVRAM with configuration/calibration data
3) Device manufacturer's data with some default values (e.g. SSIDs)
4) TRX firmware container which can hold up to 4 subpartitions
5) Backup TRX firmware used after failed upgrade
As mentioned earlier, role of some partitions may depend on extra configuration.
For example both: main firmware and backup firmware use the same TRX format with
the same header. To distinguish currently used firmware a CFE's environment
variable "bootpartition" is used.
Devices using Broadcom partitions described above should should have flash node
with a subnode named "partitions" using following properties:
Required properties:
- compatible : (required) must be "brcm,bcm947xx-cfe-partitions"
Example:
flash@0 {
partitions {
compatible = "brcm,bcm947xx-cfe-partitions";
};
};
......@@ -22,8 +22,6 @@ Optional properties:
- reset : phandle + reset specifier pair
- reset-names : must contain "ahb"
- allwinner,rb : shall contain the native Ready/Busy ids.
or
- rb-gpios : shall contain the gpios used as R/B pins.
- nand-ecc-mode : one of the supported ECC modes ("hw", "soft", "soft_bch" or
"none")
......
......@@ -9022,6 +9022,13 @@ L: linux-wireless@vger.kernel.org
S: Maintained
F: drivers/net/wireless/mediatek/mt7601u/
MEDIATEK NAND CONTROLLER DRIVER
M: Xiaolei Li <xiaolei.li@mediatek.com>
L: linux-mtd@lists.infradead.org
S: Maintained
F: drivers/mtd/nand/raw/mtk_*
F: Documentation/devicetree/bindings/mtd/mtk-nand.txt
MEDIATEK RANDOM NUMBER GENERATOR SUPPORT
M: Sean Wang <sean.wang@mediatek.com>
S: Maintained
......@@ -9666,6 +9673,7 @@ F: drivers/net/ethernet/myricom/myri10ge/
NAND FLASH SUBSYSTEM
M: Boris Brezillon <boris.brezillon@bootlin.com>
M: Miquel Raynal <miquel.raynal@bootlin.com>
R: Richard Weinberger <richard@nod.at>
L: linux-mtd@lists.infradead.org
W: http://www.linux-mtd.infradead.org/
......
......@@ -186,6 +186,8 @@ static int bcm47xxpart_parse(struct mtd_info *master,
/* TRX */
if (buf[0x000 / 4] == TRX_MAGIC) {
struct trx_header *trx;
uint32_t last_subpart;
uint32_t trx_size;
if (trx_num >= ARRAY_SIZE(trx_parts))
pr_warn("No enough space to store another TRX found at 0x%X\n",
......@@ -195,11 +197,23 @@ static int bcm47xxpart_parse(struct mtd_info *master,
bcm47xxpart_add_part(&parts[curr_part++], "firmware",
offset, 0);
/* Jump to the end of TRX */
/*
* Try to find TRX size. The "length" field isn't fully
* reliable as it could be decreased to make CRC32 cover
* only part of TRX data. It's commonly used as checksum
* can't cover e.g. ever-changing rootfs partition.
* Use offsets as helpers for assuming min TRX size.
*/
trx = (struct trx_header *)buf;
offset = roundup(offset + trx->length, blocksize);
/* Next loop iteration will increase the offset */
offset -= blocksize;
last_subpart = max3(trx->offset[0], trx->offset[1],
trx->offset[2]);
trx_size = max(trx->length, last_subpart + blocksize);
/*
* Skip the TRX data. Decrease offset by block size as
* the next loop iteration will increase it.
*/
offset += roundup(trx_size, blocksize) - blocksize;
continue;
}
......@@ -290,9 +304,16 @@ static int bcm47xxpart_parse(struct mtd_info *master,
return curr_part;
};
static const struct of_device_id bcm47xxpart_of_match_table[] = {
{ .compatible = "brcm,bcm947xx-cfe-partitions" },
{},
};
MODULE_DEVICE_TABLE(of, bcm47xxpart_of_match_table);
static struct mtd_part_parser bcm47xxpart_mtd_parser = {
.parse_fn = bcm47xxpart_parse,
.name = "bcm47xxpart",
.of_match_table = bcm47xxpart_of_match_table,
};
module_mtd_part_parser(bcm47xxpart_mtd_parser);
......
......@@ -42,10 +42,10 @@
#define AMD_BOOTLOC_BUG
#define FORCE_WORD_WRITE 0
#define MAX_WORD_RETRIES 3
#define MAX_RETRIES 3
#define SST49LF004B 0x0060
#define SST49LF040B 0x0050
#define SST49LF004B 0x0060
#define SST49LF040B 0x0050
#define SST49LF008A 0x005a
#define AT49BV6416 0x00d6
......@@ -207,7 +207,7 @@ static void fixup_use_write_buffers(struct mtd_info *mtd)
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
if (cfi->cfiq->BufWriteTimeoutTyp) {
pr_debug("Using buffer write method\n" );
pr_debug("Using buffer write method\n");
mtd->_write = cfi_amdstd_write_buffers;
}
}
......@@ -1563,7 +1563,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
* depending of the conditions. The ' + 1' is to avoid having a
* timeout of 0 jiffies if HZ is smaller than 1000.
*/
unsigned long uWriteTimeout = ( HZ / 1000 ) + 1;
unsigned long uWriteTimeout = (HZ / 1000) + 1;
int ret = 0;
map_word oldd;
int retry_cnt = 0;
......@@ -1578,7 +1578,7 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
}
pr_debug("MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n",
__func__, adr, datum.x[0] );
__func__, adr, datum.x[0]);
if (mode == FL_OTP_WRITE)
otp_enter(map, chip, adr, map_bankwidth(map));
......@@ -1644,10 +1644,10 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
/* Did we succeed? */
if (!chip_good(map, adr, datum)) {
/* reset on all failures. */
map_write( map, CMD(0xF0), chip->start );
map_write(map, CMD(0xF0), chip->start);
/* FIXME - should have reset delay before continuing */
if (++retry_cnt <= MAX_WORD_RETRIES)
if (++retry_cnt <= MAX_RETRIES)
goto retry;
ret = -EIO;
......@@ -1822,7 +1822,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
datum = map_word_load(map, buf);
pr_debug("MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n",
__func__, adr, datum.x[0] );
__func__, adr, datum.x[0]);
XIP_INVAL_CACHED_RANGE(map, adr, len);
ENABLE_VPP(map);
......@@ -1880,7 +1880,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
if (time_after(jiffies, timeo) && !chip_ready(map, adr))
break;
if (chip_ready(map, adr)) {
if (chip_good(map, adr, datum)) {
xip_enable(map, chip, adr);
goto op_done;
}
......@@ -2106,7 +2106,7 @@ static int do_panic_write_oneword(struct map_info *map, struct flchip *chip,
map_write(map, CMD(0xF0), chip->start);
/* FIXME - should have reset delay before continuing */
if (++retry_cnt <= MAX_WORD_RETRIES)
if (++retry_cnt <= MAX_RETRIES)
goto retry;
ret = -EIO;
......@@ -2241,6 +2241,7 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip)
unsigned long int adr;
DECLARE_WAITQUEUE(wait, current);
int ret = 0;
int retry_cnt = 0;
adr = cfi->addr_unlock1;
......@@ -2252,12 +2253,13 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip)
}
pr_debug("MTD %s(): ERASE 0x%.8lx\n",
__func__, chip->start );
__func__, chip->start);
XIP_INVAL_CACHED_RANGE(map, adr, map->size);
ENABLE_VPP(map);
xip_disable(map, chip, adr);
retry:
cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
......@@ -2294,12 +2296,13 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip)
chip->erase_suspended = 0;
}
if (chip_ready(map, adr))
if (chip_good(map, adr, map_word_ff(map)))
break;
if (time_after(jiffies, timeo)) {
printk(KERN_WARNING "MTD %s(): software timeout\n",
__func__ );
__func__);
ret = -EIO;
break;
}
......@@ -2307,12 +2310,15 @@ static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip)
UDELAY(map, chip, adr, 1000000/HZ);
}
/* Did we succeed? */
if (!chip_good(map, adr, map_word_ff(map))) {
if (ret) {
/* reset on all failures. */
map_write( map, CMD(0xF0), chip->start );
map_write(map, CMD(0xF0), chip->start);
/* FIXME - should have reset delay before continuing */
ret = -EIO;
if (++retry_cnt <= MAX_RETRIES) {
ret = 0;
goto retry;
}
}
chip->state = FL_READY;
......@@ -2331,6 +2337,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
unsigned long timeo = jiffies + HZ;
DECLARE_WAITQUEUE(wait, current);
int ret = 0;
int retry_cnt = 0;
adr += chip->start;
......@@ -2342,12 +2349,13 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
}
pr_debug("MTD %s(): ERASE 0x%.8lx\n",
__func__, adr );
__func__, adr);
XIP_INVAL_CACHED_RANGE(map, adr, len);
ENABLE_VPP(map);
xip_disable(map, chip, adr);
retry:
cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
......@@ -2384,15 +2392,13 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
chip->erase_suspended = 0;
}
if (chip_ready(map, adr)) {
xip_enable(map, chip, adr);
if (chip_good(map, adr, map_word_ff(map)))
break;
}
if (time_after(jiffies, timeo)) {
xip_enable(map, chip, adr);
printk(KERN_WARNING "MTD %s(): software timeout\n",
__func__ );
__func__);
ret = -EIO;
break;
}
......@@ -2400,15 +2406,19 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
UDELAY(map, chip, adr, 1000000/HZ);
}
/* Did we succeed? */
if (!chip_good(map, adr, map_word_ff(map))) {
if (ret) {
/* reset on all failures. */
map_write( map, CMD(0xF0), chip->start );
map_write(map, CMD(0xF0), chip->start);
/* FIXME - should have reset delay before continuing */
ret = -EIO;
if (++retry_cnt <= MAX_RETRIES) {
ret = 0;
goto retry;
}
}
chip->state = FL_READY;
xip_enable(map, chip, adr);
DISABLE_VPP(map);
put_chip(map, chip, adr);
mutex_unlock(&chip->mutex);
......
......@@ -63,6 +63,30 @@ do { \
#endif
/*
* This fixup occurs immediately after reading the CFI structure and can affect
* the number of chips detected, unlike cfi_fixup, which occurs after an
* mtd_info structure has been created for the chip.
*/
struct cfi_early_fixup {
uint16_t mfr;
uint16_t id;
void (*fixup)(struct cfi_private *cfi);
};
static void cfi_early_fixup(struct cfi_private *cfi,
const struct cfi_early_fixup *fixups)
{
const struct cfi_early_fixup *f;
for (f = fixups; f->fixup; f++) {
if (((f->mfr == CFI_MFR_ANY) || (f->mfr == cfi->mfr)) &&
((f->id == CFI_ID_ANY) || (f->id == cfi->id))) {
f->fixup(cfi);
}
}
}
/* check for QRY.
in: interleave,type,mode
ret: table index, <0 for error
......@@ -151,6 +175,22 @@ static int __xipram cfi_probe_chip(struct map_info *map, __u32 base,
return 1;
}
static void fixup_s70gl02gs_chips(struct cfi_private *cfi)
{
/*
* S70GL02GS flash reports a single 256 MiB chip, but is really made up
* of two 128 MiB chips with 1024 sectors each.
*/
cfi->cfiq->DevSize = 27;
cfi->cfiq->EraseRegionInfo[0] = 0x20003ff;
pr_warn("Bad S70GL02GS CFI data; adjust to detect 2 chips\n");
}
static const struct cfi_early_fixup cfi_early_fixup_table[] = {
{ CFI_MFR_AMD, 0x4801, fixup_s70gl02gs_chips },
{ },
};
static int __xipram cfi_chip_setup(struct map_info *map,
struct cfi_private *cfi)
{
......@@ -235,6 +275,8 @@ static int __xipram cfi_chip_setup(struct map_info *map,
cfi_qry_mode_off(base, map, cfi);
xip_allowed(base, map);
cfi_early_fixup(cfi, cfi_early_fixup_table);
printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit bank. Manufacturer ID %#08x Chip ID %#08x\n",
map->name, cfi->interleave, cfi->device_type*8, base,
map->bankwidth*8, cfi->mfr, cfi->id);
......
......@@ -190,7 +190,10 @@ static struct mtd_partition * newpart(char *s,
extra_mem = (unsigned char *)(parts + *num_parts);
}
/* enter this partition (offset will be calculated later if it is zero at this point) */
/*
* enter this partition (offset will be calculated later if it is
* OFFSET_CONTINUOUS at this point)
*/
parts[this_part].size = size;
parts[this_part].offset = offset;
parts[this_part].mask_flags = mask_flags;
......
......@@ -1470,8 +1470,7 @@ static struct docg3 *sysfs_dev2docg3(struct device *dev,
struct device_attribute *attr)
{
int floor;
struct platform_device *pdev = to_platform_device(dev);
struct mtd_info **docg3_floors = platform_get_drvdata(pdev);
struct mtd_info **docg3_floors = dev_get_drvdata(dev);
floor = attr->attr.name[1] - '0';
if (floor < 0 || floor >= DOC_MAX_NBFLOORS)
......
......@@ -140,7 +140,7 @@ static int dataflash_waitready(struct spi_device *spi)
if (status & (1 << 7)) /* RDY/nBSY */
return status;
msleep(3);
usleep_range(3000, 4000);
}
}
......
......@@ -334,28 +334,37 @@ static int memcmpb(void *a, int c, int n)
static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address,
int len, int check_oob)
{
u8 buf[SECTORSIZE + inftl->mbd.mtd->oobsize];
struct mtd_info *mtd = inftl->mbd.mtd;
size_t retlen;
int i;
int i, ret;
u8 *buf;
buf = kmalloc(SECTORSIZE + mtd->oobsize, GFP_KERNEL);
if (!buf)
return -1;
ret = -1;
for (i = 0; i < len; i += SECTORSIZE) {
if (mtd_read(mtd, address, SECTORSIZE, &retlen, buf))
return -1;
goto out;
if (memcmpb(buf, 0xff, SECTORSIZE) != 0)
return -1;
goto out;
if (check_oob) {
if(inftl_read_oob(mtd, address, mtd->oobsize,
&retlen, &buf[SECTORSIZE]) < 0)
return -1;
goto out;
if (memcmpb(buf + SECTORSIZE, 0xff, mtd->oobsize) != 0)
return -1;
goto out;
}
address += SECTORSIZE;
}
return 0;
ret = 0;
out:
kfree(buf);
return ret;
}
/*
......
......@@ -265,7 +265,6 @@ MODULE_DEVICE_TABLE(i2c, pismo_id);
static struct i2c_driver pismo_driver = {
.driver = {
.name = "pismo",
.owner = THIS_MODULE,
},
.probe = pismo_probe,
.remove = pismo_remove,
......
......@@ -210,6 +210,15 @@ static ssize_t mtd_oobsize_show(struct device *dev,
}
static DEVICE_ATTR(oobsize, S_IRUGO, mtd_oobsize_show, NULL);
static ssize_t mtd_oobavail_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct mtd_info *mtd = dev_get_drvdata(dev);
return snprintf(buf, PAGE_SIZE, "%u\n", mtd->oobavail);
}
static DEVICE_ATTR(oobavail, S_IRUGO, mtd_oobavail_show, NULL);
static ssize_t mtd_numeraseregions_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
......@@ -327,6 +336,7 @@ static struct attribute *mtd_attrs[] = {
&dev_attr_writesize.attr,
&dev_attr_subpagesize.attr,
&dev_attr_oobsize.attr,
&dev_attr_oobavail.attr,
&dev_attr_numeraseregions.attr,
&dev_attr_name.attr,
&dev_attr_ecc_strength.attr,
......@@ -690,7 +700,6 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
const struct mtd_partition *parts,
int nr_parts)
{
struct mtd_partitions parsed = { };
int ret;
mtd_set_dev_defaults(mtd);
......@@ -702,13 +711,10 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
}
/* Prefer parsed partitions over driver-provided fallback */
ret = parse_mtd_partitions(mtd, types, &parsed, parser_data);
if (!ret && parsed.nr_parts) {
parts = parsed.parts;
nr_parts = parsed.nr_parts;
}
if (nr_parts)
ret = parse_mtd_partitions(mtd, types, parser_data);
if (ret > 0)
ret = 0;
else if (nr_parts)
ret = add_mtd_partitions(mtd, parts, nr_parts);
else if (!device_is_registered(&mtd->dev))
ret = add_mtd_device(mtd);
......@@ -734,8 +740,6 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
}
out:
/* Cleanup any parsed partitions */
mtd_part_parser_cleanup(&parsed);
if (ret && device_is_registered(&mtd->dev))
del_mtd_device(mtd);
......
......@@ -15,7 +15,6 @@ int del_mtd_partitions(struct mtd_info *);
struct mtd_partitions;
int parse_mtd_partitions(struct mtd_info *master, const char * const *types,
struct mtd_partitions *pparts,
struct mtd_part_parser_data *data);
void mtd_part_parser_cleanup(struct mtd_partitions *parts);
......
......@@ -335,20 +335,7 @@ static inline void free_partition(struct mtd_part *p)
*/
static int mtd_parse_part(struct mtd_part *slave, const char *const *types)
{
struct mtd_partitions parsed;
int err;
err = parse_mtd_partitions(&slave->mtd, types, &parsed, NULL);
if (err)
return err;
else if (!parsed.nr_parts)
return -ENOENT;
err = add_mtd_partitions(&slave->mtd, parsed.parts, parsed.nr_parts);
mtd_part_parser_cleanup(&parsed);
return err;
return parse_mtd_partitions(&slave->mtd, types, NULL);
}
static struct mtd_part *allocate_partition(struct mtd_info *parent,
......@@ -933,30 +920,27 @@ static int mtd_part_of_parse(struct mtd_info *master,
}
/**
* parse_mtd_partitions - parse MTD partitions
* parse_mtd_partitions - parse and register MTD partitions
*
* @master: the master partition (describes whole MTD device)
* @types: names of partition parsers to try or %NULL
* @pparts: info about partitions found is returned here
* @data: MTD partition parser-specific data
*
* This function tries to find partition on MTD device @master. It uses MTD
* partition parsers, specified in @types. However, if @types is %NULL, then
* the default list of parsers is used. The default list contains only the
* This function tries to find & register partitions on MTD device @master. It
* uses MTD partition parsers, specified in @types. However, if @types is %NULL,
* then the default list of parsers is used. The default list contains only the
* "cmdlinepart" and "ofpart" parsers ATM.
* Note: If there are more then one parser in @types, the kernel only takes the
* partitions parsed out by the first parser.
*
* This function may return:
* o a negative error code in case of failure
* o zero otherwise, and @pparts will describe the partitions, number of
* partitions, and the parser which parsed them. Caller must release
* resources with mtd_part_parser_cleanup() when finished with the returned
* data.
* o number of found partitions otherwise
*/
int parse_mtd_partitions(struct mtd_info *master, const char *const *types,
struct mtd_partitions *pparts,
struct mtd_part_parser_data *data)
{
struct mtd_partitions pparts = { };
struct mtd_part_parser *parser;
int ret, err = 0;
......@@ -970,7 +954,7 @@ int parse_mtd_partitions(struct mtd_info *master, const char *const *types,
* handled in a separated function.
*/
if (!strcmp(*types, "ofpart")) {
ret = mtd_part_of_parse(master, pparts);
ret = mtd_part_of_parse(master, &pparts);
} else {
pr_debug("%s: parsing partitions %s\n", master->name,
*types);
......@@ -981,13 +965,17 @@ int parse_mtd_partitions(struct mtd_info *master, const char *const *types,
parser ? parser->name : NULL);
if (!parser)
continue;
ret = mtd_part_do_parse(parser, master, pparts, data);
ret = mtd_part_do_parse(parser, master, &pparts, data);
if (ret <= 0)
mtd_part_parser_put(parser);
}
/* Found partitions! */
if (ret > 0)
return 0;
if (ret > 0) {
err = add_mtd_partitions(master, pparts.parts,
pparts.nr_parts);
mtd_part_parser_cleanup(&pparts);
return err ? err : pparts.nr_parts;
}
/*
* Stash the first error we see; only report it if no parser
* succeeds
......
......@@ -958,8 +958,7 @@ static int s3c_onenand_remove(struct platform_device *pdev)
static int s3c_pm_ops_suspend(struct device *dev)
{