Linux Audio

Check our new training course

Loading...
v3.15
 
  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
 38static void interrupt_event_handler(struct work_struct *work);
 39
 40static int 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		return -ENOMEM;
 47
 48	info->event_type = event_type;
 49	info->p_slot = p_slot;
 50	INIT_WORK(&info->work, interrupt_event_handler);
 51
 52	queue_work(p_slot->wq, &info->work);
 53
 54	return 0;
 55}
 56
 57u8 pciehp_handle_attention_button(struct slot *p_slot)
 58{
 59	u32 event_type;
 60	struct controller *ctrl = p_slot->ctrl;
 61
 62	/* Attention Button Change */
 63	ctrl_dbg(ctrl, "Attention button interrupt received\n");
 64
 65	/*
 66	 *  Button pressed - See if need to TAKE ACTION!!!
 67	 */
 68	ctrl_info(ctrl, "Button pressed on Slot(%s)\n", slot_name(p_slot));
 69	event_type = INT_BUTTON_PRESS;
 70
 71	queue_interrupt_event(p_slot, event_type);
 72
 73	return 0;
 74}
 75
 76u8 pciehp_handle_switch_change(struct slot *p_slot)
 77{
 78	u8 getstatus;
 79	u32 event_type;
 80	struct controller *ctrl = p_slot->ctrl;
 81
 82	/* Switch Change */
 83	ctrl_dbg(ctrl, "Switch interrupt received\n");
 84
 85	pciehp_get_latch_status(p_slot, &getstatus);
 86	if (getstatus) {
 87		/*
 88		 * Switch opened
 89		 */
 90		ctrl_info(ctrl, "Latch open on Slot(%s)\n", slot_name(p_slot));
 91		event_type = INT_SWITCH_OPEN;
 92	} else {
 93		/*
 94		 *  Switch closed
 95		 */
 96		ctrl_info(ctrl, "Latch close on Slot(%s)\n", slot_name(p_slot));
 97		event_type = INT_SWITCH_CLOSE;
 98	}
 99
100	queue_interrupt_event(p_slot, event_type);
101
102	return 1;
103}
104
105u8 pciehp_handle_presence_change(struct slot *p_slot)
106{
107	u32 event_type;
108	u8 presence_save;
109	struct controller *ctrl = p_slot->ctrl;
110
111	/* Presence Change */
112	ctrl_dbg(ctrl, "Presence/Notify input change\n");
113
114	/* Switch is open, assume a presence change
115	 * Save the presence state
116	 */
117	pciehp_get_adapter_status(p_slot, &presence_save);
118	if (presence_save) {
119		/*
120		 * Card Present
121		 */
122		ctrl_info(ctrl, "Card present on Slot(%s)\n", slot_name(p_slot));
123		event_type = INT_PRESENCE_ON;
124	} else {
125		/*
126		 * Not Present
127		 */
128		ctrl_info(ctrl, "Card not present on Slot(%s)\n",
129			  slot_name(p_slot));
130		event_type = INT_PRESENCE_OFF;
131	}
132
133	queue_interrupt_event(p_slot, event_type);
134
135	return 1;
136}
137
138u8 pciehp_handle_power_fault(struct slot *p_slot)
139{
140	u32 event_type;
141	struct controller *ctrl = p_slot->ctrl;
142
143	/* power fault */
144	ctrl_dbg(ctrl, "Power fault interrupt received\n");
145	ctrl_err(ctrl, "Power fault on slot %s\n", slot_name(p_slot));
146	event_type = INT_POWER_FAULT;
147	ctrl_info(ctrl, "Power fault bit %x set\n", 0);
148	queue_interrupt_event(p_slot, event_type);
149
150	return 1;
151}
152
153void pciehp_handle_linkstate_change(struct slot *p_slot)
154{
155	u32 event_type;
156	struct controller *ctrl = p_slot->ctrl;
157
158	/* Link Status Change */
159	ctrl_dbg(ctrl, "Data Link Layer State change\n");
160
161	if (pciehp_check_link_active(ctrl)) {
162		ctrl_info(ctrl, "slot(%s): Link Up event\n",
163			  slot_name(p_slot));
164		event_type = INT_LINK_UP;
165	} else {
166		ctrl_info(ctrl, "slot(%s): Link Down event\n",
167			  slot_name(p_slot));
168		event_type = INT_LINK_DOWN;
169	}
170
171	queue_interrupt_event(p_slot, event_type);
172}
173
174/* The following routines constitute the bulk of the
175   hotplug controller logic
176 */
177
178static void set_slot_off(struct controller *ctrl, struct slot * pslot)
 
 
 
179{
180	/* turn off slot, turn on Amber LED, turn off Green LED if supported*/
 
 
 
181	if (POWER_CTRL(ctrl)) {
182		pciehp_power_off_slot(pslot);
183
184		/*
185		 * After turning power off, we must wait for at least 1 second
186		 * before taking any action that relies on power having been
187		 * removed from the slot/adapter.
188		 */
189		msleep(1000);
190	}
191
192	pciehp_green_led_off(pslot);
193	pciehp_set_attention_status(pslot, 1);
194}
195
196/**
197 * board_added - Called after a board has been added to the system.
198 * @p_slot: &slot where board is added
199 *
200 * Turns power on for the board.
201 * Configures board.
202 */
203static int board_added(struct slot *p_slot)
204{
205	int retval = 0;
206	struct controller *ctrl = p_slot->ctrl;
207	struct pci_bus *parent = ctrl->pcie->port->subordinate;
208
209	if (POWER_CTRL(ctrl)) {
210		/* Power on slot */
211		retval = pciehp_power_on_slot(p_slot);
212		if (retval)
213			return retval;
214	}
215
216	pciehp_green_led_blink(p_slot);
 
217
218	/* Check link training status */
219	retval = pciehp_check_link_status(ctrl);
220	if (retval) {
221		ctrl_err(ctrl, "Failed to check link status\n");
222		goto err_exit;
223	}
224
225	/* Check for a power fault */
226	if (ctrl->power_fault_detected || pciehp_query_power_fault(p_slot)) {
227		ctrl_err(ctrl, "Power fault on slot %s\n", slot_name(p_slot));
228		retval = -EIO;
229		goto err_exit;
230	}
231
232	retval = pciehp_configure_device(p_slot);
233	if (retval) {
234		ctrl_err(ctrl, "Cannot add device at %04x:%02x:00\n",
235			 pci_domain_nr(parent), parent->number);
236		if (retval != -EEXIST)
237			goto err_exit;
 
238	}
239
240	pciehp_green_led_on(p_slot);
 
241	return 0;
242
243err_exit:
244	set_slot_off(ctrl, p_slot);
245	return retval;
246}
247
248/**
249 * remove_board - Turns off slot and LEDs
250 * @p_slot: slot where board is being removed
 
251 */
252static int remove_board(struct slot *p_slot)
253{
254	int retval;
255	struct controller *ctrl = p_slot->ctrl;
256
257	retval = pciehp_unconfigure_device(p_slot);
258	if (retval)
259		return retval;
260
261	if (POWER_CTRL(ctrl)) {
262		pciehp_power_off_slot(p_slot);
263
264		/*
265		 * After turning power off, we must wait for at least 1 second
266		 * before taking any action that relies on power having been
267		 * removed from the slot/adapter.
268		 */
269		msleep(1000);
 
 
 
 
270	}
271
272	/* turn off Green LED */
273	pciehp_green_led_off(p_slot);
274	return 0;
275}
276
277struct power_work_info {
278	struct slot *p_slot;
279	struct work_struct work;
280	unsigned int req;
281#define DISABLE_REQ 0
282#define ENABLE_REQ  1
283};
284
285/**
286 * pciehp_power_thread - handle pushbutton events
287 * @work: &struct work_struct describing work to be done
288 *
289 * Scheduled procedure to handle blocking stuff for the pushbuttons.
290 * Handles all pending events and exits.
291 */
292static void pciehp_power_thread(struct work_struct *work)
293{
294	struct power_work_info *info =
295		container_of(work, struct power_work_info, work);
296	struct slot *p_slot = info->p_slot;
297	int ret;
298
299	switch (info->req) {
300	case DISABLE_REQ:
301		ctrl_dbg(p_slot->ctrl,
302			 "Disabling domain:bus:device=%04x:%02x:00\n",
303			 pci_domain_nr(p_slot->ctrl->pcie->port->subordinate),
304			 p_slot->ctrl->pcie->port->subordinate->number);
305		mutex_lock(&p_slot->hotplug_lock);
306		pciehp_disable_slot(p_slot);
307		mutex_unlock(&p_slot->hotplug_lock);
308		mutex_lock(&p_slot->lock);
309		p_slot->state = STATIC_STATE;
310		mutex_unlock(&p_slot->lock);
311		break;
312	case ENABLE_REQ:
313		ctrl_dbg(p_slot->ctrl,
314			 "Enabling domain:bus:device=%04x:%02x:00\n",
315			 pci_domain_nr(p_slot->ctrl->pcie->port->subordinate),
316			 p_slot->ctrl->pcie->port->subordinate->number);
317		mutex_lock(&p_slot->hotplug_lock);
318		ret = pciehp_enable_slot(p_slot);
319		mutex_unlock(&p_slot->hotplug_lock);
320		if (ret)
321			pciehp_green_led_off(p_slot);
322		mutex_lock(&p_slot->lock);
323		p_slot->state = STATIC_STATE;
324		mutex_unlock(&p_slot->lock);
325		break;
326	default:
327		break;
328	}
329
330	kfree(info);
331}
332
333void pciehp_queue_pushbutton_work(struct work_struct *work)
334{
335	struct slot *p_slot = container_of(work, struct slot, work.work);
336	struct power_work_info *info;
337
338	info = kmalloc(sizeof(*info), GFP_KERNEL);
339	if (!info) {
340		ctrl_err(p_slot->ctrl, "%s: Cannot allocate memory\n",
341			 __func__);
342		return;
343	}
344	info->p_slot = p_slot;
345	INIT_WORK(&info->work, pciehp_power_thread);
346
347	mutex_lock(&p_slot->lock);
348	switch (p_slot->state) {
349	case BLINKINGOFF_STATE:
350		p_slot->state = POWEROFF_STATE;
351		info->req = DISABLE_REQ;
352		break;
353	case BLINKINGON_STATE:
354		p_slot->state = POWERON_STATE;
355		info->req = ENABLE_REQ;
356		break;
357	default:
358		kfree(info);
359		goto out;
360	}
361	queue_work(p_slot->wq, &info->work);
362 out:
363	mutex_unlock(&p_slot->lock);
364}
365
366/*
367 * Note: This function must be called with slot->lock held
368 */
369static void handle_button_press_event(struct slot *p_slot)
370{
371	struct controller *ctrl = p_slot->ctrl;
372	u8 getstatus;
373
374	switch (p_slot->state) {
375	case STATIC_STATE:
376		pciehp_get_power_status(p_slot, &getstatus);
377		if (getstatus) {
378			p_slot->state = BLINKINGOFF_STATE;
379			ctrl_info(ctrl,
380				  "PCI slot #%s - powering off due to button "
381				  "press.\n", slot_name(p_slot));
382		} else {
383			p_slot->state = BLINKINGON_STATE;
384			ctrl_info(ctrl,
385				  "PCI slot #%s - powering on due to button "
386				  "press.\n", slot_name(p_slot));
387		}
388		/* blink green LED and turn off amber */
389		pciehp_green_led_blink(p_slot);
390		pciehp_set_attention_status(p_slot, 0);
391		queue_delayed_work(p_slot->wq, &p_slot->work, 5*HZ);
392		break;
393	case BLINKINGOFF_STATE:
394	case BLINKINGON_STATE:
395		/*
396		 * Cancel if we are still blinking; this means that we
397		 * press the attention again before the 5 sec. limit
398		 * expires to cancel hot-add or hot-remove
399		 */
400		ctrl_info(ctrl, "Button cancel on Slot(%s)\n", slot_name(p_slot));
401		cancel_delayed_work(&p_slot->work);
402		if (p_slot->state == BLINKINGOFF_STATE)
403			pciehp_green_led_on(p_slot);
404		else
405			pciehp_green_led_off(p_slot);
406		pciehp_set_attention_status(p_slot, 0);
407		ctrl_info(ctrl, "PCI slot #%s - action canceled "
408			  "due to button press\n", slot_name(p_slot));
409		p_slot->state = STATIC_STATE;
410		break;
411	case POWEROFF_STATE:
412	case POWERON_STATE:
413		/*
414		 * Ignore if the slot is on power-on or power-off state;
415		 * this means that the previous attention button action
416		 * to hot-add or hot-remove is undergoing
417		 */
418		ctrl_info(ctrl, "Button ignore on Slot(%s)\n", slot_name(p_slot));
419		break;
420	default:
421		ctrl_warn(ctrl, "Not a valid state\n");
 
422		break;
423	}
 
424}
425
426/*
427 * Note: This function must be called with slot->lock held
428 */
429static void handle_surprise_event(struct slot *p_slot)
430{
431	u8 getstatus;
432	struct power_work_info *info;
433
434	info = kmalloc(sizeof(*info), GFP_KERNEL);
435	if (!info) {
436		ctrl_err(p_slot->ctrl, "%s: Cannot allocate memory\n",
437			 __func__);
438		return;
439	}
440	info->p_slot = p_slot;
441	INIT_WORK(&info->work, pciehp_power_thread);
442
443	pciehp_get_adapter_status(p_slot, &getstatus);
444	if (!getstatus) {
445		p_slot->state = POWEROFF_STATE;
446		info->req = DISABLE_REQ;
447	} else {
448		p_slot->state = POWERON_STATE;
449		info->req = ENABLE_REQ;
450	}
 
 
451
452	queue_work(p_slot->wq, &info->work);
453}
454
455/*
456 * Note: This function must be called with slot->lock held
457 */
458static void handle_link_event(struct slot *p_slot, u32 event)
459{
460	struct controller *ctrl = p_slot->ctrl;
461	struct power_work_info *info;
462
463	info = kmalloc(sizeof(*info), GFP_KERNEL);
464	if (!info) {
465		ctrl_err(p_slot->ctrl, "%s: Cannot allocate memory\n",
466			 __func__);
467		return;
468	}
469	info->p_slot = p_slot;
470	info->req = event == INT_LINK_UP ? ENABLE_REQ : DISABLE_REQ;
471	INIT_WORK(&info->work, pciehp_power_thread);
472
473	switch (p_slot->state) {
474	case BLINKINGON_STATE:
475	case BLINKINGOFF_STATE:
476		cancel_delayed_work(&p_slot->work);
477		/* Fall through */
478	case STATIC_STATE:
479		p_slot->state = event == INT_LINK_UP ?
480		    POWERON_STATE : POWEROFF_STATE;
481		queue_work(p_slot->wq, &info->work);
482		break;
483	case POWERON_STATE:
484		if (event == INT_LINK_UP) {
485			ctrl_info(ctrl,
486				  "Link Up event ignored on slot(%s): already powering on\n",
487				  slot_name(p_slot));
488			kfree(info);
489		} else {
490			ctrl_info(ctrl,
491				  "Link Down event queued on slot(%s): currently getting powered on\n",
492				  slot_name(p_slot));
493			p_slot->state = POWEROFF_STATE;
494			queue_work(p_slot->wq, &info->work);
495		}
496		break;
497	case POWEROFF_STATE:
498		if (event == INT_LINK_UP) {
499			ctrl_info(ctrl,
500				  "Link Up event queued on slot(%s): currently getting powered off\n",
501				  slot_name(p_slot));
502			p_slot->state = POWERON_STATE;
503			queue_work(p_slot->wq, &info->work);
504		} else {
505			ctrl_info(ctrl,
506				  "Link Down event ignored on slot(%s): already powering off\n",
507				  slot_name(p_slot));
508			kfree(info);
509		}
510		break;
511	default:
512		ctrl_err(ctrl, "Not a valid state on slot(%s)\n",
513			 slot_name(p_slot));
514		kfree(info);
515		break;
516	}
517}
518
519static void interrupt_event_handler(struct work_struct *work)
520{
521	struct event_info *info = container_of(work, struct event_info, work);
522	struct slot *p_slot = info->p_slot;
523	struct controller *ctrl = p_slot->ctrl;
 
 
 
524
525	mutex_lock(&p_slot->lock);
526	switch (info->event_type) {
527	case INT_BUTTON_PRESS:
528		handle_button_press_event(p_slot);
529		break;
530	case INT_POWER_FAULT:
531		if (!POWER_CTRL(ctrl))
532			break;
533		pciehp_set_attention_status(p_slot, 1);
534		pciehp_green_led_off(p_slot);
535		break;
536	case INT_PRESENCE_ON:
537		if (!HP_SUPR_RM(ctrl))
538			break;
539		ctrl_dbg(ctrl, "Surprise Insertion\n");
540		handle_surprise_event(p_slot);
541		break;
542	case INT_PRESENCE_OFF:
543		/*
544		 * Regardless of surprise capability, we need to
545		 * definitely remove a card that has been pulled out!
546		 */
547		ctrl_dbg(ctrl, "Surprise Removal\n");
548		handle_surprise_event(p_slot);
549		break;
550	case INT_LINK_UP:
551	case INT_LINK_DOWN:
552		handle_link_event(p_slot, info->event_type);
553		break;
554	default:
 
555		break;
556	}
557	mutex_unlock(&p_slot->lock);
558
559	kfree(info);
560}
561
562/*
563 * Note: This function must be called with slot->hotplug_lock held
564 */
565int pciehp_enable_slot(struct slot *p_slot)
566{
567	u8 getstatus = 0;
568	int rc;
569	struct controller *ctrl = p_slot->ctrl;
570
571	pciehp_get_adapter_status(p_slot, &getstatus);
572	if (!getstatus) {
573		ctrl_info(ctrl, "No adapter on slot(%s)\n", slot_name(p_slot));
574		return -ENODEV;
575	}
576	if (MRL_SENS(p_slot->ctrl)) {
577		pciehp_get_latch_status(p_slot, &getstatus);
578		if (getstatus) {
579			ctrl_info(ctrl, "Latch open on slot(%s)\n",
580				  slot_name(p_slot));
581			return -ENODEV;
582		}
583	}
584
585	if (POWER_CTRL(p_slot->ctrl)) {
586		pciehp_get_power_status(p_slot, &getstatus);
587		if (getstatus) {
588			ctrl_info(ctrl, "Already enabled on slot(%s)\n",
589				  slot_name(p_slot));
590			return -EINVAL;
591		}
592	}
593
594	pciehp_get_latch_status(p_slot, &getstatus);
 
595
596	rc = board_added(p_slot);
597	if (rc)
598		pciehp_get_latch_status(p_slot, &getstatus);
599
600	return rc;
 
 
 
 
 
 
 
 
 
 
 
 
601}
602
603/*
604 * Note: This function must be called with slot->hotplug_lock held
605 */
606int pciehp_disable_slot(struct slot *p_slot)
607{
608	u8 getstatus = 0;
609	struct controller *ctrl = p_slot->ctrl;
610
611	if (!p_slot->ctrl)
612		return 1;
613
614	if (POWER_CTRL(p_slot->ctrl)) {
615		pciehp_get_power_status(p_slot, &getstatus);
616		if (!getstatus) {
617			ctrl_info(ctrl, "Already disabled on slot(%s)\n",
618				  slot_name(p_slot));
619			return -EINVAL;
620		}
621	}
622
623	return remove_board(p_slot);
 
624}
625
626int pciehp_sysfs_enable_slot(struct slot *p_slot)
627{
628	int retval = -ENODEV;
629	struct controller *ctrl = p_slot->ctrl;
 
 
 
630
631	mutex_lock(&p_slot->lock);
632	switch (p_slot->state) {
 
 
 
 
 
 
 
 
 
 
 
633	case BLINKINGON_STATE:
634		cancel_delayed_work(&p_slot->work);
635	case STATIC_STATE:
636		p_slot->state = POWERON_STATE;
637		mutex_unlock(&p_slot->lock);
638		mutex_lock(&p_slot->hotplug_lock);
639		retval = pciehp_enable_slot(p_slot);
640		mutex_unlock(&p_slot->hotplug_lock);
641		mutex_lock(&p_slot->lock);
642		p_slot->state = STATIC_STATE;
643		break;
 
 
644	case POWERON_STATE:
645		ctrl_info(ctrl, "Slot %s is already in powering on state\n",
646			  slot_name(p_slot));
647		break;
648	case BLINKINGOFF_STATE:
 
649	case POWEROFF_STATE:
650		ctrl_info(ctrl, "Already enabled on slot %s\n",
651			  slot_name(p_slot));
652		break;
653	default:
654		ctrl_err(ctrl, "Not a valid state on slot %s\n",
655			 slot_name(p_slot));
656		break;
657	}
658	mutex_unlock(&p_slot->lock);
659
660	return retval;
661}
662
663int pciehp_sysfs_disable_slot(struct slot *p_slot)
664{
665	int retval = -ENODEV;
666	struct controller *ctrl = p_slot->ctrl;
667
668	mutex_lock(&p_slot->lock);
669	switch (p_slot->state) {
670	case BLINKINGOFF_STATE:
671		cancel_delayed_work(&p_slot->work);
672	case STATIC_STATE:
673		p_slot->state = POWEROFF_STATE;
674		mutex_unlock(&p_slot->lock);
675		retval = pciehp_disable_slot(p_slot);
676		mutex_lock(&p_slot->lock);
677		p_slot->state = STATIC_STATE;
678		break;
679	case POWEROFF_STATE:
680		ctrl_info(ctrl, "Slot %s is already in powering off state\n",
681			  slot_name(p_slot));
682		break;
683	case BLINKINGON_STATE:
 
684	case POWERON_STATE:
685		ctrl_info(ctrl, "Already disabled on slot %s\n",
686			  slot_name(p_slot));
687		break;
688	default:
689		ctrl_err(ctrl, "Not a valid state on slot %s\n",
690			 slot_name(p_slot));
691		break;
692	}
693	mutex_unlock(&p_slot->lock);
694
695	return retval;
696}
v5.9
  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#include "pciehp.h"
 23
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 24/* The following routines constitute the bulk of the
 25   hotplug controller logic
 26 */
 27
 28#define SAFE_REMOVAL	 true
 29#define SURPRISE_REMOVAL false
 30
 31static void set_slot_off(struct controller *ctrl)
 32{
 33	/*
 34	 * Turn off slot, turn on attention indicator, turn off power
 35	 * indicator
 36	 */
 37	if (POWER_CTRL(ctrl)) {
 38		pciehp_power_off_slot(ctrl);
 39
 40		/*
 41		 * After turning power off, we must wait for at least 1 second
 42		 * before taking any action that relies on power having been
 43		 * removed from the slot/adapter.
 44		 */
 45		msleep(1000);
 46	}
 47
 48	pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
 49			      PCI_EXP_SLTCTL_ATTN_IND_ON);
 50}
 51
 52/**
 53 * board_added - Called after a board has been added to the system.
 54 * @ctrl: PCIe hotplug controller where board is added
 55 *
 56 * Turns power on for the board.
 57 * Configures board.
 58 */
 59static int board_added(struct controller *ctrl)
 60{
 61	int retval = 0;
 
 62	struct pci_bus *parent = ctrl->pcie->port->subordinate;
 63
 64	if (POWER_CTRL(ctrl)) {
 65		/* Power on slot */
 66		retval = pciehp_power_on_slot(ctrl);
 67		if (retval)
 68			return retval;
 69	}
 70
 71	pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_BLINK,
 72			      INDICATOR_NOOP);
 73
 74	/* Check link training status */
 75	retval = pciehp_check_link_status(ctrl);
 76	if (retval) {
 77		ctrl_err(ctrl, "Failed to check link status\n");
 78		goto err_exit;
 79	}
 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
101err_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 */
111static 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
134static int pciehp_enable_slot(struct controller *ctrl);
135static int pciehp_disable_slot(struct controller *ctrl, bool safe_removal);
 
 
 
 
 
136
137void pciehp_request(struct controller *ctrl, int action)
 
 
 
 
 
 
 
138{
139	atomic_or(action, &ctrl->pending_events);
140	if (!pciehp_poll_mode)
141		irq_wake_thread(ctrl->pcie->irq, ctrl);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
142}
143
144void pciehp_queue_pushbutton_work(struct work_struct *work)
145{
146	struct controller *ctrl = container_of(work, struct controller,
147					       button_work.work);
 
 
 
 
 
 
 
 
 
148
149	mutex_lock(&ctrl->state_lock);
150	switch (ctrl->state) {
151	case BLINKINGOFF_STATE:
152		pciehp_request(ctrl, DISABLE_SLOT);
 
153		break;
154	case BLINKINGON_STATE:
155		pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC);
 
156		break;
157	default:
158		break;
 
159	}
160	mutex_unlock(&ctrl->state_lock);
 
 
161}
162
163void pciehp_handle_button_press(struct controller *ctrl)
 
 
 
164{
165	mutex_lock(&ctrl->state_lock);
166	switch (ctrl->state) {
167	case OFF_STATE:
168	case ON_STATE:
169		if (ctrl->state == ON_STATE) {
170			ctrl->state = BLINKINGOFF_STATE;
171			ctrl_info(ctrl, "Slot(%s): Powering off due to button press\n",
172				  slot_name(ctrl));
 
 
 
173		} else {
174			ctrl->state = BLINKINGON_STATE;
175			ctrl_info(ctrl, "Slot(%s) Powering on due to button press\n",
176				  slot_name(ctrl));
 
177		}
178		/* blink power indicator and turn off attention */
179		pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_BLINK,
180				      PCI_EXP_SLTCTL_ATTN_IND_OFF);
181		schedule_delayed_work(&ctrl->button_work, 5 * HZ);
182		break;
183	case BLINKINGOFF_STATE:
184	case BLINKINGON_STATE:
185		/*
186		 * Cancel if we are still blinking; this means that we
187		 * press the attention again before the 5 sec. limit
188		 * expires to cancel hot-add or hot-remove
189		 */
190		ctrl_info(ctrl, "Slot(%s): Button cancel\n", slot_name(ctrl));
191		cancel_delayed_work(&ctrl->button_work);
192		if (ctrl->state == BLINKINGOFF_STATE) {
193			ctrl->state = ON_STATE;
194			pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_ON,
195					      PCI_EXP_SLTCTL_ATTN_IND_OFF);
196		} else {
197			ctrl->state = OFF_STATE;
198			pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
199					      PCI_EXP_SLTCTL_ATTN_IND_OFF);
200		}
201		ctrl_info(ctrl, "Slot(%s): Action canceled due to button press\n",
202			  slot_name(ctrl));
 
 
 
 
 
 
203		break;
204	default:
205		ctrl_err(ctrl, "Slot(%s): Ignoring invalid state %#x\n",
206			 slot_name(ctrl), ctrl->state);
207		break;
208	}
209	mutex_unlock(&ctrl->state_lock);
210}
211
212void pciehp_handle_disable_request(struct controller *ctrl)
 
 
 
