mbox series

[v4,0/5] PCI: EP: Add RC-to-EP doorbell with platform MSI controller

Message ID 20241031-ep-msi-v4-0-717da2d99b28@nxp.com (mailing list archive)
Headers show
Series PCI: EP: Add RC-to-EP doorbell with platform MSI controller | expand

Message

Frank Li Oct. 31, 2024, 4:26 p.m. UTC
┌────────────┐   ┌───────────────────────────────────┐   ┌────────────────┐
│            │   │                                   │   │                │
│            │   │ PCI Endpoint                      │   │ PCI Host       │
│            │   │                                   │   │                │
│            │◄──┤ 1.platform_msi_domain_alloc_irqs()│   │                │
│            │   │                                   │   │                │
│ MSI        ├──►│ 2.write_msi_msg()                 ├──►├─BAR<n>         │
│ Controller │   │   update doorbell register address│   │                │
│            │   │   for BAR                         │   │                │
│            │   │                                   │   │ 3. Write BAR<n>│
│            │◄──┼───────────────────────────────────┼───┤                │
│            │   │                                   │   │                │
│            ├──►│ 4.Irq Handle                      │   │                │
│            │   │                                   │   │                │
│            │   │                                   │   │                │
└────────────┘   └───────────────────────────────────┘   └────────────────┘

This patches based on old https://lore.kernel.org/imx/20221124055036.1630573-1-Frank.Li@nxp.com/

Original patch only target to vntb driver. But actually it is common
method.

This patches add new API to pci-epf-core, so any EP driver can use it.

Previous v2 discussion here.
https://lore.kernel.org/imx/20230911220920.1817033-1-Frank.Li@nxp.com/

Changes in v4:
- Remove patch genirq/msi: Add cleanup guard define for msi_lock_descs()/msi_unlock_descs()
- Use new method to avoid compatible problem.
  Add new command DOORBELL_ENABLE and DOORBELL_DISABLE.
  pcitest -B send DOORBELL_ENABLE first, EP test function driver try to
remap one of BAR_N (except test register bar) to ITS MSI MMIO space. Old
driver don't support new command, so failure return, not side effect.
  After test, DOORBELL_DISABLE command send out to recover original map, so
pcitest bar test can pass as normal.
- Other detail change see each patches's change log
- Link to v3: https://lore.kernel.org/r/20241015-ep-msi-v3-0-cedc89a16c1a@nxp.com

Change from v2 to v3
- Fixed manivannan's comments
- Move common part to pci-ep-msi.c and pci-ep-msi.h
- rebase to 6.12-rc1
- use RevID to distingiush old version

mkdir /sys/kernel/config/pci_ep/functions/pci_epf_test/func1
echo 16 > /sys/kernel/config/pci_ep/functions/pci_epf_test/func1/msi_interrupts
echo 0x080c > /sys/kernel/config/pci_ep/functions/pci_epf_test/func1/deviceid
echo 0x1957 > /sys/kernel/config/pci_ep/functions/pci_epf_test/func1/vendorid
echo 1 > /sys/kernel/config/pci_ep/functions/pci_epf_test/func1/revid
^^^^^^ to enable platform msi support.
ln -s /sys/kernel/config/pci_ep/functions/pci_epf_test/func1 /sys/kernel/config/pci_ep/controllers/4c380000.pcie-ep

- use new device ID, which identify support doorbell to avoid broken
compatility.

    Enable doorbell support only for PCI_DEVICE_ID_IMX8_DB, while other devices
    keep the same behavior as before.

           EP side             RC with old driver      RC with new driver
    PCI_DEVICE_ID_IMX8_DB          no probe              doorbell enabled
    Other device ID             doorbell disabled*       doorbell disabled*

    * Behavior remains unchanged.

Change from v1 to v2
- Add missed patch for endpont/pci-epf-test.c
- Move alloc and free to epc driver from epf.
- Provide general help function for EPC driver to alloc platform msi irq.
- Fixed manivannan's comments.

To: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
To: Krzysztof Wilczyński <kw@linux.com>
To: Kishon Vijay Abraham I <kishon@kernel.org>
To: Bjorn Helgaas <bhelgaas@google.com>
To: Arnd Bergmann <arnd@arndb.de>
To: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: linux-kernel@vger.kernel.org
Cc: linux-pci@vger.kernel.org
Cc: imx@lists.linux.dev
Cc: Niklas Cassel <cassel@kernel.org>
Cc: cassel@kernel.org
Cc: dlemoal@kernel.org
Cc: maz@kernel.org
Cc: tglx@linutronix.de
Cc: jdmason@kudzu.us

