[PATCH v6 7/8] i2c: amd-asf: Clear remote IRR bit to get successive interrupt

Shyam Sundar S K
2024-09-19T18:00:09Z

To ensure successive interrupts upon packet reception, it is necessary to
clear the remote IRR bit by writing the interrupt number to the EOI
register. The base address for this operation is provided by the BIOS and
retrieved by the driver by traversing the ASF object's namespace.

Co-developed-by: Sanket Goswami <Sanket.Goswami@amd.com>
Signed-off-by: Sanket Goswami <Sanket.Goswami@amd.com>
Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
---
drivers/i2c/busses/i2c-amd-asf-plat.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)

diff --git a/drivers/i2c/busses/i2c-amd-asf-plat.c b/drivers/i2c/busses/i2c-amd-asf-plat.c
index fe6cffa2fba4..35a1ad0012ec 100644
--- a/drivers/i2c/busses/i2c-amd-asf-plat.c
+++ b/drivers/i2c/busses/i2c-amd-asf-plat.c
@@ -48,6 +48,7 @@

struct amd_asf_dev {
struct i2c_adapter adap;
+ void __iomem *eoi_base;
struct i2c_client *target;
struct delayed_work work_buf;
struct sb800_mmio_cfg mmio_cfg;
@@ -292,12 +293,14 @@ static irqreturn_t amd_asf_irq_handler(int irq, void *ptr)
amd_asf_update_ioport_target(piix4_smba, ASF_SLV_INTR, SMBHSTSTS, true);
}

+ iowrite32(irq, dev->eoi_base);
return IRQ_HANDLED;
}

static int amd_asf_probe(struct platform_device *pdev)
{
struct amd_asf_dev *asf_dev;
+ struct resource *eoi_addr;
int ret, irq;

asf_dev = devm_kzalloc(&pdev->dev, sizeof(*asf_dev), GFP_KERNEL);
@@ -309,6 +312,21 @@ static int amd_asf_probe(struct platform_device *pdev)
if (!asf_dev->port_addr)
return dev_err_probe(&pdev->dev, -EINVAL, "missing IO resources\n");

+ /*
+ * The resource obtained via ACPI might not belong to the ASF device address space. Instead,
+ * it could be within other IP blocks of the ASIC, which are crucial for generating
+ * subsequent interrupts. Therefore, we avoid using devm_platform_ioremap_resource() and
+ * instead use platform_get_resource() and devm_ioremap() separately to prevent any address
+ * space conflicts.
+ */
+ eoi_addr = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!eoi_addr)
+ return dev_err_probe(&pdev->dev, -EINVAL, "missing MEM resources\n");
+
+ asf_dev->eoi_base = devm_ioremap(&pdev->dev, eoi_addr->start, resource_size(eoi_addr));
+ if (!asf_dev->eoi_base)
+ return dev_err_probe(&pdev->dev, -EBUSY, "failed mapping IO region\n");
+
ret = devm_delayed_work_autocancel(&pdev->dev, &asf_dev->work_buf, amd_asf_process_target);
if (ret)
return dev_err_probe(&pdev->dev, ret, "failed to create work queue\n");
--
2.25.1