213{
214	mutex_lock(&ctrl->state_lock);
215	switch (ctrl->state) {
216	case BLINKINGON_STATE:
217	case BLINKINGOFF_STATE:
218		cancel_delayed_work(&ctrl->button_work);
219		break;
 
 
 
 
 
 
 
 
 
 
 
 
 
220	}
221	ctrl->state = POWEROFF_STATE;
222	mutex_unlock(&ctrl->state_lock);
223
224	ctrl->request_result = pciehp_disable_slot(ctrl, SAFE_REMOVAL);
225}
226
227void pciehp_handle_presence_or_link_change(struct controller *ctrl, u32 events)
 
 
 
228{
229	int present, link_active;
 
230
231	/*
232	 * If the slot is on and presence or link has changed, turn it off.
233	 * Even if it's occupied again, we cannot assume the card is the same.
234	 */
235	mutex_lock(&ctrl->state_lock);
236	switch (ctrl->state) {
 
 
 
 
 
 
237	case BLINKINGOFF_STATE:
238		cancel_delayed_work(&ctrl->button_work);
239		fallthrough;
240	case ON_STATE:
241		ctrl->state = POWEROFF_STATE;
242		mutex_unlock(&ctrl->state_lock);
243		if (events & PCI_EXP_SLTSTA_DLLSC)
244			ctrl_info(ctrl, "Slot(%s): Link Down\n",
245				  slot_name(ctrl));
246		if (events & PCI_EXP_SLTSTA_PDC)
247			ctrl_info(ctrl, "Slot(%s): Card not present\n",
248				  slot_name(ctrl));
249		pciehp_disable_slot(ctrl, SURPRISE_REMOVAL);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
250		break;
251	default:
252		mutex_unlock(&ctrl->state_lock);
 
 
253		break;
254	}
 
255
256	/* Turn the slot on if it's occupied or link is up */
257	mutex_lock(&ctrl->state_lock);
258	present = pciehp_card_present(ctrl);
259	link_active = pciehp_check_link_active(ctrl);
260	if (present <= 0 && link_active <= 0) {
261		mutex_unlock(&ctrl->state_lock);
262		return;
263	}
264
265	switch (ctrl->state) {
266	case BLINKINGON_STATE:
267		cancel_delayed_work(&ctrl->button_work);
268		fallthrough;
269	case OFF_STATE:
270		ctrl->state = POWERON_STATE;
271		mutex_unlock(&ctrl->state_lock);
272		if (present)
273			ctrl_info(ctrl, "Slot(%s): Card present\n",
274				  slot_name(ctrl));
275		if (link_active)
276			ctrl_info(ctrl, "Slot(%s): Link Up\n",
277				  slot_name(ctrl));
278		ctrl->request_result = pciehp_enable_slot(ctrl);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
279		break;
280	default:
281		mutex_unlock(&ctrl->state_lock);
282		break;
283	}
 
 
 
284}
285
286static int __pciehp_enable_slot(struct controller *ctrl)
 
 
 
287{
288	u8 getstatus = 0;
 
 
289
290	if (MRL_SENS(ctrl)) {
291		pciehp_get_latch_status(ctrl, &getstatus);
 
 
 
 
 
292		if (getstatus) {
293			ctrl_info(ctrl, "Slot(%s): Latch open\n",
294				  slot_name(ctrl));
295			return -ENODEV;
296		}
297	}
298
299	if (POWER_CTRL(ctrl)) {
300		pciehp_get_power_status(ctrl, &getstatus);
301		if (getstatus) {
302			ctrl_info(ctrl, "Slot(%s): Already enabled\n",
303				  slot_name(ctrl));
304			return 0;
305		}
306	}
307
308	return board_added(ctrl);
309}
310
311static int pciehp_enable_slot(struct controller *ctrl)
312{
313	int ret;
314
315	pm_runtime_get_sync(&ctrl->pcie->port->dev);
316	ret = __pciehp_enable_slot(ctrl);
317	if (ret && ATTN_BUTTN(ctrl))
318		/* may be blinking */
319		pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
320				      INDICATOR_NOOP);
321	pm_runtime_put(&ctrl->pcie->port->dev);
322
323	mutex_lock(&ctrl->state_lock);
324	ctrl->state = ret ? OFF_STATE : ON_STATE;
325	mutex_unlock(&ctrl->state_lock);
326
327	return ret;
328}
329
330static int __pciehp_disable_slot(struct controller *ctrl, bool safe_removal)
 
 
 
