Skip to content

Commit

Permalink
Merge branch 'pci/hotplug' into next
Browse files Browse the repository at this point in the history
* pci/hotplug:
  x86/PCI: VMD: Request userspace control of PCIe hotplug indicators
  PCI: pciehp: Allow exclusive userspace control of indicators
  PCI: pciehp: Remove useless pciehp_get_latch_status() calls
  PCI: pciehp: Clean up dmesg "Slot(%s)" messages
  PCI: pciehp: Remove unnecessary guard
  PCI: pciehp: Don't re-read Slot Status when handling surprise event
  PCI: pciehp: Don't re-read Slot Status when queuing hotplug event
  PCI: pciehp: Process all hotplug events before looking for new ones
  PCI: pciehp: Return IRQ_NONE when we can't read interrupt status
  PCI: pciehp: Rename pcie_isr() locals for clarity
  PCI: pciehp: Clear attention LED on device add
  • Loading branch information
Bjorn Helgaas committed Oct 3, 2016
2 parents fb6b6cc + 3161832 commit 64ea3b9
Show file tree
Hide file tree
Showing 8 changed files with 141 additions and 95 deletions.
14 changes: 14 additions & 0 deletions arch/x86/include/asm/pci.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ struct pci_sysdata {
#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
void *fwnode; /* IRQ domain for MSI assignment */
#endif
#if IS_ENABLED(CONFIG_VMD)
bool vmd_domain; /* True if in Intel VMD domain */
#endif
};

extern int pci_routeirq;
Expand Down Expand Up @@ -56,6 +59,17 @@ static inline void *_pci_root_bus_fwnode(struct pci_bus *bus)
#define pci_root_bus_fwnode _pci_root_bus_fwnode
#endif

static inline bool is_vmd(struct pci_bus *bus)
{
#if IS_ENABLED(CONFIG_VMD)
struct pci_sysdata *sd = bus->sysdata;

return sd->vmd_domain;
#else
return false;
#endif
}

/* Can be used to override the logic in pci_scan_bus for skipping
already-configured bus numbers - to be used for buggy BIOSes
or architectures with incomplete PCI setup by the loader */
Expand Down
7 changes: 7 additions & 0 deletions arch/x86/pci/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,12 @@ static void set_dma_domain_ops(struct pci_dev *pdev)
static void set_dma_domain_ops(struct pci_dev *pdev) {}
#endif

static void set_dev_domain_options(struct pci_dev *pdev)
{
if (is_vmd(pdev->bus))
pdev->hotplug_user_indicators = 1;
}

int pcibios_add_device(struct pci_dev *dev)
{
struct setup_data *data;
Expand Down Expand Up @@ -707,6 +713,7 @@ int pcibios_add_device(struct pci_dev *dev)
iounmap(data);
}
set_dma_domain_ops(dev);
set_dev_domain_options(dev);
return 0;
}

Expand Down
1 change: 1 addition & 0 deletions arch/x86/pci/vmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -596,6 +596,7 @@ static int vmd_enable_domain(struct vmd_dev *vmd)
.parent = res,
};

sd->vmd_domain = true;
sd->domain = vmd_find_free_domain();
if (sd->domain < 0)
return sd->domain;
Expand Down
3 changes: 3 additions & 0 deletions drivers/pci/hotplug/pciehp.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,9 @@ bool pciehp_check_link_active(struct controller *ctrl);
void pciehp_release_ctrl(struct controller *ctrl);
int pciehp_reset_slot(struct slot *slot, int probe);

int pciehp_set_raw_indicator_status(struct hotplug_slot *h_slot, u8 status);
int pciehp_get_raw_indicator_status(struct hotplug_slot *h_slot, u8 *status);

static inline const char *slot_name(struct slot *slot)
{
return hotplug_slot_name(slot->hotplug_slot);
Expand Down
3 changes: 3 additions & 0 deletions drivers/pci/hotplug/pciehp_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ static int init_slot(struct controller *ctrl)
if (ATTN_LED(ctrl)) {
ops->get_attention_status = get_attention_status;
ops->set_attention_status = set_attention_status;
} else if (ctrl->pcie->port->hotplug_user_indicators) {
ops->get_attention_status = pciehp_get_raw_indicator_status;
ops->set_attention_status = pciehp_set_raw_indicator_status;
}

/* register this slot with the hotplug pci core */
Expand Down
84 changes: 31 additions & 53 deletions drivers/pci/hotplug/pciehp_ctrl.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ static int board_added(struct slot *p_slot)

/* Check for a power fault */
if (ctrl->power_fault_detected || pciehp_query_power_fault(p_slot)) {
ctrl_err(ctrl, "Power fault on slot %s\n", slot_name(p_slot));
ctrl_err(ctrl, "Slot(%s): Power fault\n", slot_name(p_slot));
retval = -EIO;
goto err_exit;
}
Expand All @@ -120,6 +120,7 @@ static int board_added(struct slot *p_slot)
}

