mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 18:51:56 -04:00
pci-v4.16-changes
-----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJad5lgAAoJEFmIoMA60/r8s2kQAI3PztawDpaCP9Z12pkbBHSt Ho0xTyk9rCZi9kQJbNjc+a+QrlA3QmTHXIXerB3LSWoh7M+XhsECjem92eHpgLNS JvYPhTfOrCr0vdiAmOz6hD0AqN/psrbfzgiJhSwomsGEFS77k7kERSJckRv81sxb Aj5F/WjucAgLorwm4auveAJEQ7atE7/6pkXzoqYm4G6NLOb46jUcRGndrnvXZBlz fws8fBM4BHyi7i25CYQl24tFq1CGax1rIPgLg+4KnH76bQk/N6Ju0sGVSzfh+hG8 SIerK9bJbzGRAuNKoxB3aO1dyzsK3x9WztE2mG98w5trOISPIR1FqnvC/225FWAU d6eIXiC7wKnEx+DElNTzCjzfHc7SAJoupO32H7CoiTe5zPUlWlxJ1zLYkK1gt50q m8PRBiYTglxyznzrO0drtcdjEzvbdZNRrsYnul4wi1vSHzjk6F6XLtzT10XWM1M1 1pXLB8384FTj0Hu4bq6Y3Aivkmz0Sf+eQM2NaOwe+Zj7/1VV0d3lvi4LUXkqzLCA FoXPJSMxG2Qu+iflCeYRQBJjExaZH3eNLZ3dT6QpcJrjaFVedd9u5DeeFqNL27zV bhr8TdqrR4p4rc8EBAGoCapw96IxLZROKB3gxbrZVOpfIZpzthwHbElHX6aqUgF4 w/EV1JWs36WXWaxFk8wd =ttq9 -----END PGP SIGNATURE----- Merge tag 'pci-v4.16-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci Pull PCI updates from Bjorn Helgaas: - skip AER driver error recovery callbacks for correctable errors reported via ACPI APEI, as we already do for errors reported via the native path (Tyler Baicar) - fix DPC shared interrupt handling (Alex Williamson) - print full DPC interrupt number (Keith Busch) - enable DPC only if AER is available (Keith Busch) - simplify DPC code (Bjorn Helgaas) - calculate ASPM L1 substate parameter instead of hardcoding it (Bjorn Helgaas) - enable Latency Tolerance Reporting for ASPM L1 substates (Bjorn Helgaas) - move ASPM internal interfaces out of public header (Bjorn Helgaas) - allow hot-removal of VGA devices (Mika Westerberg) - speed up unplug and shutdown by assuming Thunderbolt controllers don't support Command Completed events (Lukas Wunner) - add AtomicOps support for GPU and Infiniband drivers (Felix Kuehling, Jay Cornwall) - expose "ari_enabled" in sysfs to help NIC naming (Stuart Hayes) - clean up PCI DMA interface usage (Christoph Hellwig) - remove PCI pool API (replaced with DMA pool) (Romain Perier) - deprecate pci_get_bus_and_slot(), which assumed PCI domain 0 (Sinan Kaya) - move DT PCI code from drivers/of/ to drivers/pci/ (Rob Herring) - add PCI-specific wrappers for dev_info(), etc (Frederick Lawler) - remove warnings on sysfs mmap failure (Bjorn Helgaas) - quiet ROM validation messages (Alex Deucher) - remove redundant memory alloc failure messages (Markus Elfring) - fill in types for compile-time VGA and other I/O port resources (Bjorn Helgaas) - make "pci=pcie_scan_all" work for Root Ports as well as Downstream Ports to help AmigaOne X1000 (Bjorn Helgaas) - add SPDX tags to all PCI files (Bjorn Helgaas) - quirk Marvell 9128 DMA aliases (Alex Williamson) - quirk broken INTx disable on Ceton InfiniTV4 (Bjorn Helgaas) - fix CONFIG_PCI=n build by adding dummy pci_irqd_intx_xlate() (Niklas Cassel) - use DMA API to get MSI address for DesignWare IP (Niklas Cassel) - fix endpoint-mode DMA mask configuration (Kishon Vijay Abraham I) - fix ARTPEC-6 incorrect IS_ERR() usage (Wei Yongjun) - add support for ARTPEC-7 SoC (Niklas Cassel) - add endpoint-mode support for ARTPEC (Niklas Cassel) - add Cadence PCIe host and endpoint controller driver (Cyrille Pitchen) - handle multiple INTx status bits being set in dra7xx (Vignesh R) - translate dra7xx hwirq range to fix INTD handling (Vignesh R) - remove deprecated Exynos PHY initialization code (Jaehoon Chung) - fix MSI erratum workaround for HiSilicon Hip06/Hip07 (Dongdong Liu) - fix NULL pointer dereference in iProc BCMA driver (Ray Jui) - fix Keystone interrupt-controller-node lookup (Johan Hovold) - constify qcom driver structures (Julia Lawall) - rework Tegra config space mapping to increase space available for endpoints (Vidya Sagar) - simplify Tegra driver by using bus->sysdata (Manikanta Maddireddy) - remove PCI_REASSIGN_ALL_BUS usage on Tegra (Manikanta Maddireddy) - add support for Global Fabric Manager Server (GFMS) event to Microsemi Switchtec switch driver (Logan Gunthorpe) - add IDs for Switchtec PSX 24xG3 and PSX 48xG3 (Kelvin Cao) * tag 'pci-v4.16-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (140 commits) PCI: cadence: Add EndPoint Controller driver for Cadence PCIe controller dt-bindings: PCI: cadence: Add DT bindings for Cadence PCIe endpoint controller PCI: endpoint: Fix EPF device name to support multi-function devices PCI: endpoint: Add the function number as argument to EPC ops PCI: cadence: Add host driver for Cadence PCIe controller dt-bindings: PCI: cadence: Add DT bindings for Cadence PCIe host controller PCI: Add vendor ID for Cadence PCI: Add generic function to probe PCI host controllers PCI: generic: fix missing call of pci_free_resource_list() PCI: OF: Add generic function to parse and allocate PCI resources PCI: Regroup all PCI related entries into drivers/pci/Makefile PCI/DPC: Reformat DPC register definitions PCI/DPC: Add and use DPC Status register field definitions PCI/DPC: Squash dpc_rp_pio_get_info() into dpc_process_rp_pio_error() PCI/DPC: Remove unnecessary RP PIO register structs PCI/DPC: Push dpc->rp_pio_status assignment into dpc_rp_pio_get_info() PCI/DPC: Squash dpc_rp_pio_print_error() into dpc_rp_pio_get_info() PCI/DPC: Make RP PIO log size check more generic PCI/DPC: Rename local "status" to "dpc_status" PCI/DPC: Squash dpc_rp_pio_print_tlp_header() into dpc_rp_pio_print_error() ...
This commit is contained in:
commit
105cf3c8c6
248 changed files with 4503 additions and 3756 deletions
|
|
@ -1,3 +1,4 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# PCI configuration
|
||||
#
|
||||
|
|
@ -125,6 +126,7 @@ config PCI_PASID
|
|||
|
||||
config PCI_LABEL
|
||||
def_bool y if (DMI || ACPI)
|
||||
depends on PCI
|
||||
select NLS
|
||||
|
||||
config PCI_HYPERV
|
||||
|
|
@ -135,6 +137,7 @@ config PCI_HYPERV
|
|||
PCI devices from a PCI backend to support PCI driver domains.
|
||||
|
||||
source "drivers/pci/hotplug/Kconfig"
|
||||
source "drivers/pci/cadence/Kconfig"
|
||||
source "drivers/pci/dwc/Kconfig"
|
||||
source "drivers/pci/host/Kconfig"
|
||||
source "drivers/pci/endpoint/Kconfig"
|
||||
|
|
|
|||
|
|
@ -3,12 +3,15 @@
|
|||
# Makefile for the PCI bus specific drivers.
|
||||
#
|
||||
|
||||
obj-y += access.o bus.o probe.o host-bridge.o remove.o pci.o \
|
||||
obj-$(CONFIG_PCI) += access.o bus.o probe.o host-bridge.o remove.o pci.o \
|
||||
pci-driver.o search.o pci-sysfs.o rom.o setup-res.o \
|
||||
irq.o vpd.o setup-bus.o vc.o mmap.o setup-irq.o
|
||||
|
||||
ifdef CONFIG_PCI
|
||||
obj-$(CONFIG_PROC_FS) += proc.o
|
||||
obj-$(CONFIG_SYSFS) += slot.o
|
||||
obj-$(CONFIG_OF) += of.o
|
||||
endif
|
||||
|
||||
obj-$(CONFIG_PCI_QUIRKS) += quirks.o
|
||||
|
||||
|
|
@ -44,10 +47,15 @@ obj-$(CONFIG_PCI_ECAM) += ecam.o
|
|||
|
||||
obj-$(CONFIG_XEN_PCIDEV_FRONTEND) += xen-pcifront.o
|
||||
|
||||
obj-$(CONFIG_OF) += of.o
|
||||
|
||||
ccflags-$(CONFIG_PCI_DEBUG) := -DDEBUG
|
||||
|
||||
# PCI host controller drivers
|
||||
obj-y += host/
|
||||
obj-y += switch/
|
||||
|
||||
obj-$(CONFIG_PCI_ENDPOINT) += endpoint/
|
||||
|
||||
# Endpoint library must be initialized before its users
|
||||
obj-$(CONFIG_PCIE_CADENCE) += cadence/
|
||||
# pcie-hisi.o quirks are needed even without CONFIG_PCIE_DW
|
||||
obj-y += dwc/
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/delay.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/module.h>
|
||||
|
|
@ -333,8 +334,7 @@ static size_t pci_vpd_size(struct pci_dev *dev, size_t old_size)
|
|||
(tag == PCI_VPD_LTIN_RW_DATA)) {
|
||||
if (pci_read_vpd(dev, off+1, 2,
|
||||
&header[1]) != 2) {
|
||||
dev_warn(&dev->dev,
|
||||
"invalid large VPD tag %02x size at offset %zu",
|
||||
pci_warn(dev, "invalid large VPD tag %02x size at offset %zu",
|
||||
tag, off + 1);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -354,8 +354,7 @@ static size_t pci_vpd_size(struct pci_dev *dev, size_t old_size)
|
|||
if ((tag != PCI_VPD_LTIN_ID_STRING) &&
|
||||
(tag != PCI_VPD_LTIN_RO_DATA) &&
|
||||
(tag != PCI_VPD_LTIN_RW_DATA)) {
|
||||
dev_warn(&dev->dev,
|
||||
"invalid %s VPD tag %02x at offset %zu",
|
||||
pci_warn(dev, "invalid %s VPD tag %02x at offset %zu",
|
||||
(header[0] & PCI_VPD_LRDT) ? "large" : "short",
|
||||
tag, off);
|
||||
return 0;
|
||||
|
|
@ -402,7 +401,7 @@ static int pci_vpd_wait(struct pci_dev *dev)
|
|||
max_sleep *= 2;
|
||||
}
|
||||
|
||||
dev_warn(&dev->dev, "VPD access failed. This is likely a firmware bug on this device. Contact the card vendor for a firmware update\n");
|
||||
pci_warn(dev, "VPD access failed. This is likely a firmware bug on this device. Contact the card vendor for a firmware update\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* drivers/pci/ats.c
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* drivers/pci/bus.c
|
||||
*
|
||||
|
|
@ -289,7 +290,7 @@ bool pci_bus_clip_resource(struct pci_dev *dev, int idx)
|
|||
res->end = end;
|
||||
res->flags &= ~IORESOURCE_UNSET;
|
||||
orig_res.flags &= ~IORESOURCE_UNSET;
|
||||
dev_printk(KERN_DEBUG, &dev->dev, "%pR clipped to %pR\n",
|
||||
pci_printk(KERN_DEBUG, dev, "%pR clipped to %pR\n",
|
||||
&orig_res, res);
|
||||
|
||||
return true;
|
||||
|
|
@ -325,7 +326,7 @@ void pci_bus_add_device(struct pci_dev *dev)
|
|||
dev->match_driver = true;
|
||||
retval = device_attach(&dev->dev);
|
||||
if (retval < 0 && retval != -EPROBE_DEFER) {
|
||||
dev_warn(&dev->dev, "device attach failed (%d)\n", retval);
|
||||
pci_warn(dev, "device attach failed (%d)\n", retval);
|
||||
pci_proc_detach_device(dev);
|
||||
pci_remove_sysfs_dev_files(dev);
|
||||
return;
|
||||
|
|
|
|||
27
drivers/pci/cadence/Kconfig
Normal file
27
drivers/pci/cadence/Kconfig
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
menu "Cadence PCIe controllers support"
|
||||
|
||||
config PCIE_CADENCE
|
||||
bool
|
||||
|
||||
config PCIE_CADENCE_HOST
|
||||
bool "Cadence PCIe host controller"
|
||||
depends on OF
|
||||
depends on PCI
|
||||
select IRQ_DOMAIN
|
||||
select PCIE_CADENCE
|
||||
help
|
||||
Say Y here if you want to support the Cadence PCIe controller in host
|
||||
mode. This PCIe controller may be embedded into many different vendors
|
||||
SoCs.
|
||||
|
||||
config PCIE_CADENCE_EP
|
||||
bool "Cadence PCIe endpoint controller"
|
||||
depends on OF
|
||||
depends on PCI_ENDPOINT
|
||||
select PCIE_CADENCE
|
||||
help
|
||||
Say Y here if you want to support the Cadence PCIe controller in
|
||||
endpoint mode. This PCIe controller may be embedded into many
|
||||
different vendors SoCs.
|
||||
|
||||
endmenu
|
||||
4
drivers/pci/cadence/Makefile
Normal file
4
drivers/pci/cadence/Makefile
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
obj-$(CONFIG_PCIE_CADENCE) += pcie-cadence.o
|
||||
obj-$(CONFIG_PCIE_CADENCE_HOST) += pcie-cadence-host.o
|
||||
obj-$(CONFIG_PCIE_CADENCE_EP) += pcie-cadence-ep.o
|
||||
542
drivers/pci/cadence/pcie-cadence-ep.c
Normal file
542
drivers/pci/cadence/pcie-cadence-ep.c
Normal file
|
|
@ -0,0 +1,542 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2017 Cadence
|
||||
// Cadence PCIe endpoint controller driver.
|
||||
// Author: Cyrille Pitchen <[email protected]>
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/pci-epc.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/sizes.h>
|
||||
|
||||
#include "pcie-cadence.h"
|
||||
|
||||
#define CDNS_PCIE_EP_MIN_APERTURE 128 /* 128 bytes */
|
||||
#define CDNS_PCIE_EP_IRQ_PCI_ADDR_NONE 0x1
|
||||
#define CDNS_PCIE_EP_IRQ_PCI_ADDR_LEGACY 0x3
|
||||
|
||||
/**
|
||||
* struct cdns_pcie_ep - private data for this PCIe endpoint controller driver
|
||||
* @pcie: Cadence PCIe controller
|
||||
* @max_regions: maximum number of regions supported by hardware
|
||||
* @ob_region_map: bitmask of mapped outbound regions
|
||||
* @ob_addr: base addresses in the AXI bus where the outbound regions start
|
||||
* @irq_phys_addr: base address on the AXI bus where the MSI/legacy IRQ
|
||||
* dedicated outbound regions is mapped.
|
||||
* @irq_cpu_addr: base address in the CPU space where a write access triggers
|
||||
* the sending of a memory write (MSI) / normal message (legacy
|
||||
* IRQ) TLP through the PCIe bus.
|
||||
* @irq_pci_addr: used to save the current mapping of the MSI/legacy IRQ
|
||||
* dedicated outbound region.
|
||||
* @irq_pci_fn: the latest PCI function that has updated the mapping of
|
||||
* the MSI/legacy IRQ dedicated outbound region.
|
||||
* @irq_pending: bitmask of asserted legacy IRQs.
|
||||
*/
|
||||
struct cdns_pcie_ep {
|
||||
struct cdns_pcie pcie;
|
||||
u32 max_regions;
|
||||
unsigned long ob_region_map;
|
||||
phys_addr_t *ob_addr;
|
||||
phys_addr_t irq_phys_addr;
|
||||
void __iomem *irq_cpu_addr;
|
||||
u64 irq_pci_addr;
|
||||
u8 irq_pci_fn;
|
||||
u8 irq_pending;
|
||||
};
|
||||
|
||||
static int cdns_pcie_ep_write_header(struct pci_epc *epc, u8 fn,
|
||||
struct pci_epf_header *hdr)
|
||||
{
|
||||
struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
struct cdns_pcie *pcie = &ep->pcie;
|
||||
|
||||
cdns_pcie_ep_fn_writew(pcie, fn, PCI_DEVICE_ID, hdr->deviceid);
|
||||
cdns_pcie_ep_fn_writeb(pcie, fn, PCI_REVISION_ID, hdr->revid);
|
||||
cdns_pcie_ep_fn_writeb(pcie, fn, PCI_CLASS_PROG, hdr->progif_code);
|
||||
cdns_pcie_ep_fn_writew(pcie, fn, PCI_CLASS_DEVICE,
|
||||
hdr->subclass_code | hdr->baseclass_code << 8);
|
||||
cdns_pcie_ep_fn_writeb(pcie, fn, PCI_CACHE_LINE_SIZE,
|
||||
hdr->cache_line_size);
|
||||
cdns_pcie_ep_fn_writew(pcie, fn, PCI_SUBSYSTEM_ID, hdr->subsys_id);
|
||||
cdns_pcie_ep_fn_writeb(pcie, fn, PCI_INTERRUPT_PIN, hdr->interrupt_pin);
|
||||
|
||||
/*
|
||||
* Vendor ID can only be modified from function 0, all other functions
|
||||
* use the same vendor ID as function 0.
|
||||
*/
|
||||
if (fn == 0) {
|
||||
/* Update the vendor IDs. */
|
||||
u32 id = CDNS_PCIE_LM_ID_VENDOR(hdr->vendorid) |
|
||||
CDNS_PCIE_LM_ID_SUBSYS(hdr->subsys_vendor_id);
|
||||
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_LM_ID, id);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdns_pcie_ep_set_bar(struct pci_epc *epc, u8 fn, enum pci_barno bar,
|
||||
dma_addr_t bar_phys, size_t size, int flags)
|
||||
{
|
||||
struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
struct cdns_pcie *pcie = &ep->pcie;
|
||||
u32 addr0, addr1, reg, cfg, b, aperture, ctrl;
|
||||
u64 sz;
|
||||
|
||||
/* BAR size is 2^(aperture + 7) */
|
||||
sz = max_t(size_t, size, CDNS_PCIE_EP_MIN_APERTURE);
|
||||
/*
|
||||
* roundup_pow_of_two() returns an unsigned long, which is not suited
|
||||
* for 64bit values.
|
||||
*/
|
||||
sz = 1ULL << fls64(sz - 1);
|
||||
aperture = ilog2(sz) - 7; /* 128B -> 0, 256B -> 1, 512B -> 2, ... */
|
||||
|
||||
if ((flags & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {
|
||||
ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_IO_32BITS;
|
||||
} else {
|
||||
bool is_prefetch = !!(flags & PCI_BASE_ADDRESS_MEM_PREFETCH);
|
||||
bool is_64bits = sz > SZ_2G;
|
||||
|
||||
if (is_64bits && (bar & 1))
|
||||
return -EINVAL;
|
||||
|
||||
if (is_64bits && is_prefetch)
|
||||
ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS;
|
||||
else if (is_prefetch)
|
||||
ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS;
|
||||
else if (is_64bits)
|
||||
ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_64BITS;
|
||||
else
|
||||
ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_32BITS;
|
||||
}
|
||||
|
||||
addr0 = lower_32_bits(bar_phys);
|
||||
addr1 = upper_32_bits(bar_phys);
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar),
|
||||
addr0);
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar),
|
||||
addr1);
|
||||
|
||||
if (bar < BAR_4) {
|
||||
reg = CDNS_PCIE_LM_EP_FUNC_BAR_CFG0(fn);
|
||||
b = bar;
|
||||
} else {
|
||||
reg = CDNS_PCIE_LM_EP_FUNC_BAR_CFG1(fn);
|
||||
b = bar - BAR_4;
|
||||
}
|
||||
|
||||
cfg = cdns_pcie_readl(pcie, reg);
|
||||
cfg &= ~(CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b) |
|
||||
CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b));
|
||||
cfg |= (CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE(b, aperture) |
|
||||
CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, ctrl));
|
||||
cdns_pcie_writel(pcie, reg, cfg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cdns_pcie_ep_clear_bar(struct pci_epc *epc, u8 fn,
|
||||
enum pci_barno bar)
|
||||
{
|
||||
struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
struct cdns_pcie *pcie = &ep->pcie;
|
||||
u32 reg, cfg, b, ctrl;
|
||||
|
||||
if (bar < BAR_4) {
|
||||
reg = CDNS_PCIE_LM_EP_FUNC_BAR_CFG0(fn);
|
||||
b = bar;
|
||||
} else {
|
||||
reg = CDNS_PCIE_LM_EP_FUNC_BAR_CFG1(fn);
|
||||
b = bar - BAR_4;
|
||||
}
|
||||
|
||||
ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED;
|
||||
cfg = cdns_pcie_readl(pcie, reg);
|
||||
cfg &= ~(CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b) |
|
||||
CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b));
|
||||
cfg |= CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, ctrl);
|
||||
cdns_pcie_writel(pcie, reg, cfg);
|
||||
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar), 0);
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar), 0);
|
||||
}
|
||||
|
||||
static int cdns_pcie_ep_map_addr(struct pci_epc *epc, u8 fn, phys_addr_t addr,
|
||||
u64 pci_addr, size_t size)
|
||||
{
|
||||
struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
struct cdns_pcie *pcie = &ep->pcie;
|
||||
u32 r;
|
||||
|
||||
r = find_first_zero_bit(&ep->ob_region_map,
|
||||
sizeof(ep->ob_region_map) * BITS_PER_LONG);
|
||||
if (r >= ep->max_regions - 1) {
|
||||
dev_err(&epc->dev, "no free outbound region\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cdns_pcie_set_outbound_region(pcie, fn, r, false, addr, pci_addr, size);
|
||||
|
||||
set_bit(r, &ep->ob_region_map);
|
||||
ep->ob_addr[r] = addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void cdns_pcie_ep_unmap_addr(struct pci_epc *epc, u8 fn,
|
||||
phys_addr_t addr)
|
||||
{
|
||||
struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
struct cdns_pcie *pcie = &ep->pcie;
|
||||
u32 r;
|
||||
|
||||
for (r = 0; r < ep->max_regions - 1; r++)
|
||||
if (ep->ob_addr[r] == addr)
|
||||
break;
|
||||
|
||||
if (r == ep->max_regions - 1)
|
||||
return;
|
||||
|
||||
cdns_pcie_reset_outbound_region(pcie, r);
|
||||
|
||||
ep->ob_addr[r] = 0;
|
||||
clear_bit(r, &ep->ob_region_map);
|
||||
}
|
||||
|
||||
static int cdns_pcie_ep_set_msi(struct pci_epc *epc, u8 fn, u8 mmc)
|
||||
{
|
||||
struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
struct cdns_pcie *pcie = &ep->pcie;
|
||||
u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET;
|
||||
u16 flags;
|
||||
|
||||
/*
|
||||
* Set the Multiple Message Capable bitfield into the Message Control
|
||||
* register.
|
||||
*/
|
||||
flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_FLAGS);
|
||||
flags = (flags & ~PCI_MSI_FLAGS_QMASK) | (mmc << 1);
|
||||
flags |= PCI_MSI_FLAGS_64BIT;
|
||||
flags &= ~PCI_MSI_FLAGS_MASKBIT;
|
||||
cdns_pcie_ep_fn_writew(pcie, fn, cap + PCI_MSI_FLAGS, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdns_pcie_ep_get_msi(struct pci_epc *epc, u8 fn)
|
||||
{
|
||||
struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
struct cdns_pcie *pcie = &ep->pcie;
|
||||
u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET;
|
||||
u16 flags, mmc, mme;
|
||||
|
||||
/* Validate that the MSI feature is actually enabled. */
|
||||
flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_FLAGS);
|
||||
if (!(flags & PCI_MSI_FLAGS_ENABLE))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Get the Multiple Message Enable bitfield from the Message Control
|
||||
* register.
|
||||
*/
|
||||
mmc = (flags & PCI_MSI_FLAGS_QMASK) >> 1;
|
||||
mme = (flags & PCI_MSI_FLAGS_QSIZE) >> 4;
|
||||
|
||||
return mme;
|
||||
}
|
||||
|
||||
static void cdns_pcie_ep_assert_intx(struct cdns_pcie_ep *ep, u8 fn,
|
||||
u8 intx, bool is_asserted)
|
||||
{
|
||||
struct cdns_pcie *pcie = &ep->pcie;
|
||||
u32 r = ep->max_regions - 1;
|
||||
u32 offset;
|
||||
u16 status;
|
||||
u8 msg_code;
|
||||
|
||||
intx &= 3;
|
||||
|
||||
/* Set the outbound region if needed. */
|
||||
if (unlikely(ep->irq_pci_addr != CDNS_PCIE_EP_IRQ_PCI_ADDR_LEGACY ||
|
||||
ep->irq_pci_fn != fn)) {
|
||||
/* Last region was reserved for IRQ writes. */
|
||||
cdns_pcie_set_outbound_region_for_normal_msg(pcie, fn, r,
|
||||
ep->irq_phys_addr);
|
||||
ep->irq_pci_addr = CDNS_PCIE_EP_IRQ_PCI_ADDR_LEGACY;
|
||||
ep->irq_pci_fn = fn;
|
||||
}
|
||||
|
||||
if (is_asserted) {
|
||||
ep->irq_pending |= BIT(intx);
|
||||
msg_code = MSG_CODE_ASSERT_INTA + intx;
|
||||
} else {
|
||||
ep->irq_pending &= ~BIT(intx);
|
||||
msg_code = MSG_CODE_DEASSERT_INTA + intx;
|
||||
}
|
||||
|
||||
status = cdns_pcie_ep_fn_readw(pcie, fn, PCI_STATUS);
|
||||
if (((status & PCI_STATUS_INTERRUPT) != 0) ^ (ep->irq_pending != 0)) {
|
||||
status ^= PCI_STATUS_INTERRUPT;
|
||||
cdns_pcie_ep_fn_writew(pcie, fn, PCI_STATUS, status);
|
||||
}
|
||||
|
||||
offset = CDNS_PCIE_NORMAL_MSG_ROUTING(MSG_ROUTING_LOCAL) |
|
||||
CDNS_PCIE_NORMAL_MSG_CODE(msg_code) |
|
||||
CDNS_PCIE_MSG_NO_DATA;
|
||||
writel(0, ep->irq_cpu_addr + offset);
|
||||
}
|
||||
|
||||
static int cdns_pcie_ep_send_legacy_irq(struct cdns_pcie_ep *ep, u8 fn, u8 intx)
|
||||
{
|
||||
u16 cmd;
|
||||
|
||||
cmd = cdns_pcie_ep_fn_readw(&ep->pcie, fn, PCI_COMMAND);
|
||||
if (cmd & PCI_COMMAND_INTX_DISABLE)
|
||||
return -EINVAL;
|
||||
|
||||
cdns_pcie_ep_assert_intx(ep, fn, intx, true);
|
||||
/*
|
||||
* The mdelay() value was taken from dra7xx_pcie_raise_legacy_irq()
|
||||
* from drivers/pci/dwc/pci-dra7xx.c
|
||||
*/
|
||||
mdelay(1);
|
||||
cdns_pcie_ep_assert_intx(ep, fn, intx, false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdns_pcie_ep_send_msi_irq(struct cdns_pcie_ep *ep, u8 fn,
|
||||
u8 interrupt_num)
|
||||
{
|
||||
struct cdns_pcie *pcie = &ep->pcie;
|
||||
u32 cap = CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET;
|
||||
u16 flags, mme, data, data_mask;
|
||||
u8 msi_count;
|
||||
u64 pci_addr, pci_addr_mask = 0xff;
|
||||
|
||||
/* Check whether the MSI feature has been enabled by the PCI host. */
|
||||
flags = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_FLAGS);
|
||||
if (!(flags & PCI_MSI_FLAGS_ENABLE))
|
||||
return -EINVAL;
|
||||
|
||||
/* Get the number of enabled MSIs */
|
||||
mme = (flags & PCI_MSI_FLAGS_QSIZE) >> 4;
|
||||
msi_count = 1 << mme;
|
||||
if (!interrupt_num || interrupt_num > msi_count)
|
||||
return -EINVAL;
|
||||
|
||||
/* Compute the data value to be written. */
|
||||
data_mask = msi_count - 1;
|
||||
data = cdns_pcie_ep_fn_readw(pcie, fn, cap + PCI_MSI_DATA_64);
|
||||
data = (data & ~data_mask) | ((interrupt_num - 1) & data_mask);
|
||||
|
||||
/* Get the PCI address where to write the data into. */
|
||||
pci_addr = cdns_pcie_ep_fn_readl(pcie, fn, cap + PCI_MSI_ADDRESS_HI);
|
||||
pci_addr <<= 32;
|
||||
pci_addr |= cdns_pcie_ep_fn_readl(pcie, fn, cap + PCI_MSI_ADDRESS_LO);
|
||||
pci_addr &= GENMASK_ULL(63, 2);
|
||||
|
||||
/* Set the outbound region if needed. */
|
||||
if (unlikely(ep->irq_pci_addr != (pci_addr & ~pci_addr_mask) ||
|
||||
ep->irq_pci_fn != fn)) {
|
||||
/* Last region was reserved for IRQ writes. */
|
||||
cdns_pcie_set_outbound_region(pcie, fn, ep->max_regions - 1,
|
||||
false,
|
||||
ep->irq_phys_addr,
|
||||
pci_addr & ~pci_addr_mask,
|
||||
pci_addr_mask + 1);
|
||||
ep->irq_pci_addr = (pci_addr & ~pci_addr_mask);
|
||||
ep->irq_pci_fn = fn;
|
||||
}
|
||||
writew(data, ep->irq_cpu_addr + (pci_addr & pci_addr_mask));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdns_pcie_ep_raise_irq(struct pci_epc *epc, u8 fn,
|
||||
enum pci_epc_irq_type type, u8 interrupt_num)
|
||||
{
|
||||
struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
|
||||
switch (type) {
|
||||
case PCI_EPC_IRQ_LEGACY:
|
||||
return cdns_pcie_ep_send_legacy_irq(ep, fn, 0);
|
||||
|
||||
case PCI_EPC_IRQ_MSI:
|
||||
return cdns_pcie_ep_send_msi_irq(ep, fn, interrupt_num);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int cdns_pcie_ep_start(struct pci_epc *epc)
|
||||
{
|
||||
struct cdns_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
struct cdns_pcie *pcie = &ep->pcie;
|
||||
struct pci_epf *epf;
|
||||
u32 cfg;
|
||||
|
||||
/*
|
||||
* BIT(0) is hardwired to 1, hence function 0 is always enabled
|
||||
* and can't be disabled anyway.
|
||||
*/
|
||||
cfg = BIT(0);
|
||||
list_for_each_entry(epf, &epc->pci_epf, list)
|
||||
cfg |= BIT(epf->func_no);
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_LM_EP_FUNC_CFG, cfg);
|
||||
|
||||
/*
|
||||
* The PCIe links are automatically established by the controller
|
||||
* once for all at powerup: the software can neither start nor stop
|
||||
* those links later at runtime.
|
||||
*
|
||||
* Then we only have to notify the EP core that our links are already
|
||||
* established. However we don't call directly pci_epc_linkup() because
|
||||
* we've already locked the epc->lock.
|
||||
*/
|
||||
list_for_each_entry(epf, &epc->pci_epf, list)
|
||||
pci_epf_linkup(epf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct pci_epc_ops cdns_pcie_epc_ops = {
|
||||
.write_header = cdns_pcie_ep_write_header,
|
||||
.set_bar = cdns_pcie_ep_set_bar,
|
||||
.clear_bar = cdns_pcie_ep_clear_bar,
|
||||
.map_addr = cdns_pcie_ep_map_addr,
|
||||
.unmap_addr = cdns_pcie_ep_unmap_addr,
|
||||
.set_msi = cdns_pcie_ep_set_msi,
|
||||
.get_msi = cdns_pcie_ep_get_msi,
|
||||
.raise_irq = cdns_pcie_ep_raise_irq,
|
||||
.start = cdns_pcie_ep_start,
|
||||
};
|
||||
|
||||
static const struct of_device_id cdns_pcie_ep_of_match[] = {
|
||||
{ .compatible = "cdns,cdns-pcie-ep" },
|
||||
|
||||
{ },
|
||||
};
|
||||
|
||||
static int cdns_pcie_ep_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct cdns_pcie_ep *ep;
|
||||
struct cdns_pcie *pcie;
|
||||
struct pci_epc *epc;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
ep = devm_kzalloc(dev, sizeof(*ep), GFP_KERNEL);
|
||||
if (!ep)
|
||||
return -ENOMEM;
|
||||
|
||||
pcie = &ep->pcie;
|
||||
pcie->is_rc = false;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg");
|
||||
pcie->reg_base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(pcie->reg_base)) {
|
||||
dev_err(dev, "missing \"reg\"\n");
|
||||
return PTR_ERR(pcie->reg_base);
|
||||
}
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem");
|
||||
if (!res) {
|
||||
dev_err(dev, "missing \"mem\"\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
pcie->mem_res = res;
|
||||
|
||||
ret = of_property_read_u32(np, "cdns,max-outbound-regions",
|
||||
&ep->max_regions);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "missing \"cdns,max-outbound-regions\"\n");
|
||||
return ret;
|
||||
}
|
||||
ep->ob_addr = devm_kzalloc(dev, ep->max_regions * sizeof(*ep->ob_addr),
|
||||
GFP_KERNEL);
|
||||
if (!ep->ob_addr)
|
||||
return -ENOMEM;
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "pm_runtime_get_sync() failed\n");
|
||||
goto err_get_sync;
|
||||
}
|
||||
|
||||
/* Disable all but function 0 (anyway BIT(0) is hardwired to 1). */
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_LM_EP_FUNC_CFG, BIT(0));
|
||||
|
||||
epc = devm_pci_epc_create(dev, &cdns_pcie_epc_ops);
|
||||
if (IS_ERR(epc)) {
|
||||
dev_err(dev, "failed to create epc device\n");
|
||||
ret = PTR_ERR(epc);
|
||||
goto err_init;
|
||||
}
|
||||
|
||||
epc_set_drvdata(epc, ep);
|
||||
|
||||
if (of_property_read_u8(np, "max-functions", &epc->max_functions) < 0)
|
||||
epc->max_functions = 1;
|
||||
|
||||
ret = pci_epc_mem_init(epc, pcie->mem_res->start,
|
||||
resource_size(pcie->mem_res));
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to initialize the memory space\n");
|
||||
goto err_init;
|
||||
}
|
||||
|
||||
ep->irq_cpu_addr = pci_epc_mem_alloc_addr(epc, &ep->irq_phys_addr,
|
||||
SZ_128K);
|
||||
if (!ep->irq_cpu_addr) {
|
||||
dev_err(dev, "failed to reserve memory space for MSI\n");
|
||||
ret = -ENOMEM;
|
||||
goto free_epc_mem;
|
||||
}
|
||||
ep->irq_pci_addr = CDNS_PCIE_EP_IRQ_PCI_ADDR_NONE;
|
||||
|
||||
return 0;
|
||||
|
||||
free_epc_mem:
|
||||
pci_epc_mem_exit(epc);
|
||||
|
||||
err_init:
|
||||
pm_runtime_put_sync(dev);
|
||||
|
||||
err_get_sync:
|
||||
pm_runtime_disable(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void cdns_pcie_ep_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
int ret;
|
||||
|
||||
ret = pm_runtime_put_sync(dev);
|
||||
if (ret < 0)
|
||||
dev_dbg(dev, "pm_runtime_put_sync failed\n");
|
||||
|
||||
pm_runtime_disable(dev);
|
||||
|
||||
/* The PCIe controller can't be disabled. */
|
||||
}
|
||||
|
||||
static struct platform_driver cdns_pcie_ep_driver = {
|
||||
.driver = {
|
||||
.name = "cdns-pcie-ep",
|
||||
.of_match_table = cdns_pcie_ep_of_match,
|
||||
},
|
||||
.probe = cdns_pcie_ep_probe,
|
||||
.shutdown = cdns_pcie_ep_shutdown,
|
||||
};
|
||||
builtin_platform_driver(cdns_pcie_ep_driver);
|
||||
336
drivers/pci/cadence/pcie-cadence-host.c
Normal file
336
drivers/pci/cadence/pcie-cadence-host.c
Normal file
|
|
@ -0,0 +1,336 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2017 Cadence
|
||||
// Cadence PCIe host controller driver.
|
||||
// Author: Cyrille Pitchen <[email protected]>
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
|
||||
#include "pcie-cadence.h"
|
||||
|
||||
/**
|
||||
* struct cdns_pcie_rc - private data for this PCIe Root Complex driver
|
||||
* @pcie: Cadence PCIe controller
|
||||
* @dev: pointer to PCIe device
|
||||
* @cfg_res: start/end offsets in the physical system memory to map PCI
|
||||
* configuration space accesses
|
||||
* @bus_range: first/last buses behind the PCIe host controller
|
||||
* @cfg_base: IO mapped window to access the PCI configuration space of a
|
||||
* single function at a time
|
||||
* @max_regions: maximum number of regions supported by the hardware
|
||||
* @no_bar_nbits: Number of bits to keep for inbound (PCIe -> CPU) address
|
||||
* translation (nbits sets into the "no BAR match" register)
|
||||
* @vendor_id: PCI vendor ID
|
||||
* @device_id: PCI device ID
|
||||
*/
|
||||
struct cdns_pcie_rc {
|
||||
struct cdns_pcie pcie;
|
||||
struct device *dev;
|
||||
struct resource *cfg_res;
|
||||
struct resource *bus_range;
|
||||
void __iomem *cfg_base;
|
||||
u32 max_regions;
|
||||
u32 no_bar_nbits;
|
||||
u16 vendor_id;
|
||||
u16 device_id;
|
||||
};
|
||||
|
||||
static void __iomem *cdns_pci_map_bus(struct pci_bus *bus, unsigned int devfn,
|
||||
int where)
|
||||
{
|
||||
struct pci_host_bridge *bridge = pci_find_host_bridge(bus);
|
||||
struct cdns_pcie_rc *rc = pci_host_bridge_priv(bridge);
|
||||
struct cdns_pcie *pcie = &rc->pcie;
|
||||
unsigned int busn = bus->number;
|
||||
u32 addr0, desc0;
|
||||
|
||||
if (busn == rc->bus_range->start) {
|
||||
/*
|
||||
* Only the root port (devfn == 0) is connected to this bus.
|
||||
* All other PCI devices are behind some bridge hence on another
|
||||
* bus.
|
||||
*/
|
||||
if (devfn)
|
||||
return NULL;
|
||||
|
||||
return pcie->reg_base + (where & 0xfff);
|
||||
}
|
||||
|
||||
/* Update Output registers for AXI region 0. */
|
||||
addr0 = CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(12) |
|
||||
CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) |
|
||||
CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(busn);
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(0), addr0);
|
||||
|
||||
/* Configuration Type 0 or Type 1 access. */
|
||||
desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID |
|
||||
CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(0);
|
||||
/*
|
||||
* The bus number was already set once for all in desc1 by
|
||||
* cdns_pcie_host_init_address_translation().
|
||||
*/
|
||||
if (busn == rc->bus_range->start + 1)
|
||||
desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0;
|
||||
else
|
||||
desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1;
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(0), desc0);
|
||||
|
||||
return rc->cfg_base + (where & 0xfff);
|
||||
}
|
||||
|
||||
static struct pci_ops cdns_pcie_host_ops = {
|
||||
.map_bus = cdns_pci_map_bus,
|
||||
.read = pci_generic_config_read,
|
||||
.write = pci_generic_config_write,
|
||||
};
|
||||
|
||||
static const struct of_device_id cdns_pcie_host_of_match[] = {
|
||||
{ .compatible = "cdns,cdns-pcie-host" },
|
||||
|
||||
{ },
|
||||
};
|
||||
|
||||
static int cdns_pcie_host_init_root_port(struct cdns_pcie_rc *rc)
|
||||
{
|
||||
struct cdns_pcie *pcie = &rc->pcie;
|
||||
u32 value, ctrl;
|
||||
|
||||
/*
|
||||
* Set the root complex BAR configuration register:
|
||||
* - disable both BAR0 and BAR1.
|
||||
* - enable Prefetchable Memory Base and Limit registers in type 1
|
||||
* config space (64 bits).
|
||||
* - enable IO Base and Limit registers in type 1 config
|
||||
* space (32 bits).
|
||||
*/
|
||||
ctrl = CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED;
|
||||
value = CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(ctrl) |
|
||||
CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(ctrl) |
|
||||
CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE |
|
||||
CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS |
|
||||
CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE |
|
||||
CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS;
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_LM_RC_BAR_CFG, value);
|
||||
|
||||
/* Set root port configuration space */
|
||||
if (rc->vendor_id != 0xffff)
|
||||
cdns_pcie_rp_writew(pcie, PCI_VENDOR_ID, rc->vendor_id);
|
||||
if (rc->device_id != 0xffff)
|
||||
cdns_pcie_rp_writew(pcie, PCI_DEVICE_ID, rc->device_id);
|
||||
|
||||
cdns_pcie_rp_writeb(pcie, PCI_CLASS_REVISION, 0);
|
||||
cdns_pcie_rp_writeb(pcie, PCI_CLASS_PROG, 0);
|
||||
cdns_pcie_rp_writew(pcie, PCI_CLASS_DEVICE, PCI_CLASS_BRIDGE_PCI);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdns_pcie_host_init_address_translation(struct cdns_pcie_rc *rc)
|
||||
{
|
||||
struct cdns_pcie *pcie = &rc->pcie;
|
||||
struct resource *cfg_res = rc->cfg_res;
|
||||
struct resource *mem_res = pcie->mem_res;
|
||||
struct resource *bus_range = rc->bus_range;
|
||||
struct device *dev = rc->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct of_pci_range_parser parser;
|
||||
struct of_pci_range range;
|
||||
u32 addr0, addr1, desc1;
|
||||
u64 cpu_addr;
|
||||
int r, err;
|
||||
|
||||
/*
|
||||
* Reserve region 0 for PCI configure space accesses:
|
||||
* OB_REGION_PCI_ADDR0 and OB_REGION_DESC0 are updated dynamically by
|
||||
* cdns_pci_map_bus(), other region registers are set here once for all.
|
||||
*/
|
||||
addr1 = 0; /* Should be programmed to zero. */
|
||||
desc1 = CDNS_PCIE_AT_OB_REGION_DESC1_BUS(bus_range->start);
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(0), addr1);
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(0), desc1);
|
||||
|
||||
cpu_addr = cfg_res->start - mem_res->start;
|
||||
addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(12) |
|
||||
(lower_32_bits(cpu_addr) & GENMASK(31, 8));
|
||||
addr1 = upper_32_bits(cpu_addr);
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(0), addr0);
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(0), addr1);
|
||||
|
||||
err = of_pci_range_parser_init(&parser, np);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
r = 1;
|
||||
for_each_of_pci_range(&parser, &range) {
|
||||
bool is_io;
|
||||
|
||||
if (r >= rc->max_regions)
|
||||
break;
|
||||
|
||||
if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_MEM)
|
||||
is_io = false;
|
||||
else if ((range.flags & IORESOURCE_TYPE_BITS) == IORESOURCE_IO)
|
||||
is_io = true;
|
||||
else
|
||||
continue;
|
||||
|
||||
cdns_pcie_set_outbound_region(pcie, 0, r, is_io,
|
||||
range.cpu_addr,
|
||||
range.pci_addr,
|
||||
range.size);
|
||||
r++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set Root Port no BAR match Inbound Translation registers:
|
||||
* needed for MSI and DMA.
|
||||
* Root Port BAR0 and BAR1 are disabled, hence no need to set their
|
||||
* inbound translation registers.
|
||||
*/
|
||||
addr0 = CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(rc->no_bar_nbits);
|
||||
addr1 = 0;
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR0(RP_NO_BAR), addr0);
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_AT_IB_RP_BAR_ADDR1(RP_NO_BAR), addr1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cdns_pcie_host_init(struct device *dev,
|
||||
struct list_head *resources,
|
||||
struct cdns_pcie_rc *rc)
|
||||
{
|
||||
struct resource *bus_range = NULL;
|
||||
int err;
|
||||
|
||||
/* Parse our PCI ranges and request their resources */
|
||||
err = pci_parse_request_of_pci_ranges(dev, resources, &bus_range);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
rc->bus_range = bus_range;
|
||||
rc->pcie.bus = bus_range->start;
|
||||
|
||||
err = cdns_pcie_host_init_root_port(rc);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
err = cdns_pcie_host_init_address_translation(rc);
|
||||
if (err)
|
||||
goto err_out;
|
||||
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
pci_free_resource_list(resources);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int cdns_pcie_host_probe(struct platform_device *pdev)
|
||||
{
|
||||
const char *type;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct pci_host_bridge *bridge;
|
||||
struct list_head resources;
|
||||
struct cdns_pcie_rc *rc;
|
||||
struct cdns_pcie *pcie;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
bridge = devm_pci_alloc_host_bridge(dev, sizeof(*rc));
|
||||
if (!bridge)
|
||||
return -ENOMEM;
|
||||
|
||||
rc = pci_host_bridge_priv(bridge);
|
||||
rc->dev = dev;
|
||||
|
||||
pcie = &rc->pcie;
|
||||
pcie->is_rc = true;
|
||||
|
||||
rc->max_regions = 32;
|
||||
of_property_read_u32(np, "cdns,max-outbound-regions", &rc->max_regions);
|
||||
|
||||
rc->no_bar_nbits = 32;
|
||||
of_property_read_u32(np, "cdns,no-bar-match-nbits", &rc->no_bar_nbits);
|
||||
|
||||
rc->vendor_id = 0xffff;
|
||||
of_property_read_u16(np, "vendor-id", &rc->vendor_id);
|
||||
|
||||
rc->device_id = 0xffff;
|
||||
of_property_read_u16(np, "device-id", &rc->device_id);
|
||||
|
||||
type = of_get_property(np, "device_type", NULL);
|
||||
if (!type || strcmp(type, "pci")) {
|
||||
dev_err(dev, "invalid \"device_type\" %s\n", type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg");
|
||||
pcie->reg_base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(pcie->reg_base)) {
|
||||
dev_err(dev, "missing \"reg\"\n");
|
||||
return PTR_ERR(pcie->reg_base);
|
||||
}
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "cfg");
|
||||
rc->cfg_base = devm_pci_remap_cfg_resource(dev, res);
|
||||
if (IS_ERR(rc->cfg_base)) {
|
||||
dev_err(dev, "missing \"cfg\"\n");
|
||||
return PTR_ERR(rc->cfg_base);
|
||||
}
|
||||
rc->cfg_res = res;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem");
|
||||
if (!res) {
|
||||
dev_err(dev, "missing \"mem\"\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
pcie->mem_res = res;
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "pm_runtime_get_sync() failed\n");
|
||||
goto err_get_sync;
|
||||
}
|
||||
|
||||
ret = cdns_pcie_host_init(dev, &resources, rc);
|
||||
if (ret)
|
||||
goto err_init;
|
||||
|
||||
list_splice_init(&resources, &bridge->windows);
|
||||
bridge->dev.parent = dev;
|
||||
bridge->busnr = pcie->bus;
|
||||
bridge->ops = &cdns_pcie_host_ops;
|
||||
bridge->map_irq = of_irq_parse_and_map_pci;
|
||||
bridge->swizzle_irq = pci_common_swizzle;
|
||||
|
||||
ret = pci_host_probe(bridge);
|
||||
if (ret < 0)
|
||||
goto err_host_probe;
|
||||
|
||||
return 0;
|
||||
|
||||
err_host_probe:
|
||||
pci_free_resource_list(&resources);
|
||||
|
||||
err_init:
|
||||
pm_runtime_put_sync(dev);
|
||||
|
||||
err_get_sync:
|
||||
pm_runtime_disable(dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct platform_driver cdns_pcie_host_driver = {
|
||||
.driver = {
|
||||
.name = "cdns-pcie-host",
|
||||
.of_match_table = cdns_pcie_host_of_match,
|
||||
},
|
||||
.probe = cdns_pcie_host_probe,
|
||||
};
|
||||
builtin_platform_driver(cdns_pcie_host_driver);
|
||||
126
drivers/pci/cadence/pcie-cadence.c
Normal file
126
drivers/pci/cadence/pcie-cadence.c
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2017 Cadence
|
||||
// Cadence PCIe controller driver.
|
||||
// Author: Cyrille Pitchen <[email protected]>
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#include "pcie-cadence.h"
|
||||
|
||||
void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u8 fn,
|
||||
u32 r, bool is_io,
|
||||
u64 cpu_addr, u64 pci_addr, size_t size)
|
||||
{
|
||||
/*
|
||||
* roundup_pow_of_two() returns an unsigned long, which is not suited
|
||||
* for 64bit values.
|
||||
*/
|
||||
u64 sz = 1ULL << fls64(size - 1);
|
||||
int nbits = ilog2(sz);
|
||||
u32 addr0, addr1, desc0, desc1;
|
||||
|
||||
if (nbits < 8)
|
||||
nbits = 8;
|
||||
|
||||
/* Set the PCI address */
|
||||
addr0 = CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(nbits) |
|
||||
(lower_32_bits(pci_addr) & GENMASK(31, 8));
|
||||
addr1 = upper_32_bits(pci_addr);
|
||||
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r), addr0);
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r), addr1);
|
||||
|
||||
/* Set the PCIe header descriptor */
|
||||
if (is_io)
|
||||
desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_IO;
|
||||
else
|
||||
desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MEM;
|
||||
desc1 = 0;
|
||||
|
||||
/*
|
||||
* Whatever Bit [23] is set or not inside DESC0 register of the outbound
|
||||
* PCIe descriptor, the PCI function number must be set into
|
||||
* Bits [26:24] of DESC0 anyway.
|
||||
*
|
||||
* In Root Complex mode, the function number is always 0 but in Endpoint
|
||||
* mode, the PCIe controller may support more than one function. This
|
||||
* function number needs to be set properly into the outbound PCIe
|
||||
* descriptor.
|
||||
*
|
||||
* Besides, setting Bit [23] is mandatory when in Root Complex mode:
|
||||
* then the driver must provide the bus, resp. device, number in
|
||||
* Bits [7:0] of DESC1, resp. Bits[31:27] of DESC0. Like the function
|
||||
* number, the device number is always 0 in Root Complex mode.
|
||||
*
|
||||
* However when in Endpoint mode, we can clear Bit [23] of DESC0, hence
|
||||
* the PCIe controller will use the captured values for the bus and
|
||||
* device numbers.
|
||||
*/
|
||||
if (pcie->is_rc) {
|
||||
/* The device and function numbers are always 0. */
|
||||
desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID |
|
||||
CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(0);
|
||||
desc1 |= CDNS_PCIE_AT_OB_REGION_DESC1_BUS(pcie->bus);
|
||||
} else {
|
||||
/*
|
||||
* Use captured values for bus and device numbers but still
|
||||
* need to set the function number.
|
||||
*/
|
||||
desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(fn);
|
||||
}
|
||||
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(r), desc0);
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(r), desc1);
|
||||
|
||||
/* Set the CPU address */
|
||||
cpu_addr -= pcie->mem_res->start;
|
||||
addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(nbits) |
|
||||
(lower_32_bits(cpu_addr) & GENMASK(31, 8));
|
||||
addr1 = upper_32_bits(cpu_addr);
|
||||
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), addr0);
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), addr1);
|
||||
}
|
||||
|
||||
void cdns_pcie_set_outbound_region_for_normal_msg(struct cdns_pcie *pcie, u8 fn,
|
||||
u32 r, u64 cpu_addr)
|
||||
{
|
||||
u32 addr0, addr1, desc0, desc1;
|
||||
|
||||
desc0 = CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_NORMAL_MSG;
|
||||
desc1 = 0;
|
||||
|
||||
/* See cdns_pcie_set_outbound_region() comments above. */
|
||||
if (pcie->is_rc) {
|
||||
desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID |
|
||||
CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(0);
|
||||
desc1 |= CDNS_PCIE_AT_OB_REGION_DESC1_BUS(pcie->bus);
|
||||
} else {
|
||||
desc0 |= CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(fn);
|
||||
}
|
||||
|
||||
/* Set the CPU address */
|
||||
cpu_addr -= pcie->mem_res->start;
|
||||
addr0 = CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(17) |
|
||||
(lower_32_bits(cpu_addr) & GENMASK(31, 8));
|
||||
addr1 = upper_32_bits(cpu_addr);
|
||||
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r), 0);
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r), 0);
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(r), desc0);
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(r), desc1);
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), addr0);
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), addr1);
|
||||
}
|
||||
|
||||
void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r)
|
||||
{
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r), 0);
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r), 0);
|
||||
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC0(r), 0);
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_DESC1(r), 0);
|
||||
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r), 0);
|
||||
cdns_pcie_writel(pcie, CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r), 0);
|
||||
}
|
||||
311
drivers/pci/cadence/pcie-cadence.h
Normal file
311
drivers/pci/cadence/pcie-cadence.h
Normal file
|
|
@ -0,0 +1,311 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
// Copyright (c) 2017 Cadence
|
||||
// Cadence PCIe controller driver.
|
||||
// Author: Cyrille Pitchen <[email protected]>
|
||||
|
||||
#ifndef _PCIE_CADENCE_H
|
||||
#define _PCIE_CADENCE_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
/*
|
||||
* Local Management Registers
|
||||
*/
|
||||
#define CDNS_PCIE_LM_BASE 0x00100000
|
||||
|
||||
/* Vendor ID Register */
|
||||
#define CDNS_PCIE_LM_ID (CDNS_PCIE_LM_BASE + 0x0044)
|
||||
#define CDNS_PCIE_LM_ID_VENDOR_MASK GENMASK(15, 0)
|
||||
#define CDNS_PCIE_LM_ID_VENDOR_SHIFT 0
|
||||
#define CDNS_PCIE_LM_ID_VENDOR(vid) \
|
||||
(((vid) << CDNS_PCIE_LM_ID_VENDOR_SHIFT) & CDNS_PCIE_LM_ID_VENDOR_MASK)
|
||||
#define CDNS_PCIE_LM_ID_SUBSYS_MASK GENMASK(31, 16)
|
||||
#define CDNS_PCIE_LM_ID_SUBSYS_SHIFT 16
|
||||
#define CDNS_PCIE_LM_ID_SUBSYS(sub) \
|
||||
(((sub) << CDNS_PCIE_LM_ID_SUBSYS_SHIFT) & CDNS_PCIE_LM_ID_SUBSYS_MASK)
|
||||
|
||||
/* Root Port Requestor ID Register */
|
||||
#define CDNS_PCIE_LM_RP_RID (CDNS_PCIE_LM_BASE + 0x0228)
|
||||
#define CDNS_PCIE_LM_RP_RID_MASK GENMASK(15, 0)
|
||||
#define CDNS_PCIE_LM_RP_RID_SHIFT 0
|
||||
#define CDNS_PCIE_LM_RP_RID_(rid) \
|
||||
(((rid) << CDNS_PCIE_LM_RP_RID_SHIFT) & CDNS_PCIE_LM_RP_RID_MASK)
|
||||
|
||||
/* Endpoint Bus and Device Number Register */
|
||||
#define CDNS_PCIE_LM_EP_ID (CDNS_PCIE_LM_BASE + 0x022c)
|
||||
#define CDNS_PCIE_LM_EP_ID_DEV_MASK GENMASK(4, 0)
|
||||
#define CDNS_PCIE_LM_EP_ID_DEV_SHIFT 0
|
||||
#define CDNS_PCIE_LM_EP_ID_BUS_MASK GENMASK(15, 8)
|
||||
#define CDNS_PCIE_LM_EP_ID_BUS_SHIFT 8
|
||||
|
||||
/* Endpoint Function f BAR b Configuration Registers */
|
||||
#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG0(fn) \
|
||||
(CDNS_PCIE_LM_BASE + 0x0240 + (fn) * 0x0008)
|
||||
#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG1(fn) \
|
||||
(CDNS_PCIE_LM_BASE + 0x0244 + (fn) * 0x0008)
|
||||
#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b) \
|
||||
(GENMASK(4, 0) << ((b) * 8))
|
||||
#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE(b, a) \
|
||||
(((a) << ((b) * 8)) & CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_APERTURE_MASK(b))
|
||||
#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b) \
|
||||
(GENMASK(7, 5) << ((b) * 8))
|
||||
#define CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL(b, c) \
|
||||
(((c) << ((b) * 8 + 5)) & CDNS_PCIE_LM_EP_FUNC_BAR_CFG_BAR_CTRL_MASK(b))
|
||||
|
||||
/* Endpoint Function Configuration Register */
|
||||
#define CDNS_PCIE_LM_EP_FUNC_CFG (CDNS_PCIE_LM_BASE + 0x02c0)
|
||||
|
||||
/* Root Complex BAR Configuration Register */
|
||||
#define CDNS_PCIE_LM_RC_BAR_CFG (CDNS_PCIE_LM_BASE + 0x0300)
|
||||
#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE_MASK GENMASK(5, 0)
|
||||
#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE(a) \
|
||||
(((a) << 0) & CDNS_PCIE_LM_RC_BAR_CFG_BAR0_APERTURE_MASK)
|
||||
#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL_MASK GENMASK(8, 6)
|
||||
#define CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL(c) \
|
||||
(((c) << 6) & CDNS_PCIE_LM_RC_BAR_CFG_BAR0_CTRL_MASK)
|
||||
#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE_MASK GENMASK(13, 9)
|
||||
#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE(a) \
|
||||
(((a) << 9) & CDNS_PCIE_LM_RC_BAR_CFG_BAR1_APERTURE_MASK)
|
||||
#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL_MASK GENMASK(16, 14)
|
||||
#define CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL(c) \
|
||||
(((c) << 14) & CDNS_PCIE_LM_RC_BAR_CFG_BAR1_CTRL_MASK)
|
||||
#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_ENABLE BIT(17)
|
||||
#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_32BITS 0
|
||||
#define CDNS_PCIE_LM_RC_BAR_CFG_PREFETCH_MEM_64BITS BIT(18)
|
||||
#define CDNS_PCIE_LM_RC_BAR_CFG_IO_ENABLE BIT(19)
|
||||
#define CDNS_PCIE_LM_RC_BAR_CFG_IO_16BITS 0
|
||||
#define CDNS_PCIE_LM_RC_BAR_CFG_IO_32BITS BIT(20)
|
||||
#define CDNS_PCIE_LM_RC_BAR_CFG_CHECK_ENABLE BIT(31)
|
||||
|
||||
/* BAR control values applicable to both Endpoint Function and Root Complex */
|
||||
#define CDNS_PCIE_LM_BAR_CFG_CTRL_DISABLED 0x0
|
||||
#define CDNS_PCIE_LM_BAR_CFG_CTRL_IO_32BITS 0x1
|
||||
#define CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_32BITS 0x4
|
||||
#define CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_32BITS 0x5
|
||||
#define CDNS_PCIE_LM_BAR_CFG_CTRL_MEM_64BITS 0x6
|
||||
#define CDNS_PCIE_LM_BAR_CFG_CTRL_PREFETCH_MEM_64BITS 0x7
|
||||
|
||||
|
||||
/*
|
||||
* Endpoint Function Registers (PCI configuration space for endpoint functions)
|
||||
*/
|
||||
#define CDNS_PCIE_EP_FUNC_BASE(fn) (((fn) << 12) & GENMASK(19, 12))
|
||||
|
||||
#define CDNS_PCIE_EP_FUNC_MSI_CAP_OFFSET 0x90
|
||||
|
||||
/*
|
||||
* Root Port Registers (PCI configuration space for the root port function)
|
||||
*/
|
||||
#define CDNS_PCIE_RP_BASE 0x00200000
|
||||
|
||||
|
||||
/*
|
||||
* Address Translation Registers
|
||||
*/
|
||||
#define CDNS_PCIE_AT_BASE 0x00400000
|
||||
|
||||
/* Region r Outbound AXI to PCIe Address Translation Register 0 */
|
||||
#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0(r) \
|
||||
(CDNS_PCIE_AT_BASE + 0x0000 + ((r) & 0x1f) * 0x0020)
|
||||
#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS_MASK GENMASK(5, 0)
|
||||
#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS(nbits) \
|
||||
(((nbits) - 1) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_NBITS_MASK)
|
||||
#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK GENMASK(19, 12)
|
||||
#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN(devfn) \
|
||||
(((devfn) << 12) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_DEVFN_MASK)
|
||||
#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK GENMASK(27, 20)
|
||||
#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS(bus) \
|
||||
(((bus) << 20) & CDNS_PCIE_AT_OB_REGION_PCI_ADDR0_BUS_MASK)
|
||||
|
||||
/* Region r Outbound AXI to PCIe Address Translation Register 1 */
|
||||
#define CDNS_PCIE_AT_OB_REGION_PCI_ADDR1(r) \
|
||||
(CDNS_PCIE_AT_BASE + 0x0004 + ((r) & 0x1f) * 0x0020)
|
||||
|
||||
/* Region r Outbound PCIe Descriptor Register 0 */
|
||||
#define CDNS_PCIE_AT_OB_REGION_DESC0(r) \
|
||||
(CDNS_PCIE_AT_BASE + 0x0008 + ((r) & 0x1f) * 0x0020)
|
||||
#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MASK GENMASK(3, 0)
|
||||
#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_MEM 0x2
|
||||
#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_IO 0x6
|
||||
#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE0 0xa
|
||||
#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_CONF_TYPE1 0xb
|
||||
#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_NORMAL_MSG 0xc
|
||||
#define CDNS_PCIE_AT_OB_REGION_DESC0_TYPE_VENDOR_MSG 0xd
|
||||
/* Bit 23 MUST be set in RC mode. */
|
||||
#define CDNS_PCIE_AT_OB_REGION_DESC0_HARDCODED_RID BIT(23)
|
||||
#define CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK GENMASK(31, 24)
|
||||
#define CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN(devfn) \
|
||||
(((devfn) << 24) & CDNS_PCIE_AT_OB_REGION_DESC0_DEVFN_MASK)
|
||||
|
||||
/* Region r Outbound PCIe Descriptor Register 1 */
|
||||
#define CDNS_PCIE_AT_OB_REGION_DESC1(r) \
|
||||
(CDNS_PCIE_AT_BASE + 0x000c + ((r) & 0x1f) * 0x0020)
|
||||
#define CDNS_PCIE_AT_OB_REGION_DESC1_BUS_MASK GENMASK(7, 0)
|
||||
#define CDNS_PCIE_AT_OB_REGION_DESC1_BUS(bus) \
|
||||
((bus) & CDNS_PCIE_AT_OB_REGION_DESC1_BUS_MASK)
|
||||
|
||||
/* Region r AXI Region Base Address Register 0 */
|
||||
#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0(r) \
|
||||
(CDNS_PCIE_AT_BASE + 0x0018 + ((r) & 0x1f) * 0x0020)
|
||||
#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS_MASK GENMASK(5, 0)
|
||||
#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS(nbits) \
|
||||
(((nbits) - 1) & CDNS_PCIE_AT_OB_REGION_CPU_ADDR0_NBITS_MASK)
|
||||
|
||||
/* Region r AXI Region Base Address Register 1 */
|
||||
#define CDNS_PCIE_AT_OB_REGION_CPU_ADDR1(r) \
|
||||
(CDNS_PCIE_AT_BASE + 0x001c + ((r) & 0x1f) * 0x0020)
|
||||
|
||||
/* Root Port BAR Inbound PCIe to AXI Address Translation Register */
|
||||
#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0(bar) \
|
||||
(CDNS_PCIE_AT_BASE + 0x0800 + (bar) * 0x0008)
|
||||
#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS_MASK GENMASK(5, 0)
|
||||
#define CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS(nbits) \
|
||||
(((nbits) - 1) & CDNS_PCIE_AT_IB_RP_BAR_ADDR0_NBITS_MASK)
|
||||
#define CDNS_PCIE_AT_IB_RP_BAR_ADDR1(bar) \
|
||||
(CDNS_PCIE_AT_BASE + 0x0804 + (bar) * 0x0008)
|
||||
|
||||
enum cdns_pcie_rp_bar {
|
||||
RP_BAR0,
|
||||
RP_BAR1,
|
||||
RP_NO_BAR
|
||||
};
|
||||
|
||||
/* Endpoint Function BAR Inbound PCIe to AXI Address Translation Register */
|
||||
#define CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR0(fn, bar) \
|
||||
(CDNS_PCIE_AT_BASE + 0x0840 + (fn) * 0x0040 + (bar) * 0x0008)
|
||||
#define CDNS_PCIE_AT_IB_EP_FUNC_BAR_ADDR1(fn, bar) \
|
||||
(CDNS_PCIE_AT_BASE + 0x0844 + (fn) * 0x0040 + (bar) * 0x0008)
|
||||
|
||||
/* Normal/Vendor specific message access: offset inside some outbound region */
|
||||
#define CDNS_PCIE_NORMAL_MSG_ROUTING_MASK GENMASK(7, 5)
|
||||
#define CDNS_PCIE_NORMAL_MSG_ROUTING(route) \
|
||||
(((route) << 5) & CDNS_PCIE_NORMAL_MSG_ROUTING_MASK)
|
||||
#define CDNS_PCIE_NORMAL_MSG_CODE_MASK GENMASK(15, 8)
|
||||
#define CDNS_PCIE_NORMAL_MSG_CODE(code) \
|
||||
(((code) << 8) & CDNS_PCIE_NORMAL_MSG_CODE_MASK)
|
||||
#define CDNS_PCIE_MSG_NO_DATA BIT(16)
|
||||
|
||||
enum cdns_pcie_msg_code {
|
||||
MSG_CODE_ASSERT_INTA = 0x20,
|
||||
MSG_CODE_ASSERT_INTB = 0x21,
|
||||
MSG_CODE_ASSERT_INTC = 0x22,
|
||||
MSG_CODE_ASSERT_INTD = 0x23,
|
||||
MSG_CODE_DEASSERT_INTA = 0x24,
|
||||
MSG_CODE_DEASSERT_INTB = 0x25,
|
||||
MSG_CODE_DEASSERT_INTC = 0x26,
|
||||
MSG_CODE_DEASSERT_INTD = 0x27,
|
||||
};
|
||||
|
||||
enum cdns_pcie_msg_routing {
|
||||
/* Route to Root Complex */
|
||||
MSG_ROUTING_TO_RC,
|
||||
|
||||
/* Use Address Routing */
|
||||
MSG_ROUTING_BY_ADDR,
|
||||
|
||||
/* Use ID Routing */
|
||||
MSG_ROUTING_BY_ID,
|
||||
|
||||
/* Route as Broadcast Message from Root Complex */
|
||||
MSG_ROUTING_BCAST,
|
||||
|
||||
/* Local message; terminate at receiver (INTx messages) */
|
||||
MSG_ROUTING_LOCAL,
|
||||
|
||||
/* Gather & route to Root Complex (PME_TO_Ack message) */
|
||||
MSG_ROUTING_GATHER,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct cdns_pcie - private data for Cadence PCIe controller drivers
|
||||
* @reg_base: IO mapped register base
|
||||
* @mem_res: start/end offsets in the physical system memory to map PCI accesses
|
||||
* @is_rc: tell whether the PCIe controller mode is Root Complex or Endpoint.
|
||||
* @bus: In Root Complex mode, the bus number
|
||||
*/
|
||||
struct cdns_pcie {
|
||||
void __iomem *reg_base;
|
||||
struct resource *mem_res;
|
||||
bool is_rc;
|
||||
u8 bus;
|
||||
};
|
||||
|
||||
/* Register access */
|
||||
static inline void cdns_pcie_writeb(struct cdns_pcie *pcie, u32 reg, u8 value)
|
||||
{
|
||||
writeb(value, pcie->reg_base + reg);
|
||||
}
|
||||
|
||||
static inline void cdns_pcie_writew(struct cdns_pcie *pcie, u32 reg, u16 value)
|
||||
{
|
||||
writew(value, pcie->reg_base + reg);
|
||||
}
|
||||
|
||||
static inline void cdns_pcie_writel(struct cdns_pcie *pcie, u32 reg, u32 value)
|
||||
{
|
||||
writel(value, pcie->reg_base + reg);
|
||||
}
|
||||
|
||||
static inline u32 cdns_pcie_readl(struct cdns_pcie *pcie, u32 reg)
|
||||
{
|
||||
return readl(pcie->reg_base + reg);
|
||||
}
|
||||
|
||||
/* Root Port register access */
|
||||
static inline void cdns_pcie_rp_writeb(struct cdns_pcie *pcie,
|
||||
u32 reg, u8 value)
|
||||
{
|
||||
writeb(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg);
|
||||
}
|
||||
|
||||
static inline void cdns_pcie_rp_writew(struct cdns_pcie *pcie,
|
||||
u32 reg, u16 value)
|
||||
{
|
||||
writew(value, pcie->reg_base + CDNS_PCIE_RP_BASE + reg);
|
||||
}
|
||||
|
||||
/* Endpoint Function register access */
|
||||
static inline void cdns_pcie_ep_fn_writeb(struct cdns_pcie *pcie, u8 fn,
|
||||
u32 reg, u8 value)
|
||||
{
|
||||
writeb(value, pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
|
||||
}
|
||||
|
||||
static inline void cdns_pcie_ep_fn_writew(struct cdns_pcie *pcie, u8 fn,
|
||||
u32 reg, u16 value)
|
||||
{
|
||||
writew(value, pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
|
||||
}
|
||||
|
||||
static inline void cdns_pcie_ep_fn_writel(struct cdns_pcie *pcie, u8 fn,
|
||||
u32 reg, u16 value)
|
||||
{
|
||||
writel(value, pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
|
||||
}
|
||||
|
||||
static inline u8 cdns_pcie_ep_fn_readb(struct cdns_pcie *pcie, u8 fn, u32 reg)
|
||||
{
|
||||
return readb(pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
|
||||
}
|
||||
|
||||
static inline u16 cdns_pcie_ep_fn_readw(struct cdns_pcie *pcie, u8 fn, u32 reg)
|
||||
{
|
||||
return readw(pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
|
||||
}
|
||||
|
||||
static inline u32 cdns_pcie_ep_fn_readl(struct cdns_pcie *pcie, u8 fn, u32 reg)
|
||||
{
|
||||
return readl(pcie->reg_base + CDNS_PCIE_EP_FUNC_BASE(fn) + reg);
|
||||
}
|
||||
|
||||
void cdns_pcie_set_outbound_region(struct cdns_pcie *pcie, u8 fn,
|
||||
u32 r, bool is_io,
|
||||
u64 cpu_addr, u64 pci_addr, size_t size);
|
||||
|
||||
void cdns_pcie_set_outbound_region_for_normal_msg(struct cdns_pcie *pcie, u8 fn,
|
||||
u32 r, u64 cpu_addr);
|
||||
|
||||
void cdns_pcie_reset_outbound_region(struct cdns_pcie *pcie, u32 r);
|
||||
|
||||
#endif /* _PCIE_CADENCE_H */
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
menu "DesignWare PCI Core Support"
|
||||
|
||||
config PCIE_DW
|
||||
|
|
@ -15,39 +17,38 @@ config PCIE_DW_EP
|
|||
select PCIE_DW
|
||||
|
||||
config PCI_DRA7XX
|
||||
bool "TI DRA7xx PCIe controller"
|
||||
depends on SOC_DRA7XX || COMPILE_TEST
|
||||
depends on (PCI && PCI_MSI_IRQ_DOMAIN) || PCI_ENDPOINT
|
||||
depends on OF && HAS_IOMEM && TI_PIPE3
|
||||
help
|
||||
Enables support for the PCIe controller in the DRA7xx SoC. There
|
||||
are two instances of PCIe controller in DRA7xx. This controller can
|
||||
work either as EP or RC. In order to enable host-specific features
|
||||
PCI_DRA7XX_HOST must be selected and in order to enable device-
|
||||
specific features PCI_DRA7XX_EP must be selected. This uses
|
||||
the DesignWare core.
|
||||
|
||||
if PCI_DRA7XX
|
||||
bool
|
||||
|
||||
config PCI_DRA7XX_HOST
|
||||
bool "PCI DRA7xx Host Mode"
|
||||
depends on PCI
|
||||
depends on PCI_MSI_IRQ_DOMAIN
|
||||
bool "TI DRA7xx PCIe controller Host Mode"
|
||||
depends on SOC_DRA7XX || COMPILE_TEST
|
||||
depends on PCI && PCI_MSI_IRQ_DOMAIN
|
||||
depends on OF && HAS_IOMEM && TI_PIPE3
|
||||
select PCIE_DW_HOST
|
||||
select PCI_DRA7XX
|
||||
default y
|
||||
help
|
||||
Enables support for the PCIe controller in the DRA7xx SoC to work in
|
||||
host mode.
|
||||
Enables support for the PCIe controller in the DRA7xx SoC to work in
|
||||
host mode. There are two instances of PCIe controller in DRA7xx.
|
||||
This controller can work either as EP or RC. In order to enable
|
||||
host-specific features PCI_DRA7XX_HOST must be selected and in order
|
||||
to enable device-specific features PCI_DRA7XX_EP must be selected.
|
||||
This uses the DesignWare core.
|
||||
|
||||
config PCI_DRA7XX_EP
|
||||
bool "PCI DRA7xx Endpoint Mode"
|
||||
bool "TI DRA7xx PCIe controller Endpoint Mode"
|
||||
depends on SOC_DRA7XX || COMPILE_TEST
|
||||
depends on PCI_ENDPOINT
|
||||
depends on OF && HAS_IOMEM && TI_PIPE3
|
||||
select PCIE_DW_EP
|
||||
select PCI_DRA7XX
|
||||
help
|
||||
Enables support for the PCIe controller in the DRA7xx SoC to work in
|
||||
endpoint mode.
|
||||
|
||||
endif
|
||||
Enables support for the PCIe controller in the DRA7xx SoC to work in
|
||||
endpoint mode. There are two instances of PCIe controller in DRA7xx.
|
||||
This controller can work either as EP or RC. In order to enable
|
||||
host-specific features PCI_DRA7XX_HOST must be selected and in order
|
||||
to enable device-specific features PCI_DRA7XX_EP must be selected.
|
||||
This uses the DesignWare core.
|
||||
|
||||
config PCIE_DW_PLAT
|
||||
bool "Platform bus based DesignWare PCIe Controller"
|
||||
|
|
@ -149,15 +150,28 @@ config PCIE_ARMADA_8K
|
|||
DesignWare core functions to implement the driver.
|
||||
|
||||
config PCIE_ARTPEC6
|
||||
bool "Axis ARTPEC-6 PCIe controller"
|
||||
depends on PCI
|
||||
bool
|
||||
|
||||
config PCIE_ARTPEC6_HOST
|
||||
bool "Axis ARTPEC-6 PCIe controller Host Mode"
|
||||
depends on MACH_ARTPEC6
|
||||
depends on PCI_MSI_IRQ_DOMAIN
|
||||
depends on PCI && PCI_MSI_IRQ_DOMAIN
|
||||
select PCIEPORTBUS
|
||||
select PCIE_DW_HOST
|
||||
select PCIE_ARTPEC6
|
||||
help
|
||||
Say Y here to enable PCIe controller support on Axis ARTPEC-6
|
||||
SoCs. This PCIe controller uses the DesignWare core.
|
||||
Enables support for the PCIe controller in the ARTPEC-6 SoC to work in
|
||||
host mode. This uses the DesignWare core.
|
||||
|
||||
config PCIE_ARTPEC6_EP
|
||||
bool "Axis ARTPEC-6 PCIe controller Endpoint Mode"
|
||||
depends on MACH_ARTPEC6
|
||||
depends on PCI_ENDPOINT
|
||||
select PCIE_DW_EP
|
||||
select PCIE_ARTPEC6
|
||||
help
|
||||
Enables support for the PCIe controller in the ARTPEC-6 SoC to work in
|
||||
endpoint mode. This uses the DesignWare core.
|
||||
|
||||
config PCIE_KIRIN
|
||||
depends on OF && ARM64
|
||||
|
|
|
|||
|
|
@ -3,9 +3,7 @@ obj-$(CONFIG_PCIE_DW) += pcie-designware.o
|
|||
obj-$(CONFIG_PCIE_DW_HOST) += pcie-designware-host.o
|
||||
obj-$(CONFIG_PCIE_DW_EP) += pcie-designware-ep.o
|
||||
obj-$(CONFIG_PCIE_DW_PLAT) += pcie-designware-plat.o
|
||||
ifneq ($(filter y,$(CONFIG_PCI_DRA7XX_HOST) $(CONFIG_PCI_DRA7XX_EP)),)
|
||||
obj-$(CONFIG_PCI_DRA7XX) += pci-dra7xx.o
|
||||
endif
|
||||
obj-$(CONFIG_PCI_DRA7XX) += pci-dra7xx.o
|
||||
obj-$(CONFIG_PCI_EXYNOS) += pci-exynos.o
|
||||
obj-$(CONFIG_PCI_IMX6) += pci-imx6.o
|
||||
obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o
|
||||
|
|
@ -27,4 +25,6 @@ obj-$(CONFIG_PCIE_HISI_STB) += pcie-histb.o
|
|||
# ARM64 and use internal ifdefs to only build the pieces we need
|
||||
# depending on whether ACPI, the DT driver, or both are enabled.
|
||||
|
||||
ifdef CONFIG_PCI
|
||||
obj-$(CONFIG_ARM64) += pcie-hisi.o
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -1,13 +1,10 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* pcie-dra7xx - PCIe controller driver for TI DRA7xx SoCs
|
||||
*
|
||||
* Copyright (C) 2013-2014 Texas Instruments Incorporated - http://www.ti.com
|
||||
*
|
||||
* Authors: Kishon Vijay Abraham I <kishon@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/delay.h>
|
||||
|
|
@ -110,7 +107,7 @@ static inline void dra7xx_pcie_writel(struct dra7xx_pcie *pcie, u32 offset,
|
|||
writel(value, pcie->base + offset);
|
||||
}
|
||||
|
||||
static u64 dra7xx_pcie_cpu_addr_fixup(u64 pci_addr)
|
||||
static u64 dra7xx_pcie_cpu_addr_fixup(struct dw_pcie *pci, u64 pci_addr)
|
||||
{
|
||||
return pci_addr & DRA7XX_CPU_TO_BUS_ADDR;
|
||||
}
|
||||
|
|
@ -226,6 +223,7 @@ static int dra7xx_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
|
|||
|
||||
static const struct irq_domain_ops intx_domain_ops = {
|
||||
.map = dra7xx_pcie_intx_map,
|
||||
.xlate = pci_irqd_intx_xlate,
|
||||
};
|
||||
|
||||
static int dra7xx_pcie_init_irq_domain(struct pcie_port *pp)
|
||||
|
|
@ -256,7 +254,8 @@ static irqreturn_t dra7xx_pcie_msi_irq_handler(int irq, void *arg)
|
|||
struct dra7xx_pcie *dra7xx = arg;
|
||||
struct dw_pcie *pci = dra7xx->pci;
|
||||
struct pcie_port *pp = &pci->pp;
|
||||
u32 reg;
|
||||
unsigned long reg;
|
||||
u32 virq, bit;
|
||||
|
||||
reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_IRQSTATUS_MSI);
|
||||
|
||||
|
|
@ -268,8 +267,11 @@ static irqreturn_t dra7xx_pcie_msi_irq_handler(int irq, void *arg)
|
|||
case INTB:
|
||||
case INTC:
|
||||
case INTD:
|
||||
generic_handle_irq(irq_find_mapping(dra7xx->irq_domain,
|
||||
ffs(reg)));
|
||||
for_each_set_bit(bit, ®, PCI_NUM_INTX) {
|
||||
virq = irq_find_mapping(dra7xx->irq_domain, bit);
|
||||
if (virq)
|
||||
generic_handle_irq(virq);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -337,15 +339,6 @@ static irqreturn_t dra7xx_pcie_irq_handler(int irq, void *arg)
|
|||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
reg = PCI_BASE_ADDRESS_0 + (4 * bar);
|
||||
dw_pcie_writel_dbi2(pci, reg, 0x0);
|
||||
dw_pcie_writel_dbi(pci, reg, 0x0);
|
||||
}
|
||||
|
||||
static void dra7xx_pcie_ep_init(struct dw_pcie_ep *ep)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
|
|
@ -375,7 +368,7 @@ static void dra7xx_pcie_raise_msi_irq(struct dra7xx_pcie *dra7xx,
|
|||
dra7xx_pcie_writel(dra7xx, PCIECTRL_TI_CONF_MSI_XMT, reg);
|
||||
}
|
||||
|
||||
static int dra7xx_pcie_raise_irq(struct dw_pcie_ep *ep,
|
||||
static int dra7xx_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
enum pci_epc_irq_type type, u8 interrupt_num)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
|
|
@ -470,6 +463,8 @@ static int __init dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx,
|
|||
if (!pci->dbi_base)
|
||||
return -ENOMEM;
|
||||
|
||||
pp->ops = &dra7xx_pcie_host_ops;
|
||||
|
||||
ret = dw_pcie_host_init(pp);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to initialize host\n");
|
||||
|
|
@ -599,7 +594,6 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
|
|||
void __iomem *base;
|
||||
struct resource *res;
|
||||
struct dw_pcie *pci;
|
||||
struct pcie_port *pp;
|
||||
struct dra7xx_pcie *dra7xx;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
|
|
@ -627,9 +621,6 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
|
|||
pci->dev = dev;
|
||||
pci->ops = &dw_pcie_ops;
|
||||
|
||||
pp = &pci->pp;
|
||||
pp->ops = &dra7xx_pcie_host_ops;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
dev_err(dev, "missing IRQ resource: %d\n", irq);
|
||||
|
|
@ -705,6 +696,11 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
|
|||
|
||||
switch (mode) {
|
||||
case DW_PCIE_RC_TYPE:
|
||||
if (!IS_ENABLED(CONFIG_PCI_DRA7XX_HOST)) {
|
||||
ret = -ENODEV;
|
||||
goto err_gpio;
|
||||
}
|
||||
|
||||
dra7xx_pcie_writel(dra7xx, PCIECTRL_TI_CONF_DEVICE_TYPE,
|
||||
DEVICE_TYPE_RC);
|
||||
ret = dra7xx_add_pcie_port(dra7xx, pdev);
|
||||
|
|
@ -712,6 +708,11 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
|
|||
goto err_gpio;
|
||||
break;
|
||||
case DW_PCIE_EP_TYPE:
|
||||
if (!IS_ENABLED(CONFIG_PCI_DRA7XX_EP)) {
|
||||
ret = -ENODEV;
|
||||
goto err_gpio;
|
||||
}
|
||||
|
||||
dra7xx_pcie_writel(dra7xx, PCIECTRL_TI_CONF_DEVICE_TYPE,
|
||||
DEVICE_TYPE_EP);
|
||||
|
||||
|
|
@ -810,7 +811,7 @@ static int dra7xx_pcie_resume_noirq(struct device *dev)
|
|||
}
|
||||
#endif
|
||||
|
||||
void dra7xx_pcie_shutdown(struct platform_device *pdev)
|
||||
static void dra7xx_pcie_shutdown(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
struct dra7xx_pcie *dra7xx = dev_get_drvdata(dev);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* PCIe host controller driver for Samsung EXYNOS SoCs
|
||||
*
|
||||
|
|
@ -5,10 +6,6 @@
|
|||
* http://www.samsung.com
|
||||
*
|
||||
* Author: Jingoo Han <jg1.han@samsung.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/clk.h>
|
||||
|
|
@ -55,49 +52,8 @@
|
|||
#define PCIE_ELBI_SLV_ARMISC 0x120
|
||||
#define PCIE_ELBI_SLV_DBI_ENABLE BIT(21)
|
||||
|
||||
/* PCIe Purple registers */
|
||||
#define PCIE_PHY_GLOBAL_RESET 0x000
|
||||
#define PCIE_PHY_COMMON_RESET 0x004
|
||||
#define PCIE_PHY_CMN_REG 0x008
|
||||
#define PCIE_PHY_MAC_RESET 0x00c
|
||||
#define PCIE_PHY_PLL_LOCKED 0x010
|
||||
#define PCIE_PHY_TRSVREG_RESET 0x020
|
||||
#define PCIE_PHY_TRSV_RESET 0x024
|
||||
|
||||
/* PCIe PHY registers */
|
||||
#define PCIE_PHY_IMPEDANCE 0x004
|
||||
#define PCIE_PHY_PLL_DIV_0 0x008
|
||||
#define PCIE_PHY_PLL_BIAS 0x00c
|
||||
#define PCIE_PHY_DCC_FEEDBACK 0x014
|
||||
#define PCIE_PHY_PLL_DIV_1 0x05c
|
||||
#define PCIE_PHY_COMMON_POWER 0x064
|
||||
#define PCIE_PHY_COMMON_PD_CMN BIT(3)
|
||||
#define PCIE_PHY_TRSV0_EMP_LVL 0x084
|
||||
#define PCIE_PHY_TRSV0_DRV_LVL 0x088
|
||||
#define PCIE_PHY_TRSV0_RXCDR 0x0ac
|
||||
#define PCIE_PHY_TRSV0_POWER 0x0c4
|
||||
#define PCIE_PHY_TRSV0_PD_TSV BIT(7)
|
||||
#define PCIE_PHY_TRSV0_LVCC 0x0dc
|
||||
#define PCIE_PHY_TRSV1_EMP_LVL 0x144
|
||||
#define PCIE_PHY_TRSV1_RXCDR 0x16c
|
||||
#define PCIE_PHY_TRSV1_POWER 0x184
|
||||
#define PCIE_PHY_TRSV1_PD_TSV BIT(7)
|
||||
#define PCIE_PHY_TRSV1_LVCC 0x19c
|
||||
#define PCIE_PHY_TRSV2_EMP_LVL 0x204
|
||||
#define PCIE_PHY_TRSV2_RXCDR 0x22c
|
||||
#define PCIE_PHY_TRSV2_POWER 0x244
|
||||
#define PCIE_PHY_TRSV2_PD_TSV BIT(7)
|
||||
#define PCIE_PHY_TRSV2_LVCC 0x25c
|
||||
#define PCIE_PHY_TRSV3_EMP_LVL 0x2c4
|
||||
#define PCIE_PHY_TRSV3_RXCDR 0x2ec
|
||||
#define PCIE_PHY_TRSV3_POWER 0x304
|
||||
#define PCIE_PHY_TRSV3_PD_TSV BIT(7)
|
||||
#define PCIE_PHY_TRSV3_LVCC 0x31c
|
||||
|
||||
struct exynos_pcie_mem_res {
|
||||
void __iomem *elbi_base; /* DT 0th resource: PCIe CTRL */
|
||||
void __iomem *phy_base; /* DT 1st resource: PHY CTRL */
|
||||
void __iomem *block_base; /* DT 2nd resource: PHY ADDITIONAL CTRL */
|
||||
};
|
||||
|
||||
struct exynos_pcie_clk_res {
|
||||
|
|
@ -112,8 +68,6 @@ struct exynos_pcie {
|
|||
const struct exynos_pcie_ops *ops;
|
||||
int reset_gpio;
|
||||
|
||||
/* For Generic PHY Framework */
|
||||
bool using_phy;
|
||||
struct phy *phy;
|
||||
};
|
||||
|
||||
|
|
@ -141,20 +95,6 @@ static int exynos5440_pcie_get_mem_resources(struct platform_device *pdev,
|
|||
if (IS_ERR(ep->mem_res->elbi_base))
|
||||
return PTR_ERR(ep->mem_res->elbi_base);
|
||||
|
||||
/* If using the PHY framework, doesn't need to get other resource */
|
||||
if (ep->using_phy)
|
||||
return 0;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
ep->mem_res->phy_base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(ep->mem_res->phy_base))
|
||||
return PTR_ERR(ep->mem_res->phy_base);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
|
||||
ep->mem_res->block_base = devm_ioremap_resource(dev, res);
|
||||
if (IS_ERR(ep->mem_res->block_base))
|
||||
return PTR_ERR(ep->mem_res->block_base);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -279,111 +219,6 @@ static void exynos_pcie_deassert_core_reset(struct exynos_pcie *ep)
|
|||
exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_NONSTICKY_RESET);
|
||||
exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_APP_INIT_RESET);
|
||||
exynos_pcie_writel(ep->mem_res->elbi_base, 0, PCIE_APP_INIT_RESET);
|
||||
exynos_pcie_writel(ep->mem_res->block_base, 1, PCIE_PHY_MAC_RESET);
|
||||
}
|
||||
|
||||
static void exynos_pcie_assert_phy_reset(struct exynos_pcie *ep)
|
||||
{
|
||||
exynos_pcie_writel(ep->mem_res->block_base, 0, PCIE_PHY_MAC_RESET);
|
||||
exynos_pcie_writel(ep->mem_res->block_base, 1, PCIE_PHY_GLOBAL_RESET);
|
||||
}
|
||||
|
||||
static void exynos_pcie_deassert_phy_reset(struct exynos_pcie *ep)
|
||||
{
|
||||
exynos_pcie_writel(ep->mem_res->block_base, 0, PCIE_PHY_GLOBAL_RESET);
|
||||
exynos_pcie_writel(ep->mem_res->elbi_base, 1, PCIE_PWR_RESET);
|
||||
exynos_pcie_writel(ep->mem_res->block_base, 0, PCIE_PHY_COMMON_RESET);
|
||||
exynos_pcie_writel(ep->mem_res->block_base, 0, PCIE_PHY_CMN_REG);
|
||||
exynos_pcie_writel(ep->mem_res->block_base, 0, PCIE_PHY_TRSVREG_RESET);
|
||||
exynos_pcie_writel(ep->mem_res->block_base, 0, PCIE_PHY_TRSV_RESET);
|
||||
}
|
||||
|
||||
static void exynos_pcie_power_on_phy(struct exynos_pcie *ep)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_COMMON_POWER);
|
||||
val &= ~PCIE_PHY_COMMON_PD_CMN;
|
||||
exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_COMMON_POWER);
|
||||
|
||||
val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV0_POWER);
|
||||
val &= ~PCIE_PHY_TRSV0_PD_TSV;
|
||||
exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV0_POWER);
|
||||
|
||||
val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV1_POWER);
|
||||
val &= ~PCIE_PHY_TRSV1_PD_TSV;
|
||||
exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV1_POWER);
|
||||
|
||||
val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV2_POWER);
|
||||
val &= ~PCIE_PHY_TRSV2_PD_TSV;
|
||||
exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV2_POWER);
|
||||
|
||||
val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV3_POWER);
|
||||
val &= ~PCIE_PHY_TRSV3_PD_TSV;
|
||||
exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV3_POWER);
|
||||
}
|
||||
|
||||
static void exynos_pcie_power_off_phy(struct exynos_pcie *ep)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_COMMON_POWER);
|
||||
val |= PCIE_PHY_COMMON_PD_CMN;
|
||||
exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_COMMON_POWER);
|
||||
|
||||
val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV0_POWER);
|
||||
val |= PCIE_PHY_TRSV0_PD_TSV;
|
||||
exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV0_POWER);
|
||||
|
||||
val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV1_POWER);
|
||||
val |= PCIE_PHY_TRSV1_PD_TSV;
|
||||
exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV1_POWER);
|
||||
|
||||
val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV2_POWER);
|
||||
val |= PCIE_PHY_TRSV2_PD_TSV;
|
||||
exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV2_POWER);
|
||||
|
||||
val = exynos_pcie_readl(ep->mem_res->phy_base, PCIE_PHY_TRSV3_POWER);
|
||||
val |= PCIE_PHY_TRSV3_PD_TSV;
|
||||
exynos_pcie_writel(ep->mem_res->phy_base, val, PCIE_PHY_TRSV3_POWER);
|
||||
}
|
||||
|
||||
static void exynos_pcie_init_phy(struct exynos_pcie *ep)
|
||||
{
|
||||
/* DCC feedback control off */
|
||||
exynos_pcie_writel(ep->mem_res->phy_base, 0x29, PCIE_PHY_DCC_FEEDBACK);
|
||||
|
||||
/* set TX/RX impedance */
|
||||
exynos_pcie_writel(ep->mem_res->phy_base, 0xd5, PCIE_PHY_IMPEDANCE);
|
||||
|
||||
/* set 50Mhz PHY clock */
|
||||
exynos_pcie_writel(ep->mem_res->phy_base, 0x14, PCIE_PHY_PLL_DIV_0);
|
||||
exynos_pcie_writel(ep->mem_res->phy_base, 0x12, PCIE_PHY_PLL_DIV_1);
|
||||
|
||||
/* set TX Differential output for lane 0 */
|
||||
exynos_pcie_writel(ep->mem_res->phy_base, 0x7f, PCIE_PHY_TRSV0_DRV_LVL);
|
||||
|
||||
/* set TX Pre-emphasis Level Control for lane 0 to minimum */
|
||||
exynos_pcie_writel(ep->mem_res->phy_base, 0x0, PCIE_PHY_TRSV0_EMP_LVL);
|
||||
|
||||
/* set RX clock and data recovery bandwidth */
|
||||
exynos_pcie_writel(ep->mem_res->phy_base, 0xe7, PCIE_PHY_PLL_BIAS);
|
||||
exynos_pcie_writel(ep->mem_res->phy_base, 0x82, PCIE_PHY_TRSV0_RXCDR);
|
||||
exynos_pcie_writel(ep->mem_res->phy_base, 0x82, PCIE_PHY_TRSV1_RXCDR);
|
||||
exynos_pcie_writel(ep->mem_res->phy_base, 0x82, PCIE_PHY_TRSV2_RXCDR);
|
||||
exynos_pcie_writel(ep->mem_res->phy_base, 0x82, PCIE_PHY_TRSV3_RXCDR);
|
||||
|
||||
/* change TX Pre-emphasis Level Control for lanes */
|
||||
exynos_pcie_writel(ep->mem_res->phy_base, 0x39, PCIE_PHY_TRSV0_EMP_LVL);
|
||||
exynos_pcie_writel(ep->mem_res->phy_base, 0x39, PCIE_PHY_TRSV1_EMP_LVL);
|
||||
exynos_pcie_writel(ep->mem_res->phy_base, 0x39, PCIE_PHY_TRSV2_EMP_LVL);
|
||||
exynos_pcie_writel(ep->mem_res->phy_base, 0x39, PCIE_PHY_TRSV3_EMP_LVL);
|
||||
|
||||
/* set LVCC */
|
||||
exynos_pcie_writel(ep->mem_res->phy_base, 0x20, PCIE_PHY_TRSV0_LVCC);
|
||||
exynos_pcie_writel(ep->mem_res->phy_base, 0xa0, PCIE_PHY_TRSV1_LVCC);
|
||||
exynos_pcie_writel(ep->mem_res->phy_base, 0xa0, PCIE_PHY_TRSV2_LVCC);
|
||||
exynos_pcie_writel(ep->mem_res->phy_base, 0xa0, PCIE_PHY_TRSV3_LVCC);
|
||||
}
|
||||
|
||||
static void exynos_pcie_assert_reset(struct exynos_pcie *ep)
|
||||
|
|
@ -401,7 +236,6 @@ static int exynos_pcie_establish_link(struct exynos_pcie *ep)
|
|||
struct dw_pcie *pci = ep->pci;
|
||||
struct pcie_port *pp = &pci->pp;
|
||||
struct device *dev = pci->dev;
|
||||
u32 val;
|
||||
|
||||
if (dw_pcie_link_up(pci)) {
|
||||
dev_err(dev, "Link already up\n");
|
||||
|
|
@ -410,32 +244,13 @@ static int exynos_pcie_establish_link(struct exynos_pcie *ep)
|
|||
|
||||
exynos_pcie_assert_core_reset(ep);
|
||||
|
||||
if (ep->using_phy) {
|
||||
phy_reset(ep->phy);
|
||||
phy_reset(ep->phy);
|
||||
|
||||
exynos_pcie_writel(ep->mem_res->elbi_base, 1,
|
||||
PCIE_PWR_RESET);
|
||||
exynos_pcie_writel(ep->mem_res->elbi_base, 1,
|
||||
PCIE_PWR_RESET);
|
||||
|
||||
phy_power_on(ep->phy);
|
||||
phy_init(ep->phy);
|
||||
} else {
|
||||
exynos_pcie_assert_phy_reset(ep);
|
||||
exynos_pcie_deassert_phy_reset(ep);
|
||||
exynos_pcie_power_on_phy(ep);
|
||||
exynos_pcie_init_phy(ep);
|
||||
|
||||
/* pulse for common reset */
|
||||
exynos_pcie_writel(ep->mem_res->block_base, 1,
|
||||
PCIE_PHY_COMMON_RESET);
|
||||
udelay(500);
|
||||
exynos_pcie_writel(ep->mem_res->block_base, 0,
|
||||
PCIE_PHY_COMMON_RESET);
|
||||
}
|
||||
|
||||
/* pulse for common reset */
|
||||
exynos_pcie_writel(ep->mem_res->block_base, 1, PCIE_PHY_COMMON_RESET);
|
||||
udelay(500);
|
||||
exynos_pcie_writel(ep->mem_res->block_base, 0, PCIE_PHY_COMMON_RESET);
|
||||
phy_power_on(ep->phy);
|
||||
phy_init(ep->phy);
|
||||
|
||||
exynos_pcie_deassert_core_reset(ep);
|
||||
dw_pcie_setup_rc(pp);
|
||||
|
|
@ -449,18 +264,7 @@ static int exynos_pcie_establish_link(struct exynos_pcie *ep)
|
|||
if (!dw_pcie_wait_for_link(pci))
|
||||
return 0;
|
||||
|
||||
if (ep->using_phy) {
|
||||
phy_power_off(ep->phy);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
while (exynos_pcie_readl(ep->mem_res->phy_base,
|
||||
PCIE_PHY_PLL_LOCKED) == 0) {
|
||||
val = exynos_pcie_readl(ep->mem_res->block_base,
|
||||
PCIE_PHY_PLL_LOCKED);
|
||||
dev_info(dev, "PLL Locked: 0x%x\n", val);
|
||||
}
|
||||
exynos_pcie_power_off_phy(ep);
|
||||
phy_power_off(ep->phy);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
|
|
@ -678,16 +482,13 @@ static int __init exynos_pcie_probe(struct platform_device *pdev)
|
|||
|
||||
ep->reset_gpio = of_get_named_gpio(np, "reset-gpio", 0);
|
||||
|
||||
/* Assume that controller doesn't use the PHY framework */
|
||||
ep->using_phy = false;
|
||||
|
||||
ep->phy = devm_of_phy_get(dev, np, NULL);
|
||||
if (IS_ERR(ep->phy)) {
|
||||
if (PTR_ERR(ep->phy) == -EPROBE_DEFER)
|
||||
return PTR_ERR(ep->phy);
|
||||
dev_warn(dev, "Use the 'phy' property. Current DT of pci-exynos was deprecated!!\n");
|
||||
} else
|
||||
ep->using_phy = true;
|
||||
|
||||
ep->phy = NULL;
|
||||
}
|
||||
|
||||
if (ep->ops && ep->ops->get_mem_resources) {
|
||||
ret = ep->ops->get_mem_resources(pdev, ep);
|
||||
|
|
@ -695,7 +496,8 @@ static int __init exynos_pcie_probe(struct platform_device *pdev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
if (ep->ops && ep->ops->get_clk_resources) {
|
||||
if (ep->ops && ep->ops->get_clk_resources &&
|
||||
ep->ops->init_clk_resources) {
|
||||
ret = ep->ops->get_clk_resources(ep);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
|
@ -713,8 +515,7 @@ static int __init exynos_pcie_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
|
||||
fail_probe:
|
||||
if (ep->using_phy)
|
||||
phy_exit(ep->phy);
|
||||
phy_exit(ep->phy);
|
||||
|
||||
if (ep->ops && ep->ops->deinit_clk_resources)
|
||||
ep->ops->deinit_clk_resources(ep);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* PCIe host controller driver for Freescale i.MX6 SoCs
|
||||
*
|
||||
|
|
@ -5,10 +6,6 @@
|
|||
* http://www.kosagi.com
|
||||
*
|
||||
* Author: Sean Cross <xobs@kosagi.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/clk.h>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* DesignWare application register space functions for Keystone PCI controller
|
||||
*
|
||||
|
|
@ -5,11 +6,6 @@
|
|||
* 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>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* PCIe host controller driver for Texas Instruments Keystone SoCs
|
||||
*
|
||||
|
|
@ -6,10 +7,6 @@
|
|||
*
|
||||
* 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>
|
||||
|
|
@ -178,7 +175,7 @@ static int ks_pcie_get_irq_controller_info(struct keystone_pcie *ks_pcie,
|
|||
}
|
||||
|
||||
/* interrupt controller is in a child node */
|
||||
*np_temp = of_find_node_by_name(np_pcie, controller);
|
||||
*np_temp = of_get_child_by_name(np_pcie, controller);
|
||||
if (!(*np_temp)) {
|
||||
dev_err(dev, "Node for %s is absent\n", controller);
|
||||
return -EINVAL;
|
||||
|
|
@ -187,6 +184,7 @@ static int ks_pcie_get_irq_controller_info(struct keystone_pcie *ks_pcie,
|
|||
temp = of_irq_count(*np_temp);
|
||||
if (!temp) {
|
||||
dev_err(dev, "No IRQ entries in %s\n", controller);
|
||||
of_node_put(*np_temp);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -204,6 +202,8 @@ static int ks_pcie_get_irq_controller_info(struct keystone_pcie *ks_pcie,
|
|||
break;
|
||||
}
|
||||
|
||||
of_node_put(*np_temp);
|
||||
|
||||
if (temp) {
|
||||
*num_irqs = temp;
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Keystone PCI Controller's common includes
|
||||
*
|
||||
|
|
@ -5,11 +6,6 @@
|
|||
* 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_MSI_HOST_IRQS 8
|
||||
|
|
|
|||
|
|
@ -1,13 +1,10 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* PCIe host controller driver for Freescale Layerscape SoCs
|
||||
*
|
||||
* Copyright (C) 2014 Freescale Semiconductor.
|
||||
*
|
||||
* Author: Minghuan Lian <Minghuan.Lian@freescale.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/kernel.h>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* PCIe host controller driver for Marvell Armada-8K SoCs
|
||||
*
|
||||
|
|
@ -7,10 +8,6 @@
|
|||
*
|
||||
* Author: Yehuda Yitshak <yehuday@marvell.com>
|
||||
* Author: Shadi Ammouri <shadi@marvell.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
|
|
|
|||
|
|
@ -1,18 +1,16 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* PCIe host controller driver for Axis ARTPEC-6 SoC
|
||||
*
|
||||
* Author: Niklas Cassel <niklas.cassel@axis.com>
|
||||
*
|
||||
* Based on work done by Phil Edworthy <phil@edworthys.org>
|
||||
*
|
||||
* 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/delay.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/resource.h>
|
||||
|
|
@ -26,44 +24,72 @@
|
|||
|
||||
#define to_artpec6_pcie(x) dev_get_drvdata((x)->dev)
|
||||
|
||||
enum artpec_pcie_variants {
|
||||
ARTPEC6,
|
||||
ARTPEC7,
|
||||
};
|
||||
|
||||
struct artpec6_pcie {
|
||||
struct dw_pcie *pci;
|
||||
struct regmap *regmap; /* DT axis,syscon-pcie */
|
||||
void __iomem *phy_base; /* DT phy */
|
||||
enum artpec_pcie_variants variant;
|
||||
enum dw_pcie_device_mode mode;
|
||||
};
|
||||
|
||||
struct artpec_pcie_of_data {
|
||||
enum artpec_pcie_variants variant;
|
||||
enum dw_pcie_device_mode mode;
|
||||
};
|
||||
|
||||
static const struct of_device_id artpec6_pcie_of_match[];
|
||||
|
||||
/* PCIe Port Logic registers (memory-mapped) */
|
||||
#define PL_OFFSET 0x700
|
||||
#define PCIE_PHY_DEBUG_R0 (PL_OFFSET + 0x28)
|
||||
#define PCIE_PHY_DEBUG_R1 (PL_OFFSET + 0x2c)
|
||||
|
||||
#define MISC_CONTROL_1_OFF (PL_OFFSET + 0x1bc)
|
||||
#define DBI_RO_WR_EN 1
|
||||
#define ACK_F_ASPM_CTRL_OFF (PL_OFFSET + 0xc)
|
||||
#define ACK_N_FTS_MASK GENMASK(15, 8)
|
||||
#define ACK_N_FTS(x) (((x) << 8) & ACK_N_FTS_MASK)
|
||||
|
||||
#define FAST_TRAINING_SEQ_MASK GENMASK(7, 0)
|
||||
#define FAST_TRAINING_SEQ(x) (((x) << 0) & FAST_TRAINING_SEQ_MASK)
|
||||
|
||||
/* ARTPEC-6 specific registers */
|
||||
#define PCIECFG 0x18
|
||||
#define PCIECFG_DBG_OEN (1 << 24)
|
||||
#define PCIECFG_CORE_RESET_REQ (1 << 21)
|
||||
#define PCIECFG_LTSSM_ENABLE (1 << 20)
|
||||
#define PCIECFG_CLKREQ_B (1 << 11)
|
||||
#define PCIECFG_REFCLK_ENABLE (1 << 10)
|
||||
#define PCIECFG_PLL_ENABLE (1 << 9)
|
||||
#define PCIECFG_PCLK_ENABLE (1 << 8)
|
||||
#define PCIECFG_RISRCREN (1 << 4)
|
||||
#define PCIECFG_MODE_TX_DRV_EN (1 << 3)
|
||||
#define PCIECFG_CISRREN (1 << 2)
|
||||
#define PCIECFG_MACRO_ENABLE (1 << 0)
|
||||
#define PCIECFG_DBG_OEN BIT(24)
|
||||
#define PCIECFG_CORE_RESET_REQ BIT(21)
|
||||
#define PCIECFG_LTSSM_ENABLE BIT(20)
|
||||
#define PCIECFG_DEVICE_TYPE_MASK GENMASK(19, 16)
|
||||
#define PCIECFG_CLKREQ_B BIT(11)
|
||||
#define PCIECFG_REFCLK_ENABLE BIT(10)
|
||||
#define PCIECFG_PLL_ENABLE BIT(9)
|
||||
#define PCIECFG_PCLK_ENABLE BIT(8)
|
||||
#define PCIECFG_RISRCREN BIT(4)
|
||||
#define PCIECFG_MODE_TX_DRV_EN BIT(3)
|
||||
#define PCIECFG_CISRREN BIT(2)
|
||||
#define PCIECFG_MACRO_ENABLE BIT(0)
|
||||
/* ARTPEC-7 specific fields */
|
||||
#define PCIECFG_REFCLKSEL BIT(23)
|
||||
#define PCIECFG_NOC_RESET BIT(3)
|
||||
|
||||
#define PCIESTAT 0x1c
|
||||
/* ARTPEC-7 specific fields */
|
||||
#define PCIESTAT_EXTREFCLK BIT(3)
|
||||
|
||||
#define NOCCFG 0x40
|
||||
#define NOCCFG_ENABLE_CLK_PCIE (1 << 4)
|
||||
#define NOCCFG_POWER_PCIE_IDLEACK (1 << 3)
|
||||
#define NOCCFG_POWER_PCIE_IDLE (1 << 2)
|
||||
#define NOCCFG_POWER_PCIE_IDLEREQ (1 << 1)
|
||||
#define NOCCFG_ENABLE_CLK_PCIE BIT(4)
|
||||
#define NOCCFG_POWER_PCIE_IDLEACK BIT(3)
|
||||
#define NOCCFG_POWER_PCIE_IDLE BIT(2)
|
||||
#define NOCCFG_POWER_PCIE_IDLEREQ BIT(1)
|
||||
|
||||
#define PHY_STATUS 0x118
|
||||
#define PHY_COSPLLLOCK (1 << 0)
|
||||
#define PHY_COSPLLLOCK BIT(0)
|
||||
|
||||
#define ARTPEC6_CPU_TO_BUS_ADDR 0x0fffffff
|
||||
#define PHY_TX_ASIC_OUT 0x4040
|
||||
#define PHY_TX_ASIC_OUT_TX_ACK BIT(0)
|
||||
|
||||
#define PHY_RX_ASIC_OUT 0x405c
|
||||
#define PHY_RX_ASIC_OUT_ACK BIT(0)
|
||||
|
||||
static u32 artpec6_pcie_readl(struct artpec6_pcie *artpec6_pcie, u32 offset)
|
||||
{
|
||||
|
|
@ -78,22 +104,123 @@ static void artpec6_pcie_writel(struct artpec6_pcie *artpec6_pcie, u32 offset, u
|
|||
regmap_write(artpec6_pcie->regmap, offset, val);
|
||||
}
|
||||
|
||||
static u64 artpec6_pcie_cpu_addr_fixup(u64 pci_addr)
|
||||
static u64 artpec6_pcie_cpu_addr_fixup(struct dw_pcie *pci, u64 pci_addr)
|
||||
{
|
||||
return pci_addr & ARTPEC6_CPU_TO_BUS_ADDR;
|
||||
struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pci);
|
||||
struct pcie_port *pp = &pci->pp;
|
||||
struct dw_pcie_ep *ep = &pci->ep;
|
||||
|
||||
switch (artpec6_pcie->mode) {
|
||||
case DW_PCIE_RC_TYPE:
|
||||
return pci_addr - pp->cfg0_base;
|
||||
case DW_PCIE_EP_TYPE:
|
||||
return pci_addr - ep->phys_base;
|
||||
default:
|
||||
dev_err(pci->dev, "UNKNOWN device type\n");
|
||||
}
|
||||
return pci_addr;
|
||||
}
|
||||
|
||||
static int artpec6_pcie_establish_link(struct artpec6_pcie *artpec6_pcie)
|
||||
static int artpec6_pcie_establish_link(struct dw_pcie *pci)
|
||||
{
|
||||
struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pci);
|
||||
u32 val;
|
||||
|
||||
val = artpec6_pcie_readl(artpec6_pcie, PCIECFG);
|
||||
val |= PCIECFG_LTSSM_ENABLE;
|
||||
artpec6_pcie_writel(artpec6_pcie, PCIECFG, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void artpec6_pcie_stop_link(struct dw_pcie *pci)
|
||||
{
|
||||
struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pci);
|
||||
u32 val;
|
||||
|
||||
val = artpec6_pcie_readl(artpec6_pcie, PCIECFG);
|
||||
val &= ~PCIECFG_LTSSM_ENABLE;
|
||||
artpec6_pcie_writel(artpec6_pcie, PCIECFG, val);
|
||||
}
|
||||
|
||||
static const struct dw_pcie_ops dw_pcie_ops = {
|
||||
.cpu_addr_fixup = artpec6_pcie_cpu_addr_fixup,
|
||||
.start_link = artpec6_pcie_establish_link,
|
||||
.stop_link = artpec6_pcie_stop_link,
|
||||
};
|
||||
|
||||
static void artpec6_pcie_wait_for_phy_a6(struct artpec6_pcie *artpec6_pcie)
|
||||
{
|
||||
struct dw_pcie *pci = artpec6_pcie->pci;
|
||||
struct pcie_port *pp = &pci->pp;
|
||||
struct device *dev = pci->dev;
|
||||
u32 val;
|
||||
unsigned int retries;
|
||||
|
||||
/* Hold DW core in reset */
|
||||
val = artpec6_pcie_readl(artpec6_pcie, PCIECFG);
|
||||
val |= PCIECFG_CORE_RESET_REQ;
|
||||
artpec6_pcie_writel(artpec6_pcie, PCIECFG, val);
|
||||
retries = 50;
|
||||
do {
|
||||
usleep_range(1000, 2000);
|
||||
val = artpec6_pcie_readl(artpec6_pcie, NOCCFG);
|
||||
retries--;
|
||||
} while (retries &&
|
||||
(val & (NOCCFG_POWER_PCIE_IDLEACK | NOCCFG_POWER_PCIE_IDLE)));
|
||||
if (!retries)
|
||||
dev_err(dev, "PCIe clock manager did not leave idle state\n");
|
||||
|
||||
retries = 50;
|
||||
do {
|
||||
usleep_range(1000, 2000);
|
||||
val = readl(artpec6_pcie->phy_base + PHY_STATUS);
|
||||
retries--;
|
||||
} while (retries && !(val & PHY_COSPLLLOCK));
|
||||
if (!retries)
|
||||
dev_err(dev, "PHY PLL did not lock\n");
|
||||
}
|
||||
|
||||
static void artpec6_pcie_wait_for_phy_a7(struct artpec6_pcie *artpec6_pcie)
|
||||
{
|
||||
struct dw_pcie *pci = artpec6_pcie->pci;
|
||||
struct device *dev = pci->dev;
|
||||
u32 val;
|
||||
u16 phy_status_tx, phy_status_rx;
|
||||
unsigned int retries;
|
||||
|
||||
retries = 50;
|
||||
do {
|
||||
usleep_range(1000, 2000);
|
||||
val = artpec6_pcie_readl(artpec6_pcie, NOCCFG);
|
||||
retries--;
|
||||
} while (retries &&
|
||||
(val & (NOCCFG_POWER_PCIE_IDLEACK | NOCCFG_POWER_PCIE_IDLE)));
|
||||
if (!retries)
|
||||
dev_err(dev, "PCIe clock manager did not leave idle state\n");
|
||||
|
||||
retries = 50;
|
||||
do {
|
||||
usleep_range(1000, 2000);
|
||||
phy_status_tx = readw(artpec6_pcie->phy_base + PHY_TX_ASIC_OUT);
|
||||
phy_status_rx = readw(artpec6_pcie->phy_base + PHY_RX_ASIC_OUT);
|
||||
retries--;
|
||||
} while (retries && ((phy_status_tx & PHY_TX_ASIC_OUT_TX_ACK) ||
|
||||
(phy_status_rx & PHY_RX_ASIC_OUT_ACK)));
|
||||
if (!retries)
|
||||
dev_err(dev, "PHY did not enter Pn state\n");
|
||||
}
|
||||
|
||||
static void artpec6_pcie_wait_for_phy(struct artpec6_pcie *artpec6_pcie)
|
||||
{
|
||||
switch (artpec6_pcie->variant) {
|
||||
case ARTPEC6:
|
||||
artpec6_pcie_wait_for_phy_a6(artpec6_pcie);
|
||||
break;
|
||||
case ARTPEC7:
|
||||
artpec6_pcie_wait_for_phy_a7(artpec6_pcie);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void artpec6_pcie_init_phy_a6(struct artpec6_pcie *artpec6_pcie)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = artpec6_pcie_readl(artpec6_pcie, PCIECFG);
|
||||
val |= PCIECFG_RISRCREN | /* Receiver term. 50 Ohm */
|
||||
|
|
@ -119,45 +246,110 @@ static int artpec6_pcie_establish_link(struct artpec6_pcie *artpec6_pcie)
|
|||
val = artpec6_pcie_readl(artpec6_pcie, NOCCFG);
|
||||
val &= ~NOCCFG_POWER_PCIE_IDLEREQ;
|
||||
artpec6_pcie_writel(artpec6_pcie, NOCCFG, val);
|
||||
}
|
||||
|
||||
retries = 50;
|
||||
do {
|
||||
usleep_range(1000, 2000);
|
||||
val = artpec6_pcie_readl(artpec6_pcie, NOCCFG);
|
||||
retries--;
|
||||
} while (retries &&
|
||||
(val & (NOCCFG_POWER_PCIE_IDLEACK | NOCCFG_POWER_PCIE_IDLE)));
|
||||
static void artpec6_pcie_init_phy_a7(struct artpec6_pcie *artpec6_pcie)
|
||||
{
|
||||
struct dw_pcie *pci = artpec6_pcie->pci;
|
||||
u32 val;
|
||||
bool extrefclk;
|
||||
|
||||
retries = 50;
|
||||
do {
|
||||
usleep_range(1000, 2000);
|
||||
val = readl(artpec6_pcie->phy_base + PHY_STATUS);
|
||||
retries--;
|
||||
} while (retries && !(val & PHY_COSPLLLOCK));
|
||||
/* Check if external reference clock is connected */
|
||||
val = artpec6_pcie_readl(artpec6_pcie, PCIESTAT);
|
||||
extrefclk = !!(val & PCIESTAT_EXTREFCLK);
|
||||
dev_dbg(pci->dev, "Using reference clock: %s\n",
|
||||
extrefclk ? "external" : "internal");
|
||||
|
||||
/* Take DW core out of reset */
|
||||
val = artpec6_pcie_readl(artpec6_pcie, PCIECFG);
|
||||
val &= ~PCIECFG_CORE_RESET_REQ;
|
||||
val |= PCIECFG_RISRCREN | /* Receiver term. 50 Ohm */
|
||||
PCIECFG_PCLK_ENABLE;
|
||||
if (extrefclk)
|
||||
val |= PCIECFG_REFCLKSEL;
|
||||
else
|
||||
val &= ~PCIECFG_REFCLKSEL;
|
||||
artpec6_pcie_writel(artpec6_pcie, PCIECFG, val);
|
||||
usleep_range(10, 20);
|
||||
|
||||
val = artpec6_pcie_readl(artpec6_pcie, NOCCFG);
|
||||
val |= NOCCFG_ENABLE_CLK_PCIE;
|
||||
artpec6_pcie_writel(artpec6_pcie, NOCCFG, val);
|
||||
usleep_range(20, 30);
|
||||
|
||||
val = artpec6_pcie_readl(artpec6_pcie, NOCCFG);
|
||||
val &= ~NOCCFG_POWER_PCIE_IDLEREQ;
|
||||
artpec6_pcie_writel(artpec6_pcie, NOCCFG, val);
|
||||
}
|
||||
|
||||
static void artpec6_pcie_init_phy(struct artpec6_pcie *artpec6_pcie)
|
||||
{
|
||||
switch (artpec6_pcie->variant) {
|
||||
case ARTPEC6:
|
||||
artpec6_pcie_init_phy_a6(artpec6_pcie);
|
||||
break;
|
||||
case ARTPEC7:
|
||||
artpec6_pcie_init_phy_a7(artpec6_pcie);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void artpec6_pcie_set_nfts(struct artpec6_pcie *artpec6_pcie)
|
||||
{
|
||||
struct dw_pcie *pci = artpec6_pcie->pci;
|
||||
u32 val;
|
||||
|
||||
if (artpec6_pcie->variant != ARTPEC7)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Increase the N_FTS (Number of Fast Training Sequences)
|
||||
* to be transmitted when transitioning from L0s to L0.
|
||||
*/
|
||||
val = dw_pcie_readl_dbi(pci, ACK_F_ASPM_CTRL_OFF);
|
||||
val &= ~ACK_N_FTS_MASK;
|
||||
val |= ACK_N_FTS(180);
|
||||
dw_pcie_writel_dbi(pci, ACK_F_ASPM_CTRL_OFF, val);
|
||||
|
||||
/*
|
||||
* Set the Number of Fast Training Sequences that the core
|
||||
* advertises as its N_FTS during Gen2 or Gen3 link training.
|
||||
*/
|
||||
val = dw_pcie_readl_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL);
|
||||
val &= ~FAST_TRAINING_SEQ_MASK;
|
||||
val |= FAST_TRAINING_SEQ(180);
|
||||
dw_pcie_writel_dbi(pci, PCIE_LINK_WIDTH_SPEED_CONTROL, val);
|
||||
}
|
||||
|
||||
static void artpec6_pcie_assert_core_reset(struct artpec6_pcie *artpec6_pcie)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = artpec6_pcie_readl(artpec6_pcie, PCIECFG);
|
||||
switch (artpec6_pcie->variant) {
|
||||
case ARTPEC6:
|
||||
val |= PCIECFG_CORE_RESET_REQ;
|
||||
break;
|
||||
case ARTPEC7:
|
||||
val &= ~PCIECFG_NOC_RESET;
|
||||
break;
|
||||
}
|
||||
artpec6_pcie_writel(artpec6_pcie, PCIECFG, val);
|
||||
}
|
||||
|
||||
static void artpec6_pcie_deassert_core_reset(struct artpec6_pcie *artpec6_pcie)
|
||||
{
|
||||
u32 val;
|
||||
|
||||
val = artpec6_pcie_readl(artpec6_pcie, PCIECFG);
|
||||
switch (artpec6_pcie->variant) {
|
||||
case ARTPEC6:
|
||||
val &= ~PCIECFG_CORE_RESET_REQ;
|
||||
break;
|
||||
case ARTPEC7:
|
||||
val |= PCIECFG_NOC_RESET;
|
||||
break;
|
||||
}
|
||||
artpec6_pcie_writel(artpec6_pcie, PCIECFG, val);
|
||||
usleep_range(100, 200);
|
||||
|
||||
/* setup root complex */
|
||||
dw_pcie_setup_rc(pp);
|
||||
|
||||
/* assert LTSSM enable */
|
||||
val = artpec6_pcie_readl(artpec6_pcie, PCIECFG);
|
||||
val |= PCIECFG_LTSSM_ENABLE;
|
||||
artpec6_pcie_writel(artpec6_pcie, PCIECFG, val);
|
||||
|
||||
/* check if the link is up or not */
|
||||
if (!dw_pcie_wait_for_link(pci))
|
||||
return 0;
|
||||
|
||||
dev_dbg(pci->dev, "DEBUG_R0: 0x%08x, DEBUG_R1: 0x%08x\n",
|
||||
dw_pcie_readl_dbi(pci, PCIE_PHY_DEBUG_R0),
|
||||
dw_pcie_readl_dbi(pci, PCIE_PHY_DEBUG_R1));
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static void artpec6_pcie_enable_interrupts(struct artpec6_pcie *artpec6_pcie)
|
||||
|
|
@ -174,7 +366,14 @@ static int artpec6_pcie_host_init(struct pcie_port *pp)
|
|||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pci);
|
||||
|
||||
artpec6_pcie_establish_link(artpec6_pcie);
|
||||
artpec6_pcie_assert_core_reset(artpec6_pcie);
|
||||
artpec6_pcie_init_phy(artpec6_pcie);
|
||||
artpec6_pcie_deassert_core_reset(artpec6_pcie);
|
||||
artpec6_pcie_wait_for_phy(artpec6_pcie);
|
||||
artpec6_pcie_set_nfts(artpec6_pcie);
|
||||
dw_pcie_setup_rc(pp);
|
||||
artpec6_pcie_establish_link(pci);
|
||||
dw_pcie_wait_for_link(pci);
|
||||
artpec6_pcie_enable_interrupts(artpec6_pcie);
|
||||
|
||||
return 0;
|
||||
|
|
@ -230,10 +429,78 @@ static int artpec6_add_pcie_port(struct artpec6_pcie *artpec6_pcie,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static const struct dw_pcie_ops dw_pcie_ops = {
|
||||
.cpu_addr_fixup = artpec6_pcie_cpu_addr_fixup,
|
||||
static void artpec6_pcie_ep_init(struct dw_pcie_ep *ep)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
struct artpec6_pcie *artpec6_pcie = to_artpec6_pcie(pci);
|
||||
enum pci_barno bar;
|
||||
|
||||
artpec6_pcie_assert_core_reset(artpec6_pcie);
|
||||
artpec6_pcie_init_phy(artpec6_pcie);
|
||||
artpec6_pcie_deassert_core_reset(artpec6_pcie);
|
||||
artpec6_pcie_wait_for_phy(artpec6_pcie);
|
||||
artpec6_pcie_set_nfts(artpec6_pcie);
|
||||
|
||||
for (bar = BAR_0; bar <= BAR_5; bar++)
|
||||
dw_pcie_ep_reset_bar(pci, bar);
|
||||
}
|
||||
|
||||
static int artpec6_pcie_raise_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
enum pci_epc_irq_type type, u8 interrupt_num)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
|
||||
switch (type) {
|
||||
case PCI_EPC_IRQ_LEGACY:
|
||||
dev_err(pci->dev, "EP cannot trigger legacy IRQs\n");
|
||||
return -EINVAL;
|
||||
case PCI_EPC_IRQ_MSI:
|
||||
return dw_pcie_ep_raise_msi_irq(ep, func_no, interrupt_num);
|
||||
default:
|
||||
dev_err(pci->dev, "UNKNOWN IRQ type\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct dw_pcie_ep_ops pcie_ep_ops = {
|
||||
.ep_init = artpec6_pcie_ep_init,
|
||||
.raise_irq = artpec6_pcie_raise_irq,
|
||||
};
|
||||
|
||||
static int artpec6_add_pcie_ep(struct artpec6_pcie *artpec6_pcie,
|
||||
struct platform_device *pdev)
|
||||
{
|
||||
int ret;
|
||||
struct dw_pcie_ep *ep;
|
||||
struct resource *res;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct dw_pcie *pci = artpec6_pcie->pci;
|
||||
|
||||
ep = &pci->ep;
|
||||
ep->ops = &pcie_ep_ops;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi2");
|
||||
pci->dbi_base2 = devm_ioremap(dev, res->start, resource_size(res));
|
||||
if (!pci->dbi_base2)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "addr_space");
|
||||
if (!res)
|
||||
return -EINVAL;
|
||||
|
||||
ep->phys_base = res->start;
|
||||
ep->addr_size = resource_size(res);
|
||||
|
||||
ret = dw_pcie_ep_init(ep);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to initialize endpoint\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int artpec6_pcie_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
|
|
@ -242,6 +509,18 @@ static int artpec6_pcie_probe(struct platform_device *pdev)
|
|||
struct resource *dbi_base;
|
||||
struct resource *phy_base;
|
||||
int ret;
|
||||
const struct of_device_id *match;
|
||||
const struct artpec_pcie_of_data *data;
|
||||
enum artpec_pcie_variants variant;
|
||||
enum dw_pcie_device_mode mode;
|
||||
|
||||
match = of_match_device(artpec6_pcie_of_match, dev);
|
||||
if (!match)
|
||||
return -EINVAL;
|
||||
|
||||
data = (struct artpec_pcie_of_data *)match->data;
|
||||
variant = (enum artpec_pcie_variants)data->variant;
|
||||
mode = (enum dw_pcie_device_mode)data->mode;
|
||||
|
||||
artpec6_pcie = devm_kzalloc(dev, sizeof(*artpec6_pcie), GFP_KERNEL);
|
||||
if (!artpec6_pcie)
|
||||
|
|
@ -255,6 +534,8 @@ static int artpec6_pcie_probe(struct platform_device *pdev)
|
|||
pci->ops = &dw_pcie_ops;
|
||||
|
||||
artpec6_pcie->pci = pci;
|
||||
artpec6_pcie->variant = variant;
|
||||
artpec6_pcie->mode = mode;
|
||||
|
||||
dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
|
||||
pci->dbi_base = devm_ioremap_resource(dev, dbi_base);
|
||||
|
|
@ -274,15 +555,73 @@ static int artpec6_pcie_probe(struct platform_device *pdev)
|
|||
|
||||
platform_set_drvdata(pdev, artpec6_pcie);
|
||||
|
||||
ret = artpec6_add_pcie_port(artpec6_pcie, pdev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
switch (artpec6_pcie->mode) {
|
||||
case DW_PCIE_RC_TYPE:
|
||||
if (!IS_ENABLED(CONFIG_PCIE_ARTPEC6_HOST))
|
||||
return -ENODEV;
|
||||
|
||||
ret = artpec6_add_pcie_port(artpec6_pcie, pdev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
break;
|
||||
case DW_PCIE_EP_TYPE: {
|
||||
u32 val;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_PCIE_ARTPEC6_EP))
|
||||
return -ENODEV;
|
||||
|
||||
val = artpec6_pcie_readl(artpec6_pcie, PCIECFG);
|
||||
val &= ~PCIECFG_DEVICE_TYPE_MASK;
|
||||
artpec6_pcie_writel(artpec6_pcie, PCIECFG, val);
|
||||
ret = artpec6_add_pcie_ep(artpec6_pcie, pdev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
dev_err(dev, "INVALID device type %d\n", artpec6_pcie->mode);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct artpec_pcie_of_data artpec6_pcie_rc_of_data = {
|
||||
.variant = ARTPEC6,
|
||||
.mode = DW_PCIE_RC_TYPE,
|
||||
};
|
||||
|
||||
static const struct artpec_pcie_of_data artpec6_pcie_ep_of_data = {
|
||||
.variant = ARTPEC6,
|
||||
.mode = DW_PCIE_EP_TYPE,
|
||||
};
|
||||
|
||||
static const struct artpec_pcie_of_data artpec7_pcie_rc_of_data = {
|
||||
.variant = ARTPEC7,
|
||||
.mode = DW_PCIE_RC_TYPE,
|
||||
};
|
||||
|
||||
static const struct artpec_pcie_of_data artpec7_pcie_ep_of_data = {
|
||||
.variant = ARTPEC7,
|
||||
.mode = DW_PCIE_EP_TYPE,
|
||||
};
|
||||
|
||||
static const struct of_device_id artpec6_pcie_of_match[] = {
|
||||
{ .compatible = "axis,artpec6-pcie", },
|
||||
{
|
||||
.compatible = "axis,artpec6-pcie",
|
||||
.data = &artpec6_pcie_rc_of_data,
|
||||
},
|
||||
{
|
||||
.compatible = "axis,artpec6-pcie-ep",
|
||||
.data = &artpec6_pcie_ep_of_data,
|
||||
},
|
||||
{
|
||||
.compatible = "axis,artpec7-pcie",
|
||||
.data = &artpec7_pcie_rc_of_data,
|
||||
},
|
||||
{
|
||||
.compatible = "axis,artpec7-pcie-ep",
|
||||
.data = &artpec7_pcie_ep_of_data,
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,20 +1,9 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/**
|
||||
* Synopsys DesignWare PCIe Endpoint controller driver
|
||||
*
|
||||
* Copyright (C) 2017 Texas Instruments
|
||||
* Author: Kishon Vijay Abraham I <kishon@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 of
|
||||
* the License as published by the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/of.h>
|
||||
|
|
@ -30,21 +19,24 @@ void dw_pcie_ep_linkup(struct dw_pcie_ep *ep)
|
|||
pci_epc_linkup(epc);
|
||||
}
|
||||
|
||||
static void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar)
|
||||
void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar)
|
||||
{
|
||||
u32 reg;
|
||||
|
||||
reg = PCI_BASE_ADDRESS_0 + (4 * bar);
|
||||
dw_pcie_dbi_ro_wr_en(pci);
|
||||
dw_pcie_writel_dbi2(pci, reg, 0x0);
|
||||
dw_pcie_writel_dbi(pci, reg, 0x0);
|
||||
dw_pcie_dbi_ro_wr_dis(pci);
|
||||
}
|
||||
|
||||
static int dw_pcie_ep_write_header(struct pci_epc *epc,
|
||||
static int dw_pcie_ep_write_header(struct pci_epc *epc, u8 func_no,
|
||||
struct pci_epf_header *hdr)
|
||||
{
|
||||
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
|
||||
dw_pcie_dbi_ro_wr_en(pci);
|
||||
dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, hdr->vendorid);
|
||||
dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, hdr->deviceid);
|
||||
dw_pcie_writeb_dbi(pci, PCI_REVISION_ID, hdr->revid);
|
||||
|
|
@ -58,6 +50,7 @@ static int dw_pcie_ep_write_header(struct pci_epc *epc,
|
|||
dw_pcie_writew_dbi(pci, PCI_SUBSYSTEM_ID, hdr->subsys_id);
|
||||
dw_pcie_writeb_dbi(pci, PCI_INTERRUPT_PIN,
|
||||
hdr->interrupt_pin);
|
||||
dw_pcie_dbi_ro_wr_dis(pci);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -70,8 +63,7 @@ static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, enum pci_barno bar,
|
|||
u32 free_win;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
|
||||
free_win = find_first_zero_bit(&ep->ib_window_map,
|
||||
sizeof(ep->ib_window_map));
|
||||
free_win = find_first_zero_bit(ep->ib_window_map, ep->num_ib_windows);
|
||||
if (free_win >= ep->num_ib_windows) {
|
||||
dev_err(pci->dev, "no free inbound window\n");
|
||||
return -EINVAL;
|
||||
|
|
@ -85,7 +77,7 @@ static int dw_pcie_ep_inbound_atu(struct dw_pcie_ep *ep, enum pci_barno bar,
|
|||
}
|
||||
|
||||
ep->bar_to_atu[bar] = free_win;
|
||||
set_bit(free_win, &ep->ib_window_map);
|
||||
set_bit(free_win, ep->ib_window_map);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -96,8 +88,7 @@ static int dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, phys_addr_t phys_addr,
|
|||
u32 free_win;
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
|
||||
free_win = find_first_zero_bit(&ep->ob_window_map,
|
||||
sizeof(ep->ob_window_map));
|
||||
free_win = find_first_zero_bit(ep->ob_window_map, ep->num_ob_windows);
|
||||
if (free_win >= ep->num_ob_windows) {
|
||||
dev_err(pci->dev, "no free outbound window\n");
|
||||
return -EINVAL;
|
||||
|
|
@ -106,13 +97,14 @@ static int dw_pcie_ep_outbound_atu(struct dw_pcie_ep *ep, phys_addr_t phys_addr,
|
|||
dw_pcie_prog_outbound_atu(pci, free_win, PCIE_ATU_TYPE_MEM,
|
||||
phys_addr, pci_addr, size);
|
||||
|
||||
set_bit(free_win, &ep->ob_window_map);
|
||||
set_bit(free_win, ep->ob_window_map);
|
||||
ep->outbound_addr[free_win] = phys_addr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void dw_pcie_ep_clear_bar(struct pci_epc *epc, enum pci_barno bar)
|
||||
static void dw_pcie_ep_clear_bar(struct pci_epc *epc, u8 func_no,
|
||||
enum pci_barno bar)
|
||||
{
|
||||
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
|
|
@ -121,10 +113,11 @@ static void dw_pcie_ep_clear_bar(struct pci_epc *epc, enum pci_barno bar)
|
|||
dw_pcie_ep_reset_bar(pci, bar);
|
||||
|
||||
dw_pcie_disable_atu(pci, atu_index, DW_PCIE_REGION_INBOUND);
|
||||
clear_bit(atu_index, &ep->ib_window_map);
|
||||
clear_bit(atu_index, ep->ib_window_map);
|
||||
}
|
||||
|
||||
static int dw_pcie_ep_set_bar(struct pci_epc *epc, enum pci_barno bar,
|
||||
static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no,
|
||||
enum pci_barno bar,
|
||||
dma_addr_t bar_phys, size_t size, int flags)
|
||||
{
|
||||
int ret;
|
||||
|
|
@ -142,8 +135,10 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, enum pci_barno bar,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
dw_pcie_dbi_ro_wr_en(pci);
|
||||
dw_pcie_writel_dbi2(pci, reg, size - 1);
|
||||
dw_pcie_writel_dbi(pci, reg, flags);
|
||||
dw_pcie_dbi_ro_wr_dis(pci);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -163,7 +158,8 @@ static int dw_pcie_find_index(struct dw_pcie_ep *ep, phys_addr_t addr,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void dw_pcie_ep_unmap_addr(struct pci_epc *epc, phys_addr_t addr)
|
||||
static void dw_pcie_ep_unmap_addr(struct pci_epc *epc, u8 func_no,
|
||||
phys_addr_t addr)
|
||||
{
|
||||
int ret;
|
||||
u32 atu_index;
|
||||
|
|
@ -175,10 +171,11 @@ static void dw_pcie_ep_unmap_addr(struct pci_epc *epc, phys_addr_t addr)
|
|||
return;
|
||||
|
||||
dw_pcie_disable_atu(pci, atu_index, DW_PCIE_REGION_OUTBOUND);
|
||||
clear_bit(atu_index, &ep->ob_window_map);
|
||||
clear_bit(atu_index, ep->ob_window_map);
|
||||
}
|
||||
|
||||
static int dw_pcie_ep_map_addr(struct pci_epc *epc, phys_addr_t addr,
|
||||
static int dw_pcie_ep_map_addr(struct pci_epc *epc, u8 func_no,
|
||||
phys_addr_t addr,
|
||||
u64 pci_addr, size_t size)
|
||||
{
|
||||
int ret;
|
||||
|
|
@ -194,39 +191,37 @@ static int dw_pcie_ep_map_addr(struct pci_epc *epc, phys_addr_t addr,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int dw_pcie_ep_get_msi(struct pci_epc *epc)
|
||||
static int dw_pcie_ep_get_msi(struct pci_epc *epc, u8 func_no)
|
||||
{
|
||||
int val;
|
||||
u32 lower_addr;
|
||||
u32 upper_addr;
|
||||
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
|
||||
val = dw_pcie_readb_dbi(pci, MSI_MESSAGE_CONTROL);
|
||||
val = (val & MSI_CAP_MME_MASK) >> MSI_CAP_MME_SHIFT;
|
||||
|
||||
lower_addr = dw_pcie_readl_dbi(pci, MSI_MESSAGE_ADDR_L32);
|
||||
upper_addr = dw_pcie_readl_dbi(pci, MSI_MESSAGE_ADDR_U32);
|
||||
|
||||
if (!(lower_addr || upper_addr))
|
||||
val = dw_pcie_readw_dbi(pci, MSI_MESSAGE_CONTROL);
|
||||
if (!(val & MSI_CAP_MSI_EN_MASK))
|
||||
return -EINVAL;
|
||||
|
||||
val = (val & MSI_CAP_MME_MASK) >> MSI_CAP_MME_SHIFT;
|
||||
return val;
|
||||
}
|
||||
|
||||
static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 encode_int)
|
||||
static int dw_pcie_ep_set_msi(struct pci_epc *epc, u8 func_no, u8 encode_int)
|
||||
{
|
||||
int val;
|
||||
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
|
||||
val = (encode_int << MSI_CAP_MMC_SHIFT);
|
||||
val = dw_pcie_readw_dbi(pci, MSI_MESSAGE_CONTROL);
|
||||
val &= ~MSI_CAP_MMC_MASK;
|
||||
val |= (encode_int << MSI_CAP_MMC_SHIFT) & MSI_CAP_MMC_MASK;
|
||||
dw_pcie_dbi_ro_wr_en(pci);
|
||||
dw_pcie_writew_dbi(pci, MSI_MESSAGE_CONTROL, val);
|
||||
dw_pcie_dbi_ro_wr_dis(pci);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dw_pcie_ep_raise_irq(struct pci_epc *epc,
|
||||
static int dw_pcie_ep_raise_irq(struct pci_epc *epc, u8 func_no,
|
||||
enum pci_epc_irq_type type, u8 interrupt_num)
|
||||
{
|
||||
struct dw_pcie_ep *ep = epc_get_drvdata(epc);
|
||||
|
|
@ -234,7 +229,7 @@ static int dw_pcie_ep_raise_irq(struct pci_epc *epc,
|
|||
if (!ep->ops->raise_irq)
|
||||
return -EINVAL;
|
||||
|
||||
return ep->ops->raise_irq(ep, type, interrupt_num);
|
||||
return ep->ops->raise_irq(ep, func_no, type, interrupt_num);
|
||||
}
|
||||
|
||||
static void dw_pcie_ep_stop(struct pci_epc *epc)
|
||||
|
|
@ -272,10 +267,48 @@ static const struct pci_epc_ops epc_ops = {
|
|||
.stop = dw_pcie_ep_stop,
|
||||
};
|
||||
|
||||
int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
u8 interrupt_num)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_ep(ep);
|
||||
struct pci_epc *epc = ep->epc;
|
||||
u16 msg_ctrl, msg_data;
|
||||
u32 msg_addr_lower, msg_addr_upper;
|
||||
u64 msg_addr;
|
||||
bool has_upper;
|
||||
int ret;
|
||||
|
||||
/* Raise MSI per the PCI Local Bus Specification Revision 3.0, 6.8.1. */
|
||||
msg_ctrl = dw_pcie_readw_dbi(pci, MSI_MESSAGE_CONTROL);
|
||||
has_upper = !!(msg_ctrl & PCI_MSI_FLAGS_64BIT);
|
||||
msg_addr_lower = dw_pcie_readl_dbi(pci, MSI_MESSAGE_ADDR_L32);
|
||||
if (has_upper) {
|
||||
msg_addr_upper = dw_pcie_readl_dbi(pci, MSI_MESSAGE_ADDR_U32);
|
||||
msg_data = dw_pcie_readw_dbi(pci, MSI_MESSAGE_DATA_64);
|
||||
} else {
|
||||
msg_addr_upper = 0;
|
||||
msg_data = dw_pcie_readw_dbi(pci, MSI_MESSAGE_DATA_32);
|
||||
}
|
||||
msg_addr = ((u64) msg_addr_upper) << 32 | msg_addr_lower;
|
||||
ret = dw_pcie_ep_map_addr(epc, func_no, ep->msi_mem_phys, msg_addr,
|
||||
epc->mem->page_size);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
writel(msg_data | (interrupt_num - 1), ep->msi_mem);
|
||||
|
||||
dw_pcie_ep_unmap_addr(epc, func_no, ep->msi_mem_phys);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dw_pcie_ep_exit(struct dw_pcie_ep *ep)
|
||||
{
|
||||
struct pci_epc *epc = ep->epc;
|
||||
|
||||
pci_epc_mem_free_addr(epc, ep->msi_mem_phys, ep->msi_mem,
|
||||
epc->mem->page_size);
|
||||
|
||||
pci_epc_mem_exit(epc);
|
||||
}
|
||||
|
||||
|
|
@ -298,12 +331,32 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
|
|||
dev_err(dev, "unable to read *num-ib-windows* property\n");
|
||||
return ret;
|
||||
}
|
||||
if (ep->num_ib_windows > MAX_IATU_IN) {
|
||||
dev_err(dev, "invalid *num-ib-windows*\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32(np, "num-ob-windows", &ep->num_ob_windows);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "unable to read *num-ob-windows* property\n");
|
||||
return ret;
|
||||
}
|
||||
if (ep->num_ob_windows > MAX_IATU_OUT) {
|
||||
dev_err(dev, "invalid *num-ob-windows*\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ep->ib_window_map = devm_kzalloc(dev, sizeof(long) *
|
||||
BITS_TO_LONGS(ep->num_ib_windows),
|
||||
GFP_KERNEL);
|
||||
if (!ep->ib_window_map)
|
||||
return -ENOMEM;
|
||||
|
||||
ep->ob_window_map = devm_kzalloc(dev, sizeof(long) *
|
||||
BITS_TO_LONGS(ep->num_ob_windows),
|
||||
GFP_KERNEL);
|
||||
if (!ep->ob_window_map)
|
||||
return -ENOMEM;
|
||||
|
||||
addr = devm_kzalloc(dev, sizeof(phys_addr_t) * ep->num_ob_windows,
|
||||
GFP_KERNEL);
|
||||
|
|
@ -331,6 +384,13 @@ int dw_pcie_ep_init(struct dw_pcie_ep *ep)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ep->msi_mem = pci_epc_mem_alloc_addr(epc, &ep->msi_mem_phys,
|
||||
epc->mem->page_size);
|
||||
if (!ep->msi_mem) {
|
||||
dev_err(dev, "Failed to reserve memory for MSI\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ep->epc = epc;
|
||||
epc_set_drvdata(epc, ep);
|
||||
dw_pcie_setup(pci);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Synopsys DesignWare PCIe host controller driver
|
||||
*
|
||||
|
|
@ -5,10 +6,6 @@
|
|||
* http://www.samsung.com
|
||||
*
|
||||
* Author: Jingoo Han <jg1.han@samsung.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/irqdomain.h>
|
||||
|
|
@ -83,10 +80,19 @@ irqreturn_t dw_handle_msi_irq(struct pcie_port *pp)
|
|||
|
||||
void dw_pcie_msi_init(struct pcie_port *pp)
|
||||
{
|
||||
struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
|
||||
struct device *dev = pci->dev;
|
||||
struct page *page;
|
||||
u64 msi_target;
|
||||
|
||||
pp->msi_data = __get_free_pages(GFP_KERNEL, 0);
|
||||
msi_target = virt_to_phys((void *)pp->msi_data);
|
||||
page = alloc_page(GFP_KERNEL);
|
||||
pp->msi_data = dma_map_page(dev, page, 0, PAGE_SIZE, DMA_FROM_DEVICE);
|
||||
if (dma_mapping_error(dev, pp->msi_data)) {
|
||||
dev_err(dev, "failed to map MSI data\n");
|
||||
__free_page(page);
|
||||
return;
|
||||
}
|
||||
msi_target = (u64)pp->msi_data;
|
||||
|
||||
/* program the msi_data */
|
||||
dw_pcie_wr_own_conf(pp, PCIE_MSI_ADDR_LO, 4,
|
||||
|
|
@ -187,7 +193,7 @@ static void dw_msi_setup_msg(struct pcie_port *pp, unsigned int irq, u32 pos)
|
|||
if (pp->ops->get_msi_addr)
|
||||
msi_target = pp->ops->get_msi_addr(pp);
|
||||
else
|
||||
msi_target = virt_to_phys((void *)pp->msi_data);
|
||||
msi_target = (u64)pp->msi_data;
|
||||
|
||||
msg.address_lo = (u32)(msi_target & 0xffffffff);
|
||||
msg.address_hi = (u32)(msi_target >> 32 & 0xffffffff);
|
||||
|
|
|
|||
|
|
@ -1,13 +1,10 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* PCIe RC driver for Synopsys DesignWare Core
|
||||
*
|
||||
* Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com)
|
||||
*
|
||||
* Authors: Joao Pinto <Joao.Pinto@synopsys.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/clk.h>
|
||||
#include <linux/delay.h>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Synopsys DesignWare PCIe host controller driver
|
||||
*
|
||||
|
|
@ -5,10 +6,6 @@
|
|||
* http://www.samsung.com
|
||||
*
|
||||
* Author: Jingoo Han <jg1.han@samsung.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/delay.h>
|
||||
|
|
@ -149,7 +146,7 @@ void dw_pcie_prog_outbound_atu(struct dw_pcie *pci, int index, int type,
|
|||
u32 retries, val;
|
||||
|
||||
if (pci->ops->cpu_addr_fixup)
|
||||
cpu_addr = pci->ops->cpu_addr_fixup(cpu_addr);
|
||||
cpu_addr = pci->ops->cpu_addr_fixup(pci, cpu_addr);
|
||||
|
||||
if (pci->iatu_unroll_enabled) {
|
||||
dw_pcie_prog_outbound_atu_unroll(pci, index, type, cpu_addr,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Synopsys DesignWare PCIe host controller driver
|
||||
*
|
||||
|
|
@ -5,15 +6,12 @@
|
|||
* http://www.samsung.com
|
||||
*
|
||||
* Author: Jingoo Han <jg1.han@samsung.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.
|
||||
*/
|
||||
|
||||
#ifndef _PCIE_DESIGNWARE_H
|
||||
#define _PCIE_DESIGNWARE_H
|
||||
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/msi.h>
|
||||
#include <linux/pci.h>
|
||||
|
|
@ -100,10 +98,14 @@
|
|||
|
||||
#define MSI_MESSAGE_CONTROL 0x52
|
||||
#define MSI_CAP_MMC_SHIFT 1
|
||||
#define MSI_CAP_MMC_MASK (7 << MSI_CAP_MMC_SHIFT)
|
||||
#define MSI_CAP_MME_SHIFT 4
|
||||
#define MSI_CAP_MSI_EN_MASK 0x1
|
||||
#define MSI_CAP_MME_MASK (7 << MSI_CAP_MME_SHIFT)
|
||||
#define MSI_MESSAGE_ADDR_L32 0x54
|
||||
#define MSI_MESSAGE_ADDR_U32 0x58
|
||||
#define MSI_MESSAGE_DATA_32 0x58
|
||||
#define MSI_MESSAGE_DATA_64 0x5C
|
||||
|
||||
/*
|
||||
* Maximum number of MSI IRQs can be 256 per controller. But keep
|
||||
|
|
@ -113,6 +115,10 @@
|
|||
#define MAX_MSI_IRQS 32
|
||||
#define MAX_MSI_CTRLS (MAX_MSI_IRQS / 32)
|
||||
|
||||
/* Maximum number of inbound/outbound iATUs */
|
||||
#define MAX_IATU_IN 256
|
||||
#define MAX_IATU_OUT 256
|
||||
|
||||
struct pcie_port;
|
||||
struct dw_pcie;
|
||||
struct dw_pcie_ep;
|
||||
|
|
@ -168,7 +174,7 @@ struct pcie_port {
|
|||
const struct dw_pcie_host_ops *ops;
|
||||
int msi_irq;
|
||||
struct irq_domain *irq_domain;
|
||||
unsigned long msi_data;
|
||||
dma_addr_t msi_data;
|
||||
DECLARE_BITMAP(msi_irq_in_use, MAX_MSI_IRQS);
|
||||
};
|
||||
|
||||
|
|
@ -180,8 +186,8 @@ enum dw_pcie_as_type {
|
|||
|
||||
struct dw_pcie_ep_ops {
|
||||
void (*ep_init)(struct dw_pcie_ep *ep);
|
||||
int (*raise_irq)(struct dw_pcie_ep *ep, enum pci_epc_irq_type type,
|
||||
u8 interrupt_num);
|
||||
int (*raise_irq)(struct dw_pcie_ep *ep, u8 func_no,
|
||||
enum pci_epc_irq_type type, u8 interrupt_num);
|
||||
};
|
||||
|
||||
struct dw_pcie_ep {
|
||||
|
|
@ -192,14 +198,16 @@ struct dw_pcie_ep {
|
|||
size_t page_size;
|
||||
u8 bar_to_atu[6];
|
||||
phys_addr_t *outbound_addr;
|
||||
unsigned long ib_window_map;
|
||||
unsigned long ob_window_map;
|
||||
unsigned long *ib_window_map;
|
||||
unsigned long *ob_window_map;
|
||||
u32 num_ib_windows;
|
||||
u32 num_ob_windows;
|
||||
void __iomem *msi_mem;
|
||||
phys_addr_t msi_mem_phys;
|
||||
};
|
||||
|
||||
struct dw_pcie_ops {
|
||||
u64 (*cpu_addr_fixup)(u64 cpu_addr);
|
||||
u64 (*cpu_addr_fixup)(struct dw_pcie *pcie, u64 cpu_addr);
|
||||
u32 (*read_dbi)(struct dw_pcie *pcie, void __iomem *base, u32 reg,
|
||||
size_t size);
|
||||
void (*write_dbi)(struct dw_pcie *pcie, void __iomem *base, u32 reg,
|
||||
|
|
@ -334,6 +342,9 @@ static inline int dw_pcie_host_init(struct pcie_port *pp)
|
|||
void dw_pcie_ep_linkup(struct dw_pcie_ep *ep);
|
||||
int dw_pcie_ep_init(struct dw_pcie_ep *ep);
|
||||
void dw_pcie_ep_exit(struct dw_pcie_ep *ep);
|
||||
int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
u8 interrupt_num);
|
||||
void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar);
|
||||
#else
|
||||
static inline void dw_pcie_ep_linkup(struct dw_pcie_ep *ep)
|
||||
{
|
||||
|
|
@ -347,5 +358,15 @@ static inline int dw_pcie_ep_init(struct dw_pcie_ep *ep)
|
|||
static inline void dw_pcie_ep_exit(struct dw_pcie_ep *ep)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int dw_pcie_ep_raise_msi_irq(struct dw_pcie_ep *ep, u8 func_no,
|
||||
u8 interrupt_num)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void dw_pcie_ep_reset_bar(struct dw_pcie *pci, enum pci_barno bar)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
#endif /* _PCIE_DESIGNWARE_H */
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* PCIe host controller driver for HiSilicon SoCs
|
||||
*
|
||||
|
|
@ -6,10 +7,6 @@
|
|||
* Authors: Zhou Wang <wangzhou1@hisilicon.com>
|
||||
* Dacai Zhu <zhudacai@hisilicon.com>
|
||||
* Gabriele Paoloni <gabriele.paoloni@huawei.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/interrupt.h>
|
||||
#include <linux/init.h>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* PCIe host controller driver for HiSilicon STB SoCs
|
||||
*
|
||||
|
|
@ -5,10 +6,6 @@
|
|||
*
|
||||
* Authors: Ruqiang Ju <juruqiang@hisilicon.com>
|
||||
* Jianguo Sun <sunjianguo1@huawei.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/clk.h>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* PCIe host controller driver for Kirin Phone SoCs
|
||||
*
|
||||
|
|
@ -5,10 +6,6 @@
|
|||
* http://www.huawei.com
|
||||
*
|
||||
* Author: Xiaowei Song <songxiaowei@huawei.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 <asm/compiler.h>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Qualcomm PCIe root complex driver
|
||||
*
|
||||
|
|
@ -5,15 +6,6 @@
|
|||
* Copyright 2015 Linaro Limited.
|
||||
*
|
||||
* Author: Stanimir Varbanov <svarbanov@mm-sol.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 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* 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.h>
|
||||
|
|
@ -171,7 +163,7 @@ struct qcom_pcie {
|
|||
union qcom_pcie_resources res;
|
||||
struct phy *phy;
|
||||
struct gpio_desc *reset;
|
||||
struct qcom_pcie_ops *ops;
|
||||
const struct qcom_pcie_ops *ops;
|
||||
};
|
||||
|
||||
#define to_qcom_pcie(x) dev_get_drvdata((x)->dev)
|
||||
|
|
@ -1234,7 +1226,7 @@ static int qcom_pcie_probe(struct platform_device *pdev)
|
|||
|
||||
pcie->pci = pci;
|
||||
|
||||
pcie->ops = (struct qcom_pcie_ops *)of_device_get_match_data(dev);
|
||||
pcie->ops = of_device_get_match_data(dev);
|
||||
|
||||
pcie->reset = devm_gpiod_get_optional(dev, "perst", GPIOD_OUT_LOW);
|
||||
if (IS_ERR(pcie->reset))
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* PCIe host controller driver for ST Microelectronics SPEAr13xx SoCs
|
||||
*
|
||||
|
|
@ -6,10 +7,6 @@
|
|||
* Copyright (C) 2010-2014 ST Microelectronics
|
||||
* Pratyush Anand <pratyush.anand@gmail.com>
|
||||
* Mohit Kumar <mohit.kumar.dhaka@gmail.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
|
|
|
|||
|
|
@ -1,17 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright 2016 Broadcom
|
||||
*
|
||||
* 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 (the "GPL").
|
||||
*
|
||||
* 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 version 2 (GPLv2) for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* version 2 (GPLv2) along with this source code.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# PCI Endpoint Support
|
||||
#
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Makefile for PCI Endpoint Support
|
||||
#
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# PCI Endpoint Functions
|
||||
#
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Makefile for PCI Endpoint Functions
|
||||
#
|
||||
|
|
|
|||
|
|
@ -1,20 +1,9 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/**
|
||||
* Test driver to test endpoint functionality
|
||||
*
|
||||
* Copyright (C) 2017 Texas Instruments
|
||||
* Author: Kishon Vijay Abraham I <kishon@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 of
|
||||
* the License as published by the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/crc32.h>
|
||||
|
|
@ -104,7 +93,8 @@ static int pci_epf_test_copy(struct pci_epf_test *epf_test)
|
|||
goto err;
|
||||
}
|
||||
|
||||
ret = pci_epc_map_addr(epc, src_phys_addr, reg->src_addr, reg->size);
|
||||
ret = pci_epc_map_addr(epc, epf->func_no, src_phys_addr, reg->src_addr,
|
||||
reg->size);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to map source address\n");
|
||||
reg->status = STATUS_SRC_ADDR_INVALID;
|
||||
|
|
@ -119,7 +109,8 @@ static int pci_epf_test_copy(struct pci_epf_test *epf_test)
|
|||
goto err_src_map_addr;
|
||||
}
|
||||
|
||||
ret = pci_epc_map_addr(epc, dst_phys_addr, reg->dst_addr, reg->size);
|
||||
ret = pci_epc_map_addr(epc, epf->func_no, dst_phys_addr, reg->dst_addr,
|
||||
reg->size);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to map destination address\n");
|
||||
reg->status = STATUS_DST_ADDR_INVALID;
|
||||
|
|
@ -128,13 +119,13 @@ static int pci_epf_test_copy(struct pci_epf_test *epf_test)
|
|||
|
||||
memcpy(dst_addr, src_addr, reg->size);
|
||||
|
||||
pci_epc_unmap_addr(epc, dst_phys_addr);
|
||||
pci_epc_unmap_addr(epc, epf->func_no, dst_phys_addr);
|
||||
|
||||
err_dst_addr:
|
||||
pci_epc_mem_free_addr(epc, dst_phys_addr, dst_addr, reg->size);
|
||||
|
||||
err_src_map_addr:
|
||||
pci_epc_unmap_addr(epc, src_phys_addr);
|
||||
pci_epc_unmap_addr(epc, epf->func_no, src_phys_addr);
|
||||
|
||||
err_src_addr:
|
||||
pci_epc_mem_free_addr(epc, src_phys_addr, src_addr, reg->size);
|
||||
|
|
@ -164,7 +155,8 @@ static int pci_epf_test_read(struct pci_epf_test *epf_test)
|
|||
goto err;
|
||||
}
|
||||
|
||||
ret = pci_epc_map_addr(epc, phys_addr, reg->src_addr, reg->size);
|
||||
ret = pci_epc_map_addr(epc, epf->func_no, phys_addr, reg->src_addr,
|
||||
reg->size);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to map address\n");
|
||||
reg->status = STATUS_SRC_ADDR_INVALID;
|
||||
|
|
@ -186,7 +178,7 @@ static int pci_epf_test_read(struct pci_epf_test *epf_test)
|
|||
kfree(buf);
|
||||
|
||||
err_map_addr:
|
||||
pci_epc_unmap_addr(epc, phys_addr);
|
||||
pci_epc_unmap_addr(epc, epf->func_no, phys_addr);
|
||||
|
||||
err_addr:
|
||||
pci_epc_mem_free_addr(epc, phys_addr, src_addr, reg->size);
|
||||
|
|
@ -215,7 +207,8 @@ static int pci_epf_test_write(struct pci_epf_test *epf_test)
|
|||
goto err;
|
||||
}
|
||||
|
||||
ret = pci_epc_map_addr(epc, phys_addr, reg->dst_addr, reg->size);
|
||||
ret = pci_epc_map_addr(epc, epf->func_no, phys_addr, reg->dst_addr,
|
||||
reg->size);
|
||||
if (ret) {
|
||||
dev_err(dev, "failed to map address\n");
|
||||
reg->status = STATUS_DST_ADDR_INVALID;
|
||||
|
|
@ -242,7 +235,7 @@ static int pci_epf_test_write(struct pci_epf_test *epf_test)
|
|||
kfree(buf);
|
||||
|
||||
err_map_addr:
|
||||
pci_epc_unmap_addr(epc, phys_addr);
|
||||
pci_epc_unmap_addr(epc, epf->func_no, phys_addr);
|
||||
|
||||
err_addr:
|
||||
pci_epc_mem_free_addr(epc, phys_addr, dst_addr, reg->size);
|
||||
|
|
@ -260,11 +253,11 @@ static void pci_epf_test_raise_irq(struct pci_epf_test *epf_test, u8 irq)
|
|||
struct pci_epf_test_reg *reg = epf_test->reg[test_reg_bar];
|
||||
|
||||
reg->status |= STATUS_IRQ_RAISED;
|
||||
msi_count = pci_epc_get_msi(epc);
|
||||
msi_count = pci_epc_get_msi(epc, epf->func_no);
|
||||
if (irq > msi_count || msi_count <= 0)
|
||||
pci_epc_raise_irq(epc, PCI_EPC_IRQ_LEGACY, 0);
|
||||
pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_LEGACY, 0);
|
||||
else
|
||||
pci_epc_raise_irq(epc, PCI_EPC_IRQ_MSI, irq);
|
||||
pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_MSI, irq);
|
||||
}
|
||||
|
||||
static void pci_epf_test_cmd_handler(struct work_struct *work)
|
||||
|
|
@ -291,7 +284,7 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
|
|||
|
||||
if (command & COMMAND_RAISE_LEGACY_IRQ) {
|
||||
reg->status = STATUS_IRQ_RAISED;
|
||||
pci_epc_raise_irq(epc, PCI_EPC_IRQ_LEGACY, 0);
|
||||
pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_LEGACY, 0);
|
||||
goto reset_handler;
|
||||
}
|
||||
|
||||
|
|
@ -326,11 +319,11 @@ static void pci_epf_test_cmd_handler(struct work_struct *work)
|
|||
}
|
||||
|
||||
if (command & COMMAND_RAISE_MSI_IRQ) {
|
||||
msi_count = pci_epc_get_msi(epc);
|
||||
msi_count = pci_epc_get_msi(epc, epf->func_no);
|
||||
if (irq > msi_count || msi_count <= 0)
|
||||
goto reset_handler;
|
||||
reg->status = STATUS_IRQ_RAISED;
|
||||
pci_epc_raise_irq(epc, PCI_EPC_IRQ_MSI, irq);
|
||||
pci_epc_raise_irq(epc, epf->func_no, PCI_EPC_IRQ_MSI, irq);
|
||||
goto reset_handler;
|
||||
}
|
||||
|
||||
|
|
@ -358,7 +351,7 @@ static void pci_epf_test_unbind(struct pci_epf *epf)
|
|||
for (bar = BAR_0; bar <= BAR_5; bar++) {
|
||||
if (epf_test->reg[bar]) {
|
||||
pci_epf_free_space(epf, epf_test->reg[bar], bar);
|
||||
pci_epc_clear_bar(epc, bar);
|
||||
pci_epc_clear_bar(epc, epf->func_no, bar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -380,7 +373,8 @@ static int pci_epf_test_set_bar(struct pci_epf *epf)
|
|||
|
||||
for (bar = BAR_0; bar <= BAR_5; bar++) {
|
||||
epf_bar = &epf->bar[bar];
|
||||
ret = pci_epc_set_bar(epc, bar, epf_bar->phys_addr,
|
||||
ret = pci_epc_set_bar(epc, epf->func_no, bar,
|
||||
epf_bar->phys_addr,
|
||||
epf_bar->size, flags);
|
||||
if (ret) {
|
||||
pci_epf_free_space(epf, epf_test->reg[bar], bar);
|
||||
|
|
@ -433,7 +427,7 @@ static int pci_epf_test_bind(struct pci_epf *epf)
|
|||
if (WARN_ON_ONCE(!epc))
|
||||
return -EINVAL;
|
||||
|
||||
ret = pci_epc_write_header(epc, header);
|
||||
ret = pci_epc_write_header(epc, epf->func_no, header);
|
||||
if (ret) {
|
||||
dev_err(dev, "configuration header write failed\n");
|
||||
return ret;
|
||||
|
|
@ -447,7 +441,7 @@ static int pci_epf_test_bind(struct pci_epf *epf)
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pci_epc_set_msi(epc, epf->msi_interrupts);
|
||||
ret = pci_epc_set_msi(epc, epf->func_no, epf->msi_interrupts);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,35 +1,28 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/**
|
||||
* configfs to configure the PCI endpoint
|
||||
*
|
||||
* Copyright (C) 2017 Texas Instruments
|
||||
* Author: Kishon Vijay Abraham I <kishon@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 of
|
||||
* the License as published by the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/idr.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/pci-epc.h>
|
||||
#include <linux/pci-epf.h>
|
||||
#include <linux/pci-ep-cfs.h>
|
||||
|
||||
static DEFINE_IDR(functions_idr);
|
||||
static DEFINE_MUTEX(functions_mutex);
|
||||
static struct config_group *functions_group;
|
||||
static struct config_group *controllers_group;
|
||||
|
||||
struct pci_epf_group {
|
||||
struct config_group group;
|
||||
struct pci_epf *epf;
|
||||
int index;
|
||||
};
|
||||
|
||||
struct pci_epc_group {
|
||||
|
|
@ -97,22 +90,23 @@ static int pci_epc_epf_link(struct config_item *epc_item,
|
|||
{
|
||||
int ret;
|
||||
u32 func_no = 0;
|
||||
struct pci_epc *epc;
|
||||
struct pci_epf *epf;
|
||||
struct pci_epf_group *epf_group = to_pci_epf_group(epf_item);
|
||||
struct pci_epc_group *epc_group = to_pci_epc_group(epc_item);
|
||||
struct pci_epc *epc = epc_group->epc;
|
||||
struct pci_epf *epf = epf_group->epf;
|
||||
|
||||
func_no = find_first_zero_bit(&epc_group->function_num_map,
|
||||
BITS_PER_LONG);
|
||||
if (func_no >= BITS_PER_LONG)
|
||||
return -EINVAL;
|
||||
|
||||
set_bit(func_no, &epc_group->function_num_map);
|
||||
epf->func_no = func_no;
|
||||
|
||||
epc = epc_group->epc;
|
||||
epf = epf_group->epf;
|
||||
ret = pci_epc_add_epf(epc, epf);
|
||||
if (ret)
|
||||
goto err_add_epf;
|
||||
|
||||
func_no = find_first_zero_bit(&epc_group->function_num_map,
|
||||
sizeof(epc_group->function_num_map));
|
||||
set_bit(func_no, &epc_group->function_num_map);
|
||||
epf->func_no = func_no;
|
||||
|
||||
ret = pci_epf_bind(epf);
|
||||
if (ret)
|
||||
goto err_epf_bind;
|
||||
|
|
@ -353,6 +347,9 @@ static void pci_epf_release(struct config_item *item)
|
|||
{
|
||||
struct pci_epf_group *epf_group = to_pci_epf_group(item);
|
||||
|
||||
mutex_lock(&functions_mutex);
|
||||
idr_remove(&functions_idr, epf_group->index);
|
||||
mutex_unlock(&functions_mutex);
|
||||
pci_epf_destroy(epf_group->epf);
|
||||
kfree(epf_group);
|
||||
}
|
||||
|
|
@ -372,22 +369,57 @@ static struct config_group *pci_epf_make(struct config_group *group,
|
|||
{
|
||||
struct pci_epf_group *epf_group;
|
||||
struct pci_epf *epf;
|
||||
char *epf_name;
|
||||
int index, err;
|
||||
|
||||
epf_group = kzalloc(sizeof(*epf_group), GFP_KERNEL);
|
||||
if (!epf_group)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
mutex_lock(&functions_mutex);
|
||||
index = idr_alloc(&functions_idr, epf_group, 0, 0, GFP_KERNEL);
|
||||
mutex_unlock(&functions_mutex);
|
||||
if (index < 0) {
|
||||
err = index;
|
||||
goto free_group;
|
||||
}
|
||||
|
||||
epf_group->index = index;
|
||||
|
||||
config_group_init_type_name(&epf_group->group, name, &pci_epf_type);
|
||||
|
||||
epf = pci_epf_create(group->cg_item.ci_name);
|
||||
epf_name = kasprintf(GFP_KERNEL, "%s.%d",
|
||||
group->cg_item.ci_name, epf_group->index);
|
||||
if (!epf_name) {
|
||||
err = -ENOMEM;
|
||||
goto remove_idr;
|
||||
}
|
||||
|
||||
epf = pci_epf_create(epf_name);
|
||||
if (IS_ERR(epf)) {
|
||||
pr_err("failed to create endpoint function device\n");
|
||||
return ERR_PTR(-EINVAL);
|
||||
err = -EINVAL;
|
||||
goto free_name;
|
||||
}
|
||||
|
||||
epf_group->epf = epf;
|
||||
|
||||
kfree(epf_name);
|
||||
|
||||
return &epf_group->group;
|
||||
|
||||
free_name:
|
||||
kfree(epf_name);
|
||||
|
||||
remove_idr:
|
||||
mutex_lock(&functions_mutex);
|
||||
idr_remove(&functions_idr, epf_group->index);
|
||||
mutex_unlock(&functions_mutex);
|
||||
|
||||
free_group:
|
||||
kfree(epf_group);
|
||||
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
static void pci_epf_drop(struct config_group *group, struct config_item *item)
|
||||
|
|
|
|||
|
|
@ -1,24 +1,12 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/**
|
||||
* PCI Endpoint *Controller* (EPC) library
|
||||
*
|
||||
* Copyright (C) 2017 Texas Instruments
|
||||
* Author: Kishon Vijay Abraham I <kishon@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 of
|
||||
* the License as published by the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
|
|
@ -142,25 +130,26 @@ EXPORT_SYMBOL_GPL(pci_epc_start);
|
|||
/**
|
||||
* pci_epc_raise_irq() - interrupt the host system
|
||||
* @epc: the EPC device which has to interrupt the host
|
||||
* @func_no: the endpoint function number in the EPC device
|
||||
* @type: specify the type of interrupt; legacy or MSI
|
||||
* @interrupt_num: the MSI interrupt number
|
||||
*
|
||||
* Invoke to raise an MSI or legacy interrupt
|
||||
*/
|
||||
int pci_epc_raise_irq(struct pci_epc *epc, enum pci_epc_irq_type type,
|
||||
u8 interrupt_num)
|
||||
int pci_epc_raise_irq(struct pci_epc *epc, u8 func_no,
|
||||
enum pci_epc_irq_type type, u8 interrupt_num)
|
||||
{
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
|
||||
if (IS_ERR(epc))
|
||||
if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions)
|
||||
return -EINVAL;
|
||||
|
||||
if (!epc->ops->raise_irq)
|
||||
return 0;
|
||||
|
||||
spin_lock_irqsave(&epc->lock, flags);
|
||||
ret = epc->ops->raise_irq(epc, type, interrupt_num);
|
||||
ret = epc->ops->raise_irq(epc, func_no, type, interrupt_num);
|
||||
spin_unlock_irqrestore(&epc->lock, flags);
|
||||
|
||||
return ret;
|
||||
|
|
@ -170,22 +159,23 @@ EXPORT_SYMBOL_GPL(pci_epc_raise_irq);
|
|||
/**
|
||||
* pci_epc_get_msi() - get the number of MSI interrupt numbers allocated
|
||||
* @epc: the EPC device to which MSI interrupts was requested
|
||||
* @func_no: the endpoint function number in the EPC device
|
||||
*
|
||||
* Invoke to get the number of MSI interrupts allocated by the RC
|
||||
*/
|
||||
int pci_epc_get_msi(struct pci_epc *epc)
|
||||
int pci_epc_get_msi(struct pci_epc *epc, u8 func_no)
|
||||
{
|
||||
int interrupt;
|
||||
unsigned long flags;
|
||||
|
||||
if (IS_ERR(epc))
|
||||
if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions)
|
||||
return 0;
|
||||
|
||||
if (!epc->ops->get_msi)
|
||||
return 0;
|
||||
|
||||
spin_lock_irqsave(&epc->lock, flags);
|
||||
interrupt = epc->ops->get_msi(epc);
|
||||
interrupt = epc->ops->get_msi(epc, func_no);
|
||||
spin_unlock_irqrestore(&epc->lock, flags);
|
||||
|
||||
if (interrupt < 0)
|
||||
|
|
@ -200,17 +190,18 @@ EXPORT_SYMBOL_GPL(pci_epc_get_msi);
|
|||
/**
|
||||
* pci_epc_set_msi() - set the number of MSI interrupt numbers required
|
||||
* @epc: the EPC device on which MSI has to be configured
|
||||
* @func_no: the endpoint function number in the EPC device
|
||||
* @interrupts: number of MSI interrupts required by the EPF
|
||||
*
|
||||
* Invoke to set the required number of MSI interrupts.
|
||||
*/
|
||||
int pci_epc_set_msi(struct pci_epc *epc, u8 interrupts)
|
||||
int pci_epc_set_msi(struct pci_epc *epc, u8 func_no, u8 interrupts)
|
||||
{
|
||||
int ret;
|
||||
u8 encode_int;
|
||||
unsigned long flags;
|
||||
|
||||
if (IS_ERR(epc))
|
||||
if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions)
|
||||
return -EINVAL;
|
||||
|
||||
if (!epc->ops->set_msi)
|
||||
|
|
@ -219,7 +210,7 @@ int pci_epc_set_msi(struct pci_epc *epc, u8 interrupts)
|
|||
encode_int = order_base_2(interrupts);
|
||||
|
||||
spin_lock_irqsave(&epc->lock, flags);
|
||||
ret = epc->ops->set_msi(epc, encode_int);
|
||||
ret = epc->ops->set_msi(epc, func_no, encode_int);
|
||||
spin_unlock_irqrestore(&epc->lock, flags);
|
||||
|
||||
return ret;
|
||||
|
|
@ -229,22 +220,24 @@ EXPORT_SYMBOL_GPL(pci_epc_set_msi);
|
|||
/**
|
||||
* pci_epc_unmap_addr() - unmap CPU address from PCI address
|
||||
* @epc: the EPC device on which address is allocated
|
||||
* @func_no: the endpoint function number in the EPC device
|
||||
* @phys_addr: physical address of the local system
|
||||
*
|
||||
* Invoke to unmap the CPU address from PCI address.
|
||||
*/
|
||||
void pci_epc_unmap_addr(struct pci_epc *epc, phys_addr_t phys_addr)
|
||||
void pci_epc_unmap_addr(struct pci_epc *epc, u8 func_no,
|
||||
phys_addr_t phys_addr)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (IS_ERR(epc))
|
||||
if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions)
|
||||
return;
|
||||
|
||||
if (!epc->ops->unmap_addr)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&epc->lock, flags);
|
||||
epc->ops->unmap_addr(epc, phys_addr);
|
||||
epc->ops->unmap_addr(epc, func_no, phys_addr);
|
||||
spin_unlock_irqrestore(&epc->lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_epc_unmap_addr);
|
||||
|
|
@ -252,26 +245,27 @@ EXPORT_SYMBOL_GPL(pci_epc_unmap_addr);
|
|||
/**
|
||||
* pci_epc_map_addr() - map CPU address to PCI address
|
||||
* @epc: the EPC device on which address is allocated
|
||||
* @func_no: the endpoint function number in the EPC device
|
||||
* @phys_addr: physical address of the local system
|
||||
* @pci_addr: PCI address to which the physical address should be mapped
|
||||
* @size: the size of the allocation
|
||||
*
|
||||
* Invoke to map CPU address with PCI address.
|
||||
*/
|
||||
int pci_epc_map_addr(struct pci_epc *epc, phys_addr_t phys_addr,
|
||||
u64 pci_addr, size_t size)
|
||||
int pci_epc_map_addr(struct pci_epc *epc, u8 func_no,
|
||||
phys_addr_t phys_addr, u64 pci_addr, size_t size)
|
||||
{
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
|
||||
if (IS_ERR(epc))
|
||||
if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions)
|
||||
return -EINVAL;
|
||||
|
||||
if (!epc->ops->map_addr)
|
||||
return 0;
|
||||
|
||||
spin_lock_irqsave(&epc->lock, flags);
|
||||
ret = epc->ops->map_addr(epc, phys_addr, pci_addr, size);
|
||||
ret = epc->ops->map_addr(epc, func_no, phys_addr, pci_addr, size);
|
||||
spin_unlock_irqrestore(&epc->lock, flags);
|
||||
|
||||
return ret;
|
||||
|
|
@ -281,22 +275,23 @@ EXPORT_SYMBOL_GPL(pci_epc_map_addr);
|
|||
/**
|
||||
* pci_epc_clear_bar() - reset the BAR
|
||||
* @epc: the EPC device for which the BAR has to be cleared
|
||||
* @func_no: the endpoint function number in the EPC device
|
||||
* @bar: the BAR number that has to be reset
|
||||
*
|
||||
* Invoke to reset the BAR of the endpoint device.
|
||||
*/
|
||||
void pci_epc_clear_bar(struct pci_epc *epc, int bar)
|
||||
void pci_epc_clear_bar(struct pci_epc *epc, u8 func_no, int bar)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (IS_ERR(epc))
|
||||
if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions)
|
||||
return;
|
||||
|
||||
if (!epc->ops->clear_bar)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&epc->lock, flags);
|
||||
epc->ops->clear_bar(epc, bar);
|
||||
epc->ops->clear_bar(epc, func_no, bar);
|
||||
spin_unlock_irqrestore(&epc->lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(pci_epc_clear_bar);
|
||||
|
|
@ -304,26 +299,27 @@ EXPORT_SYMBOL_GPL(pci_epc_clear_bar);
|
|||
/**
|
||||
* pci_epc_set_bar() - configure BAR in order for host to assign PCI addr space
|
||||
* @epc: the EPC device on which BAR has to be configured
|
||||
* @func_no: the endpoint function number in the EPC device
|
||||
* @bar: the BAR number that has to be configured
|
||||
* @size: the size of the addr space
|
||||
* @flags: specify memory allocation/io allocation/32bit address/64 bit address
|
||||
*
|
||||
* Invoke to configure the BAR of the endpoint device.
|
||||
*/
|
||||
int pci_epc_set_bar(struct pci_epc *epc, enum pci_barno bar,
|
||||
int pci_epc_set_bar(struct pci_epc *epc, u8 func_no, enum pci_barno bar,
|
||||
dma_addr_t bar_phys, size_t size, int flags)
|
||||
{
|
||||
int ret;
|
||||
unsigned long irq_flags;
|
||||
|
||||
if (IS_ERR(epc))
|
||||
if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions)
|
||||
return -EINVAL;
|
||||
|
||||
if (!epc->ops->set_bar)
|
||||
return 0;
|
||||
|
||||
spin_lock_irqsave(&epc->lock, irq_flags);
|
||||
ret = epc->ops->set_bar(epc, bar, bar_phys, size, flags);
|
||||
ret = epc->ops->set_bar(epc, func_no, bar, bar_phys, size, flags);
|
||||
spin_unlock_irqrestore(&epc->lock, irq_flags);
|
||||
|
||||
return ret;
|
||||
|
|
@ -333,6 +329,7 @@ EXPORT_SYMBOL_GPL(pci_epc_set_bar);
|
|||
/**
|
||||
* pci_epc_write_header() - write standard configuration header
|
||||
* @epc: the EPC device to which the configuration header should be written
|
||||
* @func_no: the endpoint function number in the EPC device
|
||||
* @header: standard configuration header fields
|
||||
*
|
||||
* Invoke to write the configuration header to the endpoint controller. Every
|
||||
|
|
@ -340,19 +337,20 @@ EXPORT_SYMBOL_GPL(pci_epc_set_bar);
|
|||
* configuration header would be written. The callback function should write
|
||||
* the header fields to this dedicated location.
|
||||
*/
|
||||
int pci_epc_write_header(struct pci_epc *epc, struct pci_epf_header *header)
|
||||
int pci_epc_write_header(struct pci_epc *epc, u8 func_no,
|
||||
struct pci_epf_header *header)
|
||||
{
|
||||
int ret;
|
||||
unsigned long flags;
|
||||
|
||||
if (IS_ERR(epc))
|
||||
if (IS_ERR_OR_NULL(epc) || func_no >= epc->max_functions)
|
||||
return -EINVAL;
|
||||
|
||||
if (!epc->ops->write_header)
|
||||
return 0;
|
||||
|
||||
spin_lock_irqsave(&epc->lock, flags);
|
||||
ret = epc->ops->write_header(epc, header);
|
||||
ret = epc->ops->write_header(epc, func_no, header);
|
||||
spin_unlock_irqrestore(&epc->lock, flags);
|
||||
|
||||
return ret;
|
||||
|
|
@ -371,7 +369,6 @@ EXPORT_SYMBOL_GPL(pci_epc_write_header);
|
|||
int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct device *dev = epc->dev.parent;
|
||||
|
||||
if (epf->epc)
|
||||
return -EBUSY;
|
||||
|
|
@ -383,12 +380,6 @@ int pci_epc_add_epf(struct pci_epc *epc, struct pci_epf *epf)
|
|||
return -EINVAL;
|
||||
|
||||
epf->epc = epc;
|
||||
if (dev->of_node) {
|
||||
of_dma_configure(&epf->dev, dev->of_node);
|
||||
} else {
|
||||
dma_set_coherent_mask(&epf->dev, epc->dev.coherent_dma_mask);
|
||||
epf->dev.dma_mask = epc->dev.dma_mask;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&epc->lock, flags);
|
||||
list_add_tail(&epf->list, &epc->pci_epf);
|
||||
|
|
@ -503,9 +494,7 @@ __pci_epc_create(struct device *dev, const struct pci_epc_ops *ops,
|
|||
INIT_LIST_HEAD(&epc->pci_epf);
|
||||
|
||||
device_initialize(&epc->dev);
|
||||
dma_set_coherent_mask(&epc->dev, dev->coherent_dma_mask);
|
||||
epc->dev.class = pci_epc_class;
|
||||
epc->dev.dma_mask = dev->dma_mask;
|
||||
epc->dev.parent = dev;
|
||||
epc->ops = ops;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,20 +1,9 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/**
|
||||
* PCI Endpoint *Controller* Address Space Management
|
||||
*
|
||||
* Copyright (C) 2017 Texas Instruments
|
||||
* Author: Kishon Vijay Abraham I <kishon@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 of
|
||||
* the License as published by the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/io.h>
|
||||
|
|
|
|||
|
|
@ -1,20 +1,9 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/**
|
||||
* PCI Endpoint *Function* (EPF) library
|
||||
*
|
||||
* Copyright (C) 2017 Texas Instruments
|
||||
* Author: Kishon Vijay Abraham I <kishon@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 of
|
||||
* the License as published by the Free Software Foundation.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
|
|
@ -99,7 +88,7 @@ EXPORT_SYMBOL_GPL(pci_epf_bind);
|
|||
*/
|
||||
void pci_epf_free_space(struct pci_epf *epf, void *addr, enum pci_barno bar)
|
||||
{
|
||||
struct device *dev = &epf->dev;
|
||||
struct device *dev = epf->epc->dev.parent;
|
||||
|
||||
if (!addr)
|
||||
return;
|
||||
|
|
@ -122,7 +111,7 @@ EXPORT_SYMBOL_GPL(pci_epf_free_space);
|
|||
void *pci_epf_alloc_space(struct pci_epf *epf, size_t size, enum pci_barno bar)
|
||||
{
|
||||
void *space;
|
||||
struct device *dev = &epf->dev;
|
||||
struct device *dev = epf->epc->dev.parent;
|
||||
dma_addr_t phys_addr;
|
||||
|
||||
if (size < 128)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* host bridge related code
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
menu "PCI host controller drivers"
|
||||
depends on PCI
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ obj-$(CONFIG_VMD) += vmd.o
|
|||
# ARM64 and use internal ifdefs to only build the pieces we need
|
||||
# depending on whether ACPI, the DT driver, or both are enabled.
|
||||
|
||||
ifdef CONFIG_PCI
|
||||
obj-$(CONFIG_ARM64) += pci-thunder-ecam.o
|
||||
obj-$(CONFIG_ARM64) += pci-thunder-pem.o
|
||||
obj-$(CONFIG_ARM64) += pci-xgene.o
|
||||
endif
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Driver for the Aardvark PCIe controller, used on Marvell Armada
|
||||
* 3700.
|
||||
|
|
@ -5,10 +6,6 @@
|
|||
* Copyright (C) 2016 Marvell
|
||||
*
|
||||
* Author: Hezi Shahmoon <hezi.shahmoon@marvell.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
|
|
|||
|
|
@ -1,18 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Generic PCI host driver common code
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright (C) 2014 ARM Limited
|
||||
*
|
||||
* Author: Will Deacon <will.deacon@arm.com>
|
||||
|
|
@ -24,50 +13,6 @@
|
|||
#include <linux/pci-ecam.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
static int gen_pci_parse_request_of_pci_ranges(struct device *dev,
|
||||
struct list_head *resources, struct resource **bus_range)
|
||||
{
|
||||
int err, res_valid = 0;
|
||||
struct device_node *np = dev->of_node;
|
||||
resource_size_t iobase;
|
||||
struct resource_entry *win, *tmp;
|
||||
|
||||
err = of_pci_get_host_bridge_resources(np, 0, 0xff, resources, &iobase);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = devm_request_pci_bus_resources(dev, resources);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
resource_list_for_each_entry_safe(win, tmp, resources) {
|
||||
struct resource *res = win->res;
|
||||
|
||||
switch (resource_type(res)) {
|
||||
case IORESOURCE_IO:
|
||||
err = pci_remap_iospace(res, iobase);
|
||||
if (err) {
|
||||
dev_warn(dev, "error %d: failed to map resource %pR\n",
|
||||
err, res);
|
||||
resource_list_destroy_entry(win);
|
||||
}
|
||||
break;
|
||||
case IORESOURCE_MEM:
|
||||
res_valid |= !(res->flags & IORESOURCE_PREFETCH);
|
||||
break;
|
||||
case IORESOURCE_BUS:
|
||||
*bus_range = res;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (res_valid)
|
||||
return 0;
|
||||
|
||||
dev_err(dev, "non-prefetchable memory resource required\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void gen_pci_unmap_cfg(void *ptr)
|
||||
{
|
||||
pci_ecam_free((struct pci_config_window *)ptr);
|
||||
|
|
@ -82,9 +27,9 @@ static struct pci_config_window *gen_pci_init(struct device *dev,
|
|||
struct pci_config_window *cfg;
|
||||
|
||||
/* Parse our PCI ranges and request their resources */
|
||||
err = gen_pci_parse_request_of_pci_ranges(dev, resources, &bus_range);
|
||||
err = pci_parse_request_of_pci_ranges(dev, resources, &bus_range);
|
||||
if (err)
|
||||
goto err_out;
|
||||
return ERR_PTR(err);
|
||||
|
||||
err = of_address_to_resource(dev->of_node, 0, &cfgres);
|
||||
if (err) {
|
||||
|
|
@ -116,7 +61,6 @@ int pci_host_common_probe(struct platform_device *pdev,
|
|||
const char *type;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct device_node *np = dev->of_node;
|
||||
struct pci_bus *bus, *child;
|
||||
struct pci_host_bridge *bridge;
|
||||
struct pci_config_window *cfg;
|
||||
struct list_head resources;
|
||||
|
|
@ -135,14 +79,13 @@ int pci_host_common_probe(struct platform_device *pdev,
|
|||
of_pci_check_probe_only();
|
||||
|
||||
/* Parse and map our Configuration Space windows */
|
||||
INIT_LIST_HEAD(&resources);
|
||||
cfg = gen_pci_init(dev, &resources, ops);
|
||||
if (IS_ERR(cfg))
|
||||
return PTR_ERR(cfg);
|
||||
|
||||
/* Do not reassign resources if probe only */
|
||||
if (!pci_has_flag(PCI_PROBE_ONLY))
|
||||
pci_add_flags(PCI_REASSIGN_ALL_RSRC | PCI_REASSIGN_ALL_BUS);
|
||||
pci_add_flags(PCI_REASSIGN_ALL_BUS);
|
||||
|
||||
list_splice_init(&resources, &bridge->windows);
|
||||
bridge->dev.parent = dev;
|
||||
|
|
@ -152,29 +95,11 @@ int pci_host_common_probe(struct platform_device *pdev,
|
|||
bridge->map_irq = of_irq_parse_and_map_pci;
|
||||
bridge->swizzle_irq = pci_common_swizzle;
|
||||
|
||||
ret = pci_scan_root_bus_bridge(bridge);
|
||||
ret = pci_host_probe(bridge);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Scanning root bridge failed");
|
||||
pci_free_resource_list(&resources);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bus = bridge->bus;
|
||||
|
||||
/*
|
||||
* We insert PCI resources into the iomem_resource and
|
||||
* ioport_resource trees in either pci_bus_claim_resources()
|
||||
* or pci_bus_assign_resources().
|
||||
*/
|
||||
if (pci_has_flag(PCI_PROBE_ONLY)) {
|
||||
pci_bus_claim_resources(bus);
|
||||
} else {
|
||||
pci_bus_size_bridges(bus);
|
||||
pci_bus_assign_resources(bus);
|
||||
|
||||
list_for_each_entry(child, &bus->children, node)
|
||||
pcie_bus_configure_settings(child);
|
||||
}
|
||||
|
||||
pci_bus_add_devices(bus);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,8 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Simple, generic PCI host controller driver targetting firmware-initialised
|
||||
* systems and virtual machines (e.g. the PCI emulation provided by kvmtool).
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright (C) 2014 ARM Limited
|
||||
*
|
||||
* Author: Will Deacon <will.deacon@arm.com>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
|
|
@ -34,17 +35,6 @@
|
|||
* read and write handlers for config space must be aware of this mechanism.
|
||||
* Similarly, device setup and teardown involves messages sent to and from
|
||||
* the PCI back-end driver in Hyper-V.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,8 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* PCIe driver for Marvell Armada 370 and Armada XP SoCs
|
||||
*
|
||||
* Author: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* pci-rcar-gen2: internal PCI bus support
|
||||
*
|
||||
|
|
@ -5,10 +6,6 @@
|
|||
* Copyright (C) 2013 Cogent Embedded, Inc.
|
||||
*
|
||||
* Author: Valentine Barshak <valentine.barshak@cogentembedded.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/delay.h>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* PCIe host controller driver for Tegra SoCs
|
||||
*
|
||||
|
|
@ -10,20 +11,6 @@
|
|||
* Bits taken from arch/arm/mach-dove/pcie.c
|
||||
*
|
||||
* Author: Thierry Reding <treding@nvidia.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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
|
|
@ -269,11 +256,10 @@ struct tegra_pcie {
|
|||
|
||||
void __iomem *pads;
|
||||
void __iomem *afi;
|
||||
void __iomem *cfg;
|
||||
int irq;
|
||||
|
||||
struct list_head buses;
|
||||
struct resource *cs;
|
||||
|
||||
struct resource cs;
|
||||
struct resource io;
|
||||
struct resource pio;
|
||||
struct resource mem;
|
||||
|
|
@ -322,7 +308,6 @@ struct tegra_pcie_port {
|
|||
};
|
||||
|
||||
struct tegra_pcie_bus {
|
||||
struct vm_struct *area;
|
||||
struct list_head list;
|
||||
unsigned int nr;
|
||||
};
|
||||
|
|
@ -362,109 +347,26 @@ static inline u32 pads_readl(struct tegra_pcie *pcie, unsigned long offset)
|
|||
*
|
||||
* Mapping the whole extended configuration space would require 256 MiB of
|
||||
* virtual address space, only a small part of which will actually be used.
|
||||
* To work around this, a 1 MiB of virtual addresses are allocated per bus
|
||||
* when the bus is first accessed. When the physical range is mapped, the
|
||||
* the bus number bits are hidden so that the extended register number bits
|
||||
* appear as bits [19:16]. Therefore the virtual mapping looks like this:
|
||||
*
|
||||
* [19:16] extended register number
|
||||
* [15:11] device number
|
||||
* [10: 8] function number
|
||||
* [ 7: 0] register number
|
||||
*
|
||||
* This is achieved by stitching together 16 chunks of 64 KiB of physical
|
||||
* address space via the MMU.
|
||||
* To work around this, a 4 KiB region is used to generate the required
|
||||
* configuration transaction with relevant B:D:F and register offset values.
|
||||
* This is achieved by dynamically programming base address and size of
|
||||
* AFI_AXI_BAR used for end point config space mapping to make sure that the
|
||||
* address (access to which generates correct config transaction) falls in
|
||||
* this 4 KiB region.
|
||||
*/
|
||||
static unsigned long tegra_pcie_conf_offset(unsigned int devfn, int where)
|
||||
static unsigned int tegra_pcie_conf_offset(u8 bus, unsigned int devfn,
|
||||
unsigned int where)
|
||||
{
|
||||
return ((where & 0xf00) << 8) | (PCI_SLOT(devfn) << 11) |
|
||||
(PCI_FUNC(devfn) << 8) | (where & 0xfc);
|
||||
}
|
||||
|
||||
static struct tegra_pcie_bus *tegra_pcie_bus_alloc(struct tegra_pcie *pcie,
|
||||
unsigned int busnr)
|
||||
{
|
||||
struct device *dev = pcie->dev;
|
||||
pgprot_t prot = pgprot_noncached(PAGE_KERNEL);
|
||||
phys_addr_t cs = pcie->cs->start;
|
||||
struct tegra_pcie_bus *bus;
|
||||
unsigned int i;
|
||||
int err;
|
||||
|
||||
bus = kzalloc(sizeof(*bus), GFP_KERNEL);
|
||||
if (!bus)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
INIT_LIST_HEAD(&bus->list);
|
||||
bus->nr = busnr;
|
||||
|
||||
/* allocate 1 MiB of virtual addresses */
|
||||
bus->area = get_vm_area(SZ_1M, VM_IOREMAP);
|
||||
if (!bus->area) {
|
||||
err = -ENOMEM;
|
||||
goto free;
|
||||
}
|
||||
|
||||
/* map each of the 16 chunks of 64 KiB each */
|
||||
for (i = 0; i < 16; i++) {
|
||||
unsigned long virt = (unsigned long)bus->area->addr +
|
||||
i * 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) {
|
||||
dev_err(dev, "ioremap_page_range() failed: %d\n", err);
|
||||
goto unmap;
|
||||
}
|
||||
}
|
||||
|
||||
return bus;
|
||||
|
||||
unmap:
|
||||
vunmap(bus->area->addr);
|
||||
free:
|
||||
kfree(bus);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
static int tegra_pcie_add_bus(struct pci_bus *bus)
|
||||
{
|
||||
struct pci_host_bridge *host = pci_find_host_bridge(bus);
|
||||
struct tegra_pcie *pcie = pci_host_bridge_priv(host);
|
||||
struct tegra_pcie_bus *b;
|
||||
|
||||
b = tegra_pcie_bus_alloc(pcie, bus->number);
|
||||
if (IS_ERR(b))
|
||||
return PTR_ERR(b);
|
||||
|
||||
list_add_tail(&b->list, &pcie->buses);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tegra_pcie_remove_bus(struct pci_bus *child)
|
||||
{
|
||||
struct pci_host_bridge *host = pci_find_host_bridge(child);
|
||||
struct tegra_pcie *pcie = pci_host_bridge_priv(host);
|
||||
struct tegra_pcie_bus *bus, *tmp;
|
||||
|
||||
list_for_each_entry_safe(bus, tmp, &pcie->buses, list) {
|
||||
if (bus->nr == child->number) {
|
||||
vunmap(bus->area->addr);
|
||||
list_del(&bus->list);
|
||||
kfree(bus);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ((where & 0xf00) << 16) | (bus << 16) | (PCI_SLOT(devfn) << 11) |
|
||||
(PCI_FUNC(devfn) << 8) | (where & 0xff);
|
||||
}
|
||||
|
||||
static void __iomem *tegra_pcie_map_bus(struct pci_bus *bus,
|
||||
unsigned int devfn,
|
||||
int where)
|
||||
{
|
||||
struct pci_host_bridge *host = pci_find_host_bridge(bus);
|
||||
struct tegra_pcie *pcie = pci_host_bridge_priv(host);
|
||||
struct device *dev = pcie->dev;
|
||||
struct tegra_pcie *pcie = bus->sysdata;
|
||||
void __iomem *addr = NULL;
|
||||
|
||||
if (bus->number == 0) {
|
||||
|
|
@ -478,19 +380,17 @@ static void __iomem *tegra_pcie_map_bus(struct pci_bus *bus,
|
|||
}
|
||||
}
|
||||
} else {
|
||||
struct tegra_pcie_bus *b;
|
||||
unsigned int offset;
|
||||
u32 base;
|
||||
|
||||
list_for_each_entry(b, &pcie->buses, list)
|
||||
if (b->nr == bus->number)
|
||||
addr = (void __iomem *)b->area->addr;
|
||||
offset = tegra_pcie_conf_offset(bus->number, devfn, where);
|
||||
|
||||
if (!addr) {
|
||||
dev_err(dev, "failed to map cfg. space for bus %u\n",
|
||||
bus->number);
|
||||
return NULL;
|
||||
}
|
||||
/* move 4 KiB window to offset within the FPCI region */
|
||||
base = 0xfe100000 + ((offset & ~(SZ_4K - 1)) >> 8);
|
||||
afi_writel(pcie, base, AFI_FPCI_BAR0);
|
||||
|
||||
addr += tegra_pcie_conf_offset(devfn, where);
|
||||
/* move to correct offset within the 4 KiB page */
|
||||
addr = pcie->cfg + (offset & (SZ_4K - 1));
|
||||
}
|
||||
|
||||
return addr;
|
||||
|
|
@ -517,8 +417,6 @@ static int tegra_pcie_config_write(struct pci_bus *bus, unsigned int devfn,
|
|||
}
|
||||
|
||||
static struct pci_ops tegra_pcie_ops = {
|
||||
.add_bus = tegra_pcie_add_bus,
|
||||
.remove_bus = tegra_pcie_remove_bus,
|
||||
.map_bus = tegra_pcie_map_bus,
|
||||
.read = tegra_pcie_config_read,
|
||||
.write = tegra_pcie_config_write,
|
||||
|
|
@ -661,8 +559,7 @@ static int tegra_pcie_request_resources(struct tegra_pcie *pcie)
|
|||
|
||||
static int tegra_pcie_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
|
||||
{
|
||||
struct pci_host_bridge *host = pci_find_host_bridge(pdev->bus);
|
||||
struct tegra_pcie *pcie = pci_host_bridge_priv(host);
|
||||
struct tegra_pcie *pcie = pdev->bus->sysdata;
|
||||
int irq;
|
||||
|
||||
tegra_cpuidle_pcie_irqs_in_use();
|
||||
|
|
@ -743,12 +640,9 @@ static void tegra_pcie_setup_translations(struct tegra_pcie *pcie)
|
|||
u32 fpci_bar, size, axi_address;
|
||||
|
||||
/* Bar 0: type 1 extended configuration space */
|
||||
fpci_bar = 0xfe100000;
|
||||
size = resource_size(pcie->cs);
|
||||
axi_address = pcie->cs->start;
|
||||
afi_writel(pcie, axi_address, AFI_AXI_BAR0_START);
|
||||
size = resource_size(&pcie->cs);
|
||||
afi_writel(pcie, pcie->cs.start, AFI_AXI_BAR0_START);
|
||||
afi_writel(pcie, size >> 12, AFI_AXI_BAR0_SZ);
|
||||
afi_writel(pcie, fpci_bar, AFI_FPCI_BAR0);
|
||||
|
||||
/* Bar 1: downstream IO bar */
|
||||
fpci_bar = 0xfdfc0000;
|
||||
|
|
@ -1353,10 +1247,14 @@ static int tegra_pcie_get_resources(struct tegra_pcie *pcie)
|
|||
goto poweroff;
|
||||
}
|
||||
|
||||
pcie->cs = devm_request_mem_region(dev, res->start,
|
||||
resource_size(res), res->name);
|
||||
if (!pcie->cs) {
|
||||
err = -EADDRNOTAVAIL;
|
||||
pcie->cs = *res;
|
||||
|
||||
/* constrain configuration space to 4 KiB */
|
||||
pcie->cs.end = pcie->cs.start + SZ_4K - 1;
|
||||
|
||||
pcie->cfg = devm_ioremap_resource(dev, &pcie->cs);
|
||||
if (IS_ERR(pcie->cfg)) {
|
||||
err = PTR_ERR(pcie->cfg);
|
||||
goto poweroff;
|
||||
}
|
||||
|
||||
|
|
@ -2345,9 +2243,9 @@ static int tegra_pcie_probe(struct platform_device *pdev)
|
|||
return -ENOMEM;
|
||||
|
||||
pcie = pci_host_bridge_priv(host);
|
||||
host->sysdata = pcie;
|
||||
|
||||
pcie->soc = of_device_get_match_data(dev);
|
||||
INIT_LIST_HEAD(&pcie->buses);
|
||||
INIT_LIST_HEAD(&pcie->ports);
|
||||
pcie->dev = dev;
|
||||
|
||||
|
|
@ -2382,7 +2280,6 @@ static int tegra_pcie_probe(struct platform_device *pdev)
|
|||
|
||||
tegra_pcie_enable_ports(pcie);
|
||||
|
||||
pci_add_flags(PCI_REASSIGN_ALL_RSRC | PCI_REASSIGN_ALL_BUS);
|
||||
host->busnr = pcie->busn.start;
|
||||
host->dev.parent = &pdev->dev;
|
||||
host->ops = &tegra_pcie_ops;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* Copyright (C) 2015, 2016 Cavium, Inc.
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,5 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Copyright (C) 2015 - 2016 Cavium, Inc.
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Support for V3 Semiconductor PCI Local Bus to PCI Bridge
|
||||
* Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>
|
||||
|
|
|
|||
|
|
@ -1,18 +1,10 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright 2004 Koninklijke Philips Electronics NV
|
||||
*
|
||||
* Conversion to platform driver and DT:
|
||||
* Copyright 2014 Linaro Ltd.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 14/04/2005 Initial version, colin.king@philips.com
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
|
|
@ -202,7 +194,7 @@ static int versatile_pci_probe(struct platform_device *pdev)
|
|||
writel(0, versatile_cfg_base[0] + PCI_INTERRUPT_LINE);
|
||||
|
||||
pci_add_flags(PCI_ENABLE_PROC_DOMAINS);
|
||||
pci_add_flags(PCI_REASSIGN_ALL_BUS | PCI_REASSIGN_ALL_RSRC);
|
||||
pci_add_flags(PCI_REASSIGN_ALL_BUS);
|
||||
|
||||
list_splice_init(&pci_res, &bridge->windows);
|
||||
bridge->dev.parent = dev;
|
||||
|
|
|
|||
|
|
@ -1,19 +1,10 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* APM X-Gene MSI Driver
|
||||
*
|
||||
* Copyright (c) 2014, Applied Micro Circuits Corporation
|
||||
* Author: Tanmay Inamdar <tinamdar@apm.com>
|
||||
* Duc Dang <dhdang@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/cpu.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
|
|
|||
|
|
@ -1,20 +1,10 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/**
|
||||
* 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.h>
|
||||
#include <linux/delay.h>
|
||||
|
|
@ -668,7 +658,6 @@ static int xgene_pcie_probe(struct platform_device *pdev)
|
|||
|
||||
bus = bridge->bus;
|
||||
|
||||
pci_scan_child_bus(bus);
|
||||
pci_assign_unassigned_bus_resources(bus);
|
||||
list_for_each_entry(child, &bus->children, node)
|
||||
pcie_bus_configure_settings(child);
|
||||
|
|
|
|||
|
|
@ -1,21 +1,10 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Altera PCIe MSI support
|
||||
*
|
||||
* Author: Ley Foon Tan <lftan@altera.com>
|
||||
*
|
||||
* Copyright Altera Corporation (C) 2013-2015. All rights reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
|
|
|
|||
|
|
@ -1,20 +1,9 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright Altera Corporation (C) 2013-2015. All rights reserved
|
||||
*
|
||||
* Author: Ley Foon Tan <lftan@altera.com>
|
||||
* Description: Altera PCIe host controller driver
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
|
|
|||
|
|
@ -1,15 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2015 Broadcom Corporation
|
||||
* Copyright (C) 2015 Hauke Mehrtens <hauke@hauke-m.de>
|
||||
*
|
||||
* 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 version 2.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2015 Broadcom Corporation
|
||||
*
|
||||
* 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 version 2.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2015 Broadcom Corporation
|
||||
*
|
||||
* 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 version 2.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
|
@ -92,6 +84,13 @@ static int iproc_pcie_pltfm_probe(struct platform_device *pdev)
|
|||
pcie->need_ob_cfg = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* DT nodes are not used by all platforms that use the iProc PCIe
|
||||
* core driver. For platforms that require explict inbound mapping
|
||||
* configuration, "dma-ranges" would have been present in DT
|
||||
*/
|
||||
pcie->need_ib_cfg = of_property_read_bool(np, "dma-ranges");
|
||||
|
||||
/* PHY use is optional */
|
||||
pcie->phy = devm_phy_get(dev, "pcie-phy");
|
||||
if (IS_ERR(pcie->phy)) {
|
||||
|
|
|
|||
|
|
@ -1,15 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2014 Hauke Mehrtens <hauke@hauke-m.de>
|
||||
* Copyright (C) 2015 Broadcom Corporation
|
||||
*
|
||||
* 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 version 2.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
|
@ -1378,9 +1370,11 @@ int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
|
|||
}
|
||||
}
|
||||
|
||||
ret = iproc_pcie_map_dma_ranges(pcie);
|
||||
if (ret && ret != -ENOENT)
|
||||
goto err_power_off_phy;
|
||||
if (pcie->need_ib_cfg) {
|
||||
ret = iproc_pcie_map_dma_ranges(pcie);
|
||||
if (ret && ret != -ENOENT)
|
||||
goto err_power_off_phy;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARM
|
||||
pcie->sysdata.private_data = pcie;
|
||||
|
|
|
|||
|
|
@ -1,14 +1,6 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* Copyright (C) 2014-2015 Broadcom Corporation
|
||||
*
|
||||
* 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 version 2.
|
||||
*
|
||||
* This program is distributed "as is" WITHOUT ANY WARRANTY of any
|
||||
* kind, whether express or implied; without even the implied warranty
|
||||
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _PCIE_IPROC_H
|
||||
|
|
@ -74,6 +66,7 @@ struct iproc_msi;
|
|||
* @ob: outbound mapping related parameters
|
||||
* @ob_map: outbound mapping related parameters specific to the controller
|
||||
*
|
||||
* @need_ib_cfg: indicates SW needs to configure the inbound mapping window
|
||||
* @ib: inbound mapping related parameters
|
||||
* @ib_map: outbound mapping region related parameters
|
||||
*
|
||||
|
|
@ -101,6 +94,7 @@ struct iproc_pcie {
|
|||
struct iproc_pcie_ob ob;
|
||||
const struct iproc_pcie_ob_map *ob_map;
|
||||
|
||||
bool need_ib_cfg;
|
||||
struct iproc_pcie_ib ib;
|
||||
const struct iproc_pcie_ib_map *ib_map;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,18 +1,10 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* MediaTek PCIe host controller driver.
|
||||
*
|
||||
* Copyright (c) 2017 MediaTek Inc.
|
||||
* Author: Ryder Lee <ryder.lee@mediatek.com>
|
||||
* Honghui Zhang <honghui.zhang@mediatek.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.
|
||||
*
|
||||
* 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.h>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* PCIe driver for Renesas R-Car SoCs
|
||||
* Copyright (C) 2014 Renesas Electronics Europe Ltd
|
||||
|
|
@ -8,10 +9,6 @@
|
|||
* Copyright (C) 2009 - 2011 Paul Mundt
|
||||
*
|
||||
* Author: Phil Edworthy <phil.edworthy@renesas.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
|
|
@ -459,7 +456,7 @@ static int rcar_pcie_enable(struct rcar_pcie *pcie)
|
|||
|
||||
rcar_pcie_setup(&bridge->windows, pcie);
|
||||
|
||||
pci_add_flags(PCI_REASSIGN_ALL_RSRC | PCI_REASSIGN_ALL_BUS);
|
||||
pci_add_flags(PCI_REASSIGN_ALL_BUS);
|
||||
|
||||
bridge->dev.parent = dev;
|
||||
bridge->sysdata = pcie;
|
||||
|
|
@ -1123,7 +1120,9 @@ static int rcar_pcie_probe(struct platform_device *pdev)
|
|||
|
||||
INIT_LIST_HEAD(&pcie->resources);
|
||||
|
||||
rcar_pcie_parse_request_of_pci_ranges(pcie);
|
||||
err = rcar_pcie_parse_request_of_pci_ranges(pcie);
|
||||
if (err)
|
||||
goto err_free_bridge;
|
||||
|
||||
err = rcar_pcie_get_resources(pcie);
|
||||
if (err < 0) {
|
||||
|
|
@ -1178,6 +1177,7 @@ err_pm_disable:
|
|||
|
||||
err_free_resource_list:
|
||||
pci_free_resource_list(&pcie->resources);
|
||||
err_free_bridge:
|
||||
pci_free_host_bridge(bridge);
|
||||
|
||||
return err;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Rockchip AXI PCIe host controller driver
|
||||
*
|
||||
|
|
@ -8,11 +9,6 @@
|
|||
*
|
||||
* Bits taken from Synopsys DesignWare Host controller driver and
|
||||
* ARM PCI Host generic driver.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/bitrev.h>
|
||||
|
|
|
|||
|
|
@ -1,13 +1,9 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* PCIe host controller driver for NWL PCIe Bridge
|
||||
* Based on pcie-xilinx.c, pci-tegra.c
|
||||
*
|
||||
* (C) Copyright 2014 - 2015, Xilinx, Inc.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/delay.h>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* PCIe host controller driver for Xilinx AXI PCIe Bridge
|
||||
*
|
||||
|
|
@ -7,11 +8,6 @@
|
|||
*
|
||||
* Bits taken from Synopsys DesignWare Host controller driver and
|
||||
* ARM PCI Host generic driver.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
|
|
|
|||
|
|
@ -1,15 +1,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Volume Management Device driver
|
||||
* Copyright (c) 2015, Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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/device.h>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# PCI Hotplug support
|
||||
#
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Common ACPI functions for hot plug platforms
|
||||
*
|
||||
|
|
@ -5,21 +6,6 @@
|
|||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Send feedback to <kristen.c.accardi@intel.com>
|
||||
*
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* ACPI PCI Hot Plug Controller Driver
|
||||
*
|
||||
|
|
@ -12,21 +13,6 @@
|
|||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Send feedback to <gregkh@us.ibm.com>,
|
||||
* <t-kochi@bq.jp.nec.com>
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* ACPI PCI Hot Plug Controller Driver
|
||||
*
|
||||
|
|
@ -12,21 +13,6 @@
|
|||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Send feedback to <kristen.c.accardi@intel.com>
|
||||
*
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* ACPI PCI HotPlug glue functions to ACPI CA subsystem
|
||||
*
|
||||
|
|
@ -11,21 +12,6 @@
|
|||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Send feedback to <kristen.c.accardi@intel.com>
|
||||
*
|
||||
*/
|
||||
|
|
@ -811,10 +797,8 @@ void acpiphp_enumerate_slots(struct pci_bus *bus)
|
|||
|
||||
handle = adev->handle;
|
||||
bridge = kzalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
|
||||
if (!bridge) {
|
||||
acpi_handle_err(handle, "No memory for bridge object\n");
|
||||
if (!bridge)
|
||||
return;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&bridge->slots);
|
||||
kref_init(&bridge->ref);
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* ACPI PCI Hot Plug IBM Extension
|
||||
*
|
||||
|
|
@ -6,21 +7,6 @@
|
|||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Send feedback to <vernux@us.ibm.com>
|
||||
*
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* CompactPCI Hot Plug Core Functions
|
||||
*
|
||||
|
|
@ -7,21 +8,6 @@
|
|||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Send feedback to <scottm@somanetworks.com>
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* CompactPCI Hot Plug Driver
|
||||
*
|
||||
|
|
@ -7,21 +8,6 @@
|
|||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Send feedback to <scottm@somanetworks.com>
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* CompactPCI Hot Plug Driver PCI functions
|
||||
*
|
||||
|
|
@ -5,21 +6,6 @@
|
|||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Send feedback to <scottm@somanetworks.com>
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* cpcihp_generic.c
|
||||
*
|
||||
|
|
@ -7,26 +8,6 @@
|
|||
* Copyright 2001 Intel San Luis Obispo
|
||||
* Copyright 2000,2001 MontaVista Software Inc.
|
||||
*
|
||||
* 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 SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* This generic CompactPCI hotplug driver should allow using the PCI hotplug
|
||||
* mechanism on any CompactPCI board that exposes the #ENUM signal as a bit
|
||||
* in a system register that can be read through standard port I/O.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* cpcihp_zt5550.c
|
||||
*
|
||||
|
|
@ -7,26 +8,6 @@
|
|||
* Copyright 2001 Intel San Luis Obispo
|
||||
* Copyright 2000,2001 MontaVista Software Inc.
|
||||
*
|
||||
* 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 SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Send feedback to <scottm@somanetworks.com>
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* cpcihp_zt5550.h
|
||||
*
|
||||
|
|
@ -7,26 +8,6 @@
|
|||
* Copyright 2001 Intel San Luis Obispo
|
||||
* Copyright 2000,2001 MontaVista Software Inc.
|
||||
*
|
||||
* 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 SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
|
||||
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Send feedback to <scottm@somanetworks.com>
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Compaq Hot Plug Controller Driver
|
||||
*
|
||||
|
|
@ -7,21 +8,6 @@
|
|||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Send feedback to <greg@kroah.com>
|
||||
*
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Compaq Hot Plug Controller Driver
|
||||
*
|
||||
|
|
@ -7,21 +8,6 @@
|
|||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Send feedback to <greg@kroah.com>
|
||||
*
|
||||
* Jan 12, 2003 - Added 66/100/133MHz PCI-X support,
|
||||
|
|
@ -835,7 +821,7 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
|
||||
bus = pdev->subordinate;
|
||||
if (!bus) {
|
||||
dev_notice(&pdev->dev, "the device is not a bridge, skipping\n");
|
||||
pci_notice(pdev, "the device is not a bridge, skipping\n");
|
||||
rc = -ENODEV;
|
||||
goto err_disable_device;
|
||||
}
|
||||
|
|
@ -883,7 +869,6 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
|||
|
||||
ctrl = kzalloc(sizeof(struct controller), GFP_KERNEL);
|
||||
if (!ctrl) {
|
||||
err("%s : out of memory\n", __func__);
|
||||
rc = -ENOMEM;
|
||||
goto err_disable_device;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Compaq Hot Plug Controller Driver
|
||||
*
|
||||
|
|
@ -7,21 +8,6 @@
|
|||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Send feedback to <greg@kroah.com>
|
||||
*
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Compaq Hot Plug Controller Driver
|
||||
*
|
||||
|
|
@ -7,21 +8,6 @@
|
|||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Send feedback to <greg@kroah.com>
|
||||
*
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* Compaq Hot Plug Controller Driver
|
||||
*
|
||||
|
|
@ -6,21 +7,6 @@
|
|||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Send feedback to <greg@kroah.com>
|
||||
*
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Compaq Hot Plug Controller Driver
|
||||
*
|
||||
|
|
@ -7,21 +8,6 @@
|
|||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Send feedback to <greg@kroah.com>
|
||||
*
|
||||
*/
|
||||
|
|
@ -89,7 +75,9 @@ int cpqhp_configure_device(struct controller *ctrl, struct pci_func *func)
|
|||
pci_lock_rescan_remove();
|
||||
|
||||
if (func->pci_dev == NULL)
|
||||
func->pci_dev = pci_get_bus_and_slot(func->bus, PCI_DEVFN(func->device, func->function));
|
||||
func->pci_dev = pci_get_domain_bus_and_slot(0, func->bus,
|
||||
PCI_DEVFN(func->device,
|
||||
func->function));
|
||||
|
||||
/* No pci device, we need to create it then */
|
||||
if (func->pci_dev == NULL) {
|
||||
|
|
@ -99,7 +87,9 @@ int cpqhp_configure_device(struct controller *ctrl, struct pci_func *func)
|
|||
if (num)
|
||||
pci_bus_add_devices(ctrl->pci_dev->bus);
|
||||
|
||||
func->pci_dev = pci_get_bus_and_slot(func->bus, PCI_DEVFN(func->device, func->function));
|
||||
func->pci_dev = pci_get_domain_bus_and_slot(0, func->bus,
|
||||
PCI_DEVFN(func->device,
|
||||
func->function));
|
||||
if (func->pci_dev == NULL) {
|
||||
dbg("ERROR: pci_dev still null\n");
|
||||
goto out;
|
||||
|
|
@ -129,7 +119,10 @@ int cpqhp_unconfigure_device(struct pci_func *func)
|
|||
|
||||
pci_lock_rescan_remove();
|
||||
for (j = 0; j < 8 ; j++) {
|
||||
struct pci_dev *temp = pci_get_bus_and_slot(func->bus, PCI_DEVFN(func->device, j));
|
||||
struct pci_dev *temp = pci_get_domain_bus_and_slot(0,
|
||||
func->bus,
|
||||
PCI_DEVFN(func->device,
|
||||
j));
|
||||
if (temp) {
|
||||
pci_dev_put(temp);
|
||||
pci_stop_and_remove_bus_device(temp);
|
||||
|
|
@ -319,6 +312,7 @@ int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug)
|
|||
int cloop = 0;
|
||||
int stop_it;
|
||||
int index;
|
||||
u16 devfn;
|
||||
|
||||
/* Decide which slots are supported */
|
||||
|
||||
|
|
@ -416,7 +410,9 @@ int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug)
|
|||
new_slot->switch_save = 0x10;
|
||||
/* In case of unsupported board */
|
||||
new_slot->status = DevError;
|
||||
new_slot->pci_dev = pci_get_bus_and_slot(new_slot->bus, (new_slot->device << 3) | new_slot->function);
|
||||
devfn = (new_slot->device << 3) | new_slot->function;
|
||||
new_slot->pci_dev = pci_get_domain_bus_and_slot(0,
|
||||
new_slot->bus, devfn);
|
||||
|
||||
for (cloop = 0; cloop < 0x20; cloop++) {
|
||||
rc = pci_bus_read_config_dword(ctrl->pci_bus, PCI_DEVFN(device, function), cloop << 2, (u32 *) &(new_slot->config_space[cloop]));
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Compaq Hot Plug Controller Driver
|
||||
*
|
||||
|
|
@ -7,21 +8,6 @@
|
|||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Send feedback to <greg@kroah.com>
|
||||
*
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
#ifndef __IBMPHP_H
|
||||
#define __IBMPHP_H
|
||||
|
||||
|
|
@ -11,21 +12,6 @@
|
|||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Send feedback to <gregkh@us.ibm.com>
|
||||
*
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* IBM Hot Plug Controller Driver
|
||||
*
|
||||
|
|
@ -8,21 +9,6 @@
|
|||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Send feedback to <gregkh@us.ibm.com>
|
||||
*
|
||||
*/
|
||||
|
|
@ -603,10 +589,8 @@ int ibmphp_update_slot_info(struct slot *slot_cur)
|
|||
u8 mode;
|
||||
|
||||
info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL);
|
||||
if (!info) {
|
||||
err("out of system memory\n");
|
||||
if (!info)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
info->power_status = SLOT_PWRGD(slot_cur->status);
|
||||
info->attention_status = SLOT_ATTN(slot_cur->status,
|
||||
|
|
@ -707,7 +691,8 @@ static void ibm_unconfigure_device(struct pci_func *func)
|
|||
pci_lock_rescan_remove();
|
||||
|
||||
for (j = 0; j < 0x08; j++) {
|
||||
temp = pci_get_bus_and_slot(func->busno, (func->device << 3) | j);
|
||||
temp = pci_get_domain_bus_and_slot(0, func->busno,
|
||||
(func->device << 3) | j);
|
||||
if (temp) {
|
||||
pci_stop_and_remove_bus_device(temp);
|
||||
pci_dev_put(temp);
|
||||
|
|
@ -734,14 +719,12 @@ static u8 bus_structure_fixup(u8 busno)
|
|||
return 1;
|
||||
|
||||
bus = kmalloc(sizeof(*bus), GFP_KERNEL);
|
||||
if (!bus) {
|
||||
err("%s - out of memory\n", __func__);
|
||||
if (!bus)
|
||||
return 1;
|
||||
}
|
||||
|
||||
dev = kmalloc(sizeof(*dev), GFP_KERNEL);
|
||||
if (!dev) {
|
||||
kfree(bus);
|
||||
err("%s - out of memory\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -780,7 +763,7 @@ static int ibm_configure_device(struct pci_func *func)
|
|||
if (!(bus_structure_fixup(func->busno)))
|
||||
flag = 1;
|
||||
if (func->dev == NULL)
|
||||
func->dev = pci_get_bus_and_slot(func->busno,
|
||||
func->dev = pci_get_domain_bus_and_slot(0, func->busno,
|
||||
PCI_DEVFN(func->device, func->function));
|
||||
|
||||
if (func->dev == NULL) {
|
||||
|
|
@ -793,7 +776,7 @@ static int ibm_configure_device(struct pci_func *func)
|
|||
if (num)
|
||||
pci_bus_add_devices(bus);
|
||||
|
||||
func->dev = pci_get_bus_and_slot(func->busno,
|
||||
func->dev = pci_get_domain_bus_and_slot(0, func->busno,
|
||||
PCI_DEVFN(func->device, func->function));
|
||||
if (func->dev == NULL) {
|
||||
err("ERROR... : pci_dev still NULL\n");
|
||||
|
|
@ -1101,7 +1084,6 @@ static int enable_slot(struct hotplug_slot *hs)
|
|||
if (!slot_cur->func) {
|
||||
/* We cannot do update_slot_info here, since no memory for
|
||||
* kmalloc n.e.ways, and update_slot_info allocates some */
|
||||
err("out of system memory\n");
|
||||
rc = -ENOMEM;
|
||||
goto error_power;
|
||||
}
|
||||
|
|
@ -1208,7 +1190,6 @@ int ibmphp_do_disable_slot(struct slot *slot_cur)
|
|||
/* We need this for functions that were there on bootup */
|
||||
slot_cur->func = kzalloc(sizeof(struct pci_func), GFP_KERNEL);
|
||||
if (!slot_cur->func) {
|
||||
err("out of system memory\n");
|
||||
rc = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
|
@ -1306,7 +1287,6 @@ static int __init ibmphp_init(void)
|
|||
|
||||
ibmphp_pci_bus = kmalloc(sizeof(*ibmphp_pci_bus), GFP_KERNEL);
|
||||
if (!ibmphp_pci_bus) {
|
||||
err("out of memory\n");
|
||||
rc = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* IBM Hot Plug Controller Driver
|
||||
*
|
||||
|
|
@ -8,21 +9,6 @@
|
|||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Send feedback to <gregkh@us.ibm.com>
|
||||
*
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* IBM Hot Plug Controller Driver
|
||||
*
|
||||
|
|
@ -7,21 +8,6 @@
|
|||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Send feedback to <gregkh@us.ibm.com>
|
||||
* <jshah@us.ibm.com>
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* IBM Hot Plug Controller Driver
|
||||
*
|
||||
|
|
@ -8,21 +9,6 @@
|
|||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Send feedback to <gregkh@us.ibm.com>
|
||||
*
|
||||
*/
|
||||
|
|
@ -167,10 +153,9 @@ int ibmphp_configure_card(struct pci_func *func, u8 slotno)
|
|||
goto error;
|
||||
}
|
||||
newfunc = kzalloc(sizeof(*newfunc), GFP_KERNEL);
|
||||
if (!newfunc) {
|
||||
err("out of system memory\n");
|
||||
if (!newfunc)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
newfunc->busno = cur_func->busno;
|
||||
newfunc->device = device;
|
||||
cur_func->next = newfunc;
|
||||
|
|
@ -205,10 +190,9 @@ int ibmphp_configure_card(struct pci_func *func, u8 slotno)
|
|||
for (i = 0; i < 32; i++) {
|
||||
if (func->devices[i]) {
|
||||
newfunc = kzalloc(sizeof(*newfunc), GFP_KERNEL);
|
||||
if (!newfunc) {
|
||||
err("out of system memory\n");
|
||||
if (!newfunc)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
newfunc->busno = sec_number;
|
||||
newfunc->device = (u8) i;
|
||||
for (j = 0; j < 4; j++)
|
||||
|
|
@ -233,10 +217,9 @@ int ibmphp_configure_card(struct pci_func *func, u8 slotno)
|
|||
}
|
||||
|
||||
newfunc = kzalloc(sizeof(*newfunc), GFP_KERNEL);
|
||||
if (!newfunc) {
|
||||
err("out of system memory\n");
|
||||
if (!newfunc)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
newfunc->busno = cur_func->busno;
|
||||
newfunc->device = device;
|
||||
for (j = 0; j < 4; j++)
|
||||
|
|
@ -279,10 +262,9 @@ int ibmphp_configure_card(struct pci_func *func, u8 slotno)
|
|||
if (func->devices[i]) {
|
||||
debug("inside for loop, device is %x\n", i);
|
||||
newfunc = kzalloc(sizeof(*newfunc), GFP_KERNEL);
|
||||
if (!newfunc) {
|
||||
err(" out of system memory\n");
|
||||
if (!newfunc)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
newfunc->busno = sec_number;
|
||||
newfunc->device = (u8) i;
|
||||
for (j = 0; j < 4; j++)
|
||||
|
|
@ -405,10 +387,9 @@ static int configure_device(struct pci_func *func)
|
|||
|
||||
io[count] = kzalloc(sizeof(struct resource_node), GFP_KERNEL);
|
||||
|
||||
if (!io[count]) {
|
||||
err("out of system memory\n");
|
||||
if (!io[count])
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
io[count]->type = IO;
|
||||
io[count]->busno = func->busno;
|
||||
io[count]->devfunc = PCI_DEVFN(func->device, func->function);
|
||||
|
|
@ -442,10 +423,9 @@ static int configure_device(struct pci_func *func)
|
|||
debug("len[count] in PFMEM %x, count %d\n", len[count], count);
|
||||
|
||||
pfmem[count] = kzalloc(sizeof(struct resource_node), GFP_KERNEL);
|
||||
if (!pfmem[count]) {
|
||||
err("out of system memory\n");
|
||||
if (!pfmem[count])
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pfmem[count]->type = PFMEM;
|
||||
pfmem[count]->busno = func->busno;
|
||||
pfmem[count]->devfunc = PCI_DEVFN(func->device,
|
||||
|
|
@ -458,7 +438,6 @@ static int configure_device(struct pci_func *func)
|
|||
} else {
|
||||
mem_tmp = kzalloc(sizeof(*mem_tmp), GFP_KERNEL);
|
||||
if (!mem_tmp) {
|
||||
err("out of system memory\n");
|
||||
kfree(pfmem[count]);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
|
@ -508,10 +487,9 @@ static int configure_device(struct pci_func *func)
|
|||
debug("len[count] in Mem %x, count %d\n", len[count], count);
|
||||
|
||||
mem[count] = kzalloc(sizeof(struct resource_node), GFP_KERNEL);
|
||||
if (!mem[count]) {
|
||||
err("out of system memory\n");
|
||||
if (!mem[count])
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
mem[count]->type = MEM;
|
||||
mem[count]->busno = func->busno;
|
||||
mem[count]->devfunc = PCI_DEVFN(func->device,
|
||||
|
|
@ -674,7 +652,6 @@ static int configure_bridge(struct pci_func **func_passed, u8 slotno)
|
|||
bus_io[count] = kzalloc(sizeof(struct resource_node), GFP_KERNEL);
|
||||
|
||||
if (!bus_io[count]) {
|
||||
err("out of system memory\n");
|
||||
retval = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
|
@ -706,7 +683,6 @@ static int configure_bridge(struct pci_func **func_passed, u8 slotno)
|
|||
|
||||
bus_pfmem[count] = kzalloc(sizeof(struct resource_node), GFP_KERNEL);
|
||||
if (!bus_pfmem[count]) {
|
||||
err("out of system memory\n");
|
||||
retval = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
|
@ -722,7 +698,6 @@ static int configure_bridge(struct pci_func **func_passed, u8 slotno)
|
|||
} else {
|
||||
mem_tmp = kzalloc(sizeof(*mem_tmp), GFP_KERNEL);
|
||||
if (!mem_tmp) {
|
||||
err("out of system memory\n");
|
||||
retval = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
|
@ -763,7 +738,6 @@ static int configure_bridge(struct pci_func **func_passed, u8 slotno)
|
|||
|
||||
bus_mem[count] = kzalloc(sizeof(struct resource_node), GFP_KERNEL);
|
||||
if (!bus_mem[count]) {
|
||||
err("out of system memory\n");
|
||||
retval = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
|
@ -834,7 +808,6 @@ static int configure_bridge(struct pci_func **func_passed, u8 slotno)
|
|||
io = kzalloc(sizeof(*io), GFP_KERNEL);
|
||||
|
||||
if (!io) {
|
||||
err("out of system memory\n");
|
||||
retval = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
|
@ -856,7 +829,6 @@ static int configure_bridge(struct pci_func **func_passed, u8 slotno)
|
|||
debug("it wants %x memory behind the bridge\n", amount_needed->mem);
|
||||
mem = kzalloc(sizeof(*mem), GFP_KERNEL);
|
||||
if (!mem) {
|
||||
err("out of system memory\n");
|
||||
retval = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
|
@ -878,7 +850,6 @@ static int configure_bridge(struct pci_func **func_passed, u8 slotno)
|
|||
debug("it wants %x pfmemory behind the bridge\n", amount_needed->pfmem);
|
||||
pfmem = kzalloc(sizeof(*pfmem), GFP_KERNEL);
|
||||
if (!pfmem) {
|
||||
err("out of system memory\n");
|
||||
retval = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
|
@ -893,7 +864,6 @@ static int configure_bridge(struct pci_func **func_passed, u8 slotno)
|
|||
} else {
|
||||
mem_tmp = kzalloc(sizeof(*mem_tmp), GFP_KERNEL);
|
||||
if (!mem_tmp) {
|
||||
err("out of system memory\n");
|
||||
retval = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
|
@ -924,7 +894,6 @@ static int configure_bridge(struct pci_func **func_passed, u8 slotno)
|
|||
if (!bus) {
|
||||
bus = kzalloc(sizeof(*bus), GFP_KERNEL);
|
||||
if (!bus) {
|
||||
err("out of system memory\n");
|
||||
retval = -ENOMEM;
|
||||
goto error;
|
||||
}
|
||||
|
|
@ -1652,10 +1621,9 @@ static int add_new_bus(struct bus_node *bus, struct resource_node *io, struct re
|
|||
}
|
||||
if (io) {
|
||||
io_range = kzalloc(sizeof(*io_range), GFP_KERNEL);
|
||||
if (!io_range) {
|
||||
err("out of system memory\n");
|
||||
if (!io_range)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
io_range->start = io->start;
|
||||
io_range->end = io->end;
|
||||
io_range->rangeno = 1;
|
||||
|
|
@ -1664,10 +1632,9 @@ static int add_new_bus(struct bus_node *bus, struct resource_node *io, struct re
|
|||
}
|
||||
if (mem) {
|
||||
mem_range = kzalloc(sizeof(*mem_range), GFP_KERNEL);
|
||||
if (!mem_range) {
|
||||
err("out of system memory\n");
|
||||
if (!mem_range)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
mem_range->start = mem->start;
|
||||
mem_range->end = mem->end;
|
||||
mem_range->rangeno = 1;
|
||||
|
|
@ -1676,10 +1643,9 @@ static int add_new_bus(struct bus_node *bus, struct resource_node *io, struct re
|
|||
}
|
||||
if (pfmem) {
|
||||
pfmem_range = kzalloc(sizeof(*pfmem_range), GFP_KERNEL);
|
||||
if (!pfmem_range) {
|
||||
err("out of system memory\n");
|
||||
if (!pfmem_range)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
pfmem_range->start = pfmem->start;
|
||||
pfmem_range->end = pfmem->end;
|
||||
pfmem_range->rangeno = 1;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* IBM Hot Plug Controller Driver
|
||||
*
|
||||
|
|
@ -8,21 +9,6 @@
|
|||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Send feedback to <gregkh@us.ibm.com>
|
||||
*
|
||||
*/
|
||||
|
|
@ -56,10 +42,8 @@ static struct bus_node * __init alloc_error_bus(struct ebda_pci_rsrc *curr, u8 b
|
|||
}
|
||||
|
||||
newbus = kzalloc(sizeof(struct bus_node), GFP_KERNEL);
|
||||
if (!newbus) {
|
||||
err("out of system memory\n");
|
||||
if (!newbus)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (flag)
|
||||
newbus->busno = busno;
|
||||
|
|
@ -79,10 +63,9 @@ static struct resource_node * __init alloc_resources(struct ebda_pci_rsrc *curr)
|
|||
}
|
||||
|
||||
rs = kzalloc(sizeof(struct resource_node), GFP_KERNEL);
|
||||
if (!rs) {
|
||||
err("out of system memory\n");
|
||||
if (!rs)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rs->busno = curr->bus_num;
|
||||
rs->devfunc = curr->dev_fun;
|
||||
rs->start = curr->start_addr;
|
||||
|
|
@ -99,10 +82,9 @@ static int __init alloc_bus_range(struct bus_node **new_bus, struct range_node *
|
|||
|
||||
if (first_bus) {
|
||||
newbus = kzalloc(sizeof(struct bus_node), GFP_KERNEL);
|
||||
if (!newbus) {
|
||||
err("out of system memory.\n");
|
||||
if (!newbus)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
newbus->busno = curr->bus_num;
|
||||
} else {
|
||||
newbus = *new_bus;
|
||||
|
|
@ -123,7 +105,6 @@ static int __init alloc_bus_range(struct bus_node **new_bus, struct range_node *
|
|||
if (!newrange) {
|
||||
if (first_bus)
|
||||
kfree(newbus);
|
||||
err("out of system memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
newrange->start = curr->start_addr;
|
||||
|
|
@ -1707,10 +1688,9 @@ static int __init once_over(void)
|
|||
bus_cur->firstPFMemFromMem = pfmem_cur;
|
||||
|
||||
mem = kzalloc(sizeof(struct resource_node), GFP_KERNEL);
|
||||
if (!mem) {
|
||||
err("out of system memory\n");
|
||||
if (!mem)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
mem->type = MEM;
|
||||
mem->busno = pfmem_cur->busno;
|
||||
mem->devfunc = pfmem_cur->devfunc;
|
||||
|
|
@ -1989,10 +1969,9 @@ static int __init update_bridge_ranges(struct bus_node **bus)
|
|||
|
||||
if ((start_address) && (start_address <= end_address)) {
|
||||
range = kzalloc(sizeof(struct range_node), GFP_KERNEL);
|
||||
if (!range) {
|
||||
err("out of system memory\n");
|
||||
if (!range)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
range->start = start_address;
|
||||
range->end = end_address + 0xfff;
|
||||
|
||||
|
|
@ -2016,7 +1995,6 @@ static int __init update_bridge_ranges(struct bus_node **bus)
|
|||
io = kzalloc(sizeof(struct resource_node), GFP_KERNEL);
|
||||
if (!io) {
|
||||
kfree(range);
|
||||
err("out of system memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
io->type = IO;
|
||||
|
|
@ -2038,10 +2016,9 @@ static int __init update_bridge_ranges(struct bus_node **bus)
|
|||
if ((start_address) && (start_address <= end_address)) {
|
||||
|
||||
range = kzalloc(sizeof(struct range_node), GFP_KERNEL);
|
||||
if (!range) {
|
||||
err("out of system memory\n");
|
||||
if (!range)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
range->start = start_address;
|
||||
range->end = end_address + 0xfffff;
|
||||
|
||||
|
|
@ -2066,7 +2043,6 @@ static int __init update_bridge_ranges(struct bus_node **bus)
|
|||
mem = kzalloc(sizeof(struct resource_node), GFP_KERNEL);
|
||||
if (!mem) {
|
||||
kfree(range);
|
||||
err("out of system memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
mem->type = MEM;
|
||||
|
|
@ -2092,10 +2068,9 @@ static int __init update_bridge_ranges(struct bus_node **bus)
|
|||
if ((start_address) && (start_address <= end_address)) {
|
||||
|
||||
range = kzalloc(sizeof(struct range_node), GFP_KERNEL);
|
||||
if (!range) {
|
||||
err("out of system memory\n");
|
||||
if (!range)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
range->start = start_address;
|
||||
range->end = end_address + 0xfffff;
|
||||
|
||||
|
|
@ -2119,7 +2094,6 @@ static int __init update_bridge_ranges(struct bus_node **bus)
|
|||
pfmem = kzalloc(sizeof(struct resource_node), GFP_KERNEL);
|
||||
if (!pfmem) {
|
||||
kfree(range);
|
||||
err("out of system memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
pfmem->type = PFMEM;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* PCI HotPlug Controller Core
|
||||
*
|
||||
|
|
@ -6,21 +7,6 @@
|
|||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Send feedback to <kristen.c.accardi@intel.com>
|
||||
*
|
||||
* Authors:
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||
/*
|
||||
* PCI Express Hot Plug Controller Driver
|
||||
*
|
||||
|
|
@ -8,21 +9,6 @@
|
|||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com>
|
||||
*
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* PCI Express Hot Plug Controller Driver
|
||||
*
|
||||
|
|
@ -8,21 +9,6 @@
|
|||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com>
|
||||
*
|
||||
* Authors:
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* PCI Express Hot Plug Controller Driver
|
||||
*
|
||||
|
|
@ -8,21 +9,6 @@
|
|||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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, GOOD TITLE or
|
||||
* NON INFRINGEMENT. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com>
|
||||
*
|
||||
*/
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue