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