Signed-off-by: Frank Li <Frank.Li@nxp.com>
---
Frank Li (5):
      PCI: endpoint: Add pci_epc_get_fn() API for customizable filtering
      PCI: endpoint: Add RC-to-EP doorbell support using platform MSI controller
      PCI: endpoint: pci-epf-test: Add doorbell test support
      misc: pci_endpoint_test: Add doorbell test case
      tools: PCI: Add 'B' option for test doorbell

 drivers/misc/pci_endpoint_test.c              |  63 +++++++++++++
 drivers/pci/endpoint/Makefile                 |   2 +-
 drivers/pci/endpoint/functions/pci-epf-test.c | 104 +++++++++++++++++++++
 drivers/pci/endpoint/pci-ep-msi.c             | 128 ++++++++++++++++++++++++++
 drivers/pci/endpoint/pci-epc-core.c           |  23 ++++-
 include/linux/pci-ep-msi.h                    |  15 +++
 include/linux/pci-epc.h                       |   2 +
 include/linux/pci-epf.h                       |  19 ++++
 include/uapi/linux/pcitest.h                  |   1 +
 tools/pci/pcitest.c                           |  16 +++-
 10 files changed, 369 insertions(+), 4 deletions(-)
---
base-commit: f231847d7f5a171be4566099f654521606b3ec37
change-id: 20241010-ep-msi-8b4cab33b1be

Best regards,
---
Frank Li <Frank.Li@nxp.com>

Comments

Niklas Cassel Nov. 6, 2024, 9:15 a.m. UTC | #1
Hello Frank,

On Thu, Oct 31, 2024 at 12:26:59PM -0400, Frank Li wrote:
> ┌────────────┐   ┌───────────────────────────────────┐   ┌────────────────┐
> │            │   │                                   │   │                │
> │            │   │ PCI Endpoint                      │   │ PCI Host       │
> │            │   │                                   │   │                │
> │            │◄──┤ 1.platform_msi_domain_alloc_irqs()│   │                │
> │            │   │                                   │   │                │
> │ MSI        ├──►│ 2.write_msi_msg()                 ├──►├─BAR<n>         │
> │ Controller │   │   update doorbell register address│   │                │
> │            │   │   for BAR                         │   │                │
> │            │   │                                   │   │ 3. Write BAR<n>│
> │            │◄──┼───────────────────────────────────┼───┤                │
> │            │   │                                   │   │                │
> │            ├──►│ 4.Irq Handle                      │   │                │
> │            │   │                                   │   │                │
> │            │   │                                   │   │                │
> └────────────┘   └───────────────────────────────────┘   └────────────────┘
> 
> This patches based on old https://lore.kernel.org/imx/20221124055036.1630573-1-Frank.Li@nxp.com/
> 
> Original patch only target to vntb driver. But actually it is common
> method.
> 
> This patches add new API to pci-epf-core, so any EP driver can use it.
> 
> Previous v2 discussion here.
> https://lore.kernel.org/imx/20230911220920.1817033-1-Frank.Li@nxp.com/
> 
> Changes in v4:
> - Remove patch genirq/msi: Add cleanup guard define for msi_lock_descs()/msi_unlock_descs()
> - Use new method to avoid compatible problem.
>   Add new command DOORBELL_ENABLE and DOORBELL_DISABLE.
>   pcitest -B send DOORBELL_ENABLE first, EP test function driver try to
> remap one of BAR_N (except test register bar) to ITS MSI MMIO space. Old
> driver don't support new command, so failure return, not side effect.
>   After test, DOORBELL_DISABLE command send out to recover original map, so
> pcitest bar test can pass as normal.
> - Other detail change see each patches's change log
> - Link to v3: https://lore.kernel.org/r/20241015-ep-msi-v3-0-cedc89a16c1a@nxp.com
> 
> Change from v2 to v3
> - Fixed manivannan's comments
> - Move common part to pci-ep-msi.c and pci-ep-msi.h
> - rebase to 6.12-rc1
> - use RevID to distingiush old version
> 
> mkdir /sys/kernel/config/pci_ep/functions/pci_epf_test/func1
> echo 16 > /sys/kernel/config/pci_ep/functions/pci_epf_test/func1/msi_interrupts
> echo 0x080c > /sys/kernel/config/pci_ep/functions/pci_epf_test/func1/deviceid
> echo 0x1957 > /sys/kernel/config/pci_ep/functions/pci_epf_test/func1/vendorid
> echo 1 > /sys/kernel/config/pci_ep/functions/pci_epf_test/func1/revid
> ^^^^^^ to enable platform msi support.
> ln -s /sys/kernel/config/pci_ep/functions/pci_epf_test/func1 /sys/kernel/config/pci_ep/controllers/4c380000.pcie-ep

Perhaps drop these steps, to not confuse the reader.
They are no longer relevant with the latest revision anyway.

