Merge branch 'pci/enumeration'
- Enable PCIe services for host controller drivers that use managed host bridge alloc (Jean-Philippe Brucker) - Add quirk to clear PCIe Retrain Link bit to work around Pericom bridge erratum (Stefan Mätje) - Add "external-facing" DT property to identify cases where we require IOMMU protection from untrusted devices (Jean-Philippe Brucker) - Support fixed bus numbers from bridge Enhanced Allocation capabilities (Subbaraya Sundeep) * pci/enumeration: PCI: Assign bus numbers present in EA capability for bridges PCI: OF: Support "external-facing" property dt-bindings: Add "external-facing" PCIe port property PCI: Rework pcie_retrain_link() wait loop PCI: Work around Pericom PCIe-to-PCI bridge Retrain Link erratum PCI: Factor out pcie_retrain_link() function PCI: Init PCIe feature bits for managed host bridge alloc
This commit is contained in:
Коммит
178901bf6a
|
@ -24,3 +24,53 @@ driver implementation may support the following properties:
|
|||
unsupported link speed, for instance, trying to do training for
|
||||
unsupported link speed, etc. Must be '4' for gen4, '3' for gen3, '2'
|
||||
for gen2, and '1' for gen1. Any other values are invalid.
|
||||
|
||||
PCI-PCI Bridge properties
|
||||
-------------------------
|
||||
|
||||
PCIe root ports and switch ports may be described explicitly in the device
|
||||
tree, as children of the host bridge node. Even though those devices are
|
||||
discoverable by probing, it might be necessary to describe properties that
|
||||
aren't provided by standard PCIe capabilities.
|
||||
|
||||
Required properties:
|
||||
|
||||
- reg:
|
||||
Identifies the PCI-PCI bridge. As defined in the IEEE Std 1275-1994
|
||||
document, it is a five-cell address encoded as (phys.hi phys.mid
|
||||
phys.lo size.hi size.lo). phys.hi should contain the device's BDF as
|
||||
0b00000000 bbbbbbbb dddddfff 00000000. The other cells should be zero.
|
||||
|
||||
The bus number is defined by firmware, through the standard bridge
|
||||
configuration mechanism. If this port is a switch port, then firmware
|
||||
allocates the bus number and writes it into the Secondary Bus Number
|
||||
register of the bridge directly above this port. Otherwise, the bus
|
||||
number of a root port is the first number in the bus-range property,
|
||||
defaulting to zero.
|
||||
|
||||
If firmware leaves the ARI Forwarding Enable bit set in the bridge
|
||||
above this port, then phys.hi contains the 8-bit function number as
|
||||
0b00000000 bbbbbbbb ffffffff 00000000. Note that the PCIe specification
|
||||
recommends that firmware only leaves ARI enabled when it knows that the
|
||||
OS is ARI-aware.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- external-facing:
|
||||
When present, the port is external-facing. All bridges and endpoints
|
||||
downstream of this port are external to the machine. The OS can, for
|
||||
example, use this information to identify devices that cannot be
|
||||
trusted with relaxed DMA protection, as users could easily attach
|
||||
malicious devices to this port.
|
||||
|
||||
Example:
|
||||
|
||||
pcie@10000000 {
|
||||
compatible = "pci-host-ecam-generic";
|
||||
...
|
||||
pcie@0008 {
|
||||
/* Root port 00:01.0 is external-facing */
|
||||
reg = <0x00000800 0 0 0 0>;
|
||||
external-facing;
|
||||
};
|
||||
};
|
||||
|
|
|
@ -31,10 +31,16 @@ void pci_release_of_node(struct pci_dev *dev)
|
|||
|
||||
void pci_set_bus_of_node(struct pci_bus *bus)
|
||||
{
|
||||
if (bus->self == NULL)
|
||||
bus->dev.of_node = pcibios_get_phb_of_node(bus);
|
||||
else
|
||||
bus->dev.of_node = of_node_get(bus->self->dev.of_node);
|
||||
struct device_node *node;
|
||||
|
||||
if (bus->self == NULL) {
|
||||
node = pcibios_get_phb_of_node(bus);
|
||||
} else {
|
||||
node = of_node_get(bus->self->dev.of_node);
|
||||
if (node && of_property_read_bool(node, "external-facing"))
|
||||
bus->self->untrusted = true;
|
||||
}
|
||||
bus->dev.of_node = node;
|
||||
}
|
||||
|
||||
void pci_release_bus_of_node(struct pci_bus *bus)
|
||||
|
|
|
@ -196,6 +196,36 @@ static void pcie_clkpm_cap_init(struct pcie_link_state *link, int blacklist)
|
|||
link->clkpm_capable = (blacklist) ? 0 : capable;
|
||||
}
|
||||
|
||||
static bool pcie_retrain_link(struct pcie_link_state *link)
|
||||
{
|
||||
struct pci_dev *parent = link->pdev;
|
||||
unsigned long end_jiffies;
|
||||
u16 reg16;
|
||||
|
||||
pcie_capability_read_word(parent, PCI_EXP_LNKCTL, ®16);
|
||||
reg16 |= PCI_EXP_LNKCTL_RL;
|
||||
pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16);
|
||||
if (parent->clear_retrain_link) {
|
||||
/*
|
||||
* Due to an erratum in some devices the Retrain Link bit
|
||||
* needs to be cleared again manually to allow the link
|
||||
* training to succeed.
|
||||
*/
|
||||
reg16 &= ~PCI_EXP_LNKCTL_RL;
|
||||
pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16);
|
||||
}
|
||||
|
||||
/* Wait for link training end. Break out after waiting for timeout */
|
||||
end_jiffies = jiffies + LINK_RETRAIN_TIMEOUT;
|
||||
do {
|
||||
pcie_capability_read_word(parent, PCI_EXP_LNKSTA, ®16);
|
||||
if (!(reg16 & PCI_EXP_LNKSTA_LT))
|
||||
break;
|
||||
msleep(1);
|
||||
} while (time_before(jiffies, end_jiffies));
|
||||
return !(reg16 & PCI_EXP_LNKSTA_LT);
|
||||
}
|
||||
|
||||
/*
|
||||
* pcie_aspm_configure_common_clock: check if the 2 ends of a link
|
||||
* could use common clock. If they are, configure them to use the
|
||||
|
@ -205,7 +235,6 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link)
|
|||
{
|
||||
int same_clock = 1;
|
||||
u16 reg16, parent_reg, child_reg[8];
|
||||
unsigned long start_jiffies;
|
||||
struct pci_dev *child, *parent = link->pdev;
|
||||
struct pci_bus *linkbus = parent->subordinate;
|
||||
/*
|
||||
|
@ -263,21 +292,7 @@ static void pcie_aspm_configure_common_clock(struct pcie_link_state *link)
|
|||
reg16 &= ~PCI_EXP_LNKCTL_CCC;
|
||||
pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16);
|
||||
|
||||
/* Retrain link */
|
||||
reg16 |= PCI_EXP_LNKCTL_RL;
|
||||
pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16);
|
||||
|
||||
/* Wait for link training end. Break out after waiting for timeout */
|
||||
start_jiffies = jiffies;
|
||||
for (;;) {
|
||||
pcie_capability_read_word(parent, PCI_EXP_LNKSTA, ®16);
|
||||
if (!(reg16 & PCI_EXP_LNKSTA_LT))
|
||||
break;
|
||||
if (time_after(jiffies, start_jiffies + LINK_RETRAIN_TIMEOUT))
|
||||
break;
|
||||
msleep(1);
|
||||
}
|
||||
if (!(reg16 & PCI_EXP_LNKSTA_LT))
|
||||
if (pcie_retrain_link(link))
|
||||
return;
|
||||
|
||||
/* Training failed. Restore common clock configurations */
|
||||
|
|
|
@ -586,16 +586,9 @@ static void pci_release_host_bridge_dev(struct device *dev)
|
|||
kfree(to_pci_host_bridge(dev));
|
||||
}
|
||||
|
||||
struct pci_host_bridge *pci_alloc_host_bridge(size_t priv)
|
||||
static void pci_init_host_bridge(struct pci_host_bridge *bridge)
|
||||
{
|
||||
struct pci_host_bridge *bridge;
|
||||
|
||||
bridge = kzalloc(sizeof(*bridge) + priv, GFP_KERNEL);
|
||||
if (!bridge)
|
||||
return NULL;
|
||||
|
||||
INIT_LIST_HEAD(&bridge->windows);
|
||||
bridge->dev.release = pci_release_host_bridge_dev;
|
||||
|
||||
/*
|
||||
* We assume we can manage these PCIe features. Some systems may
|
||||
|
@ -608,6 +601,18 @@ struct pci_host_bridge *pci_alloc_host_bridge(size_t priv)
|
|||
bridge->native_shpc_hotplug = 1;
|
||||
bridge->native_pme = 1;
|
||||
bridge->native_ltr = 1;
|
||||
}
|
||||
|
||||
struct pci_host_bridge *pci_alloc_host_bridge(size_t priv)
|
||||
{
|
||||
struct pci_host_bridge *bridge;
|
||||
|
||||
bridge = kzalloc(sizeof(*bridge) + priv, GFP_KERNEL);
|
||||
if (!bridge)
|
||||
return NULL;
|
||||
|
||||
pci_init_host_bridge(bridge);
|
||||
bridge->dev.release = pci_release_host_bridge_dev;
|
||||
|
||||
return bridge;
|
||||
}
|
||||
|
@ -622,7 +627,7 @@ struct pci_host_bridge *devm_pci_alloc_host_bridge(struct device *dev,
|
|||
if (!bridge)
|
||||
return NULL;
|
||||
|
||||
INIT_LIST_HEAD(&bridge->windows);
|
||||
pci_init_host_bridge(bridge);
|
||||
bridge->dev.release = devm_pci_release_host_bridge_dev;
|
||||
|
||||
return bridge;
|
||||
|
@ -1081,6 +1086,36 @@ static void pci_enable_crs(struct pci_dev *pdev)
|
|||
|
||||
static unsigned int pci_scan_child_bus_extend(struct pci_bus *bus,
|
||||
unsigned int available_buses);
|
||||
/**
|
||||
* pci_ea_fixed_busnrs() - Read fixed Secondary and Subordinate bus
|
||||
* numbers from EA capability.
|
||||
* @dev: Bridge
|
||||
* @sec: updated with secondary bus number from EA
|
||||
* @sub: updated with subordinate bus number from EA
|
||||
*
|
||||
* If @dev is a bridge with EA capability, update @sec and @sub with
|
||||
* fixed bus numbers from the capability and return true. Otherwise,
|
||||
* return false.
|
||||
*/
|
||||
static bool pci_ea_fixed_busnrs(struct pci_dev *dev, u8 *sec, u8 *sub)
|
||||
{
|
||||
int ea, offset;
|
||||
u32 dw;
|
||||
|
||||
if (dev->hdr_type != PCI_HEADER_TYPE_BRIDGE)
|
||||
return false;
|
||||
|
||||
/* find PCI EA capability in list */
|
||||
ea = pci_find_capability(dev, PCI_CAP_ID_EA);
|
||||
if (!ea)
|
||||
return false;
|
||||
|
||||
offset = ea + PCI_EA_FIRST_ENT;
|
||||
pci_read_config_dword(dev, offset, &dw);
|
||||
*sec = dw & PCI_EA_SEC_BUS_MASK;
|
||||
*sub = (dw & PCI_EA_SUB_BUS_MASK) >> PCI_EA_SUB_BUS_SHIFT;
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* pci_scan_bridge_extend() - Scan buses behind a bridge
|
||||
|
@ -1115,6 +1150,9 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
|
|||
u16 bctl;
|
||||
u8 primary, secondary, subordinate;
|
||||
int broken = 0;
|
||||
bool fixed_buses;
|
||||
u8 fixed_sec, fixed_sub;
|
||||
int next_busnr;
|
||||
|
||||
/*
|
||||
* Make sure the bridge is powered on to be able to access config
|
||||
|
@ -1214,17 +1252,24 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
|
|||
/* Clear errors */
|
||||
pci_write_config_word(dev, PCI_STATUS, 0xffff);
|
||||
|
||||
/* Read bus numbers from EA Capability (if present) */
|
||||
fixed_buses = pci_ea_fixed_busnrs(dev, &fixed_sec, &fixed_sub);
|
||||
if (fixed_buses)
|
||||
next_busnr = fixed_sec;
|
||||
else
|
||||
next_busnr = max + 1;
|
||||
|
||||
/*
|
||||
* Prevent assigning a bus number that already exists.
|
||||
* This can happen when a bridge is hot-plugged, so in this
|
||||
* case we only re-scan this bus.
|
||||
*/
|
||||
child = pci_find_bus(pci_domain_nr(bus), max+1);
|
||||
child = pci_find_bus(pci_domain_nr(bus), next_busnr);
|
||||
if (!child) {
|
||||
child = pci_add_new_bus(bus, dev, max+1);
|
||||
child = pci_add_new_bus(bus, dev, next_busnr);
|
||||
if (!child)
|
||||
goto out;
|
||||
pci_bus_insert_busn_res(child, max+1,
|
||||
pci_bus_insert_busn_res(child, next_busnr,
|
||||
bus->busn_res.end);
|
||||
}
|
||||
max++;
|
||||
|
@ -1285,7 +1330,13 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
|
|||
max += i;
|
||||
}
|
||||
|
||||
/* Set subordinate bus number to its real value */
|
||||
/*
|
||||
* Set subordinate bus number to its real value.
|
||||
* If fixed subordinate bus number exists from EA
|
||||
* capability then use it.
|
||||
*/
|
||||
if (fixed_buses)
|
||||
max = fixed_sub;
|
||||
pci_bus_update_busn_res_end(child, max);
|
||||
pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max);
|
||||
}
|
||||
|
|
|
@ -2245,6 +2245,23 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x10f1, quirk_disable_aspm_l0s);
|
|||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x10f4, quirk_disable_aspm_l0s);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1508, quirk_disable_aspm_l0s);
|
||||
|
||||
/*
|
||||
* Some Pericom PCIe-to-PCI bridges in reverse mode need the PCIe Retrain
|
||||
* Link bit cleared after starting the link retrain process to allow this
|
||||
* process to finish.
|
||||
*
|
||||
* Affected devices: PI7C9X110, PI7C9X111SL, PI7C9X130. See also the
|
||||
* Pericom Errata Sheet PI7C9X111SLB_errata_rev1.2_102711.pdf.
|
||||
*/
|
||||
static void quirk_enable_clear_retrain_link(struct pci_dev *dev)
|
||||
{
|
||||
dev->clear_retrain_link = 1;
|
||||
pci_info(dev, "Enable PCIe Retrain Link quirk\n");
|
||||
}
|
||||
DECLARE_PCI_FIXUP_HEADER(0x12d8, 0xe110, quirk_enable_clear_retrain_link);
|
||||
DECLARE_PCI_FIXUP_HEADER(0x12d8, 0xe111, quirk_enable_clear_retrain_link);
|
||||
DECLARE_PCI_FIXUP_HEADER(0x12d8, 0xe130, quirk_enable_clear_retrain_link);
|
||||
|
||||
static void fixup_rev1_53c810(struct pci_dev *dev)
|
||||
{
|
||||
u32 class = dev->class;
|
||||
|
|
|
@ -348,6 +348,8 @@ struct pci_dev {
|
|||
unsigned int hotplug_user_indicators:1; /* SlotCtl indicators
|
||||
controlled exclusively by
|
||||
user sysfs */
|
||||
unsigned int clear_retrain_link:1; /* Need to clear Retrain Link
|
||||
bit manually */
|
||||
unsigned int d3_delay; /* D3->D0 transition time in ms */
|
||||
unsigned int d3cold_delay; /* D3cold->D0 transition time in ms */
|
||||
|
||||
|
|
|
@ -372,6 +372,12 @@
|
|||
#define PCI_EA_FIRST_ENT_BRIDGE 8 /* First EA Entry for Bridges */
|
||||
#define PCI_EA_ES 0x00000007 /* Entry Size */
|
||||
#define PCI_EA_BEI 0x000000f0 /* BAR Equivalent Indicator */
|
||||
|
||||
/* EA fixed Secondary and Subordinate bus numbers for Bridge */
|
||||
#define PCI_EA_SEC_BUS_MASK 0xff
|
||||
#define PCI_EA_SUB_BUS_MASK 0xff00
|
||||
#define PCI_EA_SUB_BUS_SHIFT 8
|
||||
|
||||
/* 0-5 map to BARs 0-5 respectively */
|
||||
#define PCI_EA_BEI_BAR0 0
|
||||
#define PCI_EA_BEI_BAR5 5
|
||||
|
|
Загрузка…
Ссылка в новой задаче