diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-14 20:57:44 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-08-14 20:57:44 +0300 |
commit | c2fc71c9b74c1e87336a27dba1a5edc69d2690f1 (patch) | |
tree | fddb02e3ab8a011f0a6eba1ffd7e1810325dd4a5 /drivers/mtd/nand/raw/nand_base.c | |
parent | 57ee3196ce7c7cbc52f2792414919d9756b42828 (diff) | |
parent | 9805d4bcf8f98dbeb1a66c3195f2ea8b917a083e (diff) | |
download | linux-c2fc71c9b74c1e87336a27dba1a5edc69d2690f1.tar.xz |
Merge tag 'mtd/for-4.19' of git://git.infradead.org/linux-mtd
Pull mtd updates from Boris Brezillon:
"JFFS2 changes:
- Support 64-bit timestamps
MTD core changes:
- Support sub-partitions
- Clarify mtd_oob_ops documentation
- Make Kconfig formatting consistent
- Fix potential overflows in mtdchar_{write,read}()
- Fallback to ->_{read,write}() when ->_{read,write}_oob() is missing
and no OOB data were requested
- Remove VLA usage in the bch lib
MTD driver changes:
- Use mtd_device_register() instead of mtd_device_parse_register()
where applicable
- Use proper printk format to print physical addresses in the
solutionengine driver
- Add missing mtd_set_of_node() call in the powernv driver
- Remove unneeded variables in a few drivers
- Plug the TRX part parser to the DT partition parsers logic
- Check ioremap_cache() return code in the gpio-addr-flash driver
- Stop using VMLINUX_SYMBOL_STR() in gen_probe.c
SPI NOR core changes:
- Apply reset hacks only when reset is explicitly marked as broken in
the DT
SPI NOR driver changes:
- Minor cleanup/fixes in the m25p80 driver
- Release flash_np in the nxp-spifi driver
- Add suspend/resume hooks to the atmel-quadspi driver
- Include gpio/consumer.h instead of gpio.h in the atmel-quadspi
driver
- Use %pK instead of %p in the stm32-quadspi driver
- Improve timeout handling in the cadence-quadspi driver
- Use mtd_device_register() instead of mtd_device_parse_register() in
the intel-spi driver
NAND core changes:
- Add the SPI-NAND framework.
- Create a helper to find the best ECC configuration.
- Create NAND controller operations.
- Allocate dynamically ONFI parameters structure.
- Add defines for ONFI version bits.
- Add manufacturer fixup for ONFI parameter page.
- Add an option to specify NAND chip as a boot device.
- Add Reed-Solomon error correction algorithm.
- Better name for the controller structure.
- Remove unused caller_is_module() definition.
- Make subop helpers return unsigned values.
- Expose _notsupp() helpers for raw page accessors.
- Add default values for dynamic timings.
- Kill the chip->scan_bbt() hook.
- Rename nand_default_bbt() into nand_create_bbt().
- Start to clean the nand_chip structure.
- Remove stale prototype from rawnand.h.
Raw NAND controllers drivers changes:
- Qcom: structuring cleanup.
- Denali: use core helper to find the best ECC configuration.
- Possible build of almost all drivers by adding a dependency on
COMPILE_TEST for almost all of them in Kconfig, implies various
fixes, Kconfig cleanup, GPIO headers inclusion cleanup, and even
changes in sparc64 and ia64 architectures.
- Clean the ->probe() functions error path of a lot of drivers.
- Migrate all drivers to use nand_scan() instead of
nand_scan_ident()/nand_scan_tail() pair.
- Use mtd_device_register() where applicable to simplify the code.
- Marvell:
* Handle on-die ECC.
* Better clocks handling.
* Remove bogus comment.
* Add suspend and resume support.
- Tegra: add NAND controller driver.
- Atmel:
* Add module param to avoid using dma.
* Drop Wenyou Yang from MAINTAINERS.
- Denali: optimize timings handling.
- FSMC: Stop using chip->read_buf().
- FSL:
* Switch to SPDX license tag identifiers.
* Fix qualifiers in MXC init functions.
Raw NAND chip drivers changes:
- Micron:
* Add fixup for ONFI revision.
* Update ecc_stats.corrected.
* Make ECC activation stateful.
* Avoid enabling/disabling ECC when it can't be disabled.
* Get the actual number of bitflips.
* Allow forced on-die ECC.
* Support 8/512 on-die ECC.
* Fix on-die ECC detection logic.
- Hynix:
* Fix decoding the OOB size on H27UCG8T2BTR.
* Use ->exec_op() in hynix_nand_reg_write_op()"
* tag 'mtd/for-4.19' of git://git.infradead.org/linux-mtd: (188 commits)
mtd: rawnand: atmel: Select GENERIC_ALLOCATOR
MAINTAINERS: drop Wenyou Yang from Atmel NAND driver support
mtd: rawnand: allocate dynamically ONFI parameters during detection
mtd: spi-nor: only apply reset hacks to broken hardware
mtd: spi-nor: cadence-quadspi: fix timeout handling
mtd: spi-nor: atmel-quadspi: Include gpio/consumer.h instead of gpio.h
mtd: spi-nor: intel-spi: use mtd_device_register()
mtd: spi-nor: stm32-quadspi: replace "%p" with "%pK"
mtd: spi-nor: atmel-quadspi: add suspend/resume hooks
mtd: rawnand: allocate model parameter dynamically
mtd: rawnand: do not export nand_scan_[ident|tail]() anymore
mtd: rawnand: txx9ndfmc: convert driver to nand_scan()
mtd: rawnand: txx9ndfmc: clarify ECC parameters assignation
mtd: rawnand: tegra: convert driver to nand_scan()
mtd: rawnand: jz4740: convert driver to nand_scan()
mtd: rawnand: jz4740: group nand_scan_{ident, tail} calls
mtd: rawnand: jz4740: fix probe function error path
mtd: rawnand: docg4: convert driver to nand_scan()
mtd: rawnand: do not execute nand_scan_ident() if maxchips is zero
mtd: rawnand: atmel: convert driver to nand_scan()
...
Diffstat (limited to 'drivers/mtd/nand/raw/nand_base.c')
-rw-r--r-- | drivers/mtd/nand/raw/nand_base.c | 345 |
1 files changed, 237 insertions, 108 deletions
diff --git a/drivers/mtd/nand/raw/nand_base.c b/drivers/mtd/nand/raw/nand_base.c index b01d15ec4c56..d527e448ce19 100644 --- a/drivers/mtd/nand/raw/nand_base.c +++ b/drivers/mtd/nand/raw/nand_base.c @@ -2668,8 +2668,8 @@ static bool nand_subop_instr_is_valid(const struct nand_subop *subop, return subop && instr_idx < subop->ninstrs; } -static int nand_subop_get_start_off(const struct nand_subop *subop, - unsigned int instr_idx) +static unsigned int nand_subop_get_start_off(const struct nand_subop *subop, + unsigned int instr_idx) { if (instr_idx) return 0; @@ -2688,12 +2688,12 @@ static int nand_subop_get_start_off(const struct nand_subop *subop, * * Given an address instruction, returns the offset of the first cycle to issue. */ -int nand_subop_get_addr_start_off(const struct nand_subop *subop, - unsigned int instr_idx) +unsigned int nand_subop_get_addr_start_off(const struct nand_subop *subop, + unsigned int instr_idx) { - if (!nand_subop_instr_is_valid(subop, instr_idx) || - subop->instrs[instr_idx].type != NAND_OP_ADDR_INSTR) - return -EINVAL; + if (WARN_ON(!nand_subop_instr_is_valid(subop, instr_idx) || + subop->instrs[instr_idx].type != NAND_OP_ADDR_INSTR)) + return 0; return nand_subop_get_start_off(subop, instr_idx); } @@ -2710,14 +2710,14 @@ EXPORT_SYMBOL_GPL(nand_subop_get_addr_start_off); * * Given an address instruction, returns the number of address cycle to issue. */ -int nand_subop_get_num_addr_cyc(const struct nand_subop *subop, - unsigned int instr_idx) +unsigned int nand_subop_get_num_addr_cyc(const struct nand_subop *subop, + unsigned int instr_idx) { int start_off, end_off; - if (!nand_subop_instr_is_valid(subop, instr_idx) || - subop->instrs[instr_idx].type != NAND_OP_ADDR_INSTR) - return -EINVAL; + if (WARN_ON(!nand_subop_instr_is_valid(subop, instr_idx) || + subop->instrs[instr_idx].type != NAND_OP_ADDR_INSTR)) + return 0; start_off = nand_subop_get_addr_start_off(subop, instr_idx); @@ -2742,12 +2742,12 @@ EXPORT_SYMBOL_GPL(nand_subop_get_num_addr_cyc); * * Given a data instruction, returns the offset to start from. */ -int nand_subop_get_data_start_off(const struct nand_subop *subop, - unsigned int instr_idx) +unsigned int nand_subop_get_data_start_off(const struct nand_subop *subop, + unsigned int instr_idx) { - if (!nand_subop_instr_is_valid(subop, instr_idx) || - !nand_instr_is_data(&subop->instrs[instr_idx])) - return -EINVAL; + if (WARN_ON(!nand_subop_instr_is_valid(subop, instr_idx) || + !nand_instr_is_data(&subop->instrs[instr_idx]))) + return 0; return nand_subop_get_start_off(subop, instr_idx); } @@ -2764,14 +2764,14 @@ EXPORT_SYMBOL_GPL(nand_subop_get_data_start_off); * * Returns the length of the chunk of data to send/receive. */ -int nand_subop_get_data_len(const struct nand_subop *subop, - unsigned int instr_idx) +unsigned int nand_subop_get_data_len(const struct nand_subop *subop, + unsigned int instr_idx) { int start_off = 0, end_off; - if (!nand_subop_instr_is_valid(subop, instr_idx) || - !nand_instr_is_data(&subop->instrs[instr_idx])) - return -EINVAL; + if (WARN_ON(!nand_subop_instr_is_valid(subop, instr_idx) || + !nand_instr_is_data(&subop->instrs[instr_idx]))) + return 0; start_off = nand_subop_get_data_start_off(subop, instr_idx); @@ -2967,6 +2967,23 @@ int nand_check_erased_ecc_chunk(void *data, int datalen, EXPORT_SYMBOL(nand_check_erased_ecc_chunk); /** + * nand_read_page_raw_notsupp - dummy read raw page function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: buffer to store read data + * @oob_required: caller requires OOB data read to chip->oob_poi + * @page: page number to read + * + * Returns -ENOTSUPP unconditionally. + */ +int nand_read_page_raw_notsupp(struct mtd_info *mtd, struct nand_chip *chip, + u8 *buf, int oob_required, int page) +{ + return -ENOTSUPP; +} +EXPORT_SYMBOL(nand_read_page_raw_notsupp); + +/** * nand_read_page_raw - [INTERN] read raw page data without ecc * @mtd: mtd info structure * @chip: nand chip info structure @@ -3960,6 +3977,22 @@ static int nand_read_oob(struct mtd_info *mtd, loff_t from, return ret; } +/** + * nand_write_page_raw_notsupp - dummy raw page write function + * @mtd: mtd info structure + * @chip: nand chip info structure + * @buf: data buffer + * @oob_required: must write chip->oob_poi to OOB + * @page: page number to write + * + * Returns -ENOTSUPP unconditionally. + */ +int nand_write_page_raw_notsupp(struct mtd_info *mtd, struct nand_chip *chip, + const u8 *buf, int oob_required, int page) +{ + return -ENOTSUPP; +} +EXPORT_SYMBOL(nand_write_page_raw_notsupp); /** * nand_write_page_raw - [INTERN] raw page write function @@ -4965,12 +4998,10 @@ static void nand_set_defaults(struct nand_chip *chip) chip->write_byte = busw ? nand_write_byte16 : nand_write_byte; if (!chip->read_buf || chip->read_buf == nand_read_buf) chip->read_buf = busw ? nand_read_buf16 : nand_read_buf; - if (!chip->scan_bbt) - chip->scan_bbt = nand_default_bbt; if (!chip->controller) { - chip->controller = &chip->hwcontrol; - nand_hw_control_init(chip->controller); + chip->controller = &chip->dummy_controller; + nand_controller_init(chip->controller); } if (!chip->buf_align) @@ -5120,6 +5151,8 @@ static int nand_flash_detect_onfi(struct nand_chip *chip) { struct mtd_info *mtd = nand_to_mtd(chip); struct nand_onfi_params *p; + struct onfi_params *onfi; + int onfi_version = 0; char id[4]; int i, ret, val; @@ -5168,30 +5201,35 @@ static int nand_flash_detect_onfi(struct nand_chip *chip) } } + if (chip->manufacturer.desc && chip->manufacturer.desc->ops && + chip->manufacturer.desc->ops->fixup_onfi_param_page) + chip->manufacturer.desc->ops->fixup_onfi_param_page(chip, p); + /* Check version */ val = le16_to_cpu(p->revision); - if (val & (1 << 5)) - chip->parameters.onfi.version = 23; - else if (val & (1 << 4)) - chip->parameters.onfi.version = 22; - else if (val & (1 << 3)) - chip->parameters.onfi.version = 21; - else if (val & (1 << 2)) - chip->parameters.onfi.version = 20; - else if (val & (1 << 1)) - chip->parameters.onfi.version = 10; - - if (!chip->parameters.onfi.version) { + if (val & ONFI_VERSION_2_3) + onfi_version = 23; + else if (val & ONFI_VERSION_2_2) + onfi_version = 22; + else if (val & ONFI_VERSION_2_1) + onfi_version = 21; + else if (val & ONFI_VERSION_2_0) + onfi_version = 20; + else if (val & ONFI_VERSION_1_0) + onfi_version = 10; + + if (!onfi_version) { pr_info("unsupported ONFI version: %d\n", val); goto free_onfi_param_page; - } else { - ret = 1; } sanitize_string(p->manufacturer, sizeof(p->manufacturer)); sanitize_string(p->model, sizeof(p->model)); - strncpy(chip->parameters.model, p->model, - sizeof(chip->parameters.model) - 1); + chip->parameters.model = kstrdup(p->model, GFP_KERNEL); + if (!chip->parameters.model) { + ret = -ENOMEM; + goto free_onfi_param_page; + } mtd->writesize = le32_to_cpu(p->byte_per_page); @@ -5219,7 +5257,7 @@ static int nand_flash_detect_onfi(struct nand_chip *chip) if (p->ecc_bits != 0xff) { chip->ecc_strength_ds = p->ecc_bits; chip->ecc_step_ds = 512; - } else if (chip->parameters.onfi.version >= 21 && + } else if (onfi_version >= 21 && (le16_to_cpu(p->features) & ONFI_FEATURE_EXT_PARAM_PAGE)) { /* @@ -5246,19 +5284,33 @@ static int nand_flash_detect_onfi(struct nand_chip *chip) bitmap_set(chip->parameters.set_feature_list, ONFI_FEATURE_ADDR_TIMING_MODE, 1); } - chip->parameters.onfi.tPROG = le16_to_cpu(p->t_prog); - chip->parameters.onfi.tBERS = le16_to_cpu(p->t_bers); - chip->parameters.onfi.tR = le16_to_cpu(p->t_r); - chip->parameters.onfi.tCCS = le16_to_cpu(p->t_ccs); - chip->parameters.onfi.async_timing_mode = - le16_to_cpu(p->async_timing_mode); - chip->parameters.onfi.vendor_revision = - le16_to_cpu(p->vendor_revision); - memcpy(chip->parameters.onfi.vendor, p->vendor, - sizeof(p->vendor)); + onfi = kzalloc(sizeof(*onfi), GFP_KERNEL); + if (!onfi) { + ret = -ENOMEM; + goto free_model; + } + + onfi->version = onfi_version; + onfi->tPROG = le16_to_cpu(p->t_prog); + onfi->tBERS = le16_to_cpu(p->t_bers); + onfi->tR = le16_to_cpu(p->t_r); + onfi->tCCS = le16_to_cpu(p->t_ccs); + onfi->async_timing_mode = le16_to_cpu(p->async_timing_mode); + onfi->vendor_revision = le16_to_cpu(p->vendor_revision); + memcpy(onfi->vendor, p->vendor, sizeof(p->vendor)); + chip->parameters.onfi = onfi; + + /* Identification done, free the full ONFI parameter page and exit */ + kfree(p); + + return 1; + +free_model: + kfree(chip->parameters.model); free_onfi_param_page: kfree(p); + return ret; } @@ -5321,8 +5373,11 @@ static int nand_flash_detect_jedec(struct nand_chip *chip) sanitize_string(p->manufacturer, sizeof(p->manufacturer)); sanitize_string(p->model, sizeof(p->model)); - strncpy(chip->parameters.model, p->model, - sizeof(chip->parameters.model) - 1); + chip->parameters.model = kstrdup(p->model, GFP_KERNEL); + if (!chip->parameters.model) { + ret = -ENOMEM; + goto free_jedec_param_page; + } mtd->writesize = le32_to_cpu(p->byte_per_page); @@ -5511,8 +5566,9 @@ static bool find_full_id_nand(struct nand_chip *chip, chip->onfi_timing_mode_default = type->onfi_timing_mode_default; - strncpy(chip->parameters.model, type->name, - sizeof(chip->parameters.model) - 1); + chip->parameters.model = kstrdup(type->name, GFP_KERNEL); + if (!chip->parameters.model) + return false; return true; } @@ -5651,7 +5707,6 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) } } - chip->parameters.onfi.version = 0; if (!type->name || !type->pagesize) { /* Check if the chip is ONFI compliant */ ret = nand_flash_detect_onfi(chip); @@ -5671,8 +5726,9 @@ static int nand_detect(struct nand_chip *chip, struct nand_flash_dev *type) if (!type->name) return -ENODEV; - strncpy(chip->parameters.model, type->name, - sizeof(chip->parameters.model) - 1); + chip->parameters.model = kstrdup(type->name, GFP_KERNEL); + if (!chip->parameters.model) + return -ENOMEM; chip->chipsize = (uint64_t)type->chipsize << 20; @@ -5702,7 +5758,9 @@ ident_done: mtd->name); pr_warn("bus width %d instead of %d bits\n", busw ? 16 : 8, (chip->options & NAND_BUSWIDTH_16) ? 16 : 8); - return -EINVAL; + ret = -EINVAL; + + goto free_detect_allocation; } nand_decode_bbm_options(chip); @@ -5739,6 +5797,11 @@ ident_done: (int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC", mtd->erasesize >> 10, mtd->writesize, mtd->oobsize); return 0; + +free_detect_allocation: + kfree(chip->parameters.model); + + return ret; } static const char * const nand_ecc_modes[] = { @@ -5777,6 +5840,7 @@ static int of_get_nand_ecc_mode(struct device_node *np) static const char * const nand_ecc_algos[] = { [NAND_ECC_HAMMING] = "hamming", [NAND_ECC_BCH] = "bch", + [NAND_ECC_RS] = "rs", }; static int of_get_nand_ecc_algo(struct device_node *np) @@ -5858,6 +5922,9 @@ static int nand_dt_init(struct nand_chip *chip) if (of_get_nand_bus_width(dn) == 16) chip->options |= NAND_BUSWIDTH_16; + if (of_property_read_bool(dn, "nand-is-boot-medium")) + chip->options |= NAND_IS_BOOT_MEDIUM; + if (of_get_nand_on_flash_bbt(dn)) chip->bbt_options |= NAND_BBT_USE_FLASH; @@ -5885,7 +5952,7 @@ static int nand_dt_init(struct nand_chip *chip) } /** - * nand_scan_ident - [NAND Interface] Scan for the NAND device + * nand_scan_ident - Scan for the NAND device * @mtd: MTD device structure * @maxchips: number of chips to scan for * @table: alternative NAND ID table @@ -5893,9 +5960,13 @@ static int nand_dt_init(struct nand_chip *chip) * This is the first phase of the normal nand_scan() function. It reads the * flash ID and sets up MTD fields accordingly. * + * This helper used to be called directly from controller drivers that needed + * to tweak some ECC-related parameters before nand_scan_tail(). This separation + * prevented dynamic allocations during this phase which was unconvenient and + * as been banned for the benefit of the ->init_ecc()/cleanup_ecc() hooks. */ -int nand_scan_ident(struct mtd_info *mtd, int maxchips, - struct nand_flash_dev *table) +static int nand_scan_ident(struct mtd_info *mtd, int maxchips, + struct nand_flash_dev *table) { int i, nand_maf_id, nand_dev_id; struct nand_chip *chip = mtd_to_nand(mtd); @@ -5969,7 +6040,12 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips, return 0; } -EXPORT_SYMBOL(nand_scan_ident); + +static void nand_scan_ident_cleanup(struct nand_chip *chip) +{ + kfree(chip->parameters.model); + kfree(chip->parameters.onfi); +} static int nand_set_ecc_soft_ops(struct mtd_info *mtd) { @@ -6077,24 +6153,17 @@ static int nand_set_ecc_soft_ops(struct mtd_info *mtd) * by the controller and the calculated ECC bytes fit within the chip's OOB. * On success, the calculated ECC bytes is set. */ -int nand_check_ecc_caps(struct nand_chip *chip, - const struct nand_ecc_caps *caps, int oobavail) +static int +nand_check_ecc_caps(struct nand_chip *chip, + const struct nand_ecc_caps *caps, int oobavail) { struct mtd_info *mtd = nand_to_mtd(chip); const struct nand_ecc_step_info *stepinfo; int preset_step = chip->ecc.size; int preset_strength = chip->ecc.strength; - int nsteps, ecc_bytes; + int ecc_bytes, nsteps = mtd->writesize / preset_step; int i, j; - if (WARN_ON(oobavail < 0)) - return -EINVAL; - - if (!preset_step || !preset_strength) - return -ENODATA; - - nsteps = mtd->writesize / preset_step; - for (i = 0; i < caps->nstepinfos; i++) { stepinfo = &caps->stepinfos[i]; @@ -6127,7 +6196,6 @@ int nand_check_ecc_caps(struct nand_chip *chip, return -ENOTSUPP; } -EXPORT_SYMBOL_GPL(nand_check_ecc_caps); /** * nand_match_ecc_req - meet the chip's requirement with least ECC bytes @@ -6139,8 +6207,9 @@ EXPORT_SYMBOL_GPL(nand_check_ecc_caps); * number of ECC bytes (i.e. with the largest number of OOB-free bytes). * On success, the chosen ECC settings are set. */ -int nand_match_ecc_req(struct nand_chip *chip, - const struct nand_ecc_caps *caps, int oobavail) +static int +nand_match_ecc_req(struct nand_chip *chip, + const struct nand_ecc_caps *caps, int oobavail) { struct mtd_info *mtd = nand_to_mtd(chip); const struct nand_ecc_step_info *stepinfo; @@ -6151,9 +6220,6 @@ int nand_match_ecc_req(struct nand_chip *chip, int best_ecc_bytes_total = INT_MAX; int i, j; - if (WARN_ON(oobavail < 0)) - return -EINVAL; - /* No information provided by the NAND chip */ if (!req_step || !req_strength) return -ENOTSUPP; @@ -6212,7 +6278,6 @@ int nand_match_ecc_req(struct nand_chip *chip, return 0; } -EXPORT_SYMBOL_GPL(nand_match_ecc_req); /** * nand_maximize_ecc - choose the max ECC strength available @@ -6223,8 +6288,9 @@ EXPORT_SYMBOL_GPL(nand_match_ecc_req); * Choose the max ECC strength that is supported on the controller, and can fit * within the chip's OOB. On success, the chosen ECC settings are set. */ -int nand_maximize_ecc(struct nand_chip *chip, - const struct nand_ecc_caps *caps, int oobavail) +static int +nand_maximize_ecc(struct nand_chip *chip, + const struct nand_ecc_caps *caps, int oobavail) { struct mtd_info *mtd = nand_to_mtd(chip); const struct nand_ecc_step_info *stepinfo; @@ -6234,9 +6300,6 @@ int nand_maximize_ecc(struct nand_chip *chip, int best_strength, best_ecc_bytes; int i, j; - if (WARN_ON(oobavail < 0)) - return -EINVAL; - for (i = 0; i < caps->nstepinfos; i++) { stepinfo = &caps->stepinfos[i]; step_size = stepinfo->stepsize; @@ -6285,7 +6348,44 @@ int nand_maximize_ecc(struct nand_chip *chip, return 0; } -EXPORT_SYMBOL_GPL(nand_maximize_ecc); + +/** + * nand_ecc_choose_conf - Set the ECC strength and ECC step size + * @chip: nand chip info structure + * @caps: ECC engine caps info structure + * @oobavail: OOB size that the ECC engine can use + * + * Choose the ECC configuration according to following logic + * + * 1. If both ECC step size and ECC strength are already set (usually by DT) + * then check if it is supported by this controller. + * 2. If NAND_ECC_MAXIMIZE is set, then select maximum ECC strength. + * 3. Otherwise, try to match the ECC step size and ECC strength closest + * to the chip's requirement. If available OOB size can't fit the chip + * requirement then fallback to the maximum ECC step size and ECC strength. + * + * On success, the chosen ECC settings are set. + */ +int nand_ecc_choose_conf(struct nand_chip *chip, + const struct nand_ecc_caps *caps, int oobavail) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + + if (WARN_ON(oobavail < 0 || oobavail > mtd->oobsize)) + return -EINVAL; + + if (chip->ecc.size && chip->ecc.strength) + return nand_check_ecc_caps(chip, caps, oobavail); + + if (chip->ecc.options & NAND_ECC_MAXIMIZE) + return nand_maximize_ecc(chip, caps, oobavail); + + if (!nand_match_ecc_req(chip, caps, oobavail)) + return 0; + + return nand_maximize_ecc(chip, caps, oobavail); +} +EXPORT_SYMBOL_GPL(nand_ecc_choose_conf); /* * Check if the chip configuration meet the datasheet requirements. @@ -6322,14 +6422,14 @@ static bool nand_ecc_strength_good(struct mtd_info *mtd) } /** - * nand_scan_tail - [NAND Interface] Scan for the NAND device + * nand_scan_tail - Scan for the NAND device * @mtd: MTD device structure * * This is the second phase of the normal nand_scan() function. It fills out * all the uninitialized function pointers with the defaults and scans for a * bad block table if appropriate. */ -int nand_scan_tail(struct mtd_info *mtd) +static int nand_scan_tail(struct mtd_info *mtd) { struct nand_chip *chip = mtd_to_nand(mtd); struct nand_ecc_ctrl *ecc = &chip->ecc; @@ -6636,7 +6736,7 @@ int nand_scan_tail(struct mtd_info *mtd) return 0; /* Build bad block table */ - ret = chip->scan_bbt(mtd); + ret = nand_create_bbt(chip); if (ret) goto err_nand_manuf_cleanup; @@ -6653,24 +6753,27 @@ err_free_buf: return ret; } -EXPORT_SYMBOL(nand_scan_tail); -/* - * is_module_text_address() isn't exported, and it's mostly a pointless - * test if this is a module _anyway_ -- they'd have to try _really_ hard - * to call us from in-kernel code if the core NAND support is modular. - */ -#ifdef MODULE -#define caller_is_module() (1) -#else -#define caller_is_module() \ - is_module_text_address((unsigned long)__builtin_return_address(0)) -#endif +static int nand_attach(struct nand_chip *chip) +{ + if (chip->controller->ops && chip->controller->ops->attach_chip) + return chip->controller->ops->attach_chip(chip); + + return 0; +} + +static void nand_detach(struct nand_chip *chip) +{ + if (chip->controller->ops && chip->controller->ops->detach_chip) + chip->controller->ops->detach_chip(chip); +} /** * nand_scan_with_ids - [NAND Interface] Scan for the NAND device * @mtd: MTD device structure - * @maxchips: number of chips to scan for + * @maxchips: number of chips to scan for. @nand_scan_ident() will not be run if + * this parameter is zero (useful for specific drivers that must + * handle this part of the process themselves, e.g docg4). * @ids: optional flash IDs table * * This fills out all the uninitialized function pointers with the defaults. @@ -6680,11 +6783,30 @@ EXPORT_SYMBOL(nand_scan_tail); int nand_scan_with_ids(struct mtd_info *mtd, int maxchips, struct nand_flash_dev *ids) { + struct nand_chip *chip = mtd_to_nand(mtd); int ret; - ret = nand_scan_ident(mtd, maxchips, ids); - if (!ret) - ret = nand_scan_tail(mtd); + if (maxchips) { + ret = nand_scan_ident(mtd, maxchips, ids); + if (ret) + return ret; + } + + ret = nand_attach(chip); + if (ret) + goto cleanup_ident; + + ret = nand_scan_tail(mtd); + if (ret) + goto detach_chip; + + return 0; + +detach_chip: + nand_detach(chip); +cleanup_ident: + nand_scan_ident_cleanup(chip); + return ret; } EXPORT_SYMBOL(nand_scan_with_ids); @@ -6712,7 +6834,14 @@ void nand_cleanup(struct nand_chip *chip) /* Free manufacturer priv data. */ nand_manufacturer_cleanup(chip); + + /* Free controller specific allocations after chip identification */ + nand_detach(chip); + + /* Free identification phase allocations */ + nand_scan_ident_cleanup(chip); } + EXPORT_SYMBOL_GPL(nand_cleanup); /** |