mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 20:22:09 +00:00
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:
commit
f64c146410
@ -473,12 +473,17 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm)
|
||||
}
|
||||
|
||||
control = OSC_PCI_EXPRESS_CAPABILITY_CONTROL
|
||||
| OSC_PCI_EXPRESS_NATIVE_HP_CONTROL
|
||||
| OSC_PCI_EXPRESS_PME_CONTROL;
|
||||
|
||||
if (IS_ENABLED(CONFIG_PCIEASPM))
|
||||
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 (aer_acpi_firmware_first())
|
||||
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);
|
||||
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))
|
||||
host_bridge->native_aer = 0;
|
||||
if (!(root->osc_control_set & OSC_PCI_EXPRESS_PME_CONTROL))
|
||||
|
@ -104,14 +104,11 @@ config HOTPLUG_PCI_CPCI_GENERIC
|
||||
When in doubt, say N.
|
||||
|
||||
config HOTPLUG_PCI_SHPC
|
||||
tristate "SHPC PCI Hotplug driver"
|
||||
bool "SHPC PCI Hotplug driver"
|
||||
help
|
||||
Say Y here if you have a motherboard with a SHPC PCI Hotplug
|
||||
controller.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called shpchp.
|
||||
|
||||
When in doubt, say N.
|
||||
|
||||
config HOTPLUG_PCI_POWERNV
|
||||
|
@ -63,22 +63,17 @@ static acpi_status acpi_run_oshp(acpi_handle handle)
|
||||
/**
|
||||
* acpi_get_hp_hw_control_from_firmware
|
||||
* @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.
|
||||
*/
|
||||
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_handle chandle, handle;
|
||||
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
|
||||
* 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,
|
||||
* up to the host bridge under which this controller exists.
|
||||
*/
|
||||
handle = acpi_find_root_bridge_handle(pdev);
|
||||
if (handle) {
|
||||
acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
|
||||
dbg("Trying to get hotplug control for %s\n",
|
||||
(char *)string.pointer);
|
||||
status = acpi_pci_osc_control_set(handle, &flags, flags);
|
||||
if (ACPI_SUCCESS(status))
|
||||
goto got_one;
|
||||
if (status == AE_SUPPORT)
|
||||
goto no_control;
|
||||
kfree(string.pointer);
|
||||
string = (struct acpi_buffer){ ACPI_ALLOCATE_BUFFER, NULL };
|
||||
}
|
||||
if (shpchp_is_native(pdev))
|
||||
return 0;
|
||||
|
||||
/* If _OSC exists, we should not evaluate OSHP */
|
||||
host = pci_find_host_bridge(pdev->bus);
|
||||
root = acpi_pci_find_root(ACPI_HANDLE(&host->dev));
|
||||
if (root->osc_support_set)
|
||||
goto no_control;
|
||||
|
||||
handle = ACPI_HANDLE(&pdev->dev);
|
||||
if (!handle) {
|
||||
/*
|
||||
* 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;
|
||||
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) {
|
||||
acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
|
||||
dbg("Trying to get hotplug control for %s\n",
|
||||
(char *)string.pointer);
|
||||
pci_info(pdev, "Requesting control of SHPC hotplug via OSHP (%s)\n",
|
||||
(char *)string.pointer);
|
||||
status = acpi_run_oshp(handle);
|
||||
if (ACPI_SUCCESS(status))
|
||||
goto got_one;
|
||||
@ -131,13 +121,12 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev, u32 flags)
|
||||
break;
|
||||
}
|
||||
no_control:
|
||||
dbg("Cannot get control of hotplug hardware for pci %s\n",
|
||||
pci_name(pdev));
|
||||
pci_info(pdev, "Cannot get control of SHPC hotplug\n");
|
||||
kfree(string.pointer);
|
||||
return -ENODEV;
|
||||
got_one:
|
||||
dbg("Gained control for hotplug HW for pci %s (%s)\n",
|
||||
pci_name(pdev), (char *)string.pointer);
|
||||
pci_info(pdev, "Gained control of SHPC hotplug (%s)\n",
|
||||
(char *)string.pointer);
|
||||
kfree(string.pointer);
|
||||
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
|
||||
* are located in dock stations. Do not expose them for devices handled
|
||||
* by the native PCIe hotplug (PCIeHP), becuase that code is supposed to
|
||||
* expose slots to user space in those cases.
|
||||
* by the native PCIe hotplug (PCIeHP) or standard PCI hotplug
|
||||
* (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))
|
||||
&& !(pdev && pdev->is_hotplug_bridge && pciehp_is_native(pdev))) {
|
||||
&& !(pdev && hotplug_is_native(pdev))) {
|
||||
unsigned long long sun;
|
||||
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));
|
||||
}
|
||||
|
||||
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
|
||||
* @slot: slot to be enabled
|
||||
@ -442,25 +466,42 @@ static void enable_slot(struct acpiphp_slot *slot)
|
||||
struct pci_dev *dev;
|
||||
struct pci_bus *bus = slot->bus;
|
||||
struct acpiphp_func *func;
|
||||
int max, pass;
|
||||
LIST_HEAD(add_list);
|
||||
|
||||
acpiphp_rescan_slot(slot);
|
||||
max = acpiphp_max_busnr(bus);
|
||||
for (pass = 0; pass < 2; pass++) {
|
||||
if (bus->self && hotplug_is_native(bus->self)) {
|
||||
/*
|
||||
* 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) {
|
||||
if (PCI_SLOT(dev->devfn) != slot->device)
|
||||
continue;
|
||||
if (PCI_SLOT(dev->devfn) == slot->device)
|
||||
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);
|
||||
if (pass && dev->subordinate) {
|
||||
check_hotplug_bridge(slot, dev);
|
||||
pcibios_resource_survey_bus(dev->subordinate);
|
||||
__pci_bus_size_bridges(dev->subordinate, &add_list);
|
||||
acpiphp_rescan_slot(slot);
|
||||
max = acpiphp_max_busnr(bus);
|
||||
for (pass = 0; pass < 2; pass++) {
|
||||
for_each_pci_bridge(dev, bus) {
|
||||
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);
|
||||
pcie_bus_configure_settings(bus);
|
||||
@ -481,7 +522,7 @@ static void enable_slot(struct acpiphp_slot *slot)
|
||||
if (!dev) {
|
||||
/* Do not set SLOT_ENABLED flag if some funcs
|
||||
are not added. */
|
||||
slot->flags &= (~SLOT_ENABLED);
|
||||
slot->flags &= ~SLOT_ENABLED;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -510,7 +551,7 @@ static void disable_slot(struct acpiphp_slot *slot)
|
||||
list_for_each_entry(func, &slot->funcs, sibling)
|
||||
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)
|
||||
@ -608,6 +649,11 @@ static void trim_stale_devices(struct pci_dev *dev)
|
||||
alive = pci_device_is_present(dev);
|
||||
|
||||
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);
|
||||
if (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)
|
||||
{
|
||||
int rc;
|
||||
int rc = 0;
|
||||
u8 mode = 0;
|
||||
enum pci_bus_speed speed;
|
||||
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 pciehp_enable_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);
|
||||
void pciehp_power_off_slot(struct slot *slot);
|
||||
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);
|
||||
|
||||
/* reinitialize the chipset's event detection logic */
|
||||
pcie_enable_notification(ctrl);
|
||||
pcie_reenable_notification(ctrl);
|
||||
|
||||
slot = ctrl->slot;
|
||||
|
||||
|
@ -10,7 +10,6 @@
|
||||
* All rights reserved.
|
||||
*
|
||||
* Send feedback to <greg@kroah.com>,<kristen.c.accardi@intel.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
@ -147,25 +146,22 @@ static void pcie_wait_cmd(struct controller *ctrl)
|
||||
else
|
||||
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)
|
||||
ctrl_info(ctrl, "Timeout on hotplug command %#06x (issued %u msec ago)\n",
|
||||
ctrl->slot_ctrl,
|
||||
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,
|
||||
u16 mask, bool wait)
|
||||
{
|
||||
struct pci_dev *pdev = ctrl_dev(ctrl);
|
||||
u16 slot_ctrl;
|
||||
u16 slot_ctrl_orig, slot_ctrl;
|
||||
|
||||
mutex_lock(&ctrl->ctrl_lock);
|
||||
|
||||
@ -180,6 +176,7 @@ static void pcie_do_write_cmd(struct controller *ctrl, u16 cmd,
|
||||
goto out;
|
||||
}
|
||||
|
||||
slot_ctrl_orig = slot_ctrl;
|
||||
slot_ctrl &= ~mask;
|
||||
slot_ctrl |= (cmd & mask);
|
||||
ctrl->cmd_busy = 1;
|
||||
@ -188,6 +185,17 @@ static void pcie_do_write_cmd(struct controller *ctrl, u16 cmd,
|
||||
ctrl->cmd_started = jiffies;
|
||||
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,
|
||||
* indicating completion of the above issued command.
|
||||
@ -645,7 +653,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
|
||||
return handled;
|
||||
}
|
||||
|
||||
void pcie_enable_notification(struct controller *ctrl)
|
||||
static void pcie_enable_notification(struct controller *ctrl)
|
||||
{
|
||||
u16 cmd, mask;
|
||||
|
||||
@ -683,6 +691,17 @@ void pcie_enable_notification(struct controller *ctrl)
|
||||
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)
|
||||
{
|
||||
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_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,
|
||||
FLAG(slot_cap, PCI_EXP_SLTCAP_ABP),
|
||||
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_EIP),
|
||||
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))
|
||||
goto abort_ctrl;
|
||||
@ -877,3 +897,21 @@ void pciehp_release_ctrl(struct controller *ctrl)
|
||||
pcie_cleanup_slot(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) {
|
||||
ret = of_changeset_attach_node(ocs, child);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
of_node_put(child);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = pnv_php_populate_changeset(ocs, child);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
of_node_put(child);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -105,7 +105,6 @@ struct controller {
|
||||
};
|
||||
|
||||
/* Define AMD SHPC ID */
|
||||
#define PCI_DEVICE_ID_AMD_GOLAM_7450 0x7450
|
||||
#define PCI_DEVICE_ID_AMD_POGO_7458 0x7458
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
#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 {
|
||||
volatile u32 base_offset;
|
||||
volatile u32 slot_avail1;
|
||||
|
@ -270,24 +270,12 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
|
||||
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)
|
||||
{
|
||||
int rc;
|
||||
struct controller *ctrl;
|
||||
|
||||
if (!is_shpc_capable(pdev))
|
||||
if (acpi_get_hp_hw_control_from_firmware(pdev))
|
||||
return -ENODEV;
|
||||
|
||||
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);
|
||||
p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
|
||||
|
||||
if (((p_slot->ctrl->pci_dev->vendor == PCI_VENDOR_ID_AMD) ||
|
||||
(p_slot->ctrl->pci_dev->device == PCI_DEVICE_ID_AMD_POGO_7458))
|
||||
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->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);
|
||||
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);
|
||||
} else
|
||||
retval = board_added(p_slot);
|
||||
|
@ -370,26 +370,57 @@ EXPORT_SYMBOL_GPL(pci_get_hp_params);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* and return the value of the "PCI Express Native Hot Plug control" bit.
|
||||
* On failure to obtain the _OSC Control Field return %false.
|
||||
* Returns true if the given @bridge is handled by the native PCIe hotplug
|
||||
* driver.
|
||||
*/
|
||||
bool pciehp_is_native(struct pci_dev *pdev)
|
||||
bool pciehp_is_native(struct pci_dev *bridge)
|
||||
{
|
||||
struct acpi_pci_root *root;
|
||||
acpi_handle handle;
|
||||
const struct pci_host_bridge *host;
|
||||
u32 slot_cap;
|
||||
|
||||
handle = acpi_find_root_bridge_handle(pdev);
|
||||
if (!handle)
|
||||
if (!IS_ENABLED(CONFIG_HOTPLUG_PCI_PCIE))
|
||||
return false;
|
||||
|
||||
root = acpi_pci_find_root(handle);
|
||||
if (!root)
|
||||
pcie_capability_read_dword(bridge, PCI_EXP_SLTCAP, &slot_cap);
|
||||
if (!(slot_cap & PCI_EXP_SLTCAP_HPC))
|
||||
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>
|
||||
|
||||
extern bool pcie_ports_native;
|
||||
|
||||
/* Service Type */
|
||||
#define PCIE_PORT_SERVICE_PME_SHIFT 0 /* Power Management Event */
|
||||
#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;
|
||||
|
||||
if (dev->is_hotplug_bridge &&
|
||||
(pcie_ports_native || host->native_hotplug)) {
|
||||
(pcie_ports_native || host->native_pcie_hotplug)) {
|
||||
services |= PCIE_PORT_SERVICE_HP;
|
||||
|
||||
/*
|
||||
|
@ -552,7 +552,8 @@ struct pci_host_bridge *pci_alloc_host_bridge(size_t priv)
|
||||
* OS from interfering.
|
||||
*/
|
||||
bridge->native_aer = 1;
|
||||
bridge->native_hotplug = 1;
|
||||
bridge->native_pcie_hotplug = 1;
|
||||
bridge->native_shpc_hotplug = 1;
|
||||
bridge->native_pme = 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
|
||||
* them, we proceed to assigning numbers to the remaining buses in
|
||||
* 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,
|
||||
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"),
|
||||
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) {
|
||||
if ((child->busn_res.end > bus->busn_res.end) ||
|
||||
(child->number > bus->busn_res.end) ||
|
||||
(child->number < bus->number) ||
|
||||
(child->busn_res.end < bus->number)) {
|
||||
dev_info(&child->dev, "%pR %s hidden behind%s bridge %s %pR\n",
|
||||
&child->busn_res,
|
||||
(bus->number > child->busn_res.end &&
|
||||
bus->busn_res.end < child->number) ?
|
||||
"wholly" : "partially",
|
||||
bus->self->transparent ? " transparent" : "",
|
||||
dev_name(&bus->dev),
|
||||
&bus->busn_res);
|
||||
dev_info(&dev->dev, "devices behind bridge are unusable because %pR cannot be assigned for them\n",
|
||||
&child->busn_res);
|
||||
break;
|
||||
}
|
||||
bus = bus->parent;
|
||||
}
|
||||
@ -1280,6 +1278,8 @@ out:
|
||||
* already configured by the BIOS and after we are done with all of
|
||||
* them, we proceed to assigning numbers to the remaining buses in
|
||||
* 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)
|
||||
{
|
||||
@ -2695,7 +2695,14 @@ static unsigned int pci_scan_child_bus_extend(struct pci_bus *bus,
|
||||
for_each_pci_bridge(dev, bus) {
|
||||
cmax = max;
|
||||
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 */
|
||||
@ -2718,12 +2725,14 @@ static unsigned int pci_scan_child_bus_extend(struct pci_bus *bus,
|
||||
* bridges if any.
|
||||
*/
|
||||
buses = available_buses / hotplug_bridges;
|
||||
buses = min(buses, available_buses - used_buses);
|
||||
buses = min(buses, available_buses - used_buses + 1);
|
||||
}
|
||||
|
||||
cmax = max;
|
||||
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, 0x15b8, pci_quirk_mf_endpoint_acs },
|
||||
/* QCOM QDF2xxx root ports */
|
||||
{ 0x17cb, 0x400, pci_quirk_qcom_rp_acs },
|
||||
{ 0x17cb, 0x401, pci_quirk_qcom_rp_acs },
|
||||
{ PCI_VENDOR_ID_QCOM, 0x0400, pci_quirk_qcom_rp_acs },
|
||||
{ PCI_VENDOR_ID_QCOM, 0x0401, pci_quirk_qcom_rp_acs },
|
||||
/* 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_spt_pch_acs },
|
||||
|
@ -1942,57 +1942,57 @@ static void pci_bus_distribute_available_resources(struct pci_bus *bus,
|
||||
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
|
||||
* resource space between hotplug bridges.
|
||||
*/
|
||||
for_each_pci_bridge(dev, bus) {
|
||||
resource_size_t align, io, mmio, mmio_pref;
|
||||
struct pci_bus *b;
|
||||
|
||||
b = dev->subordinate;
|
||||
if (!b)
|
||||
if (!b || !dev->is_hotplug_bridge)
|
||||
continue;
|
||||
|
||||
if (!hotplug_bridges && normal_bridges == 1) {
|
||||
/*
|
||||
* There is only one bridge on the bus (upstream
|
||||
* port) so it gets all available resources
|
||||
* which it can then distribute to the possible
|
||||
* hotplug bridges below.
|
||||
*/
|
||||
pci_bus_distribute_available_resources(b, add_list,
|
||||
available_io, available_mmio,
|
||||
available_mmio_pref);
|
||||
} else if (dev->is_hotplug_bridge) {
|
||||
resource_size_t align, io, mmio, mmio_pref;
|
||||
/*
|
||||
* Distribute available extra resources equally between
|
||||
* hotplug-capable downstream ports taking alignment into
|
||||
* account.
|
||||
*
|
||||
* 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;
|
||||
|
||||
/*
|
||||
* Distribute available extra resources equally
|
||||
* between hotplug-capable downstream ports
|
||||
* taking alignment into account.
|
||||
*
|
||||
* 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);
|
||||
mmio = div64_ul(available_mmio, hotplug_bridges);
|
||||
mmio = min(ALIGN(mmio, align), remaining_mmio);
|
||||
remaining_mmio -= mmio;
|
||||
|
||||
align = pci_resource_alignment(bridge, mmio_res);
|
||||
mmio = div64_ul(available_mmio, hotplug_bridges);
|
||||
mmio = min(ALIGN(mmio, align), remaining_mmio);
|
||||
remaining_mmio -= mmio;
|
||||
align = pci_resource_alignment(bridge, mmio_pref_res);
|
||||
mmio_pref = div64_ul(available_mmio_pref, hotplug_bridges);
|
||||
mmio_pref = min(ALIGN(mmio_pref, align), remaining_mmio_pref);
|
||||
remaining_mmio_pref -= mmio_pref;
|
||||
|
||||
align = pci_resource_alignment(bridge, mmio_pref_res);
|
||||
mmio_pref = div64_ul(available_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);
|
||||
}
|
||||
pci_bus_distribute_available_resources(b, add_list, io, mmio,
|
||||
mmio_pref);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -407,6 +407,9 @@ struct pci_dev {
|
||||
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 */
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_PCI_PCIE
|
||||
unsigned int broken_cmd_compl:1; /* No compl for some cmds */
|
||||
#endif
|
||||
#ifdef CONFIG_PCIE_PTM
|
||||
unsigned int ptm_root: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 no_ext_tags:1; /* No Extended Tags */
|
||||
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_ltr:1; /* OS may use PCIe LTR */
|
||||
/* Resource alignment requirements */
|
||||
@ -1451,8 +1455,10 @@ static inline int pci_irqd_intx_xlate(struct irq_domain *d,
|
||||
|
||||
#ifdef CONFIG_PCIEPORTBUS
|
||||
extern bool pcie_ports_disabled;
|
||||
extern bool pcie_ports_native;
|
||||
#else
|
||||
#define pcie_ports_disabled true
|
||||
#define pcie_ports_native false
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PCIEASPM
|
||||
|
@ -162,8 +162,9 @@ struct hotplug_params {
|
||||
#ifdef CONFIG_ACPI
|
||||
#include <linux/acpi.h>
|
||||
int pci_get_hp_params(struct pci_dev *dev, struct hotplug_params *hpp);
|
||||
bool pciehp_is_native(struct pci_dev *pdev);
|
||||
int acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev, u32 flags);
|
||||
bool pciehp_is_native(struct pci_dev *bridge);
|
||||
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_detect_ejectable(acpi_handle handle);
|
||||
#else
|
||||
@ -172,6 +173,17 @@ static inline int pci_get_hp_params(struct pci_dev *dev,
|
||||
{
|
||||
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
|
||||
|
||||
static inline bool hotplug_is_native(struct pci_dev *bridge)
|
||||
{
|
||||
return pciehp_is_native(bridge) || shpchp_is_native(bridge);
|
||||
}
|
||||
#endif
|
||||
|
@ -561,6 +561,7 @@
|
||||
#define PCI_DEVICE_ID_AMD_OPUS_7443 0x7443
|
||||
#define PCI_DEVICE_ID_AMD_VIPER_7443 0x7443
|
||||
#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_LPC 0x7468
|
||||
#define PCI_DEVICE_ID_AMD_8111_IDE 0x7469
|
||||
@ -2387,6 +2388,8 @@
|
||||
|
||||
#define PCI_VENDOR_ID_LENOVO 0x17aa
|
||||
|
||||
#define PCI_VENDOR_ID_QCOM 0x17cb
|
||||
|
||||
#define PCI_VENDOR_ID_CDNS 0x17cd
|
||||
|
||||
#define PCI_VENDOR_ID_ARECA 0x17d3
|
||||
|
Loading…
Reference in New Issue
Block a user