Merge tag 'pci-v3.15-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci
Pull PCI changes from Bjorn Helgaas: "Enumeration - Increment max correctly in pci_scan_bridge() (Andreas Noever) - Clarify the "scan anyway" comment in pci_scan_bridge() (Andreas Noever) - Assign CardBus bus number only during the second pass (Andreas Noever) - Use request_resource_conflict() instead of insert_ for bus numbers (Andreas Noever) - Make sure bus number resources stay within their parents bounds (Andreas Noever) - Remove pci_fixup_parent_subordinate_busnr() (Andreas Noever) - Check for child busses which use more bus numbers than allocated (Andreas Noever) - Don't scan random busses in pci_scan_bridge() (Andreas Noever) - x86: Drop pcibios_scan_root() check for bus already scanned (Bjorn Helgaas) - x86: Use pcibios_scan_root() instead of pci_scan_bus_with_sysdata() (Bjorn Helgaas) - x86: Use pcibios_scan_root() instead of pci_scan_bus_on_node() (Bjorn Helgaas) - x86: Merge pci_scan_bus_on_node() into pcibios_scan_root() (Bjorn Helgaas) - x86: Drop return value of pcibios_scan_root() (Bjorn Helgaas) NUMA - x86: Add x86_pci_root_bus_node() to look up NUMA node from PCI bus (Bjorn Helgaas) - x86: Use x86_pci_root_bus_node() instead of get_mp_bus_to_node() (Bjorn Helgaas) - x86: Remove mp_bus_to_node[], set_mp_bus_to_node(), get_mp_bus_to_node() (Bjorn Helgaas) - x86: Use NUMA_NO_NODE, not -1, for unknown node (Bjorn Helgaas) - x86: Remove acpi_get_pxm() usage (Bjorn Helgaas) - ia64: Use NUMA_NO_NODE, not MAX_NUMNODES, for unknown node (Bjorn Helgaas) - ia64: Remove acpi_get_pxm() usage (Bjorn Helgaas) - ACPI: Fix acpi_get_node() prototype (Bjorn Helgaas) Resource management - i2o: Fix and refactor PCI space allocation (Bjorn Helgaas) - Add resource_contains() (Bjorn Helgaas) - Add %pR support for IORESOURCE_UNSET (Bjorn Helgaas) - Mark resources as IORESOURCE_UNSET if we can't assign them (Bjorn Helgaas) - Don't clear IORESOURCE_UNSET when updating BAR (Bjorn Helgaas) - Check IORESOURCE_UNSET before updating BAR (Bjorn Helgaas) - Don't try to claim IORESOURCE_UNSET resources (Bjorn Helgaas) - Mark 64-bit resource as IORESOURCE_UNSET if we only support 32-bit (Bjorn Helgaas) - Don't enable decoding if BAR hasn't been assigned an address (Bjorn Helgaas) - Add "weak" generic pcibios_enable_device() implementation (Bjorn Helgaas) - alpha, microblaze, sh, sparc, tile: Use default pcibios_enable_device() (Bjorn Helgaas) - s390: Use generic pci_enable_resources() (Bjorn Helgaas) - Don't check resource_size() in pci_bus_alloc_resource() (Bjorn Helgaas) - Set type in __request_region() (Bjorn Helgaas) - Check all IORESOURCE_TYPE_BITS in pci_bus_alloc_from_region() (Bjorn Helgaas) - Change pci_bus_alloc_resource() type_mask to unsigned long (Bjorn Helgaas) - Log IDE resource quirk in dmesg (Bjorn Helgaas) - Revert "[PATCH] Insert GART region into resource map" (Bjorn Helgaas) PCI device hotplug - Make check_link_active() non-static (Rajat Jain) - Use link change notifications for hot-plug and removal (Rajat Jain) - Enable link state change notifications (Rajat Jain) - Don't disable the link permanently during removal (Rajat Jain) - Don't check adapter or latch status while disabling (Rajat Jain) - Disable link notification across slot reset (Rajat Jain) - Ensure very fast hotplug events are also processed (Rajat Jain) - Add hotplug_lock to serialize hotplug events (Rajat Jain) - Remove a non-existent card, regardless of "surprise" capability (Rajat Jain) - Don't turn slot off when hot-added device already exists (Yijing Wang) MSI - Keep pci_enable_msi() documentation (Alexander Gordeev) - ahci: Fix broken single MSI fallback (Alexander Gordeev) - ahci, vfio: Use pci_enable_msi_range() (Alexander Gordeev) - Check kmalloc() return value, fix leak of name (Greg Kroah-Hartman) - Fix leak of msi_attrs (Greg Kroah-Hartman) - Fix pci_msix_vec_count() htmldocs failure (Masanari Iida) Virtualization - Device-specific ACS support (Alex Williamson) Freescale i.MX6 - Wait for retraining (Marek Vasut) Marvell MVEBU - Use Device ID and revision from underlying endpoint (Andrew Lunn) - Fix incorrect size for PCI aperture resources (Jason Gunthorpe) - Call request_resource() on the apertures (Jason Gunthorpe) - Fix potential issue in range parsing (Jean-Jacques Hiblot) Renesas R-Car - Check platform_get_irq() return code (Ben Dooks) - Add error interrupt handling (Ben Dooks) - Fix bridge logic configuration accesses (Ben Dooks) - Register each instance independently (Magnus Damm) - Break out window size handling (Magnus Damm) - Make the Kconfig dependencies more generic (Magnus Damm) Synopsys DesignWare - Fix RC BAR to be single 64-bit non-prefetchable memory (Mohit Kumar) Miscellaneous - Remove unused SR-IOV VF Migration support (Bjorn Helgaas) - Enable INTx if BIOS left them disabled (Bjorn Helgaas) - Fix hex vs decimal typo in cpqhpc_probe() (Dan Carpenter) - Clean up par-arch object file list (Liviu Dudau) - Set IORESOURCE_ROM_SHADOW only for the default VGA device (Sander Eikelenboom) - ACPI, ARM, drm, powerpc, pcmcia, PCI: Use list_for_each_entry() for bus traversal (Yijing Wang) - Fix pci_bus_b() build failure (Paul Gortmaker)" * tag 'pci-v3.15-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (108 commits) Revert "[PATCH] Insert GART region into resource map" PCI: Log IDE resource quirk in dmesg PCI: Change pci_bus_alloc_resource() type_mask to unsigned long PCI: Check all IORESOURCE_TYPE_BITS in pci_bus_alloc_from_region() resources: Set type in __request_region() PCI: Don't check resource_size() in pci_bus_alloc_resource() s390/PCI: Use generic pci_enable_resources() tile PCI RC: Use default pcibios_enable_device() sparc/PCI: Use default pcibios_enable_device() (Leon only) sh/PCI: Use default pcibios_enable_device() microblaze/PCI: Use default pcibios_enable_device() alpha/PCI: Use default pcibios_enable_device() PCI: Add "weak" generic pcibios_enable_device() implementation PCI: Don't enable decoding if BAR hasn't been assigned an address PCI: Enable INTx in pci_reenable_device() only when MSI/MSI-X not enabled PCI: Mark 64-bit resource as IORESOURCE_UNSET if we only support 32-bit PCI: Don't try to claim IORESOURCE_UNSET resources PCI: Check IORESOURCE_UNSET before updating BAR PCI: Don't clear IORESOURCE_UNSET when updating BAR PCI: Mark resources as IORESOURCE_UNSET if we can't assign them ... Conflicts: arch/x86/include/asm/topology.h drivers/ata/ahci.c
This commit is contained in:
@@ -424,7 +424,7 @@ static void cleanup_bridge(struct acpiphp_bridge *bridge)
|
||||
*/
|
||||
static unsigned char acpiphp_max_busnr(struct pci_bus *bus)
|
||||
{
|
||||
struct list_head *tmp;
|
||||
struct pci_bus *tmp;
|
||||
unsigned char max, n;
|
||||
|
||||
/*
|
||||
@@ -437,8 +437,8 @@ static unsigned char acpiphp_max_busnr(struct pci_bus *bus)
|
||||
*/
|
||||
max = bus->busn_res.start;
|
||||
|
||||
list_for_each(tmp, &bus->children) {
|
||||
n = pci_bus_max_busnr(pci_bus_b(tmp));
|
||||
list_for_each_entry(tmp, &bus->children, node) {
|
||||
n = pci_bus_max_busnr(tmp);
|
||||
if (n > max)
|
||||
max = n;
|
||||
}
|
||||
|
@@ -920,12 +920,12 @@ static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
bus->max_bus_speed = PCI_SPEED_100MHz_PCIX;
|
||||
break;
|
||||
}
|
||||
if (bus_cap & 20) {
|
||||
if (bus_cap & 0x20) {
|
||||
dbg("bus max supports 66MHz PCI-X\n");
|
||||
bus->max_bus_speed = PCI_SPEED_66MHz_PCIX;
|
||||
break;
|
||||
}
|
||||
if (bus_cap & 10) {
|
||||
if (bus_cap & 0x10) {
|
||||
dbg("bus max supports 66MHz PCI\n");
|
||||
bus->max_bus_speed = PCI_SPEED_66MHz;
|
||||
break;
|
||||
|
@@ -76,6 +76,7 @@ struct slot {
|
||||
struct hotplug_slot *hotplug_slot;
|
||||
struct delayed_work work; /* work for button event */
|
||||
struct mutex lock;
|
||||
struct mutex hotplug_lock;
|
||||
struct workqueue_struct *wq;
|
||||
};
|
||||
|
||||
@@ -109,6 +110,8 @@ struct controller {
|
||||
#define INT_BUTTON_PRESS 7
|
||||
#define INT_BUTTON_RELEASE 8
|
||||
#define INT_BUTTON_CANCEL 9
|
||||
#define INT_LINK_UP 10
|
||||
#define INT_LINK_DOWN 11
|
||||
|
||||
#define STATIC_STATE 0
|
||||
#define BLINKINGON_STATE 1
|
||||
@@ -132,6 +135,7 @@ u8 pciehp_handle_attention_button(struct slot *p_slot);
|
||||
u8 pciehp_handle_switch_change(struct slot *p_slot);
|
||||
u8 pciehp_handle_presence_change(struct slot *p_slot);
|
||||
u8 pciehp_handle_power_fault(struct slot *p_slot);
|
||||
void pciehp_handle_linkstate_change(struct slot *p_slot);
|
||||
int pciehp_configure_device(struct slot *p_slot);
|
||||
int pciehp_unconfigure_device(struct slot *p_slot);
|
||||
void pciehp_queue_pushbutton_work(struct work_struct *work);
|
||||
@@ -153,6 +157,7 @@ void pciehp_green_led_on(struct slot *slot);
|
||||
void pciehp_green_led_off(struct slot *slot);
|
||||
void pciehp_green_led_blink(struct slot *slot);
|
||||
int pciehp_check_link_status(struct controller *ctrl);
|
||||
bool pciehp_check_link_active(struct controller *ctrl);
|
||||
void pciehp_release_ctrl(struct controller *ctrl);
|
||||
int pciehp_reset_slot(struct slot *slot, int probe);
|
||||
|
||||
|
@@ -112,6 +112,7 @@ static struct pcie_port_service_driver __initdata dummy_driver = {
|
||||
static int __init select_detection_mode(void)
|
||||
{
|
||||
struct dummy_slot *slot, *tmp;
|
||||
|
||||
if (pcie_port_service_register(&dummy_driver))
|
||||
return PCIEHP_DETECT_ACPI;
|
||||
pcie_port_service_unregister(&dummy_driver);
|
||||
|
@@ -108,6 +108,7 @@ static int init_slot(struct controller *ctrl)
|
||||
ops = kzalloc(sizeof(*ops), GFP_KERNEL);
|
||||
if (!ops)
|
||||
goto out;
|
||||
|
||||
ops->enable_slot = enable_slot;
|
||||
ops->disable_slot = disable_slot;
|
||||
ops->get_power_status = get_power_status;
|
||||
@@ -283,8 +284,11 @@ static int pciehp_probe(struct pcie_device *dev)
|
||||
slot = ctrl->slot;
|
||||
pciehp_get_adapter_status(slot, &occupied);
|
||||
pciehp_get_power_status(slot, &poweron);
|
||||
if (occupied && pciehp_force)
|
||||
if (occupied && pciehp_force) {
|
||||
mutex_lock(&slot->hotplug_lock);
|
||||
pciehp_enable_slot(slot);
|
||||
mutex_unlock(&slot->hotplug_lock);
|
||||
}
|
||||
/* If empty slot's power status is on, turn power off */
|
||||
if (!occupied && poweron && POWER_CTRL(ctrl))
|
||||
pciehp_power_off_slot(slot);
|
||||
@@ -328,10 +332,12 @@ static int pciehp_resume (struct pcie_device *dev)
|
||||
|
||||
/* Check if slot is occupied */
|
||||
pciehp_get_adapter_status(slot, &status);
|
||||
mutex_lock(&slot->hotplug_lock);
|
||||
if (status)
|
||||
pciehp_enable_slot(slot);
|
||||
else
|
||||
pciehp_disable_slot(slot);
|
||||
mutex_unlock(&slot->hotplug_lock);
|
||||
return 0;
|
||||
}
|
||||
#endif /* PM */
|
||||
|
@@ -150,6 +150,27 @@ u8 pciehp_handle_power_fault(struct slot *p_slot)
|
||||
return 1;
|
||||
}
|
||||
|
||||
void pciehp_handle_linkstate_change(struct slot *p_slot)
|
||||
{
|
||||
u32 event_type;
|
||||
struct controller *ctrl = p_slot->ctrl;
|
||||
|
||||
/* Link Status Change */
|
||||
ctrl_dbg(ctrl, "Data Link Layer State change\n");
|
||||
|
||||
if (pciehp_check_link_active(ctrl)) {
|
||||
ctrl_info(ctrl, "slot(%s): Link Up event\n",
|
||||
slot_name(p_slot));
|
||||
event_type = INT_LINK_UP;
|
||||
} else {
|
||||
ctrl_info(ctrl, "slot(%s): Link Down event\n",
|
||||
slot_name(p_slot));
|
||||
event_type = INT_LINK_DOWN;
|
||||
}
|
||||
|
||||
queue_interrupt_event(p_slot, event_type);
|
||||
}
|
||||
|
||||
/* The following routines constitute the bulk of the
|
||||
hotplug controller logic
|
||||
*/
|
||||
@@ -212,7 +233,8 @@ static int board_added(struct slot *p_slot)
|
||||
if (retval) {
|
||||
ctrl_err(ctrl, "Cannot add device at %04x:%02x:00\n",
|
||||
pci_domain_nr(parent), parent->number);
|
||||
goto err_exit;
|
||||
if (retval != -EEXIST)
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
pciehp_green_led_on(p_slot);
|
||||
@@ -255,6 +277,9 @@ static int remove_board(struct slot *p_slot)
|
||||
struct power_work_info {
|
||||
struct slot *p_slot;
|
||||
struct work_struct work;
|
||||
unsigned int req;
|
||||
#define DISABLE_REQ 0
|
||||
#define ENABLE_REQ 1
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -269,30 +294,38 @@ static void pciehp_power_thread(struct work_struct *work)
|
||||
struct power_work_info *info =
|
||||
container_of(work, struct power_work_info, work);
|
||||
struct slot *p_slot = info->p_slot;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&p_slot->lock);
|
||||
switch (p_slot->state) {
|
||||
case POWEROFF_STATE:
|
||||
mutex_unlock(&p_slot->lock);
|
||||
switch (info->req) {
|
||||
case DISABLE_REQ:
|
||||
ctrl_dbg(p_slot->ctrl,
|
||||
"Disabling domain:bus:device=%04x:%02x:00\n",
|
||||
pci_domain_nr(p_slot->ctrl->pcie->port->subordinate),
|
||||
p_slot->ctrl->pcie->port->subordinate->number);
|
||||
mutex_lock(&p_slot->hotplug_lock);
|
||||
pciehp_disable_slot(p_slot);
|
||||
mutex_unlock(&p_slot->hotplug_lock);
|
||||
mutex_lock(&p_slot->lock);
|
||||
p_slot->state = STATIC_STATE;
|
||||
break;
|
||||
case POWERON_STATE:
|
||||
mutex_unlock(&p_slot->lock);
|
||||
if (pciehp_enable_slot(p_slot))
|
||||
break;
|
||||
case ENABLE_REQ:
|
||||
ctrl_dbg(p_slot->ctrl,
|
||||
"Enabling domain:bus:device=%04x:%02x:00\n",
|
||||
pci_domain_nr(p_slot->ctrl->pcie->port->subordinate),
|
||||
p_slot->ctrl->pcie->port->subordinate->number);
|
||||
mutex_lock(&p_slot->hotplug_lock);
|
||||
ret = pciehp_enable_slot(p_slot);
|
||||
mutex_unlock(&p_slot->hotplug_lock);
|
||||
if (ret)
|
||||
pciehp_green_led_off(p_slot);
|
||||
mutex_lock(&p_slot->lock);
|
||||
p_slot->state = STATIC_STATE;
|
||||
mutex_unlock(&p_slot->lock);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
mutex_unlock(&p_slot->lock);
|
||||
|
||||
kfree(info);
|
||||
}
|
||||
@@ -315,9 +348,11 @@ void pciehp_queue_pushbutton_work(struct work_struct *work)
|
||||
switch (p_slot->state) {
|
||||
case BLINKINGOFF_STATE:
|
||||
p_slot->state = POWEROFF_STATE;
|
||||
info->req = DISABLE_REQ;
|
||||
break;
|
||||
case BLINKINGON_STATE:
|
||||
p_slot->state = POWERON_STATE;
|
||||
info->req = ENABLE_REQ;
|
||||
break;
|
||||
default:
|
||||
kfree(info);
|
||||
@@ -364,11 +399,10 @@ static void handle_button_press_event(struct slot *p_slot)
|
||||
*/
|
||||
ctrl_info(ctrl, "Button cancel on Slot(%s)\n", slot_name(p_slot));
|
||||
cancel_delayed_work(&p_slot->work);
|
||||
if (p_slot->state == BLINKINGOFF_STATE) {
|
||||
if (p_slot->state == BLINKINGOFF_STATE)
|
||||
pciehp_green_led_on(p_slot);
|
||||
} else {
|
||||
else
|
||||
pciehp_green_led_off(p_slot);
|
||||
}
|
||||
pciehp_set_attention_status(p_slot, 0);
|
||||
ctrl_info(ctrl, "PCI slot #%s - action canceled "
|
||||
"due to button press\n", slot_name(p_slot));
|
||||
@@ -407,14 +441,81 @@ static void handle_surprise_event(struct slot *p_slot)
|
||||
INIT_WORK(&info->work, pciehp_power_thread);
|
||||
|
||||
pciehp_get_adapter_status(p_slot, &getstatus);
|
||||
if (!getstatus)
|
||||
if (!getstatus) {
|
||||
p_slot->state = POWEROFF_STATE;
|
||||
else
|
||||
info->req = DISABLE_REQ;
|
||||
} else {
|
||||
p_slot->state = POWERON_STATE;
|
||||
info->req = ENABLE_REQ;
|
||||
}
|
||||
|
||||
queue_work(p_slot->wq, &info->work);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: This function must be called with slot->lock held
|
||||
*/
|
||||
static void handle_link_event(struct slot *p_slot, u32 event)
|
||||
{
|
||||
struct controller *ctrl = p_slot->ctrl;
|
||||
struct power_work_info *info;
|
||||
|
||||
info = kmalloc(sizeof(*info), GFP_KERNEL);
|
||||
if (!info) {
|
||||
ctrl_err(p_slot->ctrl, "%s: Cannot allocate memory\n",
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
info->p_slot = p_slot;
|
||||
info->req = event == INT_LINK_UP ? ENABLE_REQ : DISABLE_REQ;
|
||||
INIT_WORK(&info->work, pciehp_power_thread);
|
||||
|
||||
switch (p_slot->state) {
|
||||
case BLINKINGON_STATE:
|
||||
case BLINKINGOFF_STATE:
|
||||
cancel_delayed_work(&p_slot->work);
|
||||
/* Fall through */
|
||||
case STATIC_STATE:
|
||||
p_slot->state = event == INT_LINK_UP ?
|
||||
POWERON_STATE : POWEROFF_STATE;
|
||||
queue_work(p_slot->wq, &info->work);
|
||||
break;
|
||||
case POWERON_STATE:
|
||||
if (event == INT_LINK_UP) {
|
||||
ctrl_info(ctrl,
|
||||
"Link Up event ignored on slot(%s): already powering on\n",
|
||||
slot_name(p_slot));
|
||||
kfree(info);
|
||||
} else {
|
||||
ctrl_info(ctrl,
|
||||
"Link Down event queued on slot(%s): currently getting powered on\n",
|
||||
slot_name(p_slot));
|
||||
p_slot->state = POWEROFF_STATE;
|
||||
queue_work(p_slot->wq, &info->work);
|
||||
}
|
||||
break;
|
||||
case POWEROFF_STATE:
|
||||
if (event == INT_LINK_UP) {
|
||||
ctrl_info(ctrl,
|
||||
"Link Up event queued on slot(%s): currently getting powered off\n",
|
||||
slot_name(p_slot));
|
||||
p_slot->state = POWERON_STATE;
|
||||
queue_work(p_slot->wq, &info->work);
|
||||
} else {
|
||||
ctrl_info(ctrl,
|
||||
"Link Down event ignored on slot(%s): already powering off\n",
|
||||
slot_name(p_slot));
|
||||
kfree(info);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ctrl_err(ctrl, "Not a valid state on slot(%s)\n",
|
||||
slot_name(p_slot));
|
||||
kfree(info);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void interrupt_event_handler(struct work_struct *work)
|
||||
{
|
||||
struct event_info *info = container_of(work, struct event_info, work);
|
||||
@@ -433,12 +534,23 @@ static void interrupt_event_handler(struct work_struct *work)
|
||||
pciehp_green_led_off(p_slot);
|
||||
break;
|
||||
case INT_PRESENCE_ON:
|
||||
case INT_PRESENCE_OFF:
|
||||
if (!HP_SUPR_RM(ctrl))
|
||||
break;
|
||||
ctrl_dbg(ctrl, "Surprise Insertion\n");
|
||||
handle_surprise_event(p_slot);
|
||||
break;
|
||||
case INT_PRESENCE_OFF:
|
||||
/*
|
||||
* Regardless of surprise capability, we need to
|
||||
* definitely remove a card that has been pulled out!
|
||||
*/
|
||||
ctrl_dbg(ctrl, "Surprise Removal\n");
|
||||
handle_surprise_event(p_slot);
|
||||
break;
|
||||
case INT_LINK_UP:
|
||||
case INT_LINK_DOWN:
|
||||
handle_link_event(p_slot, info->event_type);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -447,6 +559,9 @@ static void interrupt_event_handler(struct work_struct *work)
|
||||
kfree(info);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note: This function must be called with slot->hotplug_lock held
|
||||
*/
|
||||
int pciehp_enable_slot(struct slot *p_slot)
|
||||
{
|
||||
u8 getstatus = 0;
|
||||
@@ -479,13 +594,15 @@ int pciehp_enable_slot(struct slot *p_slot)
|
||||
pciehp_get_latch_status(p_slot, &getstatus);
|
||||
|
||||
rc = board_added(p_slot);
|
||||
if (rc) {
|
||||
if (rc)
|
||||
pciehp_get_latch_status(p_slot, &getstatus);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Note: This function must be called with slot->hotplug_lock held
|
||||
*/
|
||||
int pciehp_disable_slot(struct slot *p_slot)
|
||||
{
|
||||
u8 getstatus = 0;
|
||||
@@ -494,24 +611,6 @@ int pciehp_disable_slot(struct slot *p_slot)
|
||||
if (!p_slot->ctrl)
|
||||
return 1;
|
||||
|
||||
if (!HP_SUPR_RM(p_slot->ctrl)) {
|
||||
pciehp_get_adapter_status(p_slot, &getstatus);
|
||||
if (!getstatus) {
|
||||
ctrl_info(ctrl, "No adapter on slot(%s)\n",
|
||||
slot_name(p_slot));
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
if (MRL_SENS(p_slot->ctrl)) {
|
||||
pciehp_get_latch_status(p_slot, &getstatus);
|
||||
if (getstatus) {
|
||||
ctrl_info(ctrl, "Latch open on slot(%s)\n",
|
||||
slot_name(p_slot));
|
||||
return -ENODEV;
|
||||
}
|
||||
}
|
||||
|
||||
if (POWER_CTRL(p_slot->ctrl)) {
|
||||
pciehp_get_power_status(p_slot, &getstatus);
|
||||
if (!getstatus) {
|
||||
@@ -536,7 +635,9 @@ int pciehp_sysfs_enable_slot(struct slot *p_slot)
|
||||
case STATIC_STATE:
|
||||
p_slot->state = POWERON_STATE;
|
||||
mutex_unlock(&p_slot->lock);
|
||||
mutex_lock(&p_slot->hotplug_lock);
|
||||
retval = pciehp_enable_slot(p_slot);
|
||||
mutex_unlock(&p_slot->hotplug_lock);
|
||||
mutex_lock(&p_slot->lock);
|
||||
p_slot->state = STATIC_STATE;
|
||||
break;
|
||||
|
@@ -206,7 +206,7 @@ static void pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
|
||||
mutex_unlock(&ctrl->ctrl_lock);
|
||||
}
|
||||
|
||||
static bool check_link_active(struct controller *ctrl)
|
||||
bool pciehp_check_link_active(struct controller *ctrl)
|
||||
{
|
||||
struct pci_dev *pdev = ctrl_dev(ctrl);
|
||||
u16 lnk_status;
|
||||
@@ -225,12 +225,12 @@ static void __pcie_wait_link_active(struct controller *ctrl, bool active)
|
||||
{
|
||||
int timeout = 1000;
|
||||
|
||||
if (check_link_active(ctrl) == active)
|
||||
if (pciehp_check_link_active(ctrl) == active)
|
||||
return;
|
||||
while (timeout > 0) {
|
||||
msleep(10);
|
||||
timeout -= 10;
|
||||
if (check_link_active(ctrl) == active)
|
||||
if (pciehp_check_link_active(ctrl) == active)
|
||||
return;
|
||||
}
|
||||
ctrl_dbg(ctrl, "Data Link Layer Link Active not %s in 1000 msec\n",
|
||||
@@ -242,11 +242,6 @@ static void pcie_wait_link_active(struct controller *ctrl)
|
||||
__pcie_wait_link_active(ctrl, true);
|
||||
}
|
||||
|
||||
static void pcie_wait_link_not_active(struct controller *ctrl)
|
||||
{
|
||||
__pcie_wait_link_active(ctrl, false);
|
||||
}
|
||||
|
||||
static bool pci_bus_check_dev(struct pci_bus *bus, int devfn)
|
||||
{
|
||||
u32 l;
|
||||
@@ -332,11 +327,6 @@ static int pciehp_link_enable(struct controller *ctrl)
|
||||
return __pciehp_link_set(ctrl, true);
|
||||
}
|
||||
|
||||
static int pciehp_link_disable(struct controller *ctrl)
|
||||
{
|
||||
return __pciehp_link_set(ctrl, false);
|
||||
}
|
||||
|
||||
void pciehp_get_attention_status(struct slot *slot, u8 *status)
|
||||
{
|
||||
struct controller *ctrl = slot->ctrl;
|
||||
@@ -508,14 +498,6 @@ void pciehp_power_off_slot(struct slot * slot)
|
||||
{
|
||||
struct controller *ctrl = slot->ctrl;
|
||||
|
||||
/* Disable the link at first */
|
||||
pciehp_link_disable(ctrl);
|
||||
/* wait the link is down */
|
||||
if (ctrl->link_active_reporting)
|
||||
pcie_wait_link_not_active(ctrl);
|
||||
else
|
||||
msleep(1000);
|
||||
|
||||
pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_OFF, PCI_EXP_SLTCTL_PCC);
|
||||
ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
|
||||
pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL,
|
||||
@@ -540,7 +522,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
|
||||
|
||||
detected &= (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD |
|
||||
PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC |
|
||||
PCI_EXP_SLTSTA_CC);
|
||||
PCI_EXP_SLTSTA_CC | PCI_EXP_SLTSTA_DLLSC);
|
||||
detected &= ~intr_loc;
|
||||
intr_loc |= detected;
|
||||
if (!intr_loc)
|
||||
@@ -579,6 +561,10 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
|
||||
ctrl->power_fault_detected = 1;
|
||||
pciehp_handle_power_fault(slot);
|
||||
}
|
||||
|
||||
if (intr_loc & PCI_EXP_SLTSTA_DLLSC)
|
||||
pciehp_handle_linkstate_change(slot);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@@ -596,9 +582,17 @@ void pcie_enable_notification(struct controller *ctrl)
|
||||
* when it is cleared in the interrupt service routine, and
|
||||
* next power fault detected interrupt was notified again.
|
||||
*/
|
||||
cmd = PCI_EXP_SLTCTL_PDCE;
|
||||
|
||||
/*
|
||||
* Always enable link events: thus link-up and link-down shall
|
||||
* always be treated as hotplug and unplug respectively. Enable
|
||||
* presence detect only if Attention Button is not present.
|
||||
*/
|
||||
cmd = PCI_EXP_SLTCTL_DLLSCE;
|
||||
if (ATTN_BUTTN(ctrl))
|
||||
cmd |= PCI_EXP_SLTCTL_ABPE;
|
||||
else
|
||||
cmd |= PCI_EXP_SLTCTL_PDCE;
|
||||
if (MRL_SENS(ctrl))
|
||||
cmd |= PCI_EXP_SLTCTL_MRLSCE;
|
||||
if (!pciehp_poll_mode)
|
||||
@@ -606,7 +600,8 @@ void pcie_enable_notification(struct controller *ctrl)
|
||||
|
||||
mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE |
|
||||
PCI_EXP_SLTCTL_MRLSCE | PCI_EXP_SLTCTL_PFDE |
|
||||
PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE);
|
||||
PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE |
|
||||
PCI_EXP_SLTCTL_DLLSCE);
|
||||
|
||||
pcie_write_cmd(ctrl, cmd, mask);
|
||||
}
|
||||
@@ -624,33 +619,38 @@ static void pcie_disable_notification(struct controller *ctrl)
|
||||
|
||||
/*
|
||||
* pciehp has a 1:1 bus:slot relationship so we ultimately want a secondary
|
||||
* bus reset of the bridge, but if the slot supports surprise removal we need
|
||||
* to disable presence detection around the bus reset and clear any spurious
|
||||
* bus reset of the bridge, but at the same time we want to ensure that it is
|
||||
* not seen as a hot-unplug, followed by the hot-plug of the device. Thus,
|
||||
* disable link state notification and presence detection change notification
|
||||
* momentarily, if we see that they could interfere. Also, clear any spurious
|
||||
* events after.
|
||||
*/
|
||||
int pciehp_reset_slot(struct slot *slot, int probe)
|
||||
{
|
||||
struct controller *ctrl = slot->ctrl;
|
||||
struct pci_dev *pdev = ctrl_dev(ctrl);
|
||||
u16 stat_mask = 0, ctrl_mask = 0;
|
||||
|
||||
if (probe)
|
||||
return 0;
|
||||
|
||||
if (HP_SUPR_RM(ctrl)) {
|
||||
pcie_write_cmd(ctrl, 0, PCI_EXP_SLTCTL_PDCE);
|
||||
if (pciehp_poll_mode)
|
||||
del_timer_sync(&ctrl->poll_timer);
|
||||
if (!ATTN_BUTTN(ctrl)) {
|
||||
ctrl_mask |= PCI_EXP_SLTCTL_PDCE;
|
||||
stat_mask |= PCI_EXP_SLTSTA_PDC;
|
||||
}
|
||||
ctrl_mask |= PCI_EXP_SLTCTL_DLLSCE;
|
||||
stat_mask |= PCI_EXP_SLTSTA_DLLSC;
|
||||
|
||||
pcie_write_cmd(ctrl, 0, ctrl_mask);
|
||||
if (pciehp_poll_mode)
|
||||
del_timer_sync(&ctrl->poll_timer);
|
||||
|
||||
pci_reset_bridge_secondary_bus(ctrl->pcie->port);
|
||||
|
||||
if (HP_SUPR_RM(ctrl)) {
|
||||
pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
|
||||
PCI_EXP_SLTSTA_PDC);
|
||||
pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PDCE, PCI_EXP_SLTCTL_PDCE);
|
||||
if (pciehp_poll_mode)
|
||||
int_poll_timeout(ctrl->poll_timer.data);
|
||||
}
|
||||
pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, stat_mask);
|
||||
pcie_write_cmd(ctrl, ctrl_mask, ctrl_mask);
|
||||
if (pciehp_poll_mode)
|
||||
int_poll_timeout(ctrl->poll_timer.data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -687,6 +687,7 @@ static int pcie_init_slot(struct controller *ctrl)
|
||||
|
||||
slot->ctrl = ctrl;
|
||||
mutex_init(&slot->lock);
|
||||
mutex_init(&slot->hotplug_lock);
|
||||
INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work);
|
||||
ctrl->slot = slot;
|
||||
return 0;
|
||||
|
@@ -50,7 +50,7 @@ int pciehp_configure_device(struct slot *p_slot)
|
||||
"at %04x:%02x:00, cannot hot-add\n", pci_name(dev),
|
||||
pci_domain_nr(parent), parent->number);
|
||||
pci_dev_put(dev);
|
||||
ret = -EINVAL;
|
||||
ret = -EEXIST;
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user