提交 80213c03 编写于 作者: L Linus Torvalds

Merge tag 'pci-v3.18-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci

Pull PCI updates from Bjorn Helgaas:
 "The interesting things here are:

   - Turn on Config Request Retry Status Software Visibility.  This
     caused hangs last time, but we included a fix this time.
   - Rework PCI device configuration to use _HPP/_HPX more aggressively
   - Allow PCI devices to be put into D3cold during system suspend
   - Add arm64 PCI support
   - Add APM X-Gene host bridge driver
   - Add TI Keystone host bridge driver
   - Add Xilinx AXI host bridge driver

  More detailed summary:

  Enumeration
    - Check Vendor ID only for Config Request Retry Status (Rajat Jain)
    - Enable Config Request Retry Status when supported (Rajat Jain)
    - Add generic domain handling (Catalin Marinas)
    - Generate uppercase hex for modalias interface class (Ricardo Ribalda Delgado)

  Resource management
    - Add missing MEM_64 mask in pci_assign_unassigned_bridge_resources() (Yinghai Lu)
    - Increase IBM ipr SAS Crocodile BARs to at least system page size (Douglas Lehr)

  PCI device hotplug
    - Prevent NULL dereference during pciehp probe (Andreas Noever)
    - Move _HPP & _HPX handling into core (Bjorn Helgaas)
    - Apply _HPP to PCIe devices as well as PCI (Bjorn Helgaas)
    - Apply _HPP/_HPX to display devices (Bjorn Helgaas)
    - Preserve SERR & PARITY settings when applying _HPP/_HPX (Bjorn Helgaas)
    - Preserve MPS and MRRS settings when applying _HPP/_HPX (Bjorn Helgaas)
    - Apply _HPP/_HPX to all devices, not just hot-added ones (Bjorn Helgaas)
    - Fix wait time in pciehp timeout message (Yinghai Lu)
    - Add more pciehp Slot Control debug output (Yinghai Lu)
    - Stop disabling pciehp notifications during init (Yinghai Lu)

  MSI
    - Remove arch_msi_check_device() (Alexander Gordeev)
    - Rename pci_msi_check_device() to pci_msi_supported() (Alexander Gordeev)
    - Move D0 check into pci_msi_check_device() (Alexander Gordeev)
    - Remove unused kobject from struct msi_desc (Yijing Wang)
    - Remove "pos" from the struct msi_desc msi_attrib (Yijing Wang)
    - Add "msi_bus" sysfs MSI/MSI-X control for endpoints (Yijing Wang)
    - Use __get_cached_msi_msg() instead of get_cached_msi_msg() (Yijing Wang)
    - Use __read_msi_msg() instead of read_msi_msg() (Yijing Wang)
    - Use __write_msi_msg() instead of write_msi_msg() (Yijing Wang)

  Power management
    - Drop unused runtime PM support code for PCIe ports (Rafael J.  Wysocki)
    - Allow PCI devices to be put into D3cold during system suspend (Rafael J. Wysocki)

  AER
    - Add additional AER error strings (Gong Chen)
    - Make <linux/aer.h> standalone includable (Thierry Reding)

  Virtualization
    - Add ACS quirk for Solarflare SFC9120 & SFC9140 (Alex Williamson)
    - Add ACS quirk for Intel 10G NICs (Alex Williamson)
    - Add ACS quirk for AMD A88X southbridge (Marti Raudsepp)
    - Remove unused pci_find_upstream_pcie_bridge(), pci_get_dma_source() (Alex Williamson)
    - Add device flag helpers (Ethan Zhao)
    - Assume all Mellanox devices have broken INTx masking (Gavin Shan)

  Generic host bridge driver
    - Fix ioport_map() for !CONFIG_GENERIC_IOMAP (Liviu Dudau)
    - Add pci_register_io_range() and pci_pio_to_address() (Liviu Dudau)
    - Define PCI_IOBASE as the base of virtual PCI IO space (Liviu Dudau)
    - Fix the conversion of IO ranges into IO resources (Liviu Dudau)
    - Add pci_get_new_domain_nr() and of_get_pci_domain_nr() (Liviu Dudau)
    - Add support for parsing PCI host bridge resources from DT (Liviu Dudau)
    - Add pci_remap_iospace() to map bus I/O resources (Liviu Dudau)
    - Add arm64 architectural support for PCI (Liviu Dudau)

  APM X-Gene
    - Add APM X-Gene PCIe driver (Tanmay Inamdar)
    - Add arm64 DT APM X-Gene PCIe device tree nodes (Tanmay Inamdar)

  Freescale i.MX6
    - Probe in module_init(), not fs_initcall() (Lucas Stach)
    - Delay enabling reference clock for SS until it stabilizes (Tim Harvey)

  Marvell MVEBU
    - Fix uninitialized variable in mvebu_get_tgt_attr() (Thomas Petazzoni)

  NVIDIA Tegra
    - Make sure the PCIe PLL is really reset (Eric Yuen)
    - Add error path tegra_msi_teardown_irq() cleanup (Jisheng Zhang)
    - Fix extended configuration space mapping (Peter Daifuku)
    - Implement resource hierarchy (Thierry Reding)
    - Clear CLKREQ# enable on port disable (Thierry Reding)
    - Add Tegra124 support (Thierry Reding)

  ST Microelectronics SPEAr13xx
    - Pass config resource through reg property (Pratyush Anand)

  Synopsys DesignWare
    - Use NULL instead of false (Fabio Estevam)
    - Parse bus-range property from devicetree (Lucas Stach)
    - Use pci_create_root_bus() instead of pci_scan_root_bus() (Lucas Stach)
    - Remove pci_assign_unassigned_resources() (Lucas Stach)
    - Check private_data validity in single place (Lucas Stach)
    - Setup and clear exactly one MSI at a time (Lucas Stach)
    - Remove open-coded bitmap operations (Lucas Stach)
    - Fix configuration base address when using 'reg' (Minghuan Lian)
    - Fix IO resource end address calculation (Minghuan Lian)
    - Rename get_msi_data() to get_msi_addr() (Minghuan Lian)
    - Add get_msi_data() to pcie_host_ops (Minghuan Lian)
    - Add support for v3.65 hardware (Murali Karicheri)
    - Fold struct pcie_port_info into struct pcie_port (Pratyush Anand)

  TI Keystone
    - Add TI Keystone PCIe driver (Murali Karicheri)
    - Limit MRSS for all downstream devices (Murali Karicheri)
    - Assume controller is already in RC mode (Murali Karicheri)
    - Set device ID based on SoC to support multiple ports (Murali Karicheri)

  Xilinx AXI
    - Add Xilinx AXI PCIe driver (Srikanth Thokala)
    - Fix xilinx_pcie_assign_msi() return value test (Dan Carpenter)

  Miscellaneous
    - Clean up whitespace (Quentin Lambert)
    - Remove assignments from "if" conditions (Quentin Lambert)
    - Move PCI_VENDOR_ID_VMWARE to pci_ids.h (Francesco Ruggeri)
    - x86: Mark DMI tables as initialization data (Mathias Krause)
    - x86: Move __init annotation to the correct place (Mathias Krause)
    - x86: Mark constants of pci_mmcfg_nvidia_mcp55() as __initconst (Mathias Krause)
    - x86: Constify pci_mmcfg_probes[] array (Mathias Krause)
    - x86: Mark PCI BIOS initialization code as such (Mathias Krause)
    - Parenthesize PCI_DEVID and PCI_VPD_LRDT_ID parameters (Megan Kamiya)
    - Remove unnecessary variable in pci_add_dynid() (Tobias Klauser)"

* tag 'pci-v3.18-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (109 commits)
  arm64: dts: Add APM X-Gene PCIe device tree nodes
  PCI: Add ACS quirk for AMD A88X southbridge devices
  PCI: xgene: Add APM X-Gene PCIe driver
  PCI: designware: Remove open-coded bitmap operations
  PCI/MSI: Remove unnecessary temporary variable
  PCI/MSI: Use __write_msi_msg() instead of write_msi_msg()
  MSI/powerpc: Use __read_msi_msg() instead of read_msi_msg()
  PCI/MSI: Use __get_cached_msi_msg() instead of get_cached_msi_msg()
  PCI/MSI: Add "msi_bus" sysfs MSI/MSI-X control for endpoints
  PCI/MSI: Remove "pos" from the struct msi_desc msi_attrib
  PCI/MSI: Remove unused kobject from struct msi_desc
  PCI/MSI: Rename pci_msi_check_device() to pci_msi_supported()
  PCI/MSI: Move D0 check into pci_msi_check_device()
  PCI/MSI: Remove arch_msi_check_device()
  irqchip: armada-370-xp: Remove arch_msi_check_device()
  PCI/MSI/PPC: Remove arch_msi_check_device()
  arm64: Add architectural support for PCI
  PCI: Add pci_remap_iospace() to map bus I/O resources
  of/pci: Add support for parsing PCI host bridge resources from DT
  of/pci: Add pci_get_new_domain_nr() and of_get_pci_domain_nr()
  ...

Conflicts:
	arch/arm64/boot/dts/apm-storm.dtsi
