Skip to contentSkip to conversation

drivers: fsi: Add SBE client device driver

RFC In review [email protected] 5 participants 6 messages Dec 6, 2016 – Dec 13, 2016 FSI

lore
Share & tools
lore
#0 lore raw

RFC 1/2 drivers: fsi: Add SBE client device driver

From: "Edward A. James" <[email protected]>

This driver provides an interface to the SBE engine on the P8/P9. This builds on Chris' openfsi patches, as we need the FSI protocol to talk to the SBE.

I'm not sure if we want or need the actual read/write file ops I included, as those were not there for the P8 driver.

I haven't tested this yet, as Chris is still working on getting engine register access working.

---
 drivers/fsi/Kconfig          |   6 ++
 drivers/fsi/Makefile         |   1 +
 drivers/fsi/fsi-sbe.c        | 235 +++++++++++++++++++++++++++++++++++++++++++
 include/uapi/linux/Kbuild    |   1 +
 include/uapi/linux/fsi-sbe.h |  27 +++++
 5 files changed, 270 insertions(+)
 create mode 100644 drivers/fsi/fsi-sbe.c
 create mode 100644 include/uapi/linux/fsi-sbe.h
drivers/fsi/Kconfig +6 -0
index 5917006a1f..e314f82 100644
@@ -36,6 +36,12 @@ config FSI_MBX
 	---help---
 	This option enables an FSI based Mailbox device driver.
 
+config FSI_SBE
+	tristate "SBE FSI client device driver"
+	depends on FSI
+	---help---
+	This option enables an FSI based SBE device driver.
+
 endif
 
 endmenu
drivers/fsi/Makefile +1 -0
index 36bcbd8..174c524 100644
@@ -4,3 +4,4 @@ obj-$(CONFIG_FSI_MASTER_FAKE) += fsi-master-fake.o
 obj-$(CONFIG_FSI_MASTER_GPIO) += fsi-master-gpio.o
 obj-$(CONFIG_FSI_SCOM) += fsi-scom.o
 obj-$(CONFIG_FSI_MBX) += fsi-mbx.o
+obj-$(CONFIG_FSI_SBE) += fsi-sbe.o
drivers/fsi/fsi-sbe.c new file +235 -0

235 lines not on this page · raw message

include/uapi/linux/Kbuild +1 -0
index 9493842..d092ce0 100644
@@ -132,6 +132,7 @@ header-y += firewire-constants.h
 header-y += flat.h
 header-y += fou.h
 header-y += fs.h
+header-y += fsi-sbe.h
 header-y += fsl_hypervisor.h
 header-y += fuse.h
 header-y += futex.h
include/uapi/linux/fsi-sbe.h new file +27 -0
new file mode 100644
index 0000000..57726de
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015-2016, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _UAPI_LINUX_FSI_SBE_H
+#define _UAPI_LINUX_FSI_SBE_H
+
+#include <linux/ioctl.h>
+
+struct sbe_ioctl_register {
+	unsigned long address;
+	unsigned long value;
+};
+
+#define SBE_IOCTL_MAGIC		0xF5	/* not sure about this magic number */
+
+#define SBE_IOCTL_READ_REG	_IOWR(SBE_IOCTL_MAGIC, 1, struct sbe_ioctl_register)
+#define SBE_IOCTL_WRITE_REG	_IOWR(SBE_IOCTL_MAGIC, 2, struct sbe_ioctl_register)
+#define SBE_IOCTL_REQUEST_RESET	_IO(SBE_IOCTL_MAGIC, 3)
+#define SBE_IOCTL_RESET		_IO(SBE_IOCTL_MAGIC, 4)
+
+#endif /* _UAPI_LINUX_FSI_SBE_H */
Signature · 1 line
1.9.1
#1 lore raw

Hello Eddie,

Quoted 8 lines · On Wed, Dec 7, 2016 at 9:45 AM, <[email protected]> wrote:

From: "Edward A. James" <[email protected]>

This driver provides an interface to the SBE engine on the P8/P9. This builds on Chris' openfsi patches, as we need the FSI protocol to talk to the SBE.

I'm not sure if we want or need the actual read/write file ops I included, as those were not there for the P8 driver.

Lets have a discussion abut what client drivers we will need to have in the kernel for FSI.

We should consider only creating kernel drivers when the code cannot live in userspace. This would mean situations where exclusive access to some part of the address space is required (SCOMs), when the sequence of reads/writes are timing critical, or when there are IRQs involved.

For cases where we're simply writing or reading values to the register CFAM address space, writing userspace code should be sufficient.

What do you think about this approach?

Cheers,

Joel

Quoted 330 lines

I haven't tested this yet, as Chris is still working on getting engine register access working.

