Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1ec7d99c authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6:
  pciehp: add message about pciehp_slot_with_bus option
  pci hotplug core: add check of duplicate slot name
  pciehp: move msleep after power off
  pciehp: poll cmd completion if hotplug interrupt is disabled
  pciehp: fix slow probing
  pciehp: fix NULL dereference in interrupt handler
  shpchp: add message about shpchp_slot_with_bus option
  PCI: don't enable ASPM on devices with mixed PCIe/PCI functions
parents 3dbfd080 9e4f2e8d
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -619,6 +619,7 @@ static struct hotplug_slot *get_slot_from_name (const char *name)
int pci_hp_register (struct hotplug_slot *slot)
{
	int result;
	struct hotplug_slot *tmp;

	if (slot == NULL)
		return -ENODEV;
@@ -630,7 +631,11 @@ int pci_hp_register (struct hotplug_slot *slot)
		return -EINVAL;
	}

	/* this can fail if we have already registered a slot with the same name */
	/* Check if we have already registered a slot with the same name. */
	tmp = get_slot_from_name(slot->name);
	if (tmp)
		return -EEXIST;

	slot->kobj.kset = pci_hotplug_slots_kset;
	result = kobject_init_and_add(&slot->kobj, &hotplug_slot_ktype, NULL,
				      "%s", slot->name);
+7 −4
Original line number Diff line number Diff line
@@ -97,6 +97,7 @@ struct controller {
	u8 cap_base;
	struct timer_list poll_timer;
	volatile int cmd_busy;
	unsigned int no_cmd_complete:1;
};

#define INT_BUTTON_IGNORE		0
@@ -135,6 +136,7 @@ struct controller {
#define PWR_LED_PRSN	0x00000010
#define HP_SUPR_RM_SUP	0x00000020
#define EMI_PRSN	0x00020000
#define NO_CMD_CMPL_SUP	0x00040000

#define ATTN_BUTTN(ctrl)	((ctrl)->slot_cap & ATTN_BUTTN_PRSN)
#define POWER_CTRL(ctrl)	((ctrl)->slot_cap & PWR_CTRL_PRSN)
@@ -143,13 +145,14 @@ struct controller {
#define PWR_LED(ctrl)		((ctrl)->slot_cap & PWR_LED_PRSN)
#define HP_SUPR_RM(ctrl)	((ctrl)->slot_cap & HP_SUPR_RM_SUP)
#define EMI(ctrl)		((ctrl)->slot_cap & EMI_PRSN)
#define NO_CMD_CMPL(ctrl)	((ctrl)->slot_cap & NO_CMD_CMPL_SUP)

extern int pciehp_sysfs_enable_slot(struct slot *slot);
extern int pciehp_sysfs_disable_slot(struct slot *slot);
extern u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl);
extern u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl);
extern u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl);
extern u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl);
extern u8 pciehp_handle_attention_button(struct slot *p_slot);
  extern u8 pciehp_handle_switch_change(struct slot *p_slot);
extern u8 pciehp_handle_presence_change(struct slot *p_slot);
extern u8 pciehp_handle_power_fault(struct slot *p_slot);
extern int pciehp_configure_device(struct slot *p_slot);
extern int pciehp_unconfigure_device(struct slot *p_slot);
extern void pciehp_queue_pushbutton_work(struct work_struct *work);
+5 −1
Original line number Diff line number Diff line
@@ -255,6 +255,10 @@ static int init_slots(struct controller *ctrl)
		retval = pci_hp_register(hotplug_slot);
		if (retval) {
			err("pci_hp_register failed with error %d\n", retval);
			if (retval == -EEXIST)
				err("Failed to register slot because of name "
				    "collision. Try \'pciehp_slot_with_bus\' "
				    "module option.\n");
			goto error_info;
		}
		/* create additional sysfs entries */
+19 −17
Original line number Diff line number Diff line
@@ -55,16 +55,13 @@ static int queue_interrupt_event(struct slot *p_slot, u32 event_type)
	return 0;
}

u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl)
u8 pciehp_handle_attention_button(struct slot *p_slot)
{
	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!!!
	 */
@@ -76,18 +73,15 @@ u8 pciehp_handle_attention_button(u8 hp_slot, struct controller *ctrl)
	return 0;
}

u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl)
u8 pciehp_handle_switch_change(struct slot *p_slot)
{
	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
@@ -107,17 +101,14 @@ u8 pciehp_handle_switch_change(u8 hp_slot, struct controller *ctrl)
	return 1;
}

u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl)
u8 pciehp_handle_presence_change(struct slot *p_slot)
{
	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
	 */
@@ -141,16 +132,13 @@ u8 pciehp_handle_presence_change(u8 hp_slot, struct controller *ctrl)
	return 1;
}

