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:
Linus Torvalds 2018-02-06 09:59:40 -08:00
commit 105cf3c8c6
248 changed files with 4503 additions and 3756 deletions

View file

@ -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"

View file

@ -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/

View file

@ -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;
}

View file

@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/*
* drivers/pci/ats.c
*

View file

@ -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;

View 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

View 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

View 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);

View 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);

View 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);
}

View 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 */

View file

@ -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

View file

@ -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

View file

@ -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, &reg, 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);

View file

@ -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);

View file

@ -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>

View file

@ -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>

View file

@ -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;

View file

@ -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

View file

@ -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>

View file

@ -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>

View file

@ -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,
},
{},
};

View file

@ -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);

View file

@ -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);

View file

@ -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>

View file

@ -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,

View file

@ -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 */

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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))

View file

@ -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>

View file

@ -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>

View file

@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
#
# PCI Endpoint Support
#

View file

@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for PCI Endpoint Support
#

View file

@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
#
# PCI Endpoint Functions
#

View file

@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for PCI Endpoint Functions
#

View file

@ -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;

View file

@ -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)

View file

@ -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;

View file

@ -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>

View file

@ -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)

View file

@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/*
* host bridge related code
*/

View file

@ -1,3 +1,5 @@
# SPDX-License-Identifier: GPL-2.0
menu "PCI host controller drivers"
depends on PCI

View file

@ -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

View file

@ -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>

View file

@ -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;
}

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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;

View file

@ -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.
*/

View file

@ -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.
*/

View file

@ -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>

View file

@ -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;

View file

@ -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>

View file

@ -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);

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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)) {

View file

@ -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;

View file

@ -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;

View file

@ -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>

View file

@ -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;

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
#
# PCI Hotplug support
#

View file

@ -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>
*
*/

View file

@ -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>
*

View file

@ -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>
*
*/

View file

@ -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);

View file

@ -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>
*
*/

View file

@ -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>
*/

View file

@ -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>
*/

View file

@ -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>
*/

View file

@ -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.

View file

@ -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>
*/

View file

@ -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>
*/

View file

@ -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>
*
*/

View file

@ -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;
}

View file

@ -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>
*
*/

View file

@ -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>
*
*/

View file

@ -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>
*
*/

View file

@ -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]));

View file

@ -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>
*
*/

View file

@ -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>
*
*/

View file

@ -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;
}

View file

@ -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>
*
*/

View file

@ -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>
*

View file

@ -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;

View file

@ -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;

View file

@ -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:

View file

@ -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>
*
*/

View file

@ -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:

View file

@ -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