Linux Audio

Check our new training course

Loading...
v3.1
 
  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(pciehp_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
153/* The following routines constitute the bulk of the
154   hotplug controller logic
155 */
156
157static void set_slot_off(struct controller *ctrl, struct slot * pslot)
158{
159	/* turn off slot, turn on Amber LED, turn off Green LED if supported*/
160	if (POWER_CTRL(ctrl)) {
161		if (pciehp_power_off_slot(pslot)) {
162			ctrl_err(ctrl,
163				 "Issue of Slot Power Off command failed\n");
164			return;
165		}
166		/*
167		 * After turning power off, we must wait for at least 1 second
168		 * before taking any action that relies on power having been
169		 * removed from the slot/adapter.
170		 */
171		msleep(1000);
172	}
173
174	if (PWR_LED(ctrl))
175		pciehp_green_led_off(pslot);
176
177	if (ATTN_LED(ctrl)) {
178		if (pciehp_set_attention_status(pslot, 1)) {
179			ctrl_err(ctrl,
180				 "Issue of Set Attention Led command failed\n");
181			return;
182		}
183	}
184}
185
186/**
187 * board_added - Called after a board has been added to the system.
188 * @p_slot: &slot where board is added
189 *
190 * Turns power on for the board.
191 * Configures board.
192 */
193static int board_added(struct slot *p_slot)
194{
195	int retval = 0;
196	struct controller *ctrl = p_slot->ctrl;
197	struct pci_bus *parent = ctrl->pcie->port->subordinate;
198
199	if (POWER_CTRL(ctrl)) {
200		/* Power on slot */
201		retval = pciehp_power_on_slot(p_slot);
202		if (retval)
203			return retval;
204	}
205
206	if (PWR_LED(ctrl))
207		pciehp_green_led_blink(p_slot);
208
209	/* Check link training status */
210	retval = pciehp_check_link_status(ctrl);
211	if (retval) {
212		ctrl_err(ctrl, "Failed to check link status\n");
213		goto err_exit;
214	}
215
216	/* Wait for 1 second after checking link training status */
217	msleep(1000);
218
219	/* Check for a power fault */
220	if (ctrl->power_fault_detected || pciehp_query_power_fault(p_slot)) {
221		ctrl_err(ctrl, "Power fault on slot %s\n", slot_name(p_slot));
222		retval = -EIO;
223		goto err_exit;
224	}
225
226	retval = pciehp_configure_device(p_slot);
227	if (retval) {
228		ctrl_err(ctrl, "Cannot add device at %04x:%02x:00\n",
229			 pci_domain_nr(parent), parent->number);
230		goto err_exit;
 
 
231	}
232
233	if (PWR_LED(ctrl))
234		pciehp_green_led_on(p_slot);
235
236	return 0;
237
238err_exit:
239	set_slot_off(ctrl, p_slot);
240	return retval;
241}
242
243/**
244 * remove_board - Turns off slot and LEDs
245 * @p_slot: slot where board is being removed
246 */
247static int remove_board(struct slot *p_slot)
248{
249	int retval = 0;
250	struct controller *ctrl = p_slot->ctrl;
251
252	retval = pciehp_unconfigure_device(p_slot);
253	if (retval)
254		return retval;
255
256	if (POWER_CTRL(ctrl)) {
257		/* power off slot */
258		retval = pciehp_power_off_slot(p_slot);
259		if (retval) {
260			ctrl_err(ctrl,
261				 "Issue of Slot Disable command failed\n");
262			return retval;
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	if (PWR_LED(ctrl))
274		pciehp_green_led_off(p_slot);
275
276	return 0;
277}
278
279struct power_work_info {
280	struct slot *p_slot;
281	struct work_struct work;
 
 
 
282};
283
284/**
285 * pciehp_power_thread - handle pushbutton events
286 * @work: &struct work_struct describing work to be done
287 *
288 * Scheduled procedure to handle blocking stuff for the pushbuttons.
289 * Handles all pending events and exits.
290 */
291static void pciehp_power_thread(struct work_struct *work)
292{
293	struct power_work_info *info =
294		container_of(work, struct power_work_info, work);
295	struct slot *p_slot = info->p_slot;
 
296
297	mutex_lock(&p_slot->lock);
298	switch (p_slot->state) {
299	case POWEROFF_STATE:
300		mutex_unlock(&p_slot->lock);
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		pciehp_disable_slot(p_slot);
 
306		mutex_lock(&p_slot->lock);
307		p_slot->state = STATIC_STATE;
308		break;
309	case POWERON_STATE:
310		mutex_unlock(&p_slot->lock);
311		if (pciehp_enable_slot(p_slot) && PWR_LED(p_slot->ctrl))
 
 
 
 
 
312			pciehp_green_led_off(p_slot);
313		mutex_lock(&p_slot->lock);
314		p_slot->state = STATIC_STATE;
 
315		break;
316	default:
317		break;
318	}
319	mutex_unlock(&p_slot->lock);
320
321	kfree(info);
322}
323
324void pciehp_queue_pushbutton_work(struct work_struct *work)
325{
326	struct slot *p_slot = container_of(work, struct slot, work.work);
327	struct power_work_info *info;
328
 
 
329	info = kmalloc(sizeof(*info), GFP_KERNEL);
330	if (!info) {
331		ctrl_err(p_slot->ctrl, "%s: Cannot allocate memory\n",
332			 __func__);
333		return;
334	}
335	info->p_slot = p_slot;
336	INIT_WORK(&info->work, pciehp_power_thread);
 
 
 
 
 
 
 
337
338	mutex_lock(&p_slot->lock);
339	switch (p_slot->state) {
340	case BLINKINGOFF_STATE:
341		p_slot->state = POWEROFF_STATE;
342		break;
343	case BLINKINGON_STATE:
344		p_slot->state = POWERON_STATE;
345		break;
346	default:
347		kfree(info);
348		goto out;
349	}
350	queue_work(pciehp_ordered_wq, &info->work);
351 out:
352	mutex_unlock(&p_slot->lock);
353}
354
355/*
356 * Note: This function must be called with slot->lock held
357 */
358static void handle_button_press_event(struct slot *p_slot)
359{
360	struct controller *ctrl = p_slot->ctrl;
361	u8 getstatus;
362
363	switch (p_slot->state) {
364	case STATIC_STATE:
365		pciehp_get_power_status(p_slot, &getstatus);
366		if (getstatus) {
367			p_slot->state = BLINKINGOFF_STATE;
368			ctrl_info(ctrl,
369				  "PCI slot #%s - powering off due to button "
370				  "press.\n", slot_name(p_slot));
371		} else {
372			p_slot->state = BLINKINGON_STATE;
373			ctrl_info(ctrl,
374				  "PCI slot #%s - powering on due to button "
375				  "press.\n", slot_name(p_slot));
376		}
377		/* blink green LED and turn off amber */
378		if (PWR_LED(ctrl))
379			pciehp_green_led_blink(p_slot);
380		if (ATTN_LED(ctrl))
381			pciehp_set_attention_status(p_slot, 0);
382
383		queue_delayed_work(pciehp_wq, &p_slot->work, 5*HZ);
384		break;
385	case BLINKINGOFF_STATE:
386	case BLINKINGON_STATE:
387		/*
388		 * Cancel if we are still blinking; this means that we
389		 * press the attention again before the 5 sec. limit
390		 * expires to cancel hot-add or hot-remove
391		 */
392		ctrl_info(ctrl, "Button cancel on Slot(%s)\n", slot_name(p_slot));
393		cancel_delayed_work(&p_slot->work);
394		if (p_slot->state == BLINKINGOFF_STATE) {
395			if (PWR_LED(ctrl))
396				pciehp_green_led_on(p_slot);
397		} else {
398			if (PWR_LED(ctrl))
399				pciehp_green_led_off(p_slot);
400		}
401		if (ATTN_LED(ctrl))
402			pciehp_set_attention_status(p_slot, 0);
403		ctrl_info(ctrl, "PCI slot #%s - action canceled "
404			  "due to button press\n", slot_name(p_slot));
405		p_slot->state = STATIC_STATE;
406		break;
407	case POWEROFF_STATE:
408	case POWERON_STATE:
409		/*
410		 * Ignore if the slot is on power-on or power-off state;
411		 * this means that the previous attention button action
412		 * to hot-add or hot-remove is undergoing
413		 */
414		ctrl_info(ctrl, "Button ignore on Slot(%s)\n", slot_name(p_slot));
 
415		break;
416	default:
417		ctrl_warn(ctrl, "Not a valid state\n");
 
418		break;
419	}
420}
421
422/*
423 * Note: This function must be called with slot->lock held
424 */
425static void handle_surprise_event(struct slot *p_slot)
426{
427	u8 getstatus;
428	struct power_work_info *info;
429
430	info = kmalloc(sizeof(*info), GFP_KERNEL);
431	if (!info) {
432		ctrl_err(p_slot->ctrl, "%s: Cannot allocate memory\n",
433			 __func__);
434		return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
435	}
436	info->p_slot = p_slot;
437	INIT_WORK(&info->work, pciehp_power_thread);
438
439	pciehp_get_adapter_status(p_slot, &getstatus);
440	if (!getstatus)
441		p_slot->state = POWEROFF_STATE;
442	else
443		p_slot->state = POWERON_STATE;
444
445	queue_work(pciehp_ordered_wq, &info->work);
446}
447
448static void interrupt_event_handler(struct work_struct *work)
449{
450	struct event_info *info = container_of(work, struct event_info, work);
451	struct slot *p_slot = info->p_slot;
452	struct controller *ctrl = p_slot->ctrl;
453
454	mutex_lock(&p_slot->lock);
455	switch (info->event_type) {
456	case INT_BUTTON_PRESS:
457		handle_button_press_event(p_slot);
458		break;
459	case INT_POWER_FAULT:
460		if (!POWER_CTRL(ctrl))
461			break;
462		if (ATTN_LED(ctrl))
463			pciehp_set_attention_status(p_slot, 1);
464		if (PWR_LED(ctrl))
465			pciehp_green_led_off(p_slot);
466		break;
467	case INT_PRESENCE_ON:
 
 
468	case INT_PRESENCE_OFF:
469		if (!HP_SUPR_RM(ctrl))
470			break;
471		ctrl_dbg(ctrl, "Surprise Removal\n");
472		handle_surprise_event(p_slot);
 
 
 
 
 
473		break;
474	default:
475		break;
476	}
477	mutex_unlock(&p_slot->lock);
478
479	kfree(info);
480}
481
 
 
 
482int pciehp_enable_slot(struct slot *p_slot)
483{
484	u8 getstatus = 0;
485	int rc;
486	struct controller *ctrl = p_slot->ctrl;
487
488	rc = pciehp_get_adapter_status(p_slot, &getstatus);
489	if (rc || !getstatus) {
490		ctrl_info(ctrl, "No adapter on slot(%s)\n", slot_name(p_slot));
491		return -ENODEV;
492	}
493	if (MRL_SENS(p_slot->ctrl)) {
494		rc = pciehp_get_latch_status(p_slot, &getstatus);
495		if (rc || getstatus) {
496			ctrl_info(ctrl, "Latch open on slot(%s)\n",
497				  slot_name(p_slot));
498			return -ENODEV;
499		}
500	}
501
502	if (POWER_CTRL(p_slot->ctrl)) {
503		rc = pciehp_get_power_status(p_slot, &getstatus);
504		if (rc || getstatus) {
505			ctrl_info(ctrl, "Already enabled on slot(%s)\n",
506				  slot_name(p_slot));
507			return -EINVAL;
508		}
509	}
510
511	pciehp_get_latch_status(p_slot, &getstatus);
512
513	rc = board_added(p_slot);
514	if (rc) {
515		pciehp_get_latch_status(p_slot, &getstatus);
516	}
517	return rc;
518}
519
520
 
 
521int pciehp_disable_slot(struct slot *p_slot)
522{
523	u8 getstatus = 0;
524	int ret = 0;
525	struct controller *ctrl = p_slot->ctrl;
526
527	if (!p_slot->ctrl)
528		return 1;
529
530	if (!HP_SUPR_RM(p_slot->ctrl)) {
531		ret = pciehp_get_adapter_status(p_slot, &getstatus);
532		if (ret || !getstatus) {
533			ctrl_info(ctrl, "No adapter on slot(%s)\n",
534				  slot_name(p_slot));
535			return -ENODEV;
536		}
537	}
538
539	if (MRL_SENS(p_slot->ctrl)) {
540		ret = pciehp_get_latch_status(p_slot, &getstatus);
541		if (ret || getstatus) {
542			ctrl_info(ctrl, "Latch open on slot(%s)\n",
543				  slot_name(p_slot));
544			return -ENODEV;
545		}
546	}
547
548	if (POWER_CTRL(p_slot->ctrl)) {
549		ret = pciehp_get_power_status(p_slot, &getstatus);
550		if (ret || !getstatus) {
551			ctrl_info(ctrl, "Already disabled on slot(%s)\n",
552				  slot_name(p_slot));
553			return -EINVAL;
554		}
555	}
556
557	return remove_board(p_slot);
558}
559
560int pciehp_sysfs_enable_slot(struct slot *p_slot)
561{
562	int retval = -ENODEV;
563	struct controller *ctrl = p_slot->ctrl;
564
565	mutex_lock(&p_slot->lock);
566	switch (p_slot->state) {
567	case BLINKINGON_STATE:
568		cancel_delayed_work(&p_slot->work);
569	case STATIC_STATE:
570		p_slot->state = POWERON_STATE;
571		mutex_unlock(&p_slot->lock);
 
572		retval = pciehp_enable_slot(p_slot);
 
573		mutex_lock(&p_slot->lock);
574		p_slot->state = STATIC_STATE;
575		break;
576	case POWERON_STATE:
577		ctrl_info(ctrl, "Slot %s is already in powering on state\n",
578			  slot_name(p_slot));
579		break;
580	case BLINKINGOFF_STATE:
581	case POWEROFF_STATE:
582		ctrl_info(ctrl, "Already enabled on slot %s\n",
583			  slot_name(p_slot));
584		break;
585	default:
586		ctrl_err(ctrl, "Not a valid state on slot %s\n",
587			 slot_name(p_slot));
588		break;
589	}
590	mutex_unlock(&p_slot->lock);
591
592	return retval;
593}
594
595int pciehp_sysfs_disable_slot(struct slot *p_slot)
596{
597	int retval = -ENODEV;
598	struct controller *ctrl = p_slot->ctrl;
599
600	mutex_lock(&p_slot->lock);
601	switch (p_slot->state) {
602	case BLINKINGOFF_STATE:
603		cancel_delayed_work(&p_slot->work);
604	case STATIC_STATE:
605		p_slot->state = POWEROFF_STATE;
606		mutex_unlock(&p_slot->lock);
 
607		retval = pciehp_disable_slot(p_slot);
 
608		mutex_lock(&p_slot->lock);
609		p_slot->state = STATIC_STATE;
610		break;
611	case POWEROFF_STATE:
612		ctrl_info(ctrl, "Slot %s is already in powering off state\n",
613			  slot_name(p_slot));
614		break;
615	case BLINKINGON_STATE:
616	case POWERON_STATE:
617		ctrl_info(ctrl, "Already disabled on slot %s\n",
618			  slot_name(p_slot));
619		break;
620	default:
621		ctrl_err(ctrl, "Not a valid state on slot %s\n",
622			 slot_name(p_slot));
623		break;
624	}
625	mutex_unlock(&p_slot->lock);
626
627	return retval;
628}
v4.17
  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
 24static void interrupt_event_handler(struct work_struct *work);
 25
 26void 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
 46static 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 */
 71static 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
113err_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 */
122static 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
147struct 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 */
162static 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
195static 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
213void 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 */
234static 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 */
294static 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
334static 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 */
376int 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 */
410int 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
430int 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
467int 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}