aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/drivers/pci/hotplug/pciehp.h
diff options
context:
space:
mode:
authorLukas Wunner <lukas@wunner.de>2018-07-19 17:27:46 -0500
committerBjorn Helgaas <helgaas@kernel.org>2018-07-23 17:04:15 -0500
commit32a8cef274feacd00b748a4f13b84d60aa6d82ff (patch)
treebcaabb26062fa178307276595a1c67c100f7faf9 /drivers/pci/hotplug/pciehp.h
parentPCI: pciehp: Track enable/disable status (diff)
downloadwireguard-linux-32a8cef274feacd00b748a4f13b84d60aa6d82ff.tar.xz
wireguard-linux-32a8cef274feacd00b748a4f13b84d60aa6d82ff.zip
PCI: pciehp: Enable/disable exclusively from IRQ thread
Besides the IRQ thread, there are several other places in the driver which enable or disable the slot: - pciehp_probe() enables the slot if it's occupied and the pciehp_force module parameter is used. - pciehp_resume() enables or disables the slot after system sleep. - pciehp_queue_pushbutton_work() enables or disables the slot after the 5 second delay following an Attention Button press. - pciehp_sysfs_enable_slot() and pciehp_sysfs_disable_slot() enable or disable the slot on sysfs write. This requires locking and complicates pciehp's state machine. A simplification can be achieved by enabling and disabling the slot exclusively from the IRQ thread. Amend the functions listed above to request slot enable/disablement from the IRQ thread by either synthesizing a Presence Detect Changed event or, in the case of a disable user request (via sysfs or an Attention Button press), submitting a newly introduced force disable request. The latter is needed because the slot shall be forced off despite being occupied. For this force disable request, avoid colliding with Slot Status register bits by using a bit number greater than 16. For synchronous execution of requests (on sysfs write), wait for the request to finish and retrieve the result. There can only ever be one sysfs write in flight due to the locking in kernfs_fop_write(), hence there is no risk of returning the result of a different sysfs request to user space. The POWERON_STATE and POWEROFF_STATE is now no longer entered by the above-listed functions, but solely by the IRQ thread when it begins a power transition. Afterwards, it moves to STATIC_STATE. The same applies to canceling the Attention Button work, it likewise becomes an IRQ thread only operation. An immediate consequence is that the POWERON_STATE and POWEROFF_STATE is never observed by the IRQ thread itself, only by functions called in a different context, such as pciehp_sysfs_enable_slot(). So remove handling of these states from pciehp_handle_button_press() and pciehp_handle_link_change() which are exclusively called from the IRQ thread. Signed-off-by: Lukas Wunner <lukas@wunner.de> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Diffstat (limited to 'drivers/pci/hotplug/pciehp.h')
-rw-r--r--drivers/pci/hotplug/pciehp.h18
1 files changed, 18 insertions, 0 deletions
diff --git a/drivers/pci/hotplug/pciehp.h b/drivers/pci/hotplug/pciehp.h
index 1ba335d6563a..ed42dde5f9ac 100644
--- a/drivers/pci/hotplug/pciehp.h
+++ b/drivers/pci/hotplug/pciehp.h
@@ -105,6 +105,9 @@ struct slot {
* that has not yet been cleared by the user
* @pending_events: used by the IRQ handler to save events retrieved from the
* Slot Status register for later consumption by the IRQ thread
+ * @request_result: result of last user request submitted to the IRQ thread
+ * @requester: wait queue to wake up on completion of user request,
+ * used for synchronous slot enable/disable request via sysfs
*/
struct controller {
struct mutex ctrl_lock;
@@ -120,6 +123,8 @@ struct controller {
unsigned int notification_enabled:1;
unsigned int power_fault_detected;
atomic_t pending_events;
+ int request_result;
+ wait_queue_head_t requester;
};
/**
@@ -141,6 +146,17 @@ struct controller {
#define POWEROFF_STATE 4
#define ON_STATE 5
+/**
+ * DOC: Flags to request an action from the IRQ thread
+ *
+ * These are stored together with events read from the Slot Status register,
+ * hence must be greater than its 16-bit width.
+ *
+ * %DISABLE_SLOT: Disable the slot in response to a user request via sysfs or
+ * an Attention Button press after the 5 second delay
+ */
+#define DISABLE_SLOT (1 << 16)
+
#define ATTN_BUTTN(ctrl) ((ctrl)->slot_cap & PCI_EXP_SLTCAP_ABP)
#define POWER_CTRL(ctrl) ((ctrl)->slot_cap & PCI_EXP_SLTCAP_PCP)
#define MRL_SENS(ctrl) ((ctrl)->slot_cap & PCI_EXP_SLTCAP_MRLSP)
@@ -153,7 +169,9 @@ struct controller {
int pciehp_sysfs_enable_slot(struct slot *slot);
int pciehp_sysfs_disable_slot(struct slot *slot);
+void pciehp_request(struct controller *ctrl, int action);
void pciehp_handle_button_press(struct slot *slot);
+void pciehp_handle_disable_request(struct slot *slot);
void pciehp_handle_link_change(struct slot *slot);
void pciehp_handle_presence_change(struct slot *slot);
int pciehp_configure_device(struct slot *p_slot);