summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorEdward A. James <eajames@us.ibm.com>2017-05-20 00:09:36 +0300
committerPatrick Williams <patrick@stwcx.xyz>2017-05-24 08:06:26 +0300
commitfb92f38f80699b2089c3467b1344ac107f797d3c (patch)
tree1c9914728d61d635babb2bcd084caa2c377b6f99 /drivers
parent15c30d4deb0a01f398230395dc0d9af4be92d856 (diff)
downloadlinux-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/Makefile2
-rw-r--r--drivers/fsi/fsi-sbefifo.c83
-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", &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");