[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