GNU Linux-libre 5.10.215-gnu1
[releases.git] / drivers / pci / hotplug / pciehp_ctrl.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * PCI Express Hot Plug Controller Driver
4  *
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
9  *
10  * All rights reserved.
11  *
12  * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com>
13  *
14  */
15
16 #define dev_fmt(fmt) "pciehp: " fmt
17
18 #include <linux/kernel.h>
19 #include <linux/types.h>
20 #include <linux/pm_runtime.h>
21 #include <linux/pci.h>
22 #include "pciehp.h"
23
24 /* The following routines constitute the bulk of the
25    hotplug controller logic
26  */
27
28 #define SAFE_REMOVAL     true
29 #define SURPRISE_REMOVAL false
30
31 static void set_slot_off(struct controller *ctrl)
32 {
33         /*
34          * Turn off slot, turn on attention indicator, turn off power
35          * indicator
36          */
37         if (POWER_CTRL(ctrl)) {
38                 pciehp_power_off_slot(ctrl);
39
40                 /*
41                  * After turning power off, we must wait for at least 1 second
42                  * before taking any action that relies on power having been
43                  * removed from the slot/adapter.
44                  */
45                 msleep(1000);
46         }
47
48         pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
49                               PCI_EXP_SLTCTL_ATTN_IND_ON);
50 }
51
52 /**
53  * board_added - Called after a board has been added to the system.
54  * @ctrl: PCIe hotplug controller where board is added
55  *
56  * Turns power on for the board.
57  * Configures board.
58  */
59 static int board_added(struct controller *ctrl)
60 {
61         int retval = 0;
62         struct pci_bus *parent = ctrl->pcie->port->subordinate;
63
64         if (POWER_CTRL(ctrl)) {
65                 /* Power on slot */
66                 retval = pciehp_power_on_slot(ctrl);
67                 if (retval)
68                         return retval;
69         }
70
71         pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_BLINK,
72                               INDICATOR_NOOP);
73
74         /* Check link training status */
75         retval = pciehp_check_link_status(ctrl);
76         if (retval)
77                 goto err_exit;
78
79         /* Check for a power fault */
80         if (ctrl->power_fault_detected || pciehp_query_power_fault(ctrl)) {
81                 ctrl_err(ctrl, "Slot(%s): Power fault\n", slot_name(ctrl));
82                 retval = -EIO;
83                 goto err_exit;
84         }
85
86         retval = pciehp_configure_device(ctrl);
87         if (retval) {
88                 if (retval != -EEXIST) {
89                         ctrl_err(ctrl, "Cannot add device at %04x:%02x:00\n",
90                                  pci_domain_nr(parent), parent->number);
91                         goto err_exit;
92                 }
93         }
94
95         pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_ON,
96                               PCI_EXP_SLTCTL_ATTN_IND_OFF);
97         return 0;
98
99 err_exit:
100         set_slot_off(ctrl);
101         return retval;
102 }
103
104 /**
105  * remove_board - Turn off slot and Power Indicator
106  * @ctrl: PCIe hotplug controller where board is being removed
107  * @safe_removal: whether the board is safely removed (versus surprise removed)
108  */
109 static void remove_board(struct controller *ctrl, bool safe_removal)
110 {
111         pciehp_unconfigure_device(ctrl, safe_removal);
112
113         if (POWER_CTRL(ctrl)) {
114                 pciehp_power_off_slot(ctrl);
115
116                 /*
117                  * After turning power off, we must wait for at least 1 second
118                  * before taking any action that relies on power having been
119                  * removed from the slot/adapter.
120                  */
121                 msleep(1000);
122
123                 /* Ignore link or presence changes caused by power off */
124                 atomic_and(~(PCI_EXP_SLTSTA_DLLSC | PCI_EXP_SLTSTA_PDC),
125                            &ctrl->pending_events);
126         }
127
128         pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
129                               INDICATOR_NOOP);
130 }
131
132 static int pciehp_enable_slot(struct controller *ctrl);
133 static int pciehp_disable_slot(struct controller *ctrl, bool safe_removal);
134
135 void pciehp_request(struct controller *ctrl, int action)
136 {
137         atomic_or(action, &ctrl->pending_events);
138         if (!pciehp_poll_mode)
139                 irq_wake_thread(ctrl->pcie->irq, ctrl);
140 }
141
142 void pciehp_queue_pushbutton_work(struct work_struct *work)
143 {
144         struct controller *ctrl = container_of(work, struct controller,
145                                                button_work.work);
146
147         mutex_lock(&ctrl->state_lock);
148         switch (ctrl->state) {
149         case BLINKINGOFF_STATE:
150                 pciehp_request(ctrl, DISABLE_SLOT);
151                 break;
152         case BLINKINGON_STATE:
153                 pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC);
154                 break;
155         default:
156                 break;
157         }
158         mutex_unlock(&ctrl->state_lock);
159 }
160
161 void pciehp_handle_button_press(struct controller *ctrl)
162 {
163         mutex_lock(&ctrl->state_lock);
164         switch (ctrl->state) {
165         case OFF_STATE:
166         case ON_STATE:
167                 if (ctrl->state == ON_STATE) {
168                         ctrl->state = BLINKINGOFF_STATE;
169                         ctrl_info(ctrl, "Slot(%s): Powering off due to button press\n",
170                                   slot_name(ctrl));
171                 } else {
172                         ctrl->state = BLINKINGON_STATE;
173                         ctrl_info(ctrl, "Slot(%s) Powering on due to button press\n",
174                                   slot_name(ctrl));
175                 }
176                 /* blink power indicator and turn off attention */
177                 pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_BLINK,
178                                       PCI_EXP_SLTCTL_ATTN_IND_OFF);
179                 schedule_delayed_work(&ctrl->button_work, 5 * HZ);
180                 break;
181         case BLINKINGOFF_STATE:
182         case BLINKINGON_STATE:
183                 /*
184                  * Cancel if we are still blinking; this means that we
185                  * press the attention again before the 5 sec. limit
186                  * expires to cancel hot-add or hot-remove
187                  */
188                 ctrl_info(ctrl, "Slot(%s): Button cancel\n", slot_name(ctrl));
189                 cancel_delayed_work(&ctrl->button_work);
190                 if (ctrl->state == BLINKINGOFF_STATE) {
191                         ctrl->state = ON_STATE;
192                         pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_ON,
193                                               PCI_EXP_SLTCTL_ATTN_IND_OFF);
194                 } else {
195                         ctrl->state = OFF_STATE;
196                         pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
197                                               PCI_EXP_SLTCTL_ATTN_IND_OFF);
198                 }
199                 ctrl_info(ctrl, "Slot(%s): Action canceled due to button press\n",
200                           slot_name(ctrl));
201                 break;
202         default:
203                 ctrl_err(ctrl, "Slot(%s): Ignoring invalid state %#x\n",
204                          slot_name(ctrl), ctrl->state);
205                 break;
206         }
207         mutex_unlock(&ctrl->state_lock);
208 }
209
210 void pciehp_handle_disable_request(struct controller *ctrl)
211 {
212         mutex_lock(&ctrl->state_lock);
213         switch (ctrl->state) {
214         case BLINKINGON_STATE:
215         case BLINKINGOFF_STATE:
216                 cancel_delayed_work(&ctrl->button_work);
217                 break;
218         }
219         ctrl->state = POWEROFF_STATE;
220         mutex_unlock(&ctrl->state_lock);
221
222         ctrl->request_result = pciehp_disable_slot(ctrl, SAFE_REMOVAL);
223 }
224
225 void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events)
226 {
227         int present, link_active;
228
229         /*
230          * If the slot is on and presence or link has changed, turn it off.
231          * Even if it's occupied again, we cannot assume the card is the same.
232          */
233         mutex_lock(&ctrl->state_lock);
234         switch (ctrl->state) {
235         case BLINKINGOFF_STATE:
236                 cancel_delayed_work(&ctrl->button_work);
237                 fallthrough;
238         case ON_STATE:
239                 ctrl->state = POWEROFF_STATE;
240                 mutex_unlock(&ctrl->state_lock);
241                 if (events & PCI_EXP_SLTSTA_DLLSC)
242                         ctrl_info(ctrl, "Slot(%s): Link Down\n",
243                                   slot_name(ctrl));
244                 if (events & PCI_EXP_SLTSTA_PDC)
245                         ctrl_info(ctrl, "Slot(%s): Card not present\n",
246                                   slot_name(ctrl));
247                 pciehp_disable_slot(ctrl, SURPRISE_REMOVAL);
248                 break;
249         default:
250                 mutex_unlock(&ctrl->state_lock);
251                 break;
252         }
253
254         /* Turn the slot on if it's occupied or link is up */
255         mutex_lock(&ctrl->state_lock);
256         present = pciehp_card_present(ctrl);
257         link_active = pciehp_check_link_active(ctrl);
258         if (present <= 0 && link_active <= 0) {
259                 if (ctrl->state == BLINKINGON_STATE) {
260                         ctrl->state = OFF_STATE;
261                         cancel_delayed_work(&ctrl->button_work);
262                         pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
263                                               INDICATOR_NOOP);
264                         ctrl_info(ctrl, "Slot(%s): Card not present\n",
265                                   slot_name(ctrl));
266                 }
267                 mutex_unlock(&ctrl->state_lock);
268                 return;
269         }
270
271         switch (ctrl->state) {
272         case BLINKINGON_STATE:
273                 cancel_delayed_work(&ctrl->button_work);
274                 fallthrough;
275         case OFF_STATE:
276                 ctrl->state = POWERON_STATE;
277                 mutex_unlock(&ctrl->state_lock);
278                 if (present)
279                         ctrl_info(ctrl, "Slot(%s): Card present\n",
280                                   slot_name(ctrl));
281                 if (link_active)
282                         ctrl_info(ctrl, "Slot(%s): Link Up\n",
283                                   slot_name(ctrl));
284                 ctrl->request_result = pciehp_enable_slot(ctrl);
285                 break;
286         default:
287                 mutex_unlock(&ctrl->state_lock);
288                 break;
289         }
290 }
291
292 static int __pciehp_enable_slot(struct controller *ctrl)
293 {
294         u8 getstatus = 0;
295
296         if (MRL_SENS(ctrl)) {
297                 pciehp_get_latch_status(ctrl, &getstatus);
298                 if (getstatus) {
299                         ctrl_info(ctrl, "Slot(%s): Latch open\n",
300                                   slot_name(ctrl));
301                         return -ENODEV;
302                 }
303         }
304
305         if (POWER_CTRL(ctrl)) {
306                 pciehp_get_power_status(ctrl, &getstatus);
307                 if (getstatus) {
308                         ctrl_info(ctrl, "Slot(%s): Already enabled\n",
309                                   slot_name(ctrl));
310                         return 0;
311                 }
312         }
313
314         return board_added(ctrl);
315 }
316
317 static int pciehp_enable_slot(struct controller *ctrl)
318 {
319         int ret;
320
321         pm_runtime_get_sync(&ctrl->pcie->port->dev);
322         ret = __pciehp_enable_slot(ctrl);
323         if (ret && ATTN_BUTTN(ctrl))
324                 /* may be blinking */
325                 pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
326                                       INDICATOR_NOOP);
327         pm_runtime_put(&ctrl->pcie->port->dev);
328
329         mutex_lock(&ctrl->state_lock);
330         ctrl->state = ret ? OFF_STATE : ON_STATE;
331         mutex_unlock(&ctrl->state_lock);
332
333         return ret;
334 }
335
336 static int __pciehp_disable_slot(struct controller *ctrl, bool safe_removal)
337 {
338         u8 getstatus = 0;
339
340         if (POWER_CTRL(ctrl)) {
341                 pciehp_get_power_status(ctrl, &getstatus);
342                 if (!getstatus) {
343                         ctrl_info(ctrl, "Slot(%s): Already disabled\n",
344                                   slot_name(ctrl));
345                         return -EINVAL;
346                 }
347         }
348
349         remove_board(ctrl, safe_removal);
350         return 0;
351 }
352
353 static int pciehp_disable_slot(struct controller *ctrl, bool safe_removal)
354 {
355         int ret;
356
357         pm_runtime_get_sync(&ctrl->pcie->port->dev);
358         ret = __pciehp_disable_slot(ctrl, safe_removal);
359         pm_runtime_put(&ctrl->pcie->port->dev);
360
361         mutex_lock(&ctrl->state_lock);
362         ctrl->state = OFF_STATE;
363         mutex_unlock(&ctrl->state_lock);
364
365         return ret;
366 }
367
368 int pciehp_sysfs_enable_slot(struct hotplug_slot *hotplug_slot)
369 {
370         struct controller *ctrl = to_ctrl(hotplug_slot);
371
372         mutex_lock(&ctrl->state_lock);
373         switch (ctrl->state) {
374         case BLINKINGON_STATE:
375         case OFF_STATE:
376                 mutex_unlock(&ctrl->state_lock);
377                 /*
378                  * The IRQ thread becomes a no-op if the user pulls out the
379                  * card before the thread wakes up, so initialize to -ENODEV.
380                  */
381                 ctrl->request_result = -ENODEV;
382                 pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC);
383                 wait_event(ctrl->requester,
384                            !atomic_read(&ctrl->pending_events) &&
385                            !ctrl->ist_running);
386                 return ctrl->request_result;
387         case POWERON_STATE:
388                 ctrl_info(ctrl, "Slot(%s): Already in powering on state\n",
389                           slot_name(ctrl));
390                 break;
391         case BLINKINGOFF_STATE:
392         case ON_STATE:
393         case POWEROFF_STATE:
394                 ctrl_info(ctrl, "Slot(%s): Already enabled\n",
395                           slot_name(ctrl));
396                 break;
397         default:
398                 ctrl_err(ctrl, "Slot(%s): Invalid state %#x\n",
399                          slot_name(ctrl), ctrl->state);
400                 break;
401         }
402         mutex_unlock(&ctrl->state_lock);
403
404         return -ENODEV;
405 }
406
407 int pciehp_sysfs_disable_slot(struct hotplug_slot *hotplug_slot)
408 {
409         struct controller *ctrl = to_ctrl(hotplug_slot);
410
411         mutex_lock(&ctrl->state_lock);
412         switch (ctrl->state) {
413         case BLINKINGOFF_STATE:
414         case ON_STATE:
415                 mutex_unlock(&ctrl->state_lock);
416                 pciehp_request(ctrl, DISABLE_SLOT);
417                 wait_event(ctrl->requester,
418                            !atomic_read(&ctrl->pending_events) &&
419                            !ctrl->ist_running);
420                 return ctrl->request_result;
421         case POWEROFF_STATE:
422                 ctrl_info(ctrl, "Slot(%s): Already in powering off state\n",
423                           slot_name(ctrl));
424                 break;
425         case BLINKINGON_STATE:
426         case OFF_STATE:
427         case POWERON_STATE:
428                 ctrl_info(ctrl, "Slot(%s): Already disabled\n",
429                           slot_name(ctrl));
430                 break;
431         default:
432                 ctrl_err(ctrl, "Slot(%s): Invalid state %#x\n",
433                          slot_name(ctrl), ctrl->state);
434                 break;
435         }
436         mutex_unlock(&ctrl->state_lock);
437
438         return -ENODEV;
439 }