pciehp_green_led_on(p_slot);
pciehp_set_attention_status(p_slot, 0);
return 0;

err_exit:
Expand Down Expand Up @@ -253,11 +254,11 @@ static void handle_button_press_event(struct slot *p_slot)
pciehp_get_power_status(p_slot, &getstatus);
if (getstatus) {
p_slot->state = BLINKINGOFF_STATE;
ctrl_info(ctrl, "PCI slot #%s - powering off due to button press\n",
ctrl_info(ctrl, "Slot(%s): Powering off due to button press\n",
slot_name(p_slot));
} else {
p_slot->state = BLINKINGON_STATE;
ctrl_info(ctrl, "PCI slot #%s - powering on due to button press\n",
ctrl_info(ctrl, "Slot(%s) Powering on due to button press\n",
slot_name(p_slot));
}
/* blink green LED and turn off amber */
Expand All @@ -272,14 +273,14 @@ static void handle_button_press_event(struct slot *p_slot)
* press the attention again before the 5 sec. limit
* expires to cancel hot-add or hot-remove
*/
ctrl_info(ctrl, "Button cancel on Slot(%s)\n", slot_name(p_slot));
ctrl_info(ctrl, "Slot(%s): Button cancel\n", slot_name(p_slot));
cancel_delayed_work(&p_slot->work);
if (p_slot->state == BLINKINGOFF_STATE)
pciehp_green_led_on(p_slot);
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",
ctrl_info(ctrl, "Slot(%s): Action canceled due to button press\n",
slot_name(p_slot));
p_slot->state = STATIC_STATE;
break;
Expand All @@ -290,28 +291,16 @@ static void handle_button_press_event(struct slot *p_slot)
* this means that the previous attention button action
* to hot-add or hot-remove is undergoing
*/
ctrl_info(ctrl, "Button ignore on Slot(%s)\n", slot_name(p_slot));
ctrl_info(ctrl, "Slot(%s): Button ignored\n",
slot_name(p_slot));
break;
default:
ctrl_warn(ctrl, "ignoring invalid state %#x\n", p_slot->state);
ctrl_err(ctrl, "Slot(%s): Ignoring invalid state %#x\n",
slot_name(p_slot), p_slot->state);
break;
}
}

/*
* Note: This function must be called with slot->lock held
*/
static void handle_surprise_event(struct slot *p_slot)
{
u8 getstatus;

pciehp_get_adapter_status(p_slot, &getstatus);
if (!getstatus)
pciehp_queue_power_work(p_slot, DISABLE_REQ);
else
pciehp_queue_power_work(p_slot, ENABLE_REQ);
}