> 
> - use new device ID, which identify support doorbell to avoid broken
> compatility.
> 
>     Enable doorbell support only for PCI_DEVICE_ID_IMX8_DB, while other devices
>     keep the same behavior as before.
> 
>            EP side             RC with old driver      RC with new driver
>     PCI_DEVICE_ID_IMX8_DB          no probe              doorbell enabled
>     Other device ID             doorbell disabled*       doorbell disabled*
> 
>     * Behavior remains unchanged.
> 
> Change from v1 to v2
> - Add missed patch for endpont/pci-epf-test.c
> - Move alloc and free to epc driver from epf.
> - Provide general help function for EPC driver to alloc platform msi irq.
> - Fixed manivannan's comments.

I wanted to try this series on rk3588, which has a MSI controller as part of the GIC
using Interrupt Translation Services (ITS), for the Root Complex DT node:
https://github.com/torvalds/linux/blob/v6.12-rc6/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi#L164
https://github.com/torvalds/linux/blob/v6.12-rc6/arch/arm64/boot/dts/rockchip/rk3588-base.dtsi#L1981-L1999

There isn't any reference to a MSI controller in the Endpoint DT node:
https://github.com/torvalds/linux/blob/v6.12-rc6/arch/arm64/boot/dts/rockchip/rk3588-extra.dtsi#L189

When testing your series, I get an error in
platform_device_msi_init_and_alloc_irqs(), because no domain is found.

I assume that is it "msi-parent" that we should add here.

However, looking at:
$ git grep -p msi-parent arch/arm64/boot/dts/freescale/

I do not see any freescale/iMX platform specifying a msi-parent for the EP node.

Is there any additional DTS changes needed for iMX that is not part of this series,
or what am I missing?

When adding "msi-parent = <&its1 0x0000>;
to the EP node
(this is just a guess since RC node has: msi-map = <0x0000 &its1 0x0000 0x1000>;)

I do get a domain, but I do not get any IRQ on the EP side when the RC side is
writing the doorbell (as part of pcitest -B),

[    7.978984] pci_epc_alloc_doorbell: num_db: 1
[    7.979545] pci_epf_test_bind: doorbell_addr: 0x40
[    7.979978] pci_epf_test_bind: doorbell_data: 0x0
[    7.980397] pci_epf_test_bind: doorbell_bar: 0x1
[   21.114613] pci_epf_enable_doorbell db_bar: 1
[   21.115001] pci_epf_enable_doorbell: doorbell_addr: 0xfe650040
[   21.115512] pci_epf_enable_doorbell: phys_addr: 0xfe650000
[   21.115994] pci_epf_enable_doorbell: success

# cat /proc/interrupts | grep epc
117:          0          0          0          0          0          0          0          0  ITS-pMSI-a40000000.pcie-ep   0 Edge      pci-epc-doorbell0

Even if I try to write the doorbell manually from EP side using devmem:

# devmem 0xfe670040 32 1

it still doesn't trigger a IRQ on the EP side:
# cat /proc/interrupts | grep epc
117:          0          0          0          0          0          0          0          0  ITS-pMSI-a40000000.pcie-ep   0 Edge      pci-epc-doorbell0

Any ideas?


Kind regards,
Niklas
Niklas Cassel Nov. 6, 2024, 9:36 a.m. UTC | #2
On Wed, Nov 06, 2024 at 10:15:27AM +0100, Niklas Cassel wrote:
> 
> I do get a domain, but I do not get any IRQ on the EP side when the RC side is
> writing the doorbell (as part of pcitest -B),
> 
> [    7.978984] pci_epc_alloc_doorbell: num_db: 1
> [    7.979545] pci_epf_test_bind: doorbell_addr: 0x40
> [    7.979978] pci_epf_test_bind: doorbell_data: 0x0
> [    7.980397] pci_epf_test_bind: doorbell_bar: 0x1
> [   21.114613] pci_epf_enable_doorbell db_bar: 1
> [   21.115001] pci_epf_enable_doorbell: doorbell_addr: 0xfe650040
> [   21.115512] pci_epf_enable_doorbell: phys_addr: 0xfe650000
> [   21.115994] pci_epf_enable_doorbell: success
> 
> # cat /proc/interrupts | grep epc
> 117:          0          0          0          0          0          0          0          0  ITS-pMSI-a40000000.pcie-ep   0 Edge      pci-epc-doorbell0
> 
> Even if I try to write the doorbell manually from EP side using devmem:
> 
> # devmem 0xfe670040 32 1

Sorry, this should of course have been:
# devmem 0xfe650040 32 1

But the result is the name, no IRQ triggered on the EP side.

(My command above was from testing "msi-parent = <&its0 0x0000>",
rather than &its1, but that also didn't work when writing the
corresponding "doorbell_addr" using e.g. devmem.)

Considering that the RC node is using &its1, that is probably
also what should be used in the EP node when running the controller
in EP mode instead of RC mode.


