xref: /linux/drivers/pci/hotplug/pciehp_ctrl.c (revision 7f71507851fc7764b36a3221839607d3a45c2025)
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 #define dev_fmt(fmt) "pciehp: " fmt
17 
18 #include <linux/kernel.h>
19 #include <linux/types.h>
20 #include <linux/pm_runtime.h>
21 #include <linux/pci.h>
22 
23 #include "../pci.h"
24 #include "pciehp.h"
25 
26 /* The following routines constitute the bulk of the
27    hotplug controller logic
28  */
29 
30 #define SAFE_REMOVAL	 true
31 #define SURPRISE_REMOVAL false
32 
33 static void set_slot_off(struct controller *ctrl)
34 {
35 	/*
36 	 * Turn off slot, turn on attention indicator, turn off power
37 	 * indicator
38 	 */
39 	if (POWER_CTRL(ctrl)) {
40 		pciehp_power_off_slot(ctrl);
41 
42 		/*
43 		 * After turning power off, we must wait for at least 1 second
44 		 * before taking any action that relies on power having been
45 		 * removed from the slot/adapter.
46 		 */
47 		msleep(1000);
48 	}
49 
50 	pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
51 			      PCI_EXP_SLTCTL_ATTN_IND_ON);
52 }
53 
54 /**
55  * board_added - Called after a board has been added to the system.
56  * @ctrl: PCIe hotplug controller where board is added
57  *
58  * Turns power on for the board.
59  * Configures board.
60  */
61 static int board_added(struct controller *ctrl)
62 {
63 	int retval = 0;
64 	struct pci_bus *parent = ctrl->pcie->port->subordinate;
65 
66 	if (POWER_CTRL(ctrl)) {
67 		/* Power on slot */
68 		retval = pciehp_power_on_slot(ctrl);
69 		if (retval)
70 			return retval;
71 	}
72 
73 	pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_BLINK,
74 			      INDICATOR_NOOP);
75 
76 	/* Check link training status */
77 	retval = pciehp_check_link_status(ctrl);
78 	if (retval)
79 		goto err_exit;
80 
81 	/* Check for a power fault */
82 	if (ctrl->power_fault_detected || pciehp_query_power_fault(ctrl)) {
83 		ctrl_err(ctrl, "Slot(%s): Power fault\n", slot_name(ctrl));
84 		retval = -EIO;
85 		goto err_exit;
86 	}
87 
88 	retval = pciehp_configure_device(ctrl);
89 	if (retval) {
90 		if (retval != -EEXIST) {
91 			ctrl_err(ctrl, "Cannot add device at %04x:%02x:00\n",
92 				 pci_domain_nr(parent), parent->number);
93 			goto err_exit;
94 		}
95 	}
96 
97 	pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_ON,
98 			      PCI_EXP_SLTCTL_ATTN_IND_OFF);
99 	return 0;
100 
101 err_exit:
102 	set_slot_off(ctrl);
103 	return retval;
104 }
105 
106 /**
107  * remove_board - Turn off slot and Power Indicator
108  * @ctrl: PCIe hotplug controller where board is being removed
109  * @safe_removal: whether the board is safely removed (versus surprise removed)
110  */
111 static void remove_board(struct controller *ctrl, bool safe_removal)
112 {
113 	pciehp_unconfigure_device(ctrl, safe_removal);
114 
115 	if (POWER_CTRL(ctrl)) {
116 		pciehp_power_off_slot(ctrl);
117 
118 		/*
119 		 * After turning power off, we must wait for at least 1 second
120 		 * before taking any action that relies on power having been
121 		 * removed from the slot/adapter.
122 		 */
123 		msleep(1000);
124 
125 		/* Ignore link or presence changes caused by power off */
126 		atomic_and(~(PCI_EXP_SLTSTA_DLLSC | PCI_EXP_SLTSTA_PDC),
127 			   &ctrl->pending_events);
128 	}
129 
130 	pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
131 			      INDICATOR_NOOP);
132 
133 	/* Don't carry LBMS indications across */
134 	pcie_reset_lbms_count(ctrl->pcie->port);
135 }
136 
137 static int pciehp_enable_slot(struct controller *ctrl);
138 static int pciehp_disable_slot(struct controller *ctrl, bool safe_removal);
139 
140 void pciehp_request(struct controller *ctrl, int action)
141 {
142 	atomic_or(action, &ctrl->pending_events);
143 	if (!pciehp_poll_mode)
144 		irq_wake_thread(ctrl->pcie->irq, ctrl);
145 }
146 
147 void pciehp_queue_pushbutton_work(struct work_struct *work)
148 {
149 	struct controller *ctrl = container_of(work, struct controller,
150 					       button_work.work);
151 
152 	mutex_lock(&ctrl->state_lock);
153 	switch (ctrl->state) {
154 	case BLINKINGOFF_STATE:
155 		pciehp_request(ctrl, DISABLE_SLOT);
156 		break;
157 	case BLINKINGON_STATE:
158 		pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC);
159 		break;
160 	default:
161 		break;
162 	}
163 	mutex_unlock(&ctrl->state_lock);
164 }
165 
166 void pciehp_handle_button_press(struct controller *ctrl)
167 {
168 	mutex_lock(&ctrl->state_lock);
169 	switch (ctrl->state) {
170 	case OFF_STATE:
171 	case ON_STATE:
172 		if (ctrl->state == ON_STATE) {
173 			ctrl->state = BLINKINGOFF_STATE;
174 			ctrl_info(ctrl, "Slot(%s): Button press: will power off in 5 sec\n",
175 				  slot_name(ctrl));
176 		} else {
177 			ctrl->state = BLINKINGON_STATE;
178 			ctrl_info(ctrl, "Slot(%s): Button press: will power on in 5 sec\n",
179 				  slot_name(ctrl));
180 		}
181 		/* blink power indicator and turn off attention */
182 		pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_BLINK,
183 				      PCI_EXP_SLTCTL_ATTN_IND_OFF);
184 		schedule_delayed_work(&ctrl->button_work, 5 * HZ);
185 		break;
186 	case BLINKINGOFF_STATE:
187 	case BLINKINGON_STATE:
188 		/*
189 		 * Cancel if we are still blinking; this means that we
190 		 * press the attention again before the 5 sec. limit
191 		 * expires to cancel hot-add or hot-remove
192 		 */
193 		cancel_delayed_work(&ctrl->button_work);
194 		if (ctrl->state == BLINKINGOFF_STATE) {
195 			ctrl->state = ON_STATE;
196 			pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_ON,
197 					      PCI_EXP_SLTCTL_ATTN_IND_OFF);
198 			ctrl_info(ctrl, "Slot(%s): Button press: canceling request to power off\n",
199 				  slot_name(ctrl));
200 		} else {
201 			ctrl->state = OFF_STATE;
202 			pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
203 					      PCI_EXP_SLTCTL_ATTN_IND_OFF);
204 			ctrl_info(ctrl, "Slot(%s): Button press: canceling request to power on\n",
205 				  slot_name(ctrl));
206 		}
207 		break;
208 	default:
209 		ctrl_err(ctrl, "Slot(%s): Button press: ignoring invalid state %#x\n",
210 			 slot_name(ctrl), ctrl->state);
211 		break;
212 	}
213 	mutex_unlock(&ctrl->state_lock);
214 }
215 
216 void pciehp_handle_disable_request(struct controller *ctrl)
217 {
218 	mutex_lock(&ctrl->state_lock);
219 	switch (ctrl->state) {
220 	case BLINKINGON_STATE:
221 	case BLINKINGOFF_STATE:
222 		cancel_delayed_work(&ctrl->button_work);
223 		break;
224 	}
225 	ctrl->state = POWEROFF_STATE;
226 	mutex_unlock(&ctrl->state_lock);
227 
228 	ctrl->request_result = pciehp_disable_slot(ctrl, SAFE_REMOVAL);
229 }
230 
231 void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events)
232 {
233 	int present, link_active;
234 
235 	/*
236 	 * If the slot is on and presence or link has changed, turn it off.
237 	 * Even if it's occupied again, we cannot assume the card is the same.
238 	 */
239 	mutex_lock(&ctrl->state_lock);
240 	switch (ctrl->state) {
241 	case BLINKINGOFF_STATE:
242 		cancel_delayed_work(&ctrl->button_work);
243 		fallthrough;
244 	case ON_STATE:
245 		ctrl->state = POWEROFF_STATE;
246 		mutex_unlock(&ctrl->state_lock);
247 		if (events & PCI_EXP_SLTSTA_DLLSC)
248 			ctrl_info(ctrl, "Slot(%s): Link Down\n",
249 				  slot_name(ctrl));
250 		if (events & PCI_EXP_SLTSTA_PDC)
251 			ctrl_info(ctrl, "Slot(%s): Card not present\n",
252 				  slot_name(ctrl));
253 		pciehp_disable_slot(ctrl, SURPRISE_REMOVAL);
254 		break;
255 	default:
256 		mutex_unlock(&ctrl->state_lock);
257 		break;
258 	}
259 
260 	/* Turn the slot on if it's occupied or link is up */
261 	mutex_lock(&ctrl->state_lock);
262 	present = pciehp_card_present(ctrl);
263 	link_active = pciehp_check_link_active(ctrl);
264 	if (present <= 0 && link_active <= 0) {
265 		if (ctrl->state == BLINKINGON_STATE) {
266 			ctrl->state = OFF_STATE;
267 			cancel_delayed_work(&ctrl->button_work);
268 			pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
269 					      INDICATOR_NOOP);
270 			ctrl_info(ctrl, "Slot(%s): Card not present\n",
271 				  slot_name(ctrl));
272 		}
273 		mutex_unlock(&ctrl->state_lock);
274 		return;
275 	}
276 
277 	switch (ctrl->state) {
278 	case BLINKINGON_STATE:
279 		cancel_delayed_work(&ctrl->button_work);
280 		fallthrough;
281 	case OFF_STATE:
282 		ctrl->state = POWERON_STATE;
283 		mutex_unlock(&ctrl->state_lock);
284 		if (present)
285 			ctrl_info(ctrl, "Slot(%s): Card present\n",
286 				  slot_name(ctrl));
287 		if (link_active)
288 			ctrl_info(ctrl, "Slot(%s): Link Up\n",
289 				  slot_name(ctrl));
290 		ctrl->request_result = pciehp_enable_slot(ctrl);
291 		break;
292 	default:
293 		mutex_unlock(&ctrl->state_lock);
294 		break;
295 	}
296 }
297 
298 static int __pciehp_enable_slot(struct controller *ctrl)
299 {
300 	u8 getstatus = 0;
301 
302 	if (MRL_SENS(ctrl)) {
303 		pciehp_get_latch_status(ctrl, &getstatus);
304 		if (getstatus) {
305 			ctrl_info(ctrl, "Slot(%s): Latch open\n",
306 				  slot_name(ctrl));
307 			return -ENODEV;
308 		}
309 	}
310 
311 	if (POWER_CTRL(ctrl)) {
312 		pciehp_get_power_status(ctrl, &getstatus);
313 		if (getstatus) {
314 			ctrl_info(ctrl, "Slot(%s): Already enabled\n",
315 				  slot_name(ctrl));
316 			return 0;
317 		}
318 	}
319 
320 	return board_added(ctrl);
321 }
322 
323 static int pciehp_enable_slot(struct controller *ctrl)
324 {
325 	int ret;
326 
327 	pm_runtime_get_sync(&ctrl->pcie->port->dev);
328 	ret = __pciehp_enable_slot(ctrl);
329 	if (ret && ATTN_BUTTN(ctrl))
330 		/* may be blinking */
331 		pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
332 				      INDICATOR_NOOP);
333 	pm_runtime_put(&ctrl->pcie->port->dev);
334 
335 	mutex_lock(&ctrl->state_lock);
336 	ctrl->state = ret ? OFF_STATE : ON_STATE;
337 	mutex_unlock(&ctrl->state_lock);
338 
339 	return ret;
340 }
341 
342 static int __pciehp_disable_slot(struct controller *ctrl, bool safe_removal)
343 {
344 	u8 getstatus = 0;
345 
346 	if (POWER_CTRL(ctrl)) {
347 		pciehp_get_power_status(ctrl, &getstatus);
348 		if (!getstatus) {
349 			ctrl_info(ctrl, "Slot(%s): Already disabled\n",
350 				  slot_name(ctrl));
351 			return -EINVAL;
352 		}
353 	}
354 
355 	remove_board(ctrl, safe_removal);
356 	return 0;
357 }
358 
359 static int pciehp_disable_slot(struct controller *ctrl, bool safe_removal)
360 {
361 	int ret;
362 
363 	pm_runtime_get_sync(&ctrl->pcie->port->dev);
364 	ret = __pciehp_disable_slot(ctrl, safe_removal);
365 	pm_runtime_put(&ctrl->pcie->port->dev);
366 
367 	mutex_lock(&ctrl->state_lock);
368 	ctrl->state = OFF_STATE;
369 	mutex_unlock(&ctrl->state_lock);
370 
371 	return ret;
372 }
373 
374 int pciehp_sysfs_enable_slot(struct hotplug_slot *hotplug_slot)
375 {
376 	struct controller *ctrl = to_ctrl(hotplug_slot);
377 
378 	mutex_lock(&ctrl->state_lock);
379 	switch (ctrl->state) {
380 	case BLINKINGON_STATE:
381 	case OFF_STATE:
382 		mutex_unlock(&ctrl->state_lock);
383 		/*
384 		 * The IRQ thread becomes a no-op if the user pulls out the
385 		 * card before the thread wakes up, so initialize to -ENODEV.
386 		 */
387 		ctrl->request_result = -ENODEV;
388 		pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC);
389 		wait_event(ctrl->requester,
390 			   !atomic_read(&ctrl->pending_events) &&
391 			   !ctrl->ist_running);
392 		return ctrl->request_result;
393 	case POWERON_STATE:
394 		ctrl_info(ctrl, "Slot(%s): Already in powering on state\n",
395 			  slot_name(ctrl));
396 		break;
397 	case BLINKINGOFF_STATE:
398 	case ON_STATE:
399 	case POWEROFF_STATE:
400 		ctrl_info(ctrl, "Slot(%s): Already enabled\n",
401 			  slot_name(ctrl));
402 		break;
403 	default:
404 		ctrl_err(ctrl, "Slot(%s): Invalid state %#x\n",
405 			 slot_name(ctrl), ctrl->state);
406 		break;
407 	}
408 	mutex_unlock(&ctrl->state_lock);
409 
410 	return -ENODEV;
411 }
412 
413 int pciehp_sysfs_disable_slot(struct hotplug_slot *hotplug_slot)
414 {
415 	struct controller *ctrl = to_ctrl(hotplug_slot);
416 
417 	mutex_lock(&ctrl->state_lock);
418 	switch (ctrl->state) {
419 	case BLINKINGOFF_STATE:
420 	case ON_STATE:
421 		mutex_unlock(&ctrl->state_lock);
422 		pciehp_request(ctrl, DISABLE_SLOT);
423 		wait_event(ctrl->requester,
424 			   !atomic_read(&ctrl->pending_events) &&
425 			   !ctrl->ist_running);
426 		return ctrl->request_result;
427 	case POWEROFF_STATE:
428 		ctrl_info(ctrl, "Slot(%s): Already in powering off state\n",
429 			  slot_name(ctrl));
430 		break;
431 	case BLINKINGON_STATE:
432 	case OFF_STATE:
433 	case POWERON_STATE:
434 		ctrl_info(ctrl, "Slot(%s): Already disabled\n",
435 			  slot_name(ctrl));
436 		break;
437 	default:
438 		ctrl_err(ctrl, "Slot(%s): Invalid state %#x\n",
439 			 slot_name(ctrl), ctrl->state);
440 		break;
441 	}
442 	mutex_unlock(&ctrl->state_lock);
443 
444 	return -ENODEV;
445 }
446