mirror of
https://github.com/armbian/linux-cix.git
synced 2026-01-06 12:30:45 -08:00
Merge tag 'mtd/for-6.1' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux
Pull MTD updates from Miquel Raynal:
"Core MTD changes:
- mtdchar: add MEMREAD ioctl
- Add ECC error accounting for each read request
- always initialize 'stats' in struct mtd_oob_ops
- Track maximum number of bitflips for each read request
- Fix repeated word in comment
- Move from strlcpy with unused retval to strscpy
- Fix a typo in a comment
- Add binding for U-Boot bootloader partitions
MTD device drivers changes:
- FTL: use container_of() rather than cast
- docg3:
- Use correct function names in comment blocks
- Check the return value of devm_ioremap() in the probe
- physmap-core: Fix NULL pointer dereferencing in
of_select_probe_type()
- parsers: add Broadcom's U-Boot parser
Raw NAND core changes:
- Replace of_gpio_named_count() by gpiod_count()
- Remove misguided comment of nand_get_device()
- bbt: Use the bitmap API to allocate bitmaps
Raw NAND controller drivers changes:
- Meson:
- Stop supporting legacy clocks
- Refine resource getting in probe
- Convert bindings to yaml
- Fix clock handling and update the bindings accordingly
- Fix bit map use in meson_nfc_ecc_correct()
- bcm47xx:
- Fix spelling typo in comment
- STM32 FMC2:
- Switch to using devm_fwnode_gpiod_get()
- Fix dma_map_sg error check
- Cadence:
- Remove an unneeded result variable
- Marvell:
- Fix error handle regarding dma_map_sg
- Orion:
- Use devm_clk_get_optional()
- Cafe:
- Use correct function name in comment block
- Atmel:
- Unmap streaming DMA mappings
- Arasan:
- Stop using 0 as NULL pointer
- GPMI:
- Fix typo 'the the' in comment
- BRCM:
- Add individual glue driver selection
- Move Kconfig to driver folder
- FSL: Fix none ECC mode
- Intel:
- Use devm_platform_ioremap_resource_byname()
- Remove unused clk_rate member from struct ebu_nand
- Remove unused nand_pa member from ebu_nand_cs
- Don't re-define NAND_DATA_IFACE_CHECK_ONLY
- Remove undocumented compatible string
- Fix compatible string in the bindings
- Read the chip-select line from the correct OF node
- Fix maximum chip select value in the bindings"
* tag 'mtd/for-6.1' of git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux: (43 commits)
mtd: rawnand: meson: stop supporting legacy clocks
dt-bindings: nand: meson: convert txt to yaml
mtd: rawnand: meson: refine resource getting in probe
mtd: rawnand: meson: fix the clock
dt-bindings: nand: meson: fix meson nfc clock
mtd: rawnand: bcm47xx: fix spelling typo in comment
mtd: rawnand: stm32_fmc2: switch to using devm_fwnode_gpiod_get()
mtd: rawnand: cadence: Remove an unneeded result variable
mtd: rawnand: Replace of_gpio_named_count() by gpiod_count()
mtd: rawnand: marvell: Fix error handle regarding dma_map_sg
mtd: rawnand: stm32_fmc2: Fix dma_map_sg error check
mtd: rawnand: remove misguided comment of nand_get_device()
mtd: rawnand: orion: Use devm_clk_get_optional()
mtd: rawnand: cafe: Use correct function name in comment block
mtd: rawnand: atmel: Unmap streaming DMA mappings
mtd: rawnand: meson: fix bit map use in meson_nfc_ecc_correct()
mtd: rawnand: arasan: stop using 0 as NULL pointer
mtd: rawnand: gpmi: Fix typo 'the the' in comment
mtd: rawnand: brcmnand: Add individual glue driver selection
mtd: rawnand: brcmnand: Move Kconfig to driver folder
...
This commit is contained in:
@@ -1,60 +0,0 @@
|
||||
Amlogic NAND Flash Controller (NFC) for GXBB/GXL/AXG family SoCs
|
||||
|
||||
This file documents the properties in addition to those available in
|
||||
the MTD NAND bindings.
|
||||
|
||||
Required properties:
|
||||
- compatible : contains one of:
|
||||
- "amlogic,meson-gxl-nfc"
|
||||
- "amlogic,meson-axg-nfc"
|
||||
- clocks :
|
||||
A list of phandle + clock-specifier pairs for the clocks listed
|
||||
in clock-names.
|
||||
|
||||
- clock-names: Should contain the following:
|
||||
"core" - NFC module gate clock
|
||||
"device" - device clock from eMMC sub clock controller
|
||||
"rx" - rx clock phase
|
||||
"tx" - tx clock phase
|
||||
|
||||
- amlogic,mmc-syscon : Required for NAND clocks, it's shared with SD/eMMC
|
||||
controller port C
|
||||
|
||||
Optional children nodes:
|
||||
Children nodes represent the available nand chips.
|
||||
|
||||
Other properties:
|
||||
see Documentation/devicetree/bindings/mtd/nand-controller.yaml for generic bindings.
|
||||
|
||||
Example demonstrate on AXG SoC:
|
||||
|
||||
sd_emmc_c_clkc: mmc@7000 {
|
||||
compatible = "amlogic,meson-axg-mmc-clkc", "syscon";
|
||||
reg = <0x0 0x7000 0x0 0x800>;
|
||||
};
|
||||
|
||||
nand-controller@7800 {
|
||||
compatible = "amlogic,meson-axg-nfc";
|
||||
reg = <0x0 0x7800 0x0 0x100>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
interrupts = <GIC_SPI 34 IRQ_TYPE_EDGE_RISING>;
|
||||
|
||||
clocks = <&clkc CLKID_SD_EMMC_C>,
|
||||
<&sd_emmc_c_clkc CLKID_MMC_DIV>,
|
||||
<&sd_emmc_c_clkc CLKID_MMC_PHASE_RX>,
|
||||
<&sd_emmc_c_clkc CLKID_MMC_PHASE_TX>;
|
||||
clock-names = "core", "device", "rx", "tx";
|
||||
amlogic,mmc-syscon = <&sd_emmc_c_clkc>;
|
||||
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&nand_pins>;
|
||||
|
||||
nand@0 {
|
||||
reg = <0>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
nand-on-flash-bbt;
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,93 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mtd/amlogic,meson-nand.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Amlogic NAND Flash Controller (NFC) for GXBB/GXL/AXG family SoCs
|
||||
|
||||
allOf:
|
||||
- $ref: nand-controller.yaml
|
||||
|
||||
maintainers:
|
||||
- liang.yang@amlogic.com
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- amlogic,meson-gxl-nfc
|
||||
- amlogic,meson-axg-nfc
|
||||
|
||||
reg:
|
||||
maxItems: 2
|
||||
|
||||
reg-names:
|
||||
items:
|
||||
- const: nfc
|
||||
- const: emmc
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
minItems: 2
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: core
|
||||
- const: device
|
||||
|
||||
patternProperties:
|
||||
"^nand@[0-7]$":
|
||||
type: object
|
||||
properties:
|
||||
reg:
|
||||
minimum: 0
|
||||
maximum: 1
|
||||
|
||||
nand-ecc-mode:
|
||||
const: hw
|
||||
|
||||
nand-ecc-step-size:
|
||||
const: 1024
|
||||
|
||||
nand-ecc-strength:
|
||||
enum: [8, 16, 24, 30, 40, 50, 60]
|
||||
description: |
|
||||
The ECC configurations that can be supported are as follows.
|
||||
meson-gxl-nfc 8, 16, 24, 30, 40, 50, 60
|
||||
meson-axg-nfc 8
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/clock/axg-clkc.h>
|
||||
#include <dt-bindings/interrupt-controller/arm-gic.h>
|
||||
nand-controller@ffe07800 {
|
||||
compatible = "amlogic,meson-axg-nfc";
|
||||
reg = <0xffe07800 0x100>, <0xffe07000 0x800>;
|
||||
reg-names = "nfc", "emmc";
|
||||
interrupts = <GIC_SPI 34 IRQ_TYPE_EDGE_RISING>;
|
||||
clocks = <&clkc CLKID_SD_EMMC_C>, <&clkc CLKID_FCLK_DIV2>;
|
||||
clock-names = "core", "device";
|
||||
|
||||
pinctrl-0 = <&nand_pins>;
|
||||
pinctrl-names = "default";
|
||||
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
nand@0 {
|
||||
reg = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
...
|
||||
@@ -1,7 +1,7 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mtd/intel,lgm-nand.yaml#
|
||||
$id: http://devicetree.org/schemas/mtd/intel,lgm-ebunand.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Intel LGM SoC NAND Controller Device Tree Bindings
|
||||
@@ -14,7 +14,7 @@ maintainers:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: intel,lgm-nand
|
||||
const: intel,lgm-ebunand
|
||||
|
||||
reg:
|
||||
maxItems: 6
|
||||
@@ -51,7 +51,7 @@ patternProperties:
|
||||
properties:
|
||||
reg:
|
||||
minimum: 0
|
||||
maximum: 7
|
||||
maximum: 1
|
||||
|
||||
nand-ecc-mode: true
|
||||
|
||||
@@ -75,7 +75,7 @@ additionalProperties: false
|
||||
examples:
|
||||
- |
|
||||
nand-controller@e0f00000 {
|
||||
compatible = "intel,lgm-nand";
|
||||
compatible = "intel,lgm-ebunand";
|
||||
reg = <0xe0f00000 0x100>,
|
||||
<0xe1000000 0x300>,
|
||||
<0xe1400000 0x8000>,
|
||||
49
Documentation/devicetree/bindings/mtd/partitions/u-boot.yaml
Normal file
49
Documentation/devicetree/bindings/mtd/partitions/u-boot.yaml
Normal file
@@ -0,0 +1,49 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/mtd/partitions/u-boot.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: U-Boot bootloader partition
|
||||
|
||||
description: |
|
||||
U-Boot is a bootlodaer commonly used in embedded devices. It's almost always
|
||||
located on some kind of flash device.
|
||||
|
||||
Device configuration is stored as a set of environment variables that are
|
||||
located in a (usually standalone) block of data.
|
||||
|
||||
maintainers:
|
||||
- Rafał Miłecki <rafal@milecki.pl>
|
||||
|
||||
allOf:
|
||||
- $ref: partition.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- const: brcm,u-boot
|
||||
description: |
|
||||
Broadcom stores environment variables inside a U-Boot partition. They
|
||||
can be identified by a custom header with magic value.
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
partitions {
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
partition@0 {
|
||||
compatible = "brcm,u-boot";
|
||||
reg = <0x0 0x100000>;
|
||||
label = "u-boot";
|
||||
};
|
||||
|
||||
partition@100000 {
|
||||
reg = <0x100000 0x1ff00000>;
|
||||
label = "firmware";
|
||||
};
|
||||
};
|
||||
@@ -461,7 +461,7 @@ static int block2mtd_setup(const char *val, const struct kernel_param *kp)
|
||||
the device (even kmalloc() fails). Deter that work to
|
||||
block2mtd_setup2(). */
|
||||
|
||||
strlcpy(block2mtd_paramline, val, sizeof(block2mtd_paramline));
|
||||
strscpy(block2mtd_paramline, val, sizeof(block2mtd_paramline));
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
|
||||
@@ -300,7 +300,7 @@ static void doc_write_data_area(struct docg3 *docg3, const void *buf, int len)
|
||||
}
|
||||
|
||||
/**
|
||||
* doc_set_data_mode - Sets the flash to normal or reliable data mode
|
||||
* doc_set_reliable_mode - Sets the flash to normal or reliable data mode
|
||||
* @docg3: the device
|
||||
*
|
||||
* The reliable data mode is a bit slower than the fast mode, but less errors
|
||||
@@ -442,7 +442,7 @@ static void doc_setup_writeaddr_sector(struct docg3 *docg3, int sector, int ofs)
|
||||
}
|
||||
|
||||
/**
|
||||
* doc_seek - Set both flash planes to the specified block, page for reading
|
||||
* doc_read_seek - Set both flash planes to the specified block, page for reading
|
||||
* @docg3: the device
|
||||
* @block0: the first plane block index
|
||||
* @block1: the second plane block index
|
||||
@@ -871,6 +871,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
|
||||
u8 *buf = ops->datbuf;
|
||||
size_t len, ooblen, nbdata, nboob;
|
||||
u8 hwecc[DOC_ECC_BCH_SIZE], eccconf1;
|
||||
struct mtd_ecc_stats old_stats;
|
||||
int max_bitflips = 0;
|
||||
|
||||
if (buf)
|
||||
@@ -895,6 +896,7 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
|
||||
ret = 0;
|
||||
skip = from % DOC_LAYOUT_PAGE_SIZE;
|
||||
mutex_lock(&docg3->cascade->lock);
|
||||
old_stats = mtd->ecc_stats;
|
||||
while (ret >= 0 && (len > 0 || ooblen > 0)) {
|
||||
calc_block_sector(from - skip, &block0, &block1, &page, &ofs,
|
||||
docg3->reliable);
|
||||
@@ -966,6 +968,12 @@ static int doc_read_oob(struct mtd_info *mtd, loff_t from,
|
||||
}
|
||||
|
||||
out:
|
||||
if (ops->stats) {
|
||||
ops->stats->uncorrectable_errors +=
|
||||
mtd->ecc_stats.failed - old_stats.failed;
|
||||
ops->stats->corrected_bitflips +=
|
||||
mtd->ecc_stats.corrected - old_stats.corrected;
|
||||
}
|
||||
mutex_unlock(&docg3->cascade->lock);
|
||||
return ret;
|
||||
err_in_read:
|
||||
@@ -1951,7 +1959,7 @@ static int docg3_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
}
|
||||
|
||||
/**
|
||||
* doc_probe - Probe the IO space for a DiskOnChip G3 chip
|
||||
* docg3_probe - Probe the IO space for a DiskOnChip G3 chip
|
||||
* @pdev: platform device
|
||||
*
|
||||
* Probes for a G3 chip at the specified IO space in the platform data
|
||||
@@ -1974,9 +1982,14 @@ static int __init docg3_probe(struct platform_device *pdev)
|
||||
dev_err(dev, "No I/O memory resource defined\n");
|
||||
return ret;
|
||||
}
|
||||
base = devm_ioremap(dev, ress->start, DOC_IOSPACE_SIZE);
|
||||
|
||||
ret = -ENOMEM;
|
||||
base = devm_ioremap(dev, ress->start, DOC_IOSPACE_SIZE);
|
||||
if (!base) {
|
||||
dev_err(dev, "devm_ioremap dev failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
cascade = devm_kcalloc(dev, DOC_MAX_NBFLOORS, sizeof(*cascade),
|
||||
GFP_KERNEL);
|
||||
if (!cascade)
|
||||
|
||||
@@ -941,7 +941,7 @@ static int ftl_write(partition_t *part, caddr_t buffer,
|
||||
|
||||
static int ftl_getgeo(struct mtd_blktrans_dev *dev, struct hd_geometry *geo)
|
||||
{
|
||||
partition_t *part = (void *)dev;
|
||||
partition_t *part = container_of(dev, struct partition_t, mbd);
|
||||
u_long sect;
|
||||
|
||||
/* Sort of arbitrary: round size down to 4KiB boundary */
|
||||
@@ -969,7 +969,7 @@ static int ftl_writesect(struct mtd_blktrans_dev *dev,
|
||||
static int ftl_discardsect(struct mtd_blktrans_dev *dev,
|
||||
unsigned long sector, unsigned nr_sects)
|
||||
{
|
||||
partition_t *part = (void *)dev;
|
||||
partition_t *part = container_of(dev, struct partition_t, mbd);
|
||||
uint32_t bsize = 1 << part->header.EraseUnitSize;
|
||||
|
||||
pr_debug("FTL erase sector %ld for %d sectors\n",
|
||||
|
||||
@@ -136,7 +136,7 @@ static void inftl_remove_dev(struct mtd_blktrans_dev *dev)
|
||||
int inftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,
|
||||
size_t *retlen, uint8_t *buf)
|
||||
{
|
||||
struct mtd_oob_ops ops;
|
||||
struct mtd_oob_ops ops = { };
|
||||
int res;
|
||||
|
||||
ops.mode = MTD_OPS_PLACE_OOB;
|
||||
@@ -156,7 +156,7 @@ int inftl_read_oob(struct mtd_info *mtd, loff_t offs, size_t len,
|
||||
int inftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,
|
||||
size_t *retlen, uint8_t *buf)
|
||||
{
|
||||
struct mtd_oob_ops ops;
|
||||
struct mtd_oob_ops ops = { };
|
||||
int res;
|
||||
|
||||
ops.mode = MTD_OPS_PLACE_OOB;
|
||||
@@ -176,7 +176,7 @@ int inftl_write_oob(struct mtd_info *mtd, loff_t offs, size_t len,
|
||||
static int inftl_write(struct mtd_info *mtd, loff_t offs, size_t len,
|
||||
size_t *retlen, uint8_t *buf, uint8_t *oob)
|
||||
{
|
||||
struct mtd_oob_ops ops;
|
||||
struct mtd_oob_ops ops = { };
|
||||
int res;
|
||||
|
||||
ops.mode = MTD_OPS_PLACE_OOB;
|
||||
|
||||
@@ -300,6 +300,9 @@ static const char *of_select_probe_type(struct platform_device *dev)
|
||||
const char *probe_type;
|
||||
|
||||
match = of_match_device(of_flash_match, &dev->dev);
|
||||
if (!match)
|
||||
return NULL;
|
||||
|
||||
probe_type = match->data;
|
||||
if (probe_type)
|
||||
return probe_type;
|
||||
|
||||
@@ -688,6 +688,137 @@ static int mtdchar_write_ioctl(struct mtd_info *mtd,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mtdchar_read_ioctl(struct mtd_info *mtd,
|
||||
struct mtd_read_req __user *argp)
|
||||
{
|
||||
struct mtd_info *master = mtd_get_master(mtd);
|
||||
struct mtd_read_req req;
|
||||
void __user *usr_data, *usr_oob;
|
||||
uint8_t *datbuf = NULL, *oobbuf = NULL;
|
||||
size_t datbuf_len, oobbuf_len;
|
||||
size_t orig_len, orig_ooblen;
|
||||
int ret = 0;
|
||||
|
||||
if (copy_from_user(&req, argp, sizeof(req)))
|
||||
return -EFAULT;
|
||||
|
||||
orig_len = req.len;
|
||||
orig_ooblen = req.ooblen;
|
||||
|
||||
usr_data = (void __user *)(uintptr_t)req.usr_data;
|
||||
usr_oob = (void __user *)(uintptr_t)req.usr_oob;
|
||||
|
||||
if (!master->_read_oob)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!usr_data)
|
||||
req.len = 0;
|
||||
|
||||
if (!usr_oob)
|
||||
req.ooblen = 0;
|
||||
|
||||
req.ecc_stats.uncorrectable_errors = 0;
|
||||
req.ecc_stats.corrected_bitflips = 0;
|
||||
req.ecc_stats.max_bitflips = 0;
|
||||
|
||||
req.len &= 0xffffffff;
|
||||
req.ooblen &= 0xffffffff;
|
||||
|
||||
if (req.start + req.len > mtd->size) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
datbuf_len = min_t(size_t, req.len, mtd->erasesize);
|
||||
if (datbuf_len > 0) {
|
||||
datbuf = kvmalloc(datbuf_len, GFP_KERNEL);
|
||||
if (!datbuf) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
oobbuf_len = min_t(size_t, req.ooblen, mtd->erasesize);
|
||||
if (oobbuf_len > 0) {
|
||||
oobbuf = kvmalloc(oobbuf_len, GFP_KERNEL);
|
||||
if (!oobbuf) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
while (req.len > 0 || (!usr_data && req.ooblen > 0)) {
|
||||
struct mtd_req_stats stats;
|
||||
struct mtd_oob_ops ops = {
|
||||
.mode = req.mode,
|
||||
.len = min_t(size_t, req.len, datbuf_len),
|
||||
.ooblen = min_t(size_t, req.ooblen, oobbuf_len),
|
||||
.datbuf = datbuf,
|
||||
.oobbuf = oobbuf,
|
||||
.stats = &stats,
|
||||
};
|
||||
|
||||
/*
|
||||
* Shorten non-page-aligned, eraseblock-sized reads so that the
|
||||
* read ends on an eraseblock boundary. This is necessary in
|
||||
* order to prevent OOB data for some pages from being
|
||||
* duplicated in the output of non-page-aligned reads requiring
|
||||
* multiple mtd_read_oob() calls to be completed.
|
||||
*/
|
||||
if (ops.len == mtd->erasesize)
|
||||
ops.len -= mtd_mod_by_ws(req.start + ops.len, mtd);
|
||||
|
||||
ret = mtd_read_oob(mtd, (loff_t)req.start, &ops);
|
||||
|
||||
req.ecc_stats.uncorrectable_errors +=
|
||||
stats.uncorrectable_errors;
|
||||
req.ecc_stats.corrected_bitflips += stats.corrected_bitflips;
|
||||
req.ecc_stats.max_bitflips =
|
||||
max(req.ecc_stats.max_bitflips, stats.max_bitflips);
|
||||
|
||||
if (ret && !mtd_is_bitflip_or_eccerr(ret))
|
||||
break;
|
||||
|
||||
if (copy_to_user(usr_data, ops.datbuf, ops.retlen) ||
|
||||
copy_to_user(usr_oob, ops.oobbuf, ops.oobretlen)) {
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
req.start += ops.retlen;
|
||||
req.len -= ops.retlen;
|
||||
usr_data += ops.retlen;
|
||||
|
||||
req.ooblen -= ops.oobretlen;
|
||||
usr_oob += ops.oobretlen;
|
||||
}
|
||||
|
||||
/*
|
||||
* As multiple iterations of the above loop (and therefore multiple
|
||||
* mtd_read_oob() calls) may be necessary to complete the read request,
|
||||
* adjust the final return code to ensure it accounts for all detected
|
||||
* ECC errors.
|
||||
*/
|
||||
if (!ret || mtd_is_bitflip(ret)) {
|
||||
if (req.ecc_stats.uncorrectable_errors > 0)
|
||||
ret = -EBADMSG;
|
||||
else if (req.ecc_stats.corrected_bitflips > 0)
|
||||
ret = -EUCLEAN;
|
||||
}
|
||||
|
||||
out:
|
||||
req.len = orig_len - req.len;
|
||||
req.ooblen = orig_ooblen - req.ooblen;
|
||||
|
||||
if (copy_to_user(argp, &req, sizeof(req)))
|
||||
ret = -EFAULT;
|
||||
|
||||
kvfree(datbuf);
|
||||
kvfree(oobbuf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
|
||||
{
|
||||
struct mtd_file_info *mfi = file->private_data;
|
||||
@@ -710,6 +841,7 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
|
||||
case MEMGETINFO:
|
||||
case MEMREADOOB:
|
||||
case MEMREADOOB64:
|
||||
case MEMREAD:
|
||||
case MEMISLOCKED:
|
||||
case MEMGETOOBSEL:
|
||||
case MEMGETBADBLOCK:
|
||||
@@ -884,6 +1016,13 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
|
||||
break;
|
||||
}
|
||||
|
||||
case MEMREAD:
|
||||
{
|
||||
ret = mtdchar_read_ioctl(mtd,
|
||||
(struct mtd_read_req __user *)arg);
|
||||
break;
|
||||
}
|
||||
|
||||
case MEMLOCK:
|
||||
{
|
||||
struct erase_info_user einfo;
|
||||
|
||||
@@ -836,7 +836,7 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
|
||||
|
||||
/*
|
||||
* walk the map of the new device once more and fill in
|
||||
* in erase region info:
|
||||
* erase region info:
|
||||
*/
|
||||
curr_erasesize = subdev[0]->erasesize;
|
||||
begin = position = 0;
|
||||
|
||||
@@ -1624,6 +1624,9 @@ int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
|
||||
if (!master->_read_oob && (!master->_read || ops->oobbuf))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (ops->stats)
|
||||
memset(ops->stats, 0, sizeof(*ops->stats));
|
||||
|
||||
if (mtd->flags & MTD_SLC_ON_MLC_EMULATION)
|
||||
ret_code = mtd_io_emulated_slc(mtd, from, true, ops);
|
||||
else
|
||||
@@ -1641,6 +1644,8 @@ int mtd_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
|
||||
return ret_code;
|
||||
if (mtd->ecc_strength == 0)
|
||||
return 0; /* device lacks ecc */
|
||||
if (ops->stats)
|
||||
ops->stats->max_bitflips = ret_code;
|
||||
return ret_code >= mtd->bitflip_threshold ? -EUCLEAN : 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtd_read_oob);
|
||||
|
||||
@@ -401,7 +401,7 @@ static void mtdpstore_notify_add(struct mtd_info *mtd)
|
||||
/*
|
||||
* kmsg_size must be aligned to 4096 Bytes, which is limited by
|
||||
* psblk. The default value of kmsg_size is 64KB. If kmsg_size
|
||||
* is larger than erasesize, some errors will occur since mtdpsotre
|
||||
* is larger than erasesize, some errors will occur since mtdpstore
|
||||
* is designed on it.
|
||||
*/
|
||||
if (mtd->erasesize < info->kmsg_size) {
|
||||
|
||||
@@ -323,7 +323,7 @@ static int mtdswap_read_markers(struct mtdswap_dev *d, struct swap_eb *eb)
|
||||
struct mtdswap_oobdata *data, *data2;
|
||||
int ret;
|
||||
loff_t offset;
|
||||
struct mtd_oob_ops ops;
|
||||
struct mtd_oob_ops ops = { };
|
||||
|
||||
offset = mtdswap_eb_offset(d, eb);
|
||||
|
||||
@@ -370,7 +370,7 @@ static int mtdswap_write_marker(struct mtdswap_dev *d, struct swap_eb *eb,
|
||||
struct mtdswap_oobdata n;
|
||||
int ret;
|
||||
loff_t offset;
|
||||
struct mtd_oob_ops ops;
|
||||
struct mtd_oob_ops ops = { };
|
||||
|
||||
ops.ooboffs = 0;
|
||||
ops.oobbuf = (uint8_t *)&n;
|
||||
@@ -878,7 +878,7 @@ static unsigned int mtdswap_eblk_passes(struct mtdswap_dev *d,
|
||||
loff_t base, pos;
|
||||
unsigned int *p1 = (unsigned int *)d->page_buf;
|
||||
unsigned char *p2 = (unsigned char *)d->oob_buf;
|
||||
struct mtd_oob_ops ops;
|
||||
struct mtd_oob_ops ops = { };
|
||||
int ret;
|
||||
|
||||
ops.mode = MTD_OPS_AUTO_OOB;
|
||||
|
||||
@@ -24,11 +24,8 @@ int nanddev_bbt_init(struct nand_device *nand)
|
||||
{
|
||||
unsigned int bits_per_block = fls(NAND_BBT_BLOCK_NUM_STATUS);
|
||||
unsigned int nblocks = nanddev_neraseblocks(nand);
|
||||
unsigned int nwords = DIV_ROUND_UP(nblocks * bits_per_block,
|
||||
BITS_PER_LONG);
|
||||
|
||||
nand->bbt.cache = kcalloc(nwords, sizeof(*nand->bbt.cache),
|
||||
GFP_KERNEL);
|
||||
nand->bbt.cache = bitmap_zalloc(nblocks * bits_per_block, GFP_KERNEL);
|
||||
if (!nand->bbt.cache)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -44,7 +41,7 @@ EXPORT_SYMBOL_GPL(nanddev_bbt_init);
|
||||
*/
|
||||
void nanddev_bbt_cleanup(struct nand_device *nand)
|
||||
{
|
||||
kfree(nand->bbt.cache);
|
||||
bitmap_free(nand->bbt.cache);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nanddev_bbt_cleanup);
|
||||
|
||||
|
||||
@@ -1440,6 +1440,7 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from,
|
||||
struct mtd_oob_ops *ops)
|
||||
{
|
||||
struct onenand_chip *this = mtd->priv;
|
||||
struct mtd_ecc_stats old_stats;
|
||||
int ret;
|
||||
|
||||
switch (ops->mode) {
|
||||
@@ -1453,12 +1454,23 @@ static int onenand_read_oob(struct mtd_info *mtd, loff_t from,
|
||||
}
|
||||
|
||||
onenand_get_device(mtd, FL_READING);
|
||||
|
||||
old_stats = mtd->ecc_stats;
|
||||
|
||||
if (ops->datbuf)
|
||||
ret = ONENAND_IS_4KB_PAGE(this) ?
|
||||
onenand_mlc_read_ops_nolock(mtd, from, ops) :
|
||||
onenand_read_ops_nolock(mtd, from, ops);
|
||||
else
|
||||
ret = onenand_read_oob_nolock(mtd, from, ops);
|
||||
|
||||
if (ops->stats) {
|
||||
ops->stats->uncorrectable_errors +=
|
||||
mtd->ecc_stats.failed - old_stats.failed;
|
||||
ops->stats->corrected_bitflips +=
|
||||
mtd->ecc_stats.corrected - old_stats.corrected;
|
||||
}
|
||||
|
||||
onenand_release_device(mtd);
|
||||
|
||||
return ret;
|
||||
@@ -2935,7 +2947,7 @@ static int do_otp_write(struct mtd_info *mtd, loff_t to, size_t len,
|
||||
struct onenand_chip *this = mtd->priv;
|
||||
unsigned char *pbuf = buf;
|
||||
int ret;
|
||||
struct mtd_oob_ops ops;
|
||||
struct mtd_oob_ops ops = { };
|
||||
|
||||
/* Force buffer page aligned */
|
||||
if (len < mtd->writesize) {
|
||||
@@ -2977,7 +2989,7 @@ static int do_otp_lock(struct mtd_info *mtd, loff_t from, size_t len,
|
||||
size_t *retlen, u_char *buf)
|
||||
{
|
||||
struct onenand_chip *this = mtd->priv;
|
||||
struct mtd_oob_ops ops;
|
||||
struct mtd_oob_ops ops = { };
|
||||
int ret;
|
||||
|
||||
if (FLEXONENAND(this)) {
|
||||
|
||||
@@ -61,7 +61,7 @@ static int create_bbt(struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr
|
||||
int startblock;
|
||||
loff_t from;
|
||||
size_t readlen;
|
||||
struct mtd_oob_ops ops;
|
||||
struct mtd_oob_ops ops = { };
|
||||
int rgn;
|
||||
|
||||
printk(KERN_INFO "Scanning device for bad blocks\n");
|
||||
|
||||
@@ -200,27 +200,7 @@ config MTD_NAND_TMIO
|
||||
Support for NAND flash connected to a Toshiba Mobile IO
|
||||
Controller in some PDAs, including the Sharp SL6000x.
|
||||
|
||||
config MTD_NAND_BRCMNAND
|
||||
tristate "Broadcom STB NAND controller"
|
||||
depends on ARM || ARM64 || MIPS || COMPILE_TEST
|
||||
depends on HAS_IOMEM
|
||||
help
|
||||
Enables the Broadcom NAND controller driver. The controller was
|
||||
originally designed for Set-Top Box but is used on various BCM7xxx,
|
||||
BCM3xxx, BCM63xxx, iProc/Cygnus and more.
|
||||
|
||||
if MTD_NAND_BRCMNAND
|
||||
|
||||
config MTD_NAND_BRCMNAND_BCMA
|
||||
tristate "Broadcom BCMA NAND controller"
|
||||
depends on BCMA_NFLASH
|
||||
depends on BCMA
|
||||
help
|
||||
Enables the BRCMNAND controller over BCMA on BCM47186/BCM5358 SoCs.
|
||||
The glue driver will take care of performing the low-level I/O
|
||||
operations to interface the BRCMNAND controller over the BCMA bus.
|
||||
|
||||
endif # MTD_NAND_BRCMNAND
|
||||
source "drivers/mtd/nand/raw/brcmnand/Kconfig"
|
||||
|
||||
config MTD_NAND_BCM47XXNFLASH
|
||||
tristate "BCM4706 BCMA NAND controller"
|
||||
@@ -410,7 +390,7 @@ config MTD_NAND_STM32_FMC2
|
||||
|
||||
config MTD_NAND_MESON
|
||||
tristate "Support for NAND controller on Amlogic's Meson SoCs"
|
||||
depends on ARCH_MESON || COMPILE_TEST
|
||||
depends on COMMON_CLK && (ARCH_MESON || COMPILE_TEST)
|
||||
select MFD_SYSCON
|
||||
help
|
||||
Enables support for NAND controller on Amlogic's Meson SoCs.
|
||||
|
||||
@@ -915,7 +915,7 @@ static int anfc_check_op(struct nand_chip *chip,
|
||||
if (instr->ctx.data.len > ANFC_MAX_CHUNK_SIZE)
|
||||
return -ENOTSUPP;
|
||||
|
||||
if (anfc_pkt_len_config(instr->ctx.data.len, 0, 0))
|
||||
if (anfc_pkt_len_config(instr->ctx.data.len, NULL, NULL))
|
||||
return -ENOTSUPP;
|
||||
|
||||
break;
|
||||
|
||||
@@ -405,6 +405,7 @@ static int atmel_nand_dma_transfer(struct atmel_nand_controller *nc,
|
||||
|
||||
dma_async_issue_pending(nc->dmac);
|
||||
wait_for_completion(&finished);
|
||||
dma_unmap_single(nc->dev, buf_dma, len, dir);
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user