xref: /openbmc/linux/arch/s390/pci/pci_event.c (revision e50e86dbcabda570fc8a1435fe2fca97e9ab7312)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2cbc0dd1fSJan Glauber /*
3cbc0dd1fSJan Glauber  *  Copyright IBM Corp. 2012
4cbc0dd1fSJan Glauber  *
5cbc0dd1fSJan Glauber  *  Author(s):
6cbc0dd1fSJan Glauber  *    Jan Glauber <jang@linux.vnet.ibm.com>
7cbc0dd1fSJan Glauber  */
8cbc0dd1fSJan Glauber 
9896cb7e6SGerald Schaefer #define KMSG_COMPONENT "zpci"
10896cb7e6SGerald Schaefer #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
11cbc0dd1fSJan Glauber 
12cbc0dd1fSJan Glauber #include <linux/kernel.h>
13cbc0dd1fSJan Glauber #include <linux/pci.h>
141f1dcbd4SSebastian Ott #include <asm/pci_debug.h>
15652d40b2SNiklas Schnelle #include <asm/pci_dma.h>
16d795ddadSSebastian Ott #include <asm/sclp.h>
17cbc0dd1fSJan Glauber 
1805bc1be6SPierre Morel #include "pci_bus.h"
1905bc1be6SPierre Morel 
20cbc0dd1fSJan Glauber /* Content Code Description for PCI Function Error */
21cbc0dd1fSJan Glauber struct zpci_ccdf_err {
22cbc0dd1fSJan Glauber 	u32 reserved1;
23cbc0dd1fSJan Glauber 	u32 fh;				/* function handle */
24cbc0dd1fSJan Glauber 	u32 fid;			/* function id */
25cbc0dd1fSJan Glauber 	u32 ett		:  4;		/* expected table type */
26cbc0dd1fSJan Glauber 	u32 mvn		: 12;		/* MSI vector number */
27cbc0dd1fSJan Glauber 	u32 dmaas	:  8;		/* DMA address space */
28cbc0dd1fSJan Glauber 	u32		:  6;
29cbc0dd1fSJan Glauber 	u32 q		:  1;		/* event qualifier */
30cbc0dd1fSJan Glauber 	u32 rw		:  1;		/* read/write */
31cbc0dd1fSJan Glauber 	u64 faddr;			/* failing address */
32cbc0dd1fSJan Glauber 	u32 reserved3;
33cbc0dd1fSJan Glauber 	u16 reserved4;
34cbc0dd1fSJan Glauber 	u16 pec;			/* PCI event code */
35cbc0dd1fSJan Glauber } __packed;
36cbc0dd1fSJan Glauber 
37cbc0dd1fSJan Glauber /* Content Code Description for PCI Function Availability */
38cbc0dd1fSJan Glauber struct zpci_ccdf_avail {
39cbc0dd1fSJan Glauber 	u32 reserved1;
40cbc0dd1fSJan Glauber 	u32 fh;				/* function handle */
41cbc0dd1fSJan Glauber 	u32 fid;			/* function id */
42cbc0dd1fSJan Glauber 	u32 reserved2;
43cbc0dd1fSJan Glauber 	u32 reserved3;
44cbc0dd1fSJan Glauber 	u32 reserved4;
45cbc0dd1fSJan Glauber 	u32 reserved5;
46cbc0dd1fSJan Glauber 	u16 reserved6;
47cbc0dd1fSJan Glauber 	u16 pec;			/* PCI event code */
48cbc0dd1fSJan Glauber } __packed;
49cbc0dd1fSJan Glauber 
ers_result_indicates_abort(pci_ers_result_t ers_res)504cdf2f4eSNiklas Schnelle static inline bool ers_result_indicates_abort(pci_ers_result_t ers_res)
514cdf2f4eSNiklas Schnelle {
524cdf2f4eSNiklas Schnelle 	switch (ers_res) {
534cdf2f4eSNiklas Schnelle 	case PCI_ERS_RESULT_CAN_RECOVER:
544cdf2f4eSNiklas Schnelle 	case PCI_ERS_RESULT_RECOVERED:
554cdf2f4eSNiklas Schnelle 	case PCI_ERS_RESULT_NEED_RESET:
564cdf2f4eSNiklas Schnelle 		return false;
574cdf2f4eSNiklas Schnelle 	default:
584cdf2f4eSNiklas Schnelle 		return true;
594cdf2f4eSNiklas Schnelle 	}
604cdf2f4eSNiklas Schnelle }
614cdf2f4eSNiklas Schnelle 
is_passed_through(struct zpci_dev * zdev)624cdf2f4eSNiklas Schnelle static bool is_passed_through(struct zpci_dev *zdev)
634cdf2f4eSNiklas Schnelle {
644cdf2f4eSNiklas Schnelle 	return zdev->s390_domain;
654cdf2f4eSNiklas Schnelle }
664cdf2f4eSNiklas Schnelle 
is_driver_supported(struct pci_driver * driver)674cdf2f4eSNiklas Schnelle static bool is_driver_supported(struct pci_driver *driver)
684cdf2f4eSNiklas Schnelle {
694cdf2f4eSNiklas Schnelle 	if (!driver || !driver->err_handler)
704cdf2f4eSNiklas Schnelle 		return false;
714cdf2f4eSNiklas Schnelle 	if (!driver->err_handler->error_detected)
724cdf2f4eSNiklas Schnelle 		return false;
734cdf2f4eSNiklas Schnelle 	if (!driver->err_handler->slot_reset)
744cdf2f4eSNiklas Schnelle 		return false;
754cdf2f4eSNiklas Schnelle 	if (!driver->err_handler->resume)
764cdf2f4eSNiklas Schnelle 		return false;
774cdf2f4eSNiklas Schnelle 	return true;
784cdf2f4eSNiklas Schnelle }
794cdf2f4eSNiklas Schnelle 
zpci_event_notify_error_detected(struct pci_dev * pdev,struct pci_driver * driver)804cdf2f4eSNiklas Schnelle static pci_ers_result_t zpci_event_notify_error_detected(struct pci_dev *pdev,
814cdf2f4eSNiklas Schnelle 							 struct pci_driver *driver)
824cdf2f4eSNiklas Schnelle {
834cdf2f4eSNiklas Schnelle 	pci_ers_result_t ers_res = PCI_ERS_RESULT_DISCONNECT;
844cdf2f4eSNiklas Schnelle 
854cdf2f4eSNiklas Schnelle 	ers_res = driver->err_handler->error_detected(pdev,  pdev->error_state);
864cdf2f4eSNiklas Schnelle 	if (ers_result_indicates_abort(ers_res))
874cdf2f4eSNiklas Schnelle 		pr_info("%s: Automatic recovery failed after initial reporting\n", pci_name(pdev));
884cdf2f4eSNiklas Schnelle 	else if (ers_res == PCI_ERS_RESULT_NEED_RESET)
894cdf2f4eSNiklas Schnelle 		pr_debug("%s: Driver needs reset to recover\n", pci_name(pdev));
904cdf2f4eSNiklas Schnelle 
914cdf2f4eSNiklas Schnelle 	return ers_res;
924cdf2f4eSNiklas Schnelle }
934cdf2f4eSNiklas Schnelle 
zpci_event_do_error_state_clear(struct pci_dev * pdev,struct pci_driver * driver)944cdf2f4eSNiklas Schnelle static pci_ers_result_t zpci_event_do_error_state_clear(struct pci_dev *pdev,
954cdf2f4eSNiklas Schnelle 							struct pci_driver *driver)
964cdf2f4eSNiklas Schnelle {
974cdf2f4eSNiklas Schnelle 	pci_ers_result_t ers_res = PCI_ERS_RESULT_DISCONNECT;
984cdf2f4eSNiklas Schnelle 	struct zpci_dev *zdev = to_zpci(pdev);
994cdf2f4eSNiklas Schnelle 	int rc;
1004cdf2f4eSNiklas Schnelle 
1014cdf2f4eSNiklas Schnelle 	pr_info("%s: Unblocking device access for examination\n", pci_name(pdev));
1024cdf2f4eSNiklas Schnelle 	rc = zpci_reset_load_store_blocked(zdev);
1034cdf2f4eSNiklas Schnelle 	if (rc) {
1044cdf2f4eSNiklas Schnelle 		pr_err("%s: Unblocking device access failed\n", pci_name(pdev));
1054cdf2f4eSNiklas Schnelle 		/* Let's try a full reset instead */
1064cdf2f4eSNiklas Schnelle 		return PCI_ERS_RESULT_NEED_RESET;
1074cdf2f4eSNiklas Schnelle 	}
1084cdf2f4eSNiklas Schnelle 
1094cdf2f4eSNiklas Schnelle 	if (driver->err_handler->mmio_enabled) {
1104cdf2f4eSNiklas Schnelle 		ers_res = driver->err_handler->mmio_enabled(pdev);
1114cdf2f4eSNiklas Schnelle 		if (ers_result_indicates_abort(ers_res)) {
1124cdf2f4eSNiklas Schnelle 			pr_info("%s: Automatic recovery failed after MMIO re-enable\n",
1134cdf2f4eSNiklas Schnelle 				pci_name(pdev));
1144cdf2f4eSNiklas Schnelle 			return ers_res;
1154cdf2f4eSNiklas Schnelle 		} else if (ers_res == PCI_ERS_RESULT_NEED_RESET) {
1164cdf2f4eSNiklas Schnelle 			pr_debug("%s: Driver needs reset to recover\n", pci_name(pdev));
1174cdf2f4eSNiklas Schnelle 			return ers_res;
1184cdf2f4eSNiklas Schnelle 		}
1194cdf2f4eSNiklas Schnelle 	}
1204cdf2f4eSNiklas Schnelle 
1214cdf2f4eSNiklas Schnelle 	pr_debug("%s: Unblocking DMA\n", pci_name(pdev));
1224cdf2f4eSNiklas Schnelle 	rc = zpci_clear_error_state(zdev);
1234cdf2f4eSNiklas Schnelle 	if (!rc) {
1244cdf2f4eSNiklas Schnelle 		pdev->error_state = pci_channel_io_normal;
1254cdf2f4eSNiklas Schnelle 	} else {
1264cdf2f4eSNiklas Schnelle 		pr_err("%s: Unblocking DMA failed\n", pci_name(pdev));
1274cdf2f4eSNiklas Schnelle 		/* Let's try a full reset instead */
1284cdf2f4eSNiklas Schnelle 		return PCI_ERS_RESULT_NEED_RESET;
1294cdf2f4eSNiklas Schnelle 	}
1304cdf2f4eSNiklas Schnelle 
1314cdf2f4eSNiklas Schnelle 	return ers_res;
1324cdf2f4eSNiklas Schnelle }
1334cdf2f4eSNiklas Schnelle 
zpci_event_do_reset(struct pci_dev * pdev,struct pci_driver * driver)1344cdf2f4eSNiklas Schnelle static pci_ers_result_t zpci_event_do_reset(struct pci_dev *pdev,
1354cdf2f4eSNiklas Schnelle 					    struct pci_driver *driver)
1364cdf2f4eSNiklas Schnelle {
1374cdf2f4eSNiklas Schnelle 	pci_ers_result_t ers_res = PCI_ERS_RESULT_DISCONNECT;
1384cdf2f4eSNiklas Schnelle 
1394cdf2f4eSNiklas Schnelle 	pr_info("%s: Initiating reset\n", pci_name(pdev));
1404cdf2f4eSNiklas Schnelle 	if (zpci_hot_reset_device(to_zpci(pdev))) {
1414cdf2f4eSNiklas Schnelle 		pr_err("%s: The reset request failed\n", pci_name(pdev));
1424cdf2f4eSNiklas Schnelle 		return ers_res;
1434cdf2f4eSNiklas Schnelle 	}
1444cdf2f4eSNiklas Schnelle 	pdev->error_state = pci_channel_io_normal;
1454cdf2f4eSNiklas Schnelle 	ers_res = driver->err_handler->slot_reset(pdev);
1464cdf2f4eSNiklas Schnelle 	if (ers_result_indicates_abort(ers_res)) {
1474cdf2f4eSNiklas Schnelle 		pr_info("%s: Automatic recovery failed after slot reset\n", pci_name(pdev));
1484cdf2f4eSNiklas Schnelle 		return ers_res;
1494cdf2f4eSNiklas Schnelle 	}
1504cdf2f4eSNiklas Schnelle 
1514cdf2f4eSNiklas Schnelle 	return ers_res;
1524cdf2f4eSNiklas Schnelle }
1534cdf2f4eSNiklas Schnelle 
1544cdf2f4eSNiklas Schnelle /* zpci_event_attempt_error_recovery - Try to recover the given PCI function
1554cdf2f4eSNiklas Schnelle  * @pdev: PCI function to recover currently in the error state
1564cdf2f4eSNiklas Schnelle  *
1574cdf2f4eSNiklas Schnelle  * We follow the scheme outlined in Documentation/PCI/pci-error-recovery.rst.
1584cdf2f4eSNiklas Schnelle  * With the simplification that recovery always happens per function
1594cdf2f4eSNiklas Schnelle  * and the platform determines which functions are affected for
1604cdf2f4eSNiklas Schnelle  * multi-function devices.
1614cdf2f4eSNiklas Schnelle  */
zpci_event_attempt_error_recovery(struct pci_dev * pdev)1624cdf2f4eSNiklas Schnelle static pci_ers_result_t zpci_event_attempt_error_recovery(struct pci_dev *pdev)
1634cdf2f4eSNiklas Schnelle {
1644cdf2f4eSNiklas Schnelle 	pci_ers_result_t ers_res = PCI_ERS_RESULT_DISCONNECT;
1654cdf2f4eSNiklas Schnelle 	struct pci_driver *driver;
1664cdf2f4eSNiklas Schnelle 
1674cdf2f4eSNiklas Schnelle 	/*
1684cdf2f4eSNiklas Schnelle 	 * Ensure that the PCI function is not removed concurrently, no driver
1694cdf2f4eSNiklas Schnelle 	 * is unbound or probed and that userspace can't access its
1704cdf2f4eSNiklas Schnelle 	 * configuration space while we perform recovery.
1714cdf2f4eSNiklas Schnelle 	 */
1724cdf2f4eSNiklas Schnelle 	pci_dev_lock(pdev);
1734cdf2f4eSNiklas Schnelle 	if (pdev->error_state == pci_channel_io_perm_failure) {
1744cdf2f4eSNiklas Schnelle 		ers_res = PCI_ERS_RESULT_DISCONNECT;
1754cdf2f4eSNiklas Schnelle 		goto out_unlock;
1764cdf2f4eSNiklas Schnelle 	}
1774cdf2f4eSNiklas Schnelle 	pdev->error_state = pci_channel_io_frozen;
1784cdf2f4eSNiklas Schnelle 
1794cdf2f4eSNiklas Schnelle 	if (is_passed_through(to_zpci(pdev))) {
1804cdf2f4eSNiklas Schnelle 		pr_info("%s: Cannot be recovered in the host because it is a pass-through device\n",
1814cdf2f4eSNiklas Schnelle 			pci_name(pdev));
1824cdf2f4eSNiklas Schnelle 		goto out_unlock;
1834cdf2f4eSNiklas Schnelle 	}
1844cdf2f4eSNiklas Schnelle 
1854cdf2f4eSNiklas Schnelle 	driver = to_pci_driver(pdev->dev.driver);
1864cdf2f4eSNiklas Schnelle 	if (!is_driver_supported(driver)) {
1874cdf2f4eSNiklas Schnelle 		if (!driver)
1884cdf2f4eSNiklas Schnelle 			pr_info("%s: Cannot be recovered because no driver is bound to the device\n",
1894cdf2f4eSNiklas Schnelle 				pci_name(pdev));
1904cdf2f4eSNiklas Schnelle 		else
1914cdf2f4eSNiklas Schnelle 			pr_info("%s: The %s driver bound to the device does not support error recovery\n",
1924cdf2f4eSNiklas Schnelle 				pci_name(pdev),
1934cdf2f4eSNiklas Schnelle 				driver->name);
1944cdf2f4eSNiklas Schnelle 		goto out_unlock;
1954cdf2f4eSNiklas Schnelle 	}
1964cdf2f4eSNiklas Schnelle 
1974cdf2f4eSNiklas Schnelle 	ers_res = zpci_event_notify_error_detected(pdev, driver);
1984cdf2f4eSNiklas Schnelle 	if (ers_result_indicates_abort(ers_res))
1994cdf2f4eSNiklas Schnelle 		goto out_unlock;
2004cdf2f4eSNiklas Schnelle 
2014cdf2f4eSNiklas Schnelle 	if (ers_res == PCI_ERS_RESULT_CAN_RECOVER) {
2024cdf2f4eSNiklas Schnelle 		ers_res = zpci_event_do_error_state_clear(pdev, driver);
2034cdf2f4eSNiklas Schnelle 		if (ers_result_indicates_abort(ers_res))
2044cdf2f4eSNiklas Schnelle 			goto out_unlock;
2054cdf2f4eSNiklas Schnelle 	}
2064cdf2f4eSNiklas Schnelle 
2074cdf2f4eSNiklas Schnelle 	if (ers_res == PCI_ERS_RESULT_NEED_RESET)
2084cdf2f4eSNiklas Schnelle 		ers_res = zpci_event_do_reset(pdev, driver);
2094cdf2f4eSNiklas Schnelle 
2104cdf2f4eSNiklas Schnelle 	if (ers_res != PCI_ERS_RESULT_RECOVERED) {
2114cdf2f4eSNiklas Schnelle 		pr_err("%s: Automatic recovery failed; operator intervention is required\n",
2124cdf2f4eSNiklas Schnelle 		       pci_name(pdev));
2134cdf2f4eSNiklas Schnelle 		goto out_unlock;
2144cdf2f4eSNiklas Schnelle 	}
2154cdf2f4eSNiklas Schnelle 
2164cdf2f4eSNiklas Schnelle 	pr_info("%s: The device is ready to resume operations\n", pci_name(pdev));
2174cdf2f4eSNiklas Schnelle 	if (driver->err_handler->resume)
2184cdf2f4eSNiklas Schnelle 		driver->err_handler->resume(pdev);
2194cdf2f4eSNiklas Schnelle out_unlock:
2204cdf2f4eSNiklas Schnelle 	pci_dev_unlock(pdev);
2214cdf2f4eSNiklas Schnelle 
2224cdf2f4eSNiklas Schnelle 	return ers_res;
2234cdf2f4eSNiklas Schnelle }
2244cdf2f4eSNiklas Schnelle 
2254cdf2f4eSNiklas Schnelle /* zpci_event_io_failure - Report PCI channel failure state to driver
2264cdf2f4eSNiklas Schnelle  * @pdev: PCI function for which to report
2274cdf2f4eSNiklas Schnelle  * @es: PCI channel failure state to report
2284cdf2f4eSNiklas Schnelle  */
zpci_event_io_failure(struct pci_dev * pdev,pci_channel_state_t es)2294cdf2f4eSNiklas Schnelle static void zpci_event_io_failure(struct pci_dev *pdev, pci_channel_state_t es)
2304cdf2f4eSNiklas Schnelle {
2314cdf2f4eSNiklas Schnelle 	struct pci_driver *driver;
2324cdf2f4eSNiklas Schnelle 
2334cdf2f4eSNiklas Schnelle 	pci_dev_lock(pdev);
2344cdf2f4eSNiklas Schnelle 	pdev->error_state = es;
2354cdf2f4eSNiklas Schnelle 	/**
2364cdf2f4eSNiklas Schnelle 	 * While vfio-pci's error_detected callback notifies user-space QEMU
2374cdf2f4eSNiklas Schnelle 	 * reacts to this by freezing the guest. In an s390 environment PCI
2384cdf2f4eSNiklas Schnelle 	 * errors are rarely fatal so this is overkill. Instead in the future
2394cdf2f4eSNiklas Schnelle 	 * we will inject the error event and let the guest recover the device
2404cdf2f4eSNiklas Schnelle 	 * itself.
2414cdf2f4eSNiklas Schnelle 	 */
2424cdf2f4eSNiklas Schnelle 	if (is_passed_through(to_zpci(pdev)))
2434cdf2f4eSNiklas Schnelle 		goto out;
2444cdf2f4eSNiklas Schnelle 	driver = to_pci_driver(pdev->dev.driver);
2454cdf2f4eSNiklas Schnelle 	if (driver && driver->err_handler && driver->err_handler->error_detected)
2464cdf2f4eSNiklas Schnelle 		driver->err_handler->error_detected(pdev, pdev->error_state);
2474cdf2f4eSNiklas Schnelle out:
2484cdf2f4eSNiklas Schnelle 	pci_dev_unlock(pdev);
2494cdf2f4eSNiklas Schnelle }
2504cdf2f4eSNiklas Schnelle 
__zpci_event_error(struct zpci_ccdf_err * ccdf)251aa3b7c29SSebastian Ott static void __zpci_event_error(struct zpci_ccdf_err *ccdf)
252cbc0dd1fSJan Glauber {
2531f1dcbd4SSebastian Ott 	struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid);
2549a99649fSSebastian Ott 	struct pci_dev *pdev = NULL;
2554cdf2f4eSNiklas Schnelle 	pci_ers_result_t ers_res;
256cbc0dd1fSJan Glauber 
2576526a597SNiklas Schnelle 	zpci_dbg(3, "err fid:%x, fh:%x, pec:%x\n",
2586526a597SNiklas Schnelle 		 ccdf->fid, ccdf->fh, ccdf->pec);
2591f1dcbd4SSebastian Ott 	zpci_err("error CCDF:\n");
2601f1dcbd4SSebastian Ott 	zpci_err_hex(ccdf, sizeof(*ccdf));
2611f1dcbd4SSebastian Ott 
2624cdf2f4eSNiklas Schnelle 	if (zdev) {
2634cdf2f4eSNiklas Schnelle 		zpci_update_fh(zdev, ccdf->fh);
2644cdf2f4eSNiklas Schnelle 		if (zdev->zbus->bus)
26544510d6fSPierre Morel 			pdev = pci_get_slot(zdev->zbus->bus, zdev->devfn);
2664cdf2f4eSNiklas Schnelle 	}
2679a99649fSSebastian Ott 
2681f1dcbd4SSebastian Ott 	pr_err("%s: Event 0x%x reports an error for PCI function 0x%x\n",
269515f022eSSebastian Ott 	       pdev ? pci_name(pdev) : "n/a", ccdf->pec, ccdf->fid);
2708ead7efbSSebastian Ott 
2718ead7efbSSebastian Ott 	if (!pdev)
272c122383dSNiklas Schnelle 		goto no_pdev;
2738ead7efbSSebastian Ott 
2744cdf2f4eSNiklas Schnelle 	switch (ccdf->pec) {
275*b5632866SNiklas Schnelle 	case 0x002a: /* Error event concerns FMB */
276*b5632866SNiklas Schnelle 	case 0x002b:
277*b5632866SNiklas Schnelle 	case 0x002c:
278*b5632866SNiklas Schnelle 		break;
279*b5632866SNiklas Schnelle 	case 0x0040: /* Service Action or Error Recovery Failed */
280*b5632866SNiklas Schnelle 	case 0x003b:
281*b5632866SNiklas Schnelle 		zpci_event_io_failure(pdev, pci_channel_io_perm_failure);
282*b5632866SNiklas Schnelle 		break;
283*b5632866SNiklas Schnelle 	default: /* PCI function left in the error state attempt to recover */
2844cdf2f4eSNiklas Schnelle 		ers_res = zpci_event_attempt_error_recovery(pdev);
2854cdf2f4eSNiklas Schnelle 		if (ers_res != PCI_ERS_RESULT_RECOVERED)
2864cdf2f4eSNiklas Schnelle 			zpci_event_io_failure(pdev, pci_channel_io_perm_failure);
2874cdf2f4eSNiklas Schnelle 		break;
2884cdf2f4eSNiklas Schnelle 	}
2899a99649fSSebastian Ott 	pci_dev_put(pdev);
290c122383dSNiklas Schnelle no_pdev:
291c122383dSNiklas Schnelle 	zpci_zdev_put(zdev);
292cbc0dd1fSJan Glauber }
293cbc0dd1fSJan Glauber 
zpci_event_error(void * data)294aa3b7c29SSebastian Ott void zpci_event_error(void *data)
295cbc0dd1fSJan Glauber {
296aa3b7c29SSebastian Ott 	if (zpci_is_enabled())
297aa3b7c29SSebastian Ott 		__zpci_event_error(data);
298aa3b7c29SSebastian Ott }
299aa3b7c29SSebastian Ott 
zpci_event_hard_deconfigured(struct zpci_dev * zdev,u32 fh)300dee60c0dSNiklas Schnelle static void zpci_event_hard_deconfigured(struct zpci_dev *zdev, u32 fh)
301dee60c0dSNiklas Schnelle {
3024fe20497SNiklas Schnelle 	zpci_update_fh(zdev, fh);
303dee60c0dSNiklas Schnelle 	/* Give the driver a hint that the function is
304dee60c0dSNiklas Schnelle 	 * already unusable.
305dee60c0dSNiklas Schnelle 	 */
30695b3a8b4SNiklas Schnelle 	zpci_bus_remove_device(zdev, true);
307652d40b2SNiklas Schnelle 	/* Even though the device is already gone we still
308652d40b2SNiklas Schnelle 	 * need to free zPCI resources as part of the disable.
309652d40b2SNiklas Schnelle 	 */
3101f3f7681SNiklas Schnelle 	if (zdev->dma_table)
3111f3f7681SNiklas Schnelle 		zpci_dma_exit_device(zdev);
3121f3f7681SNiklas Schnelle 	if (zdev_enabled(zdev))
313652d40b2SNiklas Schnelle 		zpci_disable_device(zdev);
314dee60c0dSNiklas Schnelle 	zdev->state = ZPCI_FN_STATE_STANDBY;
315dee60c0dSNiklas Schnelle }
316dee60c0dSNiklas Schnelle 
__zpci_event_availability(struct zpci_ccdf_avail * ccdf)317aa3b7c29SSebastian Ott static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
318aa3b7c29SSebastian Ott {
319d795ddadSSebastian Ott 	struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid);
320c122383dSNiklas Schnelle 	bool existing_zdev = !!zdev;
3210d9cf5d8SNiklas Schnelle 	enum zpci_state state;
322d795ddadSSebastian Ott 
3236526a597SNiklas Schnelle 	zpci_dbg(3, "avl fid:%x, fh:%x, pec:%x\n",
3246526a597SNiklas Schnelle 		 ccdf->fid, ccdf->fh, ccdf->pec);
325d795ddadSSebastian Ott 	switch (ccdf->pec) {
3267fc611ffSSebastian Ott 	case 0x0301: /* Reserved|Standby -> Configured */
3277fc611ffSSebastian Ott 		if (!zdev) {
32814c87ba8SNiklas Schnelle 			zdev = zpci_create_device(ccdf->fid, ccdf->fh, ZPCI_FN_STATE_CONFIGURED);
32914c87ba8SNiklas Schnelle 			if (IS_ERR(zdev))
3307fc611ffSSebastian Ott 				break;
33114c87ba8SNiklas Schnelle 		} else {
332b76fee1bSNiklas Schnelle 			/* the configuration request may be stale */
333b76fee1bSNiklas Schnelle 			if (zdev->state != ZPCI_FN_STATE_STANDBY)
334b76fee1bSNiklas Schnelle 				break;
335f606b3efSPierre Morel 			zdev->state = ZPCI_FN_STATE_CONFIGURED;
33614c87ba8SNiklas Schnelle 		}
337a7f82c36SNiklas Schnelle 		zpci_scan_configured_device(zdev, ccdf->fh);
338d795ddadSSebastian Ott 		break;
339d795ddadSSebastian Ott 	case 0x0302: /* Reserved -> Standby */
3402631f6b6SNiklas Schnelle 		if (!zdev)
341ba764dd7SNiklas Schnelle 			zpci_create_device(ccdf->fid, ccdf->fh, ZPCI_FN_STATE_STANDBY);
3422631f6b6SNiklas Schnelle 		else
3434fe20497SNiklas Schnelle 			zpci_update_fh(zdev, ccdf->fh);
344f606b3efSPierre Morel 		break;
345d795ddadSSebastian Ott 	case 0x0303: /* Deconfiguration requested */
3462631f6b6SNiklas Schnelle 		if (zdev) {
3470d9cf5d8SNiklas Schnelle 			/* The event may have been queued before we confirgured
3480d9cf5d8SNiklas Schnelle 			 * the device.
3490d9cf5d8SNiklas Schnelle 			 */
3500d9cf5d8SNiklas Schnelle 			if (zdev->state != ZPCI_FN_STATE_CONFIGURED)
3510d9cf5d8SNiklas Schnelle 				break;
3524fe20497SNiklas Schnelle 			zpci_update_fh(zdev, ccdf->fh);
3532631f6b6SNiklas Schnelle 			zpci_deconfigure_device(zdev);
3542631f6b6SNiklas Schnelle 		}
355d795ddadSSebastian Ott 		break;
356623bd44dSSebastian Ott 	case 0x0304: /* Configured -> Standby|Reserved */
3570d9cf5d8SNiklas Schnelle 		if (zdev) {
3580d9cf5d8SNiklas Schnelle 			/* The event may have been queued before we confirgured
3590d9cf5d8SNiklas Schnelle 			 * the device.:
3600d9cf5d8SNiklas Schnelle 			 */
3610d9cf5d8SNiklas Schnelle 			if (zdev->state == ZPCI_FN_STATE_CONFIGURED)
362dee60c0dSNiklas Schnelle 				zpci_event_hard_deconfigured(zdev, ccdf->fh);
3630d9cf5d8SNiklas Schnelle 			/* The 0x0304 event may immediately reserve the device */
3640d9cf5d8SNiklas Schnelle 			if (!clp_get_state(zdev->fid, &state) &&
3650d9cf5d8SNiklas Schnelle 			    state == ZPCI_FN_STATE_RESERVED) {
366a46044a9SNiklas Schnelle 				zpci_device_reserved(zdev);
3670d9cf5d8SNiklas Schnelle 			}
3680d9cf5d8SNiklas Schnelle 		}
369d795ddadSSebastian Ott 		break;
370d795ddadSSebastian Ott 	case 0x0306: /* 0x308 or 0x302 for multiple devices */
371809fcfafSNiklas Schnelle 		zpci_remove_reserved_devices();
372809fcfafSNiklas Schnelle 		clp_scan_pci_devices();
373d795ddadSSebastian Ott 		break;
374d795ddadSSebastian Ott 	case 0x0308: /* Standby -> Reserved */
37570426892SSebastian Ott 		if (!zdev)
37670426892SSebastian Ott 			break;
377a46044a9SNiklas Schnelle 		zpci_device_reserved(zdev);
378d795ddadSSebastian Ott 		break;
379d795ddadSSebastian Ott 	default:
380d795ddadSSebastian Ott 		break;
381d795ddadSSebastian Ott 	}
382c122383dSNiklas Schnelle 	if (existing_zdev)
383c122383dSNiklas Schnelle 		zpci_zdev_put(zdev);
384cbc0dd1fSJan Glauber }
385aa3b7c29SSebastian Ott 
zpci_event_availability(void * data)386aa3b7c29SSebastian Ott void zpci_event_availability(void *data)
387aa3b7c29SSebastian Ott {
388aa3b7c29SSebastian Ott 	if (zpci_is_enabled())
389aa3b7c29SSebastian Ott 		__zpci_event_availability(data);
390aa3b7c29SSebastian Ott }
391