GNU Linux-libre 6.7.9-gnu
[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): Button press: will power off in 5 sec\n",
170                                   slot_name(ctrl));
171                 } else {
172                         ctrl->state = BLINKINGON_STATE;
173                         ctrl_info(ctrl, "Slot(%s): Button press: will power on in 5 sec\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                 cancel_delayed_work(&ctrl->button_work);
189                 if (ctrl->state == BLINKINGOFF_STATE) {
190                         ctrl->state = ON_STATE;
191                         pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_ON,
192                                               PCI_EXP_SLTCTL_ATTN_IND_OFF);
193                         ctrl_info(ctrl, "Slot(%s): Button press: canceling request to power off\n",
194                                   slot_name(ctrl));
195                 } else {
196                         ctrl->state = OFF_STATE;
197                         pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
198                                               PCI_EXP_SLTCTL_ATTN_IND_OFF);
199                         ctrl_info(ctrl, "Slot(%s): Button press: canceling request to power on\n",
200                                   slot_name(ctrl));
201                 }
202                 break;
203         default:
204                 ctrl_err(ctrl, "Slot(%s): Button press: ignoring invalid state %#x\n",
205                          slot_name(ctrl), ctrl->state);
206                 break;
207         }
208         mutex_unlock(&ctrl->state_lock);
209 }
210
211 void pciehp_handle_disable_request(struct controller *ctrl)
212 {
213         mutex_lock(&ctrl->state_lock);
214         switch (ctrl->state) {
215         case BLINKINGON_STATE:
216         case BLINKINGOFF_STATE:
217                 cancel_delayed_work(&ctrl->button_work);
218                 break;
219         }
220         ctrl->state = POWEROFF_STATE;
221         mutex_unlock(&ctrl->state_lock);
222
223         ctrl->request_result = pciehp_disable_slot(ctrl, SAFE_REMOVAL);
224 }
225
226 void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events)
227 {
228         int present, link_active;
229
230         /*
231          * If the slot is on and presence or link has changed, turn it off.
232          * Even if it's occupied again, we cannot assume the card is the same.
233          */
234         mutex_lock(&ctrl->state_lock);
235         switch (ctrl->state) {
236         case BLINKINGOFF_STATE:
237                 cancel_delayed_work(&ctrl->button_work);
238                 fallthrough;
239         case ON_STATE:
240                 ctrl->state = POWEROFF_STATE;
241                 mutex_unlock(&ctrl->state_lock);
242                 if (events & PCI_EXP_SLTSTA_DLLSC)
243                         ctrl_info(ctrl, "Slot(%s): Link Down\n",
244                                   slot_name(ctrl));
245                 if (events & PCI_EXP_SLTSTA_PDC)
246                         ctrl_info(ctrl, "Slot(%s): Card not present\n",
247                                   slot_name(ctrl));
248                 pciehp_disable_slot(ctrl, SURPRISE_REMOVAL);
249                 break;
250         default:
251                 mutex_unlock(&ctrl->state_lock);
252                 break;
253         }
254
255         /* Turn the slot on if it's occupied or link is up */
256         mutex_lock(&ctrl->state_lock);
257         present = pciehp_card_present(ctrl);
258         link_active = pciehp_check_link_active(ctrl);
259         if (present <= 0 && link_active <= 0) {
260                 if (ctrl->state == BLINKINGON_STATE) {
261                         ctrl->state = OFF_STATE;
262                         cancel_delayed_work(&ctrl->button_work);
263                         pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
264                                               INDICATOR_NOOP);
265                         ctrl_info(ctrl, "Slot(%s): Card not present\n",
266                                   slot_name(ctrl));
267                 }
268                 mutex_unlock(&ctrl->state_lock);
269                 return;
270         }
271
272         switch (ctrl->state) {
273         case BLINKINGON_STATE:
274                 cancel_delayed_work(&ctrl->button_work);
275                 fallthrough;
276         case OFF_STATE:
277                 ctrl->state = POWERON_STATE;
278                 mutex_unlock(&ctrl->state_lock);
279                 if (present)
280                         ctrl_info(ctrl, "Slot(%s): Card present\n",
281                                   slot_name(ctrl));
282                 if (link_active)
283                         ctrl_info(ctrl, "Slot(%s): Link Up\n",
284                                   slot_name(ctrl));
285                 ctrl->request_result = pciehp_enable_slot(ctrl);
286                 break;
287         default:
288                 mutex_unlock(&ctrl->state_lock);
289                 break;
290         }
291 }
292
293 static int __pciehp_enable_slot(struct controller *ctrl)
294 {
295         u8 getstatus = 0;
296
297         if (MRL_SENS(ctrl)) {
298                 pciehp_get_latch_status(ctrl, &getstatus);
299                 if (getstatus) {
300                         ctrl_info(ctrl, "Slot(%s): Latch open\n",
301                                   slot_name(ctrl));
302                         return -ENODEV;
303                 }
304         }
305
306         if (POWER_CTRL(ctrl)) {
307                 pciehp_get_power_status(ctrl, &getstatus);
308                 if (getstatus) {
309                         ctrl_info(ctrl, "Slot(%s): Already enabled\n",
310                                   slot_name(ctrl));
311                         return 0;
312                 }
313         }
314
315         return board_added(ctrl);
316 }
317
318 static int pciehp_enable_slot(struct controller *ctrl)
319 {
320         int ret;
321
322         pm_runtime_get_sync(&ctrl->pcie->port->dev);
323         ret = __pciehp_enable_slot(ctrl);
324         if (ret && ATTN_BUTTN(ctrl))
325                 /* may be blinking */
326                 pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
327                                       INDICATOR_NOOP);
328         pm_runtime_put(&ctrl->pcie->port->dev);
329
330         mutex_lock(&ctrl->state_lock);
331         ctrl->state = ret ? OFF_STATE : ON_STATE;
332         mutex_unlock(&ctrl->state_lock);
333
334         return ret;
335 }
336
337 static int __pciehp_disable_slot(struct controller *ctrl, bool safe_removal)
338 {
339         u8 getstatus = 0;
340
341         if (POWER_CTRL(ctrl)) {
342                 pciehp_get_power_status(ctrl, &getstatus);
343                 if (!getstatus) {
344                         ctrl_info(ctrl, "Slot(%s): Already disabled\n",
345                                   slot_name(ctrl));
346                         return -EINVAL;
347                 }
348         }
349
350         remove_board(ctrl, safe_removal);
351         return 0;
352 }
353
354 static int pciehp_disable_slot(struct controller *ctrl, bool safe_removal)
355 {
356         int ret;
357
358         pm_runtime_get_sync(&ctrl->pcie->port->dev);
359         ret = __pciehp_disable_slot(ctrl, safe_removal);
360         pm_runtime_put(&ctrl->pcie->port->dev);
361
362         mutex_lock(&ctrl->state_lock);
363         ctrl->state = OFF_STATE;
364         mutex_unlock(&ctrl->state_lock);
365
366         return ret;
367 }
368
369 int pciehp_sysfs_enable_slot(struct hotplug_slot *hotplug_slot)
370 {
371         struct controller *ctrl = to_ctrl(hotplug_slot);
372
373         mutex_lock(&ctrl->state_lock);
374         switch (ctrl->state) {
375         case BLINKINGON_STATE:
376         case OFF_STATE:
377                 mutex_unlock(&ctrl->state_lock);
378                 /*
379                  * The IRQ thread becomes a no-op if the user pulls out the
380                  * card before the thread wakes up, so initialize to -ENODEV.
381                  */
382                 ctrl->request_result = -ENODEV;
383                 pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC);
384                 wait_event(ctrl->requester,
385                            !atomic_read(&ctrl->pending_events) &&
386                            !ctrl->ist_running);
387                 return ctrl->request_result;
388         case POWERON_STATE:
389                 ctrl_info(ctrl, "Slot(%s): Already in powering on state\n",
390                           slot_name(ctrl));
391                 break;
392         case BLINKINGOFF_STATE:
393         case ON_STATE:
394         case POWEROFF_STATE:
395                 ctrl_info(ctrl, "Slot(%s): Already enabled\n",
396                           slot_name(ctrl));
397                 break;
398         default:
399                 ctrl_err(ctrl, "Slot(%s): Invalid state %#x\n",
400                          slot_name(ctrl), ctrl->state);
401                 break;
402         }
403         mutex_unlock(&ctrl->state_lock);
404
405         return -ENODEV;
406 }
407
408 int pciehp_sysfs_disable_slot(struct hotplug_slot *hotplug_slot)
409 {
410         struct controller *ctrl = to_ctrl(hotplug_slot);
411
412         mutex_lock(&ctrl->state_lock);
413         switch (ctrl->state) {
414         case BLINKINGOFF_STATE:
415         case ON_STATE:
416                 mutex_unlock(&ctrl->state_lock);
417                 pciehp_request(ctrl, DISABLE_SLOT);
418                 wait_event(ctrl->requester,
419                            !atomic_read(&ctrl->pending_events) &&
420                            !ctrl->ist_running);
421                 return ctrl->request_result;
422         case POWEROFF_STATE:
423                 ctrl_info(ctrl, "Slot(%s): Already in powering off state\n",
424                           slot_name(ctrl));
425                 break;
426         case BLINKINGON_STATE:
427         case OFF_STATE:
428         case POWERON_STATE:
429                 ctrl_info(ctrl, "Slot(%s): Already disabled\n",
430                           slot_name(ctrl));
431                 break;
432         default:
433                 ctrl_err(ctrl, "Slot(%s): Invalid state %#x\n",
434                          slot_name(ctrl), ctrl->state);
435                 break;
436         }
437         mutex_unlock(&ctrl->state_lock);
438
439         return -ENODEV;
440 }