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