1 // SPDX-License-Identifier: GPL-2.0+
3 * PCI Express Hot Plug Controller Driver
5 * Copyright (C) 1995,2001 Compaq Computer Corporation
6 * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
7 * Copyright (C) 2001 IBM Corp.
8 * Copyright (C) 2003-2004 Intel Corporation
10 * All rights reserved.
12 * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com>
16 #include <linux/kernel.h>
17 #include <linux/types.h>
18 #include <linux/pm_runtime.h>
19 #include <linux/pci.h>
22 /* The following routines constitute the bulk of the
23 hotplug controller logic
26 #define SAFE_REMOVAL true
27 #define SURPRISE_REMOVAL false
29 static void set_slot_off(struct controller *ctrl)
31 /* turn off slot, turn on Amber LED, turn off Green LED if supported*/
32 if (POWER_CTRL(ctrl)) {
33 pciehp_power_off_slot(ctrl);
36 * After turning power off, we must wait for at least 1 second
37 * before taking any action that relies on power having been
38 * removed from the slot/adapter.
43 pciehp_green_led_off(ctrl);
44 pciehp_set_attention_status(ctrl, 1);
48 * board_added - Called after a board has been added to the system.
49 * @ctrl: PCIe hotplug controller where board is added
51 * Turns power on for the board.
54 static int board_added(struct controller *ctrl)
57 struct pci_bus *parent = ctrl->pcie->port->subordinate;
59 if (POWER_CTRL(ctrl)) {
61 retval = pciehp_power_on_slot(ctrl);
66 pciehp_green_led_blink(ctrl);
68 /* Check link training status */
69 retval = pciehp_check_link_status(ctrl);
71 ctrl_err(ctrl, "Failed to check link status\n");
75 /* Check for a power fault */
76 if (ctrl->power_fault_detected || pciehp_query_power_fault(ctrl)) {
77 ctrl_err(ctrl, "Slot(%s): Power fault\n", slot_name(ctrl));
82 retval = pciehp_configure_device(ctrl);
84 if (retval != -EEXIST) {
85 ctrl_err(ctrl, "Cannot add device at %04x:%02x:00\n",
86 pci_domain_nr(parent), parent->number);
91 pciehp_green_led_on(ctrl);
92 pciehp_set_attention_status(ctrl, 0);
101 * remove_board - Turns off slot and LEDs
102 * @ctrl: PCIe hotplug controller where board is being removed
103 * @safe_removal: whether the board is safely removed (versus surprise removed)
105 static void remove_board(struct controller *ctrl, bool safe_removal)
107 pciehp_unconfigure_device(ctrl, safe_removal);
109 if (POWER_CTRL(ctrl)) {
110 pciehp_power_off_slot(ctrl);
113 * After turning power off, we must wait for at least 1 second
114 * before taking any action that relies on power having been
115 * removed from the slot/adapter.
119 /* Ignore link or presence changes caused by power off */
120 atomic_and(~(PCI_EXP_SLTSTA_DLLSC | PCI_EXP_SLTSTA_PDC),
121 &ctrl->pending_events);
124 /* turn off Green LED */
125 pciehp_green_led_off(ctrl);
128 static int pciehp_enable_slot(struct controller *ctrl);
129 static int pciehp_disable_slot(struct controller *ctrl, bool safe_removal);
131 void pciehp_request(struct controller *ctrl, int action)
133 atomic_or(action, &ctrl->pending_events);
134 if (!pciehp_poll_mode)
135 irq_wake_thread(ctrl->pcie->irq, ctrl);
138 void pciehp_queue_pushbutton_work(struct work_struct *work)
140 struct controller *ctrl = container_of(work, struct controller,
143 mutex_lock(&ctrl->state_lock);
144 switch (ctrl->state) {
145 case BLINKINGOFF_STATE:
146 pciehp_request(ctrl, DISABLE_SLOT);
148 case BLINKINGON_STATE:
149 pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC);
154 mutex_unlock(&ctrl->state_lock);
157 void pciehp_handle_button_press(struct controller *ctrl)
159 mutex_lock(&ctrl->state_lock);
160 switch (ctrl->state) {
163 if (ctrl->state == ON_STATE) {
164 ctrl->state = BLINKINGOFF_STATE;
165 ctrl_info(ctrl, "Slot(%s): Powering off due to button press\n",
168 ctrl->state = BLINKINGON_STATE;
169 ctrl_info(ctrl, "Slot(%s) Powering on due to button press\n",
172 /* blink green LED and turn off amber */
173 pciehp_green_led_blink(ctrl);
174 pciehp_set_attention_status(ctrl, 0);
175 schedule_delayed_work(&ctrl->button_work, 5 * HZ);
177 case BLINKINGOFF_STATE:
178 case BLINKINGON_STATE:
180 * Cancel if we are still blinking; this means that we
181 * press the attention again before the 5 sec. limit
182 * expires to cancel hot-add or hot-remove
184 ctrl_info(ctrl, "Slot(%s): Button cancel\n", slot_name(ctrl));
185 cancel_delayed_work(&ctrl->button_work);
186 if (ctrl->state == BLINKINGOFF_STATE) {
187 ctrl->state = ON_STATE;
188 pciehp_green_led_on(ctrl);
190 ctrl->state = OFF_STATE;
191 pciehp_green_led_off(ctrl);
193 pciehp_set_attention_status(ctrl, 0);
194 ctrl_info(ctrl, "Slot(%s): Action canceled due to button press\n",
198 ctrl_err(ctrl, "Slot(%s): Ignoring invalid state %#x\n",
199 slot_name(ctrl), ctrl->state);
202 mutex_unlock(&ctrl->state_lock);
205 void pciehp_handle_disable_request(struct controller *ctrl)
207 mutex_lock(&ctrl->state_lock);
208 switch (ctrl->state) {
209 case BLINKINGON_STATE:
210 case BLINKINGOFF_STATE:
211 cancel_delayed_work(&ctrl->button_work);
214 ctrl->state = POWEROFF_STATE;
215 mutex_unlock(&ctrl->state_lock);
217 ctrl->request_result = pciehp_disable_slot(ctrl, SAFE_REMOVAL);
220 void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events)
222 bool present, link_active;
225 * If the slot is on and presence or link has changed, turn it off.
226 * Even if it's occupied again, we cannot assume the card is the same.
228 mutex_lock(&ctrl->state_lock);
229 switch (ctrl->state) {
230 case BLINKINGOFF_STATE:
231 cancel_delayed_work(&ctrl->button_work);
234 ctrl->state = POWEROFF_STATE;
235 mutex_unlock(&ctrl->state_lock);
236 if (events & PCI_EXP_SLTSTA_DLLSC)
237 ctrl_info(ctrl, "Slot(%s): Link Down\n",
239 if (events & PCI_EXP_SLTSTA_PDC)
240 ctrl_info(ctrl, "Slot(%s): Card not present\n",
242 pciehp_disable_slot(ctrl, SURPRISE_REMOVAL);
245 mutex_unlock(&ctrl->state_lock);
249 /* Turn the slot on if it's occupied or link is up */
250 mutex_lock(&ctrl->state_lock);
251 present = pciehp_card_present(ctrl);
252 link_active = pciehp_check_link_active(ctrl);
253 if (!present && !link_active) {
254 mutex_unlock(&ctrl->state_lock);
258 switch (ctrl->state) {
259 case BLINKINGON_STATE:
260 cancel_delayed_work(&ctrl->button_work);
263 ctrl->state = POWERON_STATE;
264 mutex_unlock(&ctrl->state_lock);
266 ctrl_info(ctrl, "Slot(%s): Card present\n",
269 ctrl_info(ctrl, "Slot(%s): Link Up\n",
271 ctrl->request_result = pciehp_enable_slot(ctrl);
274 mutex_unlock(&ctrl->state_lock);
279 static int __pciehp_enable_slot(struct controller *ctrl)
283 if (MRL_SENS(ctrl)) {
284 pciehp_get_latch_status(ctrl, &getstatus);
286 ctrl_info(ctrl, "Slot(%s): Latch open\n",
292 if (POWER_CTRL(ctrl)) {
293 pciehp_get_power_status(ctrl, &getstatus);
295 ctrl_info(ctrl, "Slot(%s): Already enabled\n",
301 return board_added(ctrl);
304 static int pciehp_enable_slot(struct controller *ctrl)
308 pm_runtime_get_sync(&ctrl->pcie->port->dev);
309 ret = __pciehp_enable_slot(ctrl);
310 if (ret && ATTN_BUTTN(ctrl))
311 pciehp_green_led_off(ctrl); /* may be blinking */
312 pm_runtime_put(&ctrl->pcie->port->dev);
314 mutex_lock(&ctrl->state_lock);
315 ctrl->state = ret ? OFF_STATE : ON_STATE;
316 mutex_unlock(&ctrl->state_lock);
321 static int __pciehp_disable_slot(struct controller *ctrl, bool safe_removal)
325 if (POWER_CTRL(ctrl)) {
326 pciehp_get_power_status(ctrl, &getstatus);
328 ctrl_info(ctrl, "Slot(%s): Already disabled\n",
334 remove_board(ctrl, safe_removal);
338 static int pciehp_disable_slot(struct controller *ctrl, bool safe_removal)
342 pm_runtime_get_sync(&ctrl->pcie->port->dev);
343 ret = __pciehp_disable_slot(ctrl, safe_removal);
344 pm_runtime_put(&ctrl->pcie->port->dev);
346 mutex_lock(&ctrl->state_lock);
347 ctrl->state = OFF_STATE;
348 mutex_unlock(&ctrl->state_lock);
353 int pciehp_sysfs_enable_slot(struct hotplug_slot *hotplug_slot)
355 struct controller *ctrl = to_ctrl(hotplug_slot);
357 mutex_lock(&ctrl->state_lock);
358 switch (ctrl->state) {
359 case BLINKINGON_STATE:
361 mutex_unlock(&ctrl->state_lock);
363 * The IRQ thread becomes a no-op if the user pulls out the
364 * card before the thread wakes up, so initialize to -ENODEV.
366 ctrl->request_result = -ENODEV;
367 pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC);
368 wait_event(ctrl->requester,
369 !atomic_read(&ctrl->pending_events));
370 return ctrl->request_result;
372 ctrl_info(ctrl, "Slot(%s): Already in powering on state\n",
375 case BLINKINGOFF_STATE:
378 ctrl_info(ctrl, "Slot(%s): Already enabled\n",
382 ctrl_err(ctrl, "Slot(%s): Invalid state %#x\n",
383 slot_name(ctrl), ctrl->state);
386 mutex_unlock(&ctrl->state_lock);
391 int pciehp_sysfs_disable_slot(struct hotplug_slot *hotplug_slot)
393 struct controller *ctrl = to_ctrl(hotplug_slot);
395 mutex_lock(&ctrl->state_lock);
396 switch (ctrl->state) {
397 case BLINKINGOFF_STATE:
399 mutex_unlock(&ctrl->state_lock);
400 pciehp_request(ctrl, DISABLE_SLOT);
401 wait_event(ctrl->requester,
402 !atomic_read(&ctrl->pending_events));
403 return ctrl->request_result;
405 ctrl_info(ctrl, "Slot(%s): Already in powering off state\n",
408 case BLINKINGON_STATE:
411 ctrl_info(ctrl, "Slot(%s): Already disabled\n",
415 ctrl_err(ctrl, "Slot(%s): Invalid state %#x\n",
416 slot_name(ctrl), ctrl->state);
419 mutex_unlock(&ctrl->state_lock);