mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -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[] = {
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user