diff options
author | Edward A. James <eajames@us.ibm.com> | 2017-05-20 00:09:36 +0300 |
---|---|---|
committer | Patrick Williams <patrick@stwcx.xyz> | 2017-05-24 08:06:26 +0300 |
commit | fb92f38f80699b2089c3467b1344ac107f797d3c (patch) | |
tree | 1c9914728d61d635babb2bcd084caa2c377b6f99 /drivers | |
parent | 15c30d4deb0a01f398230395dc0d9af4be92d856 (diff) | |
download | linux-fb92f38f80699b2089c3467b1344ac107f797d3c.tar.xz |
drivers: fsi: Fix SBE/OCC for 2 socket properly.
Also update dts.
Signed-off-by: Edward A. James <eajames@us.ibm.com>
Signed-off-by: Patrick Williams <patrick@stwcx.xyz>
Reviewed-by: Christopher Bostic <cbostic@linux.vnet.ibm.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/fsi/Makefile | 2 | ||||
-rw-r--r-- | drivers/fsi/fsi-sbefifo.c | 83 | ||||
-rw-r--r-- | drivers/fsi/occ.c (renamed from drivers/fsi/occfifo.c) | 379 |
3 files changed, 242 insertions, 222 deletions
diff --git a/drivers/fsi/Makefile b/drivers/fsi/Makefile index eddaf79604b3..eb2dd12bcc3c 100644 --- a/drivers/fsi/Makefile +++ b/drivers/fsi/Makefile @@ -2,6 +2,6 @@ obj-$(CONFIG_FSI) += fsi-core.o obj-$(CONFIG_FSI_MASTER_GPIO) += fsi-master-gpio.o obj-$(CONFIG_FSI_SBEFIFO) += fsi-sbefifo.o -obj-$(CONFIG_OCCFIFO) += occfifo.o +obj-$(CONFIG_OCCFIFO) += occ.o obj-$(CONFIG_FSI_SCOM) += fsi-scom.o obj-$(CONFIG_FSI_I2C) += i2c/ diff --git a/drivers/fsi/fsi-sbefifo.c b/drivers/fsi/fsi-sbefifo.c index b395cb6d87ee..d43e0638981d 100644 --- a/drivers/fsi/fsi-sbefifo.c +++ b/drivers/fsi/fsi-sbefifo.c @@ -20,6 +20,7 @@ #include <linux/miscdevice.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_platform.h> #include <linux/poll.h> #include <linux/sched.h> #include <linux/slab.h> @@ -51,7 +52,6 @@ struct sbefifo { wait_queue_head_t wait; struct list_head link; struct list_head xfrs; - struct list_head drv_refs; struct kref kref; struct device_node *node; spinlock_t lock; @@ -723,34 +723,21 @@ static const struct file_operations sbefifo_fops = { .release = sbefifo_release, }; -struct sbefifo *sbefifo_drv_reference(struct device_node *node, - struct sbefifo_drv_ref *ref) +struct sbefifo_client *sbefifo_drv_open(struct device *dev, + unsigned long flags) { + struct sbefifo_client *client = NULL; struct sbefifo *sbefifo; + struct fsi_device *fsi_dev = to_fsi_dev(dev); list_for_each_entry(sbefifo, &sbefifo_fifos, link) { - if (node == sbefifo->node) { - if (ref) - list_add(&ref->link, &sbefifo->drv_refs); - return sbefifo; - } - } - - return NULL; -} -EXPORT_SYMBOL_GPL(sbefifo_drv_reference); - -struct sbefifo_client *sbefifo_drv_open(struct sbefifo *sbefifo, - unsigned long flags) -{ - struct sbefifo_client *client; - - if (!sbefifo) - return NULL; + if (sbefifo->fsi_dev != fsi_dev) + continue; - client = sbefifo_new_client(sbefifo); - if (client) - client->f_flags = flags; + client = sbefifo_new_client(sbefifo); + if (client) + client->f_flags = flags; + } return client; } @@ -778,18 +765,26 @@ void sbefifo_drv_release(struct sbefifo_client *client) } EXPORT_SYMBOL_GPL(sbefifo_drv_release); -int sbefifo_drv_get_idx(struct sbefifo *sbefifo) +static int sbefifo_unregister_child(struct device *dev, void *data) { - return sbefifo->idx; + struct platform_device *child = to_platform_device(dev); + + of_device_unregister(child); + if (dev->of_node) + of_node_clear_flag(dev->of_node, OF_POPULATED); + + return 0; } static int sbefifo_probe(struct device *dev) { struct fsi_device *fsi_dev = to_fsi_dev(dev); - struct sbefifo *sbefifo; + struct sbefifo *sbefifo, *check; struct device_node *np; + struct platform_device *child; + char child_name[32]; u32 sts, addr; - int ret; + int ret, child_idx = 0; dev_info(dev, "Found sbefifo device\n"); sbefifo = kzalloc(sizeof(*sbefifo), GFP_KERNEL); @@ -829,7 +824,6 @@ static int sbefifo_probe(struct device *dev) sbefifo->idx); init_waitqueue_head(&sbefifo->wait); INIT_LIST_HEAD(&sbefifo->xfrs); - INIT_LIST_HEAD(&sbefifo->drv_refs); for_each_compatible_node(np, NULL, "ibm,power9-sbefifo") { ret = of_property_read_u32(np, "reg", &addr); @@ -839,7 +833,29 @@ static int sbefifo_probe(struct device *dev) /* TODO: get real address, not cfam offset */ if (addr == fsi_dev->addr) { sbefifo->node = np; - break; + + /* make sure we haven't found this one already */ + list_for_each_entry(check, &sbefifo_fifos, link) { + if (check->node == np) { + sbefifo->node = NULL; + break; + } + } + + if (sbefifo->node) + break; + } + } + + if (sbefifo->node) { + /* create platform devs for dts child nodes (occ, etc) */ + for_each_child_of_node(sbefifo->node, np) { + snprintf(child_name, sizeof(child_name), "%s-dev%d", + sbefifo->name, child_idx++); + child = of_platform_device_create(np, child_name, dev); + if (!child) + dev_warn(&sbefifo->fsi_dev->dev, + "failed to create child node dev\n"); } } @@ -855,18 +871,13 @@ static int sbefifo_remove(struct device *dev) { struct fsi_device *fsi_dev = to_fsi_dev(dev); struct sbefifo *sbefifo, *sbefifo_tmp; - struct sbefifo_drv_ref *ref, *ref_tmp; struct sbefifo_xfr *xfr; list_for_each_entry_safe(sbefifo, sbefifo_tmp, &sbefifo_fifos, link) { if (sbefifo->fsi_dev != fsi_dev) continue; - list_for_each_entry_safe(ref, ref_tmp, &sbefifo->drv_refs, - link) { - ref->notify(ref); - list_del(&ref->link); - } + device_for_each_child(dev, NULL, sbefifo_unregister_child); misc_deregister(&sbefifo->mdev); list_del(&sbefifo->link); diff --git a/drivers/fsi/occfifo.c b/drivers/fsi/occ.c index c1a3351e7f1f..37242b31d417 100644 --- a/drivers/fsi/occfifo.c +++ b/drivers/fsi/occ.c @@ -16,6 +16,7 @@ #include <linux/miscdevice.h> #include <linux/module.h> #include <linux/of.h> +#include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/uaccess.h> @@ -26,10 +27,10 @@ #define OCC_CMD_DATA_BYTES 4090 #define OCC_RESP_DATA_BYTES 4089 -struct occfifo { - struct sbefifo_drv_ref ref; - struct sbefifo *sbefifo; +struct occ { + struct device *sbefifo; char name[32]; + int idx; struct miscdevice mdev; struct list_head xfrs; spinlock_t list_lock; @@ -37,7 +38,7 @@ struct occfifo { struct work_struct work; }; -#define to_occfifo(x) container_of((x), struct occfifo, mdev) +#define to_occ(x) container_of((x), struct occ, mdev) struct occ_command { u8 seq_no; @@ -45,7 +46,7 @@ struct occ_command { u16 data_length; u8 data[OCC_CMD_DATA_BYTES]; u16 checksum; -}; +} __packed; struct occ_response { u8 seq_no; @@ -54,17 +55,17 @@ struct occ_response { u16 data_length; u8 data[OCC_RESP_DATA_BYTES]; u16 checksum; -}; +} __packed; -struct occfifo_xfr; +struct occ_xfr; enum { CLIENT_NONBLOCKING, }; -struct occfifo_client { - struct occfifo *occfifo; - struct occfifo_xfr *xfr; +struct occ_client { + struct occ *occ; + struct occ_xfr *xfr; spinlock_t lock; wait_queue_head_t wait; size_t read_offset; @@ -78,9 +79,9 @@ enum { XFR_WAITING, }; -struct occfifo_xfr { +struct occ_xfr { struct list_head link; - struct occfifo_client *client; + struct occ_client *client; int rc; u8 buf[OCC_SRAM_BYTES]; size_t cmd_data_length; @@ -88,33 +89,35 @@ struct occfifo_xfr { unsigned long flags; }; -static struct workqueue_struct *occfifo_wq; +static struct workqueue_struct *occ_wq; -static void occfifo_enqueue_xfr(struct occfifo_xfr *xfr) +static DEFINE_IDA(occ_ida); + +static void occ_enqueue_xfr(struct occ_xfr *xfr) { int empty; - struct occfifo *occfifo = xfr->client->occfifo; + struct occ *occ = xfr->client->occ; - spin_lock_irq(&occfifo->list_lock); - empty = list_empty(&occfifo->xfrs); - list_add_tail(&xfr->link, &occfifo->xfrs); - spin_unlock(&occfifo->list_lock); + spin_lock_irq(&occ->list_lock); + empty = list_empty(&occ->xfrs); + list_add_tail(&xfr->link, &occ->xfrs); + spin_unlock(&occ->list_lock); if (empty) - queue_work(occfifo_wq, &occfifo->work); + queue_work(occ_wq, &occ->work); } -static int occfifo_open(struct inode *inode, struct file *file) +static int occ_open(struct inode *inode, struct file *file) { - struct occfifo_client *client; + struct occ_client *client; struct miscdevice *mdev = file->private_data; - struct occfifo *occfifo = to_occfifo(mdev); + struct occ *occ = to_occ(mdev); client = kzalloc(sizeof(*client), GFP_KERNEL); if (!client) return -ENOMEM; - client->occfifo = occfifo; + client->occ = occ; spin_lock_init(&client->lock); init_waitqueue_head(&client->wait); @@ -126,13 +129,13 @@ static int occfifo_open(struct inode *inode, struct file *file) return 0; } -static ssize_t occfifo_read(struct file *file, char __user *buf, size_t len, - loff_t *offset) +static ssize_t occ_read(struct file *file, char __user *buf, size_t len, + loff_t *offset) { int rc; size_t bytes; - struct occfifo_xfr *xfr; - struct occfifo_client *client = file->private_data; + struct occ_xfr *xfr; + struct occ_client *client = file->private_data; if (!access_ok(VERIFY_WRITE, buf, len)) return -EFAULT; @@ -146,8 +149,7 @@ static ssize_t occfifo_read(struct file *file, char __user *buf, size_t len, if (client->read_offset) { rc = 0; client->read_offset = 0; - } - else + } else rc = -ENOMSG; goto done; @@ -188,7 +190,6 @@ static ssize_t occfifo_read(struct file *file, char __user *buf, size_t len, goto done; } - bytes = min(len, xfr->resp_data_length - client->read_offset); if (copy_to_user(buf, &xfr->buf[client->read_offset], bytes)) { rc = -EFAULT; goto done; @@ -209,17 +210,20 @@ done: return rc; } -static ssize_t occfifo_write(struct file *file, const char __user *buf, - size_t len, loff_t *offset) +static ssize_t occ_write(struct file *file, const char __user *buf, + size_t len, loff_t *offset) { int rc; - struct occfifo_xfr *xfr; - struct occfifo_client *client = file->private_data; + unsigned int i, j; + u8 tmp; + u16 data_length, checksum = 0; + struct occ_xfr *xfr; + struct occ_client *client = file->private_data; if (!access_ok(VERIFY_READ, buf, len)) return -EFAULT; - if (len > OCC_SRAM_BYTES) + if (len > (OCC_CMD_DATA_BYTES + 3) || len < 3) return -EINVAL; spin_lock_irq(&client->lock); @@ -234,18 +238,44 @@ static ssize_t occfifo_write(struct file *file, const char __user *buf, goto done; } - if (copy_from_user(xfr->buf, buf, len)) { + xfr->buf[0] = 1; + + if (copy_from_user(&xfr->buf[1], buf, len)) { kfree(xfr); rc = -EFAULT; goto done; } + data_length = (xfr->buf[2] << 8) + xfr->buf[3]; + if (data_length > OCC_CMD_DATA_BYTES) { + kfree(xfr); + rc = -EINVAL; + goto done; + } + + for (i = 0; i < data_length + 4; ++i) + checksum += xfr->buf[i]; + + xfr->buf[data_length + 4] = checksum >> 8; + xfr->buf[data_length + 5] = checksum & 0xFF; + + /* byte swap the whole buffer */ + for (i = 0; i < data_length + 6; i += 4) { + tmp = xfr->buf[i + 3]; + xfr->buf[i + 3] = xfr->buf[i]; + xfr->buf[i] = tmp; + + tmp = xfr->buf[i + 2]; + xfr->buf[i + 2] = xfr->buf[i + 1]; + xfr->buf[i + 1] = tmp; + } + xfr->client = client; - xfr->cmd_data_length = len; + xfr->cmd_data_length = data_length + 6; client->xfr = xfr; client->read_offset = 0; - occfifo_enqueue_xfr(xfr); + occ_enqueue_xfr(xfr); rc = len; @@ -254,11 +284,11 @@ done: return rc; } -static int occfifo_release(struct inode *inode, struct file *file) +static int occ_release(struct inode *inode, struct file *file) { - struct occfifo_xfr *xfr; - struct occfifo_client *client = file->private_data; - struct occfifo *occfifo = client->occfifo; + struct occ_xfr *xfr; + struct occ_client *client = file->private_data; + struct occ *occ = client->occ; spin_lock_irq(&client->lock); xfr = client->xfr; @@ -268,14 +298,14 @@ static int occfifo_release(struct inode *inode, struct file *file) return 0; } - spin_lock_irq(&occfifo->list_lock); + spin_lock_irq(&occ->list_lock); set_bit(XFR_CANCELED, &xfr->flags); if (!test_bit(XFR_IN_PROGRESS, &xfr->flags)) { /* already deleted from list if complete */ if (!test_bit(XFR_COMPLETE, &xfr->flags)) list_del(&xfr->link); - spin_unlock(&occfifo->list_lock); + spin_unlock(&occ->list_lock); if (test_bit(XFR_WAITING, &xfr->flags)) { /* blocking read; let reader clean up */ @@ -291,22 +321,22 @@ static int occfifo_release(struct inode *inode, struct file *file) } /* operation is in progress; let worker clean up*/ - spin_unlock(&occfifo->list_lock); + spin_unlock(&occ->list_lock); spin_unlock(&client->lock); return 0; } -static const struct file_operations occfifo_fops = { +static const struct file_operations occ_fops = { .owner = THIS_MODULE, - .open = occfifo_open, - .read = occfifo_read, - .write = occfifo_write, - .release = occfifo_release, + .open = occ_open, + .read = occ_read, + .write = occ_write, + .release = occ_release, }; -static int occfifo_getscom(struct sbefifo *sbefifo, u32 address, u8 *data) +static int occ_getscom(struct device *sbefifo, u32 address, u8 *data) { - int rc; + int i, rc; u32 buf[4]; struct sbefifo_client *client; const size_t len = sizeof(buf); @@ -324,7 +354,7 @@ static int occfifo_getscom(struct sbefifo *sbefifo, u32 address, u8 *data) if (rc < 0) goto done; else if (rc != len) { - rc = -EIO; + rc = -EMSGSIZE; goto done; } @@ -332,20 +362,29 @@ static int occfifo_getscom(struct sbefifo *sbefifo, u32 address, u8 *data) if (rc < 0) goto done; else if (rc != len) { - rc = -EIO; + rc = -EMSGSIZE; + goto done; + } + + /* check for good response */ + if ((buf[2] >> 16) != 0xC0DE) { + rc = -EFAULT; goto done; } rc = 0; - memcpy(data, buf, sizeof(u64)); + for (i = 0; i < 4; ++i) { + data[i] = ((u8 *)buf)[3 - i]; + data[i + 4] = ((u8 *)buf)[7 - i]; + } done: sbefifo_drv_release(client); return rc; } -static int occfifo_putscom(struct sbefifo *sbefifo, u32 address, u8 *data) +static int occ_putscom(struct device *sbefifo, u32 address, u8 *data) { int rc; u32 buf[6]; @@ -366,114 +405,93 @@ static int occfifo_putscom(struct sbefifo *sbefifo, u32 address, u8 *data) if (rc < 0) goto done; else if (rc != len) { - rc = -EIO; - goto done; - } - - rc = sbefifo_drv_read(client, (char *)buf, sizeof(u32) * 4); - if (rc < 0) { - rc = 0; - goto done; - } else if (rc != sizeof(u32) * 4) { - rc = -EIO; + rc = -EMSGSIZE; goto done; } rc = 0; + /* ignore response */ + sbefifo_drv_read(client, (char *)buf, len); + done: sbefifo_drv_release(client); return rc; } -static int occfifo_putscom_u32(struct sbefifo *sbefifo, u32 address, u32 data0, - u32 data1) +static int occ_putscom_u32(struct device *sbefifo, u32 address, u32 data0, + u32 data1) { u8 buf[8]; memcpy(buf, &data0, 4); memcpy(buf + 4, &data1, 4); - return occfifo_putscom(sbefifo, address, buf); + return occ_putscom(sbefifo, address, buf); } -static void occfifo_worker(struct work_struct *work) +static void occ_worker(struct work_struct *work) { int i, empty, canceled, waiting, rc; u16 resp_data_length; - struct occfifo *occfifo = container_of(work, struct occfifo, work); - struct sbefifo *sbefifo = occfifo->sbefifo; - struct occfifo_client *client; - struct occfifo_xfr *xfr; + struct occ *occ = container_of(work, struct occ, work); + struct device *sbefifo = occ->sbefifo; + struct occ_client *client; + struct occ_xfr *xfr; struct occ_response *resp; again: - spin_lock_irq(&occfifo->list_lock); - xfr = list_first_entry(&occfifo->xfrs, struct occfifo_xfr, link); + spin_lock_irq(&occ->list_lock); + xfr = list_first_entry(&occ->xfrs, struct occ_xfr, link); if (!xfr) { - spin_unlock(&occfifo->list_lock); + spin_unlock(&occ->list_lock); return; } set_bit(XFR_IN_PROGRESS, &xfr->flags); - spin_unlock(&occfifo->list_lock); + spin_unlock(&occ->list_lock); resp = (struct occ_response *)xfr->buf; - spin_lock_irq(&occfifo->occ_lock); - - /* set stream mode enabled */ - rc = occfifo_putscom_u32(sbefifo, 0x6D053, 0x08000000, 0); - if (rc) - goto done; - - /* set stream mode to linear */ - rc = occfifo_putscom_u32(sbefifo, 0x6D052, 0x04000000, 0); - if (rc) - goto done; + spin_lock_irq(&occ->occ_lock); /* set address reg to occ sram command buffer */ - rc = occfifo_putscom_u32(sbefifo, 0x6D050, 0xFFFBE000, 0); + rc = occ_putscom_u32(sbefifo, 0x6D050, 0xFFFBE000, 0); if (rc) goto done; /* write cmd data */ for (i = 0; i < xfr->cmd_data_length; i += 8) { - rc = occfifo_putscom(sbefifo, 0x6D055, &xfr->buf[i]); + rc = occ_putscom(sbefifo, 0x6D055, &xfr->buf[i]); if (rc) goto done; } - /* set stream mode enabled and stream mode to circular */ - rc = occfifo_putscom_u32(sbefifo, 0x6D033, 0x0C000000, 0); - if (rc) - goto done; - /* trigger attention */ - rc = occfifo_putscom_u32(sbefifo, 0x6D035, 0x20010000, 0); + rc = occ_putscom_u32(sbefifo, 0x6D035, 0x20010000, 0); if (rc) goto done; /* set address reg to occ sram response buffer */ - rc = occfifo_putscom_u32(sbefifo, 0x6D050, 0xFFFBF000, 0); + rc = occ_putscom_u32(sbefifo, 0x6D050, 0xFFFBF000, 0); if (rc) goto done; - rc = occfifo_getscom(sbefifo, 0x6D055, xfr->buf); + rc = occ_getscom(sbefifo, 0x6D055, xfr->buf); if (rc) goto done; xfr->resp_data_length += 8; - resp_data_length = be16_to_cpu(get_unaligned(&resp->data_length)); + resp_data_length = (xfr->buf[3] << 8) + xfr->buf[4]; if (resp_data_length > OCC_RESP_DATA_BYTES) { - rc = -EFAULT; + rc = -EDOM; goto done; } /* already read 3 bytes of resp data, but also need 2 bytes chksum */ for (i = 8; i < resp_data_length + 7; i += 8) { - rc = occfifo_getscom(sbefifo, 0x6D055, &xfr->buf[i]); + rc = occ_getscom(sbefifo, 0x6D055, &xfr->buf[i]); if (rc) goto done; @@ -484,7 +502,7 @@ again: xfr->resp_data_length = resp_data_length + 7; done: - spin_unlock(&occfifo->occ_lock); + spin_unlock(&occ->occ_lock); xfr->rc = rc; client = xfr->client; @@ -495,12 +513,12 @@ done: waiting = test_bit(XFR_WAITING, &xfr->flags); spin_unlock(&client->lock); - spin_lock_irq(&occfifo->list_lock); + spin_lock_irq(&occ->list_lock); clear_bit(XFR_IN_PROGRESS, &xfr->flags); list_del(&xfr->link); - empty = list_empty(&occfifo->xfrs); + empty = list_empty(&occ->xfrs); canceled = test_bit(XFR_CANCELED, &xfr->flags); - spin_unlock(&occfifo->list_lock); + spin_unlock(&occ->list_lock); if (waiting) wake_up_interruptible(&client->wait); @@ -513,78 +531,69 @@ done: goto again; } -void occfifo_notify(struct sbefifo_drv_ref *ref) +static int occ_probe(struct platform_device *pdev) { - struct occfifo *occfifo = container_of(ref, struct occfifo, ref); - - /* TODO: find better solution? this does seem to work if we lose - * the sbefifo in the middle of a transfer - */ - occfifo->sbefifo = NULL; -} - -static int occfifo_probe(struct platform_device *pdev) -{ - int rc; - struct occfifo *occfifo; - struct device_node *bus; + int rc, child_idx = 0; + u32 reg; + struct occ *occ; + struct device_node *np; + struct platform_device *child; struct device *dev = &pdev->dev; - struct device_node *node = dev->of_node; + char child_name[32]; - occfifo = devm_kzalloc(dev, sizeof(*occfifo), GFP_KERNEL); - if (!occfifo) + dev_info(dev, "Found occ device\n"); + occ = devm_kzalloc(dev, sizeof(*occ), GFP_KERNEL); + if (!occ) return -ENOMEM; - bus = of_parse_phandle(node, "bus", 0); - if (!bus) { - dev_err(dev, "failed to get dts phandle\n"); - return -ENODEV; - } - - occfifo->ref.notify = occfifo_notify; - occfifo->sbefifo = sbefifo_drv_reference(bus, &occfifo->ref); - if (!occfifo->sbefifo) { - dev_err(dev, "failed to get sbefifo reference\n"); - rc = -ENODEV; - goto done; - } - - INIT_LIST_HEAD(&occfifo->xfrs); - spin_lock_init(&occfifo->list_lock); - spin_lock_init(&occfifo->occ_lock); - INIT_WORK(&occfifo->work, occfifo_worker); - - snprintf(occfifo->name, sizeof(occfifo->name), "occfifo%d", - sbefifo_drv_get_idx(occfifo->sbefifo)); - - occfifo->mdev.fops = &occfifo_fops; - occfifo->mdev.minor = MISC_DYNAMIC_MINOR; - occfifo->mdev.name = occfifo->name; - occfifo->mdev.parent = dev; - - rc = misc_register(&occfifo->mdev); + occ->sbefifo = dev->parent; + INIT_LIST_HEAD(&occ->xfrs); + spin_lock_init(&occ->list_lock); + spin_lock_init(&occ->occ_lock); + INIT_WORK(&occ->work, occ_worker); + + if (dev->of_node) { + rc = of_property_read_u32(dev->of_node, "reg", ®); + if (!rc) { + /* make sure we don't have a duplicate from dts */ + occ->idx = ida_simple_get(&occ_ida, reg, reg + 1, + GFP_KERNEL); + if (occ->idx < 0) + occ->idx = ida_simple_get(&occ_ida, 1, INT_MAX, + GFP_KERNEL); + } else + occ->idx = ida_simple_get(&occ_ida, 1, INT_MAX, + GFP_KERNEL); + } else + occ->idx = ida_simple_get(&occ_ida, 1, INT_MAX, GFP_KERNEL); + + snprintf(occ->name, sizeof(occ->name), "occ%d", occ->idx); + occ->mdev.fops = &occ_fops; + occ->mdev.minor = MISC_DYNAMIC_MINOR; + occ->mdev.name = occ->name; + occ->mdev.parent = dev; + + rc = misc_register(&occ->mdev); if (rc) { dev_err(dev, "failed to register miscdevice\n"); - goto done; + return rc; } - platform_set_drvdata(pdev, occfifo); + platform_set_drvdata(pdev, occ); -done: - of_node_put(bus); - return rc; + return 0; } -static int occfifo_remove(struct platform_device *pdev) +static int occ_remove(struct platform_device *pdev) { - struct occfifo_xfr *xfr, *tmp; - struct occfifo *occfifo = platform_get_drvdata(pdev); - struct occfifo_client *client; + struct occ_xfr *xfr, *tmp; + struct occ *occ = platform_get_drvdata(pdev); + struct occ_client *client; - misc_deregister(&occfifo->mdev); + misc_deregister(&occ->mdev); - spin_lock_irq(&occfifo->list_lock); - list_for_each_entry_safe(xfr, tmp, &occfifo->xfrs, link) { + spin_lock_irq(&occ->list_lock); + list_for_each_entry_safe(xfr, tmp, &occ->xfrs, link) { client = xfr->client; set_bit(XFR_CANCELED, &xfr->flags); @@ -595,54 +604,54 @@ static int occfifo_remove(struct platform_device *pdev) if (test_bit(XFR_WAITING, &xfr->flags)) { wake_up_interruptible(&client->wait); spin_unlock(&client->lock); - } - else { + } else { kfree(xfr); spin_unlock(&client->lock); kfree(client); } } } - spin_unlock(&occfifo->list_lock); + spin_unlock(&occ->list_lock); + + flush_work(&occ->work); - flush_work(&occfifo->work); - list_del(&occfifo->ref.link); + ida_simple_remove(&occ_ida, occ->idx); return 0; } -static const struct of_device_id occfifo_match[] = { - { .compatible = "ibm,occfifo" }, +static const struct of_device_id occ_match[] = { + { .compatible = "ibm,p9-occ" }, { }, }; -static struct platform_driver occfifo_driver = { +static struct platform_driver occ_driver = { .driver = { - .name = "occfifo", - .of_match_table = occfifo_match, + .name = "occ", + .of_match_table = occ_match, }, - .probe = occfifo_probe, - .remove = occfifo_remove, + .probe = occ_probe, + .remove = occ_remove, }; -static int occfifo_init(void) +static int occ_init(void) { - occfifo_wq = create_singlethread_workqueue("occfifo"); - if (!occfifo_wq) + occ_wq = create_singlethread_workqueue("occ"); + if (!occ_wq) return -ENOMEM; - return platform_driver_register(&occfifo_driver); + return platform_driver_register(&occ_driver); } -static void occfifo_exit(void) +static void occ_exit(void) { - destroy_workqueue(occfifo_wq); + destroy_workqueue(occ_wq); - platform_driver_unregister(&occfifo_driver); + platform_driver_unregister(&occ_driver); } -module_init(occfifo_init); -module_exit(occfifo_exit); +module_init(occ_init); +module_exit(occ_exit); MODULE_AUTHOR("Eddie James <eajames@us.ibm.com>"); MODULE_DESCRIPTION("BMC P9 OCC driver"); |