Commit 79d458bf authored by Bjorn Helgaas's avatar Bjorn Helgaas

Merge branches 'pci/host-exynos', 'pci/host-rcar' and 'pci/amd-numa' into next

* pci/host-exynos:
  PCI: exynos: Remove unnecessary OOM messages

* pci/host-rcar:
  PCI: rcar: Add gen2 device tree support
  PCI: rcar: Add R-Car PCIe device tree bindings
  PCI: rcar: Add MSI support for PCIe
  PCI: rcar: Add Renesas R-Car PCIe driver
  PCI: rcar: Use new OF interrupt mapping when possible

* pci/amd-numa:
  x86/PCI: Clean up and mark early_root_info_init() as deprecated
  x86/PCI: Work around AMD Fam15h BIOSes that fail to provide _PXM
  x86/PCI: Warn if we have to "guess" host bridge node information
Renesas AHB to PCI bridge
-------------------------
This is the bridge used internally to connect the USB controllers to the
AHB. There is one bridge instance per USB port connected to the internal
OHCI and EHCI controllers.
Required properties:
- compatible: "renesas,pci-r8a7790" for the R8A7790 SoC;
"renesas,pci-r8a7791" for the R8A7791 SoC.
- reg: A list of physical regions to access the device: the first is
the operational registers for the OHCI/EHCI controllers and the
second is for the bridge configuration and control registers.
- interrupts: interrupt for the device.
- clocks: The reference to the device clock.
- bus-range: The PCI bus number range; as this is a single bus, the range
should be specified as the same value twice.
- #address-cells: must be 3.
- #size-cells: must be 2.
- #interrupt-cells: must be 1.
- interrupt-map: standard property used to define the mapping of the PCI
interrupts to the GIC interrupts.
- interrupt-map-mask: standard property that helps to define the interrupt
mapping.
Example SoC configuration:
pci0: pci@ee090000 {
compatible = "renesas,pci-r8a7790";
clocks = <&mstp7_clks R8A7790_CLK_EHCI>;
reg = <0x0 0xee090000 0x0 0xc00>,
<0x0 0xee080000 0x0 0x1100>;
interrupts = <0 108 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
bus-range = <0 0>;
#address-cells = <3>;
#size-cells = <2>;
#interrupt-cells = <1>;
interrupt-map-mask = <0xff00 0 0 0x7>;
interrupt-map = <0x0000 0 0 1 &gic 0 108 IRQ_TYPE_LEVEL_HIGH
0x0800 0 0 1 &gic 0 108 IRQ_TYPE_LEVEL_HIGH
0x1000 0 0 2 &gic 0 108 IRQ_TYPE_LEVEL_HIGH>;
pci@0,1 {
reg = <0x800 0 0 0 0>;
device_type = "pci";
phys = <&usbphy 0 0>;
phy-names = "usb";
};
pci@0,2 {
reg = <0x1000 0 0 0 0>;
device_type = "pci";
phys = <&usbphy 0 0>;
phy-names = "usb";
};
};
Example board setup:
&pci0 {
status = "okay";
pinctrl-0 = <&usb0_pins>;
pinctrl-names = "default";
};
* Renesas RCar PCIe interface
Required properties:
- compatible: should contain one of the following
"renesas,pcie-r8a7779", "renesas,pcie-r8a7790", "renesas,pcie-r8a7791"
- reg: base address and length of the pcie controller registers.
- #address-cells: set to <3>
- #size-cells: set to <2>
- bus-range: PCI bus numbers covered
- device_type: set to "pci"
- ranges: ranges for the PCI memory and I/O regions.
- dma-ranges: ranges for the inbound memory regions.
- interrupts: two interrupt sources for MSI interrupts, followed by interrupt
source for hardware related interrupts (e.g. link speed change).
- #interrupt-cells: set to <1>
- interrupt-map-mask and interrupt-map: standard PCI properties
to define the mapping of the PCIe interface to interrupt
numbers.
- clocks: from common clock binding: clock specifiers for the PCIe controller
and PCIe bus clocks.
- clock-names: from common clock binding: should be "pcie" and "pcie_bus".
Example:
SoC specific DT Entry:
pcie: pcie@fe000000 {
compatible = "renesas,pcie-r8a7791";
reg = <0 0xfe000000 0 0x80000>;
#address-cells = <3>;
#size-cells = <2>;
bus-range = <0x00 0xff>;
device_type = "pci";
ranges = <0x01000000 0 0x00000000 0 0xfe100000 0 0x00100000
0x02000000 0 0xfe200000 0 0xfe200000 0 0x00200000
0x02000000 0 0x30000000 0 0x30000000 0 0x08000000
0x42000000 0 0x38000000 0 0x38000000 0 0x08000000>;
dma-ranges = <0x42000000 0 0x40000000 0 0x40000000 0 0x40000000
0x42000000 2 0x00000000 2 0x00000000 0 0x40000000>;
interrupts = <0 116 4>, <0 117 4>, <0 118 4>;
#interrupt-cells = <1>;
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0 0 0 0 &gic 0 116 4>;
clocks = <&mstp3_clks R8A7791_CLK_PCIE>, <&pcie_bus_clk>;
clock-names = "pcie", "pcie_bus";
status = "disabled";
};
...@@ -489,8 +489,12 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) ...@@ -489,8 +489,12 @@ struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
} }
node = acpi_get_node(device->handle); node = acpi_get_node(device->handle);
if (node == NUMA_NO_NODE) if (node == NUMA_NO_NODE) {
node = x86_pci_root_bus_node(busnum); node = x86_pci_root_bus_node(busnum);
if (node != 0 && node != NUMA_NO_NODE)
dev_info(&device->dev, FW_BUG "no _PXM; falling back to node %d from hardware (may be inconsistent with ACPI node numbers)\n",
node);
}
if (node != NUMA_NO_NODE && !node_online(node)) if (node != NUMA_NO_NODE && !node_online(node))
node = NUMA_NO_NODE; node = NUMA_NO_NODE;
......
...@@ -11,27 +11,33 @@ ...@@ -11,27 +11,33 @@
#include "bus_numa.h" #include "bus_numa.h"
/* #define AMD_NB_F0_NODE_ID 0x60
* This discovers the pcibus <-> node mapping on AMD K8. #define AMD_NB_F0_UNIT_ID 0x64
* also get peer root bus resource for io,mmio #define AMD_NB_F1_CONFIG_MAP_REG 0xe0
*/
struct pci_hostbridge_probe { #define RANGE_NUM 16
#define AMD_NB_F1_CONFIG_MAP_RANGES 4
struct amd_hostbridge {
u32 bus; u32 bus;
u32 slot; u32 slot;
u32 vendor;
u32 device; u32 device;
}; };
static struct pci_hostbridge_probe pci_probes[] __initdata = { /*
{ 0, 0x18, PCI_VENDOR_ID_AMD, 0x1100 }, * IMPORTANT NOTE:
{ 0, 0x18, PCI_VENDOR_ID_AMD, 0x1200 }, * hb_probes[] and early_root_info_init() is in maintenance mode.
{ 0xff, 0, PCI_VENDOR_ID_AMD, 0x1200 }, * It only supports K8, Fam10h, Fam11h, and Fam15h_00h-0fh .
{ 0, 0x18, PCI_VENDOR_ID_AMD, 0x1300 }, * Future processor will rely on information in ACPI.
*/
static struct amd_hostbridge hb_probes[] __initdata = {
{ 0, 0x18, 0x1100 }, /* K8 */
{ 0, 0x18, 0x1200 }, /* Family10h */
{ 0xff, 0, 0x1200 }, /* Family10h */
{ 0, 0x18, 0x1300 }, /* Family11h */
{ 0, 0x18, 0x1600 }, /* Family15h */
}; };
#define RANGE_NUM 16
static struct pci_root_info __init *find_pci_root_info(int node, int link) static struct pci_root_info __init *find_pci_root_info(int node, int link)
{ {
struct pci_root_info *info; struct pci_root_info *info;
...@@ -45,12 +51,12 @@ static struct pci_root_info __init *find_pci_root_info(int node, int link) ...@@ -45,12 +51,12 @@ static struct pci_root_info __init *find_pci_root_info(int node, int link)
} }
/** /**
* early_fill_mp_bus_to_node() * early_root_info_init()
* called before pcibios_scan_root and pci_scan_bus * called before pcibios_scan_root and pci_scan_bus
* fills the mp_bus_to_cpumask array based according to the LDT Bus Number * fills the mp_bus_to_cpumask array based according
* Registers found in the K8 northbridge * to the LDT Bus Number Registers found in the northbridge.
*/ */
static int __init early_fill_mp_bus_info(void) static int __init early_root_info_init(void)
{ {
int i; int i;
unsigned bus; unsigned bus;
...@@ -75,19 +81,21 @@ static int __init early_fill_mp_bus_info(void) ...@@ -75,19 +81,21 @@ static int __init early_fill_mp_bus_info(void)
return -1; return -1;
found = false; found = false;
for (i = 0; i < ARRAY_SIZE(pci_probes); i++) { for (i = 0; i < ARRAY_SIZE(hb_probes); i++) {
u32 id; u32 id;
u16 device; u16 device;
u16 vendor; u16 vendor;
bus = pci_probes[i].bus; bus = hb_probes[i].bus;
slot = pci_probes[i].slot; slot = hb_probes[i].slot;
id = read_pci_config(bus, slot, 0, PCI_VENDOR_ID); id = read_pci_config(bus, slot, 0, PCI_VENDOR_ID);
vendor = id & 0xffff; vendor = id & 0xffff;
device = (id>>16) & 0xffff; device = (id>>16) & 0xffff;
if (pci_probes[i].vendor == vendor &&
pci_probes[i].device == device) { if (vendor != PCI_VENDOR_ID_AMD)
continue;
if (hb_probes[i].device == device) {
found = true; found = true;
break; break;
} }
...@@ -96,10 +104,16 @@ static int __init early_fill_mp_bus_info(void) ...@@ -96,10 +104,16 @@ static int __init early_fill_mp_bus_info(void)
if (!found) if (!found)
return 0; return 0;
for (i = 0; i < 4; i++) { /*
* We should learn topology and routing information from _PXM and
* _CRS methods in the ACPI namespace. We extract node numbers
* here to work around BIOSes that don't supply _PXM.
*/
for (i = 0; i < AMD_NB_F1_CONFIG_MAP_RANGES; i++) {
int min_bus; int min_bus;
int max_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 */ /* Check if that register is enabled for bus range */
if ((reg & 7) != 3) if ((reg & 7) != 3)
...@@ -113,10 +127,21 @@ static int __init early_fill_mp_bus_info(void) ...@@ -113,10 +127,21 @@ static int __init early_fill_mp_bus_info(void)
info = alloc_pci_root_info(min_bus, max_bus, node, link); info = alloc_pci_root_info(min_bus, max_bus, node, link);
} }
/*
* The following code extracts routing information for use on old
* systems where Linux doesn't automatically use host bridge _CRS
* methods (or when the user specifies "pci=nocrs").
*
* We only do this through Fam11h, because _CRS should be enough on
* newer systems.
*/
if (boot_cpu_data.x86 > 0x11)
return 0;
/* get the default node and link for left over res */ /* 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; 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; def_link = (reg >> 8) & 0x03;
memset(range, 0, sizeof(range)); memset(range, 0, sizeof(range));
...@@ -387,7 +412,7 @@ static int __init amd_postcore_init(void) ...@@ -387,7 +412,7 @@ static int __init amd_postcore_init(void)
if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
return 0; return 0;
early_fill_mp_bus_info(); early_root_info_init();
pci_io_ecs_init(); pci_io_ecs_init();
return 0; return 0;
......
...@@ -33,4 +33,10 @@ config PCI_RCAR_GEN2 ...@@ -33,4 +33,10 @@ config PCI_RCAR_GEN2
There are 3 internal PCI controllers available with a single There are 3 internal PCI controllers available with a single
built-in EHCI/OHCI host controller present on each one. built-in EHCI/OHCI host controller present on each one.
config PCI_RCAR_GEN2_PCIE
bool "Renesas R-Car PCIe controller"
depends on ARCH_SHMOBILE || (ARM && COMPILE_TEST)
help
Say Y here if you want PCIe controller support on R-Car Gen2 SoCs.
endmenu endmenu
...@@ -4,3 +4,4 @@ obj-$(CONFIG_PCI_IMX6) += pci-imx6.o ...@@ -4,3 +4,4 @@ obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o obj-$(CONFIG_PCI_TEGRA) += pci-tegra.o
obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
obj-$(CONFIG_PCI_RCAR_GEN2_PCIE) += pcie-rcar.o
...@@ -568,10 +568,8 @@ static int __init exynos_pcie_probe(struct platform_device *pdev) ...@@ -568,10 +568,8 @@ static int __init exynos_pcie_probe(struct platform_device *pdev)
exynos_pcie = devm_kzalloc(&pdev->dev, sizeof(*exynos_pcie), exynos_pcie = devm_kzalloc(&pdev->dev, sizeof(*exynos_pcie),
GFP_KERNEL); GFP_KERNEL);
if (!exynos_pcie) { if (!exynos_pcie)
dev_err(&pdev->dev, "no memory for exynos pcie\n");
return -ENOMEM; return -ENOMEM;
}
pp = &exynos_pcie->pp; pp = &exynos_pcie->pp;
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/io.h> #include <linux/io.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_pci.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
...@@ -98,6 +99,7 @@ struct rcar_pci_priv { ...@@ -98,6 +99,7 @@ struct rcar_pci_priv {
struct resource io_res; struct resource io_res;
struct resource mem_res; struct resource mem_res;
struct resource *cfg_res; struct resource *cfg_res;
unsigned busnr;
int irq; int irq;
unsigned long window_size; unsigned long window_size;
}; };
...@@ -180,8 +182,13 @@ static int rcar_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin) ...@@ -180,8 +182,13 @@ static int rcar_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{ {
struct pci_sys_data *sys = dev->bus->sysdata; struct pci_sys_data *sys = dev->bus->sysdata;
struct rcar_pci_priv *priv = sys->private_data; struct rcar_pci_priv *priv = sys->private_data;
int irq;
return priv->irq; irq = of_irq_parse_and_map_pci(dev, slot, pin);
if (!irq)
irq = priv->irq;
return irq;
} }
#ifdef CONFIG_PCI_DEBUG #ifdef CONFIG_PCI_DEBUG
...@@ -312,8 +319,8 @@ static int rcar_pci_setup(int nr, struct pci_sys_data *sys) ...@@ -312,8 +319,8 @@ static int rcar_pci_setup(int nr, struct pci_sys_data *sys)
pci_add_resource(&sys->resources, &priv->io_res); pci_add_resource(&sys->resources, &priv->io_res);
pci_add_resource(&sys->resources, &priv->mem_res); pci_add_resource(&sys->resources, &priv->mem_res);
/* Setup bus number based on platform device id */ /* Setup bus number based on platform device id / of bus-range */
sys->busnr = to_platform_device(priv->dev)->id; sys->busnr = priv->busnr;
return 1; return 1;
} }
...@@ -366,6 +373,23 @@ static int rcar_pci_probe(struct platform_device *pdev) ...@@ -366,6 +373,23 @@ static int rcar_pci_probe(struct platform_device *pdev)
priv->window_size = SZ_1G; priv->window_size = SZ_1G;
if (pdev->dev.of_node) {
struct resource busnr;
int ret;
ret = of_pci_parse_bus_range(pdev->dev.of_node, &busnr);
if (ret < 0) {
dev_err(&pdev->dev, "failed to parse bus-range\n");
return ret;
}
priv->busnr = busnr.start;
if (busnr.end != busnr.start)
dev_warn(&pdev->dev, "only one bus number supported\n");
} else {
priv->busnr = pdev->id;
}
hw_private[0] = priv; hw_private[0] = priv;
memset(&hw, 0, sizeof(hw)); memset(&hw, 0, sizeof(hw));
hw.nr_controllers = ARRAY_SIZE(hw_private); hw.nr_controllers = ARRAY_SIZE(hw_private);
...@@ -377,11 +401,20 @@ static int rcar_pci_probe(struct platform_device *pdev) ...@@ -377,11 +401,20 @@ static int rcar_pci_probe(struct platform_device *pdev)
return 0; return 0;
} }
static struct of_device_id rcar_pci_of_match[] = {
{ .compatible = "renesas,pci-r8a7790", },
{ .compatible = "renesas,pci-r8a7791", },
{ },
};
MODULE_DEVICE_TABLE(of, rcar_pci_of_match);
static struct platform_driver rcar_pci_driver = { static struct platform_driver rcar_pci_driver = {
.driver = { .driver = {
.name = "pci-rcar-gen2", .name = "pci-rcar-gen2",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.suppress_bind_attrs = true, .suppress_bind_attrs = true,
.of_match_table = rcar_pci_of_match,
}, },
.probe = rcar_pci_probe, .probe = rcar_pci_probe,
}; };
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment