Merge tag 'pci-v6.8-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci

Pull pci updates from Bjorn Helgaas:
 "Enumeration:

   - Reserve ECAM so we don't assign it to PCI BARs; this works around
     bugs where BIOS included ECAM in a PNP0A03 host bridge window,
     didn't reserve it via a PNP0C02 motherboard device, and didn't
     allocate space for SR-IOV VF BARs (Bjorn Helgaas)

   - Add MMCONFIG/ECAM debug logging (Bjorn Helgaas)

   - Rename 'MMCONFIG' to 'ECAM' to match spec usage (Bjorn Helgaas)

   - Log device type (Root Port, Switch Port, etc) during enumeration
     (Bjorn Helgaas)

   - Log bridges before downstream devices so the dmesg order is more
     logical (Bjorn Helgaas)

   - Log resource names (BAR 0, VF BAR 0, bridge window, etc)
     consistently instead of a mix of names and "reg 0x10" (Puranjay
     Mohan, Bjorn Helgaas)

   - Fix 64GT/s effective data rate calculation to use 1b/1b encoding
     rather than the 8b/10b or 128b/130b used by lower rates (Ilpo
     Järvinen)

   - Use PCI_HEADER_TYPE_* instead of literals in x86, powerpc, SCSI
     lpfc (Ilpo Järvinen)

   - Clean up open-coded PCIBIOS return code mangling (Ilpo Järvinen)

  Resource management:

   - Restructure pci_dev_for_each_resource() to avoid computing the
     address of an out-of-bounds array element (the bounds check was
     performed later so the element was never actually *read*, but it's
     nicer to avoid even computing an out-of-bounds address) (Andy
     Shevchenko)

  Driver binding:

   - Convert pci-host-common.c platform .remove() callback to
     .remove_new() returning 'void' since it's not useful to return
     error codes here (Uwe Kleine-König)

   - Convert exynos, keystone, kirin from .remove() to .remove_new(),
     which returns void instead of int (Uwe Kleine-König)

   - Drop unused struct pci_driver.node member (Mathias Krause)

  Virtualization:

   - Add ACS quirk for more Zhaoxin Root Ports (LeoLiuoc)

  Error handling:

   - Log AER errors as "Correctable" (not "Corrected") or
     "Uncorrectable" to match spec terminology (Bjorn Helgaas)

   - Decode Requester ID when no error info found instead of printing
     the raw hex value (Bjorn Helgaas)

  Endpoint framework:

   - Use a unique test pattern for each BAR in the pci_endpoint_test to
     make it easier to debug address translation issues (Niklas Cassel)

  Broadcom STB PCIe controller driver:

   - Add DT property "brcm,clkreq-mode" and driver support for different
     CLKREQ# modes to make ASPM L1.x states possible (Jim Quinlan)

  Freescale Layerscape PCIe controller driver:

   - Add suspend/resume support for Layerscape LS1043a and LS1021a,
     including software-managed PME_Turn_Off and transitions between L0,
     L2/L3_Ready Link states (Frank Li)

  MediaTek PCIe controller driver:

   - Clear MSI interrupt status before handler to avoid missing MSIs
     that occur after the handler (qizhong cheng)

  MediaTek PCIe Gen3 controller driver:

   - Update mediatek-gen3 translation window setup to handle MMIO space
     that is not a power of two in size (Jianjun Wang)

  Qualcomm PCIe controller driver:

   - Increase qcom iommu-map maxItems to accommodate SDX55 (five
     entries) and SDM845 (sixteen entries) (Krzysztof Kozlowski)

   - Describe qcom,pcie-sc8180x clocks and resets accurately (Krzysztof
     Kozlowski)

   - Describe qcom,pcie-sm8150 clocks and resets accurately (Krzysztof
     Kozlowski)

   - Correct the qcom "reset-name" property, previously incorrectly
     called "reset-names" (Krzysztof Kozlowski)

   - Document qcom,pcie-sm8650, based on qcom,pcie-sm8550 (Neil
     Armstrong)

  Renesas R-Car PCIe controller driver:

   - Replace of_device.h with explicit of.h include to untangle header
     usage (Rob Herring)

   - Add DT and driver support for optional miniPCIe 1.5v and 3.3v
     regulators on KingFisher (Wolfram Sang)

  SiFive FU740 PCIe controller driver:

   - Convert fu740 CONFIG_PCIE_FU740 dependency from SOC_SIFIVE to
     ARCH_SIFIVE (Conor Dooley)

  Synopsys DesignWare PCIe controller driver:

   - Align iATU mapping for endpoint MSI-X (Niklas Cassel)

   - Drop "host_" prefix from struct dw_pcie_host_ops members (Yoshihiro
     Shimoda)

   - Drop "ep_" prefix from struct dw_pcie_ep_ops members (Yoshihiro
     Shimoda)

   - Rename struct dw_pcie_ep_ops.func_conf_select() to
     .get_dbi_offset() to be more descriptive (Yoshihiro Shimoda)

   - Add Endpoint DBI accessors to encapsulate offset lookups (Yoshihiro
     Shimoda)

  TI J721E PCIe driver:

   - Add j721e DT and driver support for 'num-lanes' for devices that
     support x1, x2, or x4 Links (Matt Ranostay)

   - Add j721e DT compatible strings and driver support for j784s4 (Matt
     Ranostay)

   - Make TI J721E Kconfig depend on ARCH_K3 since the hardware is
     specific to those TI SoC parts (Peter Robinson)

  TI Keystone PCIe controller driver:

   - Hold power management references to all PHYs while enabling them to
     avoid a race when one provides clocks to others (Siddharth
     Vadapalli)

  Xilinx XDMA PCIe controller driver:

   - Remove redundant dev_err(), since platform_get_irq() and
     platform_get_irq_byname() already log errors (Yang Li)

   - Fix uninitialized symbols in xilinx_pl_dma_pcie_setup_irq()
     (Krzysztof Wilczyński)

   - Fix xilinx_pl_dma_pcie_init_irq_domain() error return when
     irq_domain_add_linear() fails (Harshit Mogalapalli)

  MicroSemi Switchtec management driver:

   - Do dma_mrpc cleanup during switchtec_pci_remove() to match its devm
     ioremapping in switchtec_pci_probe(). Previously the cleanup was
     done in stdev_release(), which used stale pointers if stdev->cdev
     happened to be open when the PCI device was removed (Daniel
     Stodden)

  Miscellaneous:

   - Convert interrupt terminology from "legacy" to "INTx" to be more
     specific and match spec terminology (Damien Le Moal)

   - In dw-xdata-pcie, pci_endpoint_test, and vmd, replace usage of
     deprecated ida_simple_*() API with ida_alloc() and ida_free()
     (Christophe JAILLET)"

* tag 'pci-v6.8-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/pci/pci: (97 commits)
  PCI: Fix kernel-doc issues
  PCI: brcmstb: Configure HW CLKREQ# mode appropriate for downstream device
  dt-bindings: PCI: brcmstb: Add property "brcm,clkreq-mode"
  PCI: mediatek-gen3: Fix translation window size calculation
  PCI: mediatek: Clear interrupt status before dispatching handler
  PCI: keystone: Fix race condition when initializing PHYs
  PCI: xilinx-xdma: Fix error code in xilinx_pl_dma_pcie_init_irq_domain()
  PCI: xilinx-xdma: Fix uninitialized symbols in xilinx_pl_dma_pcie_setup_irq()
  PCI: rcar-gen4: Fix -Wvoid-pointer-to-enum-cast error
  PCI: iproc: Fix -Wvoid-pointer-to-enum-cast warning
  PCI: dwc: Add dw_pcie_ep_{read,write}_dbi[2] helpers
  PCI: dwc: Rename .func_conf_select to .get_dbi_offset in struct dw_pcie_ep_ops
  PCI: dwc: Rename .ep_init to .init in struct dw_pcie_ep_ops
  PCI: dwc: Drop host prefix from struct dw_pcie_host_ops members
  misc: pci_endpoint_test: Use a unique test pattern for each BAR
  PCI: j721e: Make TI J721E depend on ARCH_K3
  PCI: j721e: Add TI J784S4 PCIe configuration
  PCI/AER: Use explicit register sizes for struct members
  PCI/AER: Decode Requester ID when no error info found
  PCI/AER: Use 'Correctable' and 'Uncorrectable' spec terms for errors
  ...
