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
This commit is contained in:
@@ -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)
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
#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 {
|
|||||||
#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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
*/
|
*/
|
||||||
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)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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,13 +247,37 @@ 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;
|
||||||
|
|
||||||
|
if (poll)
|
||||||
|
rc = pcie_poll_cmd(ctrl);
|
||||||
|
else
|
||||||
rc = wait_event_interruptible_timeout(ctrl->queue,
|
rc = wait_event_interruptible_timeout(ctrl->queue,
|
||||||
!ctrl->cmd_busy, timeout);
|
!ctrl->cmd_busy, timeout);
|
||||||
if (!rc)
|
if (!rc)
|
||||||
@@ -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
|
||||||
|
* proceed forward to issue the next command according
|
||||||
|
* to spec. Just print out the error message.
|
||||||
|
*/
|
||||||
dbg("%s: CMD_COMPLETED not clear after 1 sec.\n",
|
dbg("%s: CMD_COMPLETED not clear after 1 sec.\n",
|
||||||
__func__);
|
__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)
|
|||||||
/*
|
/*
|
||||||
* 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)
|
|||||||
}
|
}
|
||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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, ®16);
|
pciehp_readw(ctrl, SLOTSTATUS, ®16);
|
||||||
dbg("Slot Status : 0x%04x\n", reg16);
|
dbg("Slot Status : 0x%04x\n", reg16);
|
||||||
pciehp_readw(ctrl, SLOTSTATUS, ®16);
|
pciehp_readw(ctrl, SLOTSTATUS, ®16);
|
||||||
@@ -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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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);
|
||||||
|
Reference in New Issue
Block a user