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

Commit 9d68c783 authored by Bjorn Helgaas's avatar Bjorn Helgaas
Browse files

Merge branch 'pci/pciehp' into next

* pci/pciehp:
  PCI: pciehp: Cleanup whitespace
  PCI: pciehp: Remove a non-existent card, regardless of "surprise" capability
  PCI: pciehp: Don't turn slot off when hot-added device already exists
  PCI: pciehp: Add hotplug_lock to serialize hotplug events
  PCI: pciehp: Ensure very fast hotplug events are also processed
  PCI: pciehp: Disable link notification across slot reset
  PCI: pciehp: Don't check adapter or latch status while disabling
  PCI: pciehp: Don't disable the link permanently during removal
  PCI: pciehp: Enable link state change notifications
  PCI: pciehp: Use link change notifications for hot-plug and removal
  PCI: pciehp: Make check_link_active() non-static
parents 5d833a6c 9cad7f58
Loading
Loading
Loading
Loading
+5 −0
Original line number Original line Diff line number Diff line
@@ -76,6 +76,7 @@ struct slot {
	struct hotplug_slot *hotplug_slot;
	struct hotplug_slot *hotplug_slot;
	struct delayed_work work;	/* work for button event */
	struct delayed_work work;	/* work for button event */
	struct mutex lock;
	struct mutex lock;
	struct mutex hotplug_lock;
	struct workqueue_struct *wq;
	struct workqueue_struct *wq;
};
};


@@ -109,6 +110,8 @@ struct controller {
#define INT_BUTTON_PRESS		7
#define INT_BUTTON_PRESS		7
#define INT_BUTTON_RELEASE		8
#define INT_BUTTON_RELEASE		8
#define INT_BUTTON_CANCEL		9
#define INT_BUTTON_CANCEL		9
#define INT_LINK_UP			10
#define INT_LINK_DOWN			11


#define STATIC_STATE			0
#define STATIC_STATE			0
#define BLINKINGON_STATE		1
#define BLINKINGON_STATE		1
@@ -132,6 +135,7 @@ u8 pciehp_handle_attention_button(struct slot *p_slot);
u8 pciehp_handle_switch_change(struct slot *p_slot);
u8 pciehp_handle_switch_change(struct slot *p_slot);
u8 pciehp_handle_presence_change(struct slot *p_slot);
u8 pciehp_handle_presence_change(struct slot *p_slot);
u8 pciehp_handle_power_fault(struct slot *p_slot);
u8 pciehp_handle_power_fault(struct slot *p_slot);
void pciehp_handle_linkstate_change(struct slot *p_slot);
int pciehp_configure_device(struct slot *p_slot);
int pciehp_configure_device(struct slot *p_slot);
int pciehp_unconfigure_device(struct slot *p_slot);
int pciehp_unconfigure_device(struct slot *p_slot);
void pciehp_queue_pushbutton_work(struct work_struct *work);
void pciehp_queue_pushbutton_work(struct work_struct *work);
@@ -153,6 +157,7 @@ void pciehp_green_led_on(struct slot *slot);
void pciehp_green_led_off(struct slot *slot);
void pciehp_green_led_off(struct slot *slot);
void pciehp_green_led_blink(struct slot *slot);
void pciehp_green_led_blink(struct slot *slot);
int pciehp_check_link_status(struct controller *ctrl);
int pciehp_check_link_status(struct controller *ctrl);
bool pciehp_check_link_active(struct controller *ctrl);
void pciehp_release_ctrl(struct controller *ctrl);
void pciehp_release_ctrl(struct controller *ctrl);
int pciehp_reset_slot(struct slot *slot, int probe);
int pciehp_reset_slot(struct slot *slot, int probe);


+1 −0
Original line number Original line Diff line number Diff line
@@ -112,6 +112,7 @@ static struct pcie_port_service_driver __initdata dummy_driver = {
static int __init select_detection_mode(void)
static int __init select_detection_mode(void)
{
{
	struct dummy_slot *slot, *tmp;
	struct dummy_slot *slot, *tmp;

	if (pcie_port_service_register(&dummy_driver))
	if (pcie_port_service_register(&dummy_driver))
		return PCIEHP_DETECT_ACPI;
		return PCIEHP_DETECT_ACPI;
	pcie_port_service_unregister(&dummy_driver);
	pcie_port_service_unregister(&dummy_driver);
+7 −1
Original line number Original line Diff line number Diff line
@@ -108,6 +108,7 @@ static int init_slot(struct controller *ctrl)
	ops = kzalloc(sizeof(*ops), GFP_KERNEL);
	ops = kzalloc(sizeof(*ops), GFP_KERNEL);
	if (!ops)
	if (!ops)
		goto out;
		goto out;

	ops->enable_slot = enable_slot;
	ops->enable_slot = enable_slot;
	ops->disable_slot = disable_slot;
	ops->disable_slot = disable_slot;
	ops->get_power_status = get_power_status;
	ops->get_power_status = get_power_status;
@@ -283,8 +284,11 @@ static int pciehp_probe(struct pcie_device *dev)
	slot = ctrl->slot;
	slot = ctrl->slot;
	pciehp_get_adapter_status(slot, &occupied);
	pciehp_get_adapter_status(slot, &occupied);
	pciehp_get_power_status(slot, &poweron);
	pciehp_get_power_status(slot, &poweron);
	if (occupied && pciehp_force)
	if (occupied && pciehp_force) {
		mutex_lock(&slot->hotplug_lock);
		pciehp_enable_slot(slot);
		pciehp_enable_slot(slot);
		mutex_unlock(&slot->hotplug_lock);
	}
	/* If empty slot's power status is on, turn power off */
	/* If empty slot's power status is on, turn power off */
	if (!occupied && poweron && POWER_CTRL(ctrl))
	if (!occupied && poweron && POWER_CTRL(ctrl))
		pciehp_power_off_slot(slot);
		pciehp_power_off_slot(slot);
@@ -328,10 +332,12 @@ static int pciehp_resume (struct pcie_device *dev)


	/* Check if slot is occupied */
	/* Check if slot is occupied */
	pciehp_get_adapter_status(slot, &status);
	pciehp_get_adapter_status(slot, &status);
	mutex_lock(&slot->hotplug_lock);
	if (status)
	if (status)
		pciehp_enable_slot(slot);
		pciehp_enable_slot(slot);
	else
	else
		pciehp_disable_slot(slot);
		pciehp_disable_slot(slot);
	mutex_unlock(&slot->hotplug_lock);
	return 0;
	return 0;
}
}
#endif /* PM */
#endif /* PM */
+137 −36
Original line number Original line Diff line number Diff line
@@ -150,6 +150,27 @@ u8 pciehp_handle_power_fault(struct slot *p_slot)
	return 1;
	return 1;
}
}


