xref: /openbmc/linux/drivers/pci/hotplug/pciehp_hpc.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1736759efSBjorn Helgaas // SPDX-License-Identifier: GPL-2.0+
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  * PCI Express PCI Hot Plug Driver
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  * Copyright (C) 1995,2001 Compaq Computer Corporation
61da177e4SLinus Torvalds  * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
71da177e4SLinus Torvalds  * Copyright (C) 2001 IBM Corp.
81da177e4SLinus Torvalds  * Copyright (C) 2003-2004 Intel Corporation
91da177e4SLinus Torvalds  *
101da177e4SLinus Torvalds  * All rights reserved.
111da177e4SLinus Torvalds  *
128cf4c195SKristen Accardi  * Send feedback to <greg@kroah.com>,<kristen.c.accardi@intel.com>
131da177e4SLinus Torvalds  */
141da177e4SLinus Torvalds 
1594dbc956SFrederick Lawler #define dev_fmt(fmt) "pciehp: " fmt
1694dbc956SFrederick Lawler 
170b382546SStuart Hayes #include <linux/dmi.h>
181da177e4SLinus Torvalds #include <linux/kernel.h>
191da177e4SLinus Torvalds #include <linux/types.h>
20de25968cSTim Schmielau #include <linux/jiffies.h>
21ec07a447SLukas Wunner #include <linux/kthread.h>
221da177e4SLinus Torvalds #include <linux/pci.h>
236b08c385SLukas Wunner #include <linux/pm_runtime.h>
245d1b8c9eSAndrew Morton #include <linux/interrupt.h>
255a0e3ad6STejun Heo #include <linux/slab.h>
265d1b8c9eSAndrew Morton 
271da177e4SLinus Torvalds #include "../pci.h"
281da177e4SLinus Torvalds #include "pciehp.h"
291da177e4SLinus Torvalds 
300b382546SStuart Hayes static const struct dmi_system_id inband_presence_disabled_dmi_table[] = {
310b382546SStuart Hayes 	/*
320b382546SStuart Hayes 	 * Match all Dell systems, as some Dell systems have inband
330b382546SStuart Hayes 	 * presence disabled on NVMe slots (but don't support the bit to
340b382546SStuart Hayes 	 * report it). Setting inband presence disabled should have no
350b382546SStuart Hayes 	 * negative effect, except on broken hotplug slots that never
360b382546SStuart Hayes 	 * assert presence detect--and those will still work, they will
370b382546SStuart Hayes 	 * just have a bit of extra delay before being probed.
380b382546SStuart Hayes 	 */
390b382546SStuart Hayes 	{
400b382546SStuart Hayes 		.ident = "Dell System",
410b382546SStuart Hayes 		.matches = {
420b382546SStuart Hayes 			DMI_MATCH(DMI_OEM_STRING, "Dell System"),
430b382546SStuart Hayes 		},
440b382546SStuart Hayes 	},
450b382546SStuart Hayes 	{}
460b382546SStuart Hayes };
470b382546SStuart Hayes 
ctrl_dev(struct controller * ctrl)48cd84d340SBjorn Helgaas static inline struct pci_dev *ctrl_dev(struct controller *ctrl)
49a0f018daSKenji Kaneshige {
50cd84d340SBjorn Helgaas 	return ctrl->pcie->port;
51a0f018daSKenji Kaneshige }
521da177e4SLinus Torvalds 
537b4ce26bSLukas Wunner static irqreturn_t pciehp_isr(int irq, void *dev_id);
547b4ce26bSLukas Wunner static irqreturn_t pciehp_ist(int irq, void *dev_id);
55ec07a447SLukas Wunner static int pciehp_poll(void *data);
561da177e4SLinus Torvalds 
pciehp_request_irq(struct controller * ctrl)572aeeef11SKenji Kaneshige static inline int pciehp_request_irq(struct controller *ctrl)
582aeeef11SKenji Kaneshige {
59f7a10e32SKenji Kaneshige 	int retval, irq = ctrl->pcie->irq;
602aeeef11SKenji Kaneshige 
612aeeef11SKenji Kaneshige 	if (pciehp_poll_mode) {
62ec07a447SLukas Wunner 		ctrl->poll_thread = kthread_run(&pciehp_poll, ctrl,
63ec07a447SLukas Wunner 						"pciehp_poll-%s",
645790a9c7SLukas Wunner 						slot_name(ctrl));
65ec07a447SLukas Wunner 		return PTR_ERR_OR_ZERO(ctrl->poll_thread);
662aeeef11SKenji Kaneshige 	}
672aeeef11SKenji Kaneshige 
682aeeef11SKenji Kaneshige 	/* Installs the interrupt handler */
697b4ce26bSLukas Wunner 	retval = request_threaded_irq(irq, pciehp_isr, pciehp_ist,
70e07ca82aSBjorn Helgaas 				      IRQF_SHARED, "pciehp", ctrl);
712aeeef11SKenji Kaneshige 	if (retval)
727f2feec1STaku Izumi 		ctrl_err(ctrl, "Cannot get irq %d for the hotplug controller\n",
737f2feec1STaku Izumi 			 irq);
742aeeef11SKenji Kaneshige 	return retval;
752aeeef11SKenji Kaneshige }
762aeeef11SKenji Kaneshige 
pciehp_free_irq(struct controller * ctrl)772aeeef11SKenji Kaneshige static inline void pciehp_free_irq(struct controller *ctrl)
782aeeef11SKenji Kaneshige {
792aeeef11SKenji Kaneshige 	if (pciehp_poll_mode)
80ec07a447SLukas Wunner 		kthread_stop(ctrl->poll_thread);
812aeeef11SKenji Kaneshige 	else
82f7a10e32SKenji Kaneshige 		free_irq(ctrl->pcie->irq, ctrl);
832aeeef11SKenji Kaneshige }
842aeeef11SKenji Kaneshige 
pcie_poll_cmd(struct controller * ctrl,int timeout)8540b96083SBjorn Helgaas static int pcie_poll_cmd(struct controller *ctrl, int timeout)
866592e02aSKenji Kaneshige {
87cd84d340SBjorn Helgaas 	struct pci_dev *pdev = ctrl_dev(ctrl);
886592e02aSKenji Kaneshige 	u16 slot_status;
896592e02aSKenji Kaneshige 
90b94ec12dSAndy Shevchenko 	do {
911a84b99cSBjorn Helgaas 		pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status);
92a3b0f10dSNaveen Naidu 		if (PCI_POSSIBLE_ERROR(slot_status)) {
931469d17dSJarod Wilson 			ctrl_info(ctrl, "%s: no response from device\n",
941469d17dSJarod Wilson 				  __func__);
951469d17dSJarod Wilson 			return 0;
961469d17dSJarod Wilson 		}
971469d17dSJarod Wilson 
981a84b99cSBjorn Helgaas 		if (slot_status & PCI_EXP_SLTSTA_CC) {
99cd84d340SBjorn Helgaas 			pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
100cd84d340SBjorn Helgaas 						   PCI_EXP_SLTSTA_CC);
10192912b17SLiguang Zhang 			ctrl->cmd_busy = 0;
10292912b17SLiguang Zhang 			smp_mb();
103820943b6SKenji Kaneshige 			return 1;
104820943b6SKenji Kaneshige 		}
10566618badSKenji Kaneshige 		msleep(10);
10666618badSKenji Kaneshige 		timeout -= 10;
107b94ec12dSAndy Shevchenko 	} while (timeout >= 0);
1086592e02aSKenji Kaneshige 	return 0;	/* timeout */
1096592e02aSKenji Kaneshige }
1106592e02aSKenji Kaneshige 
pcie_wait_cmd(struct controller * ctrl)1114283c70eSBjorn Helgaas static void pcie_wait_cmd(struct controller *ctrl)
11244ef4cefSKenji Kaneshige {
113262303feSKenji Kaneshige 	unsigned int msecs = pciehp_poll_mode ? 2500 : 1000;
11440b96083SBjorn Helgaas 	unsigned long duration = msecs_to_jiffies(msecs);
11540b96083SBjorn Helgaas 	unsigned long cmd_timeout = ctrl->cmd_started + duration;
11640b96083SBjorn Helgaas 	unsigned long now, timeout;
117262303feSKenji Kaneshige 	int rc;
11844ef4cefSKenji Kaneshige 
1194283c70eSBjorn Helgaas 	/*
1204283c70eSBjorn Helgaas 	 * If the controller does not generate notifications for command
1214283c70eSBjorn Helgaas 	 * completions, we never need to wait between writes.
1224283c70eSBjorn Helgaas 	 */
1236c1a32e0SRajat Jain 	if (NO_CMD_CMPL(ctrl))
1244283c70eSBjorn Helgaas 		return;
1254283c70eSBjorn Helgaas 
1264283c70eSBjorn Helgaas 	if (!ctrl->cmd_busy)
1274283c70eSBjorn Helgaas 		return;
1284283c70eSBjorn Helgaas 
12940b96083SBjorn Helgaas 	/*
13040b96083SBjorn Helgaas 	 * Even if the command has already timed out, we want to call
13140b96083SBjorn Helgaas 	 * pcie_poll_cmd() so it can clear PCI_EXP_SLTSTA_CC.
13240b96083SBjorn Helgaas 	 */
13340b96083SBjorn Helgaas 	now = jiffies;
13440b96083SBjorn Helgaas 	if (time_before_eq(cmd_timeout, now))
13540b96083SBjorn Helgaas 		timeout = 1;
13640b96083SBjorn Helgaas 	else
13740b96083SBjorn Helgaas 		timeout = cmd_timeout - now;
13840b96083SBjorn Helgaas 
1394283c70eSBjorn Helgaas 	if (ctrl->slot_ctrl & PCI_EXP_SLTCTL_HPIE &&
1404283c70eSBjorn Helgaas 	    ctrl->slot_ctrl & PCI_EXP_SLTCTL_CCIE)
141d737bdc1SKenji Kaneshige 		rc = wait_event_timeout(ctrl->queue, !ctrl->cmd_busy, timeout);
1424283c70eSBjorn Helgaas 	else
1437cbeb9f9SYinghai Lu 		rc = pcie_poll_cmd(ctrl, jiffies_to_msecs(timeout));
14440b96083SBjorn Helgaas 
145262303feSKenji Kaneshige 	if (!rc)
146d537a3abSBjorn Helgaas 		ctrl_info(ctrl, "Timeout on hotplug command %#06x (issued %u msec ago)\n",
14740b96083SBjorn Helgaas 			  ctrl->slot_ctrl,
148d433889cSYinghai Lu 			  jiffies_to_msecs(jiffies - ctrl->cmd_started));
14944ef4cefSKenji Kaneshige }
15044ef4cefSKenji Kaneshige 
151d22b3621SBjorn Helgaas #define CC_ERRATUM_MASK		(PCI_EXP_SLTCTL_PCC |	\
152d22b3621SBjorn Helgaas 				 PCI_EXP_SLTCTL_PIC |	\
153d22b3621SBjorn Helgaas 				 PCI_EXP_SLTCTL_AIC |	\
154d22b3621SBjorn Helgaas 				 PCI_EXP_SLTCTL_EIC)
155d22b3621SBjorn Helgaas 
pcie_do_write_cmd(struct controller * ctrl,u16 cmd,u16 mask,bool wait)156a5dd4b4bSAlex Williamson static void pcie_do_write_cmd(struct controller *ctrl, u16 cmd,
157a5dd4b4bSAlex Williamson 			      u16 mask, bool wait)
1581da177e4SLinus Torvalds {
159cd84d340SBjorn Helgaas 	struct pci_dev *pdev = ctrl_dev(ctrl);
160d22b3621SBjorn Helgaas 	u16 slot_ctrl_orig, slot_ctrl;
1611da177e4SLinus Torvalds 
16244ef4cefSKenji Kaneshige 	mutex_lock(&ctrl->ctrl_lock);
16344ef4cefSKenji Kaneshige 
164a5dd4b4bSAlex Williamson 	/*
165a5dd4b4bSAlex Williamson 	 * Always wait for any previous command that might still be in progress
166a5dd4b4bSAlex Williamson 	 */
1673461a068SBjorn Helgaas 	pcie_wait_cmd(ctrl);
1683461a068SBjorn Helgaas 
1691a84b99cSBjorn Helgaas 	pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &slot_ctrl);
170a3b0f10dSNaveen Naidu 	if (PCI_POSSIBLE_ERROR(slot_ctrl)) {
1711469d17dSJarod Wilson 		ctrl_info(ctrl, "%s: no response from device\n", __func__);
1721469d17dSJarod Wilson 		goto out;
1731469d17dSJarod Wilson 	}
1741469d17dSJarod Wilson 
175d22b3621SBjorn Helgaas 	slot_ctrl_orig = slot_ctrl;
176f4778364SKenji Kaneshige 	slot_ctrl &= ~mask;
177b7aa1f16SKenji Kaneshige 	slot_ctrl |= (cmd & mask);
178f4778364SKenji Kaneshige 	ctrl->cmd_busy = 1;
1792d32a9aeSKenji Kaneshige 	smp_mb();
18025bd879eSMika Westerberg 	ctrl->slot_ctrl = slot_ctrl;
1811a84b99cSBjorn Helgaas 	pcie_capability_write_word(pdev, PCI_EXP_SLTCTL, slot_ctrl);
18240b96083SBjorn Helgaas 	ctrl->cmd_started = jiffies;
183f4778364SKenji Kaneshige 
184a5dd4b4bSAlex Williamson 	/*
185d22b3621SBjorn Helgaas 	 * Controllers with the Intel CF118 and similar errata advertise
186d22b3621SBjorn Helgaas 	 * Command Completed support, but they only set Command Completed
187d22b3621SBjorn Helgaas 	 * if we change the "Control" bits for power, power indicator,
188d22b3621SBjorn Helgaas 	 * attention indicator, or interlock.  If we only change the
189d22b3621SBjorn Helgaas 	 * "Enable" bits, they never set the Command Completed bit.
190d22b3621SBjorn Helgaas 	 */
191d22b3621SBjorn Helgaas 	if (pdev->broken_cmd_compl &&
192d22b3621SBjorn Helgaas 	    (slot_ctrl_orig & CC_ERRATUM_MASK) == (slot_ctrl & CC_ERRATUM_MASK))
193d22b3621SBjorn Helgaas 		ctrl->cmd_busy = 0;
194d22b3621SBjorn Helgaas 
195d22b3621SBjorn Helgaas 	/*
196a5dd4b4bSAlex Williamson 	 * Optionally wait for the hardware to be ready for a new command,
197a5dd4b4bSAlex Williamson 	 * indicating completion of the above issued command.
198a5dd4b4bSAlex Williamson 	 */
199a5dd4b4bSAlex Williamson 	if (wait)
200a5dd4b4bSAlex Williamson 		pcie_wait_cmd(ctrl);
201a5dd4b4bSAlex Williamson 
2021469d17dSJarod Wilson out:
20344ef4cefSKenji Kaneshige 	mutex_unlock(&ctrl->ctrl_lock);
2041da177e4SLinus Torvalds }
2051da177e4SLinus Torvalds 
206a5dd4b4bSAlex Williamson /**
207a5dd4b4bSAlex Williamson  * pcie_write_cmd - Issue controller command
208a5dd4b4bSAlex Williamson  * @ctrl: controller to which the command is issued
209a5dd4b4bSAlex Williamson  * @cmd:  command value written to slot control register
210a5dd4b4bSAlex Williamson  * @mask: bitmask of slot control register to be modified
211a5dd4b4bSAlex Williamson  */
pcie_write_cmd(struct controller * ctrl,u16 cmd,u16 mask)212a5dd4b4bSAlex Williamson static void pcie_write_cmd(struct controller *ctrl, u16 cmd, u16 mask)
213a5dd4b4bSAlex Williamson {
214a5dd4b4bSAlex Williamson 	pcie_do_write_cmd(ctrl, cmd, mask, true);
215a5dd4b4bSAlex Williamson }
216a5dd4b4bSAlex Williamson 
217a5dd4b4bSAlex Williamson /* Same as above without waiting for the hardware to latch */
pcie_write_cmd_nowait(struct controller * ctrl,u16 cmd,u16 mask)218a5dd4b4bSAlex Williamson static void pcie_write_cmd_nowait(struct controller *ctrl, u16 cmd, u16 mask)
219a5dd4b4bSAlex Williamson {
220a5dd4b4bSAlex Williamson 	pcie_do_write_cmd(ctrl, cmd, mask, false);
221a5dd4b4bSAlex Williamson }
222a5dd4b4bSAlex Williamson 
22387d0f2a5SMika Westerberg /**
22487d0f2a5SMika Westerberg  * pciehp_check_link_active() - Is the link active
22587d0f2a5SMika Westerberg  * @ctrl: PCIe hotplug controller
22687d0f2a5SMika Westerberg  *
22787d0f2a5SMika Westerberg  * Check whether the downstream link is currently active. Note it is
22887d0f2a5SMika Westerberg  * possible that the card is removed immediately after this so the
22987d0f2a5SMika Westerberg  * caller may need to take it into account.
23087d0f2a5SMika Westerberg  *
23187d0f2a5SMika Westerberg  * If the hotplug controller itself is not available anymore returns
23287d0f2a5SMika Westerberg  * %-ENODEV.
23387d0f2a5SMika Westerberg  */
pciehp_check_link_active(struct controller * ctrl)23487d0f2a5SMika Westerberg int pciehp_check_link_active(struct controller *ctrl)
235f18e9625SKenji Kaneshige {
236cd84d340SBjorn Helgaas 	struct pci_dev *pdev = ctrl_dev(ctrl);
2374e2ce405SYinghai Lu 	u16 lnk_status;
23887d0f2a5SMika Westerberg 	int ret;
239f18e9625SKenji Kaneshige 
24087d0f2a5SMika Westerberg 	ret = pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status);
241a3b0f10dSNaveen Naidu 	if (ret == PCIBIOS_DEVICE_NOT_FOUND || PCI_POSSIBLE_ERROR(lnk_status))
24287d0f2a5SMika Westerberg 		return -ENODEV;
24387d0f2a5SMika Westerberg 
2444e2ce405SYinghai Lu 	ret = !!(lnk_status & PCI_EXP_LNKSTA_DLLLA);
2454e2ce405SYinghai Lu 	ctrl_dbg(ctrl, "%s: lnk_status = %x\n", __func__, lnk_status);
2464e2ce405SYinghai Lu 
2474e2ce405SYinghai Lu 	return ret;
248f18e9625SKenji Kaneshige }
249f18e9625SKenji Kaneshige 
pci_bus_check_dev(struct pci_bus * bus,int devfn)2502f5d8e4fSYinghai Lu static bool pci_bus_check_dev(struct pci_bus *bus, int devfn)
2512f5d8e4fSYinghai Lu {
2522f5d8e4fSYinghai Lu 	u32 l;
2532f5d8e4fSYinghai Lu 	int count = 0;
2542f5d8e4fSYinghai Lu 	int delay = 1000, step = 20;
2552f5d8e4fSYinghai Lu 	bool found = false;
2562f5d8e4fSYinghai Lu 
2572f5d8e4fSYinghai Lu 	do {
2582f5d8e4fSYinghai Lu 		found = pci_bus_read_dev_vendor_id(bus, devfn, &l, 0);
2592f5d8e4fSYinghai Lu 		count++;
2602f5d8e4fSYinghai Lu 
2612f5d8e4fSYinghai Lu 		if (found)
2622f5d8e4fSYinghai Lu 			break;
2632f5d8e4fSYinghai Lu 
2642f5d8e4fSYinghai Lu 		msleep(step);
2652f5d8e4fSYinghai Lu 		delay -= step;
2662f5d8e4fSYinghai Lu 	} while (delay > 0);
2672f5d8e4fSYinghai Lu 
2687e696b8aSBjorn Helgaas 	if (count > 1)
269742ee16bSFrederick Lawler 		pr_debug("pci %04x:%02x:%02x.%d id reading try %d times with interval %d ms to get %08x\n",
2702f5d8e4fSYinghai Lu 			pci_domain_nr(bus), bus->number, PCI_SLOT(devfn),
2712f5d8e4fSYinghai Lu 			PCI_FUNC(devfn), count, step, l);
2722f5d8e4fSYinghai Lu 
2732f5d8e4fSYinghai Lu 	return found;
2742f5d8e4fSYinghai Lu }
2752f5d8e4fSYinghai Lu 
pcie_wait_for_presence(struct pci_dev * pdev)276f496648bSAlexandru Gagniuc static void pcie_wait_for_presence(struct pci_dev *pdev)
277f496648bSAlexandru Gagniuc {
278f496648bSAlexandru Gagniuc 	int timeout = 1250;
279f496648bSAlexandru Gagniuc 	u16 slot_status;
280f496648bSAlexandru Gagniuc 
281f496648bSAlexandru Gagniuc 	do {
282f496648bSAlexandru Gagniuc 		pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status);
283f496648bSAlexandru Gagniuc 		if (slot_status & PCI_EXP_SLTSTA_PDS)
284f496648bSAlexandru Gagniuc 			return;
285f496648bSAlexandru Gagniuc 		msleep(10);
286f496648bSAlexandru Gagniuc 		timeout -= 10;
287f496648bSAlexandru Gagniuc 	} while (timeout > 0);
288f496648bSAlexandru Gagniuc }
289f496648bSAlexandru Gagniuc 
pciehp_check_link_status(struct controller * ctrl)29082a9e79eSKenji Kaneshige int pciehp_check_link_status(struct controller *ctrl)
2911da177e4SLinus Torvalds {
292cd84d340SBjorn Helgaas 	struct pci_dev *pdev = ctrl_dev(ctrl);
2931a84b99cSBjorn Helgaas 	bool found;
2941da177e4SLinus Torvalds 	u16 lnk_status;
2951da177e4SLinus Torvalds 
2968a614499SLukas Wunner 	if (!pcie_wait_for_link(pdev, true)) {
2978a614499SLukas Wunner 		ctrl_info(ctrl, "Slot(%s): No link\n", slot_name(ctrl));
298f0157160SKeith Busch 		return -1;
2998a614499SLukas Wunner 	}
300f18e9625SKenji Kaneshige 
301f496648bSAlexandru Gagniuc 	if (ctrl->inband_presence_disabled)
302f496648bSAlexandru Gagniuc 		pcie_wait_for_presence(pdev);
303f496648bSAlexandru Gagniuc 
3042f5d8e4fSYinghai Lu 	found = pci_bus_check_dev(ctrl->pcie->port->subordinate,
3052f5d8e4fSYinghai Lu 					PCI_DEVFN(0, 0));
3060027cb3eSKenji Kaneshige 
3076c35a1acSLukas Wunner 	/* ignore link or presence changes up to this point */
3086c35a1acSLukas Wunner 	if (found)
3096c35a1acSLukas Wunner 		atomic_and(~(PCI_EXP_SLTSTA_DLLSC | PCI_EXP_SLTSTA_PDC),
3106c35a1acSLukas Wunner 			   &ctrl->pending_events);
3116c35a1acSLukas Wunner 
3121a84b99cSBjorn Helgaas 	pcie_capability_read_word(pdev, PCI_EXP_LNKSTA, &lnk_status);
3137f2feec1STaku Izumi 	ctrl_dbg(ctrl, "%s: lnk_status = %x\n", __func__, lnk_status);
314322162a7SKenji Kaneshige 	if ((lnk_status & PCI_EXP_LNKSTA_LT) ||
315322162a7SKenji Kaneshige 	    !(lnk_status & PCI_EXP_LNKSTA_NLW)) {
3168a614499SLukas Wunner 		ctrl_info(ctrl, "Slot(%s): Cannot train link: status %#06x\n",
3178a614499SLukas Wunner 			  slot_name(ctrl), lnk_status);
3181a84b99cSBjorn Helgaas 		return -1;
3191da177e4SLinus Torvalds 	}
3201da177e4SLinus Torvalds 
321fdbd3ce9SYinghai Lu 	pcie_update_link_speed(ctrl->pcie->port->subordinate, lnk_status);
322fdbd3ce9SYinghai Lu 
3238a614499SLukas Wunner 	if (!found) {
3248a614499SLukas Wunner 		ctrl_info(ctrl, "Slot(%s): No device found\n",
3258a614499SLukas Wunner 			  slot_name(ctrl));
3261a84b99cSBjorn Helgaas 		return -1;
3278a614499SLukas Wunner 	}
3282f5d8e4fSYinghai Lu 
3291a84b99cSBjorn Helgaas 	return 0;
3301da177e4SLinus Torvalds }
3311da177e4SLinus Torvalds 
__pciehp_link_set(struct controller * ctrl,bool enable)3327f822999SYinghai Lu static int __pciehp_link_set(struct controller *ctrl, bool enable)
3337f822999SYinghai Lu {
334cd84d340SBjorn Helgaas 	struct pci_dev *pdev = ctrl_dev(ctrl);
3357f822999SYinghai Lu 
336*5f75f96cSIlpo Järvinen 	pcie_capability_clear_and_set_word(pdev, PCI_EXP_LNKCTL,
337*5f75f96cSIlpo Järvinen 					   PCI_EXP_LNKCTL_LD,
338*5f75f96cSIlpo Järvinen 					   enable ? 0 : PCI_EXP_LNKCTL_LD);
3397f822999SYinghai Lu 
3401a84b99cSBjorn Helgaas 	return 0;
3417f822999SYinghai Lu }
3427f822999SYinghai Lu 
pciehp_link_enable(struct controller * ctrl)3437f822999SYinghai Lu static int pciehp_link_enable(struct controller *ctrl)
3447f822999SYinghai Lu {
3457f822999SYinghai Lu 	return __pciehp_link_set(ctrl, true);
3467f822999SYinghai Lu }
3477f822999SYinghai Lu 
pciehp_get_raw_indicator_status(struct hotplug_slot * hotplug_slot,u8 * status)348576243b3SKeith Busch int pciehp_get_raw_indicator_status(struct hotplug_slot *hotplug_slot,
349576243b3SKeith Busch 				    u8 *status)
350576243b3SKeith Busch {
351125450f8SLukas Wunner 	struct controller *ctrl = to_ctrl(hotplug_slot);
3525790a9c7SLukas Wunner 	struct pci_dev *pdev = ctrl_dev(ctrl);
353576243b3SKeith Busch 	u16 slot_ctrl;
354576243b3SKeith Busch 
3554417aa45SLukas Wunner 	pci_config_pm_runtime_get(pdev);
356576243b3SKeith Busch 	pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &slot_ctrl);
3574417aa45SLukas Wunner 	pci_config_pm_runtime_put(pdev);
358576243b3SKeith Busch 	*status = (slot_ctrl & (PCI_EXP_SLTCTL_AIC | PCI_EXP_SLTCTL_PIC)) >> 6;
359576243b3SKeith Busch 	return 0;
360576243b3SKeith Busch }
361576243b3SKeith Busch 
pciehp_get_attention_status(struct hotplug_slot * hotplug_slot,u8 * status)362eee6e273SLukas Wunner int pciehp_get_attention_status(struct hotplug_slot *hotplug_slot, u8 *status)
3631da177e4SLinus Torvalds {
364125450f8SLukas Wunner 	struct controller *ctrl = to_ctrl(hotplug_slot);
365cd84d340SBjorn Helgaas 	struct pci_dev *pdev = ctrl_dev(ctrl);
3661da177e4SLinus Torvalds 	u16 slot_ctrl;
3671da177e4SLinus Torvalds 
3684417aa45SLukas Wunner 	pci_config_pm_runtime_get(pdev);
3691a84b99cSBjorn Helgaas 	pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &slot_ctrl);
3704417aa45SLukas Wunner 	pci_config_pm_runtime_put(pdev);
3711518c17aSKenji Kaneshige 	ctrl_dbg(ctrl, "%s: SLOTCTRL %x, value read %x\n", __func__,
3721518c17aSKenji Kaneshige 		 pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_ctrl);
3731da177e4SLinus Torvalds 
374e7b4f0d7SBjorn Helgaas 	switch (slot_ctrl & PCI_EXP_SLTCTL_AIC) {
375e7b4f0d7SBjorn Helgaas 	case PCI_EXP_SLTCTL_ATTN_IND_ON:
3761da177e4SLinus Torvalds 		*status = 1;	/* On */
3771da177e4SLinus Torvalds 		break;
378e7b4f0d7SBjorn Helgaas 	case PCI_EXP_SLTCTL_ATTN_IND_BLINK:
3791da177e4SLinus Torvalds 		*status = 2;	/* Blink */
3801da177e4SLinus Torvalds 		break;
381e7b4f0d7SBjorn Helgaas 	case PCI_EXP_SLTCTL_ATTN_IND_OFF:
3821da177e4SLinus Torvalds 		*status = 0;	/* Off */
3831da177e4SLinus Torvalds 		break;
3841da177e4SLinus Torvalds 	default:
3851da177e4SLinus Torvalds 		*status = 0xFF;
3861da177e4SLinus Torvalds 		break;
3871da177e4SLinus Torvalds 	}
388eee6e273SLukas Wunner 
389eee6e273SLukas Wunner 	return 0;
3901da177e4SLinus Torvalds }
3911da177e4SLinus Torvalds 
pciehp_get_power_status(struct controller * ctrl,u8 * status)3925790a9c7SLukas Wunner void pciehp_get_power_status(struct controller *ctrl, u8 *status)
3931da177e4SLinus Torvalds {
394cd84d340SBjorn Helgaas 	struct pci_dev *pdev = ctrl_dev(ctrl);
3951da177e4SLinus Torvalds 	u16 slot_ctrl;
3961da177e4SLinus Torvalds 
3971a84b99cSBjorn Helgaas 	pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &slot_ctrl);
3981518c17aSKenji Kaneshige 	ctrl_dbg(ctrl, "%s: SLOTCTRL %x value read %x\n", __func__,
3991518c17aSKenji Kaneshige 		 pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, slot_ctrl);
4001da177e4SLinus Torvalds 
401e7b4f0d7SBjorn Helgaas 	switch (slot_ctrl & PCI_EXP_SLTCTL_PCC) {
402e7b4f0d7SBjorn Helgaas 	case PCI_EXP_SLTCTL_PWR_ON:
403e7b4f0d7SBjorn Helgaas 		*status = 1;	/* On */
4041da177e4SLinus Torvalds 		break;
405e7b4f0d7SBjorn Helgaas 	case PCI_EXP_SLTCTL_PWR_OFF:
406e7b4f0d7SBjorn Helgaas 		*status = 0;	/* Off */
4071da177e4SLinus Torvalds 		break;
4081da177e4SLinus Torvalds 	default:
4091da177e4SLinus Torvalds 		*status = 0xFF;
4101da177e4SLinus Torvalds 		break;
4111da177e4SLinus Torvalds 	}
4121da177e4SLinus Torvalds }
4131da177e4SLinus Torvalds 
pciehp_get_latch_status(struct controller * ctrl,u8 * status)4145790a9c7SLukas Wunner void pciehp_get_latch_status(struct controller *ctrl, u8 *status)
4151da177e4SLinus Torvalds {
4165790a9c7SLukas Wunner 	struct pci_dev *pdev = ctrl_dev(ctrl);
4171da177e4SLinus Torvalds 	u16 slot_status;
4181da177e4SLinus Torvalds 
4191a84b99cSBjorn Helgaas 	pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status);
420322162a7SKenji Kaneshige 	*status = !!(slot_status & PCI_EXP_SLTSTA_MRLSS);
4211da177e4SLinus Torvalds }
4221da177e4SLinus Torvalds 
42387d0f2a5SMika Westerberg /**
42487d0f2a5SMika Westerberg  * pciehp_card_present() - Is the card present
42587d0f2a5SMika Westerberg  * @ctrl: PCIe hotplug controller
42687d0f2a5SMika Westerberg  *
42787d0f2a5SMika Westerberg  * Function checks whether the card is currently present in the slot and
42887d0f2a5SMika Westerberg  * in that case returns true. Note it is possible that the card is
42987d0f2a5SMika Westerberg  * removed immediately after the check so the caller may need to take
43087d0f2a5SMika Westerberg  * this into account.
43187d0f2a5SMika Westerberg  *
43287d0f2a5SMika Westerberg  * It the hotplug controller itself is not available anymore returns
43387d0f2a5SMika Westerberg  * %-ENODEV.
43487d0f2a5SMika Westerberg  */
pciehp_card_present(struct controller * ctrl)43587d0f2a5SMika Westerberg int pciehp_card_present(struct controller *ctrl)
4361da177e4SLinus Torvalds {
43780696f99SLukas Wunner 	struct pci_dev *pdev = ctrl_dev(ctrl);
4381da177e4SLinus Torvalds 	u16 slot_status;
43987d0f2a5SMika Westerberg 	int ret;
4401da177e4SLinus Torvalds 
44187d0f2a5SMika Westerberg 	ret = pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status);
442a3b0f10dSNaveen Naidu 	if (ret == PCIBIOS_DEVICE_NOT_FOUND || PCI_POSSIBLE_ERROR(slot_status))
44387d0f2a5SMika Westerberg 		return -ENODEV;
44487d0f2a5SMika Westerberg 
44587d0f2a5SMika Westerberg 	return !!(slot_status & PCI_EXP_SLTSTA_PDS);
44680696f99SLukas Wunner }
44780696f99SLukas Wunner 
44880696f99SLukas Wunner /**
44980696f99SLukas Wunner  * pciehp_card_present_or_link_active() - whether given slot is occupied
45080696f99SLukas Wunner  * @ctrl: PCIe hotplug controller
45180696f99SLukas Wunner  *
45280696f99SLukas Wunner  * Unlike pciehp_card_present(), which determines presence solely from the
45380696f99SLukas Wunner  * Presence Detect State bit, this helper also returns true if the Link Active
45480696f99SLukas Wunner  * bit is set.  This is a concession to broken hotplug ports which hardwire
45580696f99SLukas Wunner  * Presence Detect State to zero, such as Wilocity's [1ae9:0200].
45687d0f2a5SMika Westerberg  *
45787d0f2a5SMika Westerberg  * Returns: %1 if the slot is occupied and %0 if it is not. If the hotplug
45887d0f2a5SMika Westerberg  *	    port is not present anymore returns %-ENODEV.
45980696f99SLukas Wunner  */
pciehp_card_present_or_link_active(struct controller * ctrl)46087d0f2a5SMika Westerberg int pciehp_card_present_or_link_active(struct controller *ctrl)
46180696f99SLukas Wunner {
46287d0f2a5SMika Westerberg 	int ret;
46387d0f2a5SMika Westerberg 
46487d0f2a5SMika Westerberg 	ret = pciehp_card_present(ctrl);
46587d0f2a5SMika Westerberg 	if (ret)
46687d0f2a5SMika Westerberg 		return ret;
46787d0f2a5SMika Westerberg 
46887d0f2a5SMika Westerberg 	return pciehp_check_link_active(ctrl);
4691da177e4SLinus Torvalds }
4701da177e4SLinus Torvalds 
pciehp_query_power_fault(struct controller * ctrl)4715790a9c7SLukas Wunner int pciehp_query_power_fault(struct controller *ctrl)
4721da177e4SLinus Torvalds {
4735790a9c7SLukas Wunner 	struct pci_dev *pdev = ctrl_dev(ctrl);
4741da177e4SLinus Torvalds 	u16 slot_status;
4751da177e4SLinus Torvalds 
4761a84b99cSBjorn Helgaas 	pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status);
477322162a7SKenji Kaneshige 	return !!(slot_status & PCI_EXP_SLTSTA_PFD);
4781da177e4SLinus Torvalds }
4791da177e4SLinus Torvalds 
pciehp_set_raw_indicator_status(struct hotplug_slot * hotplug_slot,u8 status)480576243b3SKeith Busch int pciehp_set_raw_indicator_status(struct hotplug_slot *hotplug_slot,
481576243b3SKeith Busch 				    u8 status)
482576243b3SKeith Busch {
483125450f8SLukas Wunner 	struct controller *ctrl = to_ctrl(hotplug_slot);
4844417aa45SLukas Wunner 	struct pci_dev *pdev = ctrl_dev(ctrl);
485576243b3SKeith Busch 
4864417aa45SLukas Wunner 	pci_config_pm_runtime_get(pdev);
487576243b3SKeith Busch 	pcie_write_cmd_nowait(ctrl, status << 6,
488576243b3SKeith Busch 			      PCI_EXP_SLTCTL_AIC | PCI_EXP_SLTCTL_PIC);
4894417aa45SLukas Wunner 	pci_config_pm_runtime_put(pdev);
490576243b3SKeith Busch 	return 0;
491576243b3SKeith Busch }
492576243b3SKeith Busch 
493688033f5SDenis Efremov /**
494688033f5SDenis Efremov  * pciehp_set_indicators() - set attention indicator, power indicator, or both
495688033f5SDenis Efremov  * @ctrl: PCIe hotplug controller
496688033f5SDenis Efremov  * @pwr: one of:
497688033f5SDenis Efremov  *	PCI_EXP_SLTCTL_PWR_IND_ON
498688033f5SDenis Efremov  *	PCI_EXP_SLTCTL_PWR_IND_BLINK
499688033f5SDenis Efremov  *	PCI_EXP_SLTCTL_PWR_IND_OFF
500688033f5SDenis Efremov  * @attn: one of:
501688033f5SDenis Efremov  *	PCI_EXP_SLTCTL_ATTN_IND_ON
502688033f5SDenis Efremov  *	PCI_EXP_SLTCTL_ATTN_IND_BLINK
503688033f5SDenis Efremov  *	PCI_EXP_SLTCTL_ATTN_IND_OFF
504688033f5SDenis Efremov  *
505688033f5SDenis Efremov  * Either @pwr or @attn can also be INDICATOR_NOOP to leave that indicator
506688033f5SDenis Efremov  * unchanged.
507688033f5SDenis Efremov  */
pciehp_set_indicators(struct controller * ctrl,int pwr,int attn)508688033f5SDenis Efremov void pciehp_set_indicators(struct controller *ctrl, int pwr, int attn)
509688033f5SDenis Efremov {
510688033f5SDenis Efremov 	u16 cmd = 0, mask = 0;
511688033f5SDenis Efremov 
512688033f5SDenis Efremov 	if (PWR_LED(ctrl) && pwr != INDICATOR_NOOP) {
513688033f5SDenis Efremov 		cmd |= (pwr & PCI_EXP_SLTCTL_PIC);
514688033f5SDenis Efremov 		mask |= PCI_EXP_SLTCTL_PIC;
515688033f5SDenis Efremov 	}
516688033f5SDenis Efremov 
517688033f5SDenis Efremov 	if (ATTN_LED(ctrl) && attn != INDICATOR_NOOP) {
518688033f5SDenis Efremov 		cmd |= (attn & PCI_EXP_SLTCTL_AIC);
519688033f5SDenis Efremov 		mask |= PCI_EXP_SLTCTL_AIC;
520688033f5SDenis Efremov 	}
521688033f5SDenis Efremov 
522688033f5SDenis Efremov 	if (cmd) {
523688033f5SDenis Efremov 		pcie_write_cmd_nowait(ctrl, cmd, mask);
524688033f5SDenis Efremov 		ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
525688033f5SDenis Efremov 			 pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, cmd);
526688033f5SDenis Efremov 	}
527688033f5SDenis Efremov }
528688033f5SDenis Efremov 
pciehp_power_on_slot(struct controller * ctrl)5295790a9c7SLukas Wunner int pciehp_power_on_slot(struct controller *ctrl)
5301da177e4SLinus Torvalds {
531cd84d340SBjorn Helgaas 	struct pci_dev *pdev = ctrl_dev(ctrl);
532f4778364SKenji Kaneshige 	u16 slot_status;
5331a84b99cSBjorn Helgaas 	int retval;
5341da177e4SLinus Torvalds 
53534fb6bf9SKeith Busch 	/* Clear power-fault bit from previous power failures */
5361a84b99cSBjorn Helgaas 	pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &slot_status);
5372f2ed41cSBjorn Helgaas 	if (slot_status & PCI_EXP_SLTSTA_PFD)
5382f2ed41cSBjorn Helgaas 		pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
5392f2ed41cSBjorn Helgaas 					   PCI_EXP_SLTSTA_PFD);
5405651c48cSKenji Kaneshige 	ctrl->power_fault_detected = 0;
541a0f018daSKenji Kaneshige 
542e7b4f0d7SBjorn Helgaas 	pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_ON, PCI_EXP_SLTCTL_PCC);
5431518c17aSKenji Kaneshige 	ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
544e7b4f0d7SBjorn Helgaas 		 pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL,
545e7b4f0d7SBjorn Helgaas 		 PCI_EXP_SLTCTL_PWR_ON);
5461da177e4SLinus Torvalds 
5472debd928SYinghai Lu 	retval = pciehp_link_enable(ctrl);
5482debd928SYinghai Lu 	if (retval)
5492debd928SYinghai Lu 		ctrl_err(ctrl, "%s: Can not enable the link!\n", __func__);
5502debd928SYinghai Lu 
5511da177e4SLinus Torvalds 	return retval;
5521da177e4SLinus Torvalds }
5531da177e4SLinus Torvalds 
pciehp_power_off_slot(struct controller * ctrl)5545790a9c7SLukas Wunner void pciehp_power_off_slot(struct controller *ctrl)
5551da177e4SLinus Torvalds {
556e7b4f0d7SBjorn Helgaas 	pcie_write_cmd(ctrl, PCI_EXP_SLTCTL_PWR_OFF, PCI_EXP_SLTCTL_PCC);
5571518c17aSKenji Kaneshige 	ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
558e7b4f0d7SBjorn Helgaas 		 pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL,
559e7b4f0d7SBjorn Helgaas 		 PCI_EXP_SLTCTL_PWR_OFF);
5601da177e4SLinus Torvalds }
5611da177e4SLinus Torvalds 
pciehp_ignore_dpc_link_change(struct controller * ctrl,struct pci_dev * pdev,int irq)562a97396c6SLukas Wunner static void pciehp_ignore_dpc_link_change(struct controller *ctrl,
563a97396c6SLukas Wunner 					  struct pci_dev *pdev, int irq)
564a97396c6SLukas Wunner {
565a97396c6SLukas Wunner 	/*
566a97396c6SLukas Wunner 	 * Ignore link changes which occurred while waiting for DPC recovery.
567a97396c6SLukas Wunner 	 * Could be several if DPC triggered multiple times consecutively.
568a97396c6SLukas Wunner 	 */
569a97396c6SLukas Wunner 	synchronize_hardirq(irq);
570a97396c6SLukas Wunner 	atomic_and(~PCI_EXP_SLTSTA_DLLSC, &ctrl->pending_events);
571a97396c6SLukas Wunner 	if (pciehp_poll_mode)
572a97396c6SLukas Wunner 		pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
573a97396c6SLukas Wunner 					   PCI_EXP_SLTSTA_DLLSC);
574a97396c6SLukas Wunner 	ctrl_info(ctrl, "Slot(%s): Link Down/Up ignored (recovered by DPC)\n",
575a97396c6SLukas Wunner 		  slot_name(ctrl));
576a97396c6SLukas Wunner 
577a97396c6SLukas Wunner 	/*
578a97396c6SLukas Wunner 	 * If the link is unexpectedly down after successful recovery,
579a97396c6SLukas Wunner 	 * the corresponding link change may have been ignored above.
580a97396c6SLukas Wunner 	 * Synthesize it to ensure that it is acted on.
581a97396c6SLukas Wunner 	 */
582085a9f43SHans de Goede 	down_read_nested(&ctrl->reset_lock, ctrl->depth);
583a97396c6SLukas Wunner 	if (!pciehp_check_link_active(ctrl))
584a97396c6SLukas Wunner 		pciehp_request(ctrl, PCI_EXP_SLTSTA_DLLSC);
585a97396c6SLukas Wunner 	up_read(&ctrl->reset_lock);
586a97396c6SLukas Wunner }
587a97396c6SLukas Wunner 
pciehp_isr(int irq,void * dev_id)588fad214b0SMayurkumar Patel static irqreturn_t pciehp_isr(int irq, void *dev_id)
5891da177e4SLinus Torvalds {
59048fe3915SKenji Kaneshige 	struct controller *ctrl = (struct controller *)dev_id;
591cd84d340SBjorn Helgaas 	struct pci_dev *pdev = ctrl_dev(ctrl);
5926b08c385SLukas Wunner 	struct device *parent = pdev->dev.parent;
5938edf5332SStuart Hayes 	u16 status, events = 0;
5941da177e4SLinus Torvalds 
5957b4ce26bSLukas Wunner 	/*
596720d6a67SMika Westerberg 	 * Interrupts only occur in D3hot or shallower and only if enabled
597720d6a67SMika Westerberg 	 * in the Slot Control register (PCIe r4.0, sec 6.7.3.4).
5987b4ce26bSLukas Wunner 	 */
599720d6a67SMika Westerberg 	if (pdev->current_state == PCI_D3cold ||
600720d6a67SMika Westerberg 	    (!(ctrl->slot_ctrl & PCI_EXP_SLTCTL_HPIE) && !pciehp_poll_mode))
601ed91de7eSLukas Wunner 		return IRQ_NONE;
602ed91de7eSLukas Wunner 
6036b08c385SLukas Wunner 	/*
6046b08c385SLukas Wunner 	 * Keep the port accessible by holding a runtime PM ref on its parent.
6056b08c385SLukas Wunner 	 * Defer resume of the parent to the IRQ thread if it's suspended.
6066b08c385SLukas Wunner 	 * Mask the interrupt until then.
6076b08c385SLukas Wunner 	 */
6086b08c385SLukas Wunner 	if (parent) {
6096b08c385SLukas Wunner 		pm_runtime_get_noresume(parent);
6106b08c385SLukas Wunner 		if (!pm_runtime_active(parent)) {
6116b08c385SLukas Wunner 			pm_runtime_put(parent);
6126b08c385SLukas Wunner 			disable_irq_nosync(irq);
6136b08c385SLukas Wunner 			atomic_or(RERUN_ISR, &ctrl->pending_events);
6146b08c385SLukas Wunner 			return IRQ_WAKE_THREAD;
6156b08c385SLukas Wunner 		}
6166b08c385SLukas Wunner 	}
6176b08c385SLukas Wunner 
6188edf5332SStuart Hayes read_status:
619a8499f20SBjorn Helgaas 	pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &status);
620a3b0f10dSNaveen Naidu 	if (PCI_POSSIBLE_ERROR(status)) {
621fad214b0SMayurkumar Patel 		ctrl_info(ctrl, "%s: no response from device\n", __func__);
6226b08c385SLukas Wunner 		if (parent)
6236b08c385SLukas Wunner 			pm_runtime_put(parent);
62470e8b401SBjorn Helgaas 		return IRQ_NONE;
6251469d17dSJarod Wilson 	}
6261da177e4SLinus Torvalds 
627a8499f20SBjorn Helgaas 	/*
628a8499f20SBjorn Helgaas 	 * Slot Status contains plain status bits as well as event
629a8499f20SBjorn Helgaas 	 * notification bits; right now we only want the event bits.
630a8499f20SBjorn Helgaas 	 */
6318edf5332SStuart Hayes 	status &= PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD |
632a8499f20SBjorn Helgaas 		  PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_CC |
6338edf5332SStuart Hayes 		  PCI_EXP_SLTSTA_DLLSC;
6347612b3b2SKeith Busch 
6357612b3b2SKeith Busch 	/*
6367612b3b2SKeith Busch 	 * If we've already reported a power fault, don't report it again
6377612b3b2SKeith Busch 	 * until we've done something to handle it.
6387612b3b2SKeith Busch 	 */
6397612b3b2SKeith Busch 	if (ctrl->power_fault_detected)
6408edf5332SStuart Hayes 		status &= ~PCI_EXP_SLTSTA_PFD;
64123584c1eSLukas Wunner 	else if (status & PCI_EXP_SLTSTA_PFD)
64223584c1eSLukas Wunner 		ctrl->power_fault_detected = true;
6437612b3b2SKeith Busch 
6448edf5332SStuart Hayes 	events |= status;
6456b08c385SLukas Wunner 	if (!events) {
6466b08c385SLukas Wunner 		if (parent)
6476b08c385SLukas Wunner 			pm_runtime_put(parent);
6481da177e4SLinus Torvalds 		return IRQ_NONE;
6496b08c385SLukas Wunner 	}
6501da177e4SLinus Torvalds 
6518edf5332SStuart Hayes 	if (status) {
65223584c1eSLukas Wunner 		pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, status);
6538edf5332SStuart Hayes 
6548edf5332SStuart Hayes 		/*
6558edf5332SStuart Hayes 		 * In MSI mode, all event bits must be zero before the port
6568edf5332SStuart Hayes 		 * will send a new interrupt (PCIe Base Spec r5.0 sec 6.7.3.4).
6578edf5332SStuart Hayes 		 * So re-read the Slot Status register in case a bit was set
6588edf5332SStuart Hayes 		 * between read and write.
6598edf5332SStuart Hayes 		 */
6608edf5332SStuart Hayes 		if (pci_dev_msi_enabled(pdev) && !pciehp_poll_mode)
6618edf5332SStuart Hayes 			goto read_status;
6628edf5332SStuart Hayes 	}
6638edf5332SStuart Hayes 
664a8499f20SBjorn Helgaas 	ctrl_dbg(ctrl, "pending interrupts %#06x from Slot Status\n", events);
6656b08c385SLukas Wunner 	if (parent)
6666b08c385SLukas Wunner 		pm_runtime_put(parent);
6671da177e4SLinus Torvalds 
6687b4ce26bSLukas Wunner 	/*
6697b4ce26bSLukas Wunner 	 * Command Completed notifications are not deferred to the
6707b4ce26bSLukas Wunner 	 * IRQ thread because it may be waiting for their arrival.
6717b4ce26bSLukas Wunner 	 */
672a8499f20SBjorn Helgaas 	if (events & PCI_EXP_SLTSTA_CC) {
673262303feSKenji Kaneshige 		ctrl->cmd_busy = 0;
6742d32a9aeSKenji Kaneshige 		smp_mb();
675d737bdc1SKenji Kaneshige 		wake_up(&ctrl->queue);
6767b4ce26bSLukas Wunner 
6777b4ce26bSLukas Wunner 		if (events == PCI_EXP_SLTSTA_CC)
6787b4ce26bSLukas Wunner 			return IRQ_HANDLED;
6797b4ce26bSLukas Wunner 
6807b4ce26bSLukas Wunner 		events &= ~PCI_EXP_SLTSTA_CC;
6811da177e4SLinus Torvalds 	}
6821da177e4SLinus Torvalds 
6831204e35bSLukas Wunner 	if (pdev->ignore_hotplug) {
6841204e35bSLukas Wunner 		ctrl_dbg(ctrl, "ignoring hotplug event %#06x\n", events);
685b440bde7SBjorn Helgaas 		return IRQ_HANDLED;
686b440bde7SBjorn Helgaas 	}
687b440bde7SBjorn Helgaas 
6887b4ce26bSLukas Wunner 	/* Save pending events for consumption by IRQ thread. */
6897b4ce26bSLukas Wunner 	atomic_or(events, &ctrl->pending_events);
6907b4ce26bSLukas Wunner 	return IRQ_WAKE_THREAD;
6917b4ce26bSLukas Wunner }
6927b4ce26bSLukas Wunner 
pciehp_ist(int irq,void * dev_id)6937b4ce26bSLukas Wunner static irqreturn_t pciehp_ist(int irq, void *dev_id)
6947b4ce26bSLukas Wunner {
6957b4ce26bSLukas Wunner 	struct controller *ctrl = (struct controller *)dev_id;
6966b08c385SLukas Wunner 	struct pci_dev *pdev = ctrl_dev(ctrl);
6976b08c385SLukas Wunner 	irqreturn_t ret;
6987b4ce26bSLukas Wunner 	u32 events;
6997b4ce26bSLukas Wunner 
700157c1062SLukas Wunner 	ctrl->ist_running = true;
7016b08c385SLukas Wunner 	pci_config_pm_runtime_get(pdev);
7026b08c385SLukas Wunner 
7036b08c385SLukas Wunner 	/* rerun pciehp_isr() if the port was inaccessible on interrupt */
7046b08c385SLukas Wunner 	if (atomic_fetch_and(~RERUN_ISR, &ctrl->pending_events) & RERUN_ISR) {
7056b08c385SLukas Wunner 		ret = pciehp_isr(irq, dev_id);
7066b08c385SLukas Wunner 		enable_irq(irq);
7073e487d2eSLukas Wunner 		if (ret != IRQ_WAKE_THREAD)
7083e487d2eSLukas Wunner 			goto out;
7096b08c385SLukas Wunner 	}
7106b08c385SLukas Wunner 
7117b4ce26bSLukas Wunner 	synchronize_hardirq(irq);
7127b4ce26bSLukas Wunner 	events = atomic_xchg(&ctrl->pending_events, 0);
7136b08c385SLukas Wunner 	if (!events) {
7143e487d2eSLukas Wunner 		ret = IRQ_NONE;
7153e487d2eSLukas Wunner 		goto out;
7166b08c385SLukas Wunner 	}
7177b4ce26bSLukas Wunner 
718c6b069e9SKenji Kaneshige 	/* Check Attention Button Pressed */
7195054133aSBjorn Helgaas 	if (events & PCI_EXP_SLTSTA_ABP)
7205790a9c7SLukas Wunner 		pciehp_handle_button_press(ctrl);
72148fe3915SKenji Kaneshige 
72234fb6bf9SKeith Busch 	/* Check Power Fault Detected */
72323584c1eSLukas Wunner 	if (events & PCI_EXP_SLTSTA_PFD) {
7245790a9c7SLukas Wunner 		ctrl_err(ctrl, "Slot(%s): Power fault\n", slot_name(ctrl));
72594719ba0SDenis Efremov 		pciehp_set_indicators(ctrl, PCI_EXP_SLTCTL_PWR_IND_OFF,
72694719ba0SDenis Efremov 				      PCI_EXP_SLTCTL_ATTN_IND_ON);
72734fb6bf9SKeith Busch 	}
72834fb6bf9SKeith Busch 
729385895feSAshok Raj 	/*
730a97396c6SLukas Wunner 	 * Ignore Link Down/Up events caused by Downstream Port Containment
731a97396c6SLukas Wunner 	 * if recovery from the error succeeded.
732a97396c6SLukas Wunner 	 */
733a97396c6SLukas Wunner 	if ((events & PCI_EXP_SLTSTA_DLLSC) && pci_dpc_recovered(pdev) &&
734a97396c6SLukas Wunner 	    ctrl->state == ON_STATE) {
735a97396c6SLukas Wunner 		events &= ~PCI_EXP_SLTSTA_DLLSC;
736a97396c6SLukas Wunner 		pciehp_ignore_dpc_link_change(ctrl, pdev, irq);
737a97396c6SLukas Wunner 	}
738a97396c6SLukas Wunner 
739a97396c6SLukas Wunner 	/*
74032a8cef2SLukas Wunner 	 * Disable requests have higher priority than Presence Detect Changed
74132a8cef2SLukas Wunner 	 * or Data Link Layer State Changed events.
742385895feSAshok Raj 	 */
743085a9f43SHans de Goede 	down_read_nested(&ctrl->reset_lock, ctrl->depth);
74432a8cef2SLukas Wunner 	if (events & DISABLE_SLOT)
7455790a9c7SLukas Wunner 		pciehp_handle_disable_request(ctrl);
746d331710eSLukas Wunner 	else if (events & (PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC))
7475790a9c7SLukas Wunner 		pciehp_handle_presence_or_link_change(ctrl, events);
7485b3f7b7dSLukas Wunner 	up_read(&ctrl->reset_lock);
74948fe3915SKenji Kaneshige 
7503e487d2eSLukas Wunner 	ret = IRQ_HANDLED;
7513e487d2eSLukas Wunner out:
7526b08c385SLukas Wunner 	pci_config_pm_runtime_put(pdev);
753157c1062SLukas Wunner 	ctrl->ist_running = false;
75432a8cef2SLukas Wunner 	wake_up(&ctrl->requester);
7553e487d2eSLukas Wunner 	return ret;
7561da177e4SLinus Torvalds }
7571da177e4SLinus Torvalds 
pciehp_poll(void * data)758ec07a447SLukas Wunner static int pciehp_poll(void *data)
759ec07a447SLukas Wunner {
760ec07a447SLukas Wunner 	struct controller *ctrl = data;
761ec07a447SLukas Wunner 
762ec07a447SLukas Wunner 	schedule_timeout_idle(10 * HZ); /* start with 10 sec delay */
763ec07a447SLukas Wunner 
764ec07a447SLukas Wunner 	while (!kthread_should_stop()) {
76532a8cef2SLukas Wunner 		/* poll for interrupt events or user requests */
76632a8cef2SLukas Wunner 		while (pciehp_isr(IRQ_NOTCONNECTED, ctrl) == IRQ_WAKE_THREAD ||
76732a8cef2SLukas Wunner 		       atomic_read(&ctrl->pending_events))
768ec07a447SLukas Wunner 			pciehp_ist(IRQ_NOTCONNECTED, ctrl);
769ec07a447SLukas Wunner 
770ec07a447SLukas Wunner 		if (pciehp_poll_time <= 0 || pciehp_poll_time > 60)
771ec07a447SLukas Wunner 			pciehp_poll_time = 2; /* clamp to sane value */
772ec07a447SLukas Wunner 
773ec07a447SLukas Wunner 		schedule_timeout_idle(pciehp_poll_time * HZ);
774ec07a447SLukas Wunner 	}
775ec07a447SLukas Wunner 
776ec07a447SLukas Wunner 	return 0;
777ec07a447SLukas Wunner }
778ec07a447SLukas Wunner 
pcie_enable_notification(struct controller * ctrl)77913c65840SMika Westerberg static void pcie_enable_notification(struct controller *ctrl)
780ecdde939SMark Lord {
781c27fb883SKenji Kaneshige 	u16 cmd, mask;
7821da177e4SLinus Torvalds 
7835651c48cSKenji Kaneshige 	/*
7845651c48cSKenji Kaneshige 	 * TBD: Power fault detected software notification support.
7855651c48cSKenji Kaneshige 	 *
7865651c48cSKenji Kaneshige 	 * Power fault detected software notification is not enabled
7875651c48cSKenji Kaneshige 	 * now, because it caused power fault detected interrupt storm
7885651c48cSKenji Kaneshige 	 * on some machines. On those machines, power fault detected
7895651c48cSKenji Kaneshige 	 * bit in the slot status register was set again immediately
7905651c48cSKenji Kaneshige 	 * when it is cleared in the interrupt service routine, and
7915651c48cSKenji Kaneshige 	 * next power fault detected interrupt was notified again.
7925651c48cSKenji Kaneshige 	 */
7934f854f2aSRajat Jain 
7944f854f2aSRajat Jain 	/*
7954f854f2aSRajat Jain 	 * Always enable link events: thus link-up and link-down shall
7964f854f2aSRajat Jain 	 * always be treated as hotplug and unplug respectively. Enable
7974f854f2aSRajat Jain 	 * presence detect only if Attention Button is not present.
7984f854f2aSRajat Jain 	 */
7994f854f2aSRajat Jain 	cmd = PCI_EXP_SLTCTL_DLLSCE;
800ae416e6bSKenji Kaneshige 	if (ATTN_BUTTN(ctrl))
801322162a7SKenji Kaneshige 		cmd |= PCI_EXP_SLTCTL_ABPE;
8024f854f2aSRajat Jain 	else
8034f854f2aSRajat Jain 		cmd |= PCI_EXP_SLTCTL_PDCE;
804c27fb883SKenji Kaneshige 	if (!pciehp_poll_mode)
8056d4671b5SPali Rohár 		cmd |= PCI_EXP_SLTCTL_HPIE;
8066d4671b5SPali Rohár 	if (!pciehp_poll_mode && !NO_CMD_CMPL(ctrl))
8076d4671b5SPali Rohár 		cmd |= PCI_EXP_SLTCTL_CCIE;
808c27fb883SKenji Kaneshige 
809322162a7SKenji Kaneshige 	mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE |
8102db0f71fSBjorn Helgaas 		PCI_EXP_SLTCTL_PFDE |
8114f854f2aSRajat Jain 		PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE |
8124f854f2aSRajat Jain 		PCI_EXP_SLTCTL_DLLSCE);
813c27fb883SKenji Kaneshige 
814a5dd4b4bSAlex Williamson 	pcie_write_cmd_nowait(ctrl, cmd, mask);
815cf8d7b58SYinghai Lu 	ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
816cf8d7b58SYinghai Lu 		 pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, cmd);
8171da177e4SLinus Torvalds }
81808e7a7d2SMark Lord 
pcie_disable_notification(struct controller * ctrl)819c4635eb0SKenji Kaneshige static void pcie_disable_notification(struct controller *ctrl)
820c4635eb0SKenji Kaneshige {
821c4635eb0SKenji Kaneshige 	u16 mask;
8226dae6202SBjorn Helgaas 
823322162a7SKenji Kaneshige 	mask = (PCI_EXP_SLTCTL_PDCE | PCI_EXP_SLTCTL_ABPE |
824322162a7SKenji Kaneshige 		PCI_EXP_SLTCTL_MRLSCE | PCI_EXP_SLTCTL_PFDE |
825f22daf1fSKenji Kaneshige 		PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_CCIE |
826f22daf1fSKenji Kaneshige 		PCI_EXP_SLTCTL_DLLSCE);
8276dae6202SBjorn Helgaas 	pcie_write_cmd(ctrl, 0, mask);
828cf8d7b58SYinghai Lu 	ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
829cf8d7b58SYinghai Lu 		 pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, 0);
830c4635eb0SKenji Kaneshige }
831c4635eb0SKenji Kaneshige 
pcie_clear_hotplug_events(struct controller * ctrl)83279037824SLukas Wunner void pcie_clear_hotplug_events(struct controller *ctrl)
83379037824SLukas Wunner {
83479037824SLukas Wunner 	pcie_capability_write_word(ctrl_dev(ctrl), PCI_EXP_SLTSTA,
83579037824SLukas Wunner 				   PCI_EXP_SLTSTA_PDC | PCI_EXP_SLTSTA_DLLSC);
83679037824SLukas Wunner }
83779037824SLukas Wunner 
pcie_enable_interrupt(struct controller * ctrl)838eb34da60SMika Westerberg void pcie_enable_interrupt(struct controller *ctrl)
839eb34da60SMika Westerberg {
840bbe54ea5SMika Westerberg 	u16 mask;
841bbe54ea5SMika Westerberg 
842bbe54ea5SMika Westerberg 	mask = PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_DLLSCE;
843bbe54ea5SMika Westerberg 	pcie_write_cmd(ctrl, mask, mask);
844eb34da60SMika Westerberg }
845eb34da60SMika Westerberg 
pcie_disable_interrupt(struct controller * ctrl)846eb34da60SMika Westerberg void pcie_disable_interrupt(struct controller *ctrl)
847eb34da60SMika Westerberg {
848bbe54ea5SMika Westerberg 	u16 mask;
849bbe54ea5SMika Westerberg 
850bbe54ea5SMika Westerberg 	/*
851bbe54ea5SMika Westerberg 	 * Mask hot-plug interrupt to prevent it triggering immediately
852bbe54ea5SMika Westerberg 	 * when the link goes inactive (we still get PME when any of the
853bbe54ea5SMika Westerberg 	 * enabled events is detected). Same goes with Link Layer State
854bbe54ea5SMika Westerberg 	 * changed event which generates PME immediately when the link goes
855bbe54ea5SMika Westerberg 	 * inactive so mask it as well.
856bbe54ea5SMika Westerberg 	 */
857bbe54ea5SMika Westerberg 	mask = PCI_EXP_SLTCTL_HPIE | PCI_EXP_SLTCTL_DLLSCE;
858bbe54ea5SMika Westerberg 	pcie_write_cmd(ctrl, 0, mask);
859eb34da60SMika Westerberg }
860eb34da60SMika Westerberg 
861ea401499SLukas Wunner /**
862ea401499SLukas Wunner  * pciehp_slot_reset() - ignore link event caused by error-induced hot reset
863ea401499SLukas Wunner  * @dev: PCI Express port service device
864ea401499SLukas Wunner  *
865ea401499SLukas Wunner  * Called from pcie_portdrv_slot_reset() after AER or DPC initiated a reset
866ea401499SLukas Wunner  * further up in the hierarchy to recover from an error.  The reset was
867ea401499SLukas Wunner  * propagated down to this hotplug port.  Ignore the resulting link flap.
868ea401499SLukas Wunner  * If the link failed to retrain successfully, synthesize the ignored event.
869ea401499SLukas Wunner  * Surprise removal during reset is detected through Presence Detect Changed.
870ea401499SLukas Wunner  */
pciehp_slot_reset(struct pcie_device * dev)871ea401499SLukas Wunner int pciehp_slot_reset(struct pcie_device *dev)
872ea401499SLukas Wunner {
873ea401499SLukas Wunner 	struct controller *ctrl = get_service_data(dev);
874ea401499SLukas Wunner 
875ea401499SLukas Wunner 	if (ctrl->state != ON_STATE)
876ea401499SLukas Wunner 		return 0;
877ea401499SLukas Wunner 
878ea401499SLukas Wunner 	pcie_capability_write_word(dev->port, PCI_EXP_SLTSTA,
879ea401499SLukas Wunner 				   PCI_EXP_SLTSTA_DLLSC);
880ea401499SLukas Wunner 
881ea401499SLukas Wunner 	if (!pciehp_check_link_active(ctrl))
882ea401499SLukas Wunner 		pciehp_request(ctrl, PCI_EXP_SLTSTA_DLLSC);
883ea401499SLukas Wunner 
884ea401499SLukas Wunner 	return 0;
885ea401499SLukas Wunner }
886ea401499SLukas Wunner 
8872e35afaeSAlex Williamson /*
8882e35afaeSAlex Williamson  * pciehp has a 1:1 bus:slot relationship so we ultimately want a secondary
8892b3940b6SRajat Jain  * bus reset of the bridge, but at the same time we want to ensure that it is
8902b3940b6SRajat Jain  * not seen as a hot-unplug, followed by the hot-plug of the device. Thus,
8912b3940b6SRajat Jain  * disable link state notification and presence detection change notification
8922b3940b6SRajat Jain  * momentarily, if we see that they could interfere. Also, clear any spurious
8932e35afaeSAlex Williamson  * events after.
8942e35afaeSAlex Williamson  */
pciehp_reset_slot(struct hotplug_slot * hotplug_slot,bool probe)8959bdc81ceSAmey Narkhede int pciehp_reset_slot(struct hotplug_slot *hotplug_slot, bool probe)
8962e35afaeSAlex Williamson {
897125450f8SLukas Wunner 	struct controller *ctrl = to_ctrl(hotplug_slot);
898cd84d340SBjorn Helgaas 	struct pci_dev *pdev = ctrl_dev(ctrl);
89906a8d89aSRajat Jain 	u16 stat_mask = 0, ctrl_mask = 0;
90018426238SSinan Kaya 	int rc;
9012e35afaeSAlex Williamson 
9022e35afaeSAlex Williamson 	if (probe)
9032e35afaeSAlex Williamson 		return 0;
9042e35afaeSAlex Williamson 
905085a9f43SHans de Goede 	down_write_nested(&ctrl->reset_lock, ctrl->depth);
9065b3f7b7dSLukas Wunner 
9072b3940b6SRajat Jain 	if (!ATTN_BUTTN(ctrl)) {
90806a8d89aSRajat Jain 		ctrl_mask |= PCI_EXP_SLTCTL_PDCE;
90906a8d89aSRajat Jain 		stat_mask |= PCI_EXP_SLTSTA_PDC;
91006a8d89aSRajat Jain 	}
91106a8d89aSRajat Jain 	ctrl_mask |= PCI_EXP_SLTCTL_DLLSCE;
91206a8d89aSRajat Jain 	stat_mask |= PCI_EXP_SLTSTA_DLLSC;
91306a8d89aSRajat Jain 
91406a8d89aSRajat Jain 	pcie_write_cmd(ctrl, 0, ctrl_mask);
915cf8d7b58SYinghai Lu 	ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
916cf8d7b58SYinghai Lu 		 pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, 0);
9172e35afaeSAlex Williamson 
918381634caSSinan Kaya 	rc = pci_bridge_secondary_bus_reset(ctrl->pcie->port);
9192e35afaeSAlex Williamson 
92006a8d89aSRajat Jain 	pcie_capability_write_word(pdev, PCI_EXP_SLTSTA, stat_mask);
921a5dd4b4bSAlex Williamson 	pcie_write_cmd_nowait(ctrl, ctrl_mask, ctrl_mask);
922cf8d7b58SYinghai Lu 	ctrl_dbg(ctrl, "%s: SLOTCTRL %x write cmd %x\n", __func__,
923cf8d7b58SYinghai Lu 		 pci_pcie_cap(ctrl->pcie->port) + PCI_EXP_SLTCTL, ctrl_mask);
9245b3f7b7dSLukas Wunner 
9255b3f7b7dSLukas Wunner 	up_write(&ctrl->reset_lock);
92618426238SSinan Kaya 	return rc;
9272e35afaeSAlex Williamson }
9282e35afaeSAlex Williamson 
pcie_init_notification(struct controller * ctrl)929dbc7e1e5SEric W. Biederman int pcie_init_notification(struct controller *ctrl)
930c4635eb0SKenji Kaneshige {
931c4635eb0SKenji Kaneshige 	if (pciehp_request_irq(ctrl))
932c4635eb0SKenji Kaneshige 		return -1;
9336dae6202SBjorn Helgaas 	pcie_enable_notification(ctrl);
934dbc7e1e5SEric W. Biederman 	ctrl->notification_enabled = 1;
935c4635eb0SKenji Kaneshige 	return 0;
936c4635eb0SKenji Kaneshige }
937c4635eb0SKenji Kaneshige 
pcie_shutdown_notification(struct controller * ctrl)938281e878eSLukas Wunner void pcie_shutdown_notification(struct controller *ctrl)
939c4635eb0SKenji Kaneshige {
940dbc7e1e5SEric W. Biederman 	if (ctrl->notification_enabled) {
941c4635eb0SKenji Kaneshige 		pcie_disable_notification(ctrl);
942c4635eb0SKenji Kaneshige 		pciehp_free_irq(ctrl);
943dbc7e1e5SEric W. Biederman 		ctrl->notification_enabled = 0;
944dbc7e1e5SEric W. Biederman 	}
945c4635eb0SKenji Kaneshige }
946c4635eb0SKenji Kaneshige 
dbg_ctrl(struct controller * ctrl)9472aeeef11SKenji Kaneshige static inline void dbg_ctrl(struct controller *ctrl)
9482aeeef11SKenji Kaneshige {
949385e2491SKenji Kaneshige 	struct pci_dev *pdev = ctrl->pcie->port;
9503784e0c6SBjorn Helgaas 	u16 reg16;
9512aeeef11SKenji Kaneshige 
9527e696b8aSBjorn Helgaas 	ctrl_dbg(ctrl, "Slot Capabilities      : 0x%08x\n", ctrl->slot_cap);
953cd84d340SBjorn Helgaas 	pcie_capability_read_word(pdev, PCI_EXP_SLTSTA, &reg16);
9547e696b8aSBjorn Helgaas 	ctrl_dbg(ctrl, "Slot Status            : 0x%04x\n", reg16);
955cd84d340SBjorn Helgaas 	pcie_capability_read_word(pdev, PCI_EXP_SLTCTL, &reg16);
9567e696b8aSBjorn Helgaas 	ctrl_dbg(ctrl, "Slot Control           : 0x%04x\n", reg16);
9572aeeef11SKenji Kaneshige }
9582aeeef11SKenji Kaneshige 
959afe2478fSBjorn Helgaas #define FLAG(x, y)	(((x) & (y)) ? '+' : '-')
960afe2478fSBjorn Helgaas 
pcie_hotplug_depth(struct pci_dev * dev)961085a9f43SHans de Goede static inline int pcie_hotplug_depth(struct pci_dev *dev)
962085a9f43SHans de Goede {
963085a9f43SHans de Goede 	struct pci_bus *bus = dev->bus;
964085a9f43SHans de Goede 	int depth = 0;
965085a9f43SHans de Goede 
966085a9f43SHans de Goede 	while (bus->parent) {
967085a9f43SHans de Goede 		bus = bus->parent;
968085a9f43SHans de Goede 		if (bus->self && bus->self->is_hotplug_bridge)
969085a9f43SHans de Goede 			depth++;
970085a9f43SHans de Goede 	}
971085a9f43SHans de Goede 
972085a9f43SHans de Goede 	return depth;
973085a9f43SHans de Goede }
974085a9f43SHans de Goede 
pcie_init(struct pcie_device * dev)975c4635eb0SKenji Kaneshige struct controller *pcie_init(struct pcie_device *dev)
97608e7a7d2SMark Lord {
977c4635eb0SKenji Kaneshige 	struct controller *ctrl;
9781f087398SMaciej W. Rozycki 	u32 slot_cap, slot_cap2;
97980696f99SLukas Wunner 	u8 poweron;
9802aeeef11SKenji Kaneshige 	struct pci_dev *pdev = dev->port;
9815790a9c7SLukas Wunner 	struct pci_bus *subordinate = pdev->subordinate;
98208e7a7d2SMark Lord 
983c4635eb0SKenji Kaneshige 	ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
984c7abb235SMarkus Elfring 	if (!ctrl)
9855790a9c7SLukas Wunner 		return NULL;
986c7abb235SMarkus Elfring 
987f7a10e32SKenji Kaneshige 	ctrl->pcie = dev;
988085a9f43SHans de Goede 	ctrl->depth = pcie_hotplug_depth(dev->port);
9891a84b99cSBjorn Helgaas 	pcie_capability_read_dword(pdev, PCI_EXP_SLTCAP, &slot_cap);
990576243b3SKeith Busch 
991576243b3SKeith Busch 	if (pdev->hotplug_user_indicators)
992576243b3SKeith Busch 		slot_cap &= ~(PCI_EXP_SLTCAP_AIP | PCI_EXP_SLTCAP_PIP);
993576243b3SKeith Busch 
994493fb50eSLukas Wunner 	/*
995493fb50eSLukas Wunner 	 * We assume no Thunderbolt controllers support Command Complete events,
996493fb50eSLukas Wunner 	 * but some controllers falsely claim they do.
997493fb50eSLukas Wunner 	 */
998493fb50eSLukas Wunner 	if (pdev->is_thunderbolt)
999493fb50eSLukas Wunner 		slot_cap |= PCI_EXP_SLTCAP_NCCS;
1000493fb50eSLukas Wunner 
10012aeeef11SKenji Kaneshige 	ctrl->slot_cap = slot_cap;
10022aeeef11SKenji Kaneshige 	mutex_init(&ctrl->ctrl_lock);
10034ff3126eSLukas Wunner 	mutex_init(&ctrl->state_lock);
10045b3f7b7dSLukas Wunner 	init_rwsem(&ctrl->reset_lock);
100532a8cef2SLukas Wunner 	init_waitqueue_head(&ctrl->requester);
10062aeeef11SKenji Kaneshige 	init_waitqueue_head(&ctrl->queue);
10074ff3126eSLukas Wunner 	INIT_DELAYED_WORK(&ctrl->button_work, pciehp_queue_pushbutton_work);
10082aeeef11SKenji Kaneshige 	dbg_ctrl(ctrl);
10092cc56f30SBjorn Helgaas 
10105790a9c7SLukas Wunner 	down_read(&pci_bus_sem);
10115790a9c7SLukas Wunner 	ctrl->state = list_empty(&subordinate->devices) ? OFF_STATE : ON_STATE;
10125790a9c7SLukas Wunner 	up_read(&pci_bus_sem);
10135790a9c7SLukas Wunner 
101420285359SAlexandru Gagniuc 	pcie_capability_read_dword(pdev, PCI_EXP_SLTCAP2, &slot_cap2);
101520285359SAlexandru Gagniuc 	if (slot_cap2 & PCI_EXP_SLTCAP2_IBPD) {
101620285359SAlexandru Gagniuc 		pcie_write_cmd_nowait(ctrl, PCI_EXP_SLTCTL_IBPD_DISABLE,
101720285359SAlexandru Gagniuc 				      PCI_EXP_SLTCTL_IBPD_DISABLE);
101820285359SAlexandru Gagniuc 		ctrl->inband_presence_disabled = 1;
101920285359SAlexandru Gagniuc 	}
102020285359SAlexandru Gagniuc 
10210b382546SStuart Hayes 	if (dmi_first_match(inband_presence_disabled_dmi_table))
10220b382546SStuart Hayes 		ctrl->inband_presence_disabled = 1;
10230b382546SStuart Hayes 
1024cdf6b736SLukas Wunner 	/* Clear all remaining event bits in Slot Status register. */
1025df72648cSBjorn Helgaas 	pcie_capability_write_word(pdev, PCI_EXP_SLTSTA,
1026df72648cSBjorn Helgaas 		PCI_EXP_SLTSTA_ABP | PCI_EXP_SLTSTA_PFD |
1027db63d400SMika Westerberg 		PCI_EXP_SLTSTA_MRLSC | PCI_EXP_SLTSTA_CC |
1028cdf6b736SLukas Wunner 		PCI_EXP_SLTSTA_DLLSC | PCI_EXP_SLTSTA_PDC);
102908e7a7d2SMark Lord 
103020285359SAlexandru Gagniuc 	ctrl_info(ctrl, "Slot #%d AttnBtn%c PwrCtrl%c MRL%c AttnInd%c PwrInd%c HotPlug%c Surprise%c Interlock%c NoCompl%c IbPresDis%c LLActRep%c%s\n",
1031afe2478fSBjorn Helgaas 		(slot_cap & PCI_EXP_SLTCAP_PSN) >> 19,
1032afe2478fSBjorn Helgaas 		FLAG(slot_cap, PCI_EXP_SLTCAP_ABP),
1033afe2478fSBjorn Helgaas 		FLAG(slot_cap, PCI_EXP_SLTCAP_PCP),
1034afe2478fSBjorn Helgaas 		FLAG(slot_cap, PCI_EXP_SLTCAP_MRLSP),
10353784e0c6SBjorn Helgaas 		FLAG(slot_cap, PCI_EXP_SLTCAP_AIP),
10363784e0c6SBjorn Helgaas 		FLAG(slot_cap, PCI_EXP_SLTCAP_PIP),
10373784e0c6SBjorn Helgaas 		FLAG(slot_cap, PCI_EXP_SLTCAP_HPC),
10383784e0c6SBjorn Helgaas 		FLAG(slot_cap, PCI_EXP_SLTCAP_HPS),
1039afe2478fSBjorn Helgaas 		FLAG(slot_cap, PCI_EXP_SLTCAP_EIP),
1040afe2478fSBjorn Helgaas 		FLAG(slot_cap, PCI_EXP_SLTCAP_NCCS),
104120285359SAlexandru Gagniuc 		FLAG(slot_cap2, PCI_EXP_SLTCAP2_IBPD),
10421f087398SMaciej W. Rozycki 		FLAG(pdev->link_active_reporting, true),
1043d22b3621SBjorn Helgaas 		pdev->broken_cmd_compl ? " (with Cmd Compl erratum)" : "");
10442aeeef11SKenji Kaneshige 
10454e6a1335SLukas Wunner 	/*
10464e6a1335SLukas Wunner 	 * If empty slot's power status is on, turn power off.  The IRQ isn't
10474e6a1335SLukas Wunner 	 * requested yet, so avoid triggering a notification with this command.
10484e6a1335SLukas Wunner 	 */
10494e6a1335SLukas Wunner 	if (POWER_CTRL(ctrl)) {
10505790a9c7SLukas Wunner 		pciehp_get_power_status(ctrl, &poweron);
105180696f99SLukas Wunner 		if (!pciehp_card_present_or_link_active(ctrl) && poweron) {
10524e6a1335SLukas Wunner 			pcie_disable_notification(ctrl);
10535790a9c7SLukas Wunner 			pciehp_power_off_slot(ctrl);
10544e6a1335SLukas Wunner 		}
10554e6a1335SLukas Wunner 	}
10564e6a1335SLukas Wunner 
1057c4635eb0SKenji Kaneshige 	return ctrl;
1058c4635eb0SKenji Kaneshige }
1059c4635eb0SKenji Kaneshige 
pciehp_release_ctrl(struct controller * ctrl)106082a9e79eSKenji Kaneshige void pciehp_release_ctrl(struct controller *ctrl)
1061c4635eb0SKenji Kaneshige {
10624ff3126eSLukas Wunner 	cancel_delayed_work_sync(&ctrl->button_work);
1063c4635eb0SKenji Kaneshige 	kfree(ctrl);
106408e7a7d2SMark Lord }
1065d22b3621SBjorn Helgaas 
quirk_cmd_compl(struct pci_dev * pdev)1066d22b3621SBjorn Helgaas static void quirk_cmd_compl(struct pci_dev *pdev)
1067d22b3621SBjorn Helgaas {
1068d22b3621SBjorn Helgaas 	u32 slot_cap;
1069d22b3621SBjorn Helgaas 
1070d22b3621SBjorn Helgaas 	if (pci_is_pcie(pdev)) {
1071d22b3621SBjorn Helgaas 		pcie_capability_read_dword(pdev, PCI_EXP_SLTCAP, &slot_cap);
1072d22b3621SBjorn Helgaas 		if (slot_cap & PCI_EXP_SLTCAP_HPC &&
1073d22b3621SBjorn Helgaas 		    !(slot_cap & PCI_EXP_SLTCAP_NCCS))
1074d22b3621SBjorn Helgaas 			pdev->broken_cmd_compl = 1;
1075d22b3621SBjorn Helgaas 	}
1076d22b3621SBjorn Helgaas }
1077d22b3621SBjorn Helgaas DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_INTEL, PCI_ANY_ID,
1078d22b3621SBjorn Helgaas 			      PCI_CLASS_BRIDGE_PCI, 8, quirk_cmd_compl);
107982b34b08SManivannan Sadhasivam DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_QCOM, 0x010e,
108082b34b08SManivannan Sadhasivam 			      PCI_CLASS_BRIDGE_PCI, 8, quirk_cmd_compl);
10819f72d475SManivannan Sadhasivam DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_QCOM, 0x0110,
10829f72d475SManivannan Sadhasivam 			      PCI_CLASS_BRIDGE_PCI, 8, quirk_cmd_compl);
1083d22b3621SBjorn Helgaas DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_QCOM, 0x0400,
1084d22b3621SBjorn Helgaas 			      PCI_CLASS_BRIDGE_PCI, 8, quirk_cmd_compl);
1085d22b3621SBjorn Helgaas DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_QCOM, 0x0401,
1086d22b3621SBjorn Helgaas 			      PCI_CLASS_BRIDGE_PCI, 8, quirk_cmd_compl);
108722e4d639SShunyong Yang DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_HXT, 0x0401,
108822e4d639SShunyong Yang 			      PCI_CLASS_BRIDGE_PCI, 8, quirk_cmd_compl);
1089