summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/base/driver.c6
-rw-r--r--drivers/mtd/core.c213
-rw-r--r--drivers/mtd/nand/nand-bb.c16
-rw-r--r--drivers/mtd/nand/nand_base.c15
-rw-r--r--drivers/mtd/nand/nand_imx.c39
-rw-r--r--drivers/mtd/partition.c14
-rw-r--r--drivers/net/cpsw.c1
-rw-r--r--drivers/net/rtl8169.c4
-rw-r--r--drivers/of/base.c4
-rw-r--r--drivers/of/of_path.c4
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;