---
 drivers/fsi/Kconfig          |   6 ++
 drivers/fsi/Makefile         |   1 +
 drivers/fsi/fsi-sbe.c        | 235 +++++++++++++++++++++++++++++++++++++++++++
 include/uapi/linux/Kbuild    |   1 +
 include/uapi/linux/fsi-sbe.h |  27 +++++
 5 files changed, 270 insertions(+)
 create mode 100644 drivers/fsi/fsi-sbe.c
 create mode 100644 include/uapi/linux/fsi-sbe.h
drivers/fsi/Kconfig +6 -0
index 5917006a1f..e314f82 100644
@@ -36,6 +36,12 @@ config FSI_MBX
        ---help---
        This option enables an FSI based Mailbox device driver.
 
+config FSI_SBE
+       tristate "SBE FSI client device driver"
+       depends on FSI
+       ---help---
+       This option enables an FSI based SBE device driver.
+
 endif
 
 endmenu
drivers/fsi/Makefile +1 -0
index 36bcbd8..174c524 100644
@@ -4,3 +4,4 @@ obj-$(CONFIG_FSI_MASTER_FAKE) += fsi-master-fake.o
 obj-$(CONFIG_FSI_MASTER_GPIO) += fsi-master-gpio.o
 obj-$(CONFIG_FSI_SCOM) += fsi-scom.o
 obj-$(CONFIG_FSI_MBX) += fsi-mbx.o
