drivers: fsi: sbefifo: Add in-kernel API
Subsystems (3)
cover drivers: fsi: sbefifo: Add in-kernel API
From: "Edward A. James" <[email protected]>
This patchset provides an in-kernel API for the SBEFIFO driver and the first user, a driver to access the P9 OCC hardware. There are also some potential devicetree bindings for the SBEFIFO and OCC devices.
The OCC provides a read/write interface, but only performs a single, atomic, OCC "command and response" operation per write operation. The driver cannot perform multiple writes in a row without first reading back to the user the response generated for each command. I can't see a use case for doing multiple commands without fetching the response.
Any feedback, particularly on how to improve the dt bindings or how to inform the OCC client that the SBEFIFO device has gone away (via unbinding FSI, or other means), would be helpful.
Edward A. James (3):
drivers: fsi: sbefifo: Add in-kernel API
drivers: fsi: sbefifo: Add OCC driver
ARM: dts: aspeed: witherspoon: Add example sbefifo and occfifo devices
arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts | 16 + drivers/fsi/Kconfig | 10 + drivers/fsi/Makefile | 1 + drivers/fsi/fsi-sbefifo.c | 173 +++++- drivers/fsi/occfifo.c | 649 +++++++++++++++++++++++ include/linux/fsi-sbefifo.h | 41 ++ 6 files changed, 861 insertions(+), 29 deletions(-) create mode 100644 drivers/fsi/occfifo.c create mode 100644 include/linux/fsi-sbefifo.h
Signature · 1 line
1.8.3.1
PATCH 1/3 drivers: fsi: sbefifo: Add in-kernel API
From: "Edward A. James" <[email protected]>
Add exported functions to the SBEFIFO driver to open/write/read/close from within the kernel.
--- drivers/fsi/fsi-sbefifo.c | 173 ++++++++++++++++++++++++++++++++++++-------- include/linux/fsi-sbefifo.h | 41 +++++++++++ 2 files changed, 185 insertions(+), 29 deletions(-) create mode 100644 include/linux/fsi-sbefifo.h
drivers/fsi/fsi-sbefifo.c +144 -29
@@ -15,9 +15,11 @@#include <linux/errno.h> #include <linux/idr.h> #include <linux/fsi.h> +#include <linux/fsi-sbefifo.h> #include <linux/list.h> #include <linux/miscdevice.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/poll.h> #include <linux/sched.h> #include <linux/slab.h>
@@ -49,7 +51,9 @@ 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;char name[32 ];int idx;
@@ -82,6 +86,7 @@ struct sbefifo_client {struct list_head xfrs;struct sbefifo *dev;struct kref kref; +unsigned long f_flags; };static struct list_head sbefifo_fifos;
@@ -493,6 +498,7 @@ static int sbefifo_open(struct inode *inode, struct file *file)return -ENOMEM ; file->private_data = client; + client->f_flags = file->f_flags;return 0 ; }
@@ -517,24 +523,18 @@ static unsigned int sbefifo_poll(struct file *file, poll_table *wait)return mask; } -static ssize_t sbefifo_read (struct file *file,char __user *buf, -size_t len,loff_t *offset) +static ssize_t sbefifo_read_common (struct sbefifo_client *client, +char __user *ubuf,char *kbuf,size_t len) { -struct sbefifo_client *client = file->private_data;struct sbefifo *sbefifo = client->dev;struct sbefifo_xfr *xfr; -ssize_t ret =0 ;size_t n; - -WARN_ON (*offset); - -if (!access_ok (VERIFY_WRITE , buf, len)) -return -EFAULT ; +ssize_t ret =0 ;if ((len >>2 ) <<2 != len)return -EINVAL ; -if ((file->f_flags &O_NONBLOCK ) && !sbefifo_xfr_rsp_pending (client)) +if ((client->f_flags &O_NONBLOCK ) && !sbefifo_xfr_rsp_pending (client))return -EAGAIN ;sbefifo_get_client (client);
@@ -553,10 +553,14 @@ static ssize_t sbefifo_read(struct file *file, char __user *buf, n =min_t (size_t, n, len); -if (copy_to_user (buf,READ_ONCE (client->rbuf.rpos), n)) { -sbefifo_put_client (client); -return -EFAULT ; +if (ubuf) { +if (copy_to_user (ubuf,READ_ONCE (client->rbuf.rpos), n)) { +sbefifo_put_client (client); +return -EFAULT ; + } } +else +memcpy (kbuf,READ_ONCE (client->rbuf.rpos), n);if (sbefifo_buf_readnb (&client->rbuf, n)) { xfr =sbefifo_client_next_xfr (client);
@@ -579,20 +583,28 @@ static ssize_t sbefifo_read(struct file *file, char __user *buf,return n; } -static ssize_t sbefifo_write (struct file *file,const char __user *buf, +static ssize_t sbefifo_read (struct file *file,char __user *buf,size_t len,loff_t *offset) {struct sbefifo_client *client = file->private_data; -struct sbefifo *sbefifo = client->dev; -struct sbefifo_xfr *xfr; -ssize_t ret =0 ; -size_t n;WARN_ON (*offset); -if (!access_ok (VERIFY_READ , buf, len)) +if (!access_ok (VERIFY_WRITE , buf, len))return -EFAULT ; +return sbefifo_read_common (client, buf,NULL , len); +} + +static ssize_t sbefifo_write_common (struct sbefifo_client *client, +const char __user *ubuf,const char *kbuf, +size_t len) +{ +struct sbefifo *sbefifo = client->dev; +struct sbefifo_xfr *xfr; +ssize_t ret =0 ; +size_t n; +if ((len >>2 ) <<2 != len)return -EINVAL ;
@@ -604,7 +616,7 @@ static ssize_t sbefifo_write(struct file *file, const char __user *buf,spin_lock_irq (&sbefifo->lock); xfr =sbefifo_next_xfr (sbefifo); -if ((file->f_flags &O_NONBLOCK ) && xfr && n < len) { +if ((client->f_flags &O_NONBLOCK ) && xfr && n < len) {spin_unlock_irq (&sbefifo->lock);return -EAGAIN ; }
@@ -644,18 +656,26 @@ static ssize_t sbefifo_write(struct file *file, const char __user *buf, n =min_t (size_t, n, len); -if (copy_from_user (READ_ONCE (client->wbuf.wpos), buf, n)) { -set_bit (SBEFIFO_XFR_CANCEL , &xfr->flags); -sbefifo_get (sbefifo); -if (mod_timer (&sbefifo->poll_timer, jiffies)) -sbefifo_put (sbefifo); -sbefifo_put_client (client); -return -EFAULT ; +if (ubuf) { +if (copy_from_user (READ_ONCE (client->wbuf.wpos), ubuf, + n)) { +set_bit (SBEFIFO_XFR_CANCEL , &xfr->flags); +sbefifo_get (sbefifo); +if (mod_timer (&sbefifo->poll_timer, jiffies)) +sbefifo_put (sbefifo); +sbefifo_put_client (client); +return -EFAULT ; + } + + ubuf += n; + } +else { +memcpy (READ_ONCE (client->wbuf.wpos), kbuf, n); + kbuf += n; }sbefifo_buf_wrotenb (&client->wbuf, n); len -= n; - buf += n; ret += n;/*
@@ -672,6 +692,19 @@ static ssize_t sbefifo_write(struct file *file, const char __user *buf,return ret; } +static ssize_t sbefifo_write (struct file *file,const char __user *buf, +size_t len,loff_t *offset) +{ +struct sbefifo_client *client = file->private_data; + +WARN_ON (*offset); + +if (!access_ok (VERIFY_READ , buf, len)) +return -EFAULT ; + +return sbefifo_write_common (client, buf,NULL , len); +} +static int sbefifo_release (struct inode *inode,struct file *file) {struct sbefifo_client *client = file->private_data;
@@ -691,11 +724,72 @@ 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 *sbefifo; + +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 ; + + client =sbefifo_new_client (sbefifo); +if (client) + client->f_flags = flags; + +return client; +} +EXPORT_SYMBOL_GPL (sbefifo_drv_open); + +int sbefifo_drv_read (struct sbefifo_client *client,char *buf,size_t len) +{ +return sbefifo_read_common (client,NULL , buf, len); +} +EXPORT_SYMBOL_GPL (sbefifo_drv_read); + +int sbefifo_drv_write (struct sbefifo_client *client,const char *buf, +size_t len) +{ +return sbefifo_write_common (client,NULL , buf, len); +} +EXPORT_SYMBOL_GPL (sbefifo_drv_write); + +void sbefifo_drv_release (struct sbefifo_client *client) +{ +if (!client) +return ; + +sbefifo_put_client (client); +} +EXPORT_SYMBOL_GPL (sbefifo_drv_release); + +int sbefifo_drv_get_idx (struct sbefifo *sbefifo) +{ +return sbefifo->idx; +} +static int sbefifo_probe (struct device *dev) {struct fsi_device *fsi_dev =to_fsi_dev (dev);struct sbefifo *sbefifo; -u32 sts; +struct device_node *np; +u32 sts, addr;int ret;dev_info (dev,"Found sbefifo device\n" );
@@ -736,6 +830,19 @@ 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); +if (ret) +continue ; + +/* TODO: get real address, not cfam offset */ +if (addr == fsi_dev->addr) { + sbefifo->node = np; +break ; + } + }/* This bit of silicon doesn't offer any interrupts... */ setup_timer(&sbefifo->poll_timer, sbefifo_poll_timer,
@@ -749,11 +856,19 @@ 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); + } +misc_deregister (&sbefifo->mdev);list_del (&sbefifo->link);ida_simple_remove (&sbefifo_ida, sbefifo->idx);
include/linux/fsi-sbefifo.h new file +41 -0
41 lines not on this page · raw message
Signature · 1 line
1.8.3.1
PATCH 2/3 drivers: fsi: sbefifo: Add OCC driver
In reply to Eddie JamesFrom: "Edward A. James" <[email protected]>
Add a driver to control communications with the OCC on the POWER9. The driver communicates with OCC SRAM using the FSI SBEFIFO driver.
The format of the communication is a command followed by response. The sequence must be done atomically. The driver performs these operations asynchronously, such that a write operation starts the command, and a read will gather the response data.
--- drivers/fsi/Kconfig | 10 + drivers/fsi/Makefile | 1 + drivers/fsi/occfifo.c | 649 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 660 insertions(+) create mode 100644 drivers/fsi/occfifo.c
drivers/fsi/Kconfig +10 -0
@@ -24,6 +24,16 @@ config FSI_SBEFIFO ---help--- This option enables an FSI based SBEFIFO device driver. +if FSI_SBEFIFO + +config OCCFIFO + tristate "OCC SBEFIFO client device driver" + depends on FSI_SBEFIFO + ---help--- + This option enables an FSI based OCC driver using the SBEFIFO. + +endif + config FSI_SCOM tristate "SCOM FSI client device driver" depends on FSI
drivers/fsi/Makefile +1 -0
@@ -2,5 +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_FSI_SCOM) += fsi-scom.o obj-$(CONFIG_FSI_I2C) += i2c/
drivers/fsi/occfifo.c new file +649 -0
649 lines not on this page · raw message
Signature · 1 line
1.8.3.1
PATCH 3/3 ARM: dts: aspeed: witherspoon: Add example sbefifo and occfifo devices
In reply to Eddie JamesFrom: "Edward A. James" <[email protected]>
A possible implementation of the bindings for SBEFIFO device and OCC "FIFO" device. Use a phandle to reference the appropriate SBE device from the OCC entry.
--- arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
arch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts +16 -0
@@ -57,6 +57,22 @@ mux-gpios = <&gpio ASPEED_GPIO(A, 6) GPIO_ACTIVE_HIGH>; enable-gpios = <&gpio ASPEED_GPIO(D, 0) GPIO_ACTIVE_HIGH>; trans-gpios = <&gpio ASPEED_GPIO(R, 2) GPIO_ACTIVE_HIGH>; + + sbefifo1: sbefifo@2400 { + compatible = "ibm,power9-sbefifo"; + + status = "okay"; + + reg = <0x2400>; + }; + }; + + occfifo@1 { + compatible = "ibm,occfifo"; + + status = "okay"; + + bus = <&sbefifo1>; }; iio-hwmon {
Signature · 1 line
1.8.3.1
Thanks for the patch Eddie.
Quoted 14 lines · Eddie James
From: "Edward A. James" <[email protected]>
This patchset provides an in-kernel API for the SBEFIFO driver and the first user, a driver to access the P9 OCC hardware. There are also some potential devicetree bindings for the SBEFIFO and OCC devices.
The OCC provides a read/write interface, but only performs a single, atomic, OCC "command and response" operation per write operation. The driver cannot perform multiple writes in a row without first reading back to the user the response generated for each command. I can't see a use case for doing multiple commands without fetching the response.
Quoted 5 lines
Any feedback, particularly on how to improve the dt bindings or how to inform the OCC client that the SBEFIFO device has gone away (via unbinding FSI, or other means), would be helpful.
Edward A. James (3):
Since un-merged patches are needed for this to apply I think the normal thing to do would have been for you and I to co-ordinate and one of us sent the entire patchset (sbefifo + these three patches).
Lets do that when we re-submit for 4.10.
Anyone else, please don’t let this discourage you from providing cursory thoughts especially on the DT bindings.
Quoted 16 lines
drivers: fsi: sbefifo: Add in-kernel API
drivers: fsi: sbefifo: Add OCC driver
ARM: dts: aspeed: witherspoon: Add example sbefifo and occfifo devicesarch/arm/boot/dts/aspeed-bmc-opp-witherspoon.dts | 16 + drivers/fsi/Kconfig | 10 + drivers/fsi/Makefile | 1 + drivers/fsi/fsi-sbefifo.c | 173 +++++- drivers/fsi/occfifo.c | 649 +++++++++++++++++++++++ include/linux/fsi-sbefifo.h | 41 ++ 6 files changed, 861 insertions(+), 29 deletions(-)create mode 100644
drivers/fsi/occfifo.c
create mode 100644include/linux/fsi-sbefifo.hSignature · 1 line
1.8.3.1