void pciehp_handle_linkstate_change(struct slot *p_slot)
{
	u32 event_type;
	struct controller *ctrl = p_slot->ctrl;

	/* Link Status Change */
	ctrl_dbg(ctrl, "Data Link Layer State change\n");

	if (pciehp_check_link_active(ctrl)) {
		ctrl_info(ctrl, "slot(%s): Link Up event\n",
			  slot_name(p_slot));
		event_type = INT_LINK_UP;
	} else {
		ctrl_info(ctrl, "slot(%s): Link Down event\n",
			  slot_name(p_slot));
		event_type = INT_LINK_DOWN;
	}

	queue_interrupt_event(p_slot, event_type);
}

/* The following routines constitute the bulk of the
/* The following routines constitute the bulk of the
   hotplug controller logic
   hotplug controller logic
 */
 */
@@ -212,6 +233,7 @@ static int board_added(struct slot *p_slot)
	if (retval) {
	if (retval) {
		ctrl_err(ctrl, "Cannot add device at %04x:%02x:00\n",
		ctrl_err(ctrl, "Cannot add device at %04x:%02x:00\n",
			 pci_domain_nr(parent), parent->number);
			 pci_domain_nr(parent), parent->number);
		if (retval != -EEXIST)
			goto err_exit;
			goto err_exit;
	}
	}


@@ -255,6 +277,9 @@ static int remove_board(struct slot *p_slot)
struct power_work_info {
struct power_work_info {
	struct slot *p_slot;
	struct slot *p_slot;
	struct work_struct work;
	struct work_struct work;
	unsigned int req;
#define DISABLE_REQ 0
#define ENABLE_REQ  1
};
};


