[PATCH 1/3] amd/pci: Add supports for generic AMD hostbridges

From: suravee.suthikulpanit
Date: Wed Mar 05 2014 - 16:07:32 EST


From: Suravee Suthikulpanit <suravee.suthikulpanit@xxxxxxx>

AMD hostbridges are gnenerally show up as PCI device 0:18.0.
This patch adds logic to automatically probe the device at
this location and check PCI device class code.

This patch should support AMD hostbridges from AMD platforms
(K8, family10h, 11h, 12h, 14h 15h and 16h processors).

Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@xxxxxxx>
Tested-by: Aravind Gopalakrishnan <Aravind.Gopalakrishnan@xxxxxxx>
---
arch/x86/pci/amd_bus.c | 88 +++++++++++++++++++++++++++++++++---------------
1 file changed, 60 insertions(+), 28 deletions(-)

diff --git a/arch/x86/pci/amd_bus.c b/arch/x86/pci/amd_bus.c
index a48be98..4041cbe 100644
--- a/arch/x86/pci/amd_bus.c
+++ b/arch/x86/pci/amd_bus.c
@@ -11,27 +11,39 @@

#include "bus_numa.h"

+#define AMD_NB_F0_NODE_ID 0x60
+#define AMD_NB_F0_UNIT_ID 0x64
+#define AMD_NB_F1_MMIO_BASE_REG 0x80
+#define AMD_NB_F1_MMIO_LIMIT_REG 0x84
+#define AMD_NB_F1_IO_BASEA_DDR_REG 0xc0
+#define AMD_NB_F1_IO_LIMIT_ADDR_REG 0xc4
+#define AMD_NB_F1_CONFIG_MAP_REG 0xe0
+
+#define RANGE_NUM 16
+#define AMD_NB_F1_MMIO_RANGES 8
+#define AMD_NB_F1_IOPORT_RANGES 4
+#define AMD_NB_F1_CONFIG_MAP_RANGES 4
+
/*
* This discovers the pcibus <-> node mapping on AMD K8.
* also get peer root bus resource for io,mmio
*/

-struct pci_hostbridge_probe {
+struct amd_hostbridge {
u32 bus;
u32 slot;
- u32 vendor;
u32 device;
};

-static struct pci_hostbridge_probe pci_probes[] __initdata = {
- { 0, 0x18, PCI_VENDOR_ID_AMD, 0x1100 },
- { 0, 0x18, PCI_VENDOR_ID_AMD, 0x1200 },
- { 0xff, 0, PCI_VENDOR_ID_AMD, 0x1200 },
- { 0, 0x18, PCI_VENDOR_ID_AMD, 0x1300 },
+static struct amd_hostbridge hb_probes[] __initdata = {
+ /* Standard AMD Hostbriges is at bus 0x0 slot 0x18.
+ * In case of PCI_ANY_ID, the logic will try matching
+ * PCI_CLASS_BRIDGE_HOST instead.
+ */
+ { 0x0 , 0x18, PCI_ANY_ID },
+ { 0xff, 0 , PCI_DEVICE_ID_AMD_10H_NB_HT },
};

-#define RANGE_NUM 16
-
static struct pci_root_info __init *find_pci_root_info(int node, int link)
{
struct pci_root_info *info;
@@ -84,31 +96,47 @@ static int __init early_fill_mp_bus_info(void)
return -1;

found = false;
- for (i = 0; i < ARRAY_SIZE(pci_probes); i++) {
+ for (i = 0; i < ARRAY_SIZE(hb_probes); i++) {
u32 id;
u16 device;
u16 vendor;
+ u32 class;

- bus = pci_probes[i].bus;
- slot = pci_probes[i].slot;
+ bus = hb_probes[i].bus;
+ slot = hb_probes[i].slot;
id = read_pci_config(bus, slot, 0, PCI_VENDOR_ID);
-
vendor = id & 0xffff;
device = (id>>16) & 0xffff;
- if (pci_probes[i].vendor == vendor &&
- pci_probes[i].device == device) {
- found = true;
- break;
+ class = read_pci_config(bus, slot, 0,
+ PCI_CLASS_REVISION) >> 16;
+
+ if (PCI_VENDOR_ID_AMD == vendor) {
+ if (hb_probes[i].device == device) {
+ found = true;
+ break;
+ }
+
+ if ((hb_probes[i].device == PCI_ANY_ID) &&
+ (class == PCI_CLASS_BRIDGE_HOST)) {
+ hb_probes[i].device = device;
+ found = true;
+ break;
+ }
}
}

- if (!found)
+ if (!found) {
+ printk(KERN_WARNING "AMD hostbridge not found\n");
return 0;
+ }
+
+ printk(KERN_DEBUG "Found AMD hostbridge at %x:%x.0\n", bus, slot);

- for (i = 0; i < 4; i++) {
+ for (i = 0; i < AMD_NB_F1_CONFIG_MAP_RANGES; i++) {
int min_bus;
int max_bus;
- reg = read_pci_config(bus, slot, 1, 0xe0 + (i << 2));
+ reg = read_pci_config(bus, slot, 1,
+ AMD_NB_F1_CONFIG_MAP_REG + (i << 2));

/* Check if that register is enabled for bus range */
if ((reg & 7) != 3)
@@ -124,21 +152,23 @@ static int __init early_fill_mp_bus_info(void)
}

/* get the default node and link for left over res */
- reg = read_pci_config(bus, slot, 0, 0x60);
+ reg = read_pci_config(bus, slot, 0, AMD_NB_F0_NODE_ID);
def_node = (reg >> 8) & 0x07;
- reg = read_pci_config(bus, slot, 0, 0x64);
+ reg = read_pci_config(bus, slot, 0, AMD_NB_F0_UNIT_ID);
def_link = (reg >> 8) & 0x03;

memset(range, 0, sizeof(range));
add_range(range, RANGE_NUM, 0, 0, 0xffff + 1);
/* io port resource */
- for (i = 0; i < 4; i++) {
- reg = read_pci_config(bus, slot, 1, 0xc0 + (i << 3));
+ for (i = 0; i < AMD_NB_F1_IOPORT_RANGES; i++) {
+ reg = read_pci_config(bus, slot, 1,
+ AMD_NB_F1_IO_BASEA_DDR_REG + (i << 3));
if (!(reg & 3))
continue;

start = reg & 0xfff000;
- reg = read_pci_config(bus, slot, 1, 0xc4 + (i << 3));
+ reg = read_pci_config(bus, slot, 1,
+ AMD_NB_F1_IO_LIMIT_ADDR_REG + (i << 3));
node = reg & 0x07;
link = (reg >> 4) & 0x03;
end = (reg & 0xfff000) | 0xfff;
@@ -198,14 +228,16 @@ static int __init early_fill_mp_bus_info(void)
}

/* mmio resource */
- for (i = 0; i < 8; i++) {
- reg = read_pci_config(bus, slot, 1, 0x80 + (i << 3));
+ for (i = 0; i < AMD_NB_F1_MMIO_RANGES; i++) {
+ reg = read_pci_config(bus, slot, 1,
+ AMD_NB_F1_MMIO_BASE_REG + (i << 3));
if (!(reg & 3))
continue;

start = reg & 0xffffff00; /* 39:16 on 31:8*/
start <<= 8;
- reg = read_pci_config(bus, slot, 1, 0x84 + (i << 3));
+ reg = read_pci_config(bus, slot, 1,
+ AMD_NB_F1_MMIO_LIMIT_REG + (i << 3));
node = reg & 0x07;
link = (reg >> 4) & 0x03;
end = (reg & 0xffffff00);
--
1.7.10.4


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/