......@@ -65,6 +65,16 @@ Description:
force a rescan of all PCI buses in the system, and
re-discover previously removed devices.
What: /sys/bus/pci/devices/.../msi_bus
Date: September 2014
Contact: Linux PCI developers <linux-pci@vger.kernel.org>
Description:
Writing a zero value to this attribute disallows MSI and
MSI-X for any future drivers of the device. If the device
is a bridge, MSI and MSI-X will be disallowed for future
drivers of all child devices under the bridge. Drivers
must be reloaded for the new setting to take effect.
What: /sys/bus/pci/devices/.../msi_irqs/
Date: September, 2011
Contact: Neil Horman <nhorman@tuxdriver.com>
......
......@@ -23,3 +23,6 @@ Required properties:
Optional properties:
- reset-gpio: gpio pin number of power good signal
- bus-range: PCI bus numbers covered (it is recommended for new devicetrees to
specify this property, to keep backwards compatibility a range of 0x00-0xff
is assumed if not present)
NVIDIA Tegra PCIe controller
Required properties:
- compatible: "nvidia,tegra20-pcie" or "nvidia,tegra30-pcie"
- compatible: Must be one of:
- "nvidia,tegra20-pcie"
- "nvidia,tegra30-pcie"
- "nvidia,tegra124-pcie"
- device_type: Must be "pci"
- reg: A list of physical base address and length for each set of controller
registers. Must contain an entry for each entry in the reg-names property.
......@@ -57,6 +60,11 @@ Required properties:
- afi
- pcie_x
Required properties on Tegra124 and later:
- phys: Must contain an entry for each entry in phy-names.
- phy-names: Must include the following entries:
- pcie
Power supplies for Tegra20:
- avdd-pex-supply: Power supply for analog PCIe logic. Must supply 1.05 V.
- vdd-pex-supply: Power supply for digital PCIe I/O. Must supply 1.05 V.
......@@ -84,6 +92,21 @@ Power supplies for Tegra30:
- avdd-pexb-supply: Power supply for analog PCIe logic. Must supply 1.05 V.
- vdd-pexb-supply: Power supply for digital PCIe I/O. Must supply 1.05 V.
Power supplies for Tegra124:
- Required:
- avddio-pex-supply: Power supply for analog PCIe logic. Must supply 1.05 V.
- dvddio-pex-supply: Power supply for digital PCIe I/O. Must supply 1.05 V.
- avdd-pex-pll-supply: Power supply for dedicated (internal) PCIe PLL. Must
supply 1.05 V.
- hvdd-pex-supply: High-voltage supply for PCIe I/O and PCIe output clocks.
Must supply 3.3 V.
- hvdd-pex-pll-e-supply: High-voltage supply for PLLE (shared with USB3).
Must supply 3.3 V.
- vddio-pex-ctl-supply: Power supply for PCIe control I/O partition. Must
supply 2.8-3.3 V.
- avdd-pll-erefe-supply: Power supply for PLLE (shared with USB3). Must
supply 1.05 V.
Root ports are defined as subnodes of the PCIe controller node.
Required properties:
......
TI Keystone PCIe interface
Keystone PCI host Controller is based on Designware PCI h/w version 3.65.
It shares common functions with PCIe Designware core driver and inherit
common properties defined in
Documentation/devicetree/bindings/pci/designware-pci.txt
Please refer to Documentation/devicetree/bindings/pci/designware-pci.txt
for the details of Designware DT bindings. Additional properties are
described here as well as properties that are not applicable.
Required Properties:-
compatibility: "ti,keystone-pcie"
reg: index 1 is the base address and length of DW application registers.
index 2 is the base address and length of PCI device ID register.
pcie_msi_intc : Interrupt controller device node for MSI IRQ chip
interrupt-cells: should be set to 1
interrupt-parent: Parent interrupt controller phandle
interrupts: GIC interrupt lines connected to PCI MSI interrupt lines
Example:
pcie_msi_intc: msi-interrupt-controller {
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&gic>;
interrupts = <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 31 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 32 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 33 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 34 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 35 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 36 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 37 IRQ_TYPE_EDGE_RISING>;
};
pcie_intc: Interrupt controller device node for Legacy IRQ chip
interrupt-cells: should be set to 1
interrupt-parent: Parent interrupt controller phandle
interrupts: GIC interrupt lines connected to PCI Legacy interrupt lines
Example:
pcie_intc: legacy-interrupt-controller {
interrupt-controller;
#interrupt-cells = <1>;
interrupt-parent = <&gic>;
interrupts = <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 27 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 28 IRQ_TYPE_EDGE_RISING>,
<GIC_SPI 29 IRQ_TYPE_EDGE_RISING>;
};
Optional properties:-
phys: phandle to Generic Keystone SerDes phy for PCI
phy-names: name of the Generic Keystine SerDes phy for PCI
- If boot loader already does PCI link establishment, then phys and
phy-names shouldn't be present.
Designware DT Properties not applicable for Keystone PCI
1. pcie_bus clock-names not used. Instead, a phandle to phys is used.
* AppliedMicro X-Gene PCIe interface
Required properties:
- device_type: set to "pci"
- compatible: should contain "apm,xgene-pcie" to identify the core.
- reg: A list of physical base address and length for each set of controller
registers. Must contain an entry for each entry in the reg-names
property.
- reg-names: Must include the following entries:
"csr": controller configuration registers.
"cfg": pcie configuration space registers.
- #address-cells: set to <3>
- #size-cells: set to <2>
- ranges: ranges for the outbound memory, I/O regions.
- dma-ranges: ranges for the inbound memory regions.
- #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: handle to pci clock.
Optional properties:
- status: Either "ok" or "disabled".
- dma-coherent: Present if dma operations are coherent
Example:
SoC specific DT Entry:
pcie0: pcie@1f2b0000 {
status = "disabled";
device_type = "pci";
compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie";
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
reg = < 0x00 0x1f2b0000 0x0 0x00010000 /* Controller registers */
0xe0 0xd0000000 0x0 0x00040000>; /* PCI config space */
reg-names = "csr", "cfg";
ranges = <0x01000000 0x00 0x00000000 0xe0 0x10000000 0x00 0x00010000 /* io */
0x02000000 0x00 0x80000000 0xe1 0x80000000 0x00 0x80000000>; /* mem */
dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000
0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>;
interrupt-map-mask = <0x0 0x0 0x0 0x7>;
interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xc2 0x1
0x0 0x0 0x0 0x2 &gic 0x0 0xc3 0x1
0x0 0x0 0x0 0x3 &gic 0x0 0xc4 0x1
0x0 0x0 0x0 0x4 &gic 0x0 0xc5 0x1>;
dma-coherent;
clocks = <&pcie0clk 0>;
};
Board specific DT Entry:
&pcie0 {
status = "ok";
};
* Xilinx AXI PCIe Root Port Bridge DT description
Required properties:
- #address-cells: Address representation for root ports, set to <3>
- #size-cells: Size representation for root ports, set to <2>
- #interrupt-cells: specifies the number of cells needed to encode an
interrupt source. The value must be 1.
- compatible: Should contain "xlnx,axi-pcie-host-1.00.a"
- reg: Should contain AXI PCIe registers location and length
- device_type: must be "pci"
- interrupts: Should contain AXI PCIe interrupt
- interrupt-map-mask,
interrupt-map: standard PCI properties to define the mapping of the
PCI interface to interrupt numbers.
- ranges: ranges for the PCI memory regions (I/O space region is not
supported by hardware)
Please refer to the standard PCI bus binding document for a more
detailed explanation
Optional properties:
- bus-range: PCI bus numbers covered
Interrupt controller child node
+++++++++++++++++++++++++++++++
Required properties:
- interrupt-controller: identifies the node as an interrupt controller
- #address-cells: specifies the number of cells needed to encode an
address. The value must be 0.
- #interrupt-cells: specifies the number of cells needed to encode an
interrupt source. The value must be 1.
NOTE:
The core provides a single interrupt for both INTx/MSI messages. So,
created a interrupt controller node to support 'interrupt-map' DT
functionality. The driver will create an IRQ domain for this map, decode
the four INTx interrupts in ISR and route them to this domain.
Example:
++++++++
pci_express: axi-pcie@50000000 {
#address-cells = <3>;
#size-cells = <2>;
#interrupt-cells = <1>;
compatible = "xlnx,axi-pcie-host-1.00.a";
reg = < 0x50000000 0x10000000 >;
device_type = "pci";
interrupts = < 0 52 4 >;
interrupt-map-mask = <0 0 0 7>;
interrupt-map = <0 0 0 1 &pcie_intc 1>,
<0 0 0 2 &pcie_intc 2>,
<0 0 0 3 &pcie_intc 3>,
<0 0 0 4 &pcie_intc 4>;
ranges = < 0x02000000 0 0x60000000 0x60000000 0 0x10000000 >;
pcie_intc: interrupt-controller {
interrupt-controller;
#address-cells = <0>;
#interrupt-cells = <1>;
}
};
......@@ -264,8 +264,10 @@ IIO
IO region
devm_release_mem_region()
devm_release_region()
devm_release_resource()
devm_request_mem_region()
devm_request_region()
devm_request_resource()
IOMAP
devm_ioport_map()
......
......@@ -6939,6 +6939,14 @@ F: include/linux/pci*
F: arch/x86/pci/
F: arch/x86/kernel/quirks.c
PCI DRIVER FOR APPLIEDMICRO XGENE
M: Tanmay Inamdar <tinamdar@apm.com>
L: linux-pci@vger.kernel.org
L: linux-arm-kernel@lists.infradead.org
S: Maintained
F: Documentation/devicetree/bindings/pci/xgene-pci.txt
F: drivers/pci/host/pci-xgene.c
PCI DRIVER FOR IMX6
M: Richard Zhu <r65037@freescale.com>
M: Lucas Stach <l.stach@pengutronix.de>
......@@ -6947,6 +6955,13 @@ L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: drivers/pci/host/*imx6*
PCI DRIVER FOR TI KEYSTONE
M: Murali Karicheri <m-karicheri2@ti.com>
L: linux-pci@vger.kernel.org
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: drivers/pci/host/*keystone*
PCI DRIVER FOR MVEBU (Marvell Armada 370 and Armada XP SOC support)
M: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
M: Jason Cooper <jason@lakedaemon.net>
......
......@@ -85,7 +85,8 @@
pcie0: pcie@b1000000 {
compatible = "st,spear1340-pcie", "snps,dw-pcie";
reg = <0xb1000000 0x4000>;
reg = <0xb1000000 0x4000>, <0x80000000 0x20000>;
reg-names = "dbi", "config";
interrupts = <0 68 0x4>;
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0x0 0 &gic 0 68 0x4>;
......@@ -95,15 +96,15 @@
#address-cells = <3>;
#size-cells = <2>;
device_type = "pci";
ranges = <0x00000800 0 0x80000000 0x80000000 0 0x00020000 /* configuration space */
0x81000000 0 0 0x80020000 0 0x00010000 /* downstream I/O */
ranges = <0x81000000 0 0 0x80020000 0 0x00010000 /* downstream I/O */
0x82000000 0 0x80030000 0xc0030000 0 0x0ffd0000>; /* non-prefetchable memory */
status = "disabled";
};
pcie1: pcie@b1800000 {
compatible = "st,spear1340-pcie", "snps,dw-pcie";
reg = <0xb1800000 0x4000>;
reg = <0xb1800000 0x4000>, <0x90000000 0x20000>;
reg-names = "dbi", "config";
interrupts = <0 69 0x4>;
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0x0 0 &gic 0 69 0x4>;
......@@ -113,15 +114,15 @@
#address-cells = <3>;
#size-cells = <2>;
device_type = "pci";
ranges = <0x00000800 0 0x90000000 0x90000000 0 0x00020000 /* configuration space */
0x81000000 0 0 0x90020000 0 0x00010000 /* downstream I/O */
ranges = <0x81000000 0 0 0x90020000 0 0x00010000 /* downstream I/O */
0x82000000 0 0x90030000 0x90030000 0 0x0ffd0000>; /* non-prefetchable memory */
status = "disabled";
};
pcie2: pcie@b4000000 {
compatible = "st,spear1340-pcie", "snps,dw-pcie";
reg = <0xb4000000 0x4000>;
reg = <0xb4000000 0x4000>, <0xc0000000 0x20000>;
reg-names = "dbi", "config";
interrupts = <0 70 0x4>;
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0x0 0 &gic 0 70 0x4>;
......@@ -131,8 +132,7 @@
#address-cells = <3>;
#size-cells = <2>;
device_type = "pci";
ranges = <0x00000800 0 0xc0000000 0xc0000000 0 0x00020000 /* configuration space */
0x81000000 0 0 0xc0020000 0 0x00010000 /* downstream I/O */
ranges = <0x81000000 0 0 0xc0020000 0 0x00010000 /* downstream I/O */
0x82000000 0 0xc0030000 0xc0030000 0 0x0ffd0000>; /* non-prefetchable memory */
status = "disabled";
};
......
......@@ -50,7 +50,8 @@
pcie0: pcie@b1000000 {
compatible = "st,spear1340-pcie", "snps,dw-pcie";
reg = <0xb1000000 0x4000>;
reg = <0xb1000000 0x4000>, <0x80000000 0x20000>;
reg-names = "dbi", "config";
interrupts = <0 68 0x4>;
interrupt-map-mask = <0 0 0 0>;
interrupt-map = <0x0 0 &gic 0 68 0x4>;
......@@ -60,8 +61,7 @@
#address-cells = <3>;
#size-cells = <2>;
device_type = "pci";
ranges = <0x00000800 0 0x80000000 0x80000000 0 0x00020000 /* configuration space */
0x81000000 0 0 0x80020000 0 0x00010000 /* downstream I/O */
ranges = <0x81000000 0 0 0x80020000 0 0x00010000 /* downstream I/O */
0x82000000 0 0x80030000 0xc0030000 0 0x0ffd0000>; /* non-prefetchable memory */
status = "disabled";
};
......
......@@ -178,6 +178,7 @@ static inline void __iomem *__typesafe_io(unsigned long addr)
/* PCI fixed i/o mapping */
#define PCI_IO_VIRT_BASE 0xfee00000
#define PCI_IOBASE ((void __iomem *)PCI_IO_VIRT_BASE)
#if defined(CONFIG_PCI)
void pci_ioremap_set_mem_type(int mem_type);
......
......@@ -660,6 +660,7 @@ static void __init pci_v3_preinit(void)
{
unsigned long flags;
unsigned int temp;
phys_addr_t io_address = pci_pio_to_address(io_mem.start);
pcibios_min_mem = 0x00100000;
......@@ -701,7 +702,7 @@ static void __init pci_v3_preinit(void)
/*
* Setup window 2 - PCI IO
*/
v3_writel(V3_LB_BASE2, v3_addr_to_lb_base2(io_mem.start) |
v3_writel(V3_LB_BASE2, v3_addr_to_lb_base2(io_address) |
V3_LB_BASE_ENABLE);
v3_writew(V3_LB_MAP2, v3_addr_to_lb_map2(0));
......@@ -742,6 +743,7 @@ static void __init pci_v3_preinit(void)
static void __init pci_v3_postinit(void)
{
unsigned int pci_cmd;
phys_addr_t io_address = pci_pio_to_address(io_mem.start);
pci_cmd = PCI_COMMAND_MEMORY |
PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
......@@ -758,7 +760,7 @@ static void __init pci_v3_postinit(void)
"interrupt: %d\n", ret);
#endif
register_isa_ports(non_mem.start, io_mem.start, 0);
register_isa_ports(non_mem.start, io_address, 0);
}
/*
......@@ -867,33 +869,32 @@ static int __init pci_v3_probe(struct platform_device *pdev)
for_each_of_pci_range(&parser, &range) {
if (!range.flags) {
of_pci_range_to_resource(&range, np, &conf_mem);
ret = of_pci_range_to_resource(&range, np, &conf_mem);
conf_mem.name = "PCIv3 config";
}
if (range.flags & IORESOURCE_IO) {
of_pci_range_to_resource(&range, np, &io_mem);
ret = of_pci_range_to_resource(&range, np, &io_mem);
io_mem.name = "PCIv3 I/O";
}
if ((range.flags & IORESOURCE_MEM) &&
!(range.flags & IORESOURCE_PREFETCH)) {
non_mem_pci = range.pci_addr;
non_mem_pci_sz = range.size;
of_pci_range_to_resource(&range, np, &non_mem);
ret = of_pci_range_to_resource(&range, np, &non_mem);
non_mem.name = "PCIv3 non-prefetched mem";
}
if ((range.flags & IORESOURCE_MEM) &&
(range.flags & IORESOURCE_PREFETCH)) {
pre_mem_pci = range.pci_addr;
pre_mem_pci_sz = range.size;
of_pci_range_to_resource(&range, np, &pre_mem);
ret = of_pci_range_to_resource(&range, np, &pre_mem);
pre_mem.name = "PCIv3 prefetched mem";
}
}
if (!conf_mem.start || !io_mem.start ||
!non_mem.start || !pre_mem.start) {
if (ret < 0) {
dev_err(&pdev->dev, "missing ranges in device node\n");
return -EINVAL;
return ret;
}
}
pci_v3.map_irq = of_irq_parse_and_map_pci;
......
......@@ -83,7 +83,7 @@ config MMU
def_bool y
config NO_IOPORT_MAP
def_bool y
def_bool y if !PCI
config STACKTRACE_SUPPORT
def_bool y
......@@ -163,6 +163,26 @@ menu "Bus support"
config ARM_AMBA
bool
config PCI
bool "PCI support"
help
This feature enables support for PCI bus system. If you say Y
here, the kernel will include drivers and infrastructure code
to support PCI bus devices.
config PCI_DOMAINS
def_bool PCI
config PCI_DOMAINS_GENERIC
def_bool PCI
config PCI_SYSCALL
def_bool PCI
source "drivers/pci/Kconfig"
source "drivers/pci/pcie/Kconfig"
source "drivers/pci/hotplug/Kconfig"
endmenu
menu "Kernel Features"
......
......@@ -25,6 +25,14 @@
};
};
&pcie0clk {
status = "ok";
};
&pcie0 {
status = "ok";
};
&serial0 {
status = "ok";
};
......
......@@ -282,6 +282,171 @@
enable-mask = <0x10>;
clock-output-names = "rngpkaclk";
};
pcie0clk: pcie0clk@1f2bc000 {
status = "disabled";
compatible = "apm,xgene-device-clock";
#clock-cells = <1>;
clocks = <&socplldiv2 0>;
reg = <0x0 0x1f2bc000 0x0 0x1000>;
reg-names = "csr-reg";
clock-output-names = "pcie0clk";
};
pcie1clk: pcie1clk@1f2cc000 {
status = "disabled";
compatible = "apm,xgene-device-clock";
#clock-cells = <1>;
clocks = <&socplldiv2 0>;
reg = <0x0 0x1f2cc000 0x0 0x1000>;
reg-names = "csr-reg";
clock-output-names = "pcie1clk";
};
pcie2clk: pcie2clk@1f2dc000 {
status = "disabled";
compatible = "apm,xgene-device-clock";
#clock-cells = <1>;
clocks = <&socplldiv2 0>;
reg = <0x0 0x1f2dc000 0x0 0x1000>;
reg-names = "csr-reg";
clock-output-names = "pcie2clk";
};
pcie3clk: pcie3clk@1f50c000 {
status = "disabled";
compatible = "apm,xgene-device-clock";
#clock-cells = <1>;
clocks = <&socplldiv2 0>;
reg = <0x0 0x1f50c000 0x0 0x1000>;
reg-names = "csr-reg";
clock-output-names = "pcie3clk";
};
pcie4clk: pcie4clk@1f51c000 {
status = "disabled";
compatible = "apm,xgene-device-clock";
#clock-cells = <1>;
clocks = <&socplldiv2 0>;
reg = <0x0 0x1f51c000 0x0 0x1000>;
reg-names = "csr-reg";
clock-output-names = "pcie4clk";
};
};
pcie0: pcie@1f2b0000 {
status = "disabled";
device_type = "pci";
compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie";
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
reg = < 0x00 0x1f2b0000 0x0 0x00010000 /* Controller registers */
0xe0 0xd0000000 0x0 0x00040000>; /* PCI config space */
reg-names = "csr", "cfg";
ranges = <0x01000000 0x00 0x00000000 0xe0 0x10000000 0x00 0x00010000 /* io */
0x02000000 0x00 0x80000000 0xe1 0x80000000 0x00 0x80000000>; /* mem */
dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000
0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>;
interrupt-map-mask = <0x0 0x0 0x0 0x7>;
interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xc2 0x1
0x0 0x0 0x0 0x2 &gic 0x0 0xc3 0x1
0x0 0x0 0x0 0x3 &gic 0x0 0xc4 0x1
0x0 0x0 0x0 0x4 &gic 0x0 0xc5 0x1>;
dma-coherent;
clocks = <&pcie0clk 0>;
};
pcie1: pcie@1f2c0000 {
status = "disabled";
device_type = "pci";
compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie";
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
reg = < 0x00 0x1f2c0000 0x0 0x00010000 /* Controller registers */
0xd0 0xd0000000 0x0 0x00040000>; /* PCI config space */
reg-names = "csr", "cfg";
ranges = <0x01000000 0x0 0x00000000 0xd0 0x10000000 0x00 0x00010000 /* io */
0x02000000 0x0 0x80000000 0xd1 0x80000000 0x00 0x80000000>; /* mem */
dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000
0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>;
interrupt-map-mask = <0x0 0x0 0x0 0x7>;
interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xc8 0x1
0x0 0x0 0x0 0x2 &gic 0x0 0xc9 0x1
0x0 0x0 0x0 0x3 &gic 0x0 0xca 0x1
0x0 0x0 0x0 0x4 &gic 0x0 0xcb 0x1>;
dma-coherent;
clocks = <&pcie1clk 0>;
};
pcie2: pcie@1f2d0000 {
status = "disabled";
device_type = "pci";
compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie";
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
reg = < 0x00 0x1f2d0000 0x0 0x00010000 /* Controller registers */
0x90 0xd0000000 0x0 0x00040000>; /* PCI config space */
reg-names = "csr", "cfg";
ranges = <0x01000000 0x0 0x00000000 0x90 0x10000000 0x0 0x00010000 /* io */
0x02000000 0x0 0x80000000 0x91 0x80000000 0x0 0x80000000>; /* mem */
dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000
0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>;
interrupt-map-mask = <0x0 0x0 0x0 0x7>;
interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xce 0x1
0x0 0x0 0x0 0x2 &gic 0x0 0xcf 0x1
0x0 0x0 0x0 0x3 &gic 0x0 0xd0 0x1
0x0 0x0 0x0 0x4 &gic 0x0 0xd1 0x1>;
dma-coherent;
clocks = <&pcie2clk 0>;
};
pcie3: pcie@1f500000 {
status = "disabled";
device_type = "pci";
compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie";
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
reg = < 0x00 0x1f500000 0x0 0x00010000 /* Controller registers */
0xa0 0xd0000000 0x0 0x00040000>; /* PCI config space */
reg-names = "csr", "cfg";
ranges = <0x01000000 0x0 0x00000000 0xa0 0x10000000 0x0 0x00010000 /* io */
0x02000000 0x0 0x80000000 0xa1 0x80000000 0x0 0x80000000>; /* mem */
dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000
0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>;
interrupt-map-mask = <0x0 0x0 0x0 0x7>;
interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xd4 0x1
0x0 0x0 0x0 0x2 &gic 0x0 0xd5 0x1
0x0 0x0 0x0 0x3 &gic 0x0 0xd6 0x1
0x0 0x0 0x0 0x4 &gic 0x0 0xd7 0x1>;
dma-coherent;
clocks = <&pcie3clk 0>;
};
pcie4: pcie@1f510000 {
status = "disabled";
device_type = "pci";
compatible = "apm,xgene-storm-pcie", "apm,xgene-pcie";
#interrupt-cells = <1>;
#size-cells = <2>;
#address-cells = <3>;
reg = < 0x00 0x1f510000 0x0 0x00010000 /* Controller registers */
0xc0 0xd0000000 0x0 0x00200000>; /* PCI config space */
reg-names = "csr", "cfg";
ranges = <0x01000000 0x0 0x00000000 0xc0 0x10000000 0x0 0x00010000 /* io */
0x02000000 0x0 0x80000000 0xc1 0x80000000 0x0 0x80000000>; /* mem */
dma-ranges = <0x42000000 0x80 0x00000000 0x80 0x00000000 0x00 0x80000000
0x42000000 0x00 0x00000000 0x00 0x00000000 0x80 0x00000000>;
interrupt-map-mask = <0x0 0x0 0x0 0x7>;
interrupt-map = <0x0 0x0 0x0 0x1 &gic 0x0 0xda 0x1
0x0 0x0 0x0 0x2 &gic 0x0 0xdb 0x1
0x0 0x0 0x0 0x3 &gic 0x0 0xdc 0x1
0x0 0x0 0x0 0x4 &gic 0x0 0xdd 0x1>;
dma-coherent;
clocks = <&pcie4clk 0>;
};
serial0: serial@1c020000 {
......
......@@ -29,6 +29,7 @@ generic-y += mman.h
generic-y += msgbuf.h
generic-y += mutex.h
generic-y += pci.h
generic-y += pci-bridge.h
generic-y += poll.h
generic-y += preempt.h
generic-y += resource.h
......
......@@ -121,7 +121,8 @@ static inline u64 __raw_readq(const volatile void __iomem *addr)
/*
* I/O port access primitives.
*/
#define IO_SPACE_LIMIT 0xffff
#define arch_has_dev_port() (1)
#define IO_SPACE_LIMIT (SZ_32M - 1)
#define PCI_IOBASE ((void __iomem *)(MODULES_VADDR - SZ_32M))
static inline u8 inb(unsigned long addr)
......
#ifndef __ASM_PCI_H
#define __ASM_PCI_H
#ifdef __KERNEL__
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/dma-mapping.h>
#include <asm/io.h>
#include <asm-generic/pci-bridge.h>
#include <asm-generic/pci-dma-compat.h>
#define PCIBIOS_MIN_IO 0x1000
#define PCIBIOS_MIN_MEM 0
/*
* Set to 1 if the kernel should re-assign all PCI bus numbers
*/
#define pcibios_assign_all_busses() \
(pci_has_flag(PCI_REASSIGN_ALL_BUS))
/*
* PCI address space differs from physical memory address space
*/
#define PCI_DMA_BUS_IS_PHYS (0)
extern int isa_dma_bridge_buggy;
#ifdef CONFIG_PCI
static inline int pci_proc_domain(struct pci_bus *bus)
{
return 1;
}
#endif /* CONFIG_PCI */
#endif /* __KERNEL__ */
#endif /* __ASM_PCI_H */
......@@ -301,6 +301,8 @@ static inline int has_transparent_hugepage(void)
__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRnE) | PTE_PXN | PTE_UXN)
#define pgprot_writecombine(prot) \
__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_NORMAL_NC) | PTE_PXN | PTE_UXN)
#define pgprot_device(prot) \
__pgprot_modify(prot, PTE_ATTRINDX_MASK, PTE_ATTRINDX(MT_DEVICE_nGnRE) | PTE_PXN | PTE_UXN)
#define __HAVE_PHYS_MEM_ACCESS_PROT
struct file;
extern pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
......
......@@ -30,6 +30,7 @@ arm64-obj-$(CONFIG_CPU_IDLE) += cpuidle.o
arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o
arm64-obj-$(CONFIG_KGDB) += kgdb.o
arm64-obj-$(CONFIG_EFI) += efi.o efi-stub.o efi-entry.o
arm64-obj-$(CONFIG_PCI) += pci.o
obj-y += $(arm64-obj-y) vdso/
obj-m += $(arm64-obj-m)
......
/*
* Code borrowed from powerpc/kernel/pci-common.c
*
* Copyright (C) 2003 Anton Blanchard <anton@au.ibm.com>, IBM
* Copyright (C) 2014 ARM Ltd.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
*/
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/of_pci.h>
#include <linux/of_platform.h>
#include <linux/slab.h>
#include <asm/pci-bridge.h>
/*
* Called after each bus is probed, but before its children are examined
*/
void pcibios_fixup_bus(struct pci_bus *bus)
{
/* nothing to do, expected to be removed in the future */
}
/*
* We don't have to worry about legacy ISA devices, so nothing to do here
*/
resource_size_t pcibios_align_resource(void *data, const struct resource *res,
resource_size_t size, resource_size_t align)
{
return res->start;
}
/*
* Try to assign the IRQ number from DT when adding a new device
*/
int pcibios_add_device(struct pci_dev *dev)
{
dev->irq = of_irq_parse_and_map_pci(dev, 0, 0);
return 0;
}
#ifdef CONFIG_PCI_DOMAINS_GENERIC
static bool dt_domain_found = false;
void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent)
{
int domain = of_get_pci_domain_nr(parent->of_node);
if (domain >= 0) {
dt_domain_found = true;
} else if (dt_domain_found == true) {
dev_err(parent, "Node %s is missing \"linux,pci-domain\" property in DT\n",
parent->of_node->full_name);
return;
} else {
domain = pci_get_new_domain_nr();
}
bus->domain_nr = domain;
}
#endif
......@@ -23,7 +23,7 @@ static int ia64_set_msi_irq_affinity(struct irq_data *idata,
if (irq_prepare_move(irq, cpu))
return -1;
get_cached_msi_msg(irq, &msg);
__get_cached_msi_msg(idata->msi_desc, &msg);
addr = msg.address_lo;
addr &= MSI_ADDR_DEST_ID_MASK;
......
......@@ -175,7 +175,7 @@ static int sn_set_msi_irq_affinity(struct irq_data *data,
* Release XIO resources for the old MSI PCI address
*/
get_cached_msi_msg(irq, &msg);
__get_cached_msi_msg(data->msi_desc, &msg);
sn_pdev = (struct pcidev_info *)sn_irq_info->irq_pciioinfo;
pdev = sn_pdev->pdi_linux_pcidev;
provider = SN_PCIDEV_BUSPROVIDER(pdev);
......
......@@ -73,8 +73,7 @@ int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
* wants. Most devices only want 1, which will give
* configured_private_bits and request_private_bits equal 0.
*/
pci_read_config_word(dev, desc->msi_attrib.pos + PCI_MSI_FLAGS,
&control);
pci_read_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, &control);
/*
* If the number of private bits has been configured then use
......@@ -176,8 +175,7 @@ int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
/* Update the number of IRQs the device has available to it */
control &= ~PCI_MSI_FLAGS_QSIZE;
control |= request_private_bits << 4;
pci_write_config_word(dev, desc->msi_attrib.pos + PCI_MSI_FLAGS,
control);
pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
irq_set_msi_desc(irq, desc);
write_msi_msg(irq, &msg);
......
......@@ -136,8 +136,6 @@ struct machdep_calls {
int (*pci_setup_phb)(struct pci_controller *host);
#ifdef CONFIG_PCI_MSI
int (*msi_check_device)(struct pci_dev* dev,
int nvec, int type);
int (*setup_msi_irqs)(struct pci_dev *dev,
int nvec, int type);
void (*teardown_msi_irqs)(struct pci_dev *dev);
......
......@@ -13,7 +13,7 @@
#include <asm/machdep.h>
int arch_msi_check_device(struct pci_dev* dev, int nvec, int type)
int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
{
if (!ppc_md.setup_msi_irqs || !ppc_md.teardown_msi_irqs) {
pr_debug("msi: Platform doesn't provide MSI callbacks.\n");
......@@ -24,16 +24,6 @@ int arch_msi_check_device(struct pci_dev* dev, int nvec, int type)
if (type == PCI_CAP_ID_MSI && nvec > 1)
return 1;
if (ppc_md.msi_check_device) {
pr_debug("msi: Using platform check routine.\n");
return ppc_md.msi_check_device(dev, nvec, type);
}
return 0;
}
int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
{
return ppc_md.setup_msi_irqs(dev, nvec, type);
}
......
......@@ -199,14 +199,6 @@ static struct axon_msic *find_msi_translator(struct pci_dev *dev)
return msic;
}
static int axon_msi_check_device(struct pci_dev *dev, int nvec, int type)
{
if (!find_msi_translator(dev))
return -ENODEV;
return 0;
}
static int setup_msi_msg_address(struct pci_dev *dev, struct msi_msg *msg)
{
struct device_node *dn;
......@@ -416,7 +408,6 @@ static int axon_msi_probe(struct platform_device *device)
ppc_md.setup_msi_irqs = axon_msi_setup_msi_irqs;
ppc_md.teardown_msi_irqs = axon_msi_teardown_msi_irqs;
ppc_md.msi_check_device = axon_msi_check_device;
axon_msi_debug_setup(dn, msic);
......
......@@ -46,29 +46,21 @@
//#define cfg_dbg(fmt...) printk(fmt)
#ifdef CONFIG_PCI_MSI
static int pnv_msi_check_device(struct pci_dev* pdev, int nvec, int type)
{
struct pci_controller *hose = pci_bus_to_host(pdev->bus);
struct pnv_phb *phb = hose->private_data;
struct pci_dn *pdn = pci_get_pdn(pdev);
if (pdn && pdn->force_32bit_msi && !phb->msi32_support)
return -ENODEV;
return (phb && phb->msi_bmp.bitmap) ? 0 : -ENODEV;
}
static int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
{
struct pci_controller *hose = pci_bus_to_host(pdev->bus);
struct pnv_phb *phb = hose->private_data;
struct pci_dn *pdn = pci_get_pdn(pdev);
struct msi_desc *entry;
struct msi_msg msg;
int hwirq;
unsigned int virq;
int rc;
if (WARN_ON(!phb))
if (WARN_ON(!phb) || !phb->msi_bmp.bitmap)
return -ENODEV;
if (pdn && pdn->force_32bit_msi && !phb->msi32_support)
return -ENODEV;
list_for_each_entry(entry, &pdev->msi_list, list) {
......@@ -860,7 +852,6 @@ void __init pnv_pci_init(void)
/* Configure MSIs */
#ifdef CONFIG_PCI_MSI
ppc_md.msi_check_device = pnv_msi_check_device;
ppc_md.setup_msi_irqs = pnv_setup_msi_irqs;
ppc_md.teardown_msi_irqs = pnv_teardown_msi_irqs;
#endif
......
......@@ -336,26 +336,6 @@ static int msi_quota_for_device(struct pci_dev *dev, int request)
return request;
}
static int rtas_msi_check_device(struct pci_dev *pdev, int nvec, int type)
{
int quota, rc;
if (type == PCI_CAP_ID_MSIX)
rc = check_req_msix(pdev, nvec);
else
rc = check_req_msi(pdev, nvec);
if (rc)
return rc;
quota = msi_quota_for_device(pdev, nvec);
if (quota && quota < nvec)
return quota;
return 0;
}
static int check_msix_entries(struct pci_dev *pdev)
{
struct msi_desc *entry;
......@@ -397,15 +377,24 @@ static void rtas_hack_32bit_msi_gen2(struct pci_dev *pdev)
static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec_in, int type)
{
struct pci_dn *pdn;
int hwirq, virq, i, rc;
int hwirq, virq, i, quota, rc;
struct msi_desc *entry;
struct msi_msg msg;
int nvec = nvec_in;
int use_32bit_msi_hack = 0;
pdn = pci_get_pdn(pdev);
if (!pdn)
return -ENODEV;
if (type == PCI_CAP_ID_MSIX)
rc = check_req_msix(pdev, nvec);
else
rc = check_req_msi(pdev, nvec);
if (rc)
return rc;
quota = msi_quota_for_device(pdev, nvec);
if (quota && quota < nvec)
return quota;
if (type == PCI_CAP_ID_MSIX && check_msix_entries(pdev))
return -EINVAL;
......@@ -416,12 +405,14 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec_in, int type)
*/
if (type == PCI_CAP_ID_MSIX) {
int m = roundup_pow_of_two(nvec);
int quota = msi_quota_for_device(pdev, m);
quota = msi_quota_for_device(pdev, m);
if (quota >= m)
nvec = m;
}
pdn = pci_get_pdn(pdev);
/*
* Try the new more explicit firmware interface, if that fails fall
* back to the old interface. The old interface is known to never
......@@ -485,7 +476,7 @@ static int rtas_setup_msi_irqs(struct pci_dev *pdev, int nvec_in, int type)
irq_set_msi_desc(virq, entry);
/* Read config space back so we can restore after reset */
read_msi_msg(virq, &msg);
__read_msi_msg(entry, &msg);
entry->msg = msg;
}
......@@ -526,7 +517,6 @@ static int rtas_msi_init(void)
WARN_ON(ppc_md.setup_msi_irqs);
ppc_md.setup_msi_irqs = rtas_setup_msi_irqs;
ppc_md.teardown_msi_irqs = rtas_teardown_msi_irqs;
ppc_md.msi_check_device = rtas_msi_check_device;
WARN_ON(ppc_md.pci_irq_fixup);
ppc_md.pci_irq_fixup = rtas_msi_pci_irq_fixup;
......
......@@ -109,14 +109,6 @@ static int fsl_msi_init_allocator(struct fsl_msi *msi_data)
return 0;
}
static int fsl_msi_check_device(struct pci_dev *pdev, int nvec, int type)
{
if (type == PCI_CAP_ID_MSIX)
pr_debug("fslmsi: MSI-X untested, trying anyway.\n");
return 0;
}
static void fsl_teardown_msi_irqs(struct pci_dev *pdev)
{
struct msi_desc *entry;
......@@ -173,6 +165,9 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
struct msi_msg msg;
struct fsl_msi *msi_data;
if (type == PCI_CAP_ID_MSIX)
pr_debug("fslmsi: MSI-X untested, trying anyway.\n");
/*
* If the PCI node has an fsl,msi property, then we need to use it
* to find the specific MSI.
......@@ -527,7 +522,6 @@ static int fsl_of_msi_probe(struct platform_device *dev)
if (!ppc_md.setup_msi_irqs) {
ppc_md.setup_msi_irqs = fsl_setup_msi_irqs;
ppc_md.teardown_msi_irqs = fsl_teardown_msi_irqs;
ppc_md.msi_check_device = fsl_msi_check_device;
} else if (ppc_md.setup_msi_irqs != fsl_setup_msi_irqs) {
dev_err(&dev->dev, "Different MSI driver already installed!\n");
err = -ENODEV;
......
......@@ -63,14 +63,6 @@ static struct irq_chip mpic_pasemi_msi_chip = {
.name = "PASEMI-MSI",
};
static int pasemi_msi_check_device(struct pci_dev *pdev, int nvec, int type)
{
if (type == PCI_CAP_ID_MSIX)
pr_debug("pasemi_msi: MSI-X untested, trying anyway\n");
return 0;
}
static void pasemi_msi_teardown_msi_irqs(struct pci_dev *pdev)
{
struct msi_desc *entry;
......@@ -97,6 +89,8 @@ static int pasemi_msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
struct msi_msg msg;
int hwirq;
if (type == PCI_CAP_ID_MSIX)
pr_debug("pasemi_msi: MSI-X untested, trying anyway\n");
pr_debug("pasemi_msi_setup_msi_irqs, pdev %p nvec %d type %d\n",
pdev, nvec, type);
......@@ -169,7 +163,6 @@ int mpic_pasemi_msi_init(struct mpic *mpic)
WARN_ON(ppc_md.setup_msi_irqs);
ppc_md.setup_msi_irqs = pasemi_msi_setup_msi_irqs;
ppc_md.teardown_msi_irqs = pasemi_msi_teardown_msi_irqs;
ppc_md.msi_check_device = pasemi_msi_check_device;
return 0;
}
......@@ -105,22 +105,6 @@ static u64 find_u4_magic_addr(struct pci_dev *pdev, unsigned int hwirq)
return 0;
}
static int u3msi_msi_check_device(struct pci_dev *pdev, int nvec, int type)
{
if (type == PCI_CAP_ID_MSIX)
pr_debug("u3msi: MSI-X untested, trying anyway.\n");
/* If we can't find a magic address then MSI ain't gonna work */
if (find_ht_magic_addr(pdev, 0) == 0 &&
find_u4_magic_addr(pdev, 0) == 0) {
pr_debug("u3msi: no magic address found for %s\n",
pci_name(pdev));
return -ENXIO;
}
return 0;
}
static void u3msi_teardown_msi_irqs(struct pci_dev *pdev)
{
struct msi_desc *entry;
......@@ -146,6 +130,17 @@ static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
u64 addr;
int hwirq;
if (type == PCI_CAP_ID_MSIX)
pr_debug("u3msi: MSI-X untested, trying anyway.\n");
/* If we can't find a magic address then MSI ain't gonna work */
if (find_ht_magic_addr(pdev, 0) == 0 &&
find_u4_magic_addr(pdev, 0) == 0) {
pr_debug("u3msi: no magic address found for %s\n",
pci_name(pdev));
return -ENXIO;
}
list_for_each_entry(entry, &pdev->msi_list, list) {
hwirq = msi_bitmap_alloc_hwirqs(&msi_mpic->msi_bitmap, 1);
if (hwirq < 0) {
......@@ -202,7 +197,6 @@ int mpic_u3msi_init(struct mpic *mpic)
WARN_ON(ppc_md.setup_msi_irqs);
ppc_md.setup_msi_irqs = u3msi_setup_msi_irqs;
ppc_md.teardown_msi_irqs = u3msi_teardown_msi_irqs;
ppc_md.msi_check_device = u3msi_msi_check_device;
return 0;
}
......@@ -44,6 +44,12 @@ static int hsta_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
int irq, hwirq;
u64 addr;
/* We don't support MSI-X */
if (type == PCI_CAP_ID_MSIX) {
pr_debug("%s: MSI-X not supported.\n", __func__);
return -EINVAL;
}
list_for_each_entry(entry, &dev->msi_list, list) {
irq = msi_bitmap_alloc_hwirqs(&ppc4xx_hsta_msi.bmp, 1);
if (irq < 0) {
......@@ -117,17 +123,6 @@ static void hsta_teardown_msi_irqs(struct pci_dev *dev)
}
}
static int hsta_msi_check_device(struct pci_dev *pdev, int nvec, int type)
{
/* We don't support MSI-X */
if (type == PCI_CAP_ID_MSIX) {
pr_debug("%s: MSI-X not supported.\n", __func__);
return -EINVAL;
}
return 0;
}
static int hsta_msi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
......@@ -178,7 +173,6 @@ static int hsta_msi_probe(struct platform_device *pdev)
ppc_md.setup_msi_irqs = hsta_setup_msi_irqs;
ppc_md.teardown_msi_irqs = hsta_teardown_msi_irqs;
ppc_md.msi_check_device = hsta_msi_check_device;
return 0;
out2:
......
......@@ -85,8 +85,12 @@ static int ppc4xx_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
struct msi_desc *entry;
struct ppc4xx_msi *msi_data = &ppc4xx_msi;
msi_data->msi_virqs = kmalloc((msi_irqs) * sizeof(int),
GFP_KERNEL);
dev_dbg(&dev->dev, "PCIE-MSI:%s called. vec %x type %d\n",
__func__, nvec, type);
if (type == PCI_CAP_ID_MSIX)
pr_debug("ppc4xx msi: MSI-X untested, trying anyway.\n");
msi_data->msi_virqs = kmalloc((msi_irqs) * sizeof(int), GFP_KERNEL);
if (!msi_data->msi_virqs)
return -ENOMEM;
......@@ -134,16 +138,6 @@ void ppc4xx_teardown_msi_irqs(struct pci_dev *dev)
}
}
static int ppc4xx_msi_check_device(struct pci_dev *pdev, int nvec, int type)
{
dev_dbg(&pdev->dev, "PCIE-MSI:%s called. vec %x type %d\n",
__func__, nvec, type);
if (type == PCI_CAP_ID_MSIX)
pr_debug("ppc4xx msi: MSI-X untested, trying anyway.\n");
return 0;
}
static int ppc4xx_setup_pcieh_hw(struct platform_device *dev,
struct resource res, struct ppc4xx_msi *msi)
{
......@@ -259,7 +253,6 @@ static int ppc4xx_msi_probe(struct platform_device *dev)
ppc_md.setup_msi_irqs = ppc4xx_setup_msi_irqs;
ppc_md.teardown_msi_irqs = ppc4xx_teardown_msi_irqs;
ppc_md.msi_check_device = ppc4xx_msi_check_device;
return err;
error_out:
......
......@@ -81,14 +81,14 @@ struct pci_ops pci_root_ops = {
*/
DEFINE_RAW_SPINLOCK(pci_config_lock);
static int can_skip_ioresource_align(const struct dmi_system_id *d)
static int __init can_skip_ioresource_align(const struct dmi_system_id *d)
{
pci_probe |= PCI_CAN_SKIP_ISA_ALIGN;
printk(KERN_INFO "PCI: %s detected, can skip ISA alignment\n", d->ident);
return 0;
}
static const struct dmi_system_id can_skip_pciprobe_dmi_table[] = {
static const struct dmi_system_id can_skip_pciprobe_dmi_table[] __initconst = {
/*
* Systems where PCI IO resource ISA alignment can be skipped
* when the ISA enable bit in the bridge control is not set
......@@ -186,7 +186,7 @@ void pcibios_remove_bus(struct pci_bus *bus)
* on the kernel command line (which was parsed earlier).
*/
static int set_bf_sort(const struct dmi_system_id *d)
static int __init set_bf_sort(const struct dmi_system_id *d)
{
if (pci_bf_sort == pci_bf_sort_default) {
pci_bf_sort = pci_dmi_bf;
......@@ -195,7 +195,7 @@ static int set_bf_sort(const struct dmi_system_id *d)
return 0;
}
static void read_dmi_type_b1(const struct dmi_header *dm,
static void __init read_dmi_type_b1(const struct dmi_header *dm,
void *private_data)
{
u8 *d = (u8 *)dm + 4;
......@@ -217,7 +217,7 @@ static void read_dmi_type_b1(const struct dmi_header *dm,
}
}
static int find_sort_method(const struct dmi_system_id *d)
static int __init find_sort_method(const struct dmi_system_id *d)
{
dmi_walk(read_dmi_type_b1, NULL);
......@@ -232,7 +232,7 @@ static int find_sort_method(const struct dmi_system_id *d)
* Enable renumbering of PCI bus# ranges to reach all PCI busses (Cardbus)
*/
#ifdef __i386__
static int assign_all_busses(const struct dmi_system_id *d)
static int __init assign_all_busses(const struct dmi_system_id *d)
{
pci_probe |= PCI_ASSIGN_ALL_BUSSES;
printk(KERN_INFO "%s detected: enabling PCI bus# renumbering"
......@@ -241,7 +241,7 @@ static int assign_all_busses(const struct dmi_system_id *d)
}
#endif
static int set_scan_all(const struct dmi_system_id *d)
static int __init set_scan_all(const struct dmi_system_id *d)
{
printk(KERN_INFO "PCI: %s detected, enabling pci=pcie_scan_all\n",
d->ident);
......@@ -249,7 +249,7 @@ static int set_scan_all(const struct dmi_system_id *d)
return 0;
}
static const struct dmi_system_id pciprobe_dmi_table[] = {
static const struct dmi_system_id pciprobe_dmi_table[] __initconst = {
#ifdef __i386__
/*
* Laptops which need pci=assign-busses to see Cardbus cards
......@@ -512,7 +512,7 @@ int __init pcibios_init(void)
return 0;
}
char * __init pcibios_setup(char *str)
char *__init pcibios_setup(char *str)
{
if (!strcmp(str, "off")) {
pci_probe = 0;
......
......@@ -31,7 +31,7 @@ static DEFINE_MUTEX(pci_mmcfg_lock);
LIST_HEAD(pci_mmcfg_list);
static __init void pci_mmconfig_remove(struct pci_mmcfg_region *cfg)
static void __init pci_mmconfig_remove(struct pci_mmcfg_region *cfg)
{
if (cfg->res.parent)
release_resource(&cfg->res);
......@@ -39,7 +39,7 @@ static __init void pci_mmconfig_remove(struct pci_mmcfg_region *cfg)
kfree(cfg);
}
static __init void free_all_mmcfg(void)
static void __init free_all_mmcfg(void)
{
struct pci_mmcfg_region *cfg, *tmp;
......@@ -93,7 +93,7 @@ static struct pci_mmcfg_region *pci_mmconfig_alloc(int segment, int start,
return new;
}
static __init struct pci_mmcfg_region *pci_mmconfig_add(int segment, int start,
static struct pci_mmcfg_region *__init pci_mmconfig_add(int segment, int start,
int end, u64 addr)
{
struct pci_mmcfg_region *new;
......@@ -125,7 +125,7 @@ struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus)
return NULL;
}
static const char __init *pci_mmcfg_e7520(void)
static const char *__init pci_mmcfg_e7520(void)
{
u32 win;
raw_pci_ops->read(0, 0, PCI_DEVFN(0, 0), 0xce, 2, &win);
......@@ -140,7 +140,7 @@ static const char __init *pci_mmcfg_e7520(void)
return "Intel Corporation E7520 Memory Controller Hub";
}
static const char __init *pci_mmcfg_intel_945(void)
static const char *__init pci_mmcfg_intel_945(void)
{
u32 pciexbar, mask = 0, len = 0;
......@@ -184,7 +184,7 @@ static const char __init *pci_mmcfg_intel_945(void)
return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub";
}
static const char __init *pci_mmcfg_amd_fam10h(void)
static const char *__init pci_mmcfg_amd_fam10h(void)
{
u32 low, high, address;
u64 base, msr;
......@@ -235,21 +235,25 @@ static const char __init *pci_mmcfg_amd_fam10h(void)
}
static bool __initdata mcp55_checked;
static const char __init *pci_mmcfg_nvidia_mcp55(void)
static const char *__init pci_mmcfg_nvidia_mcp55(void)
{
int bus;
int mcp55_mmconf_found = 0;
static const u32 extcfg_regnum = 0x90;
static const u32 extcfg_regsize = 4;
static const u32 extcfg_enable_mask = 1<<31;
static const u32 extcfg_start_mask = 0xff<<16;
static const int extcfg_start_shift = 16;
static const u32 extcfg_size_mask = 0x3<<28;
static const int extcfg_size_shift = 28;
static const int extcfg_sizebus[] = {0x100, 0x80, 0x40, 0x20};
static const u32 extcfg_base_mask[] = {0x7ff8, 0x7ffc, 0x7ffe, 0x7fff};
static const int extcfg_base_lshift = 25;
static const u32 extcfg_regnum __initconst = 0x90;
static const u32 extcfg_regsize __initconst = 4;
static const u32 extcfg_enable_mask __initconst = 1 << 31;
static const u32 extcfg_start_mask __initconst = 0xff << 16;
static const int extcfg_start_shift __initconst = 16;
static const u32 extcfg_size_mask __initconst = 0x3 << 28;
static const int extcfg_size_shift __initconst = 28;
static const int extcfg_sizebus[] __initconst = {
0x100, 0x80, 0x40, 0x20
};
static const u32 extcfg_base_mask[] __initconst = {
0x7ff8, 0x7ffc, 0x7ffe, 0x7fff
};
static const int extcfg_base_lshift __initconst = 25;
/*
* do check if amd fam10h already took over
......@@ -302,7 +306,7 @@ struct pci_mmcfg_hostbridge_probe {
const char *(*probe)(void);
};
static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = {
static const struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initconst = {
{ 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_E7520_MCH, pci_mmcfg_e7520 },
{ 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_INTEL,
......
......@@ -79,13 +79,13 @@ union bios32 {
static struct {
unsigned long address;
unsigned short segment;
} bios32_indirect = { 0, __KERNEL_CS };
} bios32_indirect __initdata = { 0, __KERNEL_CS };
/*
* Returns the entry point for the given service, NULL on error
*/
static unsigned long bios32_service(unsigned long service)
static unsigned long __init bios32_service(unsigned long service)
{
unsigned char return_code; /* %al */
unsigned long address; /* %ebx */
......@@ -124,7 +124,7 @@ static struct {
static int pci_bios_present;
static int check_pcibios(void)
static int __init check_pcibios(void)
{
u32 signature, eax, ebx, ecx;
u8 status, major_ver, minor_ver, hw_mech;
......@@ -312,7 +312,7 @@ static const struct pci_raw_ops pci_bios_access = {
* Try to find PCI BIOS.
*/
static const struct pci_raw_ops *pci_find_bios(void)
static const struct pci_raw_ops *__init pci_find_bios(void)
{
union bios32 *check;
unsigned char sum;
......
......@@ -35,7 +35,6 @@
/*
* PCI device IDs.
*/
#define PCI_VENDOR_ID_VMWARE 0x15AD
#define PCI_DEVICE_ID_VMWARE_SVGA2 0x0405
/*
......
......@@ -136,6 +136,10 @@ static int armada_370_xp_setup_msi_irq(struct msi_chip *chip,
struct msi_msg msg;
int virq, hwirq;
/* We support MSI, but not MSI-X */
if (desc->msi_attrib.is_msix)
return -EINVAL;
hwirq = armada_370_xp_alloc_msi();
if (hwirq < 0)
return hwirq;
......@@ -166,15 +170,6 @@ static void armada_370_xp_teardown_msi_irq(struct msi_chip *chip,
armada_370_xp_free_msi(hwirq);
}
static int armada_370_xp_check_msi_device(struct msi_chip *chip, struct pci_dev *dev,
int nvec, int type)
{
/* We support MSI, but not MSI-X */
if (type == PCI_CAP_ID_MSI)
return 0;
return -EINVAL;
}
static struct irq_chip armada_370_xp_msi_irq_chip = {
.name = "armada_370_xp_msi_irq",
.irq_enable = unmask_msi_irq,
......@@ -213,7 +208,6 @@ static int armada_370_xp_msi_init(struct device_node *node,
msi_chip->setup_irq = armada_370_xp_setup_msi_irq;
msi_chip->teardown_irq = armada_370_xp_teardown_msi_irq;
msi_chip->check_device = armada_370_xp_check_msi_device;
msi_chip->of_node = node;
armada_370_xp_msi_domain =
......
......@@ -35,7 +35,6 @@
#include "vmci_driver.h"
#include "vmci_event.h"
#define PCI_VENDOR_ID_VMWARE 0x15AD
#define PCI_DEVICE_ID_VMWARE_VMCI 0x0740
#define VMCI_UTIL_NUM_RESOURCES 1
......
......@@ -117,7 +117,6 @@ enum {
/*
* PCI vendor and device IDs.
*/
#define PCI_VENDOR_ID_VMWARE 0x15AD
#define PCI_DEVICE_ID_VMWARE_VMXNET3 0x07B0
#define MAX_ETHERNET_CARDS 10
#define MAX_PCI_PASSTHRU_DEVICE 6
......
......@@ -5,6 +5,8 @@
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/pci_regs.h>
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/string.h>
/* Max address size we deal with */
......@@ -293,6 +295,51 @@ struct of_pci_range *of_pci_range_parser_one(struct of_pci_range_parser *parser,
}
EXPORT_SYMBOL_GPL(of_pci_range_parser_one);
/*
* of_pci_range_to_resource - Create a resource from an of_pci_range
* @range: the PCI range that describes the resource
* @np: device node where the range belongs to
* @res: pointer to a valid resource that will be updated to
* reflect the values contained in the range.
*
* Returns EINVAL if the range cannot be converted to resource.
*
* Note that if the range is an IO range, the resource will be converted
* using pci_address_to_pio() which can fail if it is called too early or
* if the range cannot be matched to any host bridge IO space (our case here).
* To guard against that we try to register the IO range first.
* If that fails we know that pci_address_to_pio() will do too.
*/
int of_pci_range_to_resource(struct of_pci_range *range,
struct device_node *np, struct resource *res)
{
int err;
res->flags = range->flags;
res->parent = res->child = res->sibling = NULL;
res->name = np->full_name;
if (res->flags & IORESOURCE_IO) {
unsigned long port;
err = pci_register_io_range(range->cpu_addr, range->size);
if (err)
goto invalid_range;
port = pci_address_to_pio(range->cpu_addr);
if (port == (unsigned long)-1) {
err = -EINVAL;
goto invalid_range;
}
res->start = port;
} else {
res->start = range->cpu_addr;
}
res->end = res->start + range->size - 1;
return 0;
invalid_range:
res->start = (resource_size_t)OF_BAD_ADDR;
res->end = (resource_size_t)OF_BAD_ADDR;
return err;
}
#endif /* CONFIG_PCI */
/*
......@@ -601,12 +648,119 @@ const __be32 *of_get_address(struct device_node *dev, int index, u64 *size,
}
EXPORT_SYMBOL(of_get_address);
#ifdef PCI_IOBASE
struct io_range {
struct list_head list;
phys_addr_t start;
resource_size_t size;
};
static LIST_HEAD(io_range_list);
static DEFINE_SPINLOCK(io_range_lock);
#endif
/*
* Record the PCI IO range (expressed as CPU physical address + size).
* Return a negative value if an error has occured, zero otherwise
*/
int __weak pci_register_io_range(phys_addr_t addr, resource_size_t size)
{
int err = 0;
#ifdef PCI_IOBASE
struct io_range *range;
resource_size_t allocated_size = 0;
/* check if the range hasn't been previously recorded */
spin_lock(&io_range_lock);
list_for_each_entry(range, &io_range_list, list) {
if (addr >= range->start && addr + size <= range->start + size) {
/* range already registered, bail out */
goto end_register;
}
allocated_size += range->size;
}
/* range not registed yet, check for available space */
if (allocated_size + size - 1 > IO_SPACE_LIMIT) {
/* if it's too big check if 64K space can be reserved */
if (allocated_size + SZ_64K - 1 > IO_SPACE_LIMIT) {
err = -E2BIG;
goto end_register;
}
size = SZ_64K;
pr_warn("Requested IO range too big, new size set to 64K\n");
}
/* add the range to the list */
range = kzalloc(sizeof(*range), GFP_KERNEL);
if (!range) {
err = -ENOMEM;
goto end_register;
}
range->start = addr;
range->size = size;
list_add_tail(&range->list, &io_range_list);
end_register:
spin_unlock(&io_range_lock);
#endif
return err;
}
phys_addr_t pci_pio_to_address(unsigned long pio)
{
phys_addr_t address = (phys_addr_t)OF_BAD_ADDR;
#ifdef PCI_IOBASE
struct io_range *range;
resource_size_t allocated_size = 0;
if (pio > IO_SPACE_LIMIT)
return address;
spin_lock(&io_range_lock);
list_for_each_entry(range, &io_range_list, list) {
if (pio >= allocated_size && pio < allocated_size + range->size) {
address = range->start + pio - allocated_size;
break;
}
allocated_size += range->size;
}
spin_unlock(&io_range_lock);
#endif
return address;
}
unsigned long __weak pci_address_to_pio(phys_addr_t address)
{
#ifdef PCI_IOBASE
struct io_range *res;
resource_size_t offset = 0;
unsigned long addr = -1;
spin_lock(&io_range_lock);
list_for_each_entry(res, &io_range_list, list) {
if (address >= res->start && address < res->start + res->size) {
addr = res->start - address + offset;
break;
}
offset += res->size;
}
spin_unlock(&io_range_lock);
return addr;
#else
if (address > IO_SPACE_LIMIT)
return (unsigned long)-1;
return (unsigned long) address;
#endif
}
static int __of_address_to_resource(struct device_node *dev,
......
#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_pci.h>
#include <linux/slab.h>
static inline int __of_pci_pci_compare(struct device_node *node,
unsigned int data)
......@@ -89,6 +91,146 @@ int of_pci_parse_bus_range(struct device_node *node, struct resource *res)
}
EXPORT_SYMBOL_GPL(of_pci_parse_bus_range);
/**
* This function will try to obtain the host bridge domain number by
* finding a property called "linux,pci-domain" of the given device node.
*
* @node: device tree node with the domain information
*
* Returns the associated domain number from DT in the range [0-0xffff], or
* a negative value if the required property is not found.
*/
int of_get_pci_domain_nr(struct device_node *node)
{
const __be32 *value;
int len;
u16 domain;
value = of_get_property(node, "linux,pci-domain", &len);
if (!value || len < sizeof(*value))
return -EINVAL;
domain = (u16)be32_to_cpup(value);
return domain;
}
EXPORT_SYMBOL_GPL(of_get_pci_domain_nr);
#if defined(CONFIG_OF_ADDRESS)
/**
* of_pci_get_host_bridge_resources - Parse PCI host bridge resources from DT
* @dev: device node of the host bridge having the range property
* @busno: bus number associated with the bridge root bus
* @bus_max: maximum number of buses for this bridge
* @resources: list where the range of resources will be added after DT parsing
* @io_base: pointer to a variable that will contain on return the physical
* address for the start of the I/O range. Can be NULL if the caller doesn't
* expect IO ranges to be present in the device tree.
*
* It is the caller's job to free the @resources list.
*
* This function will parse the "ranges" property of a PCI host bridge device
* node and setup the resource mapping based on its content. It is expected
* that the property conforms with the Power ePAPR document.
*
* It returns zero if the range parsing has been successful or a standard error
* value if it failed.
*/
int of_pci_get_host_bridge_resources(struct device_node *dev,
unsigned char busno, unsigned char bus_max,
struct list_head *resources, resource_size_t *io_base)
{
struct resource *res;
struct resource *bus_range;
struct of_pci_range range;
struct of_pci_range_parser parser;
char range_type[4];
int err;
if (io_base)
*io_base = (resource_size_t)OF_BAD_ADDR;
bus_range = kzalloc(sizeof(*bus_range), GFP_KERNEL);
if (!bus_range)
return -ENOMEM;
pr_info("PCI host bridge %s ranges:\n", dev->full_name);
err = of_pci_parse_bus_range(dev, bus_range);
if (err) {
bus_range->start = busno;
bus_range->end = bus_max;
bus_range->flags = IORESOURCE_BUS;
pr_info(" No bus range found for %s, using %pR\n",
dev->full_name, bus_range);
} else {
if (bus_range->end > bus_range->start + bus_max)
bus_range->end = bus_range->start + bus_max;
}
pci_add_resource(resources, bus_range);
/* Check for ranges property */
err = of_pci_range_parser_init(&parser, dev);
if (err)
goto parse_failed;
pr_debug("Parsing ranges property...\n");
for_each_of_pci_range(&parser, &range) {
/* Read next ranges element */
if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_IO)
snprintf(range_type, 4, " IO");
else if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_MEM)
snprintf(range_type, 4, "MEM");
else
snprintf(range_type, 4, "err");
pr_info(" %s %#010llx..%#010llx -> %#010llx\n", range_type,
range.cpu_addr, range.cpu_addr + range.size - 1,
range.pci_addr);
/*
* If we failed translation or got a zero-sized region
* then skip this range
*/
if (range.cpu_addr == OF_BAD_ADDR || range.size == 0)
continue;
res = kzalloc(sizeof(struct resource), GFP_KERNEL);
if (!res) {
err = -ENOMEM;
goto parse_failed;
}
err = of_pci_range_to_resource(&range, dev, res);
if (err)
goto conversion_failed;
if (resource_type(res) == IORESOURCE_IO) {
if (!io_base) {
pr_err("I/O range found for %s. Please provide an io_base pointer to save CPU base address\n",
dev->full_name);
err = -EINVAL;
goto conversion_failed;
}
if (*io_base != (resource_size_t)OF_BAD_ADDR)
pr_warn("More than one I/O resource converted for %s. CPU base address for old range lost!\n",
dev->full_name);
*io_base = range.cpu_addr;
}
pci_add_resource_offset(resources, res, res->start - range.pci_addr);
}
return 0;
conversion_failed:
kfree(res);
parse_failed:
pci_free_resource_list(resources);
return err;
}
EXPORT_SYMBOL_GPL(of_pci_get_host_bridge_resources);
#endif /* CONFIG_OF_ADDRESS */
#ifdef CONFIG_PCI_MSI
static LIST_HEAD(of_pci_msi_chip_list);
......
......@@ -63,4 +63,32 @@ config PCIE_SPEAR13XX
help
Say Y here if you want PCIe support on SPEAr13XX SoCs.
config PCI_KEYSTONE
bool "TI Keystone PCIe controller"
depends on ARCH_KEYSTONE
select PCIE_DW
select PCIEPORTBUS
help
Say Y here if you want to enable PCI controller support on Keystone
SoCs. The PCI controller on Keystone is based on Designware hardware
and therefore the driver re-uses the Designware core functions to
implement the driver.
config PCIE_XILINX
bool "Xilinx AXI PCIe host bridge support"
depends on ARCH_ZYNQ
help
Say 'Y' here if you want kernel to support the Xilinx AXI PCIe
Host Bridge driver.
config PCI_XGENE
bool "X-Gene PCIe controller"
depends on ARCH_XGENE
depends on OF
select PCIEPORTBUS
help
Say Y here if you want internal PCI support on APM X-Gene SoC.
There are 5 internal PCIe ports available. Each port is GEN3 capable
and have varied lanes from x1 to x8.
endmenu
......@@ -8,3 +8,6 @@ obj-$(CONFIG_PCI_RCAR_GEN2) += pci-rcar-gen2.o
obj-$(CONFIG_PCI_RCAR_GEN2_PCIE) += pcie-rcar.o
obj-$(CONFIG_PCI_HOST_GENERIC) += pci-host-generic.o
obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o
obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o
obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o
obj-$(CONFIG_PCI_XGENE) += pci-xgene.o
......@@ -257,11 +257,6 @@ static int imx6_pcie_deassert_core_reset(struct pcie_port *pp)
struct imx6_pcie *imx6_pcie = to_imx6_pcie(pp);
int ret;
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
IMX6Q_GPR1_PCIE_TEST_PD, 0 << 18);
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16);
ret = clk_prepare_enable(imx6_pcie->pcie_phy);
if (ret) {
dev_err(pp->dev, "unable to enable pcie_phy clock\n");
......@@ -283,6 +278,12 @@ static int imx6_pcie_deassert_core_reset(struct pcie_port *pp)
/* allow the clocks to stabilize */
usleep_range(200, 500);
/* power up core phy and enable ref clock */
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
IMX6Q_GPR1_PCIE_TEST_PD, 0 << 18);
regmap_update_bits(imx6_pcie->iomuxc_gpr, IOMUXC_GPR1,
IMX6Q_GPR1_PCIE_REF_CLK_EN, 1 << 16);
/* Some boards don't have PCIe reset GPIO. */
if (gpio_is_valid(imx6_pcie->reset_gpio)) {
gpio_set_value(imx6_pcie->reset_gpio, 0);
......@@ -647,7 +648,7 @@ static int __init imx6_pcie_init(void)
{
return platform_driver_probe(&imx6_pcie_driver, imx6_pcie_probe);
}
fs_initcall(imx6_pcie_init);
module_init(imx6_pcie_init);
MODULE_AUTHOR("Sean Cross <xobs@kosagi.com>");
MODULE_DESCRIPTION("Freescale i.MX6 PCIe host controller driver");
......
/*
* Designware application register space functions for Keystone PCI controller
*
* Copyright (C) 2013-2014 Texas Instruments., Ltd.
* http://www.ti.com
*
* Author: Murali Karicheri <m-karicheri2@ti.com>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_pci.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include "pcie-designware.h"
#include "pci-keystone.h"
/* Application register defines */
#define LTSSM_EN_VAL 1
#define LTSSM_STATE_MASK 0x1f
#define LTSSM_STATE_L0 0x11
#define DBI_CS2_EN_VAL 0x20
#define OB_XLAT_EN_VAL 2
/* Application registers */
#define CMD_STATUS 0x004
#define CFG_SETUP 0x008
#define OB_SIZE 0x030
#define CFG_PCIM_WIN_SZ_IDX 3
#define CFG_PCIM_WIN_CNT 32
#define SPACE0_REMOTE_CFG_OFFSET 0x1000
#define OB_OFFSET_INDEX(n) (0x200 + (8 * n))
#define OB_OFFSET_HI(n) (0x204 + (8 * n))
/* IRQ register defines */
#define IRQ_EOI 0x050
#define IRQ_STATUS 0x184
#define IRQ_ENABLE_SET 0x188
#define IRQ_ENABLE_CLR 0x18c
#define MSI_IRQ 0x054
#define MSI0_IRQ_STATUS 0x104
#define MSI0_IRQ_ENABLE_SET 0x108
#define MSI0_IRQ_ENABLE_CLR 0x10c
#define IRQ_STATUS 0x184
#define MSI_IRQ_OFFSET 4
/* Config space registers */
#define DEBUG0 0x728
#define to_keystone_pcie(x) container_of(x, struct keystone_pcie, pp)
static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
{
return sys->private_data;
}
static inline void update_reg_offset_bit_pos(u32 offset, u32 *reg_offset,
u32 *bit_pos)
{
*reg_offset = offset % 8;
*bit_pos = offset >> 3;
}
u32 ks_dw_pcie_get_msi_addr(struct pcie_port *pp)
{
struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
return ks_pcie->app.start + MSI_IRQ;
}
void ks_dw_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset)
{
struct pcie_port *pp = &ks_pcie->pp;
u32 pending, vector;
int src, virq;
pending = readl(ks_pcie->va_app_base + MSI0_IRQ_STATUS + (offset << 4));
/*
* MSI0 status bit 0-3 shows vectors 0, 8, 16, 24, MSI1 status bit
* shows 1, 9, 17, 25 and so forth
*/
for (src = 0; src < 4; src++) {
if (BIT(src) & pending) {
vector = offset + (src << 3);
virq = irq_linear_revmap(pp->irq_domain, vector);
dev_dbg(pp->dev, "irq: bit %d, vector %d, virq %d\n",
src, vector, virq);
generic_handle_irq(virq);
}
}
}
static void ks_dw_pcie_msi_irq_ack(struct irq_data *d)
{
u32 offset, reg_offset, bit_pos;
struct keystone_pcie *ks_pcie;
unsigned int irq = d->irq;
struct msi_desc *msi;
struct pcie_port *pp;
msi = irq_get_msi_desc(irq);
pp = sys_to_pcie(msi->dev->bus->sysdata);
ks_pcie = to_keystone_pcie(pp);
offset = irq - irq_linear_revmap(pp->irq_domain, 0);
update_reg_offset_bit_pos(offset, &reg_offset, &bit_pos);
writel(BIT(bit_pos),
ks_pcie->va_app_base + MSI0_IRQ_STATUS + (reg_offset << 4));
writel(reg_offset + MSI_IRQ_OFFSET, ks_pcie->va_app_base + IRQ_EOI);
}
void ks_dw_pcie_msi_set_irq(struct pcie_port *pp, int irq)
{
u32 reg_offset, bit_pos;
struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
update_reg_offset_bit_pos(irq, &reg_offset, &bit_pos);
writel(BIT(bit_pos),
ks_pcie->va_app_base + MSI0_IRQ_ENABLE_SET + (reg_offset << 4));
}
void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
{
u32 reg_offset, bit_pos;
struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
update_reg_offset_bit_pos(irq, &reg_offset, &bit_pos);
writel(BIT(bit_pos),
ks_pcie->va_app_base + MSI0_IRQ_ENABLE_CLR + (reg_offset << 4));
}
static void ks_dw_pcie_msi_irq_mask(struct irq_data *d)
{
struct keystone_pcie *ks_pcie;
unsigned int irq = d->irq;
struct msi_desc *msi;
struct pcie_port *pp;
u32 offset;
msi = irq_get_msi_desc(irq);
pp = sys_to_pcie(msi->dev->bus->sysdata);
ks_pcie = to_keystone_pcie(pp);
offset = irq - irq_linear_revmap(pp->irq_domain, 0);
/* Mask the end point if PVM implemented */
if (IS_ENABLED(CONFIG_PCI_MSI)) {
if (msi->msi_attrib.maskbit)
mask_msi_irq(d);
}
ks_dw_pcie_msi_clear_irq(pp, offset);
}
static void ks_dw_pcie_msi_irq_unmask(struct irq_data *d)
{
struct keystone_pcie *ks_pcie;
unsigned int irq = d->irq;
struct msi_desc *msi;
struct pcie_port *pp;
u32 offset;
msi = irq_get_msi_desc(irq);
pp = sys_to_pcie(msi->dev->bus->sysdata);
ks_pcie = to_keystone_pcie(pp);
offset = irq - irq_linear_revmap(pp->irq_domain, 0);
/* Mask the end point if PVM implemented */
if (IS_ENABLED(CONFIG_PCI_MSI)) {
if (msi->msi_attrib.maskbit)
unmask_msi_irq(d);
}
ks_dw_pcie_msi_set_irq(pp, offset);
}
static struct irq_chip ks_dw_pcie_msi_irq_chip = {
.name = "Keystone-PCIe-MSI-IRQ",
.irq_ack = ks_dw_pcie_msi_irq_ack,
.irq_mask = ks_dw_pcie_msi_irq_mask,
.irq_unmask = ks_dw_pcie_msi_irq_unmask,
};
static int ks_dw_pcie_msi_map(struct irq_domain *domain, unsigned int irq,
irq_hw_number_t hwirq)
{
irq_set_chip_and_handler(irq, &ks_dw_pcie_msi_irq_chip,
handle_level_irq);
irq_set_chip_data(irq, domain->host_data);
set_irq_flags(irq, IRQF_VALID);
return 0;
}
const struct irq_domain_ops ks_dw_pcie_msi_domain_ops = {
.map = ks_dw_pcie_msi_map,
};
int ks_dw_pcie_msi_host_init(struct pcie_port *pp, struct msi_chip *chip)
{
struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
int i;
pp->irq_domain = irq_domain_add_linear(ks_pcie->msi_intc_np,
MAX_MSI_IRQS,
&ks_dw_pcie_msi_domain_ops,
chip);
if (!pp->irq_domain) {
dev_err(pp->dev, "irq domain init failed\n");
return -ENXIO;
}
for (i = 0; i < MAX_MSI_IRQS; i++)
irq_create_mapping(pp->irq_domain, i);
return 0;
}
void ks_dw_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie)
{
int i;
for (i = 0; i < MAX_LEGACY_IRQS; i++)
writel(0x1, ks_pcie->va_app_base + IRQ_ENABLE_SET + (i << 4));
}
void ks_dw_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, int offset)
{
struct pcie_port *pp = &ks_pcie->pp;
u32 pending;
int virq;
pending = readl(ks_pcie->va_app_base + IRQ_STATUS + (offset << 4));
if (BIT(0) & pending) {
virq = irq_linear_revmap(ks_pcie->legacy_irq_domain, offset);
dev_dbg(pp->dev, ": irq: irq_offset %d, virq %d\n", offset,
virq);
generic_handle_irq(virq);
}
/* EOI the INTx interrupt */
writel(offset, ks_pcie->va_app_base + IRQ_EOI);
}
static void ks_dw_pcie_ack_legacy_irq(struct irq_data *d)
{
}
static void ks_dw_pcie_mask_legacy_irq(struct irq_data *d)
{
}
static void ks_dw_pcie_unmask_legacy_irq(struct irq_data *d)
{
}
static struct irq_chip ks_dw_pcie_legacy_irq_chip = {
.name = "Keystone-PCI-Legacy-IRQ",
.irq_ack = ks_dw_pcie_ack_legacy_irq,
.irq_mask = ks_dw_pcie_mask_legacy_irq,
.irq_unmask = ks_dw_pcie_unmask_legacy_irq,
};
static int ks_dw_pcie_init_legacy_irq_map(struct irq_domain *d,
unsigned int irq, irq_hw_number_t hw_irq)
{
irq_set_chip_and_handler(irq, &ks_dw_pcie_legacy_irq_chip,
handle_level_irq);
irq_set_chip_data(irq, d->host_data);
set_irq_flags(irq, IRQF_VALID);
return 0;
}
static const struct irq_domain_ops ks_dw_pcie_legacy_irq_domain_ops = {
.map = ks_dw_pcie_init_legacy_irq_map,
.xlate = irq_domain_xlate_onetwocell,
};
/**
* ks_dw_pcie_set_dbi_mode() - Set DBI mode to access overlaid BAR mask
* registers
*
* Since modification of dbi_cs2 involves different clock domain, read the
* status back to ensure the transition is complete.
*/
static void ks_dw_pcie_set_dbi_mode(void __iomem *reg_virt)
{
u32 val;
writel(DBI_CS2_EN_VAL | readl(reg_virt + CMD_STATUS),
reg_virt + CMD_STATUS);
do {
val = readl(reg_virt + CMD_STATUS);
} while (!(val & DBI_CS2_EN_VAL));
}
/**
* ks_dw_pcie_clear_dbi_mode() - Disable DBI mode
*
* Since modification of dbi_cs2 involves different clock domain, read the
* status back to ensure the transition is complete.
*/
static void ks_dw_pcie_clear_dbi_mode(void __iomem *reg_virt)
{
u32 val;
writel(~DBI_CS2_EN_VAL & readl(reg_virt + CMD_STATUS),
reg_virt + CMD_STATUS);
do {
val = readl(reg_virt + CMD_STATUS);
} while (val & DBI_CS2_EN_VAL);
}
void ks_dw_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie)
{
struct pcie_port *pp = &ks_pcie->pp;
u32 start = pp->mem.start, end = pp->mem.end;
int i, tr_size;
/* Disable BARs for inbound access */
ks_dw_pcie_set_dbi_mode(ks_pcie->va_app_base);
writel(0, pp->dbi_base + PCI_BASE_ADDRESS_0);
writel(0, pp->dbi_base + PCI_BASE_ADDRESS_1);
ks_dw_pcie_clear_dbi_mode(ks_pcie->va_app_base);
/* Set outbound translation size per window division */
writel(CFG_PCIM_WIN_SZ_IDX & 0x7, ks_pcie->va_app_base + OB_SIZE);
tr_size = (1 << (CFG_PCIM_WIN_SZ_IDX & 0x7)) * SZ_1M;
/* Using Direct 1:1 mapping of RC <-> PCI memory space */
for (i = 0; (i < CFG_PCIM_WIN_CNT) && (start < end); i++) {
writel(start | 1, ks_pcie->va_app_base + OB_OFFSET_INDEX(i));
writel(0, ks_pcie->va_app_base + OB_OFFSET_HI(i));
start += tr_size;
}
/* Enable OB translation */
writel(OB_XLAT_EN_VAL | readl(ks_pcie->va_app_base + CMD_STATUS),
ks_pcie->va_app_base + CMD_STATUS);
}
/**
* ks_pcie_cfg_setup() - Set up configuration space address for a device
*
* @ks_pcie: ptr to keystone_pcie structure
* @bus: Bus number the device is residing on
* @devfn: device, function number info
*
* Forms and returns the address of configuration space mapped in PCIESS
* address space 0. Also configures CFG_SETUP for remote configuration space
* access.
*
* The address space has two regions to access configuration - local and remote.
* We access local region for bus 0 (as RC is attached on bus 0) and remote
* region for others with TYPE 1 access when bus > 1. As for device on bus = 1,
* we will do TYPE 0 access as it will be on our secondary bus (logical).
* CFG_SETUP is needed only for remote configuration access.
*/
static void __iomem *ks_pcie_cfg_setup(struct keystone_pcie *ks_pcie, u8 bus,
unsigned int devfn)
{
u8 device = PCI_SLOT(devfn), function = PCI_FUNC(devfn);
struct pcie_port *pp = &ks_pcie->pp;
u32 regval;
if (bus == 0)
return pp->dbi_base;
regval = (bus << 16) | (device << 8) | function;
/*
* Since Bus#1 will be a virtual bus, we need to have TYPE0
* access only.
* TYPE 1
*/
if (bus != 1)
regval |= BIT(24);
writel(regval, ks_pcie->va_app_base + CFG_SETUP);
return pp->va_cfg0_base;
}
int ks_dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
unsigned int devfn, int where, int size, u32 *val)
{
struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
u8 bus_num = bus->number;
void __iomem *addr;
addr = ks_pcie_cfg_setup(ks_pcie, bus_num, devfn);
return dw_pcie_cfg_read(addr + (where & ~0x3), where, size, val);
}
int ks_dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
unsigned int devfn, int where, int size, u32 val)
{
struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
u8 bus_num = bus->number;
void __iomem *addr;
addr = ks_pcie_cfg_setup(ks_pcie, bus_num, devfn);
return dw_pcie_cfg_write(addr + (where & ~0x3), where, size, val);
}
/**
* ks_dw_pcie_v3_65_scan_bus() - keystone scan_bus post initialization
*
* This sets BAR0 to enable inbound access for MSI_IRQ register
*/
void ks_dw_pcie_v3_65_scan_bus(struct pcie_port *pp)
{
struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
/* Configure and set up BAR0 */
ks_dw_pcie_set_dbi_mode(ks_pcie->va_app_base);
/* Enable BAR0 */
writel(1, pp->dbi_base + PCI_BASE_ADDRESS_0);
writel(SZ_4K - 1, pp->dbi_base + PCI_BASE_ADDRESS_0);
ks_dw_pcie_clear_dbi_mode(ks_pcie->va_app_base);
/*
* For BAR0, just setting bus address for inbound writes (MSI) should
* be sufficient. Use physical address to avoid any conflicts.
*/
writel(ks_pcie->app.start, pp->dbi_base + PCI_BASE_ADDRESS_0);
}
/**
* ks_dw_pcie_link_up() - Check if link up
*/
int ks_dw_pcie_link_up(struct pcie_port *pp)
{
u32 val = readl(pp->dbi_base + DEBUG0);
return (val & LTSSM_STATE_MASK) == LTSSM_STATE_L0;
}
void ks_dw_pcie_initiate_link_train(struct keystone_pcie *ks_pcie)
{
u32 val;
/* Disable Link training */
val = readl(ks_pcie->va_app_base + CMD_STATUS);
val &= ~LTSSM_EN_VAL;
writel(LTSSM_EN_VAL | val, ks_pcie->va_app_base + CMD_STATUS);
/* Initiate Link Training */
val = readl(ks_pcie->va_app_base + CMD_STATUS);
writel(LTSSM_EN_VAL | val, ks_pcie->va_app_base + CMD_STATUS);
}
/**
* ks_dw_pcie_host_init() - initialize host for v3_65 dw hardware
*
* Ioremap the register resources, initialize legacy irq domain
* and call dw_pcie_v3_65_host_init() API to initialize the Keystone
* PCI host controller.
*/
int __init ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie,
struct device_node *msi_intc_np)
{
struct pcie_port *pp = &ks_pcie->pp;
struct platform_device *pdev = to_platform_device(pp->dev);
struct resource *res;
/* Index 0 is the config reg. space address */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
pp->dbi_base = devm_ioremap_resource(pp->dev, res);
if (IS_ERR(pp->dbi_base))
return PTR_ERR(pp->dbi_base);
/*
* We set these same and is used in pcie rd/wr_other_conf
* functions
*/
pp->va_cfg0_base = pp->dbi_base + SPACE0_REMOTE_CFG_OFFSET;
pp->va_cfg1_base = pp->va_cfg0_base;
/* Index 1 is the application reg. space address */
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
ks_pcie->app = *res;
ks_pcie->va_app_base = devm_ioremap_resource(pp->dev, res);
if (IS_ERR(ks_pcie->va_app_base))
return PTR_ERR(ks_pcie->va_app_base);
/* Create legacy IRQ domain */
ks_pcie->legacy_irq_domain =
irq_domain_add_linear(ks_pcie->legacy_intc_np,
MAX_LEGACY_IRQS,
&ks_dw_pcie_legacy_irq_domain_ops,
NULL);
if (!ks_pcie->legacy_irq_domain) {
dev_err(pp->dev, "Failed to add irq domain for legacy irqs\n");
return -EINVAL;
}
return dw_pcie_host_init(pp);
}
/*
* PCIe host controller driver for Texas Instruments Keystone SoCs
*
* Copyright (C) 2013-2014 Texas Instruments., Ltd.
* http://www.ti.com
*
* Author: Murali Karicheri <m-karicheri2@ti.com>
* Implementation based on pci-exynos.c and pcie-designware.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/irqchip/chained_irq.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/irqdomain.h>
#include <linux/module.h>
#include <linux/msi.h>
#include <linux/of_irq.h>
#include <linux/of.h>
#include <linux/of_pci.h>
#include <linux/platform_device.h>
#include <linux/phy/phy.h>
#include <linux/resource.h>
#include <linux/signal.h>
#include "pcie-designware.h"
#include "pci-keystone.h"
#define DRIVER_NAME "keystone-pcie"
/* driver specific constants */
#define MAX_MSI_HOST_IRQS 8
#define MAX_LEGACY_HOST_IRQS 4
/* DEV_STAT_CTRL */
#define PCIE_CAP_BASE 0x70
/* PCIE controller device IDs */
#define PCIE_RC_K2HK 0xb008
#define PCIE_RC_K2E 0xb009
#define PCIE_RC_K2L 0xb00a
#define to_keystone_pcie(x) container_of(x, struct keystone_pcie, pp)
static void quirk_limit_mrrs(struct pci_dev *dev)
{
struct pci_bus *bus = dev->bus;
struct pci_dev *bridge = bus->self;
static const struct pci_device_id rc_pci_devids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCIE_RC_K2HK),
.class = PCI_CLASS_BRIDGE_PCI << 8, .class_mask = ~0, },
{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCIE_RC_K2E),
.class = PCI_CLASS_BRIDGE_PCI << 8, .class_mask = ~0, },
{ PCI_DEVICE(PCI_VENDOR_ID_TI, PCIE_RC_K2L),
.class = PCI_CLASS_BRIDGE_PCI << 8, .class_mask = ~0, },
{ 0, },
};
if (pci_is_root_bus(bus))
return;
/* look for the host bridge */
while (!pci_is_root_bus(bus)) {
bridge = bus->self;
bus = bus->parent;
}
if (bridge) {
/*
* Keystone PCI controller has a h/w limitation of
* 256 bytes maximum read request size. It can't handle
* anything higher than this. So force this limit on
* all downstream devices.
*/
if (pci_match_id(rc_pci_devids, bridge)) {
if (pcie_get_readrq(dev) > 256) {
dev_info(&dev->dev, "limiting MRRS to 256\n");
pcie_set_readrq(dev, 256);
}
}
}
}
DECLARE_PCI_FIXUP_ENABLE(PCI_ANY_ID, PCI_ANY_ID, quirk_limit_mrrs);
static int ks_pcie_establish_link(struct keystone_pcie *ks_pcie)
{
struct pcie_port *pp = &ks_pcie->pp;
int count = 200;
dw_pcie_setup_rc(pp);
if (dw_pcie_link_up(pp)) {
dev_err(pp->dev, "Link already up\n");
return 0;
}
ks_dw_pcie_initiate_link_train(ks_pcie);
/* check if the link is up or not */
while (!dw_pcie_link_up(pp)) {
usleep_range(100, 1000);
if (--count) {
ks_dw_pcie_initiate_link_train(ks_pcie);
continue;
}
dev_err(pp->dev, "phy link never came up\n");
return -EINVAL;
}
return 0;
}
static void ks_pcie_msi_irq_handler(unsigned int irq, struct irq_desc *desc)
{
struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
u32 offset = irq - ks_pcie->msi_host_irqs[0];
struct pcie_port *pp = &ks_pcie->pp;
struct irq_chip *chip = irq_desc_get_chip(desc);
dev_dbg(pp->dev, "ks_pci_msi_irq_handler, irq %d\n", irq);
/*
* The chained irq handler installation would have replaced normal
* interrupt driver handler so we need to take care of mask/unmask and
* ack operation.
*/
chained_irq_enter(chip, desc);
ks_dw_pcie_handle_msi_irq(ks_pcie, offset);
chained_irq_exit(chip, desc);
}
/**
* ks_pcie_legacy_irq_handler() - Handle legacy interrupt
* @irq: IRQ line for legacy interrupts
* @desc: Pointer to irq descriptor
*
* Traverse through pending legacy interrupts and invoke handler for each. Also
* takes care of interrupt controller level mask/ack operation.
*/
static void ks_pcie_legacy_irq_handler(unsigned int irq, struct irq_desc *desc)
{
struct keystone_pcie *ks_pcie = irq_desc_get_handler_data(desc);
struct pcie_port *pp = &ks_pcie->pp;
u32 irq_offset = irq - ks_pcie->legacy_host_irqs[0];
struct irq_chip *chip = irq_desc_get_chip(desc);
dev_dbg(pp->dev, ": Handling legacy irq %d\n", irq);
/*
* The chained irq handler installation would have replaced normal
* interrupt driver handler so we need to take care of mask/unmask and
* ack operation.
*/
chained_irq_enter(chip, desc);
ks_dw_pcie_handle_legacy_irq(ks_pcie, irq_offset);
chained_irq_exit(chip, desc);
}
static int ks_pcie_get_irq_controller_info(struct keystone_pcie *ks_pcie,
char *controller, int *num_irqs)
{
int temp, max_host_irqs, legacy = 1, *host_irqs, ret = -EINVAL;
struct device *dev = ks_pcie->pp.dev;
struct device_node *np_pcie = dev->of_node, **np_temp;
if (!strcmp(controller, "msi-interrupt-controller"))
legacy = 0;
if (legacy) {
np_temp = &ks_pcie->legacy_intc_np;
max_host_irqs = MAX_LEGACY_HOST_IRQS;
host_irqs = &ks_pcie->legacy_host_irqs[0];
} else {
np_temp = &ks_pcie->msi_intc_np;
max_host_irqs = MAX_MSI_HOST_IRQS;
host_irqs = &ks_pcie->msi_host_irqs[0];
}
/* interrupt controller is in a child node */
*np_temp = of_find_node_by_name(np_pcie, controller);
if (!(*np_temp)) {
dev_err(dev, "Node for %s is absent\n", controller);
goto out;
}
temp = of_irq_count(*np_temp);
if (!temp)
goto out;
if (temp > max_host_irqs)
dev_warn(dev, "Too many %s interrupts defined %u\n",
(legacy ? "legacy" : "MSI"), temp);
/*
* support upto max_host_irqs. In dt from index 0 to 3 (legacy) or 0 to
* 7 (MSI)
*/
for (temp = 0; temp < max_host_irqs; temp++) {
host_irqs[temp] = irq_of_parse_and_map(*np_temp, temp);
if (host_irqs[temp] < 0)
break;
}
if (temp) {
*num_irqs = temp;
ret = 0;
}
out:
return ret;
}
static void ks_pcie_setup_interrupts(struct keystone_pcie *ks_pcie)
{
int i;
/* Legacy IRQ */
for (i = 0; i < ks_pcie->num_legacy_host_irqs; i++) {
irq_set_handler_data(ks_pcie->legacy_host_irqs[i], ks_pcie);
irq_set_chained_handler(ks_pcie->legacy_host_irqs[i],
ks_pcie_legacy_irq_handler);
}
ks_dw_pcie_enable_legacy_irqs(ks_pcie);
/* MSI IRQ */
if (IS_ENABLED(CONFIG_PCI_MSI)) {
for (i = 0; i < ks_pcie->num_msi_host_irqs; i++) {
irq_set_chained_handler(ks_pcie->msi_host_irqs[i],
ks_pcie_msi_irq_handler);
irq_set_handler_data(ks_pcie->msi_host_irqs[i],
ks_pcie);
}
}
}
/*
* When a PCI device does not exist during config cycles, keystone host gets a
* bus error instead of returning 0xffffffff. This handler always returns 0
* for this kind of faults.
*/
static int keystone_pcie_fault(unsigned long addr, unsigned int fsr,
struct pt_regs *regs)
{
unsigned long instr = *(unsigned long *) instruction_pointer(regs);
if ((instr & 0x0e100090) == 0x00100090) {
int reg = (instr >> 12) & 15;
regs->uregs[reg] = -1;
regs->ARM_pc += 4;
}
return 0;
}
static void __init ks_pcie_host_init(struct pcie_port *pp)
{
struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
u32 val;
ks_pcie_establish_link(ks_pcie);
ks_dw_pcie_setup_rc_app_regs(ks_pcie);
ks_pcie_setup_interrupts(ks_pcie);
writew(PCI_IO_RANGE_TYPE_32 | (PCI_IO_RANGE_TYPE_32 << 8),
pp->dbi_base + PCI_IO_BASE);
/* update the Vendor ID */
writew(ks_pcie->device_id, pp->dbi_base + PCI_DEVICE_ID);
/* update the DEV_STAT_CTRL to publish right mrrs */
val = readl(pp->dbi_base + PCIE_CAP_BASE + PCI_EXP_DEVCTL);
val &= ~PCI_EXP_DEVCTL_READRQ;
/* set the mrrs to 256 bytes */
val |= BIT(12);
writel(val, pp->dbi_base + PCIE_CAP_BASE + PCI_EXP_DEVCTL);
/*
* PCIe access errors that result into OCP errors are caught by ARM as
* "External aborts"
*/
hook_fault_code(17, keystone_pcie_fault, SIGBUS, 0,
"Asynchronous external abort");
}
static struct pcie_host_ops keystone_pcie_host_ops = {
.rd_other_conf = ks_dw_pcie_rd_other_conf,
.wr_other_conf = ks_dw_pcie_wr_other_conf,
.link_up = ks_dw_pcie_link_up,
.host_init = ks_pcie_host_init,
.msi_set_irq = ks_dw_pcie_msi_set_irq,
.msi_clear_irq = ks_dw_pcie_msi_clear_irq,
.get_msi_addr = ks_dw_pcie_get_msi_addr,
.msi_host_init = ks_dw_pcie_msi_host_init,
.scan_bus = ks_dw_pcie_v3_65_scan_bus,
};
static int __init ks_add_pcie_port(struct keystone_pcie *ks_pcie,
struct platform_device *pdev)
{
struct pcie_port *pp = &ks_pcie->pp;
int ret;
ret = ks_pcie_get_irq_controller_info(ks_pcie,
"legacy-interrupt-controller",
&ks_pcie->num_legacy_host_irqs);
if (ret)
return ret;
if (IS_ENABLED(CONFIG_PCI_MSI)) {
ret = ks_pcie_get_irq_controller_info(ks_pcie,
"msi-interrupt-controller",
&ks_pcie->num_msi_host_irqs);
if (ret)
return ret;
}
pp->root_bus_nr = -1;
pp->ops = &keystone_pcie_host_ops;
ret = ks_dw_pcie_host_init(ks_pcie, ks_pcie->msi_intc_np);
if (ret) {
dev_err(&pdev->dev, "failed to initialize host\n");
return ret;
}
return ret;
}
static const struct of_device_id ks_pcie_of_match[] = {
{
.type = "pci",
.compatible = "ti,keystone-pcie",
},
{ },
};
MODULE_DEVICE_TABLE(of, ks_pcie_of_match);
static int __exit ks_pcie_remove(struct platform_device *pdev)
{
struct keystone_pcie *ks_pcie = platform_get_drvdata(pdev);
clk_disable_unprepare(ks_pcie->clk);
return 0;
}
static int __init ks_pcie_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct keystone_pcie *ks_pcie;
struct pcie_port *pp;
struct resource *res;
void __iomem *reg_p;
struct phy *phy;
int ret = 0;
ks_pcie = devm_kzalloc(&pdev->dev, sizeof(*ks_pcie),
GFP_KERNEL);
if (!ks_pcie) {
dev_err(dev, "no memory for keystone pcie\n");
return -ENOMEM;
}
pp = &ks_pcie->pp;
/* initialize SerDes Phy if present */
phy = devm_phy_get(dev, "pcie-phy");
if (!IS_ERR_OR_NULL(phy)) {
ret = phy_init(phy);
if (ret < 0)
return ret;
}
/* index 2 is to read PCI DEVICE_ID */
res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
reg_p = devm_ioremap_resource(dev, res);
if (IS_ERR(reg_p))
return PTR_ERR(reg_p);
ks_pcie->device_id = readl(reg_p) >> 16;
devm_iounmap(dev, reg_p);
devm_release_mem_region(dev, res->start, resource_size(res));
pp->dev = dev;
platform_set_drvdata(pdev, ks_pcie);
ks_pcie->clk = devm_clk_get(dev, "pcie");
if (IS_ERR(ks_pcie->clk)) {
dev_err(dev, "Failed to get pcie rc clock\n");
return PTR_ERR(ks_pcie->clk);
}
ret = clk_prepare_enable(ks_pcie->clk);
if (ret)
return ret;
ret = ks_add_pcie_port(ks_pcie, pdev);
if (ret < 0)
goto fail_clk;
return 0;
fail_clk:
clk_disable_unprepare(ks_pcie->clk);
return ret;
}
static struct platform_driver ks_pcie_driver __refdata = {
.probe = ks_pcie_probe,
.remove = __exit_p(ks_pcie_remove),
.driver = {
.name = "keystone-pcie",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(ks_pcie_of_match),
},
};
module_platform_driver(ks_pcie_driver);
MODULE_AUTHOR("Murali Karicheri <m-karicheri2@ti.com>");
MODULE_DESCRIPTION("Keystone PCIe host controller driver");
MODULE_LICENSE("GPL v2");
/*
* Keystone PCI Controller's common includes
*
* Copyright (C) 2013-2014 Texas Instruments., Ltd.
* http://www.ti.com
*
* Author: Murali Karicheri <m-karicheri2@ti.com>
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#define MAX_LEGACY_IRQS 4
#define MAX_MSI_HOST_IRQS 8
#define MAX_LEGACY_HOST_IRQS 4
struct keystone_pcie {
struct clk *clk;
struct pcie_port pp;
/* PCI Device ID */
u32 device_id;
int num_legacy_host_irqs;
int legacy_host_irqs[MAX_LEGACY_HOST_IRQS];
struct device_node *legacy_intc_np;
int num_msi_host_irqs;
int msi_host_irqs[MAX_MSI_HOST_IRQS];
struct device_node *msi_intc_np;
struct irq_domain *legacy_irq_domain;
/* Application register space */
void __iomem *va_app_base;
struct resource app;
};
/* Keystone DW specific MSI controller APIs/definitions */
void ks_dw_pcie_handle_msi_irq(struct keystone_pcie *ks_pcie, int offset);
u32 ks_dw_pcie_get_msi_addr(struct pcie_port *pp);
/* Keystone specific PCI controller APIs */
void ks_dw_pcie_enable_legacy_irqs(struct keystone_pcie *ks_pcie);
void ks_dw_pcie_handle_legacy_irq(struct keystone_pcie *ks_pcie, int offset);
int ks_dw_pcie_host_init(struct keystone_pcie *ks_pcie,
struct device_node *msi_intc_np);
int ks_dw_pcie_wr_other_conf(struct pcie_port *pp, struct pci_bus *bus,
unsigned int devfn, int where, int size, u32 val);
int ks_dw_pcie_rd_other_conf(struct pcie_port *pp, struct pci_bus *bus,
unsigned int devfn, int where, int size, u32 *val);
void ks_dw_pcie_setup_rc_app_regs(struct keystone_pcie *ks_pcie);
int ks_dw_pcie_link_up(struct pcie_port *pp);
void ks_dw_pcie_initiate_link_train(struct keystone_pcie *ks_pcie);
void ks_dw_pcie_msi_set_irq(struct pcie_port *pp, int irq);
void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq);
void ks_dw_pcie_v3_65_scan_bus(struct pcie_port *pp);
int ks_dw_pcie_msi_host_init(struct pcie_port *pp,
struct msi_chip *chip);
......@@ -873,7 +873,7 @@ static int mvebu_get_tgt_attr(struct device_node *np, int devfn,
rangesz = pna + na + ns;
nranges = rlen / sizeof(__be32) / rangesz;
for (i = 0; i < nranges; i++) {
for (i = 0; i < nranges; i++, range += rangesz) {
u32 flags = of_read_number(range, 1);
u32 slot = of_read_number(range + 1, 1);
u64 cpuaddr = of_read_number(range + na, pna);
......@@ -883,14 +883,14 @@ static int mvebu_get_tgt_attr(struct device_node *np, int devfn,
rtype = IORESOURCE_IO;
else if (DT_FLAGS_TO_TYPE(flags) == DT_TYPE_MEM32)
rtype = IORESOURCE_MEM;
else
continue;
if (slot == PCI_SLOT(devfn) && type == rtype) {
*tgt = DT_CPUADDR_TO_TARGET(cpuaddr);
*attr = DT_CPUADDR_TO_ATTR(cpuaddr);
return 0;
}
range += rangesz;
}
return -ENOENT;
......
......@@ -38,6 +38,7 @@
#include <linux/of_pci.h>
#include <linux/of_platform.h>
#include <linux/pci.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#include <linux/sizes.h>
......@@ -115,13 +116,20 @@
#define AFI_INTR_CODE 0xb8
#define AFI_INTR_CODE_MASK 0xf
#define AFI_INTR_AXI_SLAVE_ERROR 1
#define AFI_INTR_AXI_DECODE_ERROR 2
#define AFI_INTR_INI_SLAVE_ERROR 1
#define AFI_INTR_INI_DECODE_ERROR 2
#define AFI_INTR_TARGET_ABORT 3
#define AFI_INTR_MASTER_ABORT 4
#define AFI_INTR_INVALID_WRITE 5
#define AFI_INTR_LEGACY 6
#define AFI_INTR_FPCI_DECODE_ERROR 7
#define AFI_INTR_AXI_DECODE_ERROR 8
#define AFI_INTR_FPCI_TIMEOUT 9
#define AFI_INTR_PE_PRSNT_SENSE 10
#define AFI_INTR_PE_CLKREQ_SENSE 11
#define AFI_INTR_CLKCLAMP_SENSE 12
#define AFI_INTR_RDY4PD_SENSE 13
#define AFI_INTR_P2P_ERROR 14
#define AFI_INTR_SIGNATURE 0xbc
#define AFI_UPPER_FPCI_ADDRESS 0xc0
......@@ -152,8 +160,10 @@
#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK (0xf << 20)
#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_SINGLE (0x0 << 20)
#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_420 (0x0 << 20)
#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X2_X1 (0x0 << 20)
#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_DUAL (0x1 << 20)
#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_222 (0x1 << 20)
#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X4_X1 (0x1 << 20)
#define AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_411 (0x2 << 20)
#define AFI_FUSE 0x104
......@@ -165,12 +175,21 @@
#define AFI_PEX_CTRL_RST (1 << 0)
#define AFI_PEX_CTRL_CLKREQ_EN (1 << 1)
#define AFI_PEX_CTRL_REFCLK_EN (1 << 3)
#define AFI_PEX_CTRL_OVERRIDE_EN (1 << 4)
#define AFI_PLLE_CONTROL 0x160
#define AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL (1 << 9)
#define AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN (1 << 1)
#define AFI_PEXBIAS_CTRL_0 0x168
#define RP_VEND_XP 0x00000F00
#define RP_VEND_XP_DL_UP (1 << 30)
#define RP_PRIV_MISC 0x00000FE0
#define RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT (0xE << 0)
#define RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT (0xF << 0)
#define RP_LINK_CONTROL_STATUS 0x00000090
#define RP_LINK_CONTROL_STATUS_DL_LINK_ACTIVE 0x20000000
#define RP_LINK_CONTROL_STATUS_LINKSTAT_MASK 0x3fff0000
......@@ -197,6 +216,7 @@
#define PADS_REFCLK_CFG0 0x000000C8
#define PADS_REFCLK_CFG1 0x000000CC
#define PADS_REFCLK_BIAS 0x000000D0
/*
* Fields in PADS_REFCLK_CFG*. Those registers form an array of 16-bit
......@@ -236,6 +256,7 @@ struct tegra_pcie_soc_data {
bool has_pex_bias_ctrl;
bool has_intr_prsnt_sense;
bool has_cml_clk;
bool has_gen2;
};
static inline struct tegra_msi *to_tegra_msi(struct msi_chip *chip)
......@@ -253,6 +274,7 @@ struct tegra_pcie {
struct list_head buses;
struct resource *cs;
struct resource all;
struct resource io;
struct resource mem;
struct resource prefetch;
......@@ -267,6 +289,8 @@ struct tegra_pcie {
struct reset_control *afi_rst;
struct reset_control *pcie_xrst;
struct phy *phy;
struct tegra_msi msi;
struct list_head ports;
......@@ -382,7 +406,7 @@ static struct tegra_pcie_bus *tegra_pcie_bus_alloc(struct tegra_pcie *pcie,
for (i = 0; i < 16; i++) {
unsigned long virt = (unsigned long)bus->area->addr +
i * SZ_64K;
phys_addr_t phys = cs + i * SZ_1M + busnr * SZ_64K;
phys_addr_t phys = cs + i * SZ_16M + busnr * SZ_64K;
err = ioremap_page_range(virt, virt + SZ_64K, phys, prot);
if (err < 0) {
......@@ -561,6 +585,8 @@ static void tegra_pcie_port_enable(struct tegra_pcie_port *port)
if (soc->has_pex_clkreq_en)
value |= AFI_PEX_CTRL_CLKREQ_EN;
value |= AFI_PEX_CTRL_OVERRIDE_EN;
afi_writel(port->pcie, value, ctrl);
tegra_pcie_port_reset(port);
......@@ -568,6 +594,7 @@ static void tegra_pcie_port_enable(struct tegra_pcie_port *port)
static void tegra_pcie_port_disable(struct tegra_pcie_port *port)
{
const struct tegra_pcie_soc_data *soc = port->pcie->soc_data;
unsigned long ctrl = tegra_pcie_port_get_pex_ctrl(port);
unsigned long value;
......@@ -578,6 +605,10 @@ static void tegra_pcie_port_disable(struct tegra_pcie_port *port)
/* disable reference clock */
value = afi_readl(port->pcie, ctrl);
if (soc->has_pex_clkreq_en)
value &= ~AFI_PEX_CTRL_CLKREQ_EN;
value &= ~AFI_PEX_CTRL_REFCLK_EN;
afi_writel(port->pcie, value, ctrl);
}
......@@ -626,13 +657,25 @@ DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, tegra_pcie_relax_enable);
static int tegra_pcie_setup(int nr, struct pci_sys_data *sys)
{
struct tegra_pcie *pcie = sys_to_pcie(sys);
int err;
phys_addr_t io_start;
err = devm_request_resource(pcie->dev, &pcie->all, &pcie->mem);
if (err < 0)
return err;
err = devm_request_resource(pcie->dev, &pcie->all, &pcie->prefetch);
if (err)
return err;
io_start = pci_pio_to_address(pcie->io.start);
pci_add_resource_offset(&sys->resources, &pcie->mem, sys->mem_offset);
pci_add_resource_offset(&sys->resources, &pcie->prefetch,
sys->mem_offset);
pci_add_resource(&sys->resources, &pcie->busn);
pci_ioremap_io(nr * SZ_64K, pcie->io.start);
pci_ioremap_io(nr * SZ_64K, io_start);
return 1;
}
......@@ -684,9 +727,15 @@ static irqreturn_t tegra_pcie_isr(int irq, void *arg)
"Target abort",
"Master abort",
"Invalid write",
"Legacy interrupt",
"Response decoding error",
"AXI response decoding error",
"Transaction timeout",
"Slot present pin change",
"Slot clock request change",
"TMS clock ramp change",
"TMS ready for power down",
"Peer2Peer error",
};
struct tegra_pcie *pcie = arg;
u32 code, signature;
......@@ -737,6 +786,7 @@ static irqreturn_t tegra_pcie_isr(int irq, void *arg)
static void tegra_pcie_setup_translations(struct tegra_pcie *pcie)
{
u32 fpci_bar, size, axi_address;
phys_addr_t io_start = pci_pio_to_address(pcie->io.start);
/* Bar 0: type 1 extended configuration space */
fpci_bar = 0xfe100000;
......@@ -749,7 +799,7 @@ static void tegra_pcie_setup_translations(struct tegra_pcie *pcie)
/* Bar 1: downstream IO bar */
fpci_bar = 0xfdfc0000;
size = resource_size(&pcie->io);
axi_address = pcie->io.start;
axi_address = io_start;
afi_writel(pcie, axi_address, AFI_AXI_BAR1_START);
afi_writel(pcie, size >> 12, AFI_AXI_BAR1_SZ);
afi_writel(pcie, fpci_bar, AFI_FPCI_BAR1);
......@@ -792,30 +842,27 @@ static void tegra_pcie_setup_translations(struct tegra_pcie *pcie)
afi_writel(pcie, 0, AFI_MSI_BAR_SZ);
}
static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
static int tegra_pcie_pll_wait(struct tegra_pcie *pcie, unsigned long timeout)
{
const struct tegra_pcie_soc_data *soc = pcie->soc_data;
struct tegra_pcie_port *port;
unsigned int timeout;
unsigned long value;
/* power down PCIe slot clock bias pad */
if (soc->has_pex_bias_ctrl)
afi_writel(pcie, 0, AFI_PEXBIAS_CTRL_0);
u32 value;
/* configure mode and disable all ports */
value = afi_readl(pcie, AFI_PCIE_CONFIG);
value &= ~AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK;
value |= AFI_PCIE_CONFIG_PCIE_DISABLE_ALL | pcie->xbar_config;
timeout = jiffies + msecs_to_jiffies(timeout);
list_for_each_entry(port, &pcie->ports, list)
value &= ~AFI_PCIE_CONFIG_PCIE_DISABLE(port->index);
while (time_before(jiffies, timeout)) {
value = pads_readl(pcie, soc->pads_pll_ctl);
if (value & PADS_PLL_CTL_LOCKDET)
return 0;
}
afi_writel(pcie, value, AFI_PCIE_CONFIG);
return -ETIMEDOUT;
}
value = afi_readl(pcie, AFI_FUSE);
value |= AFI_FUSE_PCIE_T0_GEN2_DIS;
afi_writel(pcie, value, AFI_FUSE);
static int tegra_pcie_phy_enable(struct tegra_pcie *pcie)
{
const struct tegra_pcie_soc_data *soc = pcie->soc_data;
u32 value;
int err;
/* initialize internal PHY, enable up to 16 PCIE lanes */
pads_writel(pcie, 0x0, PADS_CTL_SEL);
......@@ -834,6 +881,13 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
value |= PADS_PLL_CTL_REFCLK_INTERNAL_CML | soc->tx_ref_sel;
pads_writel(pcie, value, soc->pads_pll_ctl);
/* reset PLL */
value = pads_readl(pcie, soc->pads_pll_ctl);
value &= ~PADS_PLL_CTL_RST_B4SM;
pads_writel(pcie, value, soc->pads_pll_ctl);
usleep_range(20, 100);
/* take PLL out of reset */
value = pads_readl(pcie, soc->pads_pll_ctl);
value |= PADS_PLL_CTL_RST_B4SM;
......@@ -846,15 +900,11 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
pads_writel(pcie, PADS_REFCLK_CFG_VALUE, PADS_REFCLK_CFG1);
/* wait for the PLL to lock */
timeout = 300;
do {
value = pads_readl(pcie, soc->pads_pll_ctl);
usleep_range(1000, 2000);
if (--timeout == 0) {
pr_err("Tegra PCIe error: timeout waiting for PLL\n");
return -EBUSY;
err = tegra_pcie_pll_wait(pcie, 500);
if (err < 0) {
dev_err(pcie->dev, "PLL failed to lock: %d\n", err);
return err;
}
} while (!(value & PADS_PLL_CTL_LOCKDET));
/* turn off IDDQ override */
value = pads_readl(pcie, PADS_CTL);
......@@ -866,6 +916,58 @@ static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
value |= PADS_CTL_TX_DATA_EN_1L | PADS_CTL_RX_DATA_EN_1L;
pads_writel(pcie, value, PADS_CTL);
return 0;
}
static int tegra_pcie_enable_controller(struct tegra_pcie *pcie)
{
const struct tegra_pcie_soc_data *soc = pcie->soc_data;
struct tegra_pcie_port *port;
unsigned long value;
int err;
/* enable PLL power down */
if (pcie->phy) {
value = afi_readl(pcie, AFI_PLLE_CONTROL);
value &= ~AFI_PLLE_CONTROL_BYPASS_PADS2PLLE_CONTROL;
value |= AFI_PLLE_CONTROL_PADS2PLLE_CONTROL_EN;
afi_writel(pcie, value, AFI_PLLE_CONTROL);
}
/* power down PCIe slot clock bias pad */
if (soc->has_pex_bias_ctrl)
afi_writel(pcie, 0, AFI_PEXBIAS_CTRL_0);
/* configure mode and disable all ports */
value = afi_readl(pcie, AFI_PCIE_CONFIG);
value &= ~AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_MASK;
value |= AFI_PCIE_CONFIG_PCIE_DISABLE_ALL | pcie->xbar_config;
list_for_each_entry(port, &pcie->ports, list)
value &= ~AFI_PCIE_CONFIG_PCIE_DISABLE(port->index);
afi_writel(pcie, value, AFI_PCIE_CONFIG);
if (soc->has_gen2) {
value = afi_readl(pcie, AFI_FUSE);
value &= ~AFI_FUSE_PCIE_T0_GEN2_DIS;
afi_writel(pcie, value, AFI_FUSE);
} else {
value = afi_readl(pcie, AFI_FUSE);
value |= AFI_FUSE_PCIE_T0_GEN2_DIS;
afi_writel(pcie, value, AFI_FUSE);
}
if (!pcie->phy)
err = tegra_pcie_phy_enable(pcie);
else
err = phy_power_on(pcie->phy);
if (err < 0) {
dev_err(pcie->dev, "failed to power on PHY: %d\n", err);
return err;
}
/* take the PCIe interface module out of reset */
reset_control_deassert(pcie->pcie_xrst);
......@@ -899,6 +1001,10 @@ static void tegra_pcie_power_off(struct tegra_pcie *pcie)
/* TODO: disable and unprepare clocks? */
err = phy_power_off(pcie->phy);
if (err < 0)
dev_warn(pcie->dev, "failed to power off PHY: %d\n", err);
reset_control_assert(pcie->pcie_xrst);
reset_control_assert(pcie->afi_rst);
reset_control_assert(pcie->pex_rst);
......@@ -1020,6 +1126,19 @@ static int tegra_pcie_get_resources(struct tegra_pcie *pcie)
return err;
}
pcie->phy = devm_phy_optional_get(pcie->dev, "pcie");
if (IS_ERR(pcie->phy)) {
err = PTR_ERR(pcie->phy);
dev_err(&pdev->dev, "failed to get PHY: %d\n", err);
return err;
}
err = phy_init(pcie->phy);
if (err < 0) {
dev_err(&pdev->dev, "failed to initialize PHY: %d\n", err);
return err;
}
err = tegra_pcie_power_on(pcie);
if (err) {
dev_err(&pdev->dev, "failed to power up: %d\n", err);
......@@ -1078,10 +1197,17 @@ static int tegra_pcie_get_resources(struct tegra_pcie *pcie)
static int tegra_pcie_put_resources(struct tegra_pcie *pcie)
{
int err;
if (pcie->irq > 0)
free_irq(pcie->irq, pcie);
tegra_pcie_power_off(pcie);
err = phy_exit(pcie->phy);
if (err < 0)
dev_err(pcie->dev, "failed to teardown PHY: %d\n", err);
return 0;
}
......@@ -1170,8 +1296,10 @@ static int tegra_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
return hwirq;
irq = irq_create_mapping(msi->domain, hwirq);
if (!irq)
if (!irq) {
tegra_msi_free(msi, hwirq);
return -EINVAL;
}
irq_set_msi_desc(irq, desc);
......@@ -1189,8 +1317,10 @@ static void tegra_msi_teardown_irq(struct msi_chip *chip, unsigned int irq)
{
struct tegra_msi *msi = to_tegra_msi(chip);
struct irq_data *d = irq_get_irq_data(irq);
irq_hw_number_t hwirq = irqd_to_hwirq(d);
tegra_msi_free(msi, d->hwirq);
irq_dispose_mapping(irq);
tegra_msi_free(msi, hwirq);
}
static struct irq_chip tegra_msi_irq_chip = {
......@@ -1327,7 +1457,19 @@ static int tegra_pcie_get_xbar_config(struct tegra_pcie *pcie, u32 lanes,
{
struct device_node *np = pcie->dev->of_node;
if (of_device_is_compatible(np, "nvidia,tegra30-pcie")) {
if (of_device_is_compatible(np, "nvidia,tegra124-pcie")) {
switch (lanes) {
case 0x0000104:
dev_info(pcie->dev, "4x1, 1x1 configuration\n");
*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X4_X1;
return 0;
case 0x0000102:
dev_info(pcie->dev, "2x1, 1x1 configuration\n");
*xbar = AFI_PCIE_CONFIG_SM2TMS0_XBAR_CONFIG_X2_X1;
return 0;
}
} else if (of_device_is_compatible(np, "nvidia,tegra30-pcie")) {
switch (lanes) {
case 0x00000204:
dev_info(pcie->dev, "4x1, 2x1 configuration\n");
......@@ -1435,7 +1577,23 @@ static int tegra_pcie_get_regulators(struct tegra_pcie *pcie, u32 lane_mask)
struct device_node *np = pcie->dev->of_node;
unsigned int i = 0;
if (of_device_is_compatible(np, "nvidia,tegra30-pcie")) {
if (of_device_is_compatible(np, "nvidia,tegra124-pcie")) {
pcie->num_supplies = 7;
pcie->supplies = devm_kcalloc(pcie->dev, pcie->num_supplies,
sizeof(*pcie->supplies),
GFP_KERNEL);
if (!pcie->supplies)
return -ENOMEM;
pcie->supplies[i++].supply = "avddio-pex";
pcie->supplies[i++].supply = "dvddio-pex";
pcie->supplies[i++].supply = "avdd-pex-pll";
pcie->supplies[i++].supply = "hvdd-pex";
pcie->supplies[i++].supply = "hvdd-pex-pll-e";
pcie->supplies[i++].supply = "vddio-pex-ctl";
pcie->supplies[i++].supply = "avdd-pll-erefe";
} else if (of_device_is_compatible(np, "nvidia,tegra30-pcie")) {
bool need_pexa = false, need_pexb = false;
/* VDD_PEXA and AVDD_PEXA supply lanes 0 to 3 */
......@@ -1514,32 +1672,50 @@ static int tegra_pcie_parse_dt(struct tegra_pcie *pcie)
struct resource res;
int err;
memset(&pcie->all, 0, sizeof(pcie->all));
pcie->all.flags = IORESOURCE_MEM;
pcie->all.name = np->full_name;
pcie->all.start = ~0;
pcie->all.end = 0;
if (of_pci_range_parser_init(&parser, np)) {
dev_err(pcie->dev, "missing \"ranges\" property\n");
return -EINVAL;
}
for_each_of_pci_range(&parser, &range) {
of_pci_range_to_resource(&range, np, &res);
err = of_pci_range_to_resource(&range, np, &res);
if (err < 0)
return err;
switch (res.flags & IORESOURCE_TYPE_BITS) {
case IORESOURCE_IO:
memcpy(&pcie->io, &res, sizeof(res));
pcie->io.name = "I/O";
pcie->io.name = np->full_name;
break;
case IORESOURCE_MEM:
if (res.flags & IORESOURCE_PREFETCH) {
memcpy(&pcie->prefetch, &res, sizeof(res));
pcie->prefetch.name = "PREFETCH";
pcie->prefetch.name = "prefetchable";
} else {
memcpy(&pcie->mem, &res, sizeof(res));
pcie->mem.name = "MEM";
pcie->mem.name = "non-prefetchable";
}
break;
}
if (res.start <= pcie->all.start)
pcie->all.start = res.start;
if (res.end >= pcie->all.end)
pcie->all.end = res.end;
}
err = devm_request_resource(pcie->dev, &iomem_resource, &pcie->all);
if (err < 0)
return err;
err = of_pci_parse_bus_range(np, &pcie->busn);
if (err < 0) {
dev_err(pcie->dev, "failed to parse ranges property: %d\n",
......@@ -1641,6 +1817,12 @@ static bool tegra_pcie_port_check_link(struct tegra_pcie_port *port)
unsigned int retries = 3;
unsigned long value;
/* override presence detection */
value = readl(port->base + RP_PRIV_MISC);
value &= ~RP_PRIV_MISC_PRSNT_MAP_EP_ABSNT;
value |= RP_PRIV_MISC_PRSNT_MAP_EP_PRSNT;
writel(value, port->base + RP_PRIV_MISC);
do {
unsigned int timeout = TEGRA_PCIE_LINKUP_TIMEOUT;
......@@ -1721,6 +1903,7 @@ static const struct tegra_pcie_soc_data tegra20_pcie_data = {
.has_pex_bias_ctrl = false,
.has_intr_prsnt_sense = false,
.has_cml_clk = false,
.has_gen2 = false,
};
static const struct tegra_pcie_soc_data tegra30_pcie_data = {
......@@ -1732,9 +1915,23 @@ static const struct tegra_pcie_soc_data tegra30_pcie_data = {
.has_pex_bias_ctrl = true,
.has_intr_prsnt_sense = true,
.has_cml_clk = true,
.has_gen2 = false,
};
static const struct tegra_pcie_soc_data tegra124_pcie_data = {
.num_ports = 2,
.msi_base_shift = 8,
.pads_pll_ctl = PADS_PLL_CTL_TEGRA30,
.tx_ref_sel = PADS_PLL_CTL_TXCLKREF_BUF_EN,
.has_pex_clkreq_en = true,
.has_pex_bias_ctrl = true,
.has_intr_prsnt_sense = true,
.has_cml_clk = true,
.has_gen2 = true,
};
static const struct of_device_id tegra_pcie_of_match[] = {
{ .compatible = "nvidia,tegra124-pcie", .data = &tegra124_pcie_data },
{ .compatible = "nvidia,tegra30-pcie", .data = &tegra30_pcie_data },
{ .compatible = "nvidia,tegra20-pcie", .data = &tegra20_pcie_data },
{ },
......
/**
* APM X-Gene PCIe Driver
*
* Copyright (c) 2014 Applied Micro Circuits Corporation.
*
* Author: Tanmay Inamdar <tinamdar@apm.com>.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/clk-private.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/jiffies.h>
#include <linux/memblock.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_pci.h>
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#define PCIECORE_CTLANDSTATUS 0x50
#define PIM1_1L 0x80
#define IBAR2 0x98
#define IR2MSK 0x9c
#define PIM2_1L 0xa0
#define IBAR3L 0xb4
#define IR3MSKL 0xbc
#define PIM3_1L 0xc4
#define OMR1BARL 0x100
#define OMR2BARL 0x118
#define OMR3BARL 0x130
#define CFGBARL 0x154
#define CFGBARH 0x158
#define CFGCTL 0x15c
#define RTDID 0x160
#define BRIDGE_CFG_0 0x2000
#define BRIDGE_CFG_4 0x2010
#define BRIDGE_STATUS_0 0x2600
#define LINK_UP_MASK 0x00000100
#define AXI_EP_CFG_ACCESS 0x10000
#define EN_COHERENCY 0xF0000000
#define EN_REG 0x00000001
#define OB_LO_IO 0x00000002
#define XGENE_PCIE_VENDORID 0x10E8
#define XGENE_PCIE_DEVICEID 0xE004
#define SZ_1T (SZ_1G*1024ULL)
#define PIPE_PHY_RATE_RD(src) ((0xc000 & (u32)(src)) >> 0xe)
struct xgene_pcie_port {
struct device_node *node;
struct device *dev;
struct clk *clk;
void __iomem *csr_base;
void __iomem *cfg_base;
unsigned long cfg_addr;
bool link_up;
};
static inline u32 pcie_bar_low_val(u32 addr, u32 flags)
{
return (addr & PCI_BASE_ADDRESS_MEM_MASK) | flags;
}
/* PCIe Configuration Out/In */
static inline void xgene_pcie_cfg_out32(void __iomem *addr, int offset, u32 val)
{
writel(val, addr + offset);
}
static inline void xgene_pcie_cfg_out16(void __iomem *addr, int offset, u16 val)
{
u32 val32 = readl(addr + (offset & ~0x3));
switch (offset & 0x3) {
case 2:
val32 &= ~0xFFFF0000;
val32 |= (u32)val << 16;
break;
case 0:
default:
val32 &= ~0xFFFF;
val32 |= val;
break;
}
writel(val32, addr + (offset & ~0x3));
}
static inline void xgene_pcie_cfg_out8(void __iomem *addr, int offset, u8 val)
{
u32 val32 = readl(addr + (offset & ~0x3));
switch (offset & 0x3) {
case 0:
val32 &= ~0xFF;
val32 |= val;
break;
case 1:
val32 &= ~0xFF00;
val32 |= (u32)val << 8;
break;
case 2:
val32 &= ~0xFF0000;
val32 |= (u32)val << 16;
break;
case 3:
default:
val32 &= ~0xFF000000;
val32 |= (u32)val << 24;
break;
}
writel(val32, addr + (offset & ~0x3));
}
static inline void xgene_pcie_cfg_in32(void __iomem *addr, int offset, u32 *val)
{
*val = readl(addr + offset);
}
static inline void xgene_pcie_cfg_in16(void __iomem *addr, int offset, u32 *val)
{
*val = readl(addr + (offset & ~0x3));
switch (offset & 0x3) {
case 2:
*val >>= 16;
break;
}
*val &= 0xFFFF;
}
static inline void xgene_pcie_cfg_in8(void __iomem *addr, int offset, u32 *val)
{
*val = readl(addr + (offset & ~0x3));
switch (offset & 0x3) {
case 3:
*val = *val >> 24;
break;
case 2:
*val = *val >> 16;
break;
case 1:
*val = *val >> 8;
break;
}
*val &= 0xFF;
}
/*
* When the address bit [17:16] is 2'b01, the Configuration access will be
* treated as Type 1 and it will be forwarded to external PCIe device.
*/
static void __iomem *xgene_pcie_get_cfg_base(struct pci_bus *bus)
{
struct xgene_pcie_port *port = bus->sysdata;
if (bus->number >= (bus->primary + 1))
return port->cfg_base + AXI_EP_CFG_ACCESS;
return port->cfg_base;
}
/*
* For Configuration request, RTDID register is used as Bus Number,
* Device Number and Function number of the header fields.
*/
static void xgene_pcie_set_rtdid_reg(struct pci_bus *bus, uint devfn)
{
struct xgene_pcie_port *port = bus->sysdata;
unsigned int b, d, f;
u32 rtdid_val = 0;
b = bus->number;
d = PCI_SLOT(devfn);
f = PCI_FUNC(devfn);
if (!pci_is_root_bus(bus))
rtdid_val = (b << 8) | (d << 3) | f;
writel(rtdid_val, port->csr_base + RTDID);
/* read the register back to ensure flush */
readl(port->csr_base + RTDID);
}
/*
* X-Gene PCIe port uses BAR0-BAR1 of RC's configuration space as
* the translation from PCI bus to native BUS. Entire DDR region
* is mapped into PCIe space using these registers, so it can be
* reached by DMA from EP devices. The BAR0/1 of bridge should be
* hidden during enumeration to avoid the sizing and resource allocation
* by PCIe core.
*/
static bool xgene_pcie_hide_rc_bars(struct pci_bus *bus, int offset)
{
if (pci_is_root_bus(bus) && ((offset == PCI_BASE_ADDRESS_0) ||
(offset == PCI_BASE_ADDRESS_1)))
return true;
return false;
}
static int xgene_pcie_read_config(struct pci_bus *bus, unsigned int devfn,
int offset, int len, u32 *val)
{
struct xgene_pcie_port *port = bus->sysdata;
void __iomem *addr;
if ((pci_is_root_bus(bus) && devfn != 0) || !port->link_up)
return PCIBIOS_DEVICE_NOT_FOUND;
if (xgene_pcie_hide_rc_bars(bus, offset)) {
*val = 0;
return PCIBIOS_SUCCESSFUL;
}
xgene_pcie_set_rtdid_reg(bus, devfn);
addr = xgene_pcie_get_cfg_base(bus);
switch (len) {
case 1:
xgene_pcie_cfg_in8(addr, offset, val);
break;
case 2:
xgene_pcie_cfg_in16(addr, offset, val);
break;
default:
xgene_pcie_cfg_in32(addr, offset, val);
break;
}
return PCIBIOS_SUCCESSFUL;
}
static int xgene_pcie_write_config(struct pci_bus *bus, unsigned int devfn,
int offset, int len, u32 val)
{
struct xgene_pcie_port *port = bus->sysdata;
void __iomem *addr;
if ((pci_is_root_bus(bus) && devfn != 0) || !port->link_up)
return PCIBIOS_DEVICE_NOT_FOUND;
if (xgene_pcie_hide_rc_bars(bus, offset))
return PCIBIOS_SUCCESSFUL;
xgene_pcie_set_rtdid_reg(bus, devfn);
addr = xgene_pcie_get_cfg_base(bus);
switch (len) {
case 1:
xgene_pcie_cfg_out8(addr, offset, (u8)val);
break;
case 2:
xgene_pcie_cfg_out16(addr, offset, (u16)val);
break;
default:
xgene_pcie_cfg_out32(addr, offset, val);
break;
}
return PCIBIOS_SUCCESSFUL;
}
static struct pci_ops xgene_pcie_ops = {
.read = xgene_pcie_read_config,
.write = xgene_pcie_write_config
};
static u64 xgene_pcie_set_ib_mask(void __iomem *csr_base, u32 addr,
u32 flags, u64 size)
{
u64 mask = (~(size - 1) & PCI_BASE_ADDRESS_MEM_MASK) | flags;
u32 val32 = 0;
u32 val;
val32 = readl(csr_base + addr);
val = (val32 & 0x0000ffff) | (lower_32_bits(mask) << 16);
writel(val, csr_base + addr);
val32 = readl(csr_base + addr + 0x04);
val = (val32 & 0xffff0000) | (lower_32_bits(mask) >> 16);
writel(val, csr_base + addr + 0x04);
val32 = readl(csr_base + addr + 0x04);
val = (val32 & 0x0000ffff) | (upper_32_bits(mask) << 16);
writel(val, csr_base + addr + 0x04);
val32 = readl(csr_base + addr + 0x08);
val = (val32 & 0xffff0000) | (upper_32_bits(mask) >> 16);
writel(val, csr_base + addr + 0x08);
return mask;
}
static void xgene_pcie_linkup(struct xgene_pcie_port *port,
u32 *lanes, u32 *speed)
{
void __iomem *csr_base = port->csr_base;
u32 val32;
port->link_up = false;
val32 = readl(csr_base + PCIECORE_CTLANDSTATUS);
if (val32 & LINK_UP_MASK) {
port->link_up = true;
*speed = PIPE_PHY_RATE_RD(val32);
val32 = readl(csr_base + BRIDGE_STATUS_0);
*lanes = val32 >> 26;
}
}
static int xgene_pcie_init_port(struct xgene_pcie_port *port)
{
int rc;
port->clk = clk_get(port->dev, NULL);
if (IS_ERR(port->clk)) {
dev_err(port->dev, "clock not available\n");
return -ENODEV;
}
rc = clk_prepare_enable(port->clk);
if (rc) {
dev_err(port->dev, "clock enable failed\n");
return rc;
}
return 0;
}
static int xgene_pcie_map_reg(struct xgene_pcie_port *port,
struct platform_device *pdev)
{
struct resource *res;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "csr");
port->csr_base = devm_ioremap_resource(port->dev, res);
if (IS_ERR(port->csr_base))
return PTR_ERR(port->csr_base);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg");
port->cfg_base = devm_ioremap_resource(port->dev, res);
if (IS_ERR(port->cfg_base))
return PTR_ERR(port->cfg_base);
port->cfg_addr = res->start;
return 0;
}
static void xgene_pcie_setup_ob_reg(struct xgene_pcie_port *port,
struct resource *res, u32 offset,
u64 cpu_addr, u64 pci_addr)
{
void __iomem *base = port->csr_base + offset;
resource_size_t size = resource_size(res);
u64 restype = resource_type(res);
u64 mask = 0;
u32 min_size;
u32 flag = EN_REG;
if (restype == IORESOURCE_MEM) {
min_size = SZ_128M;
} else {
min_size = 128;
flag |= OB_LO_IO;
}
if (size >= min_size)
mask = ~(size - 1) | flag;
else
dev_warn(port->dev, "res size 0x%llx less than minimum 0x%x\n",
(u64)size, min_size);
writel(lower_32_bits(cpu_addr), base);
writel(upper_32_bits(cpu_addr), base + 0x04);
writel(lower_32_bits(mask), base + 0x08);
writel(upper_32_bits(mask), base + 0x0c);
writel(lower_32_bits(pci_addr), base + 0x10);
writel(upper_32_bits(pci_addr), base + 0x14);
}
static void xgene_pcie_setup_cfg_reg(void __iomem *csr_base, u64 addr)
{
writel(lower_32_bits(addr), csr_base + CFGBARL);
writel(upper_32_bits(addr), csr_base + CFGBARH);
writel(EN_REG, csr_base + CFGCTL);
}
static int xgene_pcie_map_ranges(struct xgene_pcie_port *port,
struct list_head *res,
resource_size_t io_base)
{
struct pci_host_bridge_window *window;
struct device *dev = port->dev;
int ret;
list_for_each_entry(window, res, list) {
struct resource *res = window->res;
u64 restype = resource_type(res);
dev_dbg(port->dev, "%pR\n", res);
switch (restype) {
case IORESOURCE_IO:
xgene_pcie_setup_ob_reg(port, res, OMR3BARL, io_base,
res->start - window->offset);
ret = pci_remap_iospace(res, io_base);
if (ret < 0)
return ret;
break;
case IORESOURCE_MEM:
xgene_pcie_setup_ob_reg(port, res, OMR1BARL, res->start,
res->start - window->offset);
break;
case IORESOURCE_BUS:
break;
default:
dev_err(dev, "invalid resource %pR\n", res);
return -EINVAL;
}
}
xgene_pcie_setup_cfg_reg(port->csr_base, port->cfg_addr);
return 0;
}
static void xgene_pcie_setup_pims(void *addr, u64 pim, u64 size)
{
writel(lower_32_bits(pim), addr);
writel(upper_32_bits(pim) | EN_COHERENCY, addr + 0x04);
writel(lower_32_bits(size), addr + 0x10);
writel(upper_32_bits(size), addr + 0x14);
}
/*
* X-Gene PCIe support maximum 3 inbound memory regions
* This function helps to select a region based on size of region
*/
static int xgene_pcie_select_ib_reg(u8 *ib_reg_mask, u64 size)
{
if ((size > 4) && (size < SZ_16M) && !(*ib_reg_mask & (1 << 1))) {
*ib_reg_mask |= (1 << 1);
return 1;
}
if ((size > SZ_1K) && (size < SZ_1T) && !(*ib_reg_mask & (1 << 0))) {
*ib_reg_mask |= (1 << 0);
return 0;
}
if ((size > SZ_1M) && (size < SZ_1T) && !(*ib_reg_mask & (1 << 2))) {
*ib_reg_mask |= (1 << 2);
return 2;
}
return -EINVAL;
}
static void xgene_pcie_setup_ib_reg(struct xgene_pcie_port *port,
struct of_pci_range *range, u8 *ib_reg_mask)
{
void __iomem *csr_base = port->csr_base;
void __iomem *cfg_base = port->cfg_base;
void *bar_addr;
void *pim_addr;
u64 cpu_addr = range->cpu_addr;
u64 pci_addr = range->pci_addr;
u64 size = range->size;
u64 mask = ~(size - 1) | EN_REG;
u32 flags = PCI_BASE_ADDRESS_MEM_TYPE_64;
u32 bar_low;
int region;
region = xgene_pcie_select_ib_reg(ib_reg_mask, range->size);
if (region < 0) {
dev_warn(port->dev, "invalid pcie dma-range config\n");
return;
}
if (range->flags & IORESOURCE_PREFETCH)
flags |= PCI_BASE_ADDRESS_MEM_PREFETCH;
bar_low = pcie_bar_low_val((u32)cpu_addr, flags);
switch (region) {
case 0:
xgene_pcie_set_ib_mask(csr_base, BRIDGE_CFG_4, flags, size);
bar_addr = cfg_base + PCI_BASE_ADDRESS_0;
writel(bar_low, bar_addr);
writel(upper_32_bits(cpu_addr), bar_addr + 0x4);
pim_addr = csr_base + PIM1_1L;
break;
case 1:
bar_addr = csr_base + IBAR2;
writel(bar_low, bar_addr);
writel(lower_32_bits(mask), csr_base + IR2MSK);
pim_addr = csr_base + PIM2_1L;
break;
case 2:
bar_addr = csr_base + IBAR3L;
writel(bar_low, bar_addr);
writel(upper_32_bits(cpu_addr), bar_addr + 0x4);
writel(lower_32_bits(mask), csr_base + IR3MSKL);
writel(upper_32_bits(mask), csr_base + IR3MSKL + 0x4);
pim_addr = csr_base + PIM3_1L;
break;
}
xgene_pcie_setup_pims(pim_addr, pci_addr, ~(size - 1));
}
static int pci_dma_range_parser_init(struct of_pci_range_parser *parser,
struct device_node *node)
{
const int na = 3, ns = 2;
int rlen;
parser->node = node;
parser->pna = of_n_addr_cells(node);
parser->np = parser->pna + na + ns;
parser->range = of_get_property(node, "dma-ranges", &rlen);
if (!parser->range)
return -ENOENT;
parser->end = parser->range + rlen / sizeof(__be32);
return 0;
}
static int xgene_pcie_parse_map_dma_ranges(struct xgene_pcie_port *port)
{
struct device_node *np = port->node;
struct of_pci_range range;
struct of_pci_range_parser parser;
struct device *dev = port->dev;
u8 ib_reg_mask = 0;
if (pci_dma_range_parser_init(&parser, np)) {
dev_err(dev, "missing dma-ranges property\n");
return -EINVAL;
}
/* Get the dma-ranges from DT */
for_each_of_pci_range(&parser, &range) {
u64 end = range.cpu_addr + range.size - 1;
dev_dbg(port->dev, "0x%08x 0x%016llx..0x%016llx -> 0x%016llx\n",
range.flags, range.cpu_addr, end, range.pci_addr);
xgene_pcie_setup_ib_reg(port, &range, &ib_reg_mask);
}
return 0;
}
/* clear BAR configuration which was done by firmware */
static void xgene_pcie_clear_config(struct xgene_pcie_port *port)
{
int i;
for (i = PIM1_1L; i <= CFGCTL; i += 4)
writel(0x0, port->csr_base + i);
}
static int xgene_pcie_setup(struct xgene_pcie_port *port,
struct list_head *res,
resource_size_t io_base)
{
u32 val, lanes = 0, speed = 0;
int ret;
xgene_pcie_clear_config(port);
/* setup the vendor and device IDs correctly */
val = (XGENE_PCIE_DEVICEID << 16) | XGENE_PCIE_VENDORID;
writel(val, port->csr_base + BRIDGE_CFG_0);
ret = xgene_pcie_map_ranges(port, res, io_base);
if (ret)
return ret;
ret = xgene_pcie_parse_map_dma_ranges(port);
if (ret)
return ret;
xgene_pcie_linkup(port, &lanes, &speed);
if (!port->link_up)
dev_info(port->dev, "(rc) link down\n");
else
dev_info(port->dev, "(rc) x%d gen-%d link up\n",
lanes, speed + 1);
return 0;
}
static int xgene_pcie_probe_bridge(struct platform_device *pdev)
{
struct device_node *dn = pdev->dev.of_node;
struct xgene_pcie_port *port;
resource_size_t iobase = 0;
struct pci_bus *bus;
int ret;
LIST_HEAD(res);
port = devm_kzalloc(&pdev->dev, sizeof(*port), GFP_KERNEL);
if (!port)
return -ENOMEM;
port->node = of_node_get(pdev->dev.of_node);
port->dev = &pdev->dev;
ret = xgene_pcie_map_reg(port, pdev);
if (ret)
return ret;
ret = xgene_pcie_init_port(port);
if (ret)
return ret;
ret = of_pci_get_host_bridge_resources(dn, 0, 0xff, &res, &iobase);
if (ret)
return ret;
ret = xgene_pcie_setup(port, &res, iobase);
if (ret)
return ret;
bus = pci_scan_root_bus(&pdev->dev, 0, &xgene_pcie_ops, port, &res);
if (!bus)
return -ENOMEM;
platform_set_drvdata(pdev, port);
return 0;
}
static const struct of_device_id xgene_pcie_match_table[] = {
{.compatible = "apm,xgene-pcie",},
{},
};
static struct platform_driver xgene_pcie_driver = {
.driver = {
.name = "xgene-pcie",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(xgene_pcie_match_table),
},
.probe = xgene_pcie_probe_bridge,
};
module_platform_driver(xgene_pcie_driver);
MODULE_AUTHOR("Tanmay Inamdar <tinamdar@apm.com>");
MODULE_DESCRIPTION("APM X-Gene PCIe driver");
MODULE_LICENSE("GPL v2");
......@@ -73,6 +73,8 @@ static unsigned long global_io_offset;
static inline struct pcie_port *sys_to_pcie(struct pci_sys_data *sys)
{
BUG_ON(!sys->private_data);
return sys->private_data;
}
......@@ -194,30 +196,6 @@ void dw_pcie_msi_init(struct pcie_port *pp)
dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_HI, 4, 0);
}
static int find_valid_pos0(struct pcie_port *pp, int msgvec, int pos, int *pos0)
{
int flag = 1;
do {
pos = find_next_zero_bit(pp->msi_irq_in_use,
MAX_MSI_IRQS, pos);
/*if you have reached to the end then get out from here.*/
if (pos == MAX_MSI_IRQS)
return -ENOSPC;
/*
* Check if this position is at correct offset.nvec is always a
* power of two. pos0 must be nvec bit aligned.
*/
if (pos % msgvec)
pos += msgvec - (pos % msgvec);
else
flag = 0;
} while (flag);
*pos0 = pos;
return 0;
}
static void dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq)
{
unsigned int res, bit, val;
......@@ -236,13 +214,14 @@ static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base,
for (i = 0; i < nvec; i++) {
irq_set_msi_desc_off(irq_base, i, NULL);
clear_bit(pos + i, pp->msi_irq_in_use);
/* Disable corresponding interrupt on MSI controller */
if (pp->ops->msi_clear_irq)
pp->ops->msi_clear_irq(pp, pos + i);
else
dw_pcie_msi_clear_irq(pp, pos + i);
}
bitmap_release_region(pp->msi_irq_in_use, pos, order_base_2(nvec));
}
static void dw_pcie_msi_set_irq(struct pcie_port *pp, int irq)
......@@ -258,31 +237,13 @@ static void dw_pcie_msi_set_irq(struct pcie_port *pp, int irq)
static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
{
int irq, pos0, pos1, i;
int irq, pos0, i;
struct pcie_port *pp = sys_to_pcie(desc->dev->bus->sysdata);
if (!pp) {
BUG();
return -EINVAL;
}
pos0 = find_first_zero_bit(pp->msi_irq_in_use,
MAX_MSI_IRQS);
if (pos0 % no_irqs) {
if (find_valid_pos0(pp, no_irqs, pos0, &pos0))
goto no_valid_irq;
}
if (no_irqs > 1) {
pos1 = find_next_bit(pp->msi_irq_in_use,
MAX_MSI_IRQS, pos0);
/* there must be nvec number of consecutive free bits */
while ((pos1 - pos0) < no_irqs) {
if (find_valid_pos0(pp, no_irqs, pos1, &pos0))
pos0 = bitmap_find_free_region(pp->msi_irq_in_use, MAX_MSI_IRQS,
order_base_2(no_irqs));
if (pos0 < 0)
goto no_valid_irq;
pos1 = find_next_bit(pp->msi_irq_in_use,
MAX_MSI_IRQS, pos0);
}
}
irq = irq_find_mapping(pp->irq_domain, pos0);
if (!irq)
......@@ -300,7 +261,6 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
clear_irq_range(pp, irq, i, pos0);
goto no_valid_irq;
}
set_bit(pos0 + i, pp->msi_irq_in_use);
/*Enable corresponding interrupt in MSI interrupt controller */
if (pp->ops->msi_set_irq)
pp->ops->msi_set_irq(pp, pos0 + i);
......@@ -316,69 +276,28 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
return -ENOSPC;
}
static void clear_irq(unsigned int irq)
{
unsigned int pos, nvec;
struct msi_desc *msi;
struct pcie_port *pp;
struct irq_data *data = irq_get_irq_data(irq);
/* get the port structure */
msi = irq_data_get_msi(data);
pp = sys_to_pcie(msi->dev->bus->sysdata);
if (!pp) {
BUG();
return;
}
/* undo what was done in assign_irq */
pos = data->hwirq;
nvec = 1 << msi->msi_attrib.multiple;
clear_irq_range(pp, irq, nvec, pos);
/* all irqs cleared; reset attributes */
msi->irq = 0;
msi->msi_attrib.multiple = 0;
}
static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
struct msi_desc *desc)
{
int irq, pos, msgvec;
u16 msg_ctr;
int irq, pos;
struct msi_msg msg;
struct pcie_port *pp = sys_to_pcie(pdev->bus->sysdata);
if (!pp) {
BUG();
return -EINVAL;
}
pci_read_config_word(pdev, desc->msi_attrib.pos+PCI_MSI_FLAGS,
&msg_ctr);
msgvec = (msg_ctr&PCI_MSI_FLAGS_QSIZE) >> 4;
if (msgvec == 0)
msgvec = (msg_ctr & PCI_MSI_FLAGS_QMASK) >> 1;
if (msgvec > 5)
msgvec = 0;
irq = assign_irq((1 << msgvec), desc, &pos);
irq = assign_irq(1, desc, &pos);
if (irq < 0)
return irq;
/*
* write_msi_msg() will update PCI_MSI_FLAGS so there is
* no need to explicitly call pci_write_config_word().
*/
desc->msi_attrib.multiple = msgvec;
if (pp->ops->get_msi_data)
msg.address_lo = pp->ops->get_msi_data(pp);
if (pp->ops->get_msi_addr)
msg.address_lo = pp->ops->get_msi_addr(pp);
else
msg.address_lo = virt_to_phys((void *)pp->msi_data);
msg.address_hi = 0x0;
if (pp->ops->get_msi_data)
msg.data = pp->ops->get_msi_data(pp, pos);
else
msg.data = pos;
write_msi_msg(irq, &msg);
return 0;
......@@ -386,7 +305,11 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
static void dw_msi_teardown_irq(struct msi_chip *chip, unsigned int irq)
{
clear_irq(irq);
struct irq_data *data = irq_get_irq_data(irq);
struct msi_desc *msi = irq_data_get_msi(data);
struct pcie_port *pp = sys_to_pcie(msi->dev->bus->sysdata);
clear_irq_range(pp, irq, 1, data->hwirq);
}
static struct msi_chip dw_pcie_msi_chip = {
......@@ -425,7 +348,7 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
struct resource *cfg_res;
u32 val, na, ns;
const __be32 *addrp;
int i, index;
int i, index, ret;
/* Find the address cell size and the number of cells in order to get
* the untranslated address.
......@@ -435,16 +358,16 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
cfg_res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "config");
if (cfg_res) {
pp->config.cfg0_size = resource_size(cfg_res)/2;
pp->config.cfg1_size = resource_size(cfg_res)/2;
pp->cfg0_size = resource_size(cfg_res)/2;
pp->cfg1_size = resource_size(cfg_res)/2;
pp->cfg0_base = cfg_res->start;
pp->cfg1_base = cfg_res->start + pp->config.cfg0_size;
pp->cfg1_base = cfg_res->start + pp->cfg0_size;
/* Find the untranslated configuration space address */
index = of_property_match_string(np, "reg-names", "config");
addrp = of_get_address(np, index, false, false);
addrp = of_get_address(np, index, NULL, NULL);
pp->cfg0_mod_base = of_read_number(addrp, ns);
pp->cfg1_mod_base = pp->cfg0_mod_base + pp->config.cfg0_size;
pp->cfg1_mod_base = pp->cfg0_mod_base + pp->cfg0_size;
} else {
dev_err(pp->dev, "missing *config* reg space\n");
}
......@@ -466,9 +389,9 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
pp->io.end = min_t(resource_size_t,
IO_SPACE_LIMIT,
range.pci_addr + range.size
+ global_io_offset);
pp->config.io_size = resource_size(&pp->io);
pp->config.io_bus_addr = range.pci_addr;
+ global_io_offset - 1);
pp->io_size = resource_size(&pp->io);
pp->io_bus_addr = range.pci_addr;
pp->io_base = range.cpu_addr;
/* Find the untranslated IO space address */
......@@ -478,8 +401,8 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
if (restype == IORESOURCE_MEM) {
of_pci_range_to_resource(&range, np, &pp->mem);
pp->mem.name = "MEM";
pp->config.mem_size = resource_size(&pp->mem);
pp->config.mem_bus_addr = range.pci_addr;
pp->mem_size = resource_size(&pp->mem);
pp->mem_bus_addr = range.pci_addr;
/* Find the untranslated MEM space address */
pp->mem_mod_base = of_read_number(parser.range -
......@@ -487,19 +410,29 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
}
if (restype == 0) {
of_pci_range_to_resource(&range, np, &pp->cfg);
pp->config.cfg0_size = resource_size(&pp->cfg)/2;
pp->config.cfg1_size = resource_size(&pp->cfg)/2;
pp->cfg0_size = resource_size(&pp->cfg)/2;
pp->cfg1_size = resource_size(&pp->cfg)/2;
pp->cfg0_base = pp->cfg.start;
pp->cfg1_base = pp->cfg.start + pp->config.cfg0_size;
pp->cfg1_base = pp->cfg.start + pp->cfg0_size;
/* Find the untranslated configuration space address */
pp->cfg0_mod_base = of_read_number(parser.range -
parser.np + na, ns);
pp->cfg1_mod_base = pp->cfg0_mod_base +
pp->config.cfg0_size;
pp->cfg0_size;
}
}
ret = of_pci_parse_bus_range(np, &pp->busn);
if (ret < 0) {
pp->busn.name = np->name;
pp->busn.start = 0;
pp->busn.end = 0xff;
pp->busn.flags = IORESOURCE_BUS;
dev_dbg(pp->dev, "failed to parse bus-range property: %d, using default %pR\n",
ret, &pp->busn);
}
if (!pp->dbi_base) {
pp->dbi_base = devm_ioremap(pp->dev, pp->cfg.start,
resource_size(&pp->cfg));
......@@ -511,18 +444,23 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
pp->mem_base = pp->mem.start;
if (!pp->va_cfg0_base) {
pp->va_cfg0_base = devm_ioremap(pp->dev, pp->cfg0_base,
pp->config.cfg0_size);
pp->cfg0_size);
if (!pp->va_cfg0_base) {
dev_err(pp->dev, "error with ioremap in function\n");
return -ENOMEM;
}
}
if (!pp->va_cfg1_base) {
pp->va_cfg1_base = devm_ioremap(pp->dev, pp->cfg1_base,
pp->config.cfg1_size);
pp->cfg1_size);
if (!pp->va_cfg1_base) {
dev_err(pp->dev, "error with ioremap\n");
return -ENOMEM;
}
}
if (of_property_read_u32(np, "num-lanes", &pp->lanes)) {
dev_err(pp->dev, "Failed to parse the number of lanes\n");
......@@ -530,6 +468,7 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
}
if (IS_ENABLED(CONFIG_PCI_MSI)) {
if (!pp->ops->msi_host_init) {
pp->irq_domain = irq_domain_add_linear(pp->dev->of_node,
MAX_MSI_IRQS, &msi_domain_ops,
&dw_pcie_msi_chip);
......@@ -540,6 +479,11 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
for (i = 0; i < MAX_MSI_IRQS; i++)
irq_create_mapping(pp->irq_domain, i);
} else {
ret = pp->ops->msi_host_init(pp, &dw_pcie_msi_chip);
if (ret < 0)
return ret;
}
}
if (pp->ops->host_init)
......@@ -558,7 +502,6 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
dw_pci.private_data = (void **)&pp;
pci_common_init_dev(pp->dev, &dw_pci);
pci_assign_unassigned_resources();
#ifdef CONFIG_PCI_DOMAINS
dw_pci.domain++;
#endif
......@@ -573,7 +516,7 @@ static void dw_pcie_prog_viewport_cfg0(struct pcie_port *pp, u32 busdev)
PCIE_ATU_VIEWPORT);
dw_pcie_writel_rc(pp, pp->cfg0_mod_base, PCIE_ATU_LOWER_BASE);
dw_pcie_writel_rc(pp, (pp->cfg0_mod_base >> 32), PCIE_ATU_UPPER_BASE);
dw_pcie_writel_rc(pp, pp->cfg0_mod_base + pp->config.cfg0_size - 1,
dw_pcie_writel_rc(pp, pp->cfg0_mod_base + pp->cfg0_size - 1,
PCIE_ATU_LIMIT);
dw_pcie_writel_rc(pp, busdev, PCIE_ATU_LOWER_TARGET);
dw_pcie_writel_rc(pp, 0, PCIE_ATU_UPPER_TARGET);
......@@ -589,7 +532,7 @@ static void dw_pcie_prog_viewport_cfg1(struct pcie_port *pp, u32 busdev)
dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_CFG1, PCIE_ATU_CR1);
dw_pcie_writel_rc(pp, pp->cfg1_mod_base, PCIE_ATU_LOWER_BASE);
dw_pcie_writel_rc(pp, (pp->cfg1_mod_base >> 32), PCIE_ATU_UPPER_BASE);
dw_pcie_writel_rc(pp, pp->cfg1_mod_base + pp->config.cfg1_size - 1,
dw_pcie_writel_rc(pp, pp->cfg1_mod_base + pp->cfg1_size - 1,
PCIE_ATU_LIMIT);
dw_pcie_writel_rc(pp, busdev, PCIE_ATU_LOWER_TARGET);
dw_pcie_writel_rc(pp, 0, PCIE_ATU_UPPER_TARGET);
......@@ -604,10 +547,10 @@ static void dw_pcie_prog_viewport_mem_outbound(struct pcie_port *pp)
dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_MEM, PCIE_ATU_CR1);
dw_pcie_writel_rc(pp, pp->mem_mod_base, PCIE_ATU_LOWER_BASE);
dw_pcie_writel_rc(pp, (pp->mem_mod_base >> 32), PCIE_ATU_UPPER_BASE);
dw_pcie_writel_rc(pp, pp->mem_mod_base + pp->config.mem_size - 1,
dw_pcie_writel_rc(pp, pp->mem_mod_base + pp->mem_size - 1,
PCIE_ATU_LIMIT);
dw_pcie_writel_rc(pp, pp->config.mem_bus_addr, PCIE_ATU_LOWER_TARGET);
dw_pcie_writel_rc(pp, upper_32_bits(pp->config.mem_bus_addr),
dw_pcie_writel_rc(pp, pp->mem_bus_addr, PCIE_ATU_LOWER_TARGET);
dw_pcie_writel_rc(pp, upper_32_bits(pp->mem_bus_addr),
PCIE_ATU_UPPER_TARGET);
dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
}
......@@ -620,10 +563,10 @@ static void dw_pcie_prog_viewport_io_outbound(struct pcie_port *pp)
dw_pcie_writel_rc(pp, PCIE_ATU_TYPE_IO, PCIE_ATU_CR1);
dw_pcie_writel_rc(pp, pp->io_mod_base, PCIE_ATU_LOWER_BASE);
dw_pcie_writel_rc(pp, (pp->io_mod_base >> 32), PCIE_ATU_UPPER_BASE);
dw_pcie_writel_rc(pp, pp->io_mod_base + pp->config.io_size - 1,
dw_pcie_writel_rc(pp, pp->io_mod_base + pp->io_size - 1,
PCIE_ATU_LIMIT);
dw_pcie_writel_rc(pp, pp->config.io_bus_addr, PCIE_ATU_LOWER_TARGET);
dw_pcie_writel_rc(pp, upper_32_bits(pp->config.io_bus_addr),
dw_pcie_writel_rc(pp, pp->io_bus_addr, PCIE_ATU_LOWER_TARGET);
dw_pcie_writel_rc(pp, upper_32_bits(pp->io_bus_addr),
PCIE_ATU_UPPER_TARGET);
dw_pcie_writel_rc(pp, PCIE_ATU_ENABLE, PCIE_ATU_CR2);
}
......@@ -707,11 +650,6 @@ static int dw_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
struct pcie_port *pp = sys_to_pcie(bus->sysdata);
int ret;
if (!pp) {
BUG();
return -EINVAL;
}
if (dw_pcie_valid_config(pp, bus, PCI_SLOT(devfn)) == 0) {
*val = 0xffffffff;
return PCIBIOS_DEVICE_NOT_FOUND;
......@@ -736,11 +674,6 @@ static int dw_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
struct pcie_port *pp = sys_to_pcie(bus->sysdata);
int ret;
if (!pp) {
BUG();
return -EINVAL;
}
if (dw_pcie_valid_config(pp, bus, PCI_SLOT(devfn)) == 0)
return PCIBIOS_DEVICE_NOT_FOUND;
......@@ -768,19 +701,17 @@ static int dw_pcie_setup(int nr, struct pci_sys_data *sys)
pp = sys_to_pcie(sys);
if (!pp)
return 0;
if (global_io_offset < SZ_1M && pp->config.io_size > 0) {
sys->io_offset = global_io_offset - pp->config.io_bus_addr;
if (global_io_offset < SZ_1M && pp->io_size > 0) {
sys->io_offset = global_io_offset - pp->io_bus_addr;
pci_ioremap_io(global_io_offset, pp->io_base);
global_io_offset += SZ_64K;
pci_add_resource_offset(&sys->resources, &pp->io,
sys->io_offset);
}
sys->mem_offset = pp->mem.start - pp->config.mem_bus_addr;
sys->mem_offset = pp->mem.start - pp->mem_bus_addr;
pci_add_resource_offset(&sys->resources, &pp->mem, sys->mem_offset);
pci_add_resource(&sys->resources, &pp->busn);
return 1;
}
......@@ -790,14 +721,16 @@ static struct pci_bus *dw_pcie_scan_bus(int nr, struct pci_sys_data *sys)
struct pci_bus *bus;
struct pcie_port *pp = sys_to_pcie(sys);
if (pp) {
pp->root_bus_nr = sys->busnr;
bus = pci_scan_root_bus(pp->dev, sys->busnr, &dw_pcie_ops,
sys, &sys->resources);
} else {
bus = NULL;
BUG();
}
bus = pci_create_root_bus(pp->dev, sys->busnr,
&dw_pcie_ops, sys, &sys->resources);
if (!bus)
return NULL;
pci_scan_child_bus(bus);
if (bus && pp->ops->scan_bus)
pp->ops->scan_bus(pp);
return bus;
}
......@@ -833,7 +766,6 @@ static struct hw_pci dw_pci = {
void dw_pcie_setup_rc(struct pcie_port *pp)
{
struct pcie_port_info *config = &pp->config;
u32 val;
u32 membase;
u32 memlimit;
......@@ -888,7 +820,7 @@ void dw_pcie_setup_rc(struct pcie_port *pp)
/* setup memory base, memory limit */
membase = ((u32)pp->mem_base & 0xfff00000) >> 16;
memlimit = (config->mem_size + (u32)pp->mem_base) & 0xfff00000;
memlimit = (pp->mem_size + (u32)pp->mem_base) & 0xfff00000;
val = memlimit | membase;
dw_pcie_writel_rc(pp, val, PCI_MEMORY_BASE);
......
......@@ -14,15 +14,6 @@
#ifndef _PCIE_DESIGNWARE_H
#define _PCIE_DESIGNWARE_H
struct pcie_port_info {
u32 cfg0_size;
u32 cfg1_size;
u32 io_size;
u32 mem_size;
phys_addr_t io_bus_addr;
phys_addr_t mem_bus_addr;
};
/*
* Maximum number of MSI IRQs can be 256 per controller. But keep
* it 32 as of now. Probably we will never need more than 32. If needed,
......@@ -38,17 +29,23 @@ struct pcie_port {
u64 cfg0_base;
u64 cfg0_mod_base;
void __iomem *va_cfg0_base;
u32 cfg0_size;
u64 cfg1_base;
u64 cfg1_mod_base;
void __iomem *va_cfg1_base;
u32 cfg1_size;
u64 io_base;
u64 io_mod_base;
phys_addr_t io_bus_addr;
u32 io_size;
u64 mem_base;
u64 mem_mod_base;
phys_addr_t mem_bus_addr;
u32 mem_size;
struct resource cfg;
struct resource io;
struct resource mem;
struct pcie_port_info config;
struct resource busn;
int irq;
u32 lanes;
struct pcie_host_ops *ops;
......@@ -73,7 +70,10 @@ struct pcie_host_ops {
void (*host_init)(struct pcie_port *pp);
void (*msi_set_irq)(struct pcie_port *pp, int irq);
void (*msi_clear_irq)(struct pcie_port *pp, int irq);
u32 (*get_msi_data)(struct pcie_port *pp);
u32 (*get_msi_addr)(struct pcie_port *pp);
u32 (*get_msi_data)(struct pcie_port *pp, int pos);
void (*scan_bus)(struct pcie_port *pp);
int (*msi_host_init)(struct pcie_port *pp, struct msi_chip *chip);
};
int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val);
......
......@@ -323,6 +323,7 @@ static void rcar_pcie_setup_window(int win, struct rcar_pcie *pcie)
/* Setup PCIe address space mappings for each resource */
resource_size_t size;
resource_size_t res_start;
u32 mask;
rcar_pci_write_reg(pcie, 0x00000000, PCIEPTCTLR(win));
......@@ -335,8 +336,13 @@ static void rcar_pcie_setup_window(int win, struct rcar_pcie *pcie)
mask = (roundup_pow_of_two(size) / SZ_128) - 1;
rcar_pci_write_reg(pcie, mask << 7, PCIEPAMR(win));
rcar_pci_write_reg(pcie, upper_32_bits(res->start), PCIEPARH(win));
rcar_pci_write_reg(pcie, lower_32_bits(res->start), PCIEPARL(win));
if (res->flags & IORESOURCE_IO)
res_start = pci_pio_to_address(res->start);
else
res_start = res->start;
rcar_pci_write_reg(pcie, upper_32_bits(res_start), PCIEPARH(win));
rcar_pci_write_reg(pcie, lower_32_bits(res_start), PCIEPARL(win));
/* First resource is for IO */
mask = PAR_ENABLE;
......@@ -363,9 +369,10 @@ static int rcar_pcie_setup(int nr, struct pci_sys_data *sys)
rcar_pcie_setup_window(i, pcie);
if (res->flags & IORESOURCE_IO)
pci_ioremap_io(nr * SZ_64K, res->start);
else
if (res->flags & IORESOURCE_IO) {
phys_addr_t io_start = pci_pio_to_address(res->start);
pci_ioremap_io(nr * SZ_64K, io_start);
} else
pci_add_resource(&sys->resources, res);
}
pci_add_resource(&sys->resources, &pcie->busn);
......@@ -935,8 +942,10 @@ static int rcar_pcie_probe(struct platform_device *pdev)
}
for_each_of_pci_range(&parser, &range) {
of_pci_range_to_resource(&range, pdev->dev.of_node,
err = of_pci_range_to_resource(&range, pdev->dev.of_node,
&pcie->res[win++]);
if (err < 0)
return err;
if (win > RCAR_PCI_MAX_RESOURCES)
break;
......
......@@ -340,7 +340,7 @@ static int __init spear13xx_pcie_probe(struct platform_device *pdev)
pp->dev = dev;
dbi_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
pp->dbi_base = devm_ioremap_resource(dev, dbi_base);
if (IS_ERR(pp->dbi_base)) {
dev_err(dev, "couldn't remap dbi base %p\n", dbi_base);
......
此差异已折叠。
......@@ -24,7 +24,7 @@ obj-$(CONFIG_HOTPLUG_PCI_S390) += s390_pci_hpc.o
obj-$(CONFIG_HOTPLUG_PCI_ACPI_IBM) += acpiphp_ibm.o
pci_hotplug-objs := pci_hotplug_core.o pcihp_slot.o
pci_hotplug-objs := pci_hotplug_core.o
ifdef CONFIG_HOTPLUG_PCI_CPCI
pci_hotplug-objs += cpci_hotplug_core.o \
......
......@@ -46,215 +46,6 @@
static bool debug_acpi;
static acpi_status
decode_type0_hpx_record(union acpi_object *record, struct hotplug_params *hpx)
{
int i;
union acpi_object *fields = record->package.elements;
u32 revision = fields[1].integer.value;
switch (revision) {
case 1:
if (record->package.count != 6)
return AE_ERROR;
for (i = 2; i < 6; i++)
if (fields[i].type != ACPI_TYPE_INTEGER)
return AE_ERROR;
hpx->t0 = &hpx->type0_data;
hpx->t0->revision = revision;
hpx->t0->cache_line_size = fields[2].integer.value;
hpx->t0->latency_timer = fields[3].integer.value;
hpx->t0->enable_serr = fields[4].integer.value;
hpx->t0->enable_perr = fields[5].integer.value;
break;
default:
printk(KERN_WARNING
"%s: Type 0 Revision %d record not supported\n",
__func__, revision);
return AE_ERROR;
}
return AE_OK;
}
static acpi_status
decode_type1_hpx_record(union acpi_object *record, struct hotplug_params *hpx)
{
int i;
union acpi_object *fields = record->package.elements;
u32 revision = fields[1].integer.value;
switch (revision) {
case 1:
if (record->package.count != 5)
return AE_ERROR;
for (i = 2; i < 5; i++)
if (fields[i].type != ACPI_TYPE_INTEGER)
return AE_ERROR;
hpx->t1 = &hpx->type1_data;
hpx->t1->revision = revision;
hpx->t1->max_mem_read = fields[2].integer.value;
hpx->t1->avg_max_split = fields[3].integer.value;
hpx->t1->tot_max_split = fields[4].integer.value;
break;
default:
printk(KERN_WARNING
"%s: Type 1 Revision %d record not supported\n",
__func__, revision);
return AE_ERROR;
}
return AE_OK;
}
static acpi_status
decode_type2_hpx_record(union acpi_object *record, struct hotplug_params *hpx)
{
int i;
union acpi_object *fields = record->package.elements;
u32 revision = fields[1].integer.value;
switch (revision) {
case 1:
if (record->package.count != 18)
return AE_ERROR;
for (i = 2; i < 18; i++)
if (fields[i].type != ACPI_TYPE_INTEGER)
return AE_ERROR;
hpx->t2 = &hpx->type2_data;
hpx->t2->revision = revision;
hpx->t2->unc_err_mask_and = fields[2].integer.value;
hpx->t2->unc_err_mask_or = fields[3].integer.value;
hpx->t2->unc_err_sever_and = fields[4].integer.value;
hpx->t2->unc_err_sever_or = fields[5].integer.value;
hpx->t2->cor_err_mask_and = fields[6].integer.value;
hpx->t2->cor_err_mask_or = fields[7].integer.value;
hpx->t2->adv_err_cap_and = fields[8].integer.value;
hpx->t2->adv_err_cap_or = fields[9].integer.value;
hpx->t2->pci_exp_devctl_and = fields[10].integer.value;
hpx->t2->pci_exp_devctl_or = fields[11].integer.value;
hpx->t2->pci_exp_lnkctl_and = fields[12].integer.value;
hpx->t2->pci_exp_lnkctl_or = fields[13].integer.value;
hpx->t2->sec_unc_err_sever_and = fields[14].integer.value;
hpx->t2->sec_unc_err_sever_or = fields[15].integer.value;
hpx->t2->sec_unc_err_mask_and = fields[16].integer.value;
hpx->t2->sec_unc_err_mask_or = fields[17].integer.value;
break;
default:
printk(KERN_WARNING
"%s: Type 2 Revision %d record not supported\n",
__func__, revision);
return AE_ERROR;
}
return AE_OK;
}
static acpi_status
acpi_run_hpx(acpi_handle handle, struct hotplug_params *hpx)
{
acpi_status status;
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
union acpi_object *package, *record, *fields;
u32 type;
int i;
/* Clear the return buffer with zeros */
memset(hpx, 0, sizeof(struct hotplug_params));
status = acpi_evaluate_object(handle, "_HPX", NULL, &buffer);
if (ACPI_FAILURE(status))
return status;
package = (union acpi_object *)buffer.pointer;
if (package->type != ACPI_TYPE_PACKAGE) {
status = AE_ERROR;
goto exit;
}
for (i = 0; i < package->package.count; i++) {
record = &package->package.elements[i];
if (record->type != ACPI_TYPE_PACKAGE) {
status = AE_ERROR;
goto exit;
}
fields = record->package.elements;
if (fields[0].type != ACPI_TYPE_INTEGER ||
fields[1].type != ACPI_TYPE_INTEGER) {
status = AE_ERROR;
goto exit;
}
type = fields[0].integer.value;
switch (type) {
case 0:
status = decode_type0_hpx_record(record, hpx);
if (ACPI_FAILURE(status))
goto exit;
break;
case 1:
status = decode_type1_hpx_record(record, hpx);
if (ACPI_FAILURE(status))
goto exit;
break;
case 2:
status = decode_type2_hpx_record(record, hpx);
if (ACPI_FAILURE(status))
goto exit;
break;
default:
printk(KERN_ERR "%s: Type %d record not supported\n",
__func__, type);
status = AE_ERROR;
goto exit;
}
}
exit:
kfree(buffer.pointer);
return status;
}
static acpi_status
acpi_run_hpp(acpi_handle handle, struct hotplug_params *hpp)
{
acpi_status status;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *package, *fields;
int i;
memset(hpp, 0, sizeof(struct hotplug_params));
status = acpi_evaluate_object(handle, "_HPP", NULL, &buffer);
if (ACPI_FAILURE(status))
return status;
package = (union acpi_object *) buffer.pointer;
if (package->type != ACPI_TYPE_PACKAGE ||
package->package.count != 4) {
status = AE_ERROR;
goto exit;
}
fields = package->package.elements;
for (i = 0; i < 4; i++) {
if (fields[i].type != ACPI_TYPE_INTEGER) {
status = AE_ERROR;
goto exit;
}
}
hpp->t0 = &hpp->type0_data;
hpp->t0->revision = 1;
hpp->t0->cache_line_size = fields[0].integer.value;
hpp->t0->latency_timer = fields[1].integer.value;
hpp->t0->enable_serr = fields[2].integer.value;
hpp->t0->enable_perr = fields[3].integer.value;
exit:
kfree(buffer.pointer);
return status;
}
/* acpi_run_oshp - get control of hotplug from the firmware
*
* @handle - the handle of the hotplug controller.
......@@ -283,48 +74,6 @@ static acpi_status acpi_run_oshp(acpi_handle handle)
return status;
}
/* pci_get_hp_params
*
* @dev - the pci_dev for which we want parameters
* @hpp - allocated by the caller
*/
int pci_get_hp_params(struct pci_dev *dev, struct hotplug_params *hpp)
{
acpi_status status;
acpi_handle handle, phandle;
struct pci_bus *pbus;
handle = NULL;
for (pbus = dev->bus; pbus; pbus = pbus->parent) {
handle = acpi_pci_get_bridge_handle(pbus);
if (handle)
break;
}
/*
* _HPP settings apply to all child buses, until another _HPP is
* encountered. If we don't find an _HPP for the input pci dev,
* look for it in the parent device scope since that would apply to
* this pci dev.
*/
while (handle) {
status = acpi_run_hpx(handle, hpp);
if (ACPI_SUCCESS(status))
return 0;
status = acpi_run_hpp(handle, hpp);
if (ACPI_SUCCESS(status))
return 0;
if (acpi_is_root_bridge(handle))
break;
status = acpi_get_parent(handle, &phandle);
if (ACPI_FAILURE(status))
break;
handle = phandle;
}
return -ENODEV;
}
EXPORT_SYMBOL_GPL(pci_get_hp_params);
/**
* acpi_get_hp_hw_control_from_firmware
* @dev: the pci_dev of the bridge that has a hotplug controller
......@@ -433,7 +182,8 @@ int acpi_pci_check_ejectable(struct pci_bus *pbus, acpi_handle handle)
{
acpi_handle bridge_handle, parent_handle;
if (!(bridge_handle = acpi_pci_get_bridge_handle(pbus)))
bridge_handle = acpi_pci_get_bridge_handle(pbus);
if (!bridge_handle)
return 0;
if ((ACPI_FAILURE(acpi_get_parent(handle, &parent_handle))))
return 0;
......
......@@ -61,7 +61,6 @@ static DEFINE_MUTEX(bridge_mutex);
static int acpiphp_hotplug_notify(struct acpi_device *adev, u32 type);
static void acpiphp_post_dock_fixup(struct acpi_device *adev);
static void acpiphp_sanitize_bus(struct pci_bus *bus);
static void acpiphp_set_hpp_values(struct pci_bus *bus);
static void hotplug_event(u32 type, struct acpiphp_context *context);
static void free_bridge(struct kref *kref);
......@@ -510,7 +509,7 @@ static void enable_slot(struct acpiphp_slot *slot)
__pci_bus_assign_resources(bus, &add_list, NULL);
acpiphp_sanitize_bus(bus);
acpiphp_set_hpp_values(bus);
pcie_bus_configure_settings(bus);
acpiphp_set_acpi_region(slot);
list_for_each_entry(dev, &bus->devices, bus_list) {
......@@ -698,14 +697,6 @@ static void acpiphp_check_bridge(struct acpiphp_bridge *bridge)
}
}
static void acpiphp_set_hpp_values(struct pci_bus *bus)
{
struct pci_dev *dev;
list_for_each_entry(dev, &bus->devices, bus_list)
pci_configure_slot(dev);
}
/*
* Remove devices for which we could not assign resources, call
* arch specific code to fix-up the bus
......
......@@ -302,7 +302,7 @@ static int ibm_get_table_from_acpi(char **bufp)
goto read_table_done;
}
for(size = 0, i = 0; i < package->package.count; i++) {
for (size = 0, i = 0; i < package->package.count; i++) {
if (package->package.elements[i].type != ACPI_TYPE_BUFFER) {
pr_err("%s: Invalid APCI element %d\n", __func__, i);
goto read_table_done;
......
......@@ -125,7 +125,8 @@ disable_slot(struct hotplug_slot *hotplug_slot)
/* Unconfigure device */
dbg("%s - unconfiguring slot %s", __func__, slot_name(slot));
if ((retval = cpci_unconfigure_slot(slot))) {
retval = cpci_unconfigure_slot(slot);
if (retval) {
err("%s - could not unconfigure slot %s",
__func__, slot_name(slot));
goto disable_error;
......@@ -141,9 +142,11 @@ disable_slot(struct hotplug_slot *hotplug_slot)
}
cpci_led_on(slot);
if (controller->ops->set_power)
if ((retval = controller->ops->set_power(slot, 0)))
if (controller->ops->set_power) {
retval = controller->ops->set_power(slot, 0);
if (retval)
goto disable_error;
}
if (update_adapter_status(slot->hotplug_slot, 0))
warn("failure to update adapter file");
......@@ -467,9 +470,9 @@ check_slots(void)
__func__, slot_name(slot), hs_csr);
if (!slot->extracting) {
if (update_latch_status(slot->hotplug_slot, 0)) {
if (update_latch_status(slot->hotplug_slot, 0))
warn("failure to update latch file");
}
slot->extracting = 1;
atomic_inc(&extracting);
}
......
此差异已折叠。
......@@ -690,7 +690,7 @@ static inline int cpq_get_latch_status(struct controller *ctrl,
status = (readl(ctrl->hpc_reg + INT_INPUT_CLEAR) & (0x01L << hp_slot));
return(status == 0) ? 1 : 0;
return (status == 0) ? 1 : 0;
}
......
......@@ -1096,9 +1096,8 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* initialize our threads if they haven't already been started up */
rc = one_time_init();
if (rc) {
if (rc)
goto err_free_bus;
}
dbg("pdev = %p\n", pdev);
dbg("pci resource start %llx\n", (unsigned long long)pci_resource_start(pdev, 0));
......
此差异已折叠。
......@@ -204,9 +204,8 @@ static int load_HRT (void __iomem *rom_start)
u8 temp_byte = 0xFF;
u32 rc;
if (!check_for_compaq_ROM(rom_start)) {
if (!check_for_compaq_ROM(rom_start))
return -ENODEV;
}
available = 1024;
......@@ -250,9 +249,8 @@ static u32 store_HRT (void __iomem *rom_start)
available = 1024;
if (!check_for_compaq_ROM(rom_start)) {
if (!check_for_compaq_ROM(rom_start))
return(1);
}
buffer = (u32*) evbuffer;
......@@ -427,9 +425,9 @@ static u32 store_HRT (void __iomem *rom_start)
void compaq_nvram_init (void __iomem *rom_start)
{
if (rom_start) {
if (rom_start)
compaq_int15_entry_point = (rom_start + ROM_INT15_PHY_ADDR - ROM_PHY_ADDR);
}
dbg("int15 entry = %p\n", compaq_int15_entry_point);
/* initialize our int15 lock */
......@@ -661,10 +659,9 @@ int compaq_nvram_store (void __iomem *rom_start)
if (evbuffer_init) {
rc = store_HRT(rom_start);
if (rc) {
if (rc)
err(msg_unable_to_save);
}
}
return rc;
}
此差异已折叠。
......@@ -215,9 +215,8 @@ static void __init print_ebda_hpc (void)
debug ("%s - cap of the slot: %x\n", __func__, hpc_ptr->slots[index].slot_cap);
}
for (index = 0; index < hpc_ptr->bus_count; index++) {
for (index = 0; index < hpc_ptr->bus_count; index++)
debug ("%s - bus# of each bus controlled by this ctlr: %x\n", __func__, hpc_ptr->buses[index].bus_num);
}
debug ("%s - type of hpc: %x\n", __func__, hpc_ptr->ctlr_type);
switch (hpc_ptr->ctlr_type) {
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
......@@ -92,7 +92,7 @@ struct controller {
struct slot *slot;
wait_queue_head_t queue; /* sleep & wake process */
u32 slot_cap;
u32 slot_ctrl;
u16 slot_ctrl;
struct timer_list poll_timer;
unsigned long cmd_started; /* jiffies */
unsigned int cmd_busy:1;
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册