This commit is contained in:
Linus Torvalds
2024-01-17 16:23:17 -08:00
88 changed files with 1519 additions and 877 deletions
+1 -1
View File
@@ -61,7 +61,7 @@ Conditions
==========
The use of threaded interrupts is the most likely condition to trigger
this problem today. Threaded interrupts may not be reenabled after the IRQ
this problem today. Threaded interrupts may not be re-enabled after the IRQ
handler wakes. These "one shot" conditions mean that the threaded interrupt
needs to keep the interrupt line masked until the threaded handler has run.
Especially when dealing with high data rate interrupts, the thread needs to
+1 -1
View File
@@ -236,7 +236,7 @@ including a full 'lspci -v' so we can add the quirks to the kernel.
Disabling MSIs below a bridge
-----------------------------
Some PCI bridges are not able to route MSIs between busses properly.
Some PCI bridges are not able to route MSIs between buses properly.
In this case, MSIs must be disabled on all devices behind the bridge.
Some bridges allow you to enable MSIs by changing some bits in their
@@ -64,6 +64,24 @@ properties:
aspm-no-l0s: true
brcm,clkreq-mode:
description: A string that determines the operating
clkreq mode of the PCIe RC HW with respect to controlling the refclk
signal. There are three different modes -- "safe", which drives the
refclk signal unconditionally and will work for all devices but does
not provide any power savings; "no-l1ss" -- which provides Clock
Power Management, L0s, and L1, but cannot provide L1 substate (L1SS)
power savings. If the downstream device connected to the RC is L1SS
capable AND the OS enables L1SS, all PCIe traffic may abruptly halt,
potentially hanging the system; "default" -- which provides L0s, L1,
and L1SS, but not compliant to provide Clock Power Management;
specifically, may not be able to meet the T_CLRon max timing of 400ns
as specified in "Dynamic Clock Control", section 3.2.5.2.2 PCI
Express Mini CEM 2.1 specification. This situation is atypical and
should happen only with older devices.
$ref: /schemas/types.yaml#/definitions/string
enum: [ safe, no-l1ss, default ]
brcm,scb-sizes:
description: u64 giving the 64bit PCIe memory
viewport size of a memory controller. There may be up to
@@ -41,6 +41,10 @@ properties:
- qcom,pcie-sm8450-pcie0
- qcom,pcie-sm8450-pcie1
- qcom,pcie-sm8550
- items:
- enum:
- qcom,pcie-sm8650
- const: qcom,pcie-sm8550
- items:
- const: qcom,pcie-msm8998
- const: qcom,pcie-msm8996
@@ -62,7 +66,8 @@ properties:
maxItems: 8
iommu-map:
maxItems: 2
minItems: 1
maxItems: 16
# Common definitions for clocks, clock-names and reset.
# Platform constraints are described later.
@@ -88,7 +93,7 @@ properties:
minItems: 1
maxItems: 12
resets-names:
reset-names:
minItems: 1
maxItems: 12
@@ -478,6 +483,33 @@ allOf:
items:
- const: pci # PCIe core reset
- if:
properties:
compatible:
contains:
enum:
- qcom,pcie-sc8180x
then:
properties:
clocks:
minItems: 8
maxItems: 8
clock-names:
items:
- const: pipe # PIPE clock
- const: aux # Auxiliary clock
- const: cfg # Configuration clock
- const: bus_master # Master AXI clock
- const: bus_slave # Slave AXI clock
- const: slave_q2a # Slave Q2A clock
- const: ref # REFERENCE clock
- const: tbu # PCIe TBU clock
resets:
maxItems: 1
reset-names:
items:
- const: pci # PCIe core reset
- if:
properties:
compatible:
@@ -526,8 +558,33 @@ allOf:
compatible:
contains:
enum:
- qcom,pcie-sc8180x
- qcom,pcie-sm8150
then:
properties:
clocks:
minItems: 8
maxItems: 8
clock-names:
items:
- const: pipe # PIPE clock
- const: aux # Auxiliary clock
- const: cfg # Configuration clock
- const: bus_master # Master AXI clock
- const: bus_slave # Slave AXI clock
- const: slave_q2a # Slave Q2A clock
- const: tbu # PCIe TBU clock
- const: ref # REFERENCE clock
resets:
maxItems: 1
reset-names:
items:
- const: pci # PCIe core reset
- if:
properties:
compatible:
contains:
enum:
- qcom,pcie-sm8250
then:
oneOf:
@@ -68,6 +68,15 @@ properties:
phy-names:
const: pcie
vpcie1v5-supply:
description: The 1.5v regulator to use for PCIe.
vpcie3v3-supply:
description: The 3.3v regulator to use for PCIe.
vpcie12v-supply:
description: The 12v regulator to use for PCIe.
required:
- compatible
- reg
@@ -121,5 +130,7 @@ examples:
clock-names = "pcie", "pcie_bus";
power-domains = <&sysc R8A7791_PD_ALWAYS_ON>;
resets = <&cpg 319>;
vpcie3v3-supply = <&pcie_3v3>;
vpcie12v-supply = <&pcie_12v>;
};
};
@@ -49,6 +49,7 @@ properties:
- description: APB clock for PCIe
- description: Auxiliary clock for PCIe
- description: PIPE clock
- description: Reference clock for PCIe
clock-names:
minItems: 5
@@ -59,6 +60,7 @@ properties:
- const: pclk
- const: aux
- const: pipe
- const: ref
interrupts:
items:
@@ -10,13 +10,11 @@ title: TI J721E PCI EP (PCIe Wrapper)
maintainers:
- Kishon Vijay Abraham I <kishon@ti.com>
allOf:
- $ref: cdns-pcie-ep.yaml#
properties:
compatible:
oneOf:
- const: ti,j721e-pcie-ep
- const: ti,j784s4-pcie-ep
- description: PCIe EP controller in AM64
items:
- const: ti,am64-pcie-ep
@@ -65,6 +63,41 @@ properties:
items:
- const: link_state
allOf:
- $ref: cdns-pcie-ep.yaml#
- if:
properties:
compatible:
enum:
- ti,am64-pcie-ep
then:
properties:
num-lanes:
const: 1
- if:
properties:
compatible:
enum:
- ti,j7200-pcie-ep
- ti,j721e-pcie-ep
then:
properties:
num-lanes:
minimum: 1
maximum: 2
- if:
properties:
compatible:
enum:
- ti,j784s4-pcie-ep
then:
properties:
num-lanes:
minimum: 1
maximum: 4
required:
- compatible
- reg
@@ -10,13 +10,11 @@ title: TI J721E PCI Host (PCIe Wrapper)
maintainers:
- Kishon Vijay Abraham I <kishon@ti.com>
allOf:
- $ref: cdns-pcie-host.yaml#
properties:
compatible:
oneOf:
- const: ti,j721e-pcie-host
- const: ti,j784s4-pcie-host
- description: PCIe controller in AM64
items:
- const: ti,am64-pcie-host
@@ -94,6 +92,41 @@ properties:
interrupts:
maxItems: 1
allOf:
- $ref: cdns-pcie-host.yaml#
- if:
properties:
compatible:
enum:
- ti,am64-pcie-host
then:
properties:
num-lanes:
const: 1
- if:
properties:
compatible:
enum:
- ti,j7200-pcie-host
- ti,j721e-pcie-host
then:
properties:
num-lanes:
minimum: 1
maximum: 2
- if:
properties:
compatible:
enum:
- ti,j784s4-pcie-host
then:
properties:
num-lanes:
minimum: 1
maximum: 4
required:
- compatible
- reg
+3 -13
View File
@@ -83,19 +83,9 @@ this to include other types of resources like doorbells.
Client Drivers
--------------
A client driver typically only has to conditionally change its DMA map
routine to use the mapping function :c:func:`pci_p2pdma_map_sg()` instead
of the usual :c:func:`dma_map_sg()` function. Memory mapped in this
way does not need to be unmapped.
The client may also, optionally, make use of
:c:func:`is_pci_p2pdma_page()` to determine when to use the P2P mapping
functions and when to use the regular mapping functions. In some
situations, it may be more appropriate to use a flag to indicate a
given request is P2P memory and map appropriately. It is important to
ensure that struct pages that back P2P memory stay out of code that
does not have support for them as other code may treat the pages as
regular memory which may not be appropriate.
A client driver only has to use the mapping API :c:func:`dma_map_sg()`
and :c:func:`dma_unmap_sg()` functions as usual, and the implementation
will do the right thing for the P2P capable memory.
Orchestrator Drivers
+2 -2
View File
@@ -54,7 +54,7 @@ static void quirk_fsl_pcie_early(struct pci_dev *dev)
/* if we aren't in host mode don't bother */
pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr_type);
if ((hdr_type & 0x7f) != PCI_HEADER_TYPE_BRIDGE)
if ((hdr_type & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_BRIDGE)
return;
dev->class = PCI_CLASS_BRIDGE_PCI_NORMAL;
@@ -581,7 +581,7 @@ static int fsl_add_bridge(struct platform_device *pdev, int is_primary)
hose->ops = &fsl_indirect_pcie_ops;
/* For PCIE read HEADER_TYPE to identify controller mode */
early_read_config_byte(hose, 0, 0, PCI_HEADER_TYPE, &hdr_type);
if ((hdr_type & 0x7f) != PCI_HEADER_TYPE_BRIDGE)
if ((hdr_type & PCI_HEADER_TYPE_MASK) != PCI_HEADER_TYPE_BRIDGE)
goto no_bridge;
} else {
+1 -2
View File
@@ -259,10 +259,9 @@ static u32 __init search_agp_bridge(u32 *order, int *valid_agp)
order);
}
/* No multi-function device? */
type = read_pci_config_byte(bus, slot, func,
PCI_HEADER_TYPE);
if (!(type & 0x80))
if (!(type & PCI_HEADER_TYPE_MFD))
break;
}
}
+2 -2
View File
@@ -779,13 +779,13 @@ static int __init check_dev_quirk(int num, int slot, int func)
type = read_pci_config_byte(num, slot, func,
PCI_HEADER_TYPE);
if ((type & 0x7f) == PCI_HEADER_TYPE_BRIDGE) {
if ((type & PCI_HEADER_TYPE_MASK) == PCI_HEADER_TYPE_BRIDGE) {
sec = read_pci_config_byte(num, slot, func, PCI_SECONDARY_BUS);
if (sec > num)
early_pci_scan_bus(sec);
}
if (!(type & 0x80))
if (!(type & PCI_HEADER_TYPE_MFD))
return -1;
return 0;
+3
View File
@@ -283,6 +283,9 @@ static int setup_mcfg_map(struct acpi_pci_root_info *ci)
info->mcfg_added = false;
seg = info->sd.domain;
dev_dbg(dev, "%s(%04x %pR ECAM %pa)\n", __func__, seg,
&root->secondary, &root->mcfg_addr);
/* return success if MMCFG is not in use */
if (raw_pci_ext_ops && raw_pci_ext_ops != &pci_mmcfg)
return 0;
+95 -83
View File
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0
/*
* mmconfig-shared.c - Low-level direct PCI config space access via
* MMCONFIG - common code between i386 and x86-64.
* Low-level direct PCI config space access via ECAM - common code between
* i386 and x86-64.
*
* This code does:
* - known chipset handling
@@ -11,6 +11,8 @@
* themselves.
*/
#define pr_fmt(fmt) "PCI: " fmt
#include <linux/acpi.h>
#include <linux/efi.h>
#include <linux/pci.h>
@@ -24,9 +26,7 @@
#include <asm/pci_x86.h>
#include <asm/acpi.h>
#define PREFIX "PCI: "
/* Indicate if the mmcfg resources have been placed into the resource table. */
/* Indicate if the ECAM resources have been placed into the resource table */
static bool pci_mmcfg_running_state;
static bool pci_mmcfg_arch_init_failed;
static DEFINE_MUTEX(pci_mmcfg_lock);
@@ -90,7 +90,7 @@ static struct pci_mmcfg_region *pci_mmconfig_alloc(int segment, int start,
res->end = addr + PCI_MMCFG_BUS_OFFSET(end + 1) - 1;
res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
snprintf(new->name, PCI_MMCFG_RESOURCE_NAME_LEN,
"PCI MMCONFIG %04x [bus %02x-%02x]", segment, start, end);
"PCI ECAM %04x [bus %02x-%02x]", segment, start, end);
res->name = new->name;
return new;
@@ -102,16 +102,15 @@ struct pci_mmcfg_region *__init pci_mmconfig_add(int segment, int start,
struct pci_mmcfg_region *new;
new = pci_mmconfig_alloc(segment, start, end, addr);
if (new) {
mutex_lock(&pci_mmcfg_lock);
list_add_sorted(new);
mutex_unlock(&pci_mmcfg_lock);
if (!new)
return NULL;
pr_info(PREFIX
"MMCONFIG for domain %04x [bus %02x-%02x] at %pR "
"(base %#lx)\n",
segment, start, end, &new->res, (unsigned long)addr);
}
mutex_lock(&pci_mmcfg_lock);
list_add_sorted(new);
mutex_unlock(&pci_mmcfg_lock);
pr_info("ECAM %pR (base %#lx) for domain %04x [bus %02x-%02x]\n",
&new->res, (unsigned long)addr, segment, start, end);
return new;
}
@@ -205,7 +204,7 @@ static const char *__init pci_mmcfg_amd_fam10h(void)
msr <<= 32;
msr |= low;
/* mmconfig is not enable */
/* ECAM is not enabled */
if (!(msr & FAM10H_MMIO_CONF_ENABLE))
return NULL;
@@ -367,7 +366,7 @@ static int __init pci_mmcfg_check_hostbridge(void)
name = pci_mmcfg_probes[i].probe();
if (name)
pr_info(PREFIX "%s with MMCONFIG support\n", name);
pr_info("%s with ECAM support\n", name);
}
/* some end_bus_number is crazy, fix it */
@@ -443,9 +442,11 @@ static bool is_acpi_reserved(u64 start, u64 end, enum e820_type not_used)
return mcfg_res.flags;
}
static bool is_efi_mmio(u64 start, u64 end, enum e820_type not_used)
static bool is_efi_mmio(struct resource *res)
{
#ifdef CONFIG_EFI
u64 start = res->start;
u64 end = res->start + resource_size(res);
efi_memory_desc_t *md;
u64 size, mmio_start, mmio_end;
@@ -455,11 +456,6 @@ static bool is_efi_mmio(u64 start, u64 end, enum e820_type not_used)
mmio_start = md->phys_addr;
mmio_end = mmio_start + size;
/*
* N.B. Caller supplies (start, start + size),
* so to match, mmio_end is the first address
* *past* the EFI_MEMORY_MAPPED_IO area.
*/
if (mmio_start <= start && end <= mmio_end)
return true;
}
@@ -490,11 +486,10 @@ static bool __ref is_mmconf_reserved(check_reserved_t is_reserved,
return false;
if (dev)
dev_info(dev, "MMCONFIG at %pR reserved as %s\n",
dev_info(dev, "ECAM %pR reserved as %s\n",
&cfg->res, method);
else
pr_info(PREFIX "MMCONFIG at %pR reserved as %s\n",
&cfg->res, method);
pr_info("ECAM %pR reserved as %s\n", &cfg->res, method);
if (old_size != size) {
/* update end_bus */
@@ -503,47 +498,51 @@ static bool __ref is_mmconf_reserved(check_reserved_t is_reserved,
cfg->res.end = cfg->res.start +
PCI_MMCFG_BUS_OFFSET(num_buses) - 1;
snprintf(cfg->name, PCI_MMCFG_RESOURCE_NAME_LEN,
"PCI MMCONFIG %04x [bus %02x-%02x]",
"PCI ECAM %04x [bus %02x-%02x]",
cfg->segment, cfg->start_bus, cfg->end_bus);
if (dev)
dev_info(dev,
"MMCONFIG "
"at %pR (base %#lx) (size reduced!)\n",
&cfg->res, (unsigned long) cfg->address);
dev_info(dev, "ECAM %pR (base %#lx) (size reduced!)\n",
&cfg->res, (unsigned long) cfg->address);
else
pr_info(PREFIX
"MMCONFIG for %04x [bus%02x-%02x] "
"at %pR (base %#lx) (size reduced!)\n",
cfg->segment, cfg->start_bus, cfg->end_bus,
&cfg->res, (unsigned long) cfg->address);
pr_info("ECAM %pR (base %#lx) for %04x [bus%02x-%02x] (size reduced!)\n",
&cfg->res, (unsigned long) cfg->address,
cfg->segment, cfg->start_bus, cfg->end_bus);
}
return true;
}
static bool __ref
pci_mmcfg_check_reserved(struct device *dev, struct pci_mmcfg_region *cfg, int early)
static bool __ref pci_mmcfg_reserved(struct device *dev,
struct pci_mmcfg_region *cfg, int early)
{
struct resource *conflict;
if (!early && !acpi_disabled) {
if (is_mmconf_reserved(is_acpi_reserved, cfg, dev,
"ACPI motherboard resource"))
return true;
if (dev)
dev_info(dev, FW_INFO
"MMCONFIG at %pR not reserved in "
"ACPI motherboard resources\n",
dev_info(dev, FW_INFO "ECAM %pR not reserved in ACPI motherboard resources\n",
&cfg->res);
else
pr_info(FW_INFO PREFIX
"MMCONFIG at %pR not reserved in "
"ACPI motherboard resources\n",
&cfg->res);
pr_info(FW_INFO "ECAM %pR not reserved in ACPI motherboard resources\n",
&cfg->res);
if (is_mmconf_reserved(is_efi_mmio, cfg, dev,
"EfiMemoryMappedIO"))
if (is_efi_mmio(&cfg->res)) {
pr_info("ECAM %pR is EfiMemoryMappedIO; assuming valid\n",
&cfg->res);
conflict = insert_resource_conflict(&iomem_resource,
&cfg->res);
if (conflict)
pr_warn("ECAM %pR conflicts with %s %pR\n",
&cfg->res, conflict->name, conflict);
else
pr_info("ECAM %pR reserved to work around lack of ACPI motherboard _CRS\n",
&cfg->res);
return true;
}
}
/*
@@ -569,30 +568,31 @@ static void __init pci_mmcfg_reject_broken(int early)
struct pci_mmcfg_region *cfg;
list_for_each_entry(cfg, &pci_mmcfg_list, list) {
if (pci_mmcfg_check_reserved(NULL, cfg, early) == 0) {
pr_info(PREFIX "not using MMCONFIG\n");
if (!pci_mmcfg_reserved(NULL, cfg, early)) {
pr_info("not using ECAM (%pR not reserved)\n",
&cfg->res);
free_all_mmcfg();
return;
}
}
}
static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg,
struct acpi_mcfg_allocation *cfg)
static bool __init acpi_mcfg_valid_entry(struct acpi_table_mcfg *mcfg,
struct acpi_mcfg_allocation *cfg)
{
if (cfg->address < 0xFFFFFFFF)
return 0;
return true;
if (!strncmp(mcfg->header.oem_id, "SGI", 3))
return 0;
return true;
if ((mcfg->header.revision >= 1) && (dmi_get_bios_year() >= 2010))
return 0;
return true;
pr_err(PREFIX "MCFG region for %04x [bus %02x-%02x] at %#llx "
"is above 4GB, ignored\n", cfg->pci_segment,
cfg->start_bus_number, cfg->end_bus_number, cfg->address);
return -EINVAL;
pr_err("ECAM at %#llx for %04x [bus %02x-%02x] is above 4GB, ignored\n",
cfg->address, cfg->pci_segment, cfg->start_bus_number,
cfg->end_bus_number);
return false;
}
static int __init pci_parse_mcfg(struct acpi_table_header *header)
@@ -616,21 +616,21 @@ static int __init pci_parse_mcfg(struct acpi_table_header *header)
i -= sizeof(struct acpi_mcfg_allocation);
}
if (entries == 0) {
pr_err(PREFIX "MMCONFIG has no entries\n");
pr_err("MCFG has no entries\n");
return -ENODEV;
}
cfg_table = (struct acpi_mcfg_allocation *) &mcfg[1];
for (i = 0; i < entries; i++) {
cfg = &cfg_table[i];
if (acpi_mcfg_check_entry(mcfg, cfg)) {
if (!acpi_mcfg_valid_entry(mcfg, cfg)) {
free_all_mmcfg();
return -ENODEV;
}
if (pci_mmconfig_add(cfg->pci_segment, cfg->start_bus_number,
cfg->end_bus_number, cfg->address) == NULL) {
pr_warn(PREFIX "no memory for MCFG entries\n");
pr_warn("no memory for MCFG entries\n");
free_all_mmcfg();
return -ENOMEM;
}
@@ -667,6 +667,8 @@ static int pci_mmcfg_for_each_region(int (*func)(__u64 start, __u64 size,
static void __init __pci_mmcfg_init(int early)
{
pr_debug("%s(%s)\n", __func__, early ? "early" : "late");
pci_mmcfg_reject_broken(early);
if (list_empty(&pci_mmcfg_list))
return;
@@ -693,6 +695,8 @@ static int __initdata known_bridge;
void __init pci_mmcfg_early_init(void)
{
pr_debug("%s() pci_probe %#x\n", __func__, pci_probe);
if (pci_probe & PCI_PROBE_MMCONF) {
if (pci_mmcfg_check_hostbridge())
known_bridge = 1;
@@ -706,14 +710,16 @@ void __init pci_mmcfg_early_init(void)
void __init pci_mmcfg_late_init(void)
{
/* MMCONFIG disabled */
pr_debug("%s() pci_probe %#x\n", __func__, pci_probe);
/* ECAM disabled */
if ((pci_probe & PCI_PROBE_MMCONF) == 0)
return;
if (known_bridge)
return;
/* MMCONFIG hasn't been enabled yet, try again */
/* ECAM hasn't been enabled yet, try again */
if (pci_probe & PCI_PROBE_MASK & ~PCI_PROBE_MMCONF) {
acpi_table_parse(ACPI_SIG_MCFG, pci_parse_mcfg);
__pci_mmcfg_init(0);
@@ -726,7 +732,9 @@ static int __init pci_mmcfg_late_insert_resources(void)
pci_mmcfg_running_state = true;
/* If we are not using MMCONFIG, don't insert the resources. */
pr_debug("%s() pci_probe %#x\n", __func__, pci_probe);
/* If we are not using ECAM, don't insert the resources. */
if ((pci_probe & PCI_PROBE_MMCONF) == 0)
return 1;
@@ -735,21 +743,24 @@ static int __init pci_mmcfg_late_insert_resources(void)
* marked so it won't cause request errors when __request_region is
* called.
*/
list_for_each_entry(cfg, &pci_mmcfg_list, list)
if (!cfg->res.parent)
list_for_each_entry(cfg, &pci_mmcfg_list, list) {
if (!cfg->res.parent) {
pr_debug("%s() insert %pR\n", __func__, &cfg->res);
insert_resource(&iomem_resource, &cfg->res);
}
}
return 0;
}
/*
* Perform MMCONFIG resource insertion after PCI initialization to allow for
* Perform ECAM resource insertion after PCI initialization to allow for
* misprogrammed MCFG tables that state larger sizes but actually conflict
* with other system resources.
*/
late_initcall(pci_mmcfg_late_insert_resources);
/* Add MMCFG information for host bridges */
/* Add ECAM information for host bridges */
int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
phys_addr_t addr)
{
@@ -757,6 +768,8 @@ int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
struct resource *tmp = NULL;
struct pci_mmcfg_region *cfg;
dev_dbg(dev, "%s(%04x [bus %02x-%02x])\n", __func__, seg, start, end);
if (!(pci_probe & PCI_PROBE_MMCONF) || pci_mmcfg_arch_init_failed)
return -ENODEV;
@@ -767,15 +780,17 @@ int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
cfg = pci_mmconfig_lookup(seg, start);
if (cfg) {
if (cfg->end_bus < end)
dev_info(dev, FW_INFO
"MMCONFIG for "
"domain %04x [bus %02x-%02x] "
"only partially covers this bridge\n",
cfg->segment, cfg->start_bus, cfg->end_bus);
dev_info(dev, FW_INFO "ECAM %pR for domain %04x [bus %02x-%02x] only partially covers this bridge\n",
&cfg->res, cfg->segment, cfg->start_bus,
cfg->end_bus);
mutex_unlock(&pci_mmcfg_lock);
return -EEXIST;
}
/*
* Don't move earlier; we must return -EEXIST, not -EINVAL, if
* pci_mmconfig_lookup() finds something
*/
if (!addr) {
mutex_unlock(&pci_mmcfg_lock);
return -EINVAL;
@@ -784,10 +799,10 @@ int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
rc = -EBUSY;
cfg = pci_mmconfig_alloc(seg, start, end, addr);
if (cfg == NULL) {
dev_warn(dev, "fail to add MMCONFIG (out of memory)\n");
dev_warn(dev, "fail to add ECAM (out of memory)\n");
rc = -ENOMEM;
} else if (!pci_mmcfg_check_reserved(dev, cfg, 0)) {
dev_warn(dev, FW_BUG "MMCONFIG %pR isn't reserved\n",
} else if (!pci_mmcfg_reserved(dev, cfg, 0)) {
dev_warn(dev, FW_BUG "ECAM %pR isn't reserved\n",
&cfg->res);
} else {
/* Insert resource if it's not in boot stage */
@@ -796,16 +811,13 @@ int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
&cfg->res);
if (tmp) {
dev_warn(dev,
"MMCONFIG %pR conflicts with "
"%s %pR\n",
dev_warn(dev, "ECAM %pR conflicts with %s %pR\n",
&cfg->res, tmp->name, tmp);
} else if (pci_mmcfg_arch_map(cfg)) {
dev_warn(dev, "fail to map MMCONFIG %pR.\n",
&cfg->res);
dev_warn(dev, "fail to map ECAM %pR\n", &cfg->res);
} else {
list_add_sorted(cfg);
dev_info(dev, "MMCONFIG at %pR (base %#lx)\n",
dev_info(dev, "ECAM %pR (base %#lx)\n",
&cfg->res, (unsigned long)addr);
cfg = NULL;
rc = 0;
@@ -823,7 +835,7 @@ int pci_mmconfig_insert(struct device *dev, u16 seg, u8 start, u8 end,
return rc;
}
/* Delete MMCFG information for host bridges */
/* Delete ECAM information for host bridges */
int pci_mmconfig_delete(u16 seg, u8 start, u8 end)
{
struct pci_mmcfg_region *cfg;
+1 -1
View File
@@ -131,7 +131,7 @@ const struct pci_raw_ops pci_mmcfg = {
int __init pci_mmcfg_arch_init(void)
{
printk(KERN_INFO "PCI: Using MMCONFIG for extended config space\n");
printk(KERN_INFO "PCI: Using ECAM for extended config space\n");
raw_pci_ext_ops = &pci_mmcfg;
return 1;
}
+21 -21
View File
@@ -6,6 +6,8 @@
* space mapped. This allows lockless config space operation.
*/
#define pr_fmt(fmt) "PCI: " fmt
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/acpi.h>
@@ -14,8 +16,6 @@
#include <asm/e820/api.h>
#include <asm/pci_x86.h>
#define PREFIX "PCI: "
static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
{
struct pci_mmcfg_region *cfg = pci_mmconfig_lookup(seg, bus);
@@ -111,6 +111,25 @@ static void __iomem *mcfg_ioremap(struct pci_mmcfg_region *cfg)
return addr;
}
int pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg)
{
cfg->virt = mcfg_ioremap(cfg);
if (!cfg->virt) {
pr_err("can't map ECAM at %pR\n", &cfg->res);
return -ENOMEM;
}
return 0;
}
void pci_mmcfg_arch_unmap(struct pci_mmcfg_region *cfg)
{
if (cfg && cfg->virt) {
iounmap(cfg->virt + PCI_MMCFG_BUS_OFFSET(cfg->start_bus));
cfg->virt = NULL;
}
}
int __init pci_mmcfg_arch_init(void)
{
struct pci_mmcfg_region *cfg;
@@ -133,22 +152,3 @@ void __init pci_mmcfg_arch_free(void)
list_for_each_entry(cfg, &pci_mmcfg_list, list)
pci_mmcfg_arch_unmap(cfg);
}
int pci_mmcfg_arch_map(struct pci_mmcfg_region *cfg)
{
cfg->virt = mcfg_ioremap(cfg);
if (!cfg->virt) {
pr_err(PREFIX "can't map MMCONFIG at %pR\n", &cfg->res);
return -ENOMEM;
}
return 0;
}
void pci_mmcfg_arch_unmap(struct pci_mmcfg_region *cfg)
{
if (cfg && cfg->virt) {
iounmap(cfg->virt + PCI_MMCFG_BUS_OFFSET(cfg->start_bus));
cfg->virt = NULL;
}
}
+21 -7
View File
@@ -3,6 +3,8 @@
* BIOS32 and PCI BIOS handling.
*/
#include <linux/bits.h>
#include <linux/bitfield.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -29,8 +31,19 @@
#define PCIBIOS_HW_TYPE1_SPEC 0x10
#define PCIBIOS_HW_TYPE2_SPEC 0x20
/*
* Returned in EAX:
* - AH: return code
*/
#define PCIBIOS_RETURN_CODE GENMASK(15, 8)
int pcibios_enabled;
static u8 pcibios_get_return_code(u32 eax)
{
return FIELD_GET(PCIBIOS_RETURN_CODE, eax);
}
/* According to the BIOS specification at:
* http://members.datafast.net.au/dft0802/specs/bios21.pdf, we could
* restrict the x zone to some pages and make it ro. But this may be
@@ -154,7 +167,7 @@ static int __init check_pcibios(void)
: "memory");
local_irq_restore(flags);
status = (eax >> 8) & 0xff;
status = pcibios_get_return_code(eax);
hw_mech = eax & 0xff;
major_ver = (ebx >> 8) & 0xff;
minor_ver = ebx & 0xff;
@@ -227,7 +240,7 @@ static int pci_bios_read(unsigned int seg, unsigned int bus,
raw_spin_unlock_irqrestore(&pci_config_lock, flags);
return (int)((result & 0xff00) >> 8);
return pcibios_get_return_code(result);
}
static int pci_bios_write(unsigned int seg, unsigned int bus,
@@ -269,7 +282,7 @@ static int pci_bios_write(unsigned int seg, unsigned int bus,
raw_spin_unlock_irqrestore(&pci_config_lock, flags);
return (int)((result & 0xff00) >> 8);
return pcibios_get_return_code(result);
}
@@ -385,9 +398,10 @@ struct irq_routing_table * pcibios_get_irq_routing_table(void)
"m" (opt)
: "memory");
DBG("OK ret=%d, size=%d, map=%x\n", ret, opt.size, map);
if (ret & 0xff00)
printk(KERN_ERR "PCI: Error %02x when fetching IRQ routing table.\n", (ret >> 8) & 0xff);
else if (opt.size) {
ret = pcibios_get_return_code(ret);
if (ret) {
printk(KERN_ERR "PCI: Error %02x when fetching IRQ routing table.\n", ret);
} else if (opt.size) {
rt = kmalloc(sizeof(struct irq_routing_table) + opt.size, GFP_KERNEL);
if (rt) {
memset(rt, 0, sizeof(struct irq_routing_table));
@@ -415,7 +429,7 @@ int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq)
"b" ((dev->bus->number << 8) | dev->devfn),
"c" ((irq << 8) | (pin + 10)),
"S" (&pci_indirect));
return !(ret & 0xff00);
return pcibios_get_return_code(ret) == PCIBIOS_SUCCESSFUL;
}
EXPORT_SYMBOL(pcibios_set_irq_routing);
+3 -3
View File
@@ -333,7 +333,7 @@ static int dw_xdata_pcie_probe(struct pci_dev *pdev,
dw->pdev = pdev;
id = ida_simple_get(&xdata_ida, 0, 0, GFP_KERNEL);
id = ida_alloc(&xdata_ida, GFP_KERNEL);
if (id < 0) {
dev_err(dev, "xData: unable to get id\n");
return id;
@@ -377,7 +377,7 @@ err_kfree_name:
kfree(dw->misc_dev.name);
err_ida_remove:
ida_simple_remove(&xdata_ida, id);
ida_free(&xdata_ida, id);
return err;
}
@@ -396,7 +396,7 @@ static void dw_xdata_pcie_remove(struct pci_dev *pdev)
dw_xdata_stop(dw);
misc_deregister(&dw->misc_dev);
kfree(dw->misc_dev.name);
ida_simple_remove(&xdata_ida, id);
ida_free(&xdata_ida, id);
}
static const struct pci_device_id dw_xdata_pcie_id_table[] = {
+30 -20
View File
@@ -28,14 +28,14 @@
#define DRV_MODULE_NAME "pci-endpoint-test"
#define IRQ_TYPE_UNDEFINED -1
#define IRQ_TYPE_LEGACY 0
#define IRQ_TYPE_INTX 0
#define IRQ_TYPE_MSI 1
#define IRQ_TYPE_MSIX 2
#define PCI_ENDPOINT_TEST_MAGIC 0x0
#define PCI_ENDPOINT_TEST_COMMAND 0x4
#define COMMAND_RAISE_LEGACY_IRQ BIT(0)
#define COMMAND_RAISE_INTX_IRQ BIT(0)
#define COMMAND_RAISE_MSI_IRQ BIT(1)
#define COMMAND_RAISE_MSIX_IRQ BIT(2)
#define COMMAND_READ BIT(3)
@@ -183,8 +183,8 @@ static bool pci_endpoint_test_alloc_irq_vectors(struct pci_endpoint_test *test,
bool res = true;
switch (type) {
case IRQ_TYPE_LEGACY:
irq = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_LEGACY);
case IRQ_TYPE_INTX:
irq = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_INTX);
if (irq < 0)
dev_err(dev, "Failed to get Legacy interrupt\n");
break;
@@ -244,7 +244,7 @@ static bool pci_endpoint_test_request_irq(struct pci_endpoint_test *test)
fail:
switch (irq_type) {
case IRQ_TYPE_LEGACY:
case IRQ_TYPE_INTX:
dev_err(dev, "Failed to request IRQ %d for Legacy\n",
pci_irq_vector(pdev, i));
break;
@@ -263,6 +263,15 @@ fail:
return false;
}
static const u32 bar_test_pattern[] = {
0xA0A0A0A0,
0xA1A1A1A1,
0xA2A2A2A2,
0xA3A3A3A3,
0xA4A4A4A4,
0xA5A5A5A5,
};
static bool pci_endpoint_test_bar(struct pci_endpoint_test *test,
enum pci_barno barno)
{
@@ -280,26 +289,27 @@ static bool pci_endpoint_test_bar(struct pci_endpoint_test *test,
size = 0x4;
for (j = 0; j < size; j += 4)
pci_endpoint_test_bar_writel(test, barno, j, 0xA0A0A0A0);
pci_endpoint_test_bar_writel(test, barno, j,
bar_test_pattern[barno]);
for (j = 0; j < size; j += 4) {
val = pci_endpoint_test_bar_readl(test, barno, j);
if (val != 0xA0A0A0A0)
if (val != bar_test_pattern[barno])
return false;
}
return true;
}
static bool pci_endpoint_test_legacy_irq(struct pci_endpoint_test *test)
static bool pci_endpoint_test_intx_irq(struct pci_endpoint_test *test)
{
u32 val;
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_TYPE,
IRQ_TYPE_LEGACY);
IRQ_TYPE_INTX);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_IRQ_NUMBER, 0);
pci_endpoint_test_writel(test, PCI_ENDPOINT_TEST_COMMAND,
COMMAND_RAISE_LEGACY_IRQ);
COMMAND_RAISE_INTX_IRQ);
val = wait_for_completion_timeout(&test->irq_raised,
msecs_to_jiffies(1000));
if (!val)
@@ -385,7 +395,7 @@ static bool pci_endpoint_test_copy(struct pci_endpoint_test *test,
if (use_dma)
flags |= FLAG_USE_DMA;
if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) {
if (irq_type < IRQ_TYPE_INTX || irq_type > IRQ_TYPE_MSIX) {
dev_err(dev, "Invalid IRQ type option\n");
goto err;
}
@@ -521,7 +531,7 @@ static bool pci_endpoint_test_write(struct pci_endpoint_test *test,
if (use_dma)
flags |= FLAG_USE_DMA;
if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) {
if (irq_type < IRQ_TYPE_INTX || irq_type > IRQ_TYPE_MSIX) {
dev_err(dev, "Invalid IRQ type option\n");
goto err;
}
@@ -621,7 +631,7 @@ static bool pci_endpoint_test_read(struct pci_endpoint_test *test,
if (use_dma)
flags |= FLAG_USE_DMA;
if (irq_type < IRQ_TYPE_LEGACY || irq_type > IRQ_TYPE_MSIX) {
if (irq_type < IRQ_TYPE_INTX || irq_type > IRQ_TYPE_MSIX) {
dev_err(dev, "Invalid IRQ type option\n");
goto err;
}
@@ -691,7 +701,7 @@ static bool pci_endpoint_test_set_irq(struct pci_endpoint_test *test,
struct pci_dev *pdev = test->pdev;
struct device *dev = &pdev->dev;
if (req_irq_type < IRQ_TYPE_LEGACY || req_irq_type > IRQ_TYPE_MSIX) {
if (req_irq_type < IRQ_TYPE_INTX || req_irq_type > IRQ_TYPE_MSIX) {
dev_err(dev, "Invalid IRQ type option\n");
return false;
}
@@ -737,8 +747,8 @@ static long pci_endpoint_test_ioctl(struct file *file, unsigned int cmd,
goto ret;
ret = pci_endpoint_test_bar(test, bar);
break;
case PCITEST_LEGACY_IRQ:
ret = pci_endpoint_test_legacy_irq(test);
case PCITEST_INTX_IRQ:
ret = pci_endpoint_test_intx_irq(test);
break;
case PCITEST_MSI:
case PCITEST_MSIX:
@@ -801,7 +811,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
test->irq_type = IRQ_TYPE_UNDEFINED;
if (no_msi)
irq_type = IRQ_TYPE_LEGACY;
irq_type = IRQ_TYPE_INTX;
data = (struct pci_endpoint_test_data *)ent->driver_data;
if (data) {
@@ -860,7 +870,7 @@ static int pci_endpoint_test_probe(struct pci_dev *pdev,
pci_set_drvdata(pdev, test);
id = ida_simple_get(&pci_endpoint_test_ida, 0, 0, GFP_KERNEL);
id = ida_alloc(&pci_endpoint_test_ida, GFP_KERNEL);
if (id < 0) {
err = id;
dev_err(dev, "Unable to get id\n");
@@ -907,7 +917,7 @@ err_kfree_test_name:
kfree(test->name);
err_ida_remove:
ida_simple_remove(&pci_endpoint_test_ida, id);
ida_free(&pci_endpoint_test_ida, id);
err_iounmap:
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
@@ -943,7 +953,7 @@ static void pci_endpoint_test_remove(struct pci_dev *pdev)
misc_deregister(&test->miscdev);
kfree(misc_device->name);
kfree(test->name);
ida_simple_remove(&pci_endpoint_test_ida, id);
ida_free(&pci_endpoint_test_ida, id);
for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
if (test->bar[bar])
pci_iounmap(pdev, test->bar[bar]);
@@ -2707,7 +2707,6 @@ MODULE_DEVICE_TABLE(pci, brcmf_pcie_devid_table);
static struct pci_driver brcmf_pciedrvr = {
.node = {},
.name = KBUILD_MODNAME,
.id_table = brcmf_pcie_devid_table,
.probe = brcmf_pcie_probe,

Some files were not shown because too many files have changed in this diff Show More