/**
/**
@@ -269,30 +294,38 @@ static void pciehp_power_thread(struct work_struct *work)
	struct power_work_info *info =
	struct power_work_info *info =
		container_of(work, struct power_work_info, work);
		container_of(work, struct power_work_info, work);
	struct slot *p_slot = info->p_slot;
	struct slot *p_slot = info->p_slot;
	int ret;


	mutex_lock(&p_slot->lock);
	switch (info->req) {
	switch (p_slot->state) {
	case DISABLE_REQ:
	case POWEROFF_STATE:
		mutex_unlock(&p_slot->lock);
		ctrl_dbg(p_slot->ctrl,
		ctrl_dbg(p_slot->ctrl,
			 "Disabling domain:bus:device=%04x:%02x:00\n",
			 "Disabling domain:bus:device=%04x:%02x:00\n",
			 pci_domain_nr(p_slot->ctrl->pcie->port->subordinate),
			 pci_domain_nr(p_slot->ctrl->pcie->port->subordinate),
			 p_slot->ctrl->pcie->port->subordinate->number);
			 p_slot->ctrl->pcie->port->subordinate->number);
		mutex_lock(&p_slot->hotplug_lock);
		pciehp_disable_slot(p_slot);
		pciehp_disable_slot(p_slot);
		mutex_unlock(&p_slot->hotplug_lock);
		mutex_lock(&p_slot->lock);
		mutex_lock(&p_slot->lock);
		p_slot->state = STATIC_STATE;
		p_slot->state = STATIC_STATE;
		break;
	case POWERON_STATE:
		mutex_unlock(&p_slot->lock);
		mutex_unlock(&p_slot->lock);
		if (pciehp_enable_slot(p_slot))
		break;
	case ENABLE_REQ:
		ctrl_dbg(p_slot->ctrl,
			 "Enabling domain:bus:device=%04x:%02x:00\n",
			 pci_domain_nr(p_slot->ctrl->pcie->port->subordinate),
			 p_slot->ctrl->pcie->port->subordinate->number);
		mutex_lock(&p_slot->hotplug_lock);
		ret = pciehp_enable_slot(p_slot);
		mutex_unlock(&p_slot->hotplug_lock);
		if (ret)
			pciehp_green_led_off(p_slot);
			pciehp_green_led_off(p_slot);
		mutex_lock(&p_slot->lock);
		mutex_lock(&p_slot->lock);
		p_slot->state = STATIC_STATE;
		p_slot->state = STATIC_STATE;
		mutex_unlock(&p_slot->lock);
		break;
		break;
	default:
	default:
		break;
		break;
	}
	}
	mutex_unlock(&p_slot->lock);


	kfree(info);
	kfree(info);
}
}
@@ -315,9 +348,11 @@ void pciehp_queue_pushbutton_work(struct work_struct *work)
	switch (p_slot->state) {
	switch (p_slot->state) {
	case BLINKINGOFF_STATE:
	case BLINKINGOFF_STATE:
		p_slot->state = POWEROFF_STATE;
		p_slot->state = POWEROFF_STATE;
		info->req = DISABLE_REQ;
		break;
		break;
	case BLINKINGON_STATE:
	case BLINKINGON_STATE:
		p_slot->state = POWERON_STATE;
		p_slot->state = POWERON_STATE;
		info->req = ENABLE_REQ;
		break;
		break;
	default:
	default:
		kfree(info);
		kfree(info);
@@ -364,11 +399,10 @@ static void handle_button_press_event(struct slot *p_slot)
		 */
		 */
		ctrl_info(ctrl, "Button cancel on Slot(%s)\n", slot_name(p_slot));
		ctrl_info(ctrl, "Button cancel on Slot(%s)\n", slot_name(p_slot));
		cancel_delayed_work(&p_slot->work);
		cancel_delayed_work(&p_slot->work);
		if (p_slot->state == BLINKINGOFF_STATE) {
		if (p_slot->state == BLINKINGOFF_STATE)
			pciehp_green_led_on(p_slot);
			pciehp_green_led_on(p_slot);
		} else {
		else
			pciehp_green_led_off(p_slot);
			pciehp_green_led_off(p_slot);
		}
		pciehp_set_attention_status(p_slot, 0);
		pciehp_set_attention_status(p_slot, 0);
		ctrl_info(ctrl, "PCI slot #%s - action canceled "
		ctrl_info(ctrl, "PCI slot #%s - action canceled "
			  "due to button press\n", slot_name(p_slot));
			  "due to button press\n", slot_name(p_slot));
@@ -407,13 +441,80 @@ static void handle_surprise_event(struct slot *p_slot)
	INIT_WORK(&info->work, pciehp_power_thread);
	INIT_WORK(&info->work, pciehp_power_thread);


	pciehp_get_adapter_status(p_slot, &getstatus);
	pciehp_get_adapter_status(p_slot, &getstatus);
	if (!getstatus)
	if (!getstatus) {
		p_slot->state = POWEROFF_STATE;
		p_slot->state = POWEROFF_STATE;
	else
		info->req = DISABLE_REQ;
	} else {
		p_slot->state = POWERON_STATE;
		p_slot->state = POWERON_STATE;
		info->req = ENABLE_REQ;
	}

	queue_work(p_slot->wq, &info->work);
}

/*
 * Note: This function must be called with slot->lock held
 */
static void handle_link_event(struct slot *p_slot, u32 event)
{
	struct controller *ctrl = p_slot->ctrl;
	struct power_work_info *info;

	info = kmalloc(sizeof(*info), GFP_KERNEL);
	if (!info) {
		ctrl_err(p_slot->ctrl, "%s: Cannot allocate memory\n",
			 __func__);
		return;
	}
	info->p_slot = p_slot;
	info->req = event == INT_LINK_UP ? ENABLE_REQ : DISABLE_REQ;
	INIT_WORK(&info->work, pciehp_power_thread);


	switch (p_slot->state) {
	case BLINKINGON_STATE:
	case BLINKINGOFF_STATE:
		cancel_delayed_work(&p_slot->work);
		/* Fall through */
	case STATIC_STATE:
		p_slot->state = event == INT_LINK_UP ?
		    POWERON_STATE : POWEROFF_STATE;
		queue_work(p_slot->wq, &info->work);
		break;
	case POWERON_STATE:
		if (event == INT_LINK_UP) {
			ctrl_info(ctrl,
				  "Link Up event ignored on slot(%s): already powering on\n",
				  slot_name(p_slot));
			kfree(info);
		} else {
			ctrl_info(ctrl,
				  "Link Down event queued on slot(%s): currently getting powered on\n",
				  slot_name(p_slot));
			p_slot->state = POWEROFF_STATE;
			queue_work(p_slot->wq, &info->work);
			queue_work(p_slot->wq, &info->work);
		}
		}
		break;
	case POWEROFF_STATE:
		if (event == INT_LINK_UP) {
			ctrl_info(ctrl,
				  "Link Up event queued on slot(%s): currently getting powered off\n",
				  slot_name(p_slot));
			p_slot->state = POWERON_STATE;
			queue_work(p_slot->wq, &info->work);
		} else {
			ctrl_info(ctrl,
				  "Link Down event ignored on slot(%s): already powering off\n",
				  slot_name(p_slot));
			kfree(info);
		}
		break;
	default:
		ctrl_err(ctrl, "Not a valid state on slot(%s)\n",
			 slot_name(p_slot));
		kfree(info);
		break;
	}
}


static void interrupt_event_handler(struct work_struct *work)
static void interrupt_event_handler(struct work_struct *work)
{
{
@@ -433,12 +534,23 @@ static void interrupt_event_handler(struct work_struct *work)
		pciehp_green_led_off(p_slot);
		pciehp_green_led_off(p_slot);
		break;
		break;
	case INT_PRESENCE_ON:
	case INT_PRESENCE_ON:
	case INT_PRESENCE_OFF:
		if (!HP_SUPR_RM(ctrl))
		if (!HP_SUPR_RM(ctrl))
			break;
			break;
		ctrl_dbg(ctrl, "Surprise Insertion\n");
		handle_surprise_event(p_slot);
		break;
	case INT_PRESENCE_OFF:
		/*
		 * Regardless of surprise capability, we need to
		 * definitely remove a card that has been pulled out!
		 */
		ctrl_dbg(ctrl, "Surprise Removal\n");
		ctrl_dbg(ctrl, "Surprise Removal\n");
		handle_surprise_event(p_slot);
		handle_surprise_event(p_slot);
		break;
		break;
	case INT_LINK_UP:
	case INT_LINK_DOWN:
		handle_link_event(p_slot, info->event_type);
		break;
	default:
	default:
		break;
		break;
	}
	}
