diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/base/driver.c | 6 | ||||
-rw-r--r-- | drivers/mtd/core.c | 213 | ||||
-rw-r--r-- | drivers/mtd/nand/nand-bb.c | 16 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_base.c | 15 | ||||
-rw-r--r-- | drivers/mtd/nand/nand_imx.c | 39 | ||||
-rw-r--r-- | drivers/mtd/partition.c | 14 | ||||
-rw-r--r-- | drivers/net/cpsw.c | 1 | ||||
-rw-r--r-- | drivers/net/rtl8169.c | 4 | ||||
-rw-r--r-- | drivers/of/base.c | 4 | ||||
-rw-r--r-- | drivers/of/of_path.c | 4 |
10 files changed, 267 insertions, 49 deletions
diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 81b35031a1..3363b56675 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c @@ -350,12 +350,6 @@ void __iomem *dev_request_mem_region(struct device_d *dev, int num) } EXPORT_SYMBOL(dev_request_mem_region); -int dev_protect(struct device_d *dev, size_t count, unsigned long offset, int prot) -{ - printf("%s: currently broken\n", __func__); - return -EINVAL; -} - int generic_memmap_ro(struct cdev *cdev, void **map, int flags) { if (!cdev->dev) diff --git a/drivers/mtd/core.c b/drivers/mtd/core.c index 345752ecfe..63b1e4a824 100644 --- a/drivers/mtd/core.c +++ b/drivers/mtd/core.c @@ -18,6 +18,7 @@ #include <common.h> #include <linux/mtd/nand.h> #include <linux/mtd/mtd.h> +#include <cmdlinepart.h> #include <init.h> #include <xfuncs.h> #include <driver.h> @@ -377,9 +378,174 @@ static struct file_operations mtd_ops = { .lseek = dev_lseek_default, }; +static int mtd_partition_set(struct device_d *dev, struct param_d *p, const char *val) +{ + struct mtd_info *mtd = container_of(dev, struct mtd_info, class_dev); + struct mtd_info *mtdpart, *tmp; + int ret; + + list_for_each_entry_safe(mtdpart, tmp, &mtd->partitions, partitions_entry) { + ret = mtd_del_partition(mtdpart); + if (ret) + return ret; + } + + return cmdlinepart_do_parse(mtd->cdev.name, val, mtd->size, CMDLINEPART_ADD_DEVNAME); +} + +static char *print_size(uint64_t s) +{ + if (!(s & ((1 << 20) - 1))) + return asprintf("%lldM", s >> 20); + if (!(s & ((1 << 10) - 1))) + return asprintf("%lldk", s >> 10); + return asprintf("0x%lld", s); +} + +static int print_part(char *buf, int bufsize, struct mtd_info *mtd, uint64_t last_ofs, + int is_last) +{ + char *size = print_size(mtd->size); + char *ofs = print_size(mtd->master_offset); + int ret; + + if (!size || !ofs) { + ret = -ENOMEM; + goto out; + } + + if (mtd->master_offset == last_ofs) + ret = snprintf(buf, bufsize, "%s(%s)%s", size, + mtd->cdev.partname, + is_last ? "" : ","); + else + ret = snprintf(buf, bufsize, "%s@%s(%s)%s", size, + ofs, + mtd->cdev.partname, + is_last ? "" : ","); +out: + free(size); + free(ofs); + + return ret; +} + +static int print_parts(char *buf, int bufsize, struct mtd_info *mtd) +{ + struct mtd_info *mtdpart; + uint64_t last_ofs = 0; + int ret = 0; + + list_for_each_entry(mtdpart, &mtd->partitions, partitions_entry) { + int now; + int is_last = list_is_last(&mtdpart->partitions_entry, + &mtd->partitions); + + now = print_part(buf, bufsize, mtdpart, last_ofs, is_last); + if (now < 0) + return now; + + if (buf && bufsize) { + buf += now; + bufsize -= now; + } + ret += now; + last_ofs = mtdpart->master_offset + mtdpart->size; + } + + return ret; +} + +static const char *mtd_partition_get(struct device_d *dev, struct param_d *p) +{ + struct mtd_info *mtd = container_of(dev, struct mtd_info, class_dev); + int len = 0; + + free(p->value); + + len = print_parts(NULL, 0, mtd); + p->value = xzalloc(len + 1); + print_parts(p->value, len + 1, mtd); + + return p->value; +} + +static int mtd_part_compare(struct list_head *a, struct list_head *b) +{ + struct mtd_info *mtda = container_of(a, struct mtd_info, partitions_entry); + struct mtd_info *mtdb = container_of(b, struct mtd_info, partitions_entry); + + if (mtda->master_offset > mtdb->master_offset) + return 1; + if (mtda->master_offset < mtdb->master_offset) + return -1; + return 0; +} + +static int of_mtd_fixup(struct device_node *root, void *ctx) +{ + struct mtd_info *mtd = ctx, *partmtd; + struct device_node *np, *part, *tmp; + int ret, i = 0; + + np = of_find_node_by_path(mtd->of_path); + if (!np) { + dev_err(&mtd->class_dev, "Cannot find nodepath %s, cannot fixup\n", + mtd->of_path); + return -EINVAL; + } + + for_each_child_of_node_safe(np, tmp, part) { + if (of_get_property(part, "compatible", NULL)) + continue; + of_delete_node(part); + } + + list_for_each_entry(partmtd, &mtd->partitions, partitions_entry) { + int na, ns, len = 0; + char *name = asprintf("partition@%d", i++); + void *p; + u8 tmp[16 * 16]; /* Up to 64-bit address + 64-bit size */ + + if (!name) + return -ENOMEM; + + part = of_new_node(np, name); + free(name); + if (!part) + return -ENOMEM; + + p = of_new_property(part, "label", partmtd->cdev.partname, + strlen(partmtd->cdev.partname) + 1); + if (!p) + return -ENOMEM; + + na = of_n_addr_cells(np); + ns = of_n_size_cells(np); + + of_write_number(tmp + len, partmtd->master_offset, na); + len += na * 4; + of_write_number(tmp + len, partmtd->size, ns); + len += ns * 4; + + ret = of_set_property(part, "reg", tmp, len, 1); + if (ret) + return ret; + + if (partmtd->cdev.flags & DEVFS_PARTITION_READONLY) { + ret = of_set_property(part, "read-only", NULL, 0, 1); + if (ret) + return ret; + } + } + + return 0; +} + int add_mtd_device(struct mtd_info *mtd, char *devname, int device_id) { struct mtddev_hook *hook; + int ret; if (!devname) devname = "mtd"; @@ -387,7 +553,10 @@ int add_mtd_device(struct mtd_info *mtd, char *devname, int device_id) mtd->class_dev.id = device_id; if (mtd->parent) mtd->class_dev.parent = mtd->parent; - register_device(&mtd->class_dev); + + ret = register_device(&mtd->class_dev); + if (ret) + return ret; mtd->cdev.ops = &mtd_ops; mtd->cdev.size = mtd->size; @@ -396,6 +565,8 @@ int add_mtd_device(struct mtd_info *mtd, char *devname, int device_id) else mtd->cdev.name = asprintf("%s%d", devname, mtd->class_dev.id); + INIT_LIST_HEAD(&mtd->partitions); + mtd->cdev.priv = mtd; mtd->cdev.dev = &mtd->class_dev; mtd->cdev.mtd = mtd; @@ -407,19 +578,50 @@ int add_mtd_device(struct mtd_info *mtd, char *devname, int device_id) dev_add_param_int_ro(&mtd->class_dev, "oobsize", mtd->oobsize, "%u"); } - devfs_create(&mtd->cdev); + ret = devfs_create(&mtd->cdev); + if (ret) + goto err; + + if (mtd->master && !(mtd->cdev.flags & DEVFS_PARTITION_FIXED)) { + struct mtd_info *mtdpart; + + list_for_each_entry(mtdpart, &mtd->master->partitions, partitions_entry) { + if (mtdpart->master_offset + mtdpart->size <= mtd->master_offset) + continue; + if (mtd->master_offset + mtd->size <= mtdpart->master_offset) + continue; + dev_err(&mtd->class_dev, "New partition %s conflicts with %s\n", + mtd->name, mtdpart->name); + goto err1; + } + + list_add_sort(&mtd->partitions_entry, &mtd->master->partitions, mtd_part_compare); + } if (mtd_can_have_bb(mtd)) mtd->cdev_bb = mtd_add_bb(mtd, NULL); - if (mtd->parent && !mtd->master) + if (mtd->parent && !mtd->master) { + dev_add_param(&mtd->class_dev, "partitions", mtd_partition_set, mtd_partition_get, 0); of_parse_partitions(&mtd->cdev, mtd->parent->device_node); + if (IS_ENABLED(CONFIG_OFDEVICE) && mtd->parent->device_node) { + mtd->of_path = xstrdup(mtd->parent->device_node->full_name); + of_register_fixup(of_mtd_fixup, mtd); + } + } list_for_each_entry(hook, &mtd_register_hooks, hook) if (hook->add_mtd_device) hook->add_mtd_device(mtd, devname, &hook->priv); return 0; +err1: + devfs_remove(&mtd->cdev); +err: + free(mtd->cdev.name); + unregister_device(&mtd->class_dev); + + return ret; } int del_mtd_device (struct mtd_info *mtd) @@ -431,9 +633,14 @@ int del_mtd_device (struct mtd_info *mtd) hook->del_mtd_device(mtd, &hook->priv); devfs_remove(&mtd->cdev); + if (mtd->cdev_bb) + mtd_del_bb(mtd); unregister_device(&mtd->class_dev); free(mtd->param_size.value); free(mtd->cdev.name); + if (mtd->master) + list_del(&mtd->partitions_entry); + return 0; } diff --git a/drivers/mtd/nand/nand-bb.c b/drivers/mtd/nand/nand-bb.c index 23957c358e..539c685482 100644 --- a/drivers/mtd/nand/nand-bb.c +++ b/drivers/mtd/nand/nand-bb.c @@ -307,6 +307,17 @@ err: return ERR_PTR(ret); } +void mtd_del_bb(struct mtd_info *mtd) +{ + struct cdev *cdev = mtd->cdev_bb; + struct nand_bb *bb = container_of(cdev, struct nand_bb, cdev); + + devfs_remove(&bb->cdev); + list_del_init(&bb->list); + free(bb->name); + free(bb); +} + /** * Add a bad block aware device ontop of another (NAND) device * @param[in] dev The device to add a partition on @@ -335,10 +346,7 @@ int dev_remove_bb_dev(const char *name) list_for_each_entry_safe(bb, tmp, &bb_list, list) { if (!strcmp(bb->cdev.name, name)) { - devfs_remove(&bb->cdev); - list_del_init(&bb->list); - free(bb->name); - free(bb); + mtd_del_bb(bb->mtd); return 0; } } diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c index 54d8ba34ff..2b3f9a9942 100644 --- a/drivers/mtd/nand/nand_base.c +++ b/drivers/mtd/nand/nand_base.c @@ -2768,14 +2768,9 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, int *busw) { struct nand_onfi_params *p = &chip->onfi_params; - int i; + int i, j; int val; - /* ONFI need to be probed in 8 bits mode, and 16 bits should be selected with NAND_BUSWIDTH_AUTO */ - if (chip->options & NAND_BUSWIDTH_16) { - pr_err("Trying ONFI probe in 16 bits mode, aborting !\n"); - return 0; - } /* Try ONFI for unknown chip or LP */ chip->cmdfunc(mtd, NAND_CMD_READID, 0x20, -1); if (chip->read_byte(mtd) != 'O' || chip->read_byte(mtd) != 'N' || @@ -2784,16 +2779,18 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip, chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1); for (i = 0; i < 3; i++) { - chip->read_buf(mtd, (uint8_t *)p, sizeof(*p)); + for (j = 0; j < sizeof(*p); j++) + ((uint8_t *)p)[j] = chip->read_byte(mtd); if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) == le16_to_cpu(p->crc)) { - pr_info("ONFI param page %d valid\n", i); break; } } - if (i == 3) + if (i == 3) { + pr_err("Could not find valid ONFI parameter page; aborting\n"); return 0; + } /* Check version */ val = le16_to_cpu(p->revision); diff --git a/drivers/mtd/nand/nand_imx.c b/drivers/mtd/nand/nand_imx.c index e2aaa153eb..00c05d00af 100644 --- a/drivers/mtd/nand/nand_imx.c +++ b/drivers/mtd/nand/nand_imx.c @@ -362,7 +362,11 @@ static void send_read_id_v3(struct imx_nand_host *host) wait_op_done(host); - memcpy(host->data_buf, host->main_area0, 16); + /* + * NFC_ID results in reading 6 bytes or words (depending on data width), + * so copying 3 32-bit values is just fine. + */ + memcpy(host->data_buf, host->main_area0, 12); } static void send_read_param_v3(struct imx_nand_host *host) @@ -377,8 +381,6 @@ static void send_read_param_v3(struct imx_nand_host *host) static void send_read_id_v1_v2(struct imx_nand_host *host) { - struct nand_chip *this = &host->nand; - /* NANDFC buffer 0 is used for device ID output */ writew(0x0, host->regs + NFC_V1_V2_BUF_ADDR); @@ -387,20 +389,11 @@ static void send_read_id_v1_v2(struct imx_nand_host *host) /* Wait for operation to complete */ wait_op_done(host); - if (this->options & NAND_BUSWIDTH_16) { - volatile u16 *mainbuf = host->main_area0; - - /* - * Pack the every-other-byte result for 16-bit ID reads - * into every-byte as the generic code expects and various - * chips implement. - */ - - mainbuf[0] = (mainbuf[0] & 0xff) | ((mainbuf[1] & 0xff) << 8); - mainbuf[1] = (mainbuf[2] & 0xff) | ((mainbuf[3] & 0xff) << 8); - mainbuf[2] = (mainbuf[4] & 0xff) | ((mainbuf[5] & 0xff) << 8); - } - memcpy32(host->data_buf, host->main_area0, 16); + /* + * NFC_ID results in reading 6 bytes or words (depending on data width), + * so copying 3 32-bit values is just fine. + */ + memcpy32(host->data_buf, host->main_area0, 12); } static void send_read_param_v1_v2(struct imx_nand_host *host) @@ -572,8 +565,16 @@ static u_char imx_nand_read_byte(struct mtd_info *mtd) if (host->status_request) return host->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 */ + BUG_ON(host->buf_start & 1); + 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++; + } return ret; } diff --git a/drivers/mtd/partition.c b/drivers/mtd/partition.c index e393fa68f8..98b90819bd 100644 --- a/drivers/mtd/partition.c +++ b/drivers/mtd/partition.c @@ -108,6 +108,7 @@ struct mtd_info *mtd_add_partition(struct mtd_info *mtd, off_t offset, uint64_t size, unsigned long flags, const char *name) { struct mtd_info *part; + int ret; part = xzalloc(sizeof(*part)); @@ -122,6 +123,7 @@ struct mtd_info *mtd_add_partition(struct mtd_info *mtd, off_t offset, part->ecclayout = mtd->ecclayout; part->ecc_strength = mtd->ecc_strength; part->subpage_sft = mtd->subpage_sft; + part->cdev.flags = flags; if (mtd->numeraseregions > 1) { /* Deal with variable erase size stuff */ @@ -160,7 +162,7 @@ struct mtd_info *mtd_add_partition(struct mtd_info *mtd, off_t offset, part->block_isbad = mtd->block_isbad ? mtd_part_block_isbad : NULL; part->size = size; - part->name = strdup(name); + part->name = xstrdup(name); part->master_offset = offset; part->master = mtd; @@ -168,9 +170,17 @@ struct mtd_info *mtd_add_partition(struct mtd_info *mtd, off_t offset, if (!strncmp(mtd->cdev.name, name, strlen(mtd->cdev.name))) part->cdev.partname = xstrdup(name + strlen(mtd->cdev.name) + 1); - add_mtd_device(part, part->name, DEVICE_ID_SINGLE); + ret = add_mtd_device(part, part->name, DEVICE_ID_SINGLE); + if (ret) + goto err; return part; +err: + free(part->cdev.partname); + free(part->name); + free(part); + + return ERR_PTR(ret); } int mtd_del_partition(struct mtd_info *part) diff --git a/drivers/net/cpsw.c b/drivers/net/cpsw.c index 799fac89a2..301b8a9dfd 100644 --- a/drivers/net/cpsw.c +++ b/drivers/net/cpsw.c @@ -888,6 +888,7 @@ static int cpsw_recv(struct eth_device *edev) while (cpdma_process(priv, &priv->rx_chan, &buffer, &len) >= 0) { dma_inv_range((ulong)buffer, (ulong)buffer + len); net_receive(edev, buffer, len); + dma_inv_range((ulong)buffer, (ulong)buffer + len); cpdma_submit(priv, &priv->rx_chan, buffer, PKTSIZE); } diff --git a/drivers/net/rtl8169.c b/drivers/net/rtl8169.c index 19f5763c87..f8a6500a0f 100644 --- a/drivers/net/rtl8169.c +++ b/drivers/net/rtl8169.c @@ -236,8 +236,8 @@ static void rtl8169_init_ring(struct rtl8169_priv *priv) dma_clean_range((unsigned long)priv->rx_buf, (unsigned long)priv->rx_buf + NUM_RX_DESC * PKT_BUF_SIZE); - memset(priv->tx_desc, 0, NUM_TX_DESC * sizeof(struct bufdesc)); - memset(priv->rx_desc, 0, NUM_RX_DESC * sizeof(struct bufdesc)); + memset((void *)priv->tx_desc, 0, NUM_TX_DESC * sizeof(struct bufdesc)); + memset((void *)priv->rx_desc, 0, NUM_RX_DESC * sizeof(struct bufdesc)); for (i = 0; i < NUM_RX_DESC; i++) { if (i == (NUM_RX_DESC - 1)) diff --git a/drivers/of/base.c b/drivers/of/base.c index af10fd1da3..d45d3941b8 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -184,7 +184,7 @@ void of_alias_scan(void) end--; len = end - start; - id = simple_strtol(end, 0, 10); + id = simple_strtol(end, NULL, 10); if (id < 0) continue; @@ -280,7 +280,7 @@ struct device_node *of_find_node_by_phandle_from(phandle phandle, root = root_node; if (!root) - return 0; + return NULL; of_tree_for_each_node_from(node, root) if (node->phandle == phandle) diff --git a/drivers/of/of_path.c b/drivers/of/of_path.c index f0fd917ada..df63c5782a 100644 --- a/drivers/of/of_path.c +++ b/drivers/of/of_path.c @@ -132,9 +132,9 @@ int of_find_path(struct device_node *node, const char *propname, char **outpath) struct of_path op = {}; struct device_node *rnode; const char *path, *str; - int i, len, ret; + int i, ret; - path = of_get_property(node, propname, &len); + path = of_get_property(node, propname, NULL); if (!path) return -EINVAL; |