mirror of https://gitee.com/openkylin/linux.git
Merge branch 'pci/pciehp' into next
* pci/pciehp: PCI: pciehp: Cleanup whitespace PCI: pciehp: Remove a non-existent card, regardless of "surprise" capability PCI: pciehp: Don't turn slot off when hot-added device already exists PCI: pciehp: Add hotplug_lock to serialize hotplug events PCI: pciehp: Ensure very fast hotplug events are also processed PCI: pciehp: Disable link notification across slot reset PCI: pciehp: Don't check adapter or latch status while disabling PCI: pciehp: Don't disable the link permanently during removal PCI: pciehp: Enable link state change notifications PCI: pciehp: Use link change notifications for hot-plug and removal PCI: pciehp: Make check_link_active() non-static
This commit is contained in:
commit
9d68c783d7
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue