Skip to content

Commit

Permalink
i2c: ismt: Provide a DMA buffer for Interrupt Cause Logging
Browse files Browse the repository at this point in the history
[ Upstream commit 17a0f3a ]

Before sending a MSI the hardware writes information pertinent to the
interrupt cause to a memory location pointed by SMTICL register. This
memory holds three double words where the least significant bit tells
whether the interrupt cause of master/target/error is valid. The driver
does not use this but we need to set it up because otherwise it will
perform DMA write to the default address (0) and this will cause an
IOMMU fault such as below:

  DMAR: DRHD: handling fault status reg 2
  DMAR: [DMA Write] Request device [00:12.0] PASID ffffffff fault addr 0
        [fault reason 05] PTE Write access is not set

To prevent this from happening, provide a proper DMA buffer for this
that then gets mapped by the IOMMU accordingly.

Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Reviewed-by: From: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Wolfram Sang <wsa@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
westeri authored and gregkh committed Jun 6, 2022
1 parent 828309e commit f0749ae
Showing 1 changed file with 14 additions and 0 deletions.
14 changes: 14 additions & 0 deletions drivers/i2c/busses/i2c-ismt.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@

#define ISMT_DESC_ENTRIES 2 /* number of descriptor entries */
#define ISMT_MAX_RETRIES 3 /* number of SMBus retries to attempt */
#define ISMT_LOG_ENTRIES 3 /* number of interrupt cause log entries */

/* Hardware Descriptor Constants - Control Field */
#define ISMT_DESC_CWRL 0x01 /* Command/Write Length */
Expand Down Expand Up @@ -175,6 +176,8 @@ struct ismt_priv {
u8 head; /* ring buffer head pointer */
struct completion cmp; /* interrupt completion */
u8 buffer[I2C_SMBUS_BLOCK_MAX + 16]; /* temp R/W data buffer */
dma_addr_t log_dma;
u32 *log;
};

static const struct pci_device_id ismt_ids[] = {
Expand Down Expand Up @@ -409,6 +412,9 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
memset(desc, 0, sizeof(struct ismt_desc));
desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(addr, read_write);

/* Always clear the log entries */
memset(priv->log, 0, ISMT_LOG_ENTRIES * sizeof(u32));

/* Initialize common control bits */
if (likely(pci_dev_msi_enabled(priv->pci_dev)))
desc->control = ISMT_DESC_INT | ISMT_DESC_FAIR;
Expand Down Expand Up @@ -693,6 +699,8 @@ static void ismt_hw_init(struct ismt_priv *priv)
/* initialize the Master Descriptor Base Address (MDBA) */
writeq(priv->io_rng_dma, priv->smba + ISMT_MSTR_MDBA);

writeq(priv->log_dma, priv->smba + ISMT_GR_SMTICL);

/* initialize the Master Control Register (MCTRL) */
writel(ISMT_MCTRL_MEIE, priv->smba + ISMT_MSTR_MCTRL);

Expand Down Expand Up @@ -780,6 +788,12 @@ static int ismt_dev_init(struct ismt_priv *priv)
priv->head = 0;
init_completion(&priv->cmp);

priv->log = dmam_alloc_coherent(&priv->pci_dev->dev,
ISMT_LOG_ENTRIES * sizeof(u32),
&priv->log_dma, GFP_KERNEL);
if (!priv->log)
return -ENOMEM;

return 0;
}

Expand Down

0 comments on commit f0749ae

Please sign in to comment.