Kind regards,
Niklas
Frank Li Nov. 6, 2024, 5:13 p.m. UTC | #3
On Wed, Nov 06, 2024 at 10:36:42AM +0100, Niklas Cassel wrote:
> On Wed, Nov 06, 2024 at 10:15:27AM +0100, Niklas Cassel wrote:
> >
> > I do get a domain, but I do not get any IRQ on the EP side when the RC side is
> > writing the doorbell (as part of pcitest -B),
> >
> > [    7.978984] pci_epc_alloc_doorbell: num_db: 1
> > [    7.979545] pci_epf_test_bind: doorbell_addr: 0x40
> > [    7.979978] pci_epf_test_bind: doorbell_data: 0x0
> > [    7.980397] pci_epf_test_bind: doorbell_bar: 0x1
> > [   21.114613] pci_epf_enable_doorbell db_bar: 1
> > [   21.115001] pci_epf_enable_doorbell: doorbell_addr: 0xfe650040
> > [   21.115512] pci_epf_enable_doorbell: phys_addr: 0xfe650000
> > [   21.115994] pci_epf_enable_doorbell: success
> >
> > # cat /proc/interrupts | grep epc
> > 117:          0          0          0          0          0          0          0          0  ITS-pMSI-a40000000.pcie-ep   0 Edge      pci-epc-doorbell0
> >
> > Even if I try to write the doorbell manually from EP side using devmem:
> >
> > # devmem 0xfe670040 32 1
>
> Sorry, this should of course have been:
> # devmem 0xfe650040 32 1

Thank you test it. You can't write it at EP side. ITS identify the bus
master. master ID (streamid) of CPU is the diffference with PCI master's
ID (streamid). You set msi-parent = <&its0 0x0000>, not sure if 0x0000 is
validate stream.

You have to run at RC side, "devmem (Bar1+0x40) 32 0".  So PCIe EP
controller can use EP streamid.

some system need special register to config stream id, you can refer host
side's settings.

Frank

>
> But the result is the name, no IRQ triggered on the EP side.
>
> (My command above was from testing "msi-parent = <&its0 0x0000>",
> rather than &its1, but that also didn't work when writing the
> corresponding "doorbell_addr" using e.g. devmem.)

<&its0 0x0000>,  second argument is your PCIe controller's stream ID. You
can ref RC side.

>
> Considering that the RC node is using &its1, that is probably
> also what should be used in the EP node when running the controller
> in EP mode instead of RC mode.

Generally,  RC node should use smmu-map, instead &its1. Or your PCI
controller direct use 16bit RID as streamid.

>
>
> Kind regards,
> Niklas
Niklas Cassel Nov. 6, 2024, 11:57 p.m. UTC | #4
On Wed, Nov 06, 2024 at 12:13:09PM -0500, Frank Li wrote:
> On Wed, Nov 06, 2024 at 10:36:42AM +0100, Niklas Cassel wrote:
> > On Wed, Nov 06, 2024 at 10:15:27AM +0100, Niklas Cassel wrote:
> > >
> > > I do get a domain, but I do not get any IRQ on the EP side when the RC side is
> > > writing the doorbell (as part of pcitest -B),
> > >
> > > [    7.978984] pci_epc_alloc_doorbell: num_db: 1
> > > [    7.979545] pci_epf_test_bind: doorbell_addr: 0x40
> > > [    7.979978] pci_epf_test_bind: doorbell_data: 0x0
> > > [    7.980397] pci_epf_test_bind: doorbell_bar: 0x1
> > > [   21.114613] pci_epf_enable_doorbell db_bar: 1
> > > [   21.115001] pci_epf_enable_doorbell: doorbell_addr: 0xfe650040
> > > [   21.115512] pci_epf_enable_doorbell: phys_addr: 0xfe650000
> > > [   21.115994] pci_epf_enable_doorbell: success
> > >
> > > # cat /proc/interrupts | grep epc
> > > 117:          0          0          0          0          0          0          0          0  ITS-pMSI-a40000000.pcie-ep   0 Edge      pci-epc-doorbell0
> > >
> > > Even if I try to write the doorbell manually from EP side using devmem:
> > >
> > > # devmem 0xfe670040 32 1
> >
> > Sorry, this should of course have been:
> > # devmem 0xfe650040 32 1
> 
> Thank you test it. You can't write it at EP side. ITS identify the bus
> master. master ID (streamid) of CPU is the diffference with PCI master's
> ID (streamid). You set msi-parent = <&its0 0x0000>, not sure if 0x0000 is
> validate stream.

I see, this makes sense since the ITS converts BDF to an MSI specifier.


> 
> You have to run at RC side, "devmem (Bar1+0x40) 32 0".  So PCIe EP
> controller can use EP streamid.
> 
> some system need special register to config stream id, you can refer host
> side's settings.

> <&its0 0x0000>,  second argument is your PCIe controller's stream ID. You
> can ref RC side.

The RC node looks like this:
msi-map = <0x0000 &its1 0x0000 0x1000>;
So it does indeed use 0x0 as the MSI specifier.