331{
332	u8 getstatus = 0;
 
333
334	if (POWER_CTRL(ctrl)) {
335		pciehp_get_power_status(ctrl, &getstatus);
 
 
 
336		if (!getstatus) {
337			ctrl_info(ctrl, "Slot(%s): Already disabled\n",
338				  slot_name(ctrl));
339			return -EINVAL;
340		}
341	}
342
343	remove_board(ctrl, safe_removal);
344	return 0;
345}
346
347static int pciehp_disable_slot(struct controller *ctrl, bool safe_removal)
348{
349	int ret;
350
351	pm_runtime_get_sync(&ctrl->pcie->port->dev);
352	ret = __pciehp_disable_slot(ctrl, safe_removal);
353	pm_runtime_put(&ctrl->pcie->port->dev);
354
355	mutex_lock(&ctrl->state_lock);
356	ctrl->state = OFF_STATE;
357	mutex_unlock(&ctrl->state_lock);
358
359	return ret;
360}
361
362int pciehp_sysfs_enable_slot(struct hotplug_slot *hotplug_slot)
363{
364	struct controller *ctrl = to_ctrl(hotplug_slot);
365
366	mutex_lock(&ctrl->state_lock);
367	switch (ctrl->state) {
368	case BLINKINGON_STATE:
369	case OFF_STATE:
370		mutex_unlock(&ctrl->state_lock);
371		/*
372		 * The IRQ thread becomes a no-op if the user pulls out the
373		 * card before the thread wakes up, so initialize to -ENODEV.
374		 */
375		ctrl->request_result = -ENODEV;
376		pciehp_request(ctrl, PCI_EXP_SLTSTA_PDC);
377		wait_event(ctrl->requester,
378			   !atomic_read(&ctrl->pending_events) &&
379			   !ctrl->ist_running);
380		return ctrl->request_result;
381	case POWERON_STATE:
382		ctrl_info(ctrl, "Slot(%s): Already in powering on state\n",
383			  slot_name(ctrl));
384		break;
385	case BLINKINGOFF_STATE:
386	case ON_STATE:
387	case POWEROFF_STATE:
388		ctrl_info(ctrl, "Slot(%s): Already enabled\n",
389			  slot_name(ctrl));
390		break;
391	default:
392		ctrl_err(ctrl, "Slot(%s): Invalid state %#x\n",
393			 slot_name(ctrl), ctrl->state);
394		break;
395	}
396	mutex_unlock(&ctrl->state_lock);
397
398	return -ENODEV;
399}
400
401int pciehp_sysfs_disable_slot(struct hotplug_slot *hotplug_slot)
402{
403	struct controller *ctrl = to_ctrl(hotplug_slot);
 
404
405	mutex_lock(&ctrl->state_lock);
406	switch (ctrl->state) {
407	case BLINKINGOFF_STATE:
408	case ON_STATE:
409		mutex_unlock(&ctrl->state_lock);
410		pciehp_request(ctrl, DISABLE_SLOT);
411		wait_event(ctrl->requester,
412			   !atomic_read(&ctrl->pending_events) &&
413			   !ctrl->ist_running);
414		return ctrl->request_result;
 
415	case POWEROFF_STATE:
416		ctrl_info(ctrl, "Slot(%s): Already in powering off state\n",
417			  slot_name(ctrl));
418		break;
419	case BLINKINGON_STATE:
420	case OFF_STATE:
421	case POWERON_STATE:
422		ctrl_info(ctrl, "Slot(%s): Already disabled\n",
423			  slot_name(ctrl));
424		break;
425	default:
426		ctrl_err(ctrl, "Slot(%s): Invalid state %#x\n",
427			 slot_name(ctrl), ctrl->state);
428		break;
429	}
430	mutex_unlock(&ctrl->state_lock);
431
432	return -ENODEV;
433}