]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/pci/hotplug/pciehp_ctrl.c
PM / QoS: Remove global notifiers
[linux.git] / drivers / pci / hotplug / pciehp_ctrl.c
1 /*
2  * PCI Express Hot Plug Controller Driver
3  *
4  * Copyright (C) 1995,2001 Compaq Computer Corporation
5  * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
6  * Copyright (C) 2001 IBM Corp.
7  * Copyright (C) 2003-2004 Intel Corporation
8  *
9  * All rights reserved.
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or (at
14  * your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful, but
17  * WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
19  * NON INFRINGEMENT.  See the GNU General Public License for more
20  * details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25  *
26  * Send feedback to <greg@kroah.com>, <kristen.c.accardi@intel.com>
27  *
28  */
29
30 #include <linux/module.h>
31 #include <linux/kernel.h>
32 #include <linux/types.h>
33 #include <linux/slab.h>
34 #include <linux/pm_runtime.h>
35 #include <linux/pci.h>
36 #include "../pci.h"
37 #include "pciehp.h"
38
39 static void interrupt_event_handler(struct work_struct *work);
40
41 void pciehp_queue_interrupt_event(struct slot *p_slot, u32 event_type)
42 {
43         struct event_info *info;
44
45         info = kmalloc(sizeof(*info), GFP_ATOMIC);
46         if (!info) {
47                 ctrl_err(p_slot->ctrl, "dropped event %d (ENOMEM)\n", event_type);
48                 return;
49         }
50
51         INIT_WORK(&info->work, interrupt_event_handler);
52         info->event_type = event_type;
53         info->p_slot = p_slot;
54         queue_work(p_slot->wq, &info->work);
55 }
56
57 /* The following routines constitute the bulk of the
58    hotplug controller logic
59  */
60
61 static void set_slot_off(struct controller *ctrl, struct slot *pslot)
62 {
63         /* turn off slot, turn on Amber LED, turn off Green LED if supported*/
64         if (POWER_CTRL(ctrl)) {
65                 pciehp_power_off_slot(pslot);
66
67                 /*
68                  * After turning power off, we must wait for at least 1 second
69                  * before taking any action that relies on power having been
70                  * removed from the slot/adapter.
71                  */
72                 msleep(1000);
73         }
74
75         pciehp_green_led_off(pslot);
76         pciehp_set_attention_status(pslot, 1);
77 }
78
79 /**
80  * board_added - Called after a board has been added to the system.
81  * @p_slot: &slot where board is added
82  *
83  * Turns power on for the board.
84  * Configures board.
85  */
86 static int board_added(struct slot *p_slot)
87 {
88         int retval = 0;
89         struct controller *ctrl = p_slot->ctrl;
90         struct pci_bus *parent = ctrl->pcie->port->subordinate;
91
92         if (POWER_CTRL(ctrl)) {
93                 /* Power on slot */
94                 retval = pciehp_power_on_slot(p_slot);
95                 if (retval)
96                         return retval;
97         }
98
99         pciehp_green_led_blink(p_slot);
100
101         /* Check link training status */
102         pm_runtime_get_sync(&ctrl->pcie->port->dev);
103         retval = pciehp_check_link_status(ctrl);
104         if (retval) {
105                 ctrl_err(ctrl, "Failed to check link status\n");
106                 goto err_exit;
107         }
108
109         /* Check for a power fault */
110         if (ctrl->power_fault_detected || pciehp_query_power_fault(p_slot)) {
111                 ctrl_err(ctrl, "Slot(%s): Power fault\n", slot_name(p_slot));
112                 retval = -EIO;
113                 goto err_exit;
114         }
115
116         retval = pciehp_configure_device(p_slot);
117         if (retval) {
118                 ctrl_err(ctrl, "Cannot add device at %04x:%02x:00\n",
119                          pci_domain_nr(parent), parent->number);
120                 if (retval != -EEXIST)
121                         goto err_exit;
122         }
123         pm_runtime_put(&ctrl->pcie->port->dev);
124
125         pciehp_green_led_on(p_slot);
126         pciehp_set_attention_status(p_slot, 0);
127         return 0;
128
129 err_exit:
130         pm_runtime_put(&ctrl->pcie->port->dev);
131         set_slot_off(ctrl, p_slot);
132         return retval;
133 }
134
135 /**
136  * remove_board - Turns off slot and LEDs
137  * @p_slot: slot where board is being removed
138  */
139 static int remove_board(struct slot *p_slot)
140 {
141         int retval;
142         struct controller *ctrl = p_slot->ctrl;
143
144         pm_runtime_get_sync(&ctrl->pcie->port->dev);
145         retval = pciehp_unconfigure_device(p_slot);
146         pm_runtime_put(&ctrl->pcie->port->dev);
147         if (retval)
148                 return retval;
149
150         if (POWER_CTRL(ctrl)) {
151                 pciehp_power_off_slot(p_slot);
152
153                 /*
154                  * After turning power off, we must wait for at least 1 second
155                  * before taking any action that relies on power having been
156                  * removed from the slot/adapter.
157                  */
158                 msleep(1000);
159         }
160
161         /* turn off Green LED */
162         pciehp_green_led_off(p_slot);
163         return 0;
164 }
165
166 struct power_work_info {
167         struct slot *p_slot;
168         struct work_struct work;
169         unsigned int req;
170 #define DISABLE_REQ 0
171 #define ENABLE_REQ  1
172 };
173
174 /**
175  * pciehp_power_thread - handle pushbutton events
176  * @work: &struct work_struct describing work to be done
177  *
178  * Scheduled procedure to handle blocking stuff for the pushbuttons.
179  * Handles all pending events and exits.
180  */
181 static void pciehp_power_thread(struct work_struct *work)
182 {
183         struct power_work_info *info =
184                 container_of(work, struct power_work_info, work);
185         struct slot *p_slot = info->p_slot;
186         int ret;
187
188         switch (info->req) {
189         case DISABLE_REQ:
190                 mutex_lock(&p_slot->hotplug_lock);
191                 pciehp_disable_slot(p_slot);
192                 mutex_unlock(&p_slot->hotplug_lock);
193                 mutex_lock(&p_slot->lock);
194                 p_slot->state = STATIC_STATE;
195                 mutex_unlock(&p_slot->lock);
196                 break;
197         case ENABLE_REQ:
198                 mutex_lock(&p_slot->hotplug_lock);
199                 ret = pciehp_enable_slot(p_slot);
200                 mutex_unlock(&p_slot->hotplug_lock);
201                 if (ret)
202                         pciehp_green_led_off(p_slot);
203                 mutex_lock(&p_slot->lock);
204                 p_slot->state = STATIC_STATE;
205                 mutex_unlock(&p_slot->lock);
206                 break;
207         default:
208                 break;
209         }
210
211         kfree(info);
212 }
213
214 static void pciehp_queue_power_work(struct slot *p_slot, int req)
215 {
216         struct power_work_info *info;
217
218         p_slot->state = (req == ENABLE_REQ) ? POWERON_STATE : POWEROFF_STATE;
219
220         info = kmalloc(sizeof(*info), GFP_KERNEL);
221         if (!info) {
222                 ctrl_err(p_slot->ctrl, "no memory to queue %s request\n",
223                          (req == ENABLE_REQ) ? "poweron" : "poweroff");
224                 return;
225         }
226         info->p_slot = p_slot;
227         INIT_WORK(&info->work, pciehp_power_thread);
228         info->req = req;
229         queue_work(p_slot->wq, &info->work);
230 }
231
232 void pciehp_queue_pushbutton_work(struct work_struct *work)
233 {
234         struct slot *p_slot = container_of(work, struct slot, work.work);
235
236         mutex_lock(&p_slot->lock);
237         switch (p_slot->state) {
238         case BLINKINGOFF_STATE:
239                 pciehp_queue_power_work(p_slot, DISABLE_REQ);
240                 break;
241         case BLINKINGON_STATE:
242                 pciehp_queue_power_work(p_slot, ENABLE_REQ);
243                 break;
244         default:
245                 break;
246         }
247         mutex_unlock(&p_slot->lock);
248 }
249
250 /*
251  * Note: This function must be called with slot->lock held
252  */
253 static void handle_button_press_event(struct slot *p_slot)
254 {
255         struct controller *ctrl = p_slot->ctrl;
256         u8 getstatus;
257
258         switch (p_slot->state) {
259         case STATIC_STATE:
260                 pciehp_get_power_status(p_slot, &getstatus);
261                 if (getstatus) {
262                         p_slot->state = BLINKINGOFF_STATE;
263                         ctrl_info(ctrl, "Slot(%s): Powering off due to button press\n",
264                                   slot_name(p_slot));
265                 } else {
266                         p_slot->state = BLINKINGON_STATE;
267                         ctrl_info(ctrl, "Slot(%s) Powering on due to button press\n",
268                                   slot_name(p_slot));
269                 }
270                 /* blink green LED and turn off amber */
271                 pciehp_green_led_blink(p_slot);
272                 pciehp_set_attention_status(p_slot, 0);
273                 queue_delayed_work(p_slot->wq, &p_slot->work, 5*HZ);
274                 break;
275         case BLINKINGOFF_STATE:
276         case BLINKINGON_STATE:
277                 /*
278                  * Cancel if we are still blinking; this means that we
279                  * press the attention again before the 5 sec. limit
280                  * expires to cancel hot-add or hot-remove
281                  */
282                 ctrl_info(ctrl, "Slot(%s): Button cancel\n", slot_name(p_slot));
283                 cancel_delayed_work(&p_slot->work);
284                 if (p_slot->state == BLINKINGOFF_STATE)
285                         pciehp_green_led_on(p_slot);
286                 else
287                         pciehp_green_led_off(p_slot);
288                 pciehp_set_attention_status(p_slot, 0);
289                 ctrl_info(ctrl, "Slot(%s): Action canceled due to button press\n",
290                           slot_name(p_slot));
291                 p_slot->state = STATIC_STATE;
292                 break;
293         case POWEROFF_STATE:
294         case POWERON_STATE:
295                 /*
296                  * Ignore if the slot is on power-on or power-off state;
297                  * this means that the previous attention button action
298                  * to hot-add or hot-remove is undergoing
299                  */
300                 ctrl_info(ctrl, "Slot(%s): Button ignored\n",
301                           slot_name(p_slot));
302                 break;
303         default:
304                 ctrl_err(ctrl, "Slot(%s): Ignoring invalid state %#x\n",
305                          slot_name(p_slot), p_slot->state);
306                 break;
307         }
308 }
309
310 /*
311  * Note: This function must be called with slot->lock held
312  */
313 static void handle_link_event(struct slot *p_slot, u32 event)
314 {
315         struct controller *ctrl = p_slot->ctrl;
316
317         switch (p_slot->state) {
318         case BLINKINGON_STATE:
319         case BLINKINGOFF_STATE:
320                 cancel_delayed_work(&p_slot->work);
321                 /* Fall through */
322         case STATIC_STATE:
323                 pciehp_queue_power_work(p_slot, event == INT_LINK_UP ?
324                                         ENABLE_REQ : DISABLE_REQ);
325                 break;
326         case POWERON_STATE:
327                 if (event == INT_LINK_UP) {
328                         ctrl_info(ctrl, "Slot(%s): Link Up event ignored; already powering on\n",
329                                   slot_name(p_slot));
330                 } else {
331                         ctrl_info(ctrl, "Slot(%s): Link Down event queued; currently getting powered on\n",
332                                   slot_name(p_slot));
333                         pciehp_queue_power_work(p_slot, DISABLE_REQ);
334                 }
335                 break;
336         case POWEROFF_STATE:
337                 if (event == INT_LINK_UP) {
338                         ctrl_info(ctrl, "Slot(%s): Link Up event queued; currently getting powered off\n",
339                                   slot_name(p_slot));
340                         pciehp_queue_power_work(p_slot, ENABLE_REQ);
341                 } else {
342                         ctrl_info(ctrl, "Slot(%s): Link Down event ignored; already powering off\n",
343                                   slot_name(p_slot));
344                 }
345                 break;
346         default:
347                 ctrl_err(ctrl, "Slot(%s): Ignoring invalid state %#x\n",
348                          slot_name(p_slot), p_slot->state);
349                 break;
350         }
351 }
352
353 static void interrupt_event_handler(struct work_struct *work)
354 {
355         struct event_info *info = container_of(work, struct event_info, work);
356         struct slot *p_slot = info->p_slot;
357         struct controller *ctrl = p_slot->ctrl;
358
359         mutex_lock(&p_slot->lock);
360         switch (info->event_type) {
361         case INT_BUTTON_PRESS:
362                 handle_button_press_event(p_slot);
363                 break;
364         case INT_POWER_FAULT:
365                 if (!POWER_CTRL(ctrl))
366                         break;
367                 pciehp_set_attention_status(p_slot, 1);
368                 pciehp_green_led_off(p_slot);
369                 break;
370         case INT_PRESENCE_ON:
371                 pciehp_queue_power_work(p_slot, ENABLE_REQ);
372                 break;
373         case INT_PRESENCE_OFF:
374                 /*
375                  * Regardless of surprise capability, we need to
376                  * definitely remove a card that has been pulled out!
377                  */
378                 pciehp_queue_power_work(p_slot, DISABLE_REQ);
379                 break;
380         case INT_LINK_UP:
381         case INT_LINK_DOWN:
382                 handle_link_event(p_slot, info->event_type);
383                 break;
384         default:
385                 break;
386         }
387         mutex_unlock(&p_slot->lock);
388
389         kfree(info);
390 }
391
392 /*
393  * Note: This function must be called with slot->hotplug_lock held
394  */
395 int pciehp_enable_slot(struct slot *p_slot)
396 {
397         u8 getstatus = 0;
398         struct controller *ctrl = p_slot->ctrl;
399
400         pciehp_get_adapter_status(p_slot, &getstatus);
401         if (!getstatus) {
402                 ctrl_info(ctrl, "Slot(%s): No adapter\n", slot_name(p_slot));
403                 return -ENODEV;
404         }
405         if (MRL_SENS(p_slot->ctrl)) {
406                 pciehp_get_latch_status(p_slot, &getstatus);
407                 if (getstatus) {
408                         ctrl_info(ctrl, "Slot(%s): Latch open\n",
409                                   slot_name(p_slot));
410                         return -ENODEV;
411                 }
412         }
413
414         if (POWER_CTRL(p_slot->ctrl)) {
415                 pciehp_get_power_status(p_slot, &getstatus);
416                 if (getstatus) {
417                         ctrl_info(ctrl, "Slot(%s): Already enabled\n",
418                                   slot_name(p_slot));
419                         return 0;
420                 }
421         }
422
423         return board_added(p_slot);
424 }
425
426 /*
427  * Note: This function must be called with slot->hotplug_lock held
428  */
429 int pciehp_disable_slot(struct slot *p_slot)
430 {
431         u8 getstatus = 0;
432         struct controller *ctrl = p_slot->ctrl;
433
434         if (!p_slot->ctrl)
435                 return 1;
436
437         if (POWER_CTRL(p_slot->ctrl)) {
438                 pciehp_get_power_status(p_slot, &getstatus);
439                 if (!getstatus) {
440                         ctrl_info(ctrl, "Slot(%s): Already disabled\n",
441                                   slot_name(p_slot));
442                         return -EINVAL;
443                 }
444         }
445
446         return remove_board(p_slot);
447 }
448
449 int pciehp_sysfs_enable_slot(struct slot *p_slot)
450 {
451         int retval = -ENODEV;
452         struct controller *ctrl = p_slot->ctrl;
453
454         mutex_lock(&p_slot->lock);
455         switch (p_slot->state) {
456         case BLINKINGON_STATE:
457                 cancel_delayed_work(&p_slot->work);
458         case STATIC_STATE:
459                 p_slot->state = POWERON_STATE;
460                 mutex_unlock(&p_slot->lock);
461                 mutex_lock(&p_slot->hotplug_lock);
462                 retval = pciehp_enable_slot(p_slot);
463                 mutex_unlock(&p_slot->hotplug_lock);
464                 mutex_lock(&p_slot->lock);
465                 p_slot->state = STATIC_STATE;
466                 break;
467         case POWERON_STATE:
468                 ctrl_info(ctrl, "Slot(%s): Already in powering on state\n",
469                           slot_name(p_slot));
470                 break;
471         case BLINKINGOFF_STATE:
472         case POWEROFF_STATE:
473                 ctrl_info(ctrl, "Slot(%s): Already enabled\n",
474                           slot_name(p_slot));
475                 break;
476         default:
477                 ctrl_err(ctrl, "Slot(%s): Invalid state %#x\n",
478                          slot_name(p_slot), p_slot->state);
479                 break;
480         }
481         mutex_unlock(&p_slot->lock);
482
483         return retval;
484 }
485
486 int pciehp_sysfs_disable_slot(struct slot *p_slot)
487 {
488         int retval = -ENODEV;
489         struct controller *ctrl = p_slot->ctrl;
490
491         mutex_lock(&p_slot->lock);
492         switch (p_slot->state) {
493         case BLINKINGOFF_STATE:
494                 cancel_delayed_work(&p_slot->work);
495         case STATIC_STATE:
496                 p_slot->state = POWEROFF_STATE;
497                 mutex_unlock(&p_slot->lock);
498                 mutex_lock(&p_slot->hotplug_lock);
499                 retval = pciehp_disable_slot(p_slot);
500                 mutex_unlock(&p_slot->hotplug_lock);
501                 mutex_lock(&p_slot->lock);
502                 p_slot->state = STATIC_STATE;
503                 break;
504         case POWEROFF_STATE:
505                 ctrl_info(ctrl, "Slot(%s): Already in powering off state\n",
506                           slot_name(p_slot));
507                 break;
508         case BLINKINGON_STATE:
509         case POWERON_STATE:
510                 ctrl_info(ctrl, "Slot(%s): Already disabled\n",
511                           slot_name(p_slot));
512                 break;
513         default:
514                 ctrl_err(ctrl, "Slot(%s): Invalid state %#x\n",
515                          slot_name(p_slot), p_slot->state);
516                 break;
517         }
518         mutex_unlock(&p_slot->lock);
519
520         return retval;
521 }