u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl)
u8 pciehp_handle_power_fault(struct slot *p_slot)
{
	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
@@ -163,7 +151,7 @@ u8 pciehp_handle_power_fault(u8 hp_slot, struct controller *ctrl)
		 */
		info("Power fault on Slot(%s)\n", p_slot->name);
		event_type = INT_POWER_FAULT;
		info("power fault bit %x set\n", hp_slot);
		info("power fault bit %x set\n", 0);
	}

	queue_interrupt_event(p_slot, event_type);
@@ -186,6 +174,13 @@ static void set_slot_off(struct controller *ctrl, struct slot * pslot)
		}
	}

	/*
	 * After turning power off, we must wait for at least 1 second
	 * before taking any action that relies on power having been
	 * removed from the slot/adapter.
	 */
	msleep(1000);

	if (PWR_LED(ctrl))
		pslot->hpc_ops->green_led_off(pslot);

@@ -289,6 +284,13 @@ static int remove_board(struct slot *p_slot)
		}
	}

	/*
	 * After turning power off, we must wait for at least 1 second
	 * before taking any action that relies on power having been
	 * removed from the slot/adapter.
	 */
	msleep(1000);

	if (PWR_LED(ctrl))
		/* turn off Green LED */
		p_slot->hpc_ops->green_led_off(p_slot);
+98 −31
Original line number Diff line number Diff line
@@ -247,13 +247,37 @@ static inline void pciehp_free_irq(struct controller *ctrl)
		free_irq(ctrl->pci_dev->irq, ctrl);
}

static inline int pcie_wait_cmd(struct controller *ctrl)
static inline int pcie_poll_cmd(struct controller *ctrl)
{
	u16 slot_status;
	int timeout = 1000;

	if (!pciehp_readw(ctrl, SLOTSTATUS, &slot_status))
		if (slot_status & CMD_COMPLETED)
			goto completed;
	for (timeout = 1000; timeout > 0; timeout -= 100) {
		msleep(100);
		if (!pciehp_readw(ctrl, SLOTSTATUS, &slot_status))
			if (slot_status & CMD_COMPLETED)
				goto completed;
	}
	return 0;	/* timeout */

completed:
	pciehp_writew(ctrl, SLOTSTATUS, CMD_COMPLETED);
	return timeout;
}

static inline int pcie_wait_cmd(struct controller *ctrl, int poll)
{
	int retval = 0;
	unsigned int msecs = pciehp_poll_mode ? 2500 : 1000;
	unsigned long timeout = msecs_to_jiffies(msecs);
	int rc;

	if (poll)
		rc = pcie_poll_cmd(ctrl);
	else
		rc = wait_event_interruptible_timeout(ctrl->queue,
					      !ctrl->cmd_busy, timeout);
	if (!rc)
@@ -286,12 +310,28 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
		goto out;
	}

	if ((slot_status & CMD_COMPLETED) == CMD_COMPLETED ) {
		/* After 1 sec and CMD_COMPLETED still not set, just
		   proceed forward to issue the next command according
		   to spec.  Just print out the error message */
	if (slot_status & CMD_COMPLETED) {
		if (!ctrl->no_cmd_complete) {
			/*
			 * After 1 sec and CMD_COMPLETED still not set, just
			 * proceed forward to issue the next command according
			 * to spec. Just print out the error message.
			 */
			dbg("%s: CMD_COMPLETED not clear after 1 sec.\n",
			    __func__);
		} else if (!NO_CMD_CMPL(ctrl)) {
			/*
			 * This controller semms to notify of command completed
			 * event even though it supports none of power
			 * controller, attention led, power led and EMI.
			 */
			dbg("%s: Unexpected CMD_COMPLETED. Need to wait for "
			    "command completed event.\n", __func__);
			ctrl->no_cmd_complete = 0;
		} else {
			dbg("%s: Unexpected CMD_COMPLETED. Maybe the "
			    "controller is broken.\n", __func__);
		}
	}

	retval = pciehp_readw(ctrl, SLOTCTRL, &slot_ctrl);
@@ -315,8 +355,18 @@ static int pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
	/*
	 * Wait for command completion.
	 */
	if (!retval)
		retval = pcie_wait_cmd(ctrl);
	if (!retval && !ctrl->no_cmd_complete) {
		int poll = 0;
		/*
		 * if hotplug interrupt is not enabled or command
		 * completed interrupt is not enabled, we need to poll
		 * command completed event.
		 */
		if (!(slot_ctrl & HP_INTR_ENABLE) ||
		    !(slot_ctrl & CMD_CMPL_INTR_ENABLE))
			poll = 1;
                retval = pcie_wait_cmd(ctrl, poll);
	}
 out:
	mutex_unlock(&ctrl->ctrl_lock);
	return retval;
@@ -704,13 +754,6 @@ static int hpc_power_off_slot(struct slot * slot)
	}
	dbg("%s: SLOTCTRL %x write cmd %x\n",
	    __func__, ctrl->cap_base + SLOTCTRL, slot_cmd);

	/*
	 * After turning power off, we must wait for at least 1 second
	 * before taking any action that relies on power having been
	 * removed from the slot/adapter.
	 */
	msleep(1000);
 out:
	if (changed)
		pcie_unmask_bad_dllp(ctrl);
