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