> 
> >
> > Considering that the RC node is using &its1, that is probably
> > also what should be used in the EP node when running the controller
> > in EP mode instead of RC mode.
> 
> Generally,  RC node should use smmu-map, instead &its1. Or your PCI
> controller direct use 16bit RID as streamid.

smmu-map? Do you mean iommu-map?

I don't see why we would need to have the SMMU enabled to use ITS.
The iommu is currently disabled on my platform.

I did enable the iommu, and all BAR tests, read tests, write tests,
and copy tests pass. However I get an iommu error when the RC is
writing the doorbell. Perhaps you need to do dma_map_single() on
the address that you are setting the inbound address translation to?



Without the IOMMU, if I modify pci_endpoint_test.c to not send the
DISABLE_DOORBELL command on error (so that EP side still has DB enabled),
I can read all BARs except BAR1 (which was used for the doorbell):
[   21.077417] pci 0000:01:00.0: BAR 0 [mem 0xf0300000-0xf03fffff]: assigned
[   21.078029] pci 0000:01:00.0: BAR 1 [mem 0xf0400000-0xf04fffff]: assigned
[   21.078640] pci 0000:01:00.0: BAR 2 [mem 0xf0500000-0xf05fffff]: assigned
[   21.079250] pci 0000:01:00.0: BAR 3 [mem 0xf0600000-0xf06fffff]: assigned
[   21.079860] pci 0000:01:00.0: BAR 5 [mem 0xf0700000-0xf07fffff]: assigned
# pcitest -B
[   25.156623] COMMAND_ENABLE_DOORBELL complete - status: 0x440
[   25.157131] db_bar: 1 addr: 0x40 data: 0x0
[   25.157501] setting irq_type to: 1
[   25.157802] writing: 0x0 to offset: 0x40 in BAR: 1
[   35.300676] we wrote to the BAR, status is now: 0x0

status is not updated after writing to DB,
and /proc/interrupts on EP side is not incrementing.

# devmem 0xf0300000
0x00000000
# devmem 0xf0400040
0xFFFFFFFF
# devmem 0xf0500000
0x00000000
# devmem 0xf0600000
0x00000000
# devmem 0xf0700000
0x00000000

So there does seem to be something wrong with the inbound translation,
at least when testing on rk3588 which only uses 1MB fixed size BARs:
https://github.com/torvalds/linux/blob/v6.12-rc6/drivers/pci/controller/dwc/pcie-dw-rockchip.c#L276-L281



You also didn't answer which imx platform that you are using to test this,
I don't see a single imx platform that specifies "msi-parent".


Kind regards,
Niklas
Frank Li Nov. 7, 2024, 12:41 a.m. UTC | #5
On Thu, Nov 07, 2024 at 12:57:16AM +0100, Niklas Cassel wrote:
> On Wed, Nov 06, 2024 at 12:13:09PM -0500, Frank Li wrote:
> > On Wed, Nov 06, 2024 at 10:36:42AM +0100, Niklas Cassel wrote:
> > > On Wed, Nov 06, 2024 at 10:15:27AM +0100, Niklas Cassel wrote:
> > > >
> > > > I do get a domain, but I do not get any IRQ on the EP side when the RC side is
> > > > writing the doorbell (as part of pcitest -B),
> > > >
> > > > [    7.978984] pci_epc_alloc_doorbell: num_db: 1
> > > > [    7.979545] pci_epf_test_bind: doorbell_addr: 0x40
> > > > [    7.979978] pci_epf_test_bind: doorbell_data: 0x0
> > > > [    7.980397] pci_epf_test_bind: doorbell_bar: 0x1
> > > > [   21.114613] pci_epf_enable_doorbell db_bar: 1
> > > > [   21.115001] pci_epf_enable_doorbell: doorbell_addr: 0xfe650040
> > > > [   21.115512] pci_epf_enable_doorbell: phys_addr: 0xfe650000
> > > > [   21.115994] pci_epf_enable_doorbell: success
> > > >
> > > > # cat /proc/interrupts | grep epc
> > > > 117:          0          0          0          0          0          0          0          0  ITS-pMSI-a40000000.pcie-ep   0 Edge      pci-epc-doorbell0
> > > >
> > > > Even if I try to write the doorbell manually from EP side using devmem:
> > > >
> > > > # devmem 0xfe670040 32 1
> > >
> > > Sorry, this should of course have been:
> > > # devmem 0xfe650040 32 1
> >
> > Thank you test it. You can't write it at EP side. ITS identify the bus
> > master. master ID (streamid) of CPU is the diffference with PCI master's
> > ID (streamid). You set msi-parent = <&its0 0x0000>, not sure if 0x0000 is
> > validate stream.
>
> I see, this makes sense since the ITS converts BDF to an MSI specifier.
>
>
> >
> > You have to run at RC side, "devmem (Bar1+0x40) 32 0".  So PCIe EP
> > controller can use EP streamid.
> >
> > some system need special register to config stream id, you can refer host
> > side's settings.
>
> > <&its0 0x0000>,  second argument is your PCIe controller's stream ID. You
> > can ref RC side.
>
> The RC node looks like this:
> msi-map = <0x0000 &its1 0x0000 0x1000>;
> So it does indeed use 0x0 as the MSI specifier.
>
>
> >
> > >
> > > Considering that the RC node is using &its1, that is probably
> > > also what should be used in the EP node when running the controller
> > > in EP mode instead of RC mode.
> >
> > Generally,  RC node should use smmu-map, instead &its1. Or your PCI
> > controller direct use 16bit RID as streamid.
>
> smmu-map? Do you mean iommu-map?

