Linux Audio

Check our new training course

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