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