@@ -447,6 +559,9 @@ static void interrupt_event_handler(struct work_struct *work)
	kfree(info);
	kfree(info);
}
}


/*
 * Note: This function must be called with slot->hotplug_lock held
 */
int pciehp_enable_slot(struct slot *p_slot)
int pciehp_enable_slot(struct slot *p_slot)
{
{
	u8 getstatus = 0;
	u8 getstatus = 0;
@@ -479,13 +594,15 @@ int pciehp_enable_slot(struct slot *p_slot)
	pciehp_get_latch_status(p_slot, &getstatus);
	pciehp_get_latch_status(p_slot, &getstatus);


	rc = board_added(p_slot);
	rc = board_added(p_slot);
	if (rc) {
	if (rc)
		pciehp_get_latch_status(p_slot, &getstatus);
		pciehp_get_latch_status(p_slot, &getstatus);
	}

	return rc;
	return rc;
}
}



/*
 * Note: This function must be called with slot->hotplug_lock held
 */
int pciehp_disable_slot(struct slot *p_slot)
int pciehp_disable_slot(struct slot *p_slot)
{
{
	u8 getstatus = 0;
	u8 getstatus = 0;
@@ -494,24 +611,6 @@ int pciehp_disable_slot(struct slot *p_slot)
	if (!p_slot->ctrl)
	if (!p_slot->ctrl)
		return 1;
		return 1;


	if (!HP_SUPR_RM(p_slot->ctrl)) {
		pciehp_get_adapter_status(p_slot, &getstatus);
		if (!getstatus) {
			ctrl_info(ctrl, "No adapter on slot(%s)\n",
				  slot_name(p_slot));
			return -ENODEV;
		}
	}

	if (MRL_SENS(p_slot->ctrl)) {
		pciehp_get_latch_status(p_slot, &getstatus);
		if (getstatus) {
			ctrl_info(ctrl, "Latch open on slot(%s)\n",
				  slot_name(p_slot));
			return -ENODEV;
		}
	}

	if (POWER_CTRL(p_slot->ctrl)) {
	if (POWER_CTRL(p_slot->ctrl)) {
		pciehp_get_power_status(p_slot, &getstatus);
		pciehp_get_power_status(p_slot, &getstatus);
		if (!getstatus) {
		if (!getstatus) {
@@ -536,7 +635,9 @@ int pciehp_sysfs_enable_slot(struct slot *p_slot)
	case STATIC_STATE:
	case STATIC_STATE:
		p_slot->state = POWERON_STATE;
		p_slot->state = POWERON_STATE;
		mutex_unlock(&p_slot->lock);
		mutex_unlock(&p_slot->lock);
		mutex_lock(&p_slot->hotplug_lock);
		retval = pciehp_enable_slot(p_slot);
		retval = pciehp_enable_slot(p_slot);
		mutex_unlock(&p_slot->hotplug_lock);
		mutex_lock(&p_slot->lock);
		mutex_lock(&p_slot->lock);
		p_slot->state = STATIC_STATE;
		p_slot->state = STATIC_STATE;
		break;
		break;
+38 −37
Original line number Original line Diff line number Diff line
@@ -206,7 +206,7 @@ static void pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
	mutex_unlock(&ctrl->ctrl_lock);
	mutex_unlock(&ctrl->ctrl_lock);
}
}


static bool check_link_active(struct controller *ctrl)
bool pciehp_check_link_active(struct controller *ctrl)
{
{
	struct pci_dev *pdev = ctrl_dev(ctrl);
	struct pci_dev *pdev = ctrl_dev(ctrl);
	u16 lnk_status;
	u16 lnk_status;
@@ -225,12 +225,12 @@ static void __pcie_wait_link_active(struct controller *ctrl, bool active)
{
{
	int timeout = 1000;
	int timeout = 1000;


	if (check_link_active(ctrl) == active)
	if (pciehp_check_link_active(ctrl) == active)
		return;
		return;
	while (timeout > 0) {
	while (timeout > 0) {
		msleep(10);
		msleep(10);
		timeout -= 10;
		timeout -= 10;
		if (check_link_active(ctrl) == active)
		if (pciehp_check_link_active(ctrl) == active)
			return;
			return;
	}
	}
	ctrl_dbg(ctrl, "Data Link Layer Link Active not %s in 1000 msec\n",
	ctrl_dbg(ctrl, "Data Link Layer Link Active not %s in 1000 msec\n",
@@ -242,11 +242,6 @@ static void pcie_wait_link_active(struct controller *ctrl)
	__pcie_wait_link_active(ctrl, true);
	__pcie_wait_link_active(ctrl, true);
}
}


static void pcie_wait_link_not_active(struct controller *ctrl)
{
	__pcie_wait_link_active(ctrl, false);
}

static bool pci_bus_check_dev(struct pci_bus *bus, int devfn)
static bool pci_bus_check_dev(struct pci_bus *bus, int devfn)
{
{
	u32 l;
	u32 l;
@@ -332,11 +327,6 @@ static int pciehp_link_enable(struct controller *ctrl)
	return __pciehp_link_set(ctrl, true);
	return __pciehp_link_set(ctrl, true);
}
}


static int pciehp_link_disable(struct controller *ctrl)
{
	return __pciehp_link_set(ctrl, false);
}

void pciehp_get_attention_status(struct slot *slot, u8 *status)
void pciehp_get_attention_status(struct slot *slot, u8 *status)
{
{
	struct controller *ctrl = slot->ctrl;
	struct controller *ctrl = slot->ctrl;
@@ -508,14 +498,6 @@ void pciehp_power_off_slot(struct slot * slot)
{
{
	struct controller *ctrl = slot->ctrl;
	struct controller *ctrl = slot->ctrl;


	/* Disable the link at first */
	pciehp_link_disable(ctrl);
	/* wait the link is down */
	if (ctrl->link_active_reporting)
		pcie_wait_link_not_active(ctrl);
	else
		msleep(1000);

	pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_OFF, PCI_EXP_SLTCTL_PCC);
	pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_OFF, PCI_EXP_SLTCTL_PCC);
	ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
	ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
		 pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL,
		 pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL,
@@ -540,7 +522,7 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)


		detected &= (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD |
		detected &= (PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD |
			     PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC |
			     PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_PDC |
			     PCI_EXP_SLTSTA_CC);
			     PCI_EXP_SLTSTA_CC | PCI_EXP_SLTSTA_DLLSC);
		detected &= ~intr_loc;
		detected &= ~intr_loc;
		intr_loc |= detected;
		intr_loc |= detected;
		if (!intr_loc)
		if (!intr_loc)
@@ -579,6 +561,10 @@ static irqreturn_t pcie_isr(int irq, void *dev_id)
		ctrl->power_fault_detected = 1;
		ctrl->power_fault_detected = 1;
		pciehp_handle_power_fault(slot);
		pciehp_handle_power_fault(slot);
	}
	}

	if (intr_loc & PCI_EXP_SLTSTA_DLLSC)
		pciehp_handle_linkstate_change(slot);

	return IRQ_HANDLED;
	return IRQ_HANDLED;
}
}


@@ -596,9 +582,17 @@ void pcie_enable_notification(struct controller *ctrl)
	 * when it is cleared in the interrupt service routine, and
	 * when it is cleared in the interrupt service routine, and
	 * next power fault detected interrupt was notified again.
	 * next power fault detected interrupt was notified again.
	 */
	 */
	cmd = PCI_EXP_SLTCTL_PDCE;

	/*
	 * Always enable link events: thus link-up and link-down shall
	 * always be treated as hotplug and unplug respectively. Enable
	 * presence detect only if Attention Button is not present.
	 */
	cmd = PCI_EXP_SLTCTL_DLLSCE;
	if (ATTN_BUTTN(ctrl))
	if (ATTN_BUTTN(ctrl))
		cmd |= PCI_EXP_SLTCTL_ABPE;
		cmd |= PCI_EXP_SLTCTL_ABPE;
	else
		cmd |= PCI_EXP_SLTCTL_PDCE;
	if (MRL_SENS(ctrl))
	if (MRL_SENS(ctrl))
		cmd |= PCI_EXP_SLTCTL_MRLSCE;
		cmd |= PCI_EXP_SLTCTL_MRLSCE;
	if (!pciehp_poll_mode)
	if (!pciehp_poll_mode)
@@ -606,7 +600,8 @@ void pcie_enable_notification(struct controller *ctrl)


	mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE |
	mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE |
		PCI_EXP_SLTCTL_MRLSCE | PCI_EXP_SLTCTL_PFDE |
		PCI_EXP_SLTCTL_MRLSCE | PCI_EXP_SLTCTL_PFDE |
		PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE);
		PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE |
		PCI_EXP_SLTCTL_DLLSCE);


	pcie_write_cmd(ctrl, cmd, mask);
	pcie_write_cmd(ctrl, cmd, mask);
}
}
@@ -624,33 +619,38 @@ static void pcie_disable_notification(struct controller *ctrl)


/*
/*
 * pciehp has a 1:1 bus:slot relationship so we ultimately want a secondary
 * pciehp has a 1:1 bus:slot relationship so we ultimately want a secondary
 * bus reset of the bridge, but if the slot supports surprise removal we need
 * bus reset of the bridge, but at the same time we want to ensure that it is
 * to disable presence detection around the bus reset and clear any spurious
 * not seen as a hot-unplug, followed by the hot-plug of the device. Thus,
 * disable link state notification and presence detection change notification
 * momentarily, if we see that they could interfere. Also, clear any spurious
 * events after.
 * events after.
 */
 */
int pciehp_reset_slot(struct slot *slot, int probe)
int pciehp_reset_slot(struct slot *slot, int probe)
{
{
	struct controller *ctrl = slot->ctrl;
	struct controller *ctrl = slot->ctrl;
	struct pci_dev *pdev = ctrl_dev(ctrl);
	struct pci_dev *pdev = ctrl_dev(ctrl);
	u16 stat_mask = 0, ctrl_mask = 0;


	if (probe)
	if (probe)
		return 0;
		return 0;


	if (HP_SUPR_RM(ctrl)) {
	if (!ATTN_BUTTN(ctrl)) {
		pcie_write_cmd(ctrl, 0, PCI_EXP_SLTCTL_PDCE);
		ctrl_mask |= PCI_EXP_SLTCTL_PDCE;
		stat_mask |= PCI_EXP_SLTSTA_PDC;
	}
	ctrl_mask |= PCI_EXP_SLTCTL_DLLSCE;
	stat_mask |= PCI_EXP_SLTSTA_DLLSC;

	pcie_write_cmd(ctrl, 0, ctrl_mask);
	if (pciehp_poll_mode)
	if (pciehp_poll_mode)
		del_timer_sync(&ctrl->poll_timer);
		del_timer_sync(&ctrl->poll_timer);
	}


	pci_reset_bridge_secondary_bus(ctrl->pcie->port);
	pci_reset_bridge_secondary_bus(ctrl->pcie->port);


	if (HP_SUPR_RM(ctrl)) {
	pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, stat_mask);
		pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
	pcie_write_cmd(ctrl, ctrl_mask, ctrl_mask);
					   PCI_EXP_SLTSTA_PDC);
		pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PDCE, PCI_EXP_SLTCTL_PDCE);
	if (pciehp_poll_mode)
	if (pciehp_poll_mode)
		int_poll_timeout(ctrl->poll_timer.data);
		int_poll_timeout(ctrl->poll_timer.data);
	}


	return 0;
	return 0;
}
}
@@ -687,6 +687,7 @@ static int pcie_init_slot(struct controller *ctrl)


	slot->ctrl = ctrl;
	slot->ctrl = ctrl;
	mutex_init(&slot->lock);
	mutex_init(&slot->lock);
	mutex_init(&slot->hotplug_lock);
	INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work);
	INIT_DELAYED_WORK(&slot->work, pciehp_queue_pushbutton_work);
	ctrl->slot = slot;
	ctrl->slot = slot;
	return 0;
	return 0;
Loading