Sorry, typo, my means msi-map.

>
> I don't see why we would need to have the SMMU enabled to use ITS.
> The iommu is currently disabled on my platform.
>
> I did enable the iommu, and all BAR tests, read tests, write tests,
> and copy tests pass. However I get an iommu error when the RC is
> writing the doorbell. Perhaps you need to do dma_map_single() on
> the address that you are setting the inbound address translation to?
>
>
>
> Without the IOMMU, if I modify pci_endpoint_test.c to not send the
> DISABLE_DOORBELL command on error (so that EP side still has DB enabled),
> I can read all BARs except BAR1 (which was used for the doorbell):
> [   21.077417] pci 0000:01:00.0: BAR 0 [mem 0xf0300000-0xf03fffff]: assigned
> [   21.078029] pci 0000:01:00.0: BAR 1 [mem 0xf0400000-0xf04fffff]: assigned
> [   21.078640] pci 0000:01:00.0: BAR 2 [mem 0xf0500000-0xf05fffff]: assigned
> [   21.079250] pci 0000:01:00.0: BAR 3 [mem 0xf0600000-0xf06fffff]: assigned
> [   21.079860] pci 0000:01:00.0: BAR 5 [mem 0xf0700000-0xf07fffff]: assigned
> # pcitest -B
> [   25.156623] COMMAND_ENABLE_DOORBELL complete - status: 0x440
> [   25.157131] db_bar: 1 addr: 0x40 data: 0x0
> [   25.157501] setting irq_type to: 1
> [   25.157802] writing: 0x0 to offset: 0x40 in BAR: 1
> [   35.300676] we wrote to the BAR, status is now: 0x0
>
> status is not updated after writing to DB,
> and /proc/interrupts on EP side is not incrementing.
>
> # devmem 0xf0300000
> 0x00000000
> # devmem 0xf0400040
> 0xFFFFFFFF
> # devmem 0xf0500000
> 0x00000000
> # devmem 0xf0600000
> 0x00000000
> # devmem 0xf0700000
> 0x00000000
>
> So there does seem to be something wrong with the inbound translation,
> at least when testing on rk3588 which only uses 1MB fixed size BARs:
> https://github.com/torvalds/linux/blob/v6.12-rc6/drivers/pci/controller/dwc/pcie-dw-rockchip.c#L276-L281
>

It should be fine.  Some hardware many append some stream id bits before
send to ITS.

>
>
> You also didn't answer which imx platform that you are using to test this,
> I don't see a single imx platform that specifies "msi-parent".

Only imx95 support its now. LUT part code is still under review. EP support
part should after lut merged. Preivous use layerscape, which uboot set it.

Frank

