xref: /linux/drivers/pci/hotplug/pciehp_ctrl.c (revision e5c86679d5e864947a52fb31e45a425dea3e7fa9)
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, "Slot(%s): Power fault\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 	pciehp_set_attention_status(p_slot, 0);
124 	return 0;
125 
126 err_exit:
127 	set_slot_off(ctrl, p_slot);
128 	return retval;
129 }
130 
131 /**
132  * remove_board - Turns off slot and LEDs
133  * @p_slot: slot where board is being removed
134  */
135 static int remove_board(struct slot *p_slot)
136 {
137 	int retval;
138 	struct controller *ctrl = p_slot->ctrl;
139 
140 	retval = pciehp_unconfigure_device(p_slot);
141 	if (retval)
142 		return retval;
143 
144 	if (POWER_CTRL(ctrl)) {
145 		pciehp_power_off_slot(p_slot);
146 
147 		/*
148 		 * After turning power off, we must wait for at least 1 second
149 		 * before taking any action that relies on power having been
150 		 * removed from the slot/adapter.
151 		 */
152 		msleep(1000);
153 	}
154 
155 	/* turn off Green LED */
156 	pciehp_green_led_off(p_slot);
157 	return 0;
158 }
159 
160 struct power_work_info {
161 	struct slot *p_slot;
162 	struct work_struct work;
163 	unsigned int req;
164 #define DISABLE_REQ 0
165 #define ENABLE_REQ  1
166 };
167 
168 /**
169  * pciehp_power_thread - handle pushbutton events
170  * @work: &struct work_struct describing work to be done
171  *
172  * Scheduled procedure to handle blocking stuff for the pushbuttons.
173  * Handles all pending events and exits.
174  */
175 static void pciehp_power_thread(struct work_struct *work)
176 {
177 	struct power_work_info *info =
178 		container_of(work, struct power_work_info, work);
179 	struct slot *p_slot = info->p_slot;
180 	int ret;
181 
182 	switch (info->req) {
183 	case DISABLE_REQ:
184 		mutex_lock(&p_slot->hotplug_lock);
185 		pciehp_disable_slot(p_slot);
186 		mutex_unlock(&p_slot->hotplug_lock);
187 		mutex_lock(&p_slot->lock);
188 		p_slot->state = STATIC_STATE;
189 		mutex_unlock(&p_slot->lock);
190 		break;
191 	case ENABLE_REQ:
192 		mutex_lock(&p_slot->hotplug_lock);
193 		ret = pciehp_enable_slot(p_slot);
194 		mutex_unlock(&p_slot->hotplug_lock);
195 		if (ret)
196 			pciehp_green_led_off(p_slot);
197 		mutex_lock(&p_slot->lock);
198 		p_slot->state = STATIC_STATE;
199 		mutex_unlock(&p_slot->lock);
200 		break;
201 	default:
202 		break;
203 	}
204 
205 	kfree(info);
206 }
207 
208 static void pciehp_queue_power_work(struct slot *p_slot, int req)
209 {
210 	struct power_work_info *info;
211 
212 	p_slot->state = (req == ENABLE_REQ) ? POWERON_STATE : POWEROFF_STATE;
213 
214 	info = kmalloc(sizeof(*info), GFP_KERNEL);
215 	if (!info) {
216 		ctrl_err(p_slot->ctrl, "no memory to queue %s request\n",
217 			 (req == ENABLE_REQ) ? "poweron" : "poweroff");
218 		return;
219 	}
220 	info->p_slot = p_slot;
221 	INIT_WORK(&info->work, pciehp_power_thread);
222 	info->req = req;
223 	queue_work(p_slot->wq, &info->work);
224 }
225 
226 void pciehp_queue_pushbutton_work(struct work_struct *work)
227 {
228 	struct slot *p_slot = container_of(work, struct slot, work.work);
229 
230 	mutex_lock(&p_slot->lock);
231 	switch (p_slot->state) {
232 	case BLINKINGOFF_STATE:
233 		pciehp_queue_power_work(p_slot, DISABLE_REQ);
234 		break;
235 	case BLINKINGON_STATE:
236 		pciehp_queue_power_work(p_slot, ENABLE_REQ);
237 		break;
238 	default:
239 		break;
240 	}
241 	mutex_unlock(&p_slot->lock);
242 }
243 
244 /*
245  * Note: This function must be called with slot->lock held
246  */
247 static void handle_button_press_event(struct slot *p_slot)
248 {
249 	struct controller *ctrl = p_slot->ctrl;
250 	u8 getstatus;
251 
252 	switch (p_slot->state) {
253 	case STATIC_STATE:
254 		pciehp_get_power_status(p_slot, &getstatus);
255 		if (getstatus) {
256 			p_slot->state = BLINKINGOFF_STATE;
257 			ctrl_info(ctrl, "Slot(%s): Powering off due to button press\n",
258 				  slot_name(p_slot));
259 		} else {
260 			p_slot->state = BLINKINGON_STATE;
261 			ctrl_info(ctrl, "Slot(%s) Powering on due to button press\n",
262 				  slot_name(p_slot));
263 		}
264 		/* blink green LED and turn off amber */
265 		pciehp_green_led_blink(p_slot);
266 		pciehp_set_attention_status(p_slot, 0);
267 		queue_delayed_work(p_slot->wq, &p_slot->work, 5*HZ);
268 		break;
269 	case BLINKINGOFF_STATE:
270 	case BLINKINGON_STATE:
271 		/*
272 		 * Cancel if we are still blinking; this means that we
273 		 * press the attention again before the 5 sec. limit
274 		 * expires to cancel hot-add or hot-remove
275 		 */
276 		ctrl_info(ctrl, "Slot(%s): Button cancel\n", slot_name(p_slot));
277 		cancel_delayed_work(&p_slot->work);
278 		if (p_slot->state == BLINKINGOFF_STATE)
279 			pciehp_green_led_on(p_slot);
280 		else
281 			pciehp_green_led_off(p_slot);
282 		pciehp_set_attention_status(p_slot, 0);
283 		ctrl_info(ctrl, "Slot(%s): Action canceled due to button press\n",
284 			  slot_name(p_slot));
285 		p_slot->state = STATIC_STATE;
286 		break;
287 	case POWEROFF_STATE:
288 	case POWERON_STATE:
289 		/*
290 		 * Ignore if the slot is on power-on or power-off state;
291 		 * this means that the previous attention button action
292 		 * to hot-add or hot-remove is undergoing
293 		 */
294 		ctrl_info(ctrl, "Slot(%s): Button ignored\n",
295 			  slot_name(p_slot));
296 		break;
297 	default:
298 		ctrl_err(ctrl, "Slot(%s): Ignoring invalid state %#x\n",
299 			 slot_name(p_slot), p_slot->state);
300 		break;
301 	}
302 }
303 
304 /*
305  * Note: This function must be called with slot->lock held
306  */
307 static void handle_link_event(struct slot *p_slot, u32 event)
308 {
309 	struct controller *ctrl = p_slot->ctrl;
310 
311 	switch (p_slot->state) {
312 	case BLINKINGON_STATE:
313 	case BLINKINGOFF_STATE:
314 		cancel_delayed_work(&p_slot->work);
315 		/* Fall through */
316 	case STATIC_STATE:
317 		pciehp_queue_power_work(p_slot, event == INT_LINK_UP ?
318 					ENABLE_REQ : DISABLE_REQ);
319 		break;
320 	case POWERON_STATE:
321 		if (event == INT_LINK_UP) {
322 			ctrl_info(ctrl, "Slot(%s): Link Up event ignored; already powering on\n",
323 				  slot_name(p_slot));
324 		} else {
325 			ctrl_info(ctrl, "Slot(%s): Link Down event queued; currently getting powered on\n",
326 				  slot_name(p_slot));
327 			pciehp_queue_power_work(p_slot, DISABLE_REQ);
328 		}
329 		break;
330 	case POWEROFF_STATE:
331 		if (event == INT_LINK_UP) {
332 			ctrl_info(ctrl, "Slot(%s): Link Up event queued; currently getting powered off\n",
333 				  slot_name(p_slot));
334 			pciehp_queue_power_work(p_slot, ENABLE_REQ);
335 		} else {
336 			ctrl_info(ctrl, "Slot(%s): Link Down event ignored; already powering off\n",
337 				  slot_name(p_slot));
338 		}
339 		break;
340 	default:
341 		ctrl_err(ctrl, "Slot(%s): Ignoring invalid state %#x\n",
342 			 slot_name(p_slot), p_slot->state);
343 		break;
344 	}
345 }
346 
347 static void interrupt_event_handler(struct work_struct *work)
348 {
349 	struct event_info *info = container_of(work, struct event_info, work);
350 	struct slot *p_slot = info->p_slot;
351 	struct controller *ctrl = p_slot->ctrl;
352 
353 	mutex_lock(&p_slot->lock);
354 	switch (info->event_type) {
355 	case INT_BUTTON_PRESS:
356 		handle_button_press_event(p_slot);
357 		break;
358 	case INT_POWER_FAULT:
359 		if (!POWER_CTRL(ctrl))
360 			break;
361 		pciehp_set_attention_status(p_slot, 1);
362 		pciehp_green_led_off(p_slot);
363 		break;
364 	case INT_PRESENCE_ON:
365 		pciehp_queue_power_work(p_slot, ENABLE_REQ);
366 		break;
367 	case INT_PRESENCE_OFF:
368 		/*
369 		 * Regardless of surprise capability, we need to
370 		 * definitely remove a card that has been pulled out!
371 		 */
372 		pciehp_queue_power_work(p_slot, DISABLE_REQ);
373 		break;
374 	case INT_LINK_UP:
375 	case INT_LINK_DOWN:
376 		handle_link_event(p_slot, info->event_type);
377 		break;
378 	default:
379 		break;
380 	}
381 	mutex_unlock(&p_slot->lock);
382 
383 	kfree(info);
384 }
385 
386 /*
387  * Note: This function must be called with slot->hotplug_lock held
388  */
389 int pciehp_enable_slot(struct slot *p_slot)
390 {
391 	u8 getstatus = 0;
392 	struct controller *ctrl = p_slot->ctrl;
393 
394 	pciehp_get_adapter_status(p_slot, &getstatus);
395 	if (!getstatus) {
396 		ctrl_info(ctrl, "Slot(%s): No adapter\n", slot_name(p_slot));
397 		return -ENODEV;
398 	}
399 	if (MRL_SENS(p_slot->ctrl)) {
400 		pciehp_get_latch_status(p_slot, &getstatus);
401 		if (getstatus) {
402 			ctrl_info(ctrl, "Slot(%s): Latch open\n",
403 				  slot_name(p_slot));
404 			return -ENODEV;
405 		}
406 	}
407 
408 	if (POWER_CTRL(p_slot->ctrl)) {
409 		pciehp_get_power_status(p_slot, &getstatus);
410 		if (getstatus) {
411 			ctrl_info(ctrl, "Slot(%s): Already enabled\n",
412 				  slot_name(p_slot));
413 			return 0;
414 		}
415 	}
416 
417 	return board_added(p_slot);
418 }
419 
420 /*
421  * Note: This function must be called with slot->hotplug_lock held
422  */
423 int pciehp_disable_slot(struct slot *p_slot)
424 {
425 	u8 getstatus = 0;
426 	struct controller *ctrl = p_slot->ctrl;
427 
428 	if (!p_slot->ctrl)
429 		return 1;
430 
431 	if (POWER_CTRL(p_slot->ctrl)) {
432 		pciehp_get_power_status(p_slot, &getstatus);
433 		if (!getstatus) {
434 			ctrl_info(ctrl, "Slot(%s): Already disabled\n",
435 				  slot_name(p_slot));
436 			return -EINVAL;
437 		}
438 	}
439 
440 	return remove_board(p_slot);
441 }
442 
443 int pciehp_sysfs_enable_slot(struct slot *p_slot)
444 {
445 	int retval = -ENODEV;
446 	struct controller *ctrl = p_slot->ctrl;
447 
448 	mutex_lock(&p_slot->lock);
449 	switch (p_slot->state) {
450 	case BLINKINGON_STATE:
451 		cancel_delayed_work(&p_slot->work);
452 	case STATIC_STATE:
453 		p_slot->state = POWERON_STATE;
454 		mutex_unlock(&p_slot->lock);
455 		mutex_lock(&p_slot->hotplug_lock);
456 		retval = pciehp_enable_slot(p_slot);
457 		mutex_unlock(&p_slot->hotplug_lock);
458 		mutex_lock(&p_slot->lock);
459 		p_slot->state = STATIC_STATE;
460 		break;
461 	case POWERON_STATE:
462 		ctrl_info(ctrl, "Slot(%s): Already in powering on state\n",
463 			  slot_name(p_slot));
464 		break;
465 	case BLINKINGOFF_STATE:
466 	case POWEROFF_STATE:
467 		ctrl_info(ctrl, "Slot(%s): Already enabled\n",
468 			  slot_name(p_slot));
469 		break;
470 	default:
471 		ctrl_err(ctrl, "Slot(%s): Invalid state %#x\n",
472 			 slot_name(p_slot), p_slot->state);
473 		break;
474 	}
475 	mutex_unlock(&p_slot->lock);
476 
477 	return retval;
478 }
479 
480 int pciehp_sysfs_disable_slot(struct slot *p_slot)
481 {
482 	int retval = -ENODEV;
483 	struct controller *ctrl = p_slot->ctrl;
484 
485 	mutex_lock(&p_slot->lock);
486 	switch (p_slot->state) {
487 	case BLINKINGOFF_STATE:
488 		cancel_delayed_work(&p_slot->work);
489 	case STATIC_STATE:
490 		p_slot->state = POWEROFF_STATE;
491 		mutex_unlock(&p_slot->lock);
492 		mutex_lock(&p_slot->hotplug_lock);
493 		retval = pciehp_disable_slot(p_slot);
494 		mutex_unlock(&p_slot->hotplug_lock);
495 		mutex_lock(&p_slot->lock);
496 		p_slot->state = STATIC_STATE;
497 		break;
498 	case POWEROFF_STATE:
499 		ctrl_info(ctrl, "Slot(%s): Already in powering off state\n",
500 			  slot_name(p_slot));
501 		break;
502 	case BLINKINGON_STATE:
503 	case POWERON_STATE:
504 		ctrl_info(ctrl, "Slot(%s): Already disabled\n",
505 			  slot_name(p_slot));
506 		break;
507 	default:
508 		ctrl_err(ctrl, "Slot(%s): Invalid state %#x\n",
509 			 slot_name(p_slot), p_slot->state);
510 		break;
511 	}
512 	mutex_unlock(&p_slot->lock);
513 
514 	return retval;
515 }
516