Commit 1ec7d99c authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6:
  pciehp: add message about pciehp_slot_with_bus option
  pci hotplug core: add check of duplicate slot name
  pciehp: move msleep after power off
  pciehp: poll cmd completion if hotplug interrupt is disabled
  pciehp: fix slow probing
  pciehp: fix NULL dereference in interrupt handler
  shpchp: add message about shpchp_slot_with_bus option
  PCI: don't enable ASPM on devices with mixed PCIe/PCI functions
parents 3dbfd080 9e4f2e8d
...@@ -619,6 +619,7 @@ static struct hotplug_slot *get_slot_from_name (const char *name) ...@@ -619,6 +619,7 @@ static struct hotplug_slot *get_slot_from_name (const char *name)
int pci_hp_register (struct hotplug_slot *slot) int pci_hp_register (struct hotplug_slot *slot)
{ {
int result; int result;
struct hotplug_slot *tmp;
if (slot == NULL) if (slot == NULL)
return -ENODEV; return -ENODEV;
...@@ -630,7 +631,11 @@ int pci_hp_register (struct hotplug_slot *slot) ...@@ -630,7 +631,11 @@ int pci_hp_register (struct hotplug_slot *slot)
return -EINVAL; return -EINVAL;
} }
/* this can fail if we have already registered a slot with the same name */ /* Check if we have already registered a slot with the same name. */
tmp = get_slot_from_name(slot->name);
if (tmp)
return -EEXIST;
slot->kobj.kset = pci_hotplug_slots_kset; slot->kobj.kset = pci_hotplug_slots_kset;
result = kobject_init_and_add(&slot->kobj, &hotplug_slot_ktype, NULL, result = kobject_init_and_add(&slot->kobj, &hotplug_slot_ktype, NULL,
"%s", slot->name); "%s", slot->name);
......
...@@ -97,6 +97,7 @@ struct controller { ...@@ -97,6 +97,7 @@ struct controller {
u8 cap_base; u8 cap_base;
struct timer_list poll_timer; struct timer_list poll_timer;
volatile int cmd_busy; volatile int cmd_busy;
unsigned int no_cmd_complete:1;
}; };
#define INT_BUTTON_IGNORE 0 #define INT_BUTTON_IGNORE 0
...@@ -135,6 +136,7 @@ struct controller { ...@@ -135,6 +136,7 @@ struct controller {
#define PWR_LED_PRSN 0x00000010 #define PWR_LED_PRSN 0x00000010
#define HP_SUPR_RM_SUP 0x00000020 #define HP_SUPR_RM_SUP 0x00000020
#define EMI_PRSN 0x00020000 #define EMI_PRSN 0x00020000
#define NO_CMD_CMPL_SUP 0x00040000
#define ATTN_BUTTN(ctrl) ((ctrl)->slot_cap & ATTN_BUTTN_PRSN) #define ATTN_BUTTN(ctrl) ((ctrl)->slot_cap & ATTN_BUTTN_PRSN)
#define POWER_CTRL(ctrl) ((ctrl)->slot_cap & PWR_CTRL_PRSN) #define POWER_CTRL(ctrl) ((ctrl)->slot_cap & PWR_CTRL_PRSN)
...@@ -143,13 +145,14 @@ struct controller { ...@@ -143,13 +145,14 @@ struct controller {
#define PWR_LED(ctrl) ((ctrl)->slot_cap & PWR_LED_PRSN) #define PWR_LED(ctrl) ((ctrl)->slot_cap & PWR_LED_PRSN)
#define HP_SUPR_RM(ctrl) ((ctrl)->slot_cap & HP_SUPR_RM_SUP) #define HP_SUPR_RM(ctrl) ((ctrl)->slot_cap & HP_SUPR_RM_SUP)
#define EMI(ctrl) ((ctrl)->slot_cap & EMI_PRSN) #define EMI(ctrl) ((ctrl)->slot_cap & EMI_PRSN)
#define NO_CMD_CMPL(ctrl) ((ctrl)->slot_cap & NO_CMD_CMPL_SUP)
extern int pciehp_sysfs_enable_slot(struct slot *slot); extern int pciehp_sysfs_enable_slot(struct slot *slot);
extern int pciehp_sysfs_disable_slot(struct slot *slot); extern int pciehp_sysfs_disable_slot(struct slot *slot);
extern u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl); extern u8 pciehp_handle_attention_button(struct slot *p_slot);
extern u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl); extern u8 pciehp_handle_switch_change(struct slot *p_slot);
extern u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl); extern u8 pciehp_handle_presence_change(struct slot *p_slot);
extern u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl); extern u8 pciehp_handle_power_fault(struct slot *p_slot);
extern int pciehp_configure_device(struct slot *p_slot); extern int pciehp_configure_device(struct slot *p_slot);
extern int pciehp_unconfigure_device(struct slot *p_slot); extern int pciehp_unconfigure_device(struct slot *p_slot);
extern void pciehp_queue_pushbutton_work(struct work_struct *work); extern void pciehp_queue_pushbutton_work(struct work_struct *work);
......
...@@ -254,7 +254,11 @@ static int init_slots(struct controller *ctrl) ...@@ -254,7 +254,11 @@ static int init_slots(struct controller *ctrl)
slot->hp_slot, slot->number, ctrl->slot_device_offset); slot->hp_slot, slot->number, ctrl->slot_device_offset);
retval = pci_hp_register(hotplug_slot); retval = pci_hp_register(hotplug_slot);
if (retval) { if (retval) {
err ("pci_hp_register failed with error %d\n", retval); err("pci_hp_register failed with error %d\n", retval);
if (retval == -EEXIST)
err("Failed to register slot because of name "
"collision. Try \'pciehp_slot_with_bus\' "
"module option.\n");
goto error_info; goto error_info;
} }
/* create additional sysfs entries */ /* create additional sysfs entries */
......
...@@ -55,16 +55,13 @@ static int queue_interrupt_event(struct slot *p_slot, u32 event_type) ...@@ -55,16 +55,13 @@ static int queue_interrupt_event(struct slot *p_slot, u32 event_type)
return 0; return 0;
} }
u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl) u8 pciehp_handle_attention_button(struct slot *p_slot)
{ {
struct slot *p_slot;
u32 event_type; u32 event_type;
/* Attention Button Change */ /* Attention Button Change */
dbg("pciehp: Attention button interrupt received.\n"); dbg("pciehp: Attention button interrupt received.\n");
p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
/* /*
* Button pressed - See if need to TAKE ACTION!!! * Button pressed - See if need to TAKE ACTION!!!
*/ */
...@@ -76,18 +73,15 @@ u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl) ...@@ -76,18 +73,15 @@ u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl)
return 0; return 0;
} }
u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl) u8 pciehp_handle_switch_change(struct slot *p_slot)
{ {
struct slot *p_slot;
u8 getstatus; u8 getstatus;
u32 event_type; u32 event_type;
/* Switch Change */ /* Switch Change */
dbg("pciehp: Switch interrupt received.\n"); dbg("pciehp: Switch interrupt received.\n");
p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
p_slot->hpc_ops->get_latch_status(p_slot, &getstatus); p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
if (getstatus) { if (getstatus) {
/* /*
* Switch opened * Switch opened
...@@ -107,17 +101,14 @@ u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl) ...@@ -107,17 +101,14 @@ u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl)
return 1; return 1;
} }
u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl) u8 pciehp_handle_presence_change(struct slot *p_slot)
{ {
struct slot *p_slot;
u32 event_type; u32 event_type;
u8 presence_save; u8 presence_save;
/* Presence Change */ /* Presence Change */
dbg("pciehp: Presence/Notify input change.\n"); dbg("pciehp: Presence/Notify input change.\n");
p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
/* Switch is open, assume a presence change /* Switch is open, assume a presence change
* Save the presence state * Save the presence state
*/ */
...@@ -141,16 +132,13 @@ u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl) ...@@ -141,16 +132,13 @@ u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl)
return 1; return 1;
} }
u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl) u8 pciehp_handle_power_fault(struct slot *p_slot)
{ {
struct slot *p_slot;
u32 event_type; u32 event_type;
/* power fault */ /* power fault */
dbg("pciehp: Power fault interrupt received.\n"); dbg("pciehp: Power fault interrupt received.\n");
p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) { if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) {
/* /*
* power fault Cleared * power fault Cleared
...@@ -163,7 +151,7 @@ u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl) ...@@ -163,7 +151,7 @@ u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl)
*/ */
info("Power fault on Slot(%s)\n", p_slot->name); info("Power fault on Slot(%s)\n", p_slot->name);
event_type = INT_POWER_FAULT; event_type = INT_POWER_FAULT;
info("power fault bit %x set\n", hp_slot); info("power fault bit %x set\n", 0);
} }
queue_interrupt_event(p_slot, event_type); queue_interrupt_event(p_slot, event_type);
...@@ -186,6 +174,13 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot) ...@@ -186,6 +174,13 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot)
} }
} }
/*
* After turning power off, we must wait for at least 1 second
* before taking any action that relies on power having been
* removed from the slot/adapter.
*/
msleep(1000);
if (PWR_LED(ctrl)) if (PWR_LED(ctrl))
pslot->hpc_ops->green_led_off(pslot); pslot->hpc_ops->green_led_off(pslot);
...@@ -289,6 +284,13 @@ static int remove_board(struct slot *p_slot) ...@@ -289,6 +284,13 @@ static int remove_board(struct slot *p_slot)
} }
} }
/*
* After turning power off, we must wait for at least 1 second
* before taking any action that relies on power having been
* removed from the slot/adapter.
*/
msleep(1000);
if (PWR_LED(ctrl)) if (PWR_LED(ctrl))
/* turn off Green LED */ /* turn off Green LED */
p_slot->hpc_ops->green_led_off(p_slot); p_slot->hpc_ops->green_led_off(p_slot);
......
...@@ -247,14 +247,38 @@ static inline void pciehp_free_irq(struct controller *ctrl) ...@@ -247,14 +247,38 @@ static inline void pciehp_free_irq(struct controller *ctrl)
free_irq(ctrl->pci_dev->irq, ctrl); free_irq(ctrl->pci_dev->irq, ctrl);
} }
static inline int pcie_wait_cmd(struct controller *ctrl) static inline int pcie_poll_cmd(struct controller *ctrl)
{
u16 slot_status;
int timeout = 1000;
if (!pciehp_readw(ctrl, SLOTSTATUS, &slot_status))
if (slot_status & CMD_COMPLETED)
goto completed;
for (timeout = 1000; timeout > 0; timeout -= 100) {
msleep(100);
if (!pciehp_readw(ctrl, SLOTSTATUS, &slot_status))
if (slot_status & CMD_COMPLETED)
goto completed;
}
return 0; /* timeout */
completed:
pciehp_writew(ctrl, SLOTSTATUS, CMD_COMPLETED);
return timeout;
}
static inline int pcie_wait_cmd(struct controller *ctrl, int poll)
{ {
int retval = 0; int retval = 0;
unsigned int msecs = pciehp_poll_mode ? 2500 : 1000; unsigned int msecs = pciehp_poll_mode ? 2500 : 1000;
unsigned long timeout = msecs_to_jiffies(msecs); unsigned long timeout = msecs_to_jiffies(msecs);
int rc; int rc;
rc = wait_event_interruptible_timeout(ctrl->queue, if (poll)
rc = pcie_poll_cmd(ctrl);
else
rc = wait_event_interruptible_timeout(ctrl->queue,
!ctrl->cmd_busy, timeout); !ctrl->cmd_busy, timeout);
if (!rc) if (!rc)
dbg("Command not completed in 1000 msec\n"); dbg("Command not completed in 1000 msec\n");
...@@ -286,12 +310,28 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask) ...@@ -286,12 +310,28 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
goto out; goto out;
} }
if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) { if (slot_status & CMD_COMPLETED) {
/* After 1 sec and CMD_COMPLETED still not set, just if (!ctrl->no_cmd_complete) {
proceed forward to issue the next command according /*
to spec. Just print out the error message */ * After 1 sec and CMD_COMPLETED still not set, just
dbg("%s: CMD_COMPLETED not clear after 1 sec.\n", * proceed forward to issue the next command according
__func__); * to spec. Just print out the error message.
*/
dbg("%s: CMD_COMPLETED not clear after 1 sec.\n",
__func__);
} else if (!NO_CMD_CMPL(ctrl)) {
/*
* This controller semms to notify of command completed
* event even though it supports none of power
* controller, attention led, power led and EMI.
*/
dbg("%s: Unexpected CMD_COMPLETED. Need to wait for "
"command completed event.\n", __func__);
ctrl->no_cmd_complete = 0;
} else {
dbg("%s: Unexpected CMD_COMPLETED. Maybe the "
"controller is broken.\n", __func__);
}
} }
retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl); retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
...@@ -315,8 +355,18 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask) ...@@ -315,8 +355,18 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
/* /*
* Wait for command completion. * Wait for command completion.
*/ */
if (!retval) if (!retval && !ctrl->no_cmd_complete) {
retval = pcie_wait_cmd(ctrl); int poll = 0;
/*
* if hotplug interrupt is not enabled or command
* completed interrupt is not enabled, we need to poll
* command completed event.
*/
if (!(slot_ctrl & HP_INTR_ENABLE) ||
!(slot_ctrl & CMD_CMPL_INTR_ENABLE))
poll = 1;
retval = pcie_wait_cmd(ctrl, poll);
}
out: out:
mutex_unlock(&ctrl->ctrl_lock); mutex_unlock(&ctrl->ctrl_lock);
return retval; return retval;
...@@ -704,13 +754,6 @@ static int hpc_power_off_slot(struct slot * slot) ...@@ -704,13 +754,6 @@ static int hpc_power_off_slot(struct slot * slot)
} }
dbg("%s: SLOTCTRL %x write cmd %x\n", dbg("%s: SLOTCTRL %x write cmd %x\n",
__func__, ctrl->cap_base + SLOTCTRL, slot_cmd); __func__, ctrl->cap_base + SLOTCTRL, slot_cmd);
/*
* After turning power off, we must wait for at least 1 second
* before taking any action that relies on power having been
* removed from the slot/adapter.
*/
msleep(1000);
out: out:
if (changed) if (changed)
pcie_unmask_bad_dllp(ctrl); pcie_unmask_bad_dllp(ctrl);
...@@ -722,6 +765,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) ...@@ -722,6 +765,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
{ {
struct controller *ctrl = (struct controller *)dev_id; struct controller *ctrl = (struct controller *)dev_id;
u16 detected, intr_loc; u16 detected, intr_loc;
struct slot *p_slot;
/* /*
* In order to guarantee that all interrupt events are * In order to guarantee that all interrupt events are
...@@ -756,21 +800,38 @@ static irqreturn_t pcie_isr(int irq, void *dev_id) ...@@ -756,21 +800,38 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
wake_up_interruptible(&ctrl->queue); wake_up_interruptible(&ctrl->queue);
} }
if (!(intr_loc & ~CMD_COMPLETED))
return IRQ_HANDLED;
/*
* Return without handling events if this handler routine is
* called before controller initialization is done. This may
* happen if hotplug event or another interrupt that shares
* the IRQ with pciehp arrives before slot initialization is
* done after interrupt handler is registered.
*
* FIXME - Need more structural fixes. We need to be ready to
* handle the event before installing interrupt handler.
*/
p_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset);
if (!p_slot || !p_slot->hpc_ops)
return IRQ_HANDLED;
/* Check MRL Sensor Changed */ /* Check MRL Sensor Changed */
if (intr_loc & MRL_SENS_CHANGED) if (intr_loc & MRL_SENS_CHANGED)
pciehp_handle_switch_change(0, ctrl); pciehp_handle_switch_change(p_slot);
/* Check Attention Button Pressed */ /* Check Attention Button Pressed */
if (intr_loc & ATTN_BUTTN_PRESSED) if (intr_loc & ATTN_BUTTN_PRESSED)
pciehp_handle_attention_button(0, ctrl); pciehp_handle_attention_button(p_slot);
/* Check Presence Detect Changed */ /* Check Presence Detect Changed */
if (intr_loc & PRSN_DETECT_CHANGED) if (intr_loc & PRSN_DETECT_CHANGED)
pciehp_handle_presence_change(0, ctrl); pciehp_handle_presence_change(p_slot);
/* Check Power Fault Detected */ /* Check Power Fault Detected */
if (intr_loc & PWR_FAULT_DETECTED) if (intr_loc & PWR_FAULT_DETECTED)
pciehp_handle_power_fault(0, ctrl); pciehp_handle_power_fault(p_slot);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -1028,6 +1089,12 @@ static int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev) ...@@ -1028,6 +1089,12 @@ static int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
static int pcie_init_hardware_part1(struct controller *ctrl, static int pcie_init_hardware_part1(struct controller *ctrl,
struct pcie_device *dev) struct pcie_device *dev)
{ {
/* Clear all remaining event bits in Slot Status register */
if (pciehp_writew(ctrl, SLOTSTATUS, 0x1f)) {
err("%s: Cannot write to SLOTSTATUS register\n", __func__);
return -1;
}
/* Mask Hot-plug Interrupt Enable */ /* Mask Hot-plug Interrupt Enable */
if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE)) { if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE)) {
err("%s: Cannot mask hotplug interrupt enable\n", __func__); err("%s: Cannot mask hotplug interrupt enable\n", __func__);
...@@ -1040,16 +1107,6 @@ int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev) ...@@ -1040,16 +1107,6 @@ int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev)
{ {
u16 cmd, mask; u16 cmd, mask;
/*
* We need to clear all events before enabling hotplug interrupt
* notification mechanism in order for hotplug controler to
* generate interrupts.
*/
if (pciehp_writew(ctrl, SLOTSTATUS, 0x1f)) {
err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
return -1;
}
cmd = PRSN_DETECT_ENABLE; cmd = PRSN_DETECT_ENABLE;
if (ATTN_BUTTN(ctrl)) if (ATTN_BUTTN(ctrl))
cmd |= ATTN_BUTTN_ENABLE; cmd |= ATTN_BUTTN_ENABLE;
...@@ -1116,6 +1173,7 @@ static inline void dbg_ctrl(struct controller *ctrl) ...@@ -1116,6 +1173,7 @@ static inline void dbg_ctrl(struct controller *ctrl)
dbg(" Power Indicator : %3s\n", PWR_LED(ctrl) ? "yes" : "no"); dbg(" Power Indicator : %3s\n", PWR_LED(ctrl) ? "yes" : "no");
dbg(" Hot-Plug Surprise : %3s\n", HP_SUPR_RM(ctrl) ? "yes" : "no"); dbg(" Hot-Plug Surprise : %3s\n", HP_SUPR_RM(ctrl) ? "yes" : "no");
dbg(" EMI Present : %3s\n", EMI(ctrl) ? "yes" : "no"); dbg(" EMI Present : %3s\n", EMI(ctrl) ? "yes" : "no");
dbg(" Comamnd Completed : %3s\n", NO_CMD_CMPL(ctrl)? "no" : "yes");
pciehp_readw(ctrl, SLOTSTATUS, &reg16); pciehp_readw(ctrl, SLOTSTATUS, &reg16);
dbg("Slot Status : 0x%04x\n", reg16); dbg("Slot Status : 0x%04x\n", reg16);
pciehp_readw(ctrl, SLOTSTATUS, &reg16); pciehp_readw(ctrl, SLOTSTATUS, &reg16);
...@@ -1147,6 +1205,15 @@ int pcie_init(struct controller *ctrl, struct pcie_device *dev) ...@@ -1147,6 +1205,15 @@ int pcie_init(struct controller *ctrl, struct pcie_device *dev)
mutex_init(&ctrl->ctrl_lock); mutex_init(&ctrl->ctrl_lock);
init_waitqueue_head(&ctrl->queue); init_waitqueue_head(&ctrl->queue);
dbg_ctrl(ctrl); dbg_ctrl(ctrl);
/*
* Controller doesn't notify of command completion if the "No
* Command Completed Support" bit is set in Slot Capability
* register or the controller supports none of power
* controller, attention led, power led and EMI.
*/
if (NO_CMD_CMPL(ctrl) ||
!(POWER_CTRL(ctrl) | ATTN_LED(ctrl) | PWR_LED(ctrl) | EMI(ctrl)))
ctrl->no_cmd_complete = 1;
info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n", info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n",
pdev->vendor, pdev->device, pdev->vendor, pdev->device,
......
...@@ -162,6 +162,10 @@ static int init_slots(struct controller *ctrl) ...@@ -162,6 +162,10 @@ static int init_slots(struct controller *ctrl)
retval = pci_hp_register(slot->hotplug_slot); retval = pci_hp_register(slot->hotplug_slot);
if (retval) { if (retval) {
err("pci_hp_register failed with error %d\n", retval); err("pci_hp_register failed with error %d\n", retval);
if (retval == -EEXIST)
err("Failed to register slot because of name "
"collision. Try \'shpchp_slot_with_bus\' "
"module option.\n");
goto error_info; goto error_info;
} }
......
...@@ -506,6 +506,23 @@ static void free_link_state(struct pci_dev *pdev) ...@@ -506,6 +506,23 @@ static void free_link_state(struct pci_dev *pdev)
pdev->link_state = NULL; pdev->link_state = NULL;
} }
static int pcie_aspm_sanity_check(struct pci_dev *pdev)
{
struct pci_dev *child_dev;
int child_pos;
/*
* Some functions in a slot might not all be PCIE functions, very
* strange. Disable ASPM for the whole slot
*/
list_for_each_entry(child_dev, &pdev->subordinate->devices, bus_list) {
child_pos = pci_find_capability(child_dev, PCI_CAP_ID_EXP);
if (!child_pos)
return -EINVAL;
}
return 0;
}
/* /*
* pcie_aspm_init_link_state: Initiate PCI express link state. * pcie_aspm_init_link_state: Initiate PCI express link state.
* It is called after the pcie and its children devices are scaned. * It is called after the pcie and its children devices are scaned.
...@@ -526,6 +543,9 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev) ...@@ -526,6 +543,9 @@ void pcie_aspm_init_link_state(struct pci_dev *pdev)
if (list_empty(&pdev->subordinate->devices)) if (list_empty(&pdev->subordinate->devices))
goto out; goto out;
if (pcie_aspm_sanity_check(pdev))
goto out;
mutex_lock(&aspm_lock); mutex_lock(&aspm_lock);
link_state = kzalloc(sizeof(*link_state), GFP_KERNEL); link_state = kzalloc(sizeof(*link_state), GFP_KERNEL);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment