On Wed, 2018-06-13 at 09:57 -0500, Eddie James wrote: > > On 06/12/2018 12:19 AM, Benjamin Herrenschmidt wrote: > > This was too hard to split ... this adds a number of features > > to the SCOM user interface: > > > > - Support for indirect SCOMs > > > > - read()/write() interface now handle errors and retries > > > > - New ioctl() "raw" interface for use by debuggers > > > > Signed-off-by: Benjamin Herrenschmidt <b...@kernel.crashing.org> > > --- > > drivers/fsi/fsi-scom.c | 424 ++++++++++++++++++++++++++++++++++++--- > > include/uapi/linux/fsi.h | 56 ++++++ > > 2 files changed, 450 insertions(+), 30 deletions(-) > > create mode 100644 include/uapi/linux/fsi.h > > > > diff --git a/drivers/fsi/fsi-scom.c b/drivers/fsi/fsi-scom.c > > index e98573ecdae1..39c74351f1bf 100644 > > --- a/drivers/fsi/fsi-scom.c > > +++ b/drivers/fsi/fsi-scom.c > > @@ -24,6 +24,8 @@ > > #include <linux/list.h> > > #include <linux/idr.h> > > + > > +static int scom_reset(struct scom_device *scom, void __user *argp) > > +{ > > + uint32_t flags, dummy = -1; > > + int rc = 0; > > + > > + if (get_user(flags, (__u32 __user *)argp)) > > + return -EFAULT; > > + if (flags & SCOM_RESET_PIB) > > + rc = fsi_device_write(scom->fsi_dev, SCOM_PIB_RESET_REG, &dummy, > > + sizeof(uint32_t)); > > I realize this is a user requested flag but I believe the BMC is never > supposed to issue this type of reset, due to the possibility of breaking > stuff on the host side. Not sure if it should even be available?
It's for use by cronus or similar low level system debuggers. Cheers, Ben. > Otherwise, looks good! > Thanks, > Eddie > > > + if (!rc && (flags & (SCOM_RESET_PIB | SCOM_RESET_INTF))) > > + rc = fsi_device_write(scom->fsi_dev, SCOM_FSI2PIB_RESET_REG, > > &dummy, > > + sizeof(uint32_t)); > > + return rc; > > +} > > + > > +static int scom_check(struct scom_device *scom, void __user *argp) > > +{ > > + /* Still need to find out how to get "protected" */ > > + return put_user(SCOM_CHECK_SUPPORTED, (__u32 __user *)argp); > > +} > > + > > +static long scom_ioctl(struct file *file, unsigned int cmd, unsigned long > > arg) > > +{ > > + struct miscdevice *mdev = file->private_data; > > + struct scom_device *scom = to_scom_dev(mdev); > > + void __user *argp = (void __user *)arg; > > + int rc = -ENOTTY; > > + > > + mutex_lock(&scom->lock); > > + switch(cmd) { > > + case FSI_SCOM_CHECK: > > + rc = scom_check(scom, argp); > > + break; > > + case FSI_SCOM_READ: > > + rc = scom_raw_read(scom, argp); > > + break; > > + case FSI_SCOM_WRITE: > > + rc = scom_raw_write(scom, argp); > > + break; > > + case FSI_SCOM_RESET: > > + rc = scom_reset(scom, argp); > > + break; > > + } > > + mutex_unlock(&scom->lock); > > + return rc; > > +} > > + > > static const struct file_operations scom_fops = { > > - .owner = THIS_MODULE, > > - .llseek = scom_llseek, > > - .read = scom_read, > > - .write = scom_write, > > + .owner = THIS_MODULE, > > + .llseek = scom_llseek, > > + .read = scom_read, > > + .write = scom_write, > > + .unlocked_ioctl = scom_ioctl, > > }; > > > > static int scom_probe(struct device *dev) > > diff --git a/include/uapi/linux/fsi.h b/include/uapi/linux/fsi.h > > new file mode 100644 > > index 000000000000..6008d93f2e48 > > --- /dev/null > > +++ b/include/uapi/linux/fsi.h > > @@ -0,0 +1,56 @@ > > +#ifndef _UAPI_LINUX_FSI_H > > +#define _UAPI_LINUX_FSI_H > > + > > +#include <linux/ioctl.h> > > + > > +/* > > + * /dev/scom "raw" ioctl interface > > + * > > + * The driver supports a high level "read/write" interface which > > + * handles retries and converts the status to Linux error codes, > > + * however low level tools an debugger need to access the "raw" > > + * HW status information and interpret it themselves, so this > > + * ioctl interface is also provided for their use case. > > + */ > > + > > +/* Structure for SCOM read/write */ > > +struct scom_access { > > + __u64 addr; /* SCOM address, supports indirect */ > > + __u64 data; /* SCOM data (in for write, out for read) */ > > + __u64 mask; /* Data mask for writes */ > > + __u32 intf_errors; /* Interface error flags */ > > +#define SCOM_INTF_ERR_PARITY 0x00000001 /* Parity error */ > > +#define SCOM_INTF_ERR_PROTECTION 0x00000002 /* Blocked by secure boot */ > > +#define SCOM_INTF_ERR_ABORT 0x00000004 /* PIB reset during > > access */ > > +#define SCOM_INTF_ERR_UNKNOWN 0x80000000 /* Unknown error */ > > + /* > > + * Note: Any other bit set in intf_errors need to be considered as an > > + * error. Future implementations may define new error conditions. The > > + * pib_status below is only valid if intf_errors is 0. > > + */ > > + __u8 pib_status; /* 3-bit PIB status */ > > +#define SCOM_PIB_SUCCESS 0 /* Access successful */ > > +#define SCOM_PIB_BLOCKED 1 /* PIB blocked, pls retry */ > > +#define SCOM_PIB_OFFLINE 2 /* Chiplet offline */ > > +#define SCOM_PIB_PARTIAL 3 /* Partial good */ > > +#define SCOM_PIB_BAD_ADDR 4 /* Invalid address */ > > +#define SCOM_PIB_CLK_ERR 5 /* Clock error */ > > +#define SCOM_PIB_PARITY_ERR 6 /* Parity error on the PIB bus > > */ > > +#define SCOM_PIB_TIMEOUT 7 /* Bus timeout */ > > + __u8 pad; > > +}; > > + > > +/* Flags for SCOM check */ > > +#define SCOM_CHECK_SUPPORTED 0x00000001 /* Interface supported > > */ > > +#define SCOM_CHECK_PROTECTED 0x00000002 /* Interface blocked by > > secure boot */ > > + > > +/* Flags for SCOM reset */ > > +#define SCOM_RESET_INTF 0x00000001 /* Reset interface */ > > +#define SCOM_RESET_PIB 0x00000002 /* Reset PIB */ > > + > > +#define FSI_SCOM_CHECK _IOR('s', 0x00, __u32) > > +#define FSI_SCOM_READ _IOWR('s', 0x01, struct scom_access) > > +#define FSI_SCOM_WRITE _IOWR('s', 0x02, struct scom_access) > > +#define FSI_SCOM_RESET _IOW('s', 0x03, __u32) > > + > > +#endif /* _UAPI_LINUX_FSI_H */