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:
commit
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, for instance, trying to do training for
|
||||||
unsupported link speed, etc. Must be '4' for gen4, '3' for gen3, '2'
|
unsupported link speed, etc. Must be '4' for gen4, '3' for gen3, '2'
|
||||||
for gen2, and '1' for gen1. Any other values are invalid.
|
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)
|
void pci_set_bus_of_node(struct pci_bus *bus)
|
||||||
{
|
{
|
||||||
if (bus->self == NULL)
|
struct device_node *node;
|
||||||
bus->dev.of_node = pcibios_get_phb_of_node(bus);
|
|
||||||
else
|
if (bus->self == NULL) {
|
||||||
bus->dev.of_node = of_node_get(bus->self->dev.of_node);
|
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)
|
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;
|
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
|
* 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
|
* 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;
|
int same_clock = 1;
|
||||||
u16 reg16, parent_reg, child_reg[8];
|
u16 reg16, parent_reg, child_reg[8];
|
||||||
unsigned long start_jiffies;
|
|
||||||
struct pci_dev *child, *parent = link->pdev;
|
struct pci_dev *child, *parent = link->pdev;
|
||||||
struct pci_bus *linkbus = parent->subordinate;
|
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;
|
reg16 &= ~PCI_EXP_LNKCTL_CCC;
|
||||||
pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16);
|
pcie_capability_write_word(parent, PCI_EXP_LNKCTL, reg16);
|
||||||
|
|
||||||
/* Retrain link */
|
if (pcie_retrain_link(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))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Training failed. Restore common clock configurations */
|
/* 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));
|
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);
|
INIT_LIST_HEAD(&bridge->windows);
|
||||||
bridge->dev.release = pci_release_host_bridge_dev;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We assume we can manage these PCIe features. Some systems may
|
* 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_shpc_hotplug = 1;
|
||||||
bridge->native_pme = 1;
|
bridge->native_pme = 1;
|
||||||
bridge->native_ltr = 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;
|
return bridge;
|
||||||
}
|
}
|
||||||
|
@ -622,7 +627,7 @@ struct pci_host_bridge *devm_pci_alloc_host_bridge(struct device *dev,
|
||||||
if (!bridge)
|
if (!bridge)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
INIT_LIST_HEAD(&bridge->windows);
|
pci_init_host_bridge(bridge);
|
||||||
bridge->dev.release = devm_pci_release_host_bridge_dev;
|
bridge->dev.release = devm_pci_release_host_bridge_dev;
|
||||||
|
|
||||||
return bridge;
|
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,
|
static unsigned int pci_scan_child_bus_extend(struct pci_bus *bus,
|
||||||
unsigned int available_buses);
|
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
|
* 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;
|
u16 bctl;
|
||||||
u8 primary, secondary, subordinate;
|
u8 primary, secondary, subordinate;
|
||||||
int broken = 0;
|
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
|
* 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 */
|
/* Clear errors */
|
||||||
pci_write_config_word(dev, PCI_STATUS, 0xffff);
|
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.
|
* Prevent assigning a bus number that already exists.
|
||||||
* This can happen when a bridge is hot-plugged, so in this
|
* This can happen when a bridge is hot-plugged, so in this
|
||||||
* case we only re-scan this bus.
|
* 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) {
|
if (!child) {
|
||||||
child = pci_add_new_bus(bus, dev, max+1);
|
child = pci_add_new_bus(bus, dev, next_busnr);
|
||||||
if (!child)
|
if (!child)
|
||||||
goto out;
|
goto out;
|
||||||
pci_bus_insert_busn_res(child, max+1,
|
pci_bus_insert_busn_res(child, next_busnr,
|
||||||
bus->busn_res.end);
|
bus->busn_res.end);
|
||||||
}
|
}
|
||||||
max++;
|
max++;
|
||||||
|
@ -1285,7 +1330,13 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
|
||||||
max += i;
|
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_bus_update_busn_res_end(child, max);
|
||||||
pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, 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, 0x10f4, quirk_disable_aspm_l0s);
|
||||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1508, 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)
|
static void fixup_rev1_53c810(struct pci_dev *dev)
|
||||||
{
|
{
|
||||||
u32 class = dev->class;
|
u32 class = dev->class;
|
||||||
|
|
|
@ -348,6 +348,8 @@ struct pci_dev {
|
||||||
unsigned int hotplug_user_indicators:1; /* SlotCtl indicators
|
unsigned int hotplug_user_indicators:1; /* SlotCtl indicators
|
||||||
controlled exclusively by
|
controlled exclusively by
|
||||||
user sysfs */
|
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 d3_delay; /* D3->D0 transition time in ms */
|
||||||
unsigned int d3cold_delay; /* D3cold->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_FIRST_ENT_BRIDGE 8 /* First EA Entry for Bridges */
|
||||||
#define PCI_EA_ES 0x00000007 /* Entry Size */
|
#define PCI_EA_ES 0x00000007 /* Entry Size */
|
||||||
#define PCI_EA_BEI 0x000000f0 /* BAR Equivalent Indicator */
|
#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 */
|
/* 0-5 map to BARs 0-5 respectively */
|
||||||
#define PCI_EA_BEI_BAR0 0
|
#define PCI_EA_BEI_BAR0 0
|
||||||
#define PCI_EA_BEI_BAR5 5
|
#define PCI_EA_BEI_BAR5 5
|
||||||
|
|
Loading…
Reference in New Issue