/*
* Note: This function must be called with slot->lock held
*/
Expand All @@ -330,31 +319,27 @@ static void handle_link_event(struct slot *p_slot, u32 event)
break;
case POWERON_STATE:
if (event == INT_LINK_UP) {
ctrl_info(ctrl,
"Link Up event ignored on slot(%s): already powering on\n",
ctrl_info(ctrl, "Slot(%s): Link Up event ignored; already powering on\n",
slot_name(p_slot));
} else {
ctrl_info(ctrl,
"Link Down event queued on slot(%s): currently getting powered on\n",
ctrl_info(ctrl, "Slot(%s): Link Down event queued; currently getting powered on\n",
slot_name(p_slot));
pciehp_queue_power_work(p_slot, DISABLE_REQ);
}
break;
case POWEROFF_STATE:
if (event == INT_LINK_UP) {
ctrl_info(ctrl,
"Link Up event queued on slot(%s): currently getting powered off\n",
ctrl_info(ctrl, "Slot(%s): Link Up event queued; currently getting powered off\n",
slot_name(p_slot));
pciehp_queue_power_work(p_slot, ENABLE_REQ);
} else {
ctrl_info(ctrl,
"Link Down event ignored on slot(%s): already powering off\n",
ctrl_info(ctrl, "Slot(%s): Link Down event ignored; already powering off\n",
slot_name(p_slot));
}
break;
default:
ctrl_err(ctrl, "ignoring invalid state %#x on slot(%s)\n",
p_slot->state, slot_name(p_slot));
ctrl_err(ctrl, "Slot(%s): Ignoring invalid state %#x\n",
slot_name(p_slot), p_slot->state);
break;
}
}
Expand All @@ -377,14 +362,14 @@ static void interrupt_event_handler(struct work_struct *work)
pciehp_green_led_off(p_slot);
break;
case INT_PRESENCE_ON:
handle_surprise_event(p_slot);
pciehp_queue_power_work(p_slot, ENABLE_REQ);
break;
case INT_PRESENCE_OFF:
/*
* Regardless of surprise capability, we need to
* definitely remove a card that has been pulled out!
*/
handle_surprise_event(p_slot);
pciehp_queue_power_work(p_slot, DISABLE_REQ);
break;
case INT_LINK_UP:
case INT_LINK_DOWN:
Expand All @@ -404,18 +389,17 @@ static void interrupt_event_handler(struct work_struct *work)
int pciehp_enable_slot(struct slot *p_slot)
{
u8 getstatus = 0;
int rc;
struct controller *ctrl = 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));
ctrl_info(ctrl, "Slot(%s): No adapter\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",
ctrl_info(ctrl, "Slot(%s): Latch open\n",
slot_name(p_slot));
return -ENODEV;
}
Expand All @@ -424,19 +408,13 @@ int pciehp_enable_slot(struct slot *p_slot)
if (POWER_CTRL(p_slot->ctrl)) {
pciehp_get_power_status(p_slot, &getstatus);
if (getstatus) {
ctrl_info(ctrl, "Already enabled on slot(%s)\n",
ctrl_info(ctrl, "Slot(%s): Already enabled\n",
slot_name(p_slot));
return -EINVAL;
}
}

pciehp_get_latch_status(p_slot, &getstatus);

rc = board_added(p_slot);
if (rc)
pciehp_get_latch_status(p_slot, &getstatus);

return rc;
return board_added(p_slot);
}

/*
Expand All @@ -453,7 +431,7 @@ int pciehp_disable_slot(struct slot *p_slot)
if (POWER_CTRL(p_slot->ctrl)) {
pciehp_get_power_status(p_slot, &getstatus);
if (!getstatus) {
ctrl_info(ctrl, "Already disabled on slot(%s)\n",
ctrl_info(ctrl, "Slot(%s): Already disabled\n",
slot_name(p_slot));
return -EINVAL;
}
Expand Down Expand Up @@ -481,17 +459,17 @@ int pciehp_sysfs_enable_slot(struct slot *p_slot)
p_slot->state = STATIC_STATE;
break;
case POWERON_STATE:
ctrl_info(ctrl, "Slot %s is already in powering on state\n",
ctrl_info(ctrl, "Slot(%s): Already in powering on state\n",
slot_name(p_slot));
break;
case BLINKINGOFF_STATE:
case POWEROFF_STATE:
ctrl_info(ctrl, "Already enabled on slot %s\n",
ctrl_info(ctrl, "Slot(%s): Already enabled\n",
slot_name(p_slot));
break;
default:
ctrl_err(ctrl, "invalid state %#x on slot %s\n",
p_slot->state, slot_name(p_slot));
ctrl_err(ctrl, "Slot(%s): Invalid state %#x\n",
slot_name(p_slot), p_slot->state);
break;
}
mutex_unlock(&p_slot->lock);
Expand All @@ -518,17 +496,17 @@ int pciehp_sysfs_disable_slot(struct slot *p_slot)
p_slot->state = STATIC_STATE;
break;
case POWEROFF_STATE:
ctrl_info(ctrl, "Slot %s is already in powering off state\n",
ctrl_info(ctrl, "Slot(%s): Already in powering off state\n",
slot_name(p_slot));
break;
case BLINKINGON_STATE:
case POWERON_STATE:
ctrl_info(ctrl, "Already disabled on slot %s\n",
ctrl_info(ctrl, "Slot(%s): Already disabled\n",
slot_name(p_slot));
break;
default:
ctrl_err(ctrl, "invalid state %#x on slot %s\n",
p_slot->state, slot_name(p_slot));
ctrl_err(ctrl, "Slot(%s): Invalid state %#x\n",
slot_name(p_slot), p_slot->state);
break;
}
mutex_unlock(&p_slot->lock);
Expand Down
Loading

0 comments on commit 64ea3b9

Please sign in to comment.