[PATCH linux dev-4.7 3/4] drivers/fsi: Scan for hub link IRQ sources
Eddie James
eajames at linux.vnet.ibm.com
Tue Apr 11 06:08:47 AEST 2017
On 04/07/2017 08:52 AM, Christopher Bostic wrote:
> Look for the hub link that may have sourced the IRQ being handled.
> Clear out hub link interrupting conditions that are latched in
> hardware after FSI client handler has been dispatched.
>
> Signed-off-by: Christopher Bostic <cbostic at linux.vnet.ibm.com>
> ---
> drivers/fsi/fsi-core.c | 129 +++++++++++++++++++++++++++++++++++++++++++++++--
> 1 file changed, 124 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/fsi/fsi-core.c b/drivers/fsi/fsi-core.c
> index 45e1171..72f3a35 100644
> --- a/drivers/fsi/fsi-core.c
> +++ b/drivers/fsi/fsi-core.c
> @@ -96,6 +96,10 @@ static int fsi_slave_write(struct fsi_slave *slave, uint32_t addr,
> #define FSI_SMODE 0x0 /* R/W: Mode register */
> #define FSI_SI1M 0x18 /* R/W: IRQ mask */
> #define FSI_SI1S 0x1C /* R: IRQ status */
> +#define FSI_SRSIC0 0x68 /* R/W: Remote IRQ condition 0 */
> +#define FSI_SRSIC1 0x6C /* R/W: Remote IRQ condition 1 */
> +#define FSI_SRSIM0 0x70 /* R/W: Remote IRQ mask 0 */
> +#define FSI_SRSIS0 0x78 /* R: Remote IRQ status 0 */
>
> /*
> * SI1S, SI1M fields
> @@ -116,6 +120,13 @@ static int fsi_slave_write(struct fsi_slave *slave, uint32_t addr,
> #define FSI_SMODE_LBCRR_SHIFT 8 /* Clk ratio shift */
> #define FSI_SMODE_LBCRR_MASK 0xf /* Clk ratio mask */
>
> +/*
> + * SRSIS, SRSIM, SRSIC fields
> + */
> +#define FSI_SRSIX_IRQ1_MASK 0x00aaaaaa /* SI1 IRQ sources */
> +#define FSI_SRSIX_BITS_PER_LINK 8
> +
> +
> /* FSI endpoint-device support */
> int fsi_device_read(struct fsi_device *dev, uint32_t addr, void *val,
> size_t size)
> @@ -584,6 +595,21 @@ static struct bin_attribute fsi_slave_raw_attr = {
> .write = fsi_slave_sysfs_raw_write,
> };
>
> +static int fsi_slave_irq_clear(struct fsi_slave *slave)
> +{
> + uint32_t clear = ~0;
> + int rc;
> +
> + rc = fsi_slave_write(slave, FSI_SLAVE_BASE + FSI_SRSIC0, &clear,
> + sizeof(clear));
> + if (rc) {
> + dev_dbg(&slave->dev, "Failed on write to SRSIC0\n");
> + return rc;
> + }
> + return fsi_slave_write(slave, FSI_SLAVE_BASE + FSI_SRSIC1, &clear,
> + sizeof(clear));
> +}
> +
> static int fsi_slave_init(struct fsi_master *master,
> int link, uint8_t slave_id)
> {
> @@ -649,8 +675,11 @@ static int fsi_slave_init(struct fsi_master *master,
> dev_warn(&slave->dev, "failed to create raw attr: %d\n", rc);
>
> list_add(&slave->list_link, &master->my_slaves);
> - fsi_slave_scan(slave);
> - return 0;
> + rc = fsi_slave_scan(slave);
> + if (rc)
> + return rc;
> +
> + return fsi_slave_irq_clear(slave);
> }
>
> /* FSI master support */
> @@ -783,10 +812,62 @@ static void fsi_master_unscan(struct fsi_master *master)
> master->slave_list = false;
> }
>
> +/* TODO: Add support for hub links 4-7 */
> +static int next_hublink_source(struct fsi_slave *slave, uint32_t srsis)
> +{
> + int index;
> +
> + if (!slave)
> + return -EINVAL;
> +
> + if (!(srsis & FSI_SRSIX_IRQ1_MASK)) {
> + dev_dbg(&slave->dev, "Unexpected IRQ source SRSIS:0x%08x\n",
> + srsis);
> + return -EINVAL;
> + }
> +
> + /*
> + * TODO: add a fair scheduler to ensure we don't favor lower
> + * hublink IRQ sources over others
> + */
> + index = __clz(srsis);
> + dev_dbg(&slave->dev, "SRSIS:0x%08x index:%d\n", srsis, index);
> + return index / FSI_SRSIX_BITS_PER_LINK;
> +}
> +
> +static int __fsi_dev_irq(struct device *dev, void *data);
> +
> +static int __fsi_hub_slave_irq(struct device *dev, void *data)
> +{
> + int rc;
> + struct fsi_slave *hub_slave = to_fsi_slave(dev);
> + uint32_t si1s;
> +
> + if (!hub_slave) {
> + dev_dbg(dev, "Could not find hub slave\n");
> + return -ENODEV;
> + }
> +
> + rc = fsi_slave_read(hub_slave, FSI_SLAVE_BASE + FSI_SI1S, &si1s,
> + sizeof(si1s));
> + if (rc) {
> + dev_dbg(dev, "Fail on read of hub slave si1s\n");
> + return rc;
> + }
> +
> + if (!si1s)
> + return 0;
> +
> + return device_for_each_child(dev, &si1s, __fsi_dev_irq);
> +}
> +
> static int __fsi_dev_irq(struct device *dev, void *data)
> {
> - uint32_t *si1s = data;
> + uint32_t *si1s = data, srsis;
> struct fsi_device *fsi_dev = to_fsi_dev(dev);
> + struct fsi_slave *slave;
> + struct fsi_master_hub *hub;
> + int rc, hublink;
>
> if (!fsi_dev || !si1s) {
> dev_dbg(dev, "Invalid input: %p %p\n", fsi_dev, si1s);
> @@ -803,9 +884,47 @@ static int __fsi_dev_irq(struct device *dev, void *data)
> return 0;
> }
>
> - /* TODO: handle hub sourced IRQ */
> + hub = dev_get_drvdata(dev);
> + if (!hub) {
> + dev_dbg(dev, "Not a hub device\n");
> + return 0;
> + }
>
> - return 0;
> + /* Scan the hub links for the source of IRQ */
> + slave = to_fsi_slave(dev->parent);
> + if (!slave) {
> + dev_dbg(dev, "Could not retrieve device's slave\n");
> + return -ENODEV;
> + }
> +
> + rc = fsi_slave_read(slave, FSI_SLAVE_BASE + FSI_SRSIS0, &srsis,
> + sizeof(srsis));
> + if (rc) {
> + dev_dbg(&slave->dev, "Failed to read SRSIS0\n");
> + return rc;
> + }
> + if (srsis) {
> + hublink = next_hublink_source(slave, srsis);
> +
> + if (!hub->master.dev)
> + return 0;
> +
> + device_for_each_child(dev, &hublink, __fsi_hub_slave_irq);
> +
> + /* Clear out the interrupting condition */
> + srsis = 0xff000000 >> (hublink * FSI_SRSIX_BITS_PER_LINK);
> + rc = fsi_slave_write(slave, FSI_SLAVE_BASE + FSI_SRSIC0,
> + &srsis, sizeof(srsis));
> + if (rc) {
> + dev_dbg(&slave->dev, "Failed to clear out SRSIC\n");
> + return rc;
> + }
> + } else {
> + dev_dbg(&slave->dev, "SI1S HUB src but no SRSIS0 bits!\n");
> + return -EINVAL;
> + }
> +
> + return 1;
> }
>
> static int __fsi_slave_irq(struct device *dev, void *data)
This one looks fine too.
Acked-by: Eddie James <eajames at linux.vnet.ibm.com>
More information about the openbmc
mailing list