Example #1
0
u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl)
{
	struct slot *p_slot;
	u8 getstatus;
	u32 event_type;

	/* Switch Change */
	dbg("pciehp:  Switch interrupt received.\n");

	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);

	if (getstatus) {
		/*
		 * Switch opened
		 */
		info("Latch open on Slot(%s)\n", p_slot->name);
		event_type = INT_SWITCH_OPEN;
	} else {
		/*
		 *  Switch closed
		 */
		info("Latch close on Slot(%s)\n", p_slot->name);
		event_type = INT_SWITCH_CLOSE;
	}

	queue_interrupt_event(p_slot, event_type);

	return 1;
}
Example #2
0
/**
 * remove_board - Turns off slot and LED's
 *
 */
static int remove_board(struct slot *p_slot)
{
	u8 device;
	u8 hp_slot;
	int retval = 0;
	struct controller *ctrl = p_slot->ctrl;

	retval = pciehp_unconfigure_device(p_slot);
	if (retval)
		return retval;

	device = p_slot->device;
	hp_slot = p_slot->device - ctrl->slot_device_offset;
	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);

	dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);

	if (POWER_CTRL(ctrl->ctrlcap)) {
		/* power off slot */
		retval = p_slot->hpc_ops->power_off_slot(p_slot);
		if (retval) {
			err("%s: Issue of Slot Disable command failed\n",
			    __FUNCTION__);
			return retval;
		}
	}

	if (PWR_LED(ctrl->ctrlcap))
		/* turn off Green LED */
		p_slot->hpc_ops->green_led_off(p_slot);

	return 0;
}
Example #3
0
u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl)
{
	struct slot *p_slot;
	u32 event_type;
	u8 presence_save;

	/* Presence Change */
	dbg("pciehp:  Presence/Notify input change.\n");

	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);

	/* Switch is open, assume a presence change
	 * Save the presence state
	 */
	p_slot->hpc_ops->get_adapter_status(p_slot, &presence_save);
	if (presence_save) {
		/*
		 * Card Present
		 */
		info("Card present on Slot(%s)\n", p_slot->name);
		event_type = INT_PRESENCE_ON;
	} else {
		/*
		 * Not Present
		 */
		info("Card not present on Slot(%s)\n", p_slot->name);
		event_type = INT_PRESENCE_OFF;
	}

	queue_interrupt_event(p_slot, event_type);

	return 1;
}
Example #4
0
u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl)
{
	struct slot *p_slot;
	u32 event_type;

	/* power fault */
	dbg("pciehp:  Power fault interrupt received.\n");

	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);

	if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) {
		/*
		 * power fault Cleared
		 */
		info("Power fault cleared on Slot(%s)\n", p_slot->name);
		event_type = INT_POWER_FAULT_CLEAR;
	} else {
		/*
		 *   power fault
		 */
		info("Power fault on Slot(%s)\n", p_slot->name);
		event_type = INT_POWER_FAULT;
		info("power fault bit %x set\n", hp_slot);
	}

	queue_interrupt_event(p_slot, event_type);

	return 1;
}
Example #5
0
u8 pciehp_handle_attention_button(u8 hp_slot, void *inst_id)
{
	struct controller *ctrl = (struct controller *) inst_id;
	struct slot *p_slot;
	u8 rc = 0;
	u8 getstatus;
	struct event_info *taskInfo;

	/* Attention Button Change */
	dbg("pciehp:  Attention button interrupt received.\n");
	
	/* This is the structure that tells the worker thread what to do */
	taskInfo = &(ctrl->event_queue[ctrl->next_event]);
	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);

	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);
	
	ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS;
	taskInfo->hp_slot = hp_slot;

	rc++;

	/*
	 *  Button pressed - See if need to TAKE ACTION!!!
	 */
	info("Button pressed on Slot(%d)\n", ctrl->first_slot + hp_slot);
	taskInfo->event_type = INT_BUTTON_PRESS;

	if ((p_slot->state == BLINKINGON_STATE)
	    || (p_slot->state == BLINKINGOFF_STATE)) {
		/* Cancel if we are still blinking; this means that we press the
		 * attention again before the 5 sec. limit expires to cancel hot-add
		 * or hot-remove
		 */
		taskInfo->event_type = INT_BUTTON_CANCEL;
		info("Button cancel on Slot(%d)\n", ctrl->first_slot + hp_slot);
	} else if ((p_slot->state == POWERON_STATE)
		   || (p_slot->state == POWEROFF_STATE)) {
		/* Ignore if the slot is on power-on or power-off state; this 
		 * means that the previous attention button action to hot-add or
		 * hot-remove is undergoing
		 */
		taskInfo->event_type = INT_BUTTON_IGNORE;
		info("Button ignore on Slot(%d)\n", ctrl->first_slot + hp_slot);
	}

	if (rc)
		up(&event_semaphore);	/* signal event thread that new event is posted */

	return 0;

}
Example #6
0
/**
 * remove_board - Turns off slot and LED's
 *
 */
static int remove_board(struct slot *p_slot)
{
	u8 device;
	u8 hp_slot;
	int rc;
	struct controller *ctrl = p_slot->ctrl;

	if (pciehp_unconfigure_device(p_slot))
		return 1;

	device = p_slot->device;

	hp_slot = p_slot->device - ctrl->slot_device_offset;
	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);

	dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot);

	/* Wait for exclusive access to hardware */
	down(&ctrl->crit_sect);

	if (POWER_CTRL(ctrl->ctrlcap)) {
		/* power off slot */
		rc = p_slot->hpc_ops->power_off_slot(p_slot);
		if (rc) {
			err("%s: Issue of Slot Disable command failed\n", __FUNCTION__);
			up(&ctrl->crit_sect);
			return rc;
		}
		/* Wait for the command to complete */
		wait_for_ctrl_irq (ctrl);
	}

	if (PWR_LED(ctrl->ctrlcap)) {
		/* turn off Green LED */
		p_slot->hpc_ops->green_led_off(p_slot);
	
		/* Wait for the command to complete */
		wait_for_ctrl_irq (ctrl);
	}

	/* Done with exclusive hardware access */
	up(&ctrl->crit_sect);

	return 0;
}
Example #7
0
u8 pciehp_handle_presence_change(u8 hp_slot, void *inst_id)
{
	struct controller *ctrl = (struct controller *) inst_id;
	struct slot *p_slot;
	u8 presence_save, rc = 0;
	struct event_info *taskInfo;

	/* Presence Change */
	dbg("pciehp:  Presence/Notify input change.\n");

	/* This is the structure that tells the worker thread
	 * what to do
	 */
	taskInfo = &(ctrl->event_queue[ctrl->next_event]);
	ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS;
	taskInfo->hp_slot = hp_slot;

	rc++;
	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);

	/* Switch is open, assume a presence change
	 * Save the presence state
	 */
	p_slot->hpc_ops->get_adapter_status(p_slot, &presence_save);
	if (presence_save) {
		/*
		 * Card Present
		 */
		info("Card present on Slot(%d)\n", ctrl->first_slot + hp_slot);
		taskInfo->event_type = INT_PRESENCE_ON;
	} else {
		/*
		 * Not Present
		 */
		info("Card not present on Slot(%d)\n", ctrl->first_slot + hp_slot);
		taskInfo->event_type = INT_PRESENCE_OFF;
	}

	if (rc)
		up(&event_semaphore);	/* signal event thread that new event is posted */

	return rc;
}
Example #8
0
u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl)
{
	struct slot *p_slot;
	u32 event_type;

	/* Attention Button Change */
	dbg("pciehp:  Attention button interrupt received.\n");

	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);

	/*
	 *  Button pressed - See if need to TAKE ACTION!!!
	 */
	info("Button pressed on Slot(%s)\n", p_slot->name);
	event_type = INT_BUTTON_PRESS;

	queue_interrupt_event(p_slot, event_type);

	return 0;
}
Example #9
0
u8 pciehp_handle_switch_change(u8 hp_slot, void *inst_id)
{
	struct controller *ctrl = (struct controller *) inst_id;
	struct slot *p_slot;
	u8 rc = 0;
	u8 getstatus;
	struct event_info *taskInfo;

	/* Switch Change */
	dbg("pciehp:  Switch interrupt received.\n");

	/* This is the structure that tells the worker thread
	 * what to do
	 */
	taskInfo = &(ctrl->event_queue[ctrl->next_event]);
	ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS;
	taskInfo->hp_slot = hp_slot;

	rc++;
	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
	p_slot->hpc_ops->get_latch_status(p_slot, &getstatus);

	if (getstatus) {
		/*
		 * Switch opened
		 */
		info("Latch open on Slot(%d)\n", ctrl->first_slot + hp_slot);
		taskInfo->event_type = INT_SWITCH_OPEN;
	} else {
		/*
		 *  Switch closed
		 */
		info("Latch close on Slot(%d)\n", ctrl->first_slot + hp_slot);
		taskInfo->event_type = INT_SWITCH_CLOSE;
	}

	if (rc)
		up(&event_semaphore);	/* signal event thread that new event is posted */

	return rc;
}
Example #10
0
u8 pciehp_handle_power_fault(u8 hp_slot, void *inst_id)
{
	struct controller *ctrl = (struct controller *) inst_id;
	struct slot *p_slot;
	u8 rc = 0;
	struct event_info *taskInfo;

	/* power fault */
	dbg("pciehp:  Power fault interrupt received.\n");

	/* this is the structure that tells the worker thread
	 * what to do
	 */
	taskInfo = &(ctrl->event_queue[ctrl->next_event]);
	ctrl->next_event = (ctrl->next_event + 1) % MAX_EVENTS;
	taskInfo->hp_slot = hp_slot;

	rc++;
	p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);

	if ( !(p_slot->hpc_ops->query_power_fault(p_slot))) {
		/*
		 * power fault Cleared
		 */
		info("Power fault cleared on Slot(%d)\n", ctrl->first_slot + hp_slot);
		taskInfo->event_type = INT_POWER_FAULT_CLEAR;
	} else {
		/*
		 *   power fault
		 */
		info("Power fault on Slot(%d)\n", ctrl->first_slot + hp_slot);
		taskInfo->event_type = INT_POWER_FAULT;
		info("power fault bit %x set\n", hp_slot);
	}
	if (rc)
		up(&event_semaphore);	/* signal event thread that new event is posted */

	return rc;
}
Example #11
0
static void interrupt_event_handler(struct controller *ctrl)
{
	int loop = 0;
	int change = 1;
	u8 hp_slot;
	u8 getstatus;
	struct slot *p_slot;

	while (change) {
		change = 0;

		for (loop = 0; loop < MAX_EVENTS; loop++) {
			if (ctrl->event_queue[loop].event_type != 0) {
				hp_slot = ctrl->event_queue[loop].hp_slot;

				p_slot = pciehp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);

				if (ctrl->event_queue[loop].event_type == INT_BUTTON_CANCEL) {
					dbg("button cancel\n");
					del_timer(&p_slot->task_event);

					switch (p_slot->state) {
					case BLINKINGOFF_STATE:
						/* Wait for exclusive access to hardware */
						down(&ctrl->crit_sect);
						
						if (PWR_LED(ctrl->ctrlcap)) {
							p_slot->hpc_ops->green_led_on(p_slot);
							/* Wait for the command to complete */
							wait_for_ctrl_irq (ctrl);
						}
						if (ATTN_LED(ctrl->ctrlcap)) {
							p_slot->hpc_ops->set_attention_status(p_slot, 0);

							/* Wait for the command to complete */
							wait_for_ctrl_irq (ctrl);
						}
						/* Done with exclusive hardware access */
						up(&ctrl->crit_sect);
						break;
					case BLINKINGON_STATE:
						/* Wait for exclusive access to hardware */
						down(&ctrl->crit_sect);

						if (PWR_LED(ctrl->ctrlcap)) {
							p_slot->hpc_ops->green_led_off(p_slot);
							/* Wait for the command to complete */
							wait_for_ctrl_irq (ctrl);
						}
						if (ATTN_LED(ctrl->ctrlcap)){
							p_slot->hpc_ops->set_attention_status(p_slot, 0);
							/* Wait for the command to complete */
							wait_for_ctrl_irq (ctrl);
						}
						/* Done with exclusive hardware access */
						up(&ctrl->crit_sect);

						break;
					default:
						warn("Not a valid state\n");
						return;
					}
					info(msg_button_cancel, p_slot->number);
					p_slot->state = STATIC_STATE;
				}
				/* ***********Button Pressed (No action on 1st press...) */
				else if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) {
					
					if (ATTN_BUTTN(ctrl->ctrlcap)) {
						dbg("Button pressed\n");
						p_slot->hpc_ops->get_power_status(p_slot, &getstatus);
						if (getstatus) {
							/* slot is on */
							dbg("slot is on\n");
							p_slot->state = BLINKINGOFF_STATE;
							info(msg_button_off, p_slot->number);
						} else {
							/* slot is off */
							dbg("slot is off\n");
							p_slot->state = BLINKINGON_STATE;
							info(msg_button_on, p_slot->number);
						}

						/* Wait for exclusive access to hardware */
						down(&ctrl->crit_sect);

						/* blink green LED and turn off amber */
						if (PWR_LED(ctrl->ctrlcap)) {
							p_slot->hpc_ops->green_led_blink(p_slot);
							/* Wait for the command to complete */
							wait_for_ctrl_irq (ctrl);
						}

						if (ATTN_LED(ctrl->ctrlcap)) {
							p_slot->hpc_ops->set_attention_status(p_slot, 0);

							/* Wait for the command to complete */
							wait_for_ctrl_irq (ctrl);
						}

						/* Done with exclusive hardware access */
						up(&ctrl->crit_sect);

						init_timer(&p_slot->task_event);
						p_slot->task_event.expires = jiffies + 5 * HZ;   /* 5 second delay */
						p_slot->task_event.function = (void (*)(unsigned long)) pushbutton_helper_thread;
						p_slot->task_event.data = (unsigned long) p_slot;

						add_timer(&p_slot->task_event);
					}
				}
				/***********POWER FAULT********************/
				else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) {
					if (POWER_CTRL(ctrl->ctrlcap)) {
						dbg("power fault\n");
						/* Wait for exclusive access to hardware */
						down(&ctrl->crit_sect);

						if (ATTN_LED(ctrl->ctrlcap)) {
							p_slot->hpc_ops->set_attention_status(p_slot, 1);
							wait_for_ctrl_irq (ctrl);
						}

						if (PWR_LED(ctrl->ctrlcap)) {
							p_slot->hpc_ops->green_led_off(p_slot);
							wait_for_ctrl_irq (ctrl);
						}

						/* Done with exclusive hardware access */
						up(&ctrl->crit_sect);
					}
				}
				/***********SURPRISE REMOVAL********************/
				else if ((ctrl->event_queue[loop].event_type == INT_PRESENCE_ON) || 
					(ctrl->event_queue[loop].event_type == INT_PRESENCE_OFF)) {
					if (HP_SUPR_RM(ctrl->ctrlcap)) {
						dbg("Surprise Removal\n");
						if (p_slot) {
							surprise_rm_pending = (unsigned long) p_slot;
							up(&event_semaphore);
							update_slot_info(p_slot);
						}
					}
				} else {
					/* refresh notification */
					if (p_slot)
						update_slot_info(p_slot);
				}

				ctrl->event_queue[loop].event_type = 0;

				change = 1;
			}
		}		/* End of FOR loop */
	}
}
static irqreturn_t pcie_isr(int irq, void *dev_id)
{
	struct controller *ctrl = (struct controller *)dev_id;
	u16 detected, intr_loc;
	struct slot *p_slot;

	/*
	 * In order to guarantee that all interrupt events are
	 * serviced, we need to re-inspect Slot Status register after
	 * clearing what is presumed to be the last pending interrupt.
	 */
	intr_loc = 0;
	do {
		if (pciehp_readw(ctrl, PCI_EXP_SLTSTA, &detected)) {
			ctrl_err(ctrl, "%s: Cannot read SLOTSTATUS\n",
				 __func__);
			return IRQ_NONE;
		}

		detected &= (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD |
			     PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC |
			     PCI_EXP_SLTSTA_CC);
		detected &= ~intr_loc;
		intr_loc |= detected;
		if (!intr_loc)
			return IRQ_NONE;
		if (detected && pciehp_writew(ctrl, PCI_EXP_SLTSTA, intr_loc)) {
			ctrl_err(ctrl, "%s: Cannot write to SLOTSTATUS\n",
				 __func__);
			return IRQ_NONE;
		}
	} while (detected);

	ctrl_dbg(ctrl, "%s: intr_loc %x\n", __func__, intr_loc);

	/* Check Command Complete Interrupt Pending */
	if (intr_loc & PCI_EXP_SLTSTA_CC) {
		ctrl->cmd_busy = 0;
		smp_mb();
		wake_up(&ctrl->queue);
	}

	if (!(intr_loc & ~PCI_EXP_SLTSTA_CC))
		return IRQ_HANDLED;

	p_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset);

	/* Check MRL Sensor Changed */
	if (intr_loc & PCI_EXP_SLTSTA_MRLSC)
		pciehp_handle_switch_change(p_slot);

	/* Check Attention Button Pressed */
	if (intr_loc & PCI_EXP_SLTSTA_ABP)
		pciehp_handle_attention_button(p_slot);

	/* Check Presence Detect Changed */
	if (intr_loc & PCI_EXP_SLTSTA_PDC)
		pciehp_handle_presence_change(p_slot);

	/* Check Power Fault Detected */
	if ((intr_loc & PCI_EXP_SLTSTA_PFD) && !ctrl->power_fault_detected) {
		ctrl->power_fault_detected = 1;
		pciehp_handle_power_fault(p_slot);
	}
	return IRQ_HANDLED;
}