Merge branch 'pci/hotplug'
- fix use-before-set error in ibmphp (Dan Carpenter)
- fix pciehp timeouts caused by Command Completed errata (Bjorn Helgaas)
- fix refcounting in pnv_php hotplug (Julia Lawall)
- clear pciehp Presence Detect and Data Link Layer Status Changed on
resume so we don't miss hotplug events (Mika Westerberg)
- only request pciehp control if we support it, so platform can use ACPI
hotplug otherwise (Mika Westerberg)
- convert SHPC to be builtin only (Mika Westerberg)
- request SHPC control via _OSC if we support it (Mika Westerberg)
- simplify SHPC handoff from firmware (Mika Westerberg)
* pci/hotplug:
PCI: Improve "partially hidden behind bridge" log message
PCI: Improve pci_scan_bridge() and pci_scan_bridge_extend() doc
PCI: Move resource distribution for single bridge outside loop
PCI: Account for all bridges on bus when distributing bus numbers
ACPI / hotplug / PCI: Drop unnecessary parentheses
ACPI / hotplug / PCI: Mark stale PCI devices disconnected
ACPI / hotplug / PCI: Don't scan bridges managed by native hotplug
PCI: hotplug: Add hotplug_is_native()
PCI: shpchp: Add shpchp_is_native()
PCI: shpchp: Fix AMD POGO identification
PCI: shpchp: Use dev_printk() for OSHP-related messages
PCI: shpchp: Remove get_hp_hw_control_from_firmware() wrapper
PCI: shpchp: Remove acpi_get_hp_hw_control_from_firmware() flags
PCI: shpchp: Rely on previous _OSC results
PCI: shpchp: Request SHPC control via _OSC when adding host bridge
PCI: shpchp: Convert SHPC to be builtin only
PCI: pciehp: Make pciehp_is_native() stricter
PCI: pciehp: Rename host->native_hotplug to host->native_pcie_hotplug
PCI: pciehp: Request control of native hotplug only if supported
PCI: pciehp: Clear Presence Detect and Data Link Layer Status Changed on resume
PCI: pnv_php: Add missing of_node_put()
PCI: pciehp: Add quirk for Command Completed errata
PCI: Add Qualcomm vendor ID
PCI: ibmphp: Fix use-before-set in get_max_bus_speed()
# Conflicts:
# drivers/acpi/pci_root.c
This commit is contained in:
@@ -473,12 +473,17 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm)
|
|||||||
}
|
}
|
||||||
|
|
||||||
control = OSC_PCI_EXPRESS_CAPABILITY_CONTROL
|
control = OSC_PCI_EXPRESS_CAPABILITY_CONTROL
|
||||||
| OSC_PCI_EXPRESS_NATIVE_HP_CONTROL
|
|
||||||
| OSC_PCI_EXPRESS_PME_CONTROL;
|
| OSC_PCI_EXPRESS_PME_CONTROL;
|
||||||
|
|
||||||
if (IS_ENABLED(CONFIG_PCIEASPM))
|
if (IS_ENABLED(CONFIG_PCIEASPM))
|
||||||
control |= OSC_PCI_EXPRESS_LTR_CONTROL;
|
control |= OSC_PCI_EXPRESS_LTR_CONTROL;
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE))
|
||||||
|
control |= OSC_PCI_EXPRESS_NATIVE_HP_CONTROL;
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_HOTPLUG_PCI_SHPC))
|
||||||
|
control |= OSC_PCI_SHPC_NATIVE_HP_CONTROL;
|
||||||
|
|
||||||
if (pci_aer_available()) {
|
if (pci_aer_available()) {
|
||||||
if (aer_acpi_firmware_first())
|
if (aer_acpi_firmware_first())
|
||||||
dev_info(&device->dev,
|
dev_info(&device->dev,
|
||||||
@@ -904,7 +909,9 @@ struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
|
|||||||
|
|
||||||
host_bridge = to_pci_host_bridge(bus->bridge);
|
host_bridge = to_pci_host_bridge(bus->bridge);
|
||||||
if (!(root->osc_control_set & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL))
|
if (!(root->osc_control_set & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL))
|
||||||
host_bridge->native_hotplug = 0;
|
host_bridge->native_pcie_hotplug = 0;
|
||||||
|
if (!(root->osc_control_set & OSC_PCI_SHPC_NATIVE_HP_CONTROL))
|
||||||
|
host_bridge->native_shpc_hotplug = 0;
|
||||||
if (!(root->osc_control_set & OSC_PCI_EXPRESS_AER_CONTROL))
|
if (!(root->osc_control_set & OSC_PCI_EXPRESS_AER_CONTROL))
|
||||||
host_bridge->native_aer = 0;
|
host_bridge->native_aer = 0;
|
||||||
if (!(root->osc_control_set & OSC_PCI_EXPRESS_PME_CONTROL))
|
if (!(root->osc_control_set & OSC_PCI_EXPRESS_PME_CONTROL))
|
||||||
|
|||||||
@@ -104,14 +104,11 @@ config HOTPLUG_PCI_CPCI_GENERIC
|
|||||||
When in doubt, say N.
|
When in doubt, say N.
|
||||||
|
|
||||||
config HOTPLUG_PCI_SHPC
|
config HOTPLUG_PCI_SHPC
|
||||||
tristate "SHPC PCI Hotplug driver"
|
bool "SHPC PCI Hotplug driver"
|
||||||
help
|
help
|
||||||
Say Y here if you have a motherboard with a SHPC PCI Hotplug
|
Say Y here if you have a motherboard with a SHPC PCI Hotplug
|
||||||
controller.
|
controller.
|
||||||
|
|
||||||
To compile this driver as a module, choose M here: the
|
|
||||||
module will be called shpchp.
|
|
||||||
|
|
||||||
When in doubt, say N.
|
When in doubt, say N.
|
||||||
|
|
||||||
config HOTPLUG_PCI_POWERNV
|
config HOTPLUG_PCI_POWERNV
|
||||||
|
|||||||
@@ -63,22 +63,17 @@ static acpi_status acpi_run_oshp(acpi_handle handle)
|
|||||||
/**
|
/**
|
||||||
* acpi_get_hp_hw_control_from_firmware
|
* acpi_get_hp_hw_control_from_firmware
|
||||||
* @dev: the pci_dev of the bridge that has a hotplug controller
|
* @dev: the pci_dev of the bridge that has a hotplug controller
|
||||||
* @flags: requested control bits for _OSC
|
|
||||||
*
|
*
|
||||||
* Attempt to take hotplug control from firmware.
|
* Attempt to take hotplug control from firmware.
|
||||||
*/
|
*/
|
||||||
int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev, u32 flags)
|
int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev)
|
||||||
{
|
{
|
||||||
|
const struct pci_host_bridge *host;
|
||||||
|
const struct acpi_pci_root *root;
|
||||||
acpi_status status;
|
acpi_status status;
|
||||||
acpi_handle chandle, handle;
|
acpi_handle chandle, handle;
|
||||||
struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL };
|
struct acpi_buffer string = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||||
|
|
||||||
flags &= OSC_PCI_SHPC_NATIVE_HP_CONTROL;
|
|
||||||
if (!flags) {
|
|
||||||
err("Invalid flags %u specified!\n", flags);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Per PCI firmware specification, we should run the ACPI _OSC
|
* Per PCI firmware specification, we should run the ACPI _OSC
|
||||||
* method to get control of hotplug hardware before using it. If
|
* method to get control of hotplug hardware before using it. If
|
||||||
@@ -88,25 +83,20 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev, u32 flags)
|
|||||||
* OSHP within the scope of the hotplug controller and its parents,
|
* OSHP within the scope of the hotplug controller and its parents,
|
||||||
* up to the host bridge under which this controller exists.
|
* up to the host bridge under which this controller exists.
|
||||||
*/
|
*/
|
||||||
handle = acpi_find_root_bridge_handle(pdev);
|
if (shpchp_is_native(pdev))
|
||||||
if (handle) {
|
return 0;
|
||||||
acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
|
|
||||||
dbg("Trying to get hotplug control for %s\n",
|
/* If _OSC exists, we should not evaluate OSHP */
|
||||||
(char *)string.pointer);
|
host = pci_find_host_bridge(pdev->bus);
|
||||||
status = acpi_pci_osc_control_set(handle, &flags, flags);
|
root = acpi_pci_find_root(ACPI_HANDLE(&host->dev));
|
||||||
if (ACPI_SUCCESS(status))
|
if (root->osc_support_set)
|
||||||
goto got_one;
|
goto no_control;
|
||||||
if (status == AE_SUPPORT)
|
|
||||||
goto no_control;
|
|
||||||
kfree(string.pointer);
|
|
||||||
string = (struct acpi_buffer){ ACPI_ALLOCATE_BUFFER, NULL };
|
|
||||||
}
|
|
||||||
|
|
||||||
handle = ACPI_HANDLE(&pdev->dev);
|
handle = ACPI_HANDLE(&pdev->dev);
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
/*
|
/*
|
||||||
* This hotplug controller was not listed in the ACPI name
|
* This hotplug controller was not listed in the ACPI name
|
||||||
* space at all. Try to get acpi handle of parent pci bus.
|
* space at all. Try to get ACPI handle of parent PCI bus.
|
||||||
*/
|
*/
|
||||||
struct pci_bus *pbus;
|
struct pci_bus *pbus;
|
||||||
for (pbus = pdev->bus; pbus; pbus = pbus->parent) {
|
for (pbus = pdev->bus; pbus; pbus = pbus->parent) {
|
||||||
@@ -118,8 +108,8 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev, u32 flags)
|
|||||||
|
|
||||||
while (handle) {
|
while (handle) {
|
||||||
acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
|
acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
|
||||||
dbg("Trying to get hotplug control for %s\n",
|
pci_info(pdev, "Requesting control of SHPC hotplug via OSHP (%s)\n",
|
||||||
(char *)string.pointer);
|
(char *)string.pointer);
|
||||||
status = acpi_run_oshp(handle);
|
status = acpi_run_oshp(handle);
|
||||||
if (ACPI_SUCCESS(status))
|
if (ACPI_SUCCESS(status))
|
||||||
goto got_one;
|
goto got_one;
|
||||||
@@ -131,13 +121,12 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev, u32 flags)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
no_control:
|
no_control:
|
||||||
dbg("Cannot get control of hotplug hardware for pci %s\n",
|
pci_info(pdev, "Cannot get control of SHPC hotplug\n");
|
||||||
pci_name(pdev));
|
|
||||||
kfree(string.pointer);
|
kfree(string.pointer);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
got_one:
|
got_one:
|
||||||
dbg("Gained control for hotplug HW for pci %s (%s)\n",
|
pci_info(pdev, "Gained control of SHPC hotplug (%s)\n",
|
||||||
pci_name(pdev), (char *)string.pointer);
|
(char *)string.pointer);
|
||||||
kfree(string.pointer);
|
kfree(string.pointer);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -287,11 +287,12 @@ static acpi_status acpiphp_add_context(acpi_handle handle, u32 lvl, void *data,
|
|||||||
/*
|
/*
|
||||||
* Expose slots to user space for functions that have _EJ0 or _RMV or
|
* Expose slots to user space for functions that have _EJ0 or _RMV or
|
||||||
* are located in dock stations. Do not expose them for devices handled
|
* are located in dock stations. Do not expose them for devices handled
|
||||||
* by the native PCIe hotplug (PCIeHP), becuase that code is supposed to
|
* by the native PCIe hotplug (PCIeHP) or standard PCI hotplug
|
||||||
* expose slots to user space in those cases.
|
* (SHPCHP), because that code is supposed to expose slots to user
|
||||||
|
* space in those cases.
|
||||||
*/
|
*/
|
||||||
if ((acpi_pci_check_ejectable(pbus, handle) || is_dock_device(adev))
|
if ((acpi_pci_check_ejectable(pbus, handle) || is_dock_device(adev))
|
||||||
&& !(pdev && pdev->is_hotplug_bridge && pciehp_is_native(pdev))) {
|
&& !(pdev && hotplug_is_native(pdev))) {
|
||||||
unsigned long long sun;
|
unsigned long long sun;
|
||||||
int retval;
|
int retval;
|
||||||
|
|
||||||
@@ -430,6 +431,29 @@ static int acpiphp_rescan_slot(struct acpiphp_slot *slot)
|
|||||||
return pci_scan_slot(slot->bus, PCI_DEVFN(slot->device, 0));
|
return pci_scan_slot(slot->bus, PCI_DEVFN(slot->device, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void acpiphp_native_scan_bridge(struct pci_dev *bridge)
|
||||||
|
{
|
||||||
|
struct pci_bus *bus = bridge->subordinate;
|
||||||
|
struct pci_dev *dev;
|
||||||
|
int max;
|
||||||
|
|
||||||
|
if (!bus)
|
||||||
|
return;
|
||||||
|
|
||||||
|
max = bus->busn_res.start;
|
||||||
|
/* Scan already configured non-hotplug bridges */
|
||||||
|
for_each_pci_bridge(dev, bus) {
|
||||||
|
if (!hotplug_is_native(dev))
|
||||||
|
max = pci_scan_bridge(bus, dev, max, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scan non-hotplug bridges that need to be reconfigured */
|
||||||
|
for_each_pci_bridge(dev, bus) {
|
||||||
|
if (!hotplug_is_native(dev))
|
||||||
|
max = pci_scan_bridge(bus, dev, max, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* enable_slot - enable, configure a slot
|
* enable_slot - enable, configure a slot
|
||||||
* @slot: slot to be enabled
|
* @slot: slot to be enabled
|
||||||
@@ -442,25 +466,42 @@ static void enable_slot(struct acpiphp_slot *slot)
|
|||||||
struct pci_dev *dev;
|
struct pci_dev *dev;
|
||||||
struct pci_bus *bus = slot->bus;
|
struct pci_bus *bus = slot->bus;
|
||||||
struct acpiphp_func *func;
|
struct acpiphp_func *func;
|
||||||
int max, pass;
|
|
||||||
LIST_HEAD(add_list);
|
|
||||||
|
|
||||||
acpiphp_rescan_slot(slot);
|
if (bus->self && hotplug_is_native(bus->self)) {
|
||||||
max = acpiphp_max_busnr(bus);
|
/*
|
||||||
for (pass = 0; pass < 2; pass++) {
|
* If native hotplug is used, it will take care of hotplug
|
||||||
|
* slot management and resource allocation for hotplug
|
||||||
|
* bridges. However, ACPI hotplug may still be used for
|
||||||
|
* non-hotplug bridges to bring in additional devices such
|
||||||
|
* as a Thunderbolt host controller.
|
||||||
|
*/
|
||||||
for_each_pci_bridge(dev, bus) {
|
for_each_pci_bridge(dev, bus) {
|
||||||
if (PCI_SLOT(dev->devfn) != slot->device)
|
if (PCI_SLOT(dev->devfn) == slot->device)
|
||||||
continue;
|
acpiphp_native_scan_bridge(dev);
|
||||||
|
}
|
||||||
|
pci_assign_unassigned_bridge_resources(bus->self);
|
||||||
|
} else {
|
||||||
|
LIST_HEAD(add_list);
|
||||||
|
int max, pass;
|
||||||
|
|
||||||
max = pci_scan_bridge(bus, dev, max, pass);
|
acpiphp_rescan_slot(slot);
|
||||||
if (pass && dev->subordinate) {
|
max = acpiphp_max_busnr(bus);
|
||||||
check_hotplug_bridge(slot, dev);
|
for (pass = 0; pass < 2; pass++) {
|
||||||
pcibios_resource_survey_bus(dev->subordinate);
|
for_each_pci_bridge(dev, bus) {
|
||||||
__pci_bus_size_bridges(dev->subordinate, &add_list);
|
if (PCI_SLOT(dev->devfn) != slot->device)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
max = pci_scan_bridge(bus, dev, max, pass);
|
||||||
|
if (pass && dev->subordinate) {
|
||||||
|
check_hotplug_bridge(slot, dev);
|
||||||
|
pcibios_resource_survey_bus(dev->subordinate);
|
||||||
|
__pci_bus_size_bridges(dev->subordinate,
|
||||||
|
&add_list);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
__pci_bus_assign_resources(bus, &add_list, NULL);
|
||||||
}
|
}
|
||||||
__pci_bus_assign_resources(bus, &add_list, NULL);
|
|
||||||
|
|
||||||
acpiphp_sanitize_bus(bus);
|
acpiphp_sanitize_bus(bus);
|
||||||
pcie_bus_configure_settings(bus);
|
pcie_bus_configure_settings(bus);
|
||||||
@@ -481,7 +522,7 @@ static void enable_slot(struct acpiphp_slot *slot)
|
|||||||
if (!dev) {
|
if (!dev) {
|
||||||
/* Do not set SLOT_ENABLED flag if some funcs
|
/* Do not set SLOT_ENABLED flag if some funcs
|
||||||
are not added. */
|
are not added. */
|
||||||
slot->flags &= (~SLOT_ENABLED);
|
slot->flags &= ~SLOT_ENABLED;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -510,7 +551,7 @@ static void disable_slot(struct acpiphp_slot *slot)
|
|||||||
list_for_each_entry(func, &slot->funcs, sibling)
|
list_for_each_entry(func, &slot->funcs, sibling)
|
||||||
acpi_bus_trim(func_to_acpi_device(func));
|
acpi_bus_trim(func_to_acpi_device(func));
|
||||||
|
|
||||||
slot->flags &= (~SLOT_ENABLED);
|
slot->flags &= ~SLOT_ENABLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool slot_no_hotplug(struct acpiphp_slot *slot)
|
static bool slot_no_hotplug(struct acpiphp_slot *slot)
|
||||||
@@ -608,6 +649,11 @@ static void trim_stale_devices(struct pci_dev *dev)
|
|||||||
alive = pci_device_is_present(dev);
|
alive = pci_device_is_present(dev);
|
||||||
|
|
||||||
if (!alive) {
|
if (!alive) {
|
||||||
|
pci_dev_set_disconnected(dev, NULL);
|
||||||
|
if (pci_has_subordinate(dev))
|
||||||
|
pci_walk_bus(dev->subordinate, pci_dev_set_disconnected,
|
||||||
|
NULL);
|
||||||
|
|
||||||
pci_stop_and_remove_bus_device(dev);
|
pci_stop_and_remove_bus_device(dev);
|
||||||
if (adev)
|
if (adev)
|
||||||
acpi_bus_trim(adev);
|
acpi_bus_trim(adev);
|
||||||
|
|||||||
@@ -379,7 +379,7 @@ static int get_adapter_present(struct hotplug_slot *hotplug_slot, u8 *value)
|
|||||||
|
|
||||||
static int get_max_bus_speed(struct slot *slot)
|
static int get_max_bus_speed(struct slot *slot)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc = 0;
|
||||||
u8 mode = 0;
|
u8 mode = 0;
|
||||||
enum pci_bus_speed speed;
|
enum pci_bus_speed speed;
|
||||||
struct pci_bus *bus = slot->hotplug_slot->pci_slot->bus;
|
struct pci_bus *bus = slot->hotplug_slot->pci_slot->bus;
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ struct controller *pcie_init(struct pcie_device *dev);
|
|||||||
int pcie_init_notification(struct controller *ctrl);
|
int pcie_init_notification(struct controller *ctrl);
|
||||||
int pciehp_enable_slot(struct slot *p_slot);
|
int pciehp_enable_slot(struct slot *p_slot);
|
||||||
int pciehp_disable_slot(struct slot *p_slot);
|
int pciehp_disable_slot(struct slot *p_slot);
|
||||||
void pcie_enable_notification(struct controller *ctrl);
|
void pcie_reenable_notification(struct controller *ctrl);
|
||||||
int pciehp_power_on_slot(struct slot *slot);
|
int pciehp_power_on_slot(struct slot *slot);
|
||||||
void pciehp_power_off_slot(struct slot *slot);
|
void pciehp_power_off_slot(struct slot *slot);
|
||||||
void pciehp_get_power_status(struct slot *slot, u8 *status);
|
void pciehp_get_power_status(struct slot *slot, u8 *status);
|
||||||
|
|||||||
@@ -283,7 +283,7 @@ static int pciehp_resume(struct pcie_device *dev)
|
|||||||
ctrl = get_service_data(dev);
|
ctrl = get_service_data(dev);
|
||||||
|
|
||||||
/* reinitialize the chipset's event detection logic */
|
/* reinitialize the chipset's event detection logic */
|
||||||
pcie_enable_notification(ctrl);
|
pcie_reenable_notification(ctrl);
|
||||||
|
|
||||||
slot = ctrl->slot;
|
slot = ctrl->slot;
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Send feedback to <greg@kroah.com>,<kristen.c.accardi@intel.com>
|
* Send feedback to <greg@kroah.com>,<kristen.c.accardi@intel.com>
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
@@ -147,25 +146,22 @@ static void pcie_wait_cmd(struct controller *ctrl)
|
|||||||
else
|
else
|
||||||
rc = pcie_poll_cmd(ctrl, jiffies_to_msecs(timeout));
|
rc = pcie_poll_cmd(ctrl, jiffies_to_msecs(timeout));
|
||||||
|
|
||||||
/*
|
|
||||||
* Controllers with errata like Intel CF118 don't generate
|
|
||||||
* completion notifications unless the power/indicator/interlock
|
|
||||||
* control bits are changed. On such controllers, we'll emit this
|
|
||||||
* timeout message when we wait for completion of commands that
|
|
||||||
* don't change those bits, e.g., commands that merely enable
|
|
||||||
* interrupts.
|
|
||||||
*/
|
|
||||||
if (!rc)
|
if (!rc)
|
||||||
ctrl_info(ctrl, "Timeout on hotplug command %#06x (issued %u msec ago)\n",
|
ctrl_info(ctrl, "Timeout on hotplug command %#06x (issued %u msec ago)\n",
|
||||||
ctrl->slot_ctrl,
|
ctrl->slot_ctrl,
|
||||||
jiffies_to_msecs(jiffies - ctrl->cmd_started));
|
jiffies_to_msecs(jiffies - ctrl->cmd_started));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define CC_ERRATUM_MASK (PCI_EXP_SLTCTL_PCC | \
|
||||||
|
PCI_EXP_SLTCTL_PIC | \
|
||||||
|
PCI_EXP_SLTCTL_AIC | \
|
||||||
|
PCI_EXP_SLTCTL_EIC)
|
||||||
|
|
||||||
static void pcie_do_write_cmd(struct controller *ctrl, u16 cmd,
|
static void pcie_do_write_cmd(struct controller *ctrl, u16 cmd,
|
||||||
u16 mask, bool wait)
|
u16 mask, bool wait)
|
||||||
{
|
{
|
||||||
struct pci_dev *pdev = ctrl_dev(ctrl);
|
struct pci_dev *pdev = ctrl_dev(ctrl);
|
||||||
u16 slot_ctrl;
|
u16 slot_ctrl_orig, slot_ctrl;
|
||||||
|
|
||||||
mutex_lock(&ctrl->ctrl_lock);
|
mutex_lock(&ctrl->ctrl_lock);
|
||||||
|
|
||||||
@@ -180,6 +176,7 @@ static void pcie_do_write_cmd(struct controller *ctrl, u16 cmd,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
slot_ctrl_orig = slot_ctrl;
|
||||||
slot_ctrl &= ~mask;
|
slot_ctrl &= ~mask;
|
||||||
slot_ctrl |= (cmd & mask);
|
slot_ctrl |= (cmd & mask);
|
||||||
ctrl->cmd_busy = 1;
|
ctrl->cmd_busy = 1;
|
||||||
@@ -188,6 +185,17 @@ static void pcie_do_write_cmd(struct controller *ctrl, u16 cmd,
|
|||||||
ctrl->cmd_started = jiffies;
|
ctrl->cmd_started = jiffies;
|
||||||
ctrl->slot_ctrl = slot_ctrl;
|
ctrl->slot_ctrl = slot_ctrl;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Controllers with the Intel CF118 and similar errata advertise
|
||||||
|
* Command Completed support, but they only set Command Completed
|
||||||
|
* if we change the "Control" bits for power, power indicator,
|
||||||
|
* attention indicator, or interlock. If we only change the
|
||||||
|
* "Enable" bits, they never set the Command Completed bit.
|
||||||
|
*/
|
||||||
|
if (pdev->broken_cmd_compl &&
|
||||||
|
(slot_ctrl_orig & CC_ERRATUM_MASK) == (slot_ctrl & CC_ERRATUM_MASK))
|
||||||
|
ctrl->cmd_busy = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Optionally wait for the hardware to be ready for a new command,
|
* Optionally wait for the hardware to be ready for a new command,
|
||||||
* indicating completion of the above issued command.
|
* indicating completion of the above issued command.
|
||||||
@@ -645,7 +653,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
|
|||||||
return handled;
|
return handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pcie_enable_notification(struct controller *ctrl)
|
static void pcie_enable_notification(struct controller *ctrl)
|
||||||
{
|
{
|
||||||
u16 cmd, mask;
|
u16 cmd, mask;
|
||||||
|
|
||||||
@@ -683,6 +691,17 @@ void pcie_enable_notification(struct controller *ctrl)
|
|||||||
pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, cmd);
|
pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pcie_reenable_notification(struct controller *ctrl)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Clear both Presence and Data Link Layer Changed to make sure
|
||||||
|
* those events still fire after we have re-enabled them.
|
||||||
|
*/
|
||||||
|
pcie_capability_write_word(ctrl->pcie->port, PCI_EXP_SLTSTA,
|
||||||
|
PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC);
|
||||||
|
pcie_enable_notification(ctrl);
|
||||||
|
}
|
||||||
|
|
||||||
static void pcie_disable_notification(struct controller *ctrl)
|
static void pcie_disable_notification(struct controller *ctrl)
|
||||||
{
|
{
|
||||||
u16 mask;
|
u16 mask;
|
||||||
@@ -847,7 +866,7 @@ struct controller *pcie_init(struct pcie_device *dev)
|
|||||||
PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_CC |
|
PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_CC |
|
||||||
PCI_EXP_SLTSTA_DLLSC);
|
PCI_EXP_SLTSTA_DLLSC);
|
||||||
|
|
||||||
ctrl_info(ctrl, "Slot #%d AttnBtn%c PwrCtrl%c MRL%c AttnInd%c PwrInd%c HotPlug%c Surprise%c Interlock%c NoCompl%c LLActRep%c\n",
|
ctrl_info(ctrl, "Slot #%d AttnBtn%c PwrCtrl%c MRL%c AttnInd%c PwrInd%c HotPlug%c Surprise%c Interlock%c NoCompl%c LLActRep%c%s\n",
|
||||||
(slot_cap & PCI_EXP_SLTCAP_PSN) >> 19,
|
(slot_cap & PCI_EXP_SLTCAP_PSN) >> 19,
|
||||||
FLAG(slot_cap, PCI_EXP_SLTCAP_ABP),
|
FLAG(slot_cap, PCI_EXP_SLTCAP_ABP),
|
||||||
FLAG(slot_cap, PCI_EXP_SLTCAP_PCP),
|
FLAG(slot_cap, PCI_EXP_SLTCAP_PCP),
|
||||||
@@ -858,7 +877,8 @@ struct controller *pcie_init(struct pcie_device *dev)
|
|||||||
FLAG(slot_cap, PCI_EXP_SLTCAP_HPS),
|
FLAG(slot_cap, PCI_EXP_SLTCAP_HPS),
|
||||||
FLAG(slot_cap, PCI_EXP_SLTCAP_EIP),
|
FLAG(slot_cap, PCI_EXP_SLTCAP_EIP),
|
||||||
FLAG(slot_cap, PCI_EXP_SLTCAP_NCCS),
|
FLAG(slot_cap, PCI_EXP_SLTCAP_NCCS),
|
||||||
FLAG(link_cap, PCI_EXP_LNKCAP_DLLLARC));
|
FLAG(link_cap, PCI_EXP_LNKCAP_DLLLARC),
|
||||||
|
pdev->broken_cmd_compl ? " (with Cmd Compl erratum)" : "");
|
||||||
|
|
||||||
if (pcie_init_slot(ctrl))
|
if (pcie_init_slot(ctrl))
|
||||||
goto abort_ctrl;
|
goto abort_ctrl;
|
||||||
@@ -877,3 +897,21 @@ void pciehp_release_ctrl(struct controller *ctrl)
|
|||||||
pcie_cleanup_slot(ctrl);
|
pcie_cleanup_slot(ctrl);
|
||||||
kfree(ctrl);
|
kfree(ctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void quirk_cmd_compl(struct pci_dev *pdev)
|
||||||
|
{
|
||||||
|
u32 slot_cap;
|
||||||
|
|
||||||
|
if (pci_is_pcie(pdev)) {
|
||||||
|
pcie_capability_read_dword(pdev, PCI_EXP_SLTCAP, &slot_cap);
|
||||||
|
if (slot_cap & PCI_EXP_SLTCAP_HPC &&
|
||||||
|
!(slot_cap & PCI_EXP_SLTCAP_NCCS))
|
||||||
|
pdev->broken_cmd_compl = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_INTEL, PCI_ANY_ID,
|
||||||
|
PCI_CLASS_BRIDGE_PCI, 8, quirk_cmd_compl);
|
||||||
|
DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_QCOM, 0x0400,
|
||||||
|
PCI_CLASS_BRIDGE_PCI, 8, quirk_cmd_compl);
|
||||||
|
DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_QCOM, 0x0401,
|
||||||
|
PCI_CLASS_BRIDGE_PCI, 8, quirk_cmd_compl);
|
||||||
|
|||||||
@@ -220,12 +220,16 @@ static int pnv_php_populate_changeset(struct of_changeset *ocs,
|
|||||||
|
|
||||||
for_each_child_of_node(dn, child) {
|
for_each_child_of_node(dn, child) {
|
||||||
ret = of_changeset_attach_node(ocs, child);
|
ret = of_changeset_attach_node(ocs, child);
|
||||||
if (ret)
|
if (ret) {
|
||||||
|
of_node_put(child);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
ret = pnv_php_populate_changeset(ocs, child);
|
ret = pnv_php_populate_changeset(ocs, child);
|
||||||
if (ret)
|
if (ret) {
|
||||||
|
of_node_put(child);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
@@ -105,7 +105,6 @@ struct controller {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/* Define AMD SHPC ID */
|
/* Define AMD SHPC ID */
|
||||||
#define PCI_DEVICE_ID_AMD_GOLAM_7450 0x7450
|
|
||||||
#define PCI_DEVICE_ID_AMD_POGO_7458 0x7458
|
#define PCI_DEVICE_ID_AMD_POGO_7458 0x7458
|
||||||
|
|
||||||
/* AMD PCI-X bridge registers */
|
/* AMD PCI-X bridge registers */
|
||||||
@@ -173,17 +172,6 @@ static inline const char *slot_name(struct slot *slot)
|
|||||||
return hotplug_slot_name(slot->hotplug_slot);
|
return hotplug_slot_name(slot->hotplug_slot);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_ACPI
|
|
||||||
#include <linux/pci-acpi.h>
|
|
||||||
static inline int get_hp_hw_control_from_firmware(struct pci_dev *dev)
|
|
||||||
{
|
|
||||||
u32 flags = OSC_PCI_SHPC_NATIVE_HP_CONTROL;
|
|
||||||
return acpi_get_hp_hw_control_from_firmware(dev, flags);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#define get_hp_hw_control_from_firmware(dev) (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct ctrl_reg {
|
struct ctrl_reg {
|
||||||
volatile u32 base_offset;
|
volatile u32 base_offset;
|
||||||
volatile u32 slot_avail1;
|
volatile u32 slot_avail1;
|
||||||
|
|||||||
@@ -270,24 +270,12 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int is_shpc_capable(struct pci_dev *dev)
|
|
||||||
{
|
|
||||||
if (dev->vendor == PCI_VENDOR_ID_AMD &&
|
|
||||||
dev->device == PCI_DEVICE_ID_AMD_GOLAM_7450)
|
|
||||||
return 1;
|
|
||||||
if (!pci_find_capability(dev, PCI_CAP_ID_SHPC))
|
|
||||||
return 0;
|
|
||||||
if (get_hp_hw_control_from_firmware(dev))
|
|
||||||
return 0;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
static int shpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
struct controller *ctrl;
|
struct controller *ctrl;
|
||||||
|
|
||||||
if (!is_shpc_capable(pdev))
|
if (acpi_get_hp_hw_control_from_firmware(pdev))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
|
ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
|
||||||
|
|||||||
@@ -585,13 +585,13 @@ static int shpchp_enable_slot (struct slot *p_slot)
|
|||||||
ctrl_dbg(ctrl, "%s: p_slot->pwr_save %x\n", __func__, p_slot->pwr_save);
|
ctrl_dbg(ctrl, "%s: p_slot->pwr_save %x\n", __func__, p_slot->pwr_save);
|
||||||
p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
|
p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
|
||||||
|
|
||||||
if (((p_slot->ctrl->pci_dev->vendor == PCI_VENDOR_ID_AMD) ||
|
if ((p_slot->ctrl->pci_dev->vendor == PCI_VENDOR_ID_AMD &&
|
||||||
(p_slot->ctrl->pci_dev->device == PCI_DEVICE_ID_AMD_POGO_7458))
|
p_slot->ctrl->pci_dev->device == PCI_DEVICE_ID_AMD_POGO_7458)
|
||||||
&& p_slot->ctrl->num_slots == 1) {
|
&& p_slot->ctrl->num_slots == 1) {
|
||||||
/* handle amd pogo errata; this must be done before enable */
|
/* handle AMD POGO errata; this must be done before enable */
|
||||||
amd_pogo_errata_save_misc_reg(p_slot);
|
amd_pogo_errata_save_misc_reg(p_slot);
|
||||||
retval = board_added(p_slot);
|
retval = board_added(p_slot);
|
||||||
/* handle amd pogo errata; this must be done after enable */
|
/* handle AMD POGO errata; this must be done after enable */
|
||||||
amd_pogo_errata_restore_misc_reg(p_slot);
|
amd_pogo_errata_restore_misc_reg(p_slot);
|
||||||
} else
|
} else
|
||||||
retval = board_added(p_slot);
|
retval = board_added(p_slot);
|
||||||
|
|||||||
+43
-12
@@ -370,26 +370,57 @@ EXPORT_SYMBOL_GPL(pci_get_hp_params);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* pciehp_is_native - Check whether a hotplug port is handled by the OS
|
* pciehp_is_native - Check whether a hotplug port is handled by the OS
|
||||||
* @pdev: Hotplug port to check
|
* @bridge: Hotplug port to check
|
||||||
*
|
*
|
||||||
* Walk up from @pdev to the host bridge, obtain its cached _OSC Control Field
|
* Returns true if the given @bridge is handled by the native PCIe hotplug
|
||||||
* and return the value of the "PCI Express Native Hot Plug control" bit.
|
* driver.
|
||||||
* On failure to obtain the _OSC Control Field return %false.
|
|
||||||
*/
|
*/
|
||||||
bool pciehp_is_native(struct pci_dev *pdev)
|
bool pciehp_is_native(struct pci_dev *bridge)
|
||||||
{
|
{
|
||||||
struct acpi_pci_root *root;
|
const struct pci_host_bridge *host;
|
||||||
acpi_handle handle;
|
u32 slot_cap;
|
||||||
|
|
||||||
handle = acpi_find_root_bridge_handle(pdev);
|
if (!IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE))
|
||||||
if (!handle)
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
root = acpi_pci_find_root(handle);
|
pcie_capability_read_dword(bridge, PCI_EXP_SLTCAP, &slot_cap);
|
||||||
if (!root)
|
if (!(slot_cap & PCI_EXP_SLTCAP_HPC))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return root->osc_control_set & OSC_PCI_EXPRESS_NATIVE_HP_CONTROL;
|
if (pcie_ports_native)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
host = pci_find_host_bridge(bridge->bus);
|
||||||
|
return host->native_pcie_hotplug;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* shpchp_is_native - Check whether a hotplug port is handled by the OS
|
||||||
|
* @bridge: Hotplug port to check
|
||||||
|
*
|
||||||
|
* Returns true if the given @bridge is handled by the native SHPC hotplug
|
||||||
|
* driver.
|
||||||
|
*/
|
||||||
|
bool shpchp_is_native(struct pci_dev *bridge)
|
||||||
|
{
|
||||||
|
const struct pci_host_bridge *host;
|
||||||
|
|
||||||
|
if (!IS_ENABLED(CONFIG_HOTPLUG_PCI_SHPC))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* It is assumed that AMD GOLAM chips support SHPC but they do not
|
||||||
|
* have SHPC capability.
|
||||||
|
*/
|
||||||
|
if (bridge->vendor == PCI_VENDOR_ID_AMD &&
|
||||||
|
bridge->device == PCI_DEVICE_ID_AMD_GOLAM_7450)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (!pci_find_capability(bridge, PCI_CAP_ID_SHPC))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
host = pci_find_host_bridge(bridge->bus);
|
||||||
|
return host->native_shpc_hotplug;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -11,8 +11,6 @@
|
|||||||
|
|
||||||
#include <linux/compiler.h>
|
#include <linux/compiler.h>
|
||||||
|
|
||||||
extern bool pcie_ports_native;
|
|
||||||
|
|
||||||
/* Service Type */
|
/* Service Type */
|
||||||
#define PCIE_PORT_SERVICE_PME_SHIFT 0 /* Power Management Event */
|
#define PCIE_PORT_SERVICE_PME_SHIFT 0 /* Power Management Event */
|
||||||
#define PCIE_PORT_SERVICE_PME (1 << PCIE_PORT_SERVICE_PME_SHIFT)
|
#define PCIE_PORT_SERVICE_PME (1 << PCIE_PORT_SERVICE_PME_SHIFT)
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ static int get_port_device_capability(struct pci_dev *dev)
|
|||||||
int services = 0;
|
int services = 0;
|
||||||
|
|
||||||
if (dev->is_hotplug_bridge &&
|
if (dev->is_hotplug_bridge &&
|
||||||
(pcie_ports_native || host->native_hotplug)) {
|
(pcie_ports_native || host->native_pcie_hotplug)) {
|
||||||
services |= PCIE_PORT_SERVICE_HP;
|
services |= PCIE_PORT_SERVICE_HP;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
+22
-13
@@ -552,7 +552,8 @@ struct pci_host_bridge *pci_alloc_host_bridge(size_t priv)
|
|||||||
* OS from interfering.
|
* OS from interfering.
|
||||||
*/
|
*/
|
||||||
bridge->native_aer = 1;
|
bridge->native_aer = 1;
|
||||||
bridge->native_hotplug = 1;
|
bridge->native_pcie_hotplug = 1;
|
||||||
|
bridge->native_shpc_hotplug = 1;
|
||||||
bridge->native_pme = 1;
|
bridge->native_pme = 1;
|
||||||
bridge->native_ltr = 1;
|
bridge->native_ltr = 1;
|
||||||
|
|
||||||
@@ -1048,6 +1049,8 @@ static unsigned int pci_scan_child_bus_extend(struct pci_bus *bus,
|
|||||||
* already configured by the BIOS and after we are done with all of
|
* already configured by the BIOS and after we are done with all of
|
||||||
* them, we proceed to assigning numbers to the remaining buses in
|
* them, we proceed to assigning numbers to the remaining buses in
|
||||||
* order to avoid overlaps between old and new bus numbers.
|
* order to avoid overlaps between old and new bus numbers.
|
||||||
|
*
|
||||||
|
* Return: New subordinate number covering all buses behind this bridge.
|
||||||
*/
|
*/
|
||||||
static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
|
static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
|
||||||
int max, unsigned int available_buses,
|
int max, unsigned int available_buses,
|
||||||
@@ -1238,20 +1241,15 @@ static int pci_scan_bridge_extend(struct pci_bus *bus, struct pci_dev *dev,
|
|||||||
(is_cardbus ? "PCI CardBus %04x:%02x" : "PCI Bus %04x:%02x"),
|
(is_cardbus ? "PCI CardBus %04x:%02x" : "PCI Bus %04x:%02x"),
|
||||||
pci_domain_nr(bus), child->number);
|
pci_domain_nr(bus), child->number);
|
||||||
|
|
||||||
/* Has only triggered on CardBus, fixup is in yenta_socket */
|
/* Check that all devices are accessible */
|
||||||
while (bus->parent) {
|
while (bus->parent) {
|
||||||
if ((child->busn_res.end > bus->busn_res.end) ||
|
if ((child->busn_res.end > bus->busn_res.end) ||
|
||||||
(child->number > bus->busn_res.end) ||
|
(child->number > bus->busn_res.end) ||
|
||||||
(child->number < bus->number) ||
|
(child->number < bus->number) ||
|
||||||
(child->busn_res.end < bus->number)) {
|
(child->busn_res.end < bus->number)) {
|
||||||
dev_info(&child->dev, "%pR %s hidden behind%s bridge %s %pR\n",
|
dev_info(&dev->dev, "devices behind bridge are unusable because %pR cannot be assigned for them\n",
|
||||||
&child->busn_res,
|
&child->busn_res);
|
||||||
(bus->number > child->busn_res.end &&
|
break;
|
||||||
bus->busn_res.end < child->number) ?
|
|
||||||
"wholly" : "partially",
|
|
||||||
bus->self->transparent ? " transparent" : "",
|
|
||||||
dev_name(&bus->dev),
|
|
||||||
&bus->busn_res);
|
|
||||||
}
|
}
|
||||||
bus = bus->parent;
|
bus = bus->parent;
|
||||||
}
|
}
|
||||||
@@ -1280,6 +1278,8 @@ out:
|
|||||||
* already configured by the BIOS and after we are done with all of
|
* already configured by the BIOS and after we are done with all of
|
||||||
* them, we proceed to assigning numbers to the remaining buses in
|
* them, we proceed to assigning numbers to the remaining buses in
|
||||||
* order to avoid overlaps between old and new bus numbers.
|
* order to avoid overlaps between old and new bus numbers.
|
||||||
|
*
|
||||||
|
* Return: New subordinate number covering all buses behind this bridge.
|
||||||
*/
|
*/
|
||||||
int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
|
int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
|
||||||
{
|
{
|
||||||
@@ -2695,7 +2695,14 @@ static unsigned int pci_scan_child_bus_extend(struct pci_bus *bus,
|
|||||||
for_each_pci_bridge(dev, bus) {
|
for_each_pci_bridge(dev, bus) {
|
||||||
cmax = max;
|
cmax = max;
|
||||||
max = pci_scan_bridge_extend(bus, dev, max, 0, 0);
|
max = pci_scan_bridge_extend(bus, dev, max, 0, 0);
|
||||||
used_buses += cmax - max;
|
|
||||||
|
/*
|
||||||
|
* Reserve one bus for each bridge now to avoid extending
|
||||||
|
* hotplug bridges too much during the second scan below.
|
||||||
|
*/
|
||||||
|
used_buses++;
|
||||||
|
if (cmax - max > 1)
|
||||||
|
used_buses += cmax - max - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Scan bridges that need to be reconfigured */
|
/* Scan bridges that need to be reconfigured */
|
||||||
@@ -2718,12 +2725,14 @@ static unsigned int pci_scan_child_bus_extend(struct pci_bus *bus,
|
|||||||
* bridges if any.
|
* bridges if any.
|
||||||
*/
|
*/
|
||||||
buses = available_buses / hotplug_bridges;
|
buses = available_buses / hotplug_bridges;
|
||||||
buses = min(buses, available_buses - used_buses);
|
buses = min(buses, available_buses - used_buses + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
cmax = max;
|
cmax = max;
|
||||||
max = pci_scan_bridge_extend(bus, dev, cmax, buses, 1);
|
max = pci_scan_bridge_extend(bus, dev, cmax, buses, 1);
|
||||||
used_buses += max - cmax;
|
/* One bus is already accounted so don't add it again */
|
||||||
|
if (max - cmax > 1)
|
||||||
|
used_buses += max - cmax - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -4361,8 +4361,8 @@ static const struct pci_dev_acs_enabled {
|
|||||||
{ PCI_VENDOR_ID_INTEL, 0x15b7, pci_quirk_mf_endpoint_acs },
|
{ PCI_VENDOR_ID_INTEL, 0x15b7, pci_quirk_mf_endpoint_acs },
|
||||||
{ PCI_VENDOR_ID_INTEL, 0x15b8, pci_quirk_mf_endpoint_acs },
|
{ PCI_VENDOR_ID_INTEL, 0x15b8, pci_quirk_mf_endpoint_acs },
|
||||||
/* QCOM QDF2xxx root ports */
|
/* QCOM QDF2xxx root ports */
|
||||||
{ 0x17cb, 0x400, pci_quirk_qcom_rp_acs },
|
{ PCI_VENDOR_ID_QCOM, 0x0400, pci_quirk_qcom_rp_acs },
|
||||||
{ 0x17cb, 0x401, pci_quirk_qcom_rp_acs },
|
{ PCI_VENDOR_ID_QCOM, 0x0401, pci_quirk_qcom_rp_acs },
|
||||||
/* Intel PCH root ports */
|
/* Intel PCH root ports */
|
||||||
{ PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_intel_pch_acs },
|
{ PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_intel_pch_acs },
|
||||||
{ PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_intel_spt_pch_acs },
|
{ PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_intel_spt_pch_acs },
|
||||||
|
|||||||
+38
-38
@@ -1942,57 +1942,57 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus,
|
|||||||
remaining_mmio_pref -= resource_size(res);
|
remaining_mmio_pref -= resource_size(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* There is only one bridge on the bus so it gets all available
|
||||||
|
* resources which it can then distribute to the possible
|
||||||
|
* hotplug bridges below.
|
||||||
|
*/
|
||||||
|
if (hotplug_bridges + normal_bridges == 1) {
|
||||||
|
dev = list_first_entry(&bus->devices, struct pci_dev, bus_list);
|
||||||
|
if (dev->subordinate) {
|
||||||
|
pci_bus_distribute_available_resources(dev->subordinate,
|
||||||
|
add_list, available_io, available_mmio,
|
||||||
|
available_mmio_pref);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Go over devices on this bus and distribute the remaining
|
* Go over devices on this bus and distribute the remaining
|
||||||
* resource space between hotplug bridges.
|
* resource space between hotplug bridges.
|
||||||
*/
|
*/
|
||||||
for_each_pci_bridge(dev, bus) {
|
for_each_pci_bridge(dev, bus) {
|
||||||
|
resource_size_t align, io, mmio, mmio_pref;
|
||||||
struct pci_bus *b;
|
struct pci_bus *b;
|
||||||
|
|
||||||
b = dev->subordinate;
|
b = dev->subordinate;
|
||||||
if (!b)
|
if (!b || !dev->is_hotplug_bridge)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!hotplug_bridges && normal_bridges == 1) {
|
/*
|
||||||
/*
|
* Distribute available extra resources equally between
|
||||||
* There is only one bridge on the bus (upstream
|
* hotplug-capable downstream ports taking alignment into
|
||||||
* port) so it gets all available resources
|
* account.
|
||||||
* which it can then distribute to the possible
|
*
|
||||||
* hotplug bridges below.
|
* Here hotplug_bridges is always != 0.
|
||||||
*/
|
*/
|
||||||
pci_bus_distribute_available_resources(b, add_list,
|
align = pci_resource_alignment(bridge, io_res);
|
||||||
available_io, available_mmio,
|
io = div64_ul(available_io, hotplug_bridges);
|
||||||
available_mmio_pref);
|
io = min(ALIGN(io, align), remaining_io);
|
||||||
} else if (dev->is_hotplug_bridge) {
|
remaining_io -= io;
|
||||||
resource_size_t align, io, mmio, mmio_pref;
|
|
||||||
|
|
||||||
/*
|
align = pci_resource_alignment(bridge, mmio_res);
|
||||||
* Distribute available extra resources equally
|
mmio = div64_ul(available_mmio, hotplug_bridges);
|
||||||
* between hotplug-capable downstream ports
|
mmio = min(ALIGN(mmio, align), remaining_mmio);
|
||||||
* taking alignment into account.
|
remaining_mmio -= mmio;
|
||||||
*
|
|
||||||
* Here hotplug_bridges is always != 0.
|
|
||||||
*/
|
|
||||||
align = pci_resource_alignment(bridge, io_res);
|
|
||||||
io = div64_ul(available_io, hotplug_bridges);
|
|
||||||
io = min(ALIGN(io, align), remaining_io);
|
|
||||||
remaining_io -= io;
|
|
||||||
|
|
||||||
align = pci_resource_alignment(bridge, mmio_res);
|
align = pci_resource_alignment(bridge, mmio_pref_res);
|
||||||
mmio = div64_ul(available_mmio, hotplug_bridges);
|
mmio_pref = div64_ul(available_mmio_pref, hotplug_bridges);
|
||||||
mmio = min(ALIGN(mmio, align), remaining_mmio);
|
mmio_pref = min(ALIGN(mmio_pref, align), remaining_mmio_pref);
|
||||||
remaining_mmio -= mmio;
|
remaining_mmio_pref -= mmio_pref;
|
||||||
|
|
||||||
align = pci_resource_alignment(bridge, mmio_pref_res);
|
pci_bus_distribute_available_resources(b, add_list, io, mmio,
|
||||||
mmio_pref = div64_ul(available_mmio_pref,
|
mmio_pref);
|
||||||
hotplug_bridges);
|
|
||||||
mmio_pref = min(ALIGN(mmio_pref, align),
|
|
||||||
remaining_mmio_pref);
|
|
||||||
remaining_mmio_pref -= mmio_pref;
|
|
||||||
|
|
||||||
pci_bus_distribute_available_resources(b, add_list, io,
|
|
||||||
mmio, mmio_pref);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-1
@@ -407,6 +407,9 @@ struct pci_dev {
|
|||||||
struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */
|
struct bin_attribute *res_attr[DEVICE_COUNT_RESOURCE]; /* sysfs file for resources */
|
||||||
struct bin_attribute *res_attr_wc[DEVICE_COUNT_RESOURCE]; /* sysfs file for WC mapping of resources */
|
struct bin_attribute *res_attr_wc[DEVICE_COUNT_RESOURCE]; /* sysfs file for WC mapping of resources */
|
||||||
|
|
||||||
|
#ifdef CONFIG_HOTPLUG_PCI_PCIE
|
||||||
|
unsigned int broken_cmd_compl:1; /* No compl for some cmds */
|
||||||
|
#endif
|
||||||
#ifdef CONFIG_PCIE_PTM
|
#ifdef CONFIG_PCIE_PTM
|
||||||
unsigned int ptm_root:1;
|
unsigned int ptm_root:1;
|
||||||
unsigned int ptm_enabled:1;
|
unsigned int ptm_enabled:1;
|
||||||
@@ -472,7 +475,8 @@ struct pci_host_bridge {
|
|||||||
unsigned int ignore_reset_delay:1; /* For entire hierarchy */
|
unsigned int ignore_reset_delay:1; /* For entire hierarchy */
|
||||||
unsigned int no_ext_tags:1; /* No Extended Tags */
|
unsigned int no_ext_tags:1; /* No Extended Tags */
|
||||||
unsigned int native_aer:1; /* OS may use PCIe AER */
|
unsigned int native_aer:1; /* OS may use PCIe AER */
|
||||||
unsigned int native_hotplug:1; /* OS may use PCIe hotplug */
|
unsigned int native_pcie_hotplug:1; /* OS may use PCIe hotplug */
|
||||||
|
unsigned int native_shpc_hotplug:1; /* OS may use SHPC hotplug */
|
||||||
unsigned int native_pme:1; /* OS may use PCIe PME */
|
unsigned int native_pme:1; /* OS may use PCIe PME */
|
||||||
unsigned int native_ltr:1; /* OS may use PCIe LTR */
|
unsigned int native_ltr:1; /* OS may use PCIe LTR */
|
||||||
/* Resource alignment requirements */
|
/* Resource alignment requirements */
|
||||||
@@ -1451,8 +1455,10 @@ static inline int pci_irqd_intx_xlate(struct irq_domain *d,
|
|||||||
|
|
||||||
#ifdef CONFIG_PCIEPORTBUS
|
#ifdef CONFIG_PCIEPORTBUS
|
||||||
extern bool pcie_ports_disabled;
|
extern bool pcie_ports_disabled;
|
||||||
|
extern bool pcie_ports_native;
|
||||||
#else
|
#else
|
||||||
#define pcie_ports_disabled true
|
#define pcie_ports_disabled true
|
||||||
|
#define pcie_ports_native false
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_PCIEASPM
|
#ifdef CONFIG_PCIEASPM
|
||||||
|
|||||||
@@ -162,8 +162,9 @@ struct hotplug_params {
|
|||||||
#ifdef CONFIG_ACPI
|
#ifdef CONFIG_ACPI
|
||||||
#include <linux/acpi.h>
|
#include <linux/acpi.h>
|
||||||
int pci_get_hp_params(struct pci_dev *dev, struct hotplug_params *hpp);
|
int pci_get_hp_params(struct pci_dev *dev, struct hotplug_params *hpp);
|
||||||
bool pciehp_is_native(struct pci_dev *pdev);
|
bool pciehp_is_native(struct pci_dev *bridge);
|
||||||
int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags);
|
int acpi_get_hp_hw_control_from_firmware(struct pci_dev *bridge);
|
||||||
|
bool shpchp_is_native(struct pci_dev *bridge);
|
||||||
int acpi_pci_check_ejectable(struct pci_bus *pbus, acpi_handle handle);
|
int acpi_pci_check_ejectable(struct pci_bus *pbus, acpi_handle handle);
|
||||||
int acpi_pci_detect_ejectable(acpi_handle handle);
|
int acpi_pci_detect_ejectable(acpi_handle handle);
|
||||||
#else
|
#else
|
||||||
@@ -172,6 +173,17 @@ static inline int pci_get_hp_params(struct pci_dev *dev,
|
|||||||
{
|
{
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
static inline bool pciehp_is_native(struct pci_dev *pdev) { return true; }
|
|
||||||
|
static inline int acpi_get_hp_hw_control_from_firmware(struct pci_dev *bridge)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static inline bool pciehp_is_native(struct pci_dev *bridge) { return true; }
|
||||||
|
static inline bool shpchp_is_native(struct pci_dev *bridge) { return true; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static inline bool hotplug_is_native(struct pci_dev *bridge)
|
||||||
|
{
|
||||||
|
return pciehp_is_native(bridge) || shpchp_is_native(bridge);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -561,6 +561,7 @@
|
|||||||
#define PCI_DEVICE_ID_AMD_OPUS_7443 0x7443
|
#define PCI_DEVICE_ID_AMD_OPUS_7443 0x7443
|
||||||
#define PCI_DEVICE_ID_AMD_VIPER_7443 0x7443
|
#define PCI_DEVICE_ID_AMD_VIPER_7443 0x7443
|
||||||
#define PCI_DEVICE_ID_AMD_OPUS_7445 0x7445
|
#define PCI_DEVICE_ID_AMD_OPUS_7445 0x7445
|
||||||
|
#define PCI_DEVICE_ID_AMD_GOLAM_7450 0x7450
|
||||||
#define PCI_DEVICE_ID_AMD_8111_PCI 0x7460
|
#define PCI_DEVICE_ID_AMD_8111_PCI 0x7460
|
||||||
#define PCI_DEVICE_ID_AMD_8111_LPC 0x7468
|
#define PCI_DEVICE_ID_AMD_8111_LPC 0x7468
|
||||||
#define PCI_DEVICE_ID_AMD_8111_IDE 0x7469
|
#define PCI_DEVICE_ID_AMD_8111_IDE 0x7469
|
||||||
@@ -2387,6 +2388,8 @@
|
|||||||
|
|
||||||
#define PCI_VENDOR_ID_LENOVO 0x17aa
|
#define PCI_VENDOR_ID_LENOVO 0x17aa
|
||||||
|
|
||||||
|
#define PCI_VENDOR_ID_QCOM 0x17cb
|
||||||
|
|
||||||
#define PCI_VENDOR_ID_CDNS 0x17cd
|
#define PCI_VENDOR_ID_CDNS 0x17cd
|
||||||
|
|
||||||
#define PCI_VENDOR_ID_ARECA 0x17d3
|
#define PCI_VENDOR_ID_ARECA 0x17d3
|
||||||
|
|||||||
Reference in New Issue
Block a user