@@ -722,6 +765,7 @@ 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
@@ -756,21 +800,38 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
		wake_up_interruptible(&ctrl->queue);
	}

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

	/*
	 * Return without handling events if this handler routine is
	 * called before controller initialization is done. This may
	 * happen if hotplug event or another interrupt that shares
	 * the IRQ with pciehp arrives before slot initialization is
	 * done after interrupt handler is registered.
	 *
	 * FIXME - Need more structural fixes. We need to be ready to
	 * handle the event before installing interrupt handler.
	 */
	p_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset);
	if (!p_slot || !p_slot->hpc_ops)
		return IRQ_HANDLED;

	/* Check MRL Sensor Changed */
	if (intr_loc & MRL_SENS_CHANGED)
		pciehp_handle_switch_change(0, ctrl);
		pciehp_handle_switch_change(p_slot);

	/* Check Attention Button Pressed */
	if (intr_loc & ATTN_BUTTN_PRESSED)
		pciehp_handle_attention_button(0, ctrl);
		pciehp_handle_attention_button(p_slot);

	/* Check Presence Detect Changed */
	if (intr_loc & PRSN_DETECT_CHANGED)
		pciehp_handle_presence_change(0, ctrl);
		pciehp_handle_presence_change(p_slot);

	/* Check Power Fault Detected */
	if (intr_loc & PWR_FAULT_DETECTED)
		pciehp_handle_power_fault(0, ctrl);
		pciehp_handle_power_fault(p_slot);

	return IRQ_HANDLED;
}
@@ -1028,6 +1089,12 @@ static int pciehp_acpi_get_hp_hw_control_from_firmware(struct pci_dev *dev)
static int pcie_init_hardware_part1(struct controller *ctrl,
				    struct pcie_device *dev)
{
	/* Clear all remaining event bits in Slot Status register */
	if (pciehp_writew(ctrl, SLOTSTATUS, 0x1f)) {
		err("%s: Cannot write to SLOTSTATUS register\n", __func__);
		return -1;
	}

	/* Mask Hot-plug Interrupt Enable */
	if (pcie_write_cmd(ctrl, 0, HP_INTR_ENABLE | CMD_CMPL_INTR_ENABLE)) {
		err("%s: Cannot mask hotplug interrupt enable\n", __func__);
@@ -1040,16 +1107,6 @@ int pcie_init_hardware_part2(struct controller *ctrl, struct pcie_device *dev)
{
	u16 cmd, mask;

	/*
	 * We need to clear all events before enabling hotplug interrupt
	 * notification mechanism in order for hotplug controler to
	 * generate interrupts.
	 */
	if (pciehp_writew(ctrl, SLOTSTATUS, 0x1f)) {
		err("%s: Cannot write to SLOTSTATUS register\n", __FUNCTION__);
		return -1;
	}

	cmd = PRSN_DETECT_ENABLE;
	if (ATTN_BUTTN(ctrl))
		cmd |= ATTN_BUTTN_ENABLE;
@@ -1116,6 +1173,7 @@ static inline void dbg_ctrl(struct controller *ctrl)
	dbg("  Power Indicator      : %3s\n", PWR_LED(ctrl)    ? "yes" : "no");
	dbg("  Hot-Plug Surprise    : %3s\n", HP_SUPR_RM(ctrl) ? "yes" : "no");
	dbg("  EMI Present          : %3s\n", EMI(ctrl)        ? "yes" : "no");
	dbg("  Comamnd Completed    : %3s\n", NO_CMD_CMPL(ctrl)? "no" : "yes");
	pciehp_readw(ctrl, SLOTSTATUS, &reg16);
	dbg("Slot Status            : 0x%04x\n", reg16);
	pciehp_readw(ctrl, SLOTSTATUS, &reg16);
@@ -1147,6 +1205,15 @@ int pcie_init(struct controller *ctrl, struct pcie_device *dev)
	mutex_init(&ctrl->ctrl_lock);
	init_waitqueue_head(&ctrl->queue);
	dbg_ctrl(ctrl);
	/*
	 * Controller doesn't notify of command completion if the "No
	 * Command Completed Support" bit is set in Slot Capability
	 * register or the controller supports none of power
	 * controller, attention led, power led and EMI.
	 */
	if (NO_CMD_CMPL(ctrl) ||
	    !(POWER_CTRL(ctrl) | ATTN_LED(ctrl) | PWR_LED(ctrl) | EMI(ctrl)))
	    ctrl->no_cmd_complete = 1;

	info("HPC vendor_id %x device_id %x ss_vid %x ss_did %x\n",
	     pdev->vendor, pdev->device,
Loading