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 }
522