forked from Minki/linux
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
This commit is contained in:
commit
79d458bf47
66
Documentation/devicetree/bindings/pci/pci-rcar-gen2.txt
Normal file
66
Documentation/devicetree/bindings/pci/pci-rcar-gen2.txt
Normal file
@ -0,0 +1,66 @@
|
||||
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";
|
||||
};
|
47
Documentation/devicetree/bindings/pci/rcar-pci.txt
Normal file
47
Documentation/devicetree/bindings/pci/rcar-pci.txt
Normal file
@ -0,0 +1,47 @@
|
||||
* 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)
|
||||
}
|
||||
|
||||
node = acpi_get_node(device->handle);
|
||||
if (node == NUMA_NO_NODE)
|
||||
if (node == NUMA_NO_NODE) {
|
||||
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))
|
||||
node = NUMA_NO_NODE;
|
||||
|
@ -11,27 +11,33 @@
|
||||
|
||||
#include "bus_numa.h"
|
||||
|
||||
/*
|
||||
* This discovers the pcibus <-> node mapping on AMD K8.
|
||||
* also get peer root bus resource for io,mmio
|
||||
*/
|
||||
#define AMD_NB_F0_NODE_ID 0x60
|
||||
#define AMD_NB_F0_UNIT_ID 0x64
|
||||
#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 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 },
|
||||
/*
|
||||
* IMPORTANT NOTE:
|
||||
* hb_probes[] and early_root_info_init() is in maintenance mode.
|
||||
* It only supports K8, Fam10h, Fam11h, and Fam15h_00h-0fh .
|
||||
* 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)
|
||||
{
|
||||
struct pci_root_info *info;
|
||||
@ -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
|
||||
* fills the mp_bus_to_cpumask array based according to the LDT Bus Number
|
||||
* Registers found in the K8 northbridge
|
||||
* fills the mp_bus_to_cpumask array based according
|
||||
* 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;
|
||||
unsigned bus;
|
||||
@ -75,19 +81,21 @@ 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;
|
||||
|
||||
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) {
|
||||
|
||||
if (vendor != PCI_VENDOR_ID_AMD)
|
||||
continue;
|
||||
|
||||
if (hb_probes[i].device == device) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
@ -96,10 +104,16 @@ static int __init early_fill_mp_bus_info(void)
|
||||
if (!found)
|
||||
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 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)
|
||||
@ -113,10 +127,21 @@ static int __init early_fill_mp_bus_info(void)
|
||||
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 */
|
||||
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));
|
||||
@ -363,7 +388,7 @@ static int __init pci_io_ecs_init(void)
|
||||
int cpu;
|
||||
|
||||
/* assume all cpus from fam10h have IO ECS */
|
||||
if (boot_cpu_data.x86 < 0x10)
|
||||
if (boot_cpu_data.x86 < 0x10)
|
||||
return 0;
|
||||
|
||||
/* Try the PCI method first. */
|
||||
@ -387,7 +412,7 @@ static int __init amd_postcore_init(void)
|
||||
if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
|
||||
return 0;
|
||||
|
||||
early_fill_mp_bus_info();
|
||||
early_root_info_init();
|
||||
pci_io_ecs_init();
|
||||
|
||||
return 0;
|
||||
|
@ -33,4 +33,10 @@ config PCI_RCAR_GEN2
|
||||
There are 3 internal PCI controllers available with a single
|
||||
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
|
||||
|
@ -4,3 +4,4 @@ obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
|
||||
obj-$(CONFIG_PCI_MVEBU) += pci-mvebu.o
|
||||
obj-$(CONFIG_PCI_TEGRA) += pci-tegra.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)
|
||||
|
||||
exynos_pcie = devm_kzalloc(&pdev->dev, sizeof(*exynos_pcie),
|
||||
GFP_KERNEL);
|
||||
if (!exynos_pcie) {
|
||||
dev_err(&pdev->dev, "no memory for exynos pcie\n");
|
||||
if (!exynos_pcie)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pp = &exynos_pcie->pp;
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_pci.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
@ -98,6 +99,7 @@ struct rcar_pci_priv {
|
||||
struct resource io_res;
|
||||
struct resource mem_res;
|
||||
struct resource *cfg_res;
|
||||
unsigned busnr;
|
||||
int irq;
|
||||
unsigned long window_size;
|
||||
};
|
||||
@ -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 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
|
||||
@ -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->mem_res);
|
||||
|
||||
/* Setup bus number based on platform device id */
|
||||
sys->busnr = to_platform_device(priv->dev)->id;
|
||||
/* Setup bus number based on platform device id / of bus-range */
|
||||
sys->busnr = priv->busnr;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -366,6 +373,23 @@ static int rcar_pci_probe(struct platform_device *pdev)
|
||||
|
||||
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;
|
||||
memset(&hw, 0, sizeof(hw));
|
||||
hw.nr_controllers = ARRAY_SIZE(hw_private);
|
||||
@ -377,11 +401,20 @@ static int rcar_pci_probe(struct platform_device *pdev)
|
||||
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 = {
|
||||
.driver = {
|
||||
.name = "pci-rcar-gen2",
|
||||
.owner = THIS_MODULE,
|
||||
.suppress_bind_attrs = true,
|
||||
.of_match_table = rcar_pci_of_match,
|
||||
},
|
||||
.probe = rcar_pci_probe,
|
||||
};
|
||||
|
1008
drivers/pci/host/pcie-rcar.c
Normal file
1008
drivers/pci/host/pcie-rcar.c
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user