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