>
>
> Kind regards,
> Niklas
Frank Li Nov. 7, 2024, 12:46 a.m. UTC | #6
On Thu, Nov 07, 2024 at 12:57:16AM +0100, Niklas Cassel wrote:
> On Wed, Nov 06, 2024 at 12:13:09PM -0500, Frank Li wrote:
> > On Wed, Nov 06, 2024 at 10:36:42AM +0100, Niklas Cassel wrote:
> > > On Wed, Nov 06, 2024 at 10:15:27AM +0100, Niklas Cassel wrote:
> > > >
> > > > I do get a domain, but I do not get any IRQ on the EP side when the RC side is
> > > > writing the doorbell (as part of pcitest -B),
> > > >
> > > > [    7.978984] pci_epc_alloc_doorbell: num_db: 1
> > > > [    7.979545] pci_epf_test_bind: doorbell_addr: 0x40
> > > > [    7.979978] pci_epf_test_bind: doorbell_data: 0x0
> > > > [    7.980397] pci_epf_test_bind: doorbell_bar: 0x1
> > > > [   21.114613] pci_epf_enable_doorbell db_bar: 1
> > > > [   21.115001] pci_epf_enable_doorbell: doorbell_addr: 0xfe650040
> > > > [   21.115512] pci_epf_enable_doorbell: phys_addr: 0xfe650000
> > > > [   21.115994] pci_epf_enable_doorbell: success
> > > >
> > > > # cat /proc/interrupts | grep epc
> > > > 117:          0          0          0          0          0          0          0          0  ITS-pMSI-a40000000.pcie-ep   0 Edge      pci-epc-doorbell0
> > > >
> > > > Even if I try to write the doorbell manually from EP side using devmem:
> > > >
> > > > # devmem 0xfe670040 32 1
> > >
> > > Sorry, this should of course have been:
> > > # devmem 0xfe650040 32 1
> >
> > Thank you test it. You can't write it at EP side. ITS identify the bus
> > master. master ID (streamid) of CPU is the diffference with PCI master's
> > ID (streamid). You set msi-parent = <&its0 0x0000>, not sure if 0x0000 is
> > validate stream.
>
> I see, this makes sense since the ITS converts BDF to an MSI specifier.
>
>
> >
> > You have to run at RC side, "devmem (Bar1+0x40) 32 0".  So PCIe EP
> > controller can use EP streamid.
> >
> > some system need special register to config stream id, you can refer host
> > side's settings.
>
> > <&its0 0x0000>,  second argument is your PCIe controller's stream ID. You
> > can ref RC side.
>
> The RC node looks like this:
> msi-map = <0x0000 &its1 0x0000 0x1000>;
> So it does indeed use 0x0 as the MSI specifier.
>
>
> >
> > >
> > > Considering that the RC node is using &its1, that is probably
> > > also what should be used in the EP node when running the controller
> > > in EP mode instead of RC mode.
> >
> > Generally,  RC node should use smmu-map, instead &its1. Or your PCI
> > controller direct use 16bit RID as streamid.
>
> smmu-map? Do you mean iommu-map?
>
> I don't see why we would need to have the SMMU enabled to use ITS.
> The iommu is currently disabled on my platform.
>
> I did enable the iommu, and all BAR tests, read tests, write tests,
> and copy tests pass. However I get an iommu error when the RC is
> writing the doorbell. Perhaps you need to do dma_map_single() on
> the address that you are setting the inbound address translation to?
>
>
>
> Without the IOMMU, if I modify pci_endpoint_test.c to not send the
> DISABLE_DOORBELL command on error (so that EP side still has DB enabled),
> I can read all BARs except BAR1 (which was used for the doorbell):

If you enable IOMMU, please double check pci_epc_write_msi_msg() pass
down iommu mapped address. I have not test iommu enabled's case yet.

Frank

> [   21.077417] pci 0000:01:00.0: BAR 0 [mem 0xf0300000-0xf03fffff]: assigned
> [   21.078029] pci 0000:01:00.0: BAR 1 [mem 0xf0400000-0xf04fffff]: assigned
> [   21.078640] pci 0000:01:00.0: BAR 2 [mem 0xf0500000-0xf05fffff]: assigned
> [   21.079250] pci 0000:01:00.0: BAR 3 [mem 0xf0600000-0xf06fffff]: assigned
> [   21.079860] pci 0000:01:00.0: BAR 5 [mem 0xf0700000-0xf07fffff]: assigned
> # pcitest -B
> [   25.156623] COMMAND_ENABLE_DOORBELL complete - status: 0x440
> [   25.157131] db_bar: 1 addr: 0x40 data: 0x0
> [   25.157501] setting irq_type to: 1
> [   25.157802] writing: 0x0 to offset: 0x40 in BAR: 1
> [   35.300676] we wrote to the BAR, status is now: 0x0
>
> status is not updated after writing to DB,
> and /proc/interrupts on EP side is not incrementing.
>
> # devmem 0xf0300000
> 0x00000000
> # devmem 0xf0400040
> 0xFFFFFFFF
> # devmem 0xf0500000
> 0x00000000
> # devmem 0xf0600000
> 0x00000000
> # devmem 0xf0700000
> 0x00000000
>
> So there does seem to be something wrong with the inbound translation,
> at least when testing on rk3588 which only uses 1MB fixed size BARs:
> https://github.com/torvalds/linux/blob/v6.12-rc6/drivers/pci/controller/dwc/pcie-dw-rockchip.c#L276-L281
>
>
>
> You also didn't answer which imx platform that you are using to test this,
> I don't see a single imx platform that specifies "msi-parent".
>
>
> Kind regards,
> Niklas
Niklas Cassel Nov. 8, 2024, 12:07 a.m. UTC | #7
On Wed, Nov 06, 2024 at 07:41:42PM -0500, Frank Li wrote:
> >
> > So there does seem to be something wrong with the inbound translation,
> > at least when testing on rk3588 which only uses 1MB fixed size BARs:
> > https://github.com/torvalds/linux/blob/v6.12-rc6/drivers/pci/controller/dwc/pcie-dw-rockchip.c#L276-L281
> >
> 
> It should be fine.  Some hardware many append some stream id bits before
> send to ITS.

Some more debugging with the IOMMU on.

EP side start:
[   14.601081] pci_epc_alloc_doorbell: num_db: 1
[   14.601588] pci_epf_test_bind: doorbell_addr: 0xf040 (align: 0x10000)
[   14.602162] pci_epf_test_bind: doorbell_data: 0x0
[   14.602573] pci_epf_test_bind: doorbell_bar: 0x1