+obj-$(CONFIG_FSI_SBE) += fsi-sbe.o
drivers/fsi/fsi-sbe.c new file +235 -0
new file mode 100644
index 0000000..8a4f29a
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2015-2016, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/fsi.h>
+#include <linux/module.h>
+#include <linux/cdev.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/miscdevice.h>
+#include <linux/list.h>
+#include <linux/fsi-sbe.h>
+
+#define FSI_ENGID_P9SBE                0x22
+
+struct sbe_device {
+       struct list_head link;
+       struct fsi_device *fsi_dev;
+       struct miscdevice mdev;
+       char name[32];
+};
+
+#define to_sbe_dev(x)          container_of((x), struct sbe_device, mdev)
+
+static struct list_head sbe_devices;
+static atomic_t sbe_idx = ATOMIC_INIT(0);
+
+enum SBE_ENGINE {
+       SBE_UPSTREAM_FIFO = 0,
+       SBE_UPSTREAM_STATUS,
+       SBE_UPSTREAM_EOT,
+       SBE_UPSTREAM_REQUEST_RESET,
+       SBE_UPSTREAM_PERFORM_RESET,
+       SBE_UPSTREAM_ACK_EOT,
+       SBE_DOWNSTREAM_FIFO = 0x10,
+       SBE_DOWNSTREAM_STATUS,
+       SBE_DOWNSTREAM_EOT,
+       SBE_DOWNSTREAM_REQUEST_RESET,
+       SBE_DOWNSTREAM_PERFORM_RESET,
+       SBE_DOWNSTREAM_ACK_EOT,
+       SBE_DOWNSTREAM_MAX_TRANSFER_COUNT
+};
+
+static ssize_t sbe_read(struct file *filep, char __user *buf, size_t len,
+                       loff_t *offset)
+{
+       int rc;
+       struct miscdevice *mdev = (struct miscdevice *)filep->private_data;
+       struct sbe_device *sbe = to_sbe_dev(mdev);
+       char *data = kmalloc(len, GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       rc = fsi_device_read(sbe->fsi_dev, *offset, data, len);
+       if (rc)
+               goto done;
+
+       rc = copy_to_user(buf, data, len);
+
+done:
+       kfree(data);
+       return rc ? rc : len;
+}
+
+static ssize_t sbe_write(struct file *filep, const char __user *buf,
+                        size_t len, loff_t *offset)
+{
+       int rc;
+       struct miscdevice *mdev = (struct miscdevice *)filep->private_data;
+       struct sbe_device *sbe = to_sbe_dev(mdev);
+       char *data = kmalloc(len, GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
+       rc = copy_from_user(data, buf, len);
+       if (rc)
+               goto done;
+
+       rc = fsi_device_write(sbe->fsi_dev, *offset, data, len);
+
+done:
+       kfree(data);
+       return rc ? rc : len;
+}
+
+static int sbe_register_read(struct sbe_device *sbe, unsigned long data)
+{
+       int rc;
+       struct sbe_ioctl_register reg;
+
+       rc = copy_from_user(&reg, (void *)data,
+                           sizeof(struct sbe_ioctl_register));
+       if (rc)
+               return rc;
+
+       rc = fsi_device_read(sbe->fsi_dev, reg.address, &reg.value,
+                            sizeof(unsigned long));
+       if (rc)
+               return rc;
+
+       rc = copy_to_user((void *)data, &reg,
+                         sizeof(struct sbe_ioctl_register));
+
+       return rc;
+}
+
+static int sbe_register_write(struct sbe_device *sbe, unsigned long data)
+{
+       int rc;
+       struct sbe_ioctl_register reg;
+
+       rc = copy_from_user(&reg, (void *)data,
+                           sizeof(struct sbe_ioctl_register));
+       if (rc)
+               return rc;
+
+       rc = fsi_device_write(sbe->fsi_dev, reg.address, &reg.value,
+                             sizeof(unsigned long));
+
+       return rc;
+}
+
+static int sbe_reset(struct sbe_device *sbe)
+{
+       unsigned long val = 0xFFFFFFFF;
+
+       return fsi_device_write(sbe->fsi_dev, SBE_DOWNSTREAM_PERFORM_RESET,
+                               &val, sizeof(unsigned long));
+}
+
+
+static int sbe_request_reset(struct sbe_device *sbe)
+{
+       unsigned long val = 0xFFFFFFFF;
+
+       return fsi_device_write(sbe->fsi_dev, SBE_DOWNSTREAM_REQUEST_RESET,
+                               &val, sizeof(unsigned long));
+}
+
+static long sbe_ioctl(struct file *filep, uint32_t cmd, unsigned long data)
+{
+       struct miscdevice *mdev = (struct miscdevice *)filep->private_data;
+       struct sbe_device *sbe = to_sbe_dev(mdev);
+       struct device *dev = &sbe->fsi_dev->dev;
+       ssize_t rc;
+
+       switch (cmd) {
+       case SBE_IOCTL_READ_REG:
+               rc = sbe_register_read(sbe, data);
+               break;
+       case SBE_IOCTL_WRITE_REG:
+               rc = sbe_register_write(sbe, data);
+               break;
+       case SBE_IOCTL_REQUEST_RESET:
+               rc = sbe_request_reset(sbe);
+               break;
+       case SBE_IOCTL_RESET:
+               rc = sbe_reset(sbe);
+               break;
+       default:
+               dev_dbg(mdev->this_device, "invalid ioctl command:%d\n", cmd);
+               return -EINVAL;
+       }
+
+       return rc;
+};
+
+static const struct file_operations sbe_fops = {
+       .owner  = THIS_MODULE,
+       .llseek = no_seek_end_llseek,
+       .read   = sbe_read,
+       .write  = sbe_write,
+       .compat_ioctl = sbe_ioctl
+};
+
+static int sbe_probe(struct device *dev)
+{
+       struct fsi_device *fsi_dev = to_fsi_dev(dev);
+       struct sbe_device *sbe;
+
+       sbe = devm_kzalloc(dev, sizeof(struct sbe_device), GFP_KERNEL);
+       if (!sbe)
+               return -ENOMEM;
+
+       snprintf(sbe->name, 32, "sbe%d", atomic_inc_return(&sbe_idx));
+       sbe->fsi_dev = fsi_dev;
+
+       sbe->mdev.minor = MISC_DYNAMIC_MINOR;
+       sbe->mdev.fops = &sbe_fops;
+       sbe->mdev.name = sbe->name;
+       sbe->mdev.parent = dev;
+
+       list_add(&sbe->link, &sbe_devices);
+
+       return misc_register(&sbe->mdev);
+}
+
+static struct fsi_device_id sbe_ids[] = {
+       {
+               .engine_type = FSI_ENGID_P9SBE,
+               .version = FSI_VERSION_ANY,
+       },
+       { 0 }
+};
+
+static struct fsi_driver sbe_drv = {
+       .id_table = sbe_ids,
+       .drv = {
+               .name = "sbe",
+               .bus = &fsi_bus_type,
+               .probe = sbe_probe,
+       }
+};
+
+static int sbe_init(void)
+{
+       INIT_LIST_HEAD(&sbe_devices);
+       return fsi_driver_register(&sbe_drv);
+}
+
+static void sbe_exit(void)
+{
+       fsi_driver_unregister(&sbe_drv);
+}
+
+module_init(sbe_init);
+module_exit(sbe_exit);
+MODULE_LICENSE("GPL");
include/uapi/linux/Kbuild +1 -0
index 9493842..d092ce0 100644
@@ -132,6 +132,7 @@ header-y += firewire-constants.h
 header-y += flat.h
 header-y += fou.h
 header-y += fs.h
+header-y += fsi-sbe.h
 header-y += fsl_hypervisor.h
 header-y += fuse.h
 header-y += futex.h
include/uapi/linux/fsi-sbe.h new file +27 -1
new file mode 100644
index 0000000..57726de
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2015-2016, IBM Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _UAPI_LINUX_FSI_SBE_H
+#define _UAPI_LINUX_FSI_SBE_H
+
+#include <linux/ioctl.h>
+
+struct sbe_ioctl_register {
+       unsigned long address;
+       unsigned long value;
+};
+
+#define SBE_IOCTL_MAGIC                0xF5    /* not sure about this magic number */
+
+#define SBE_IOCTL_READ_REG     _IOWR(SBE_IOCTL_MAGIC, 1, struct sbe_ioctl_register)
+#define SBE_IOCTL_WRITE_REG    _IOWR(SBE_IOCTL_MAGIC, 2, struct sbe_ioctl_register)
+#define SBE_IOCTL_REQUEST_RESET        _IO(SBE_IOCTL_MAGIC, 3)
+#define SBE_IOCTL_RESET                _IO(SBE_IOCTL_MAGIC, 4)
+
+#endif /* _UAPI_LINUX_FSI_SBE_H */
--

1.9.1

#2 lore raw
Quoted 9 lines · Joel Stanley

Lets have a discussion abut what client drivers we will need to have in the kernel for FSI.

We should consider only creating kernel drivers when the code cannot live in userspace. This would mean situations where exclusive access to some part of the address space is required (SCOMs), when the sequence of reads/writes are timing critical, or when there are IRQs involved.

Quoted 4 lines

For cases where we're simply writing or reading values to the register CFAM address space, writing userspace code should be sufficient.

What do you think about this approach?

I'm pretty sure there is some layering going on here. SBE driver uses FSI, OCC driver (on P9) uses SBE. We can't get an hwmon OCC driver without this SBE driver.

Eddie, can you confirm?

Signature · 1 line
Patrick Williams
#3 lore raw

Hi,  Yes, the OCC driver will depend on the SBE driver for P9. I suppose the OCC driver could handle all the SBE register access over FSI itself... but not sure if that's a good approach.   I'll be on the call this evening.   Eddie   ----- Original message -----
From: Patrick Williams <[email protected]>
To: Joel Stanley <[email protected]>
Cc: [email protected], OpenBMC Maillist <[email protected]>, Christopher Bostic <[email protected]>, Edward James/Austin/IBM@IBMUS
Subject: Re: [RFC linux 1/2] drivers: fsi: Add SBE client device driver
Date: Mon, Dec 12, 2016 4:52 PM

Quoted 9 lines · Joel Stanley

Lets have a discussion abut what client drivers we will need to have in the kernel for FSI.

We should consider only creating kernel drivers when the code cannot live in userspace. This would mean situations where exclusive access to some part of the address space is required (SCOMs), when the sequence of reads/writes are timing critical, or when there are IRQs involved.

Quoted 4 lines

For cases where we're simply writing or reading values to the register CFAM address space, writing userspace code should be sufficient.

What do you think about this approach?

I'm pretty sure there is some layering going on here.  SBE driver uses FSI, OCC driver (on P9) uses SBE.  We can't get an hwmon OCC driver without this SBE driver.

Eddie, can you confirm?

--
Patrick Williams

#4 lore raw

Hi Eddie,

Quoted 3 lines · Edward James

Yes, the OCC driver will depend on the SBE driver for P9. I suppose the OCC driver could handle all the SBE register access over FSI itself... but not sure if that's a good approach.

Can you expand on why you think this not a good approach?

What abstraction does the SBE driver provide that the OCC driver benefits from? In other words, how does the code change in the OCC driver if we don't have a SBE driver in between?

Cheers,

Joel

#5 lore raw
Quoted 4 lines · Joel Stanley

Hi Eddie,

Quoted 1 line · Edward James

Yes, the OCC driver will depend on the SBE driver for P9. I suppose the

OCC

Quoted 8 lines
Quoted 2 lines

driver could handle all the SBE register access over FSI itself... but not sure if that's a good approach.

Can you expand on why you think this not a good approach?

What abstraction does the SBE driver provide that the OCC driver benefits from? In other words, how does the code change in the OCC driver if we don't have a SBE driver in between?

I think it may have been mentioned earlier but it's probably not necessary to have drivers that simply provide read/write methods to the FSI address spaces at different offsets as these just add code to the kernel for no real benefit as it's easy to add those offsets to a /dev/cfam device access for example.

The thing the kernel can provide that userspace can't easily is atomic/shared access to multiple registers. So for example I seem to recall there was a discussion somewhere on using a FIFO to communicate with the SBE. It may make sense in this case for a kernel SBE client driver to provide read/write calls that would access that FIFO, but any userspace client that just needs to read/write an FSI/CFAM address should just do that via a single chardev/driver.

- Alistair

Quoted 8 lines

Cheers,

Joel
_______________________________________________
openbmc mailing list
[email protected]
https://lists.ozlabs.org/listinfo/openbmc