Raul Rangel has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/48632 )
Change subject: soc/amd/picasso: Fix PCI routing table ......................................................................
soc/amd/picasso: Fix PCI routing table
The original routing table did not handle all 8 INTx interrupts. Additionally it also didn't take the swizzling into account.
Now that we know how AGESA programs the routing table we can correctly generate it.
We still route the PCI interrupts through the FCH IOAPIC. A follow up will have the GNB IOAPIC handle the PCI interrupts.
There is still work to be done to fix the legacy PCI_IRQ register for each PCI device. We can then remove the mainboard_pirq_data from each mainboard.
Signed-off-by: Raul E Rangel rrangel@chromium.org Change-Id: I2b2cce9913081d5cd456043ba619a79c1dfd4a8e --- M src/soc/amd/picasso/acpi/northbridge.asl M src/soc/amd/picasso/acpi/pci_int.asl M src/soc/amd/picasso/pcie_gpp.c 3 files changed, 153 insertions(+), 14 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/32/48632/1
diff --git a/src/soc/amd/picasso/acpi/northbridge.asl b/src/soc/amd/picasso/acpi/northbridge.asl index a81d3b2..f6e198f 100644 --- a/src/soc/amd/picasso/acpi/northbridge.asl +++ b/src/soc/amd/picasso/acpi/northbridge.asl @@ -26,18 +26,6 @@ Package() { 0x0000FFFF, 0, INTC, 0 }, Package() { 0x0000FFFF, 0, INTD, 0 },
- /* Bus 0, Dev 0x01 - F[1-7]: GPP PCI Bridges */ - Package() { 0x0001FFFF, 0, INTA, 0 }, - Package() { 0x0001FFFF, 1, INTB, 0 }, - Package() { 0x0001FFFF, 2, INTC, 0 }, - Package() { 0x0001FFFF, 3, INTD, 0 }, - - /* Bus 0, Dev 0x08 - F[1:PCI Bridge to Bus A, 2: PCI Bridge to Bus B] */ - Package() { 0x0008FFFF, 0, INTA, 0 }, - Package() { 0x0008FFFF, 1, INTB, 0 }, - Package() { 0x0008FFFF, 2, INTC, 0 }, - Package() { 0x0008FFFF, 3, INTD, 0 }, - /* Bus 0, Dev 0x14 - F[0:SMBus 3:LPC] */ Package() { 0x0014FFFF, 0, INTA, 0 }, Package() { 0x0014FFFF, 1, INTB, 0 }, diff --git a/src/soc/amd/picasso/acpi/pci_int.asl b/src/soc/amd/picasso/acpi/pci_int.asl index 2a2a561..4f723e9 100644 --- a/src/soc/amd/picasso/acpi/pci_int.asl +++ b/src/soc/amd/picasso/acpi/pci_int.asl @@ -104,3 +104,7 @@ PCI_LINK(INTB, PIRB, IORB) PCI_LINK(INTC, PIRC, IORC) PCI_LINK(INTD, PIRD, IORD) +PCI_LINK(INTE, PIRE, IORE) +PCI_LINK(INTF, PIRF, IORF) +PCI_LINK(INTG, PIRG, IORG) +PCI_LINK(INTH, PIRH, IORH) diff --git a/src/soc/amd/picasso/pcie_gpp.c b/src/soc/amd/picasso/pcie_gpp.c index 96d33f2..80ef7e7 100644 --- a/src/soc/amd/picasso/pcie_gpp.c +++ b/src/soc/amd/picasso/pcie_gpp.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */
#include <acpi/acpigen.h> +#include <assert.h> #include <device/device.h> #include <device/pci.h> #include <device/pciexp.h> @@ -8,6 +9,44 @@ #include <soc/pci_devs.h> #include <stdio.h>
+/** + * Each PCI bridge has its INTx lines routed to one of the 8 GNB IOAPIC PCI + * groups. Each group has 4 interrupts. The INTx lines can be swizzled before + * being routed to the IOAPIC. If the IOAPIC redirection entry is masked, the + * interrupt are reduced modulo 8 on 8 interrupts (INTA-INTH) and forwarded to + * the FCH IOAPIC. + **/ +struct pci_routing { + unsigned int devfn; + unsigned int group; + const char intx[5]; +}; + +/* See AMD PPR 55570 - IOAPIC Initialization for the table that AGESA sets up */ +static const struct pci_routing pci_routing_table[] = { + {PCIE_GPP_0_DEVFN, 0, "ABCD"}, + {PCIE_GPP_1_DEVFN, 1, "ABCD"}, + {PCIE_GPP_2_DEVFN, 2, "ABCD"}, + {PCIE_GPP_3_DEVFN, 3, "ABCD"}, + {PCIE_GPP_4_DEVFN, 4, "ABCD"}, + {PCIE_GPP_5_DEVFN, 5, "ABCD"}, + {PCIE_GPP_6_DEVFN, 6, "ABCD"}, + {PCIE_GPP_A_DEVFN, 7, "ABCD"}, + {PCIE_GPP_B_DEVFN, 7, "CDAB"}, +}; + +static const struct pci_routing *get_pci_routing(const struct device *dev) +{ + for (size_t i = 0; i < ARRAY_SIZE(pci_routing_table); ++i) { + printk(BIOS_ERR, "%s %s %d , %d\n", __func__, dev_path(dev), + dev->path.pci.devfn, pci_routing_table[i].devfn); + if (dev->path.pci.devfn == pci_routing_table[i].devfn) + return &pci_routing_table[i]; + } + + return NULL; +} + static const char *pcie_gpp_acpi_name(const struct device *dev) { if (dev->path.type != DEVICE_PATH_PCI) @@ -37,6 +76,114 @@ return NULL; }
+static void acpigen_write_PRT(const struct device *dev) +{ + char link_template[] = "\_SB.INTX"; + unsigned int irq_index; + + const struct pci_routing *pci_routing = get_pci_routing(dev); + if (pci_routing == NULL) { + printk(BIOS_ERR, "PCI routing table not found for %s\n", dev_path(dev)); + return; + } + + acpigen_write_method("_PRT", 0); + acpigen_emit_byte(RETURN_OP); + + acpigen_write_package(4); + for (unsigned int i = 0; i < 4; ++i) { + irq_index = pci_routing->group * 4; + irq_index += pci_routing->intx[i] - 'A'; + + link_template[8] = 'A' + (irq_index % 8); + + acpigen_write_package(4); + acpigen_write_dword(0x0000FFFF); + acpigen_write_byte(i); + acpigen_emit_namestring(link_template); + acpigen_write_dword(0); + acpigen_pop_len(); + } + acpigen_pop_len(); /* Package */ + + acpigen_pop_len(); /* Method */ +} + +/* + * This function writes a PCI device with _ADR, _STA, and _PRT objects: + * Example: + * Scope (_SB.PCI0) + * { + * Device (PBRA) + * { + * Name (_ADR, 0x0000000000080001) // _ADR: Address + * Method (_STA, 0, NotSerialized) // _STA: Status + * { + * Return (0x0F) + * } + * + * Method (_PRT, 0, NotSerialized) // _PRT: PCI Routing Table + * { + * Return (Package (0x04) + * { + * Package (0x04) + * { + * 0x0000FFFF, + * 0x00, + * _SB.INTE, + * 0x00000000 + * }, + * + * Package (0x04) + * { + * 0x0000FFFF, + * 0x01, + * _SB.INTF, + * 0x00000000 + * }, + * + * Package (0x04) + * { + * 0x0000FFFF, + * 0x02, + * _SB.INTG, + * 0x00000000 + * }, + * + * Package (0x04) + * { + * 0x0000FFFF, + * 0x03, + * _SB.INTH, + * 0x00000000 + * } + * }) + * } + * } + * } + */ +static void acpi_device_write_gpp_pci_dev(const struct device *dev) +{ + const char *scope = acpi_device_scope(dev); + const char *name = acpi_device_name(dev); + + assert(dev->path.type == DEVICE_PATH_PCI); + assert(name); + assert(scope); + + acpigen_write_scope(scope); + acpigen_write_device(name); + + acpigen_write_ADR_pci_device(dev); + acpigen_write_STA(acpi_device_status(dev)); + + acpigen_write_PRT(dev); + + acpigen_pop_len(); /* Device */ + acpigen_pop_len(); /* Scope */ +} + + static struct device_operations internal_pcie_gpp_ops = { .read_resources = pci_bus_read_resources, .set_resources = pci_dev_set_resources, @@ -44,7 +191,7 @@ .scan_bus = pci_scan_bridge, .reset_bus = pci_bus_reset, .acpi_name = pcie_gpp_acpi_name, - .acpi_fill_ssdt = acpi_device_write_pci_dev, + .acpi_fill_ssdt = acpi_device_write_gpp_pci_dev, };
static const unsigned short pci_device_ids[] = { @@ -66,7 +213,7 @@ .scan_bus = pciexp_scan_bridge, .reset_bus = pci_bus_reset, .acpi_name = pcie_gpp_acpi_name, - .acpi_fill_ssdt = acpi_device_write_pci_dev, + .acpi_fill_ssdt = acpi_device_write_gpp_pci_dev, };
static const struct pci_driver external_pcie_gpp_driver __pci_driver = {
Hello build bot (Jenkins), Jason Glenesk, Marshall Dawson, Felix Held,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/48632
to look at the new patch set (#2).
Change subject: soc/amd/picasso: Fix PCI routing table ......................................................................
soc/amd/picasso: Fix PCI routing table
The original routing table did not handle all 8 INTx interrupts. Additionally it also didn't take the swizzling into account.
Now that we know how AGESA programs the routing table we can correctly generate it.
We still route the PCI interrupts through the FCH IOAPIC. A follow up will have the GNB IOAPIC handle the PCI interrupts.
There is still work to be done to fix the legacy PCI_IRQ register for each PCI device. We can then remove the mainboard_pirq_data from each mainboard.
BUG=b:170595019 TEST=Used ezkinil Boot kernel with `pci=nomsi amd_iommu=off noapic` and `pci=nomsi amd_iommu=off` then verified system was usable and verified /proc/interrupts looked correct.
Signed-off-by: Raul E Rangel rrangel@chromium.org Change-Id: I2b2cce9913081d5cd456043ba619a79c1dfd4a8e --- M src/soc/amd/picasso/acpi/northbridge.asl M src/soc/amd/picasso/acpi/pci_int.asl M src/soc/amd/picasso/pcie_gpp.c 3 files changed, 153 insertions(+), 14 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/32/48632/2
Hello build bot (Jenkins), Jason Glenesk, Marshall Dawson, Felix Held,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/48632
to look at the new patch set (#3).
Change subject: soc/amd/picasso: Fix PCI routing table ......................................................................
soc/amd/picasso: Fix PCI routing table
The original routing table did not handle all 8 INTx interrupts. Additionally it also didn't take the swizzling into account.
Now that we know how AGESA programs the routing table we can correctly generate it.
We still route the PCI interrupts through the FCH IOAPIC. A follow up will have the GNB IOAPIC handle the PCI interrupts.
There is still work to be done to fix the legacy PCI_IRQ register for each PCI device. We can then remove the mainboard_pirq_data from each mainboard.
BUG=b:170595019 TEST=Used ezkinil Boot kernel with `pci=nomsi amd_iommu=off noapic` and `pci=nomsi amd_iommu=off` then verified system was usable and verified /proc/interrupts looked correct.
Signed-off-by: Raul E Rangel rrangel@chromium.org Change-Id: I2b2cce9913081d5cd456043ba619a79c1dfd4a8e --- M src/soc/amd/picasso/acpi/northbridge.asl M src/soc/amd/picasso/acpi/pci_int.asl M src/soc/amd/picasso/pcie_gpp.c 3 files changed, 153 insertions(+), 14 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/32/48632/3
Hello build bot (Jenkins), Jason Glenesk, Marshall Dawson, Felix Held,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/coreboot/+/48632
to look at the new patch set (#4).
Change subject: soc/amd/picasso: Fix ACPI PCI routing table ......................................................................
soc/amd/picasso: Fix ACPI PCI routing table
The original routing table did not handle all 8 INTx interrupts. Additionally it also didn't take the swizzling into account.
Now that we know how AGESA programs the routing table we can correctly generate it.
We still route the PCI interrupts through the FCH IOAPIC. A follow up will have the GNB IOAPIC handle the PCI interrupts.
There is still work to be done to fix the legacy PCI_IRQ register for each PCI device. We can then remove the mainboard_pirq_data from each mainboard.
BUG=b:170595019 TEST=Used ezkinil Boot kernel with `pci=nomsi amd_iommu=off noapic` and `pci=nomsi amd_iommu=off` then verified system was usable and verified /proc/interrupts looked correct.
Signed-off-by: Raul E Rangel rrangel@chromium.org Change-Id: I2b2cce9913081d5cd456043ba619a79c1dfd4a8e --- M src/soc/amd/picasso/acpi/northbridge.asl M src/soc/amd/picasso/acpi/pci_int.asl M src/soc/amd/picasso/pcie_gpp.c 3 files changed, 158 insertions(+), 14 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/32/48632/4
Nikolai Vyssotski has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/48632 )
Change subject: soc/amd/picasso: Fix ACPI PCI routing table ......................................................................
Patch Set 4: Code-Review+1
Felix Held has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/48632 )
Change subject: soc/amd/picasso: Fix ACPI PCI routing table ......................................................................
Patch Set 4:
(1 comment)
https://review.coreboot.org/c/coreboot/+/48632/4/src/soc/amd/picasso/pcie_gp... File src/soc/amd/picasso/pcie_gpp.c:
https://review.coreboot.org/c/coreboot/+/48632/4/src/soc/amd/picasso/pcie_gp... PS4, Line 51: pci_routing->intx[i] - 'A' should we check here if it's in the expected range?
Raul Rangel has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/48632 )
Change subject: soc/amd/picasso: Fix ACPI PCI routing table ......................................................................
Patch Set 4:
(1 comment)
https://review.coreboot.org/c/coreboot/+/48632/4/src/soc/amd/picasso/pcie_gp... File src/soc/amd/picasso/pcie_gpp.c:
https://review.coreboot.org/c/coreboot/+/48632/4/src/soc/amd/picasso/pcie_gp... PS4, Line 51: pci_routing->intx[i] - 'A'
should we check here if it's in the expected range?
The pci_routing_table is self contained, so I didn't see a reason to add additional validation. If the data was coming from an external source then we would need to validate it.
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/48632 )
Change subject: soc/amd/picasso: Fix ACPI PCI routing table ......................................................................
Patch Set 4:
(1 comment)
https://review.coreboot.org/c/coreboot/+/48632/4/src/soc/amd/picasso/pcie_gp... File src/soc/amd/picasso/pcie_gpp.c:
https://review.coreboot.org/c/coreboot/+/48632/4/src/soc/amd/picasso/pcie_gp... PS4, Line 103: % 8 I don't understand where this `% 8` here comes from, especially considering the `* 4` in `calculate_irq`.
Raul Rangel has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/48632 )
Change subject: soc/amd/picasso: Fix ACPI PCI routing table ......................................................................
Patch Set 4:
(1 comment)
https://review.coreboot.org/c/coreboot/+/48632/4/src/soc/amd/picasso/pcie_gp... File src/soc/amd/picasso/pcie_gpp.c:
https://review.coreboot.org/c/coreboot/+/48632/4/src/soc/amd/picasso/pcie_gp... PS4, Line 103: % 8
I don't understand where this `% 8` here comes from, especially considering the `* 4` in `calculate_ […]
Take GPP6 INTC for example, 6 * 4 + 2 = 26. That would be the redirection table entry in the NB-IOAPIC. This is then reduced mod 8 and passed into the the FCH-IOAPIC because the FCH-IOAPIC only has 8 INTx lines. i.e. INT[A-H].
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/48632 )
Change subject: soc/amd/picasso: Fix ACPI PCI routing table ......................................................................
Patch Set 4:
(1 comment)
https://review.coreboot.org/c/coreboot/+/48632/4/src/soc/amd/picasso/pcie_gp... File src/soc/amd/picasso/pcie_gpp.c:
https://review.coreboot.org/c/coreboot/+/48632/4/src/soc/amd/picasso/pcie_gp... PS4, Line 103: % 8
Take GPP6 INTC for example, 6 * 4 + 2 = 26. […]
Ah, makes sense now. Thanks.
Felix Held has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/48632 )
Change subject: soc/amd/picasso: Fix ACPI PCI routing table ......................................................................
Patch Set 4:
(2 comments)
https://review.coreboot.org/c/coreboot/+/48632/4/src/soc/amd/picasso/pcie_gp... File src/soc/amd/picasso/pcie_gpp.c:
https://review.coreboot.org/c/coreboot/+/48632/4/src/soc/amd/picasso/pcie_gp... PS4, Line 51: pci_routing->intx[i] - 'A'
The pci_routing_table is self contained, so I didn't see a reason to add additional validation. […]
ok
https://review.coreboot.org/c/coreboot/+/48632/4/src/soc/amd/picasso/pcie_gp... PS4, Line 106: 0x0000FFFF shouldn't this rather be: PCI_SLOT(dev->path.pci.devfn) << 16 | 0xffff
the spec says that the lower 2 bytes need to be ffff and the rest needs to have the format used in _ADR where the device number is encoded in the upper 2 bytes
Raul Rangel has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/48632 )
Change subject: soc/amd/picasso: Fix ACPI PCI routing table ......................................................................
Patch Set 4:
(1 comment)
https://review.coreboot.org/c/coreboot/+/48632/4/src/soc/amd/picasso/pcie_gp... File src/soc/amd/picasso/pcie_gpp.c:
https://review.coreboot.org/c/coreboot/+/48632/4/src/soc/amd/picasso/pcie_gp... PS4, Line 106: 0x0000FFFF
shouldn't this rather be: […]
It's 0x0000FFFF because there is only one device on each bridge:
-[0000:00]-+-00.0 +-00.2 +-01.0 +-01.2-[01]----00.0 <-- 00.X +-01.3-[02]----00.0 <-- 00.X +-08.0 +-08.1-[03]--+-00.0 <-- 00.X | +-00.1 | +-00.2 | +-00.3 | +-00.5 | -00.7
Felix Held has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/48632 )
Change subject: soc/amd/picasso: Fix ACPI PCI routing table ......................................................................
Patch Set 4:
(1 comment)
https://review.coreboot.org/c/coreboot/+/48632/4/src/soc/amd/picasso/pcie_gp... File src/soc/amd/picasso/pcie_gpp.c:
https://review.coreboot.org/c/coreboot/+/48632/4/src/soc/amd/picasso/pcie_gp... PS4, Line 106: 0x0000FFFF
It's 0x0000FFFF because there is only one device on each bridge: […]
ah, that makes sense. maybe add a comment on that, since it wasn't obvious to me when i had a look
Felix Held has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/48632 )
Change subject: soc/amd/picasso: Fix ACPI PCI routing table ......................................................................
Patch Set 4: Code-Review+2
apart from that one comment that patch is a +2 for me. not sure if you want to add the comment in this patch or in a follow-up to get this one merged now
Raul Rangel has posted comments on this change. ( https://review.coreboot.org/c/coreboot/+/48632 )
Change subject: soc/amd/picasso: Fix ACPI PCI routing table ......................................................................
Patch Set 4:
Patch Set 4: Code-Review+2
apart from that one comment that patch is a +2 for me. not sure if you want to add the comment in this patch or in a follow-up to get this one merged now
I can do it in a follow-up to avoid pushing a new change.
Felix Held has submitted this change. ( https://review.coreboot.org/c/coreboot/+/48632 )
Change subject: soc/amd/picasso: Fix ACPI PCI routing table ......................................................................
soc/amd/picasso: Fix ACPI PCI routing table
The original routing table did not handle all 8 INTx interrupts. Additionally it also didn't take the swizzling into account.
Now that we know how AGESA programs the routing table we can correctly generate it.
We still route the PCI interrupts through the FCH IOAPIC. A follow up will have the GNB IOAPIC handle the PCI interrupts.
There is still work to be done to fix the legacy PCI_IRQ register for each PCI device. We can then remove the mainboard_pirq_data from each mainboard.
BUG=b:170595019 TEST=Used ezkinil Boot kernel with `pci=nomsi amd_iommu=off noapic` and `pci=nomsi amd_iommu=off` then verified system was usable and verified /proc/interrupts looked correct.
Signed-off-by: Raul E Rangel rrangel@chromium.org Change-Id: I2b2cce9913081d5cd456043ba619a79c1dfd4a8e Reviewed-on: https://review.coreboot.org/c/coreboot/+/48632 Tested-by: build bot (Jenkins) no-reply@coreboot.org Reviewed-by: Nikolai Vyssotski nikolai.vyssotski@amd.corp-partner.google.com Reviewed-by: Felix Held felix-coreboot@felixheld.de --- M src/soc/amd/picasso/acpi/northbridge.asl M src/soc/amd/picasso/acpi/pci_int.asl M src/soc/amd/picasso/pcie_gpp.c 3 files changed, 158 insertions(+), 14 deletions(-)
Approvals: build bot (Jenkins): Verified Felix Held: Looks good to me, approved Nikolai Vyssotski: Looks good to me, but someone else must approve
diff --git a/src/soc/amd/picasso/acpi/northbridge.asl b/src/soc/amd/picasso/acpi/northbridge.asl index a81d3b2..f6e198f 100644 --- a/src/soc/amd/picasso/acpi/northbridge.asl +++ b/src/soc/amd/picasso/acpi/northbridge.asl @@ -26,18 +26,6 @@ Package() { 0x0000FFFF, 0, INTC, 0 }, Package() { 0x0000FFFF, 0, INTD, 0 },
- /* Bus 0, Dev 0x01 - F[1-7]: GPP PCI Bridges */ - Package() { 0x0001FFFF, 0, INTA, 0 }, - Package() { 0x0001FFFF, 1, INTB, 0 }, - Package() { 0x0001FFFF, 2, INTC, 0 }, - Package() { 0x0001FFFF, 3, INTD, 0 }, - - /* Bus 0, Dev 0x08 - F[1:PCI Bridge to Bus A, 2: PCI Bridge to Bus B] */ - Package() { 0x0008FFFF, 0, INTA, 0 }, - Package() { 0x0008FFFF, 1, INTB, 0 }, - Package() { 0x0008FFFF, 2, INTC, 0 }, - Package() { 0x0008FFFF, 3, INTD, 0 }, - /* Bus 0, Dev 0x14 - F[0:SMBus 3:LPC] */ Package() { 0x0014FFFF, 0, INTA, 0 }, Package() { 0x0014FFFF, 1, INTB, 0 }, diff --git a/src/soc/amd/picasso/acpi/pci_int.asl b/src/soc/amd/picasso/acpi/pci_int.asl index 8114c52..feaec12 100644 --- a/src/soc/amd/picasso/acpi/pci_int.asl +++ b/src/soc/amd/picasso/acpi/pci_int.asl @@ -104,3 +104,7 @@ PCI_LINK(INTB, PIRB, IORB) PCI_LINK(INTC, PIRC, IORC) PCI_LINK(INTD, PIRD, IORD) +PCI_LINK(INTE, PIRE, IORE) +PCI_LINK(INTF, PIRF, IORF) +PCI_LINK(INTG, PIRG, IORG) +PCI_LINK(INTH, PIRH, IORH) diff --git a/src/soc/amd/picasso/pcie_gpp.c b/src/soc/amd/picasso/pcie_gpp.c index 3c3021e..1b65118 100644 --- a/src/soc/amd/picasso/pcie_gpp.c +++ b/src/soc/amd/picasso/pcie_gpp.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */
#include <acpi/acpigen.h> +#include <assert.h> #include <device/device.h> #include <device/pci.h> #include <device/pciexp.h> @@ -8,6 +9,50 @@ #include <soc/pci_devs.h> #include <stdio.h>
+/** + * Each PCI bridge has its INTx lines routed to one of the 8 GNB IOAPIC PCI + * groups. Each group has 4 interrupts. The INTx lines can be swizzled before + * being routed to the IOAPIC. If the IOAPIC redirection entry is masked, the + * interrupt is reduced modulo 8 onto INT[A-H] and forwarded to the FCH IOAPIC. + **/ +struct pci_routing { + unsigned int devfn; + unsigned int group; + const char intx[5]; +}; + +/* See AMD PPR 55570 - IOAPIC Initialization for the table that AGESA sets up */ +static const struct pci_routing pci_routing_table[] = { + {PCIE_GPP_0_DEVFN, 0, "ABCD"}, + {PCIE_GPP_1_DEVFN, 1, "ABCD"}, + {PCIE_GPP_2_DEVFN, 2, "ABCD"}, + {PCIE_GPP_3_DEVFN, 3, "ABCD"}, + {PCIE_GPP_4_DEVFN, 4, "ABCD"}, + {PCIE_GPP_5_DEVFN, 5, "ABCD"}, + {PCIE_GPP_6_DEVFN, 6, "ABCD"}, + {PCIE_GPP_A_DEVFN, 7, "ABCD"}, + {PCIE_GPP_B_DEVFN, 7, "CDAB"}, +}; + +static const struct pci_routing *get_pci_routing(unsigned int devfn) +{ + for (size_t i = 0; i < ARRAY_SIZE(pci_routing_table); ++i) { + if (devfn == pci_routing_table[i].devfn) + return &pci_routing_table[i]; + } + + return NULL; +} + +static unsigned int calculate_irq(const struct pci_routing *pci_routing, unsigned int i) +{ + unsigned int irq_index; + irq_index = pci_routing->group * 4; + irq_index += pci_routing->intx[i] - 'A'; + + return irq_index; +} + static const char *pcie_gpp_acpi_name(const struct device *dev) { if (dev->path.type != DEVICE_PATH_PCI) @@ -37,6 +82,113 @@ return NULL; }
+static void acpigen_write_PRT(const struct device *dev) +{ + char link_template[] = "\_SB.INTX"; + unsigned int irq_index; + + const struct pci_routing *pci_routing = get_pci_routing(dev->path.pci.devfn); + if (!pci_routing) { + printk(BIOS_ERR, "PCI routing table not found for %s\n", dev_path(dev)); + return; + } + + acpigen_write_method("_PRT", 0); + acpigen_emit_byte(RETURN_OP); + + acpigen_write_package(4); + for (unsigned int i = 0; i < 4; ++i) { + irq_index = calculate_irq(pci_routing, i); + + link_template[8] = 'A' + (irq_index % 8); + + acpigen_write_package(4); + acpigen_write_dword(0x0000FFFF); + acpigen_write_byte(i); + acpigen_emit_namestring(link_template); + acpigen_write_dword(0); + acpigen_pop_len(); + } + acpigen_pop_len(); /* Package */ + + acpigen_pop_len(); /* Method */ +} + +/* + * This function writes a PCI device with _ADR, _STA, and _PRT objects: + * Example: + * Scope (_SB.PCI0) + * { + * Device (PBRA) + * { + * Name (_ADR, 0x0000000000080001) // _ADR: Address + * Method (_STA, 0, NotSerialized) // _STA: Status + * { + * Return (0x0F) + * } + * + * Method (_PRT, 0, NotSerialized) // _PRT: PCI Routing Table + * { + * Return (Package (0x04) + * { + * Package (0x04) + * { + * 0x0000FFFF, + * 0x00, + * _SB.INTE, + * 0x00000000 + * }, + * + * Package (0x04) + * { + * 0x0000FFFF, + * 0x01, + * _SB.INTF, + * 0x00000000 + * }, + * + * Package (0x04) + * { + * 0x0000FFFF, + * 0x02, + * _SB.INTG, + * 0x00000000 + * }, + * + * Package (0x04) + * { + * 0x0000FFFF, + * 0x03, + * _SB.INTH, + * 0x00000000 + * } + * }) + * } + * } + * } + */ +static void acpi_device_write_gpp_pci_dev(const struct device *dev) +{ + const char *scope = acpi_device_scope(dev); + const char *name = acpi_device_name(dev); + + assert(dev->path.type == DEVICE_PATH_PCI); + assert(name); + assert(scope); + + acpigen_write_scope(scope); + acpigen_write_device(name); + + acpigen_write_ADR_pci_device(dev); + acpigen_write_STA(acpi_device_status(dev)); + + acpigen_write_PRT(dev); + + acpigen_pop_len(); /* Device */ + acpigen_pop_len(); /* Scope */ +} + + static struct device_operations internal_pcie_gpp_ops = { .read_resources = pci_bus_read_resources, .set_resources = pci_dev_set_resources, @@ -44,7 +196,7 @@ .scan_bus = pci_scan_bridge, .reset_bus = pci_bus_reset, .acpi_name = pcie_gpp_acpi_name, - .acpi_fill_ssdt = acpi_device_write_pci_dev, + .acpi_fill_ssdt = acpi_device_write_gpp_pci_dev, };
static const unsigned short pci_device_ids[] = { @@ -66,7 +218,7 @@ .scan_bus = pciexp_scan_bridge, .reset_bus = pci_bus_reset, .acpi_name = pcie_gpp_acpi_name, - .acpi_fill_ssdt = acpi_device_write_pci_dev, + .acpi_fill_ssdt = acpi_device_write_gpp_pci_dev, };
static const struct pci_driver external_pcie_gpp_driver __pci_driver = {