xref: /openbmc/linux/arch/s390/pci/pci_event.c (revision 723b5a9d)
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)
272*c122383dSNiklas Schnelle 		goto no_pdev;
2738ead7efbSSebastian Ott 
2744cdf2f4eSNiklas Schnelle 	switch (ccdf->pec) {
2754cdf2f4eSNiklas Schnelle 	case 0x003a: /* Service Action or Error Recovery Successful */
2764cdf2f4eSNiklas Schnelle 		ers_res = zpci_event_attempt_error_recovery(pdev);
2774cdf2f4eSNiklas Schnelle 		if (ers_res != PCI_ERS_RESULT_RECOVERED)
2784cdf2f4eSNiklas Schnelle 			zpci_event_io_failure(pdev, pci_channel_io_perm_failure);
2794cdf2f4eSNiklas Schnelle 		break;
2804cdf2f4eSNiklas Schnelle 	default:
2814cdf2f4eSNiklas Schnelle 		/*
2824cdf2f4eSNiklas Schnelle 		 * Mark as frozen not permanently failed because the device
2834cdf2f4eSNiklas Schnelle 		 * could be subsequently recovered by the platform.
2844cdf2f4eSNiklas Schnelle 		 */
2854cdf2f4eSNiklas Schnelle 		zpci_event_io_failure(pdev, pci_channel_io_frozen);
2864cdf2f4eSNiklas Schnelle 		break;
2874cdf2f4eSNiklas Schnelle 	}
2889a99649fSSebastian Ott 	pci_dev_put(pdev);
289*c122383dSNiklas Schnelle no_pdev:
290*c122383dSNiklas Schnelle 	zpci_zdev_put(zdev);
291cbc0dd1fSJan Glauber }
292cbc0dd1fSJan Glauber 
zpci_event_error(void * data)293aa3b7c29SSebastian Ott void zpci_event_error(void *data)
294cbc0dd1fSJan Glauber {
295aa3b7c29SSebastian Ott 	if (zpci_is_enabled())
296aa3b7c29SSebastian Ott 		__zpci_event_error(data);
297aa3b7c29SSebastian Ott }
298aa3b7c29SSebastian Ott 
zpci_event_hard_deconfigured(struct zpci_dev * zdev,u32 fh)299dee60c0dSNiklas Schnelle static void zpci_event_hard_deconfigured(struct zpci_dev *zdev, u32 fh)
300dee60c0dSNiklas Schnelle {
3014fe20497SNiklas Schnelle 	zpci_update_fh(zdev, fh);
302dee60c0dSNiklas Schnelle 	/* Give the driver a hint that the function is
303dee60c0dSNiklas Schnelle 	 * already unusable.
304dee60c0dSNiklas Schnelle 	 */
30595b3a8b4SNiklas Schnelle 	zpci_bus_remove_device(zdev, true);
306652d40b2SNiklas Schnelle 	/* Even though the device is already gone we still
307652d40b2SNiklas Schnelle 	 * need to free zPCI resources as part of the disable.
308652d40b2SNiklas Schnelle 	 */
3091f3f7681SNiklas Schnelle 	if (zdev->dma_table)
3101f3f7681SNiklas Schnelle 		zpci_dma_exit_device(zdev);
3111f3f7681SNiklas Schnelle 	if (zdev_enabled(zdev))
312652d40b2SNiklas Schnelle 		zpci_disable_device(zdev);
313dee60c0dSNiklas Schnelle 	zdev->state = ZPCI_FN_STATE_STANDBY;
314dee60c0dSNiklas Schnelle }
315dee60c0dSNiklas Schnelle 
__zpci_event_availability(struct zpci_ccdf_avail * ccdf)316aa3b7c29SSebastian Ott static void __zpci_event_availability(struct zpci_ccdf_avail *ccdf)
317aa3b7c29SSebastian Ott {
318d795ddadSSebastian Ott 	struct zpci_dev *zdev = get_zdev_by_fid(ccdf->fid);
319*c122383dSNiklas Schnelle 	bool existing_zdev = !!zdev;
3200d9cf5d8SNiklas Schnelle 	enum zpci_state state;
321d795ddadSSebastian Ott 
3226526a597SNiklas Schnelle 	zpci_dbg(3, "avl fid:%x, fh:%x, pec:%x\n",
3236526a597SNiklas Schnelle 		 ccdf->fid, ccdf->fh, ccdf->pec);
324d795ddadSSebastian Ott 	switch (ccdf->pec) {
3257fc611ffSSebastian Ott 	case 0x0301: /* Reserved|Standby -> Configured */
3267fc611ffSSebastian Ott 		if (!zdev) {
32714c87ba8SNiklas Schnelle 			zdev = zpci_create_device(ccdf->fid, ccdf->fh, ZPCI_FN_STATE_CONFIGURED);
32814c87ba8SNiklas Schnelle 			if (IS_ERR(zdev))
3297fc611ffSSebastian Ott 				break;
33014c87ba8SNiklas Schnelle 		} else {
331b76fee1bSNiklas Schnelle 			/* the configuration request may be stale */
332b76fee1bSNiklas Schnelle 			if (zdev->state != ZPCI_FN_STATE_STANDBY)
333b76fee1bSNiklas Schnelle 				break;
334f606b3efSPierre Morel 			zdev->state = ZPCI_FN_STATE_CONFIGURED;
33514c87ba8SNiklas Schnelle 		}
336a7f82c36SNiklas Schnelle 		zpci_scan_configured_device(zdev, ccdf->fh);
337d795ddadSSebastian Ott 		break;
338d795ddadSSebastian Ott 	case 0x0302: /* Reserved -> Standby */
3392631f6b6SNiklas Schnelle 		if (!zdev)
340ba764dd7SNiklas Schnelle 			zpci_create_device(ccdf->fid, ccdf->fh, ZPCI_FN_STATE_STANDBY);
3412631f6b6SNiklas Schnelle 		else
3424fe20497SNiklas Schnelle 			zpci_update_fh(zdev, ccdf->fh);
343f606b3efSPierre Morel 		break;
344d795ddadSSebastian Ott 	case 0x0303: /* Deconfiguration requested */
3452631f6b6SNiklas Schnelle 		if (zdev) {
3460d9cf5d8SNiklas Schnelle 			/* The event may have been queued before we confirgured
3470d9cf5d8SNiklas Schnelle 			 * the device.
3480d9cf5d8SNiklas Schnelle 			 */
3490d9cf5d8SNiklas Schnelle 			if (zdev->state != ZPCI_FN_STATE_CONFIGURED)
3500d9cf5d8SNiklas Schnelle 				break;
3514fe20497SNiklas Schnelle 			zpci_update_fh(zdev, ccdf->fh);
3522631f6b6SNiklas Schnelle 			zpci_deconfigure_device(zdev);
3532631f6b6SNiklas Schnelle 		}
354d795ddadSSebastian Ott 		break;
355623bd44dSSebastian Ott 	case 0x0304: /* Configured -> Standby|Reserved */
3560d9cf5d8SNiklas Schnelle 		if (zdev) {
3570d9cf5d8SNiklas Schnelle 			/* The event may have been queued before we confirgured
3580d9cf5d8SNiklas Schnelle 			 * the device.:
3590d9cf5d8SNiklas Schnelle 			 */
3600d9cf5d8SNiklas Schnelle 			if (zdev->state == ZPCI_FN_STATE_CONFIGURED)
361dee60c0dSNiklas Schnelle 				zpci_event_hard_deconfigured(zdev, ccdf->fh);
3620d9cf5d8SNiklas Schnelle 			/* The 0x0304 event may immediately reserve the device */
3630d9cf5d8SNiklas Schnelle 			if (!clp_get_state(zdev->fid, &state) &&
3640d9cf5d8SNiklas Schnelle 			    state == ZPCI_FN_STATE_RESERVED) {
365a46044a9SNiklas Schnelle 				zpci_device_reserved(zdev);
3660d9cf5d8SNiklas Schnelle 			}
3670d9cf5d8SNiklas Schnelle 		}
368d795ddadSSebastian Ott 		break;
369d795ddadSSebastian Ott 	case 0x0306: /* 0x308 or 0x302 for multiple devices */
370809fcfafSNiklas Schnelle 		zpci_remove_reserved_devices();
371809fcfafSNiklas Schnelle 		clp_scan_pci_devices();
372d795ddadSSebastian Ott 		break;
373d795ddadSSebastian Ott 	case 0x0308: /* Standby -> Reserved */
37470426892SSebastian Ott 		if (!zdev)
37570426892SSebastian Ott 			break;
376a46044a9SNiklas Schnelle 		zpci_device_reserved(zdev);
377d795ddadSSebastian Ott 		break;
378d795ddadSSebastian Ott 	default:
379d795ddadSSebastian Ott 		break;
380d795ddadSSebastian Ott 	}
381*c122383dSNiklas Schnelle 	if (existing_zdev)
382*c122383dSNiklas Schnelle 		zpci_zdev_put(zdev);
383cbc0dd1fSJan Glauber }
384aa3b7c29SSebastian Ott 
zpci_event_availability(void * data)385aa3b7c29SSebastian Ott void zpci_event_availability(void *data)
386aa3b7c29SSebastian Ott {
387aa3b7c29SSebastian Ott 	if (zpci_is_enabled())
388aa3b7c29SSebastian Ott 		__zpci_event_availability(data);
389aa3b7c29SSebastian Ott }
390