* [PATCH] i3c: mipi-i3c-hci: Use physical device pointer with DMA API
@ 2025-02-03 14:55 Jarkko Nikula
2025-02-13 12:58 ` Jarkko Nikula
0 siblings, 1 reply; 3+ messages in thread
From: Jarkko Nikula @ 2025-02-03 14:55 UTC (permalink / raw)
To: linux-i3c; +Cc: Alexandre Belloni, Jarkko Nikula, Prabhakaran, Krishna
DMA transfer faults on Intel hardware when the IOMMU is enabled and
driver initialization will fail when attempting to do the first transfer:
DMAR: DRHD: handling fault status reg 2
DMAR: [DMA Read NO_PASID] Request device [00:11.0] fault addr 0x676e3000 [fault reason 0x71] SM: Present bit in first-level paging entry
i3c mipi-i3c-hci.0: ring 0: Transfer Aborted
mipi-i3c-hci mipi-i3c-hci.0: probe with driver mipi-i3c-hci failed with error -62
Reason for this is that the IOMMU setup is done for the physical devices
only and not for the virtual I3C Controller device object.
Therefore use the pointer to a physical device object with the DMA API.
Reported-by: Prabhakaran, Krishna <krishna.prabhakaran@intel.com>
Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
---
drivers/i3c/master/mipi-i3c-hci/dma.c | 45 ++++++++++++++++++---------
1 file changed, 31 insertions(+), 14 deletions(-)
diff --git a/drivers/i3c/master/mipi-i3c-hci/dma.c b/drivers/i3c/master/mipi-i3c-hci/dma.c
index 491dfe70b660..57c044b5264b 100644
--- a/drivers/i3c/master/mipi-i3c-hci/dma.c
+++ b/drivers/i3c/master/mipi-i3c-hci/dma.c
@@ -14,6 +14,7 @@
#include <linux/errno.h>
#include <linux/i3c/master.h>
#include <linux/io.h>
+#include <linux/pci.h>
#include "hci.h"
#include "cmd.h"
@@ -138,6 +139,7 @@ struct hci_rh_data {
};
struct hci_rings_data {
+ struct device *sysdev;
unsigned int total;
struct hci_rh_data headers[] __counted_by(total);
};
@@ -165,20 +167,20 @@ static void hci_dma_cleanup(struct i3c_hci *hci)
rh_reg_write(IBI_SETUP, 0);
if (rh->xfer)
- dma_free_coherent(&hci->master.dev,
+ dma_free_coherent(rings->sysdev,
rh->xfer_struct_sz * rh->xfer_entries,
rh->xfer, rh->xfer_dma);
if (rh->resp)
- dma_free_coherent(&hci->master.dev,
+ dma_free_coherent(rings->sysdev,
rh->resp_struct_sz * rh->xfer_entries,
rh->resp, rh->resp_dma);
kfree(rh->src_xfers);
if (rh->ibi_status)
- dma_free_coherent(&hci->master.dev,
+ dma_free_coherent(rings->sysdev,
rh->ibi_status_sz * rh->ibi_status_entries,
rh->ibi_status, rh->ibi_status_dma);
if (rh->ibi_data_dma)
- dma_unmap_single(&hci->master.dev, rh->ibi_data_dma,
+ dma_unmap_single(rings->sysdev, rh->ibi_data_dma,
rh->ibi_chunk_sz * rh->ibi_chunks_total,
DMA_FROM_DEVICE);
kfree(rh->ibi_data);
@@ -194,11 +196,23 @@ static int hci_dma_init(struct i3c_hci *hci)
{
struct hci_rings_data *rings;
struct hci_rh_data *rh;
+ struct device *sysdev;
u32 regval;
unsigned int i, nr_rings, xfers_sz, resps_sz;
unsigned int ibi_status_ring_sz, ibi_data_ring_sz;
int ret;
+ /*
+ * Set pointer to a physical device that does DMA and has IOMMU setup
+ * done for it in case of enabled IOMMU and use it with the DMA API.
+ * Here such device is either
+ * "mipi-i3c-hci" platform device (OF/ACPI enumeration) parent or
+ * grandparent (PCI enumeration).
+ */
+ sysdev = hci->master.dev.parent;
+ if (sysdev->parent && dev_is_pci(sysdev->parent))
+ sysdev = sysdev->parent;
+
regval = rhs_reg_read(CONTROL);
nr_rings = FIELD_GET(MAX_HEADER_COUNT_CAP, regval);
dev_info(&hci->master.dev, "%d DMA rings available\n", nr_rings);
@@ -213,6 +227,7 @@ static int hci_dma_init(struct i3c_hci *hci)
return -ENOMEM;
hci->io_data = rings;
rings->total = nr_rings;
+ rings->sysdev = sysdev;
regval = FIELD_PREP(MAX_HEADER_COUNT, rings->total);
rhs_reg_write(CONTROL, regval);
@@ -239,9 +254,9 @@ static int hci_dma_init(struct i3c_hci *hci)
xfers_sz = rh->xfer_struct_sz * rh->xfer_entries;
resps_sz = rh->resp_struct_sz * rh->xfer_entries;
- rh->xfer = dma_alloc_coherent(&hci->master.dev, xfers_sz,
+ rh->xfer = dma_alloc_coherent(rings->sysdev, xfers_sz,
&rh->xfer_dma, GFP_KERNEL);
- rh->resp = dma_alloc_coherent(&hci->master.dev, resps_sz,
+ rh->resp = dma_alloc_coherent(rings->sysdev, resps_sz,
&rh->resp_dma, GFP_KERNEL);
rh->src_xfers =
kmalloc_array(rh->xfer_entries, sizeof(*rh->src_xfers),
@@ -295,16 +310,16 @@ static int hci_dma_init(struct i3c_hci *hci)
ibi_data_ring_sz = rh->ibi_chunk_sz * rh->ibi_chunks_total;
rh->ibi_status =
- dma_alloc_coherent(&hci->master.dev, ibi_status_ring_sz,
+ dma_alloc_coherent(rings->sysdev, ibi_status_ring_sz,
&rh->ibi_status_dma, GFP_KERNEL);
rh->ibi_data = kmalloc(ibi_data_ring_sz, GFP_KERNEL);
ret = -ENOMEM;
if (!rh->ibi_status || !rh->ibi_data)
goto err_out;
rh->ibi_data_dma =
- dma_map_single(&hci->master.dev, rh->ibi_data,
+ dma_map_single(rings->sysdev, rh->ibi_data,
ibi_data_ring_sz, DMA_FROM_DEVICE);
- if (dma_mapping_error(&hci->master.dev, rh->ibi_data_dma)) {
+ if (dma_mapping_error(rings->sysdev, rh->ibi_data_dma)) {
rh->ibi_data_dma = 0;
ret = -ENOMEM;
goto err_out;
@@ -342,6 +357,7 @@ static int hci_dma_init(struct i3c_hci *hci)
static void hci_dma_unmap_xfer(struct i3c_hci *hci,
struct hci_xfer *xfer_list, unsigned int n)
{
+ struct hci_rings_data *rings = hci->io_data;
struct hci_xfer *xfer;
unsigned int i;
@@ -349,7 +365,7 @@ static void hci_dma_unmap_xfer(struct i3c_hci *hci,
xfer = xfer_list + i;
if (!xfer->data)
continue;
- dma_unmap_single(&hci->master.dev,
+ dma_unmap_single(rings->sysdev,
xfer->data_dma, xfer->data_len,
xfer->rnw ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
@@ -393,13 +409,13 @@ static int hci_dma_queue_xfer(struct i3c_hci *hci,
if (xfer->data) {
buf = xfer->bounce_buf ? xfer->bounce_buf : xfer->data;
xfer->data_dma =
- dma_map_single(&hci->master.dev,
+ dma_map_single(rings->sysdev,
buf,
xfer->data_len,
xfer->rnw ?
DMA_FROM_DEVICE :
DMA_TO_DEVICE);
- if (dma_mapping_error(&hci->master.dev,
+ if (dma_mapping_error(rings->sysdev,
xfer->data_dma)) {
hci_dma_unmap_xfer(hci, xfer_list, i);
return -ENOMEM;
@@ -586,6 +602,7 @@ static void hci_dma_recycle_ibi_slot(struct i3c_hci *hci,
static void hci_dma_process_ibi(struct i3c_hci *hci, struct hci_rh_data *rh)
{
+ struct hci_rings_data *rings = hci->io_data;
struct i3c_dev_desc *dev;
struct i3c_hci_dev_data *dev_data;
struct hci_dma_dev_ibi_data *dev_ibi;
@@ -696,7 +713,7 @@ static void hci_dma_process_ibi(struct i3c_hci *hci, struct hci_rh_data *rh)
* rh->ibi_chunk_sz;
if (first_part > ibi_size)
first_part = ibi_size;
- dma_sync_single_for_cpu(&hci->master.dev, ring_ibi_data_dma,
+ dma_sync_single_for_cpu(rings->sysdev, ring_ibi_data_dma,
first_part, DMA_FROM_DEVICE);
memcpy(slot->data, ring_ibi_data, first_part);
@@ -705,7 +722,7 @@ static void hci_dma_process_ibi(struct i3c_hci *hci, struct hci_rh_data *rh)
/* we wrap back to the start and copy remaining data */
ring_ibi_data = rh->ibi_data;
ring_ibi_data_dma = rh->ibi_data_dma;
- dma_sync_single_for_cpu(&hci->master.dev, ring_ibi_data_dma,
+ dma_sync_single_for_cpu(rings->sysdev, ring_ibi_data_dma,
ibi_size - first_part, DMA_FROM_DEVICE);
memcpy(slot->data + first_part, ring_ibi_data,
ibi_size - first_part);
--
2.47.2
--
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c
^ permalink raw reply related [flat|nested] 3+ messages in thread* Re: [PATCH] i3c: mipi-i3c-hci: Use physical device pointer with DMA API
2025-02-03 14:55 [PATCH] i3c: mipi-i3c-hci: Use physical device pointer with DMA API Jarkko Nikula
@ 2025-02-13 12:58 ` Jarkko Nikula
2025-02-19 19:32 ` Alexandre Belloni
0 siblings, 1 reply; 3+ messages in thread
From: Jarkko Nikula @ 2025-02-13 12:58 UTC (permalink / raw)
To: linux-i3c; +Cc: Alexandre Belloni, Prabhakaran, Krishna
Hi
On 2/3/25 4:55 PM, Jarkko Nikula wrote:
> DMA transfer faults on Intel hardware when the IOMMU is enabled and
> driver initialization will fail when attempting to do the first transfer:
>
> DMAR: DRHD: handling fault status reg 2
> DMAR: [DMA Read NO_PASID] Request device [00:11.0] fault addr 0x676e3000 [fault reason 0x71] SM: Present bit in first-level paging entry
> i3c mipi-i3c-hci.0: ring 0: Transfer Aborted
> mipi-i3c-hci mipi-i3c-hci.0: probe with driver mipi-i3c-hci failed with error -62
>
> Reason for this is that the IOMMU setup is done for the physical devices
> only and not for the virtual I3C Controller device object.
>
> Therefore use the pointer to a physical device object with the DMA API.
>
> Reported-by: Prabhakaran, Krishna <krishna.prabhakaran@intel.com>
> Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
> ---
> drivers/i3c/master/mipi-i3c-hci/dma.c | 45 ++++++++++++++++++---------
> 1 file changed, 31 insertions(+), 14 deletions(-)
>
Please don't apply this.
KFENCE started detecting memory corruption from the
i3c_hci_free_safe_xfer_buf() when IOMMU is on with this patch.
Corruption is not limited to a bounce buffer only but thanks to KFENCE
was noticed.
Which is obviously much worse than the DMAR fault and driver not loading.
The corruption happens after the last DMA write address for transfers
where size is not multiple of DWORDs corrupting the remaining bytes on
it or extending also to a next DWORD depending on buffer alignment and
transfer length.
I'm currently investigating the root cause for this with the experts.
So before this patch it'd need to have a change to the bounce buffer
implementation (extend to other use cases and allocate extra DWORDs) and
apply this patch only after it.
--
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH] i3c: mipi-i3c-hci: Use physical device pointer with DMA API
2025-02-13 12:58 ` Jarkko Nikula
@ 2025-02-19 19:32 ` Alexandre Belloni
0 siblings, 0 replies; 3+ messages in thread
From: Alexandre Belloni @ 2025-02-19 19:32 UTC (permalink / raw)
To: Jarkko Nikula; +Cc: linux-i3c, Prabhakaran, Krishna
On 13/02/2025 14:58:02+0200, Jarkko Nikula wrote:
> Hi
>
> On 2/3/25 4:55 PM, Jarkko Nikula wrote:
> > DMA transfer faults on Intel hardware when the IOMMU is enabled and
> > driver initialization will fail when attempting to do the first transfer:
> >
> > DMAR: DRHD: handling fault status reg 2
> > DMAR: [DMA Read NO_PASID] Request device [00:11.0] fault addr 0x676e3000 [fault reason 0x71] SM: Present bit in first-level paging entry
> > i3c mipi-i3c-hci.0: ring 0: Transfer Aborted
> > mipi-i3c-hci mipi-i3c-hci.0: probe with driver mipi-i3c-hci failed with error -62
> >
> > Reason for this is that the IOMMU setup is done for the physical devices
> > only and not for the virtual I3C Controller device object.
> >
> > Therefore use the pointer to a physical device object with the DMA API.
> >
> > Reported-by: Prabhakaran, Krishna <krishna.prabhakaran@intel.com>
> > Signed-off-by: Jarkko Nikula <jarkko.nikula@linux.intel.com>
> > ---
> > drivers/i3c/master/mipi-i3c-hci/dma.c | 45 ++++++++++++++++++---------
> > 1 file changed, 31 insertions(+), 14 deletions(-)
> >
> Please don't apply this.
>
> KFENCE started detecting memory corruption from the
> i3c_hci_free_safe_xfer_buf() when IOMMU is on with this patch. Corruption is
> not limited to a bounce buffer only but thanks to KFENCE was noticed.
>
> Which is obviously much worse than the DMAR fault and driver not loading.
>
> The corruption happens after the last DMA write address for transfers where
> size is not multiple of DWORDs corrupting the remaining bytes on it or
> extending also to a next DWORD depending on buffer alignment and transfer
> length.
>
> I'm currently investigating the root cause for this with the experts.
>
> So before this patch it'd need to have a change to the bounce buffer
> implementation (extend to other use cases and allocate extra DWORDs) and
> apply this patch only after it.
Thanks for the heads up, I was going to apply it!
--
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
--
linux-i3c mailing list
linux-i3c@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-i3c
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2025-02-19 19:43 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-02-03 14:55 [PATCH] i3c: mipi-i3c-hci: Use physical device pointer with DMA API Jarkko Nikula
2025-02-13 12:58 ` Jarkko Nikula
2025-02-19 19:32 ` Alexandre Belloni
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).