When RC side does:
pcitest -B
[  109.252900] COMMAND_ENABLE_DOORBELL complete - status: 0x440
[  109.253406] db_bar: 1 addr: 0xf040 data: 0x0
[  109.254094] writing: 0x0 to offset: 0xf040 in BAR: 1
[  119.268887] we wrote to the BAR, status is now: 0x0

EP side results in:
[  117.894997] pci_epf_enable_doorbell db_bar: 1
[  117.895399] pci_epf_enable_doorbell: using doorbell_addr: 0xffffff9ff040
[  117.896517] pci_epf_enable_doorbell: phys_addr: 0xffffff9f0000
[  117.897037] dw_pcie_ep_set_bar: set_bar: bar: 1 phys_addr: ffffff9f0000 flags: 0x0 size: 0x100000
[  117.898504] pci_epf_enable_doorbell: success
[  118.912433] arm-smmu-v3 fc900000.iommu: event 0x10 received:
[  118.912965] arm-smmu-v3 fc900000.iommu:      0x0000000000000010
[  118.913508] arm-smmu-v3 fc900000.iommu:      0x0000020000000000
[  118.914018] arm-smmu-v3 fc900000.iommu:      0x0000ffffff90f040
[  118.914534] arm-smmu-v3 fc900000.iommu:      0x0000000000000000

Looking at the doorbell_addr, it seems to be a IOMMU address already.

If we look at the ARM SMMU-v3 specification, event 0x10 is:
Translation fault: The address provided to a stage of translation failed the
range check defined by TxSZ/SLx, the address was within a disabled TTBx, or a
valid translation table descriptor was not found for the address.

for event F_TRANSLATION:
0x0000ffffff90f040
is input address.

StreamID is: 0x0, so that looks as expected for rk3588.
(And if the SteamID was incorrect, I would have expected a C_BAD_STREAMID
event instead.)


Comparing the address of the IOMMU error:
0xffffff90f040
with the doorbell addr:
0xffffff9ff040
XOR value:
0x0000000f0000

We can see that they are not identical.


When RC side does:
devmem $((0xf0400000+0xf040)) 32 0
it results in the exact same IOMMU error on the EP side as the one above.

However, if I manually append the XOR value:
devmem $((0xf0400000+0xf040+0xf0000)) 32 0

I can see on the EP side:
[  631.399530] pci_epf_doorbell_handler
[  631.399850] pci_epf_test_doorbell



So why is the inbound translation incorrect?

Like I told you earlier, rk3588 has fixed size 1MB BARs,
so the BAR_MASK will be:
~(SZ_1M-1)
0xfff00000

So the physical address that you write in the iATU:
0xffffff9f0000
will actually be:
0xfffffff00000
after reading back the same register from the iATU,
since the lower bits will be masked away.

I'm guessing that you would need to do something like:
diff --git a/drivers/pci/endpoint/functions/pci-epf-test.c b/drivers/pci/endpoint/functions/pci-epf-test.c
index e5b6a65e3e16f..0ab5d61bf0493 100644
--- a/drivers/pci/endpoint/functions/pci-epf-test.c
+++ b/drivers/pci/endpoint/functions/pci-epf-test.c
@@ -675,6 +675,9 @@ static void pci_epf_enable_doorbell(struct pci_epf_test *epf_test, struct pci_ep
                return;
        }
 
+       if (epf_test->epc_features->bar[bar].type == BAR_FIXED)
+               align = max(epf_test->epc_features->bar[bar].fixed_size, align);
+
        msg = &epf->db_msg[0].msg;
        doorbell_addr = msg->address_hi;
        doorbell_addr <<= 32;
@@ -1016,15 +1021,22 @@ static int pci_epf_test_bind(struct pci_epf *epf)
                struct msi_msg *msg = &epf->db_msg[0].msg;
                u32 align = epc_features->align;
                u64 doorbell_addr;
+               enum pci_barno bar;
+
+               bar = pci_epc_get_next_free_bar(epc_features, test_reg_bar + 1);
 
                align = align ? align : 128;
+               if (epf_test->epc_features->bar[bar].type == BAR_FIXED)
+                       align = max(epf_test->epc_features->bar[bar].fixed_size,
+                                   align);
+
                doorbell_addr = msg->address_hi;
                doorbell_addr <<= 32;
                doorbell_addr |= msg->address_lo;
 
                reg->doorbell_addr = doorbell_addr & (align - 1);
                reg->doorbell_data = msg->data;
-               reg->doorbell_bar = pci_epc_get_next_free_bar(epc_features, test_reg_bar + 1);
+               reg->doorbell_bar = bar;
        }
 
        return 0;



I tested the above on top of your series, and now
pcitest -B
works as expected :) yay!


Kind regards,
Niklas