18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Driver for handling the PCIe controller errors on 48c2ecf20Sopenharmony_ci * HiSilicon HIP SoCs. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Copyright (c) 2020 HiSilicon Limited. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/acpi.h> 108c2ecf20Sopenharmony_ci#include <acpi/ghes.h> 118c2ecf20Sopenharmony_ci#include <linux/bitops.h> 128c2ecf20Sopenharmony_ci#include <linux/delay.h> 138c2ecf20Sopenharmony_ci#include <linux/pci.h> 148c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 158c2ecf20Sopenharmony_ci#include <linux/kfifo.h> 168c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci/* HISI PCIe controller error definitions */ 198c2ecf20Sopenharmony_ci#define HISI_PCIE_ERR_MISC_REGS 33 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define HISI_PCIE_LOCAL_VALID_VERSION BIT(0) 228c2ecf20Sopenharmony_ci#define HISI_PCIE_LOCAL_VALID_SOC_ID BIT(1) 238c2ecf20Sopenharmony_ci#define HISI_PCIE_LOCAL_VALID_SOCKET_ID BIT(2) 248c2ecf20Sopenharmony_ci#define HISI_PCIE_LOCAL_VALID_NIMBUS_ID BIT(3) 258c2ecf20Sopenharmony_ci#define HISI_PCIE_LOCAL_VALID_SUB_MODULE_ID BIT(4) 268c2ecf20Sopenharmony_ci#define HISI_PCIE_LOCAL_VALID_CORE_ID BIT(5) 278c2ecf20Sopenharmony_ci#define HISI_PCIE_LOCAL_VALID_PORT_ID BIT(6) 288c2ecf20Sopenharmony_ci#define HISI_PCIE_LOCAL_VALID_ERR_TYPE BIT(7) 298c2ecf20Sopenharmony_ci#define HISI_PCIE_LOCAL_VALID_ERR_SEVERITY BIT(8) 308c2ecf20Sopenharmony_ci#define HISI_PCIE_LOCAL_VALID_ERR_MISC 9 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic guid_t hisi_pcie_sec_guid = 338c2ecf20Sopenharmony_ci GUID_INIT(0xB2889FC9, 0xE7D7, 0x4F9D, 348c2ecf20Sopenharmony_ci 0xA8, 0x67, 0xAF, 0x42, 0xE9, 0x8B, 0xE7, 0x72); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci/* 378c2ecf20Sopenharmony_ci * Firmware reports the socket port ID where the error occurred. These 388c2ecf20Sopenharmony_ci * macros convert that to the core ID and core port ID required by the 398c2ecf20Sopenharmony_ci * ACPI reset method. 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_ci#define HISI_PCIE_PORT_ID(core, v) (((v) >> 1) + ((core) << 3)) 428c2ecf20Sopenharmony_ci#define HISI_PCIE_CORE_ID(v) ((v) >> 3) 438c2ecf20Sopenharmony_ci#define HISI_PCIE_CORE_PORT_ID(v) (((v) & 7) << 1) 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_cistruct hisi_pcie_error_data { 468c2ecf20Sopenharmony_ci u64 val_bits; 478c2ecf20Sopenharmony_ci u8 version; 488c2ecf20Sopenharmony_ci u8 soc_id; 498c2ecf20Sopenharmony_ci u8 socket_id; 508c2ecf20Sopenharmony_ci u8 nimbus_id; 518c2ecf20Sopenharmony_ci u8 sub_module_id; 528c2ecf20Sopenharmony_ci u8 core_id; 538c2ecf20Sopenharmony_ci u8 port_id; 548c2ecf20Sopenharmony_ci u8 err_severity; 558c2ecf20Sopenharmony_ci u16 err_type; 568c2ecf20Sopenharmony_ci u8 reserv[2]; 578c2ecf20Sopenharmony_ci u32 err_misc[HISI_PCIE_ERR_MISC_REGS]; 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistruct hisi_pcie_error_private { 618c2ecf20Sopenharmony_ci struct notifier_block nb; 628c2ecf20Sopenharmony_ci struct device *dev; 638c2ecf20Sopenharmony_ci}; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cienum hisi_pcie_submodule_id { 668c2ecf20Sopenharmony_ci HISI_PCIE_SUB_MODULE_ID_AP, 678c2ecf20Sopenharmony_ci HISI_PCIE_SUB_MODULE_ID_TL, 688c2ecf20Sopenharmony_ci HISI_PCIE_SUB_MODULE_ID_MAC, 698c2ecf20Sopenharmony_ci HISI_PCIE_SUB_MODULE_ID_DL, 708c2ecf20Sopenharmony_ci HISI_PCIE_SUB_MODULE_ID_SDI, 718c2ecf20Sopenharmony_ci}; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic const char * const hisi_pcie_sub_module[] = { 748c2ecf20Sopenharmony_ci [HISI_PCIE_SUB_MODULE_ID_AP] = "AP Layer", 758c2ecf20Sopenharmony_ci [HISI_PCIE_SUB_MODULE_ID_TL] = "TL Layer", 768c2ecf20Sopenharmony_ci [HISI_PCIE_SUB_MODULE_ID_MAC] = "MAC Layer", 778c2ecf20Sopenharmony_ci [HISI_PCIE_SUB_MODULE_ID_DL] = "DL Layer", 788c2ecf20Sopenharmony_ci [HISI_PCIE_SUB_MODULE_ID_SDI] = "SDI Layer", 798c2ecf20Sopenharmony_ci}; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cienum hisi_pcie_err_severity { 828c2ecf20Sopenharmony_ci HISI_PCIE_ERR_SEV_RECOVERABLE, 838c2ecf20Sopenharmony_ci HISI_PCIE_ERR_SEV_FATAL, 848c2ecf20Sopenharmony_ci HISI_PCIE_ERR_SEV_CORRECTED, 858c2ecf20Sopenharmony_ci HISI_PCIE_ERR_SEV_NONE, 868c2ecf20Sopenharmony_ci}; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic const char * const hisi_pcie_error_sev[] = { 898c2ecf20Sopenharmony_ci [HISI_PCIE_ERR_SEV_RECOVERABLE] = "recoverable", 908c2ecf20Sopenharmony_ci [HISI_PCIE_ERR_SEV_FATAL] = "fatal", 918c2ecf20Sopenharmony_ci [HISI_PCIE_ERR_SEV_CORRECTED] = "corrected", 928c2ecf20Sopenharmony_ci [HISI_PCIE_ERR_SEV_NONE] = "none", 938c2ecf20Sopenharmony_ci}; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic const char *hisi_pcie_get_string(const char * const *array, 968c2ecf20Sopenharmony_ci size_t n, u32 id) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci u32 index; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci for (index = 0; index < n; index++) { 1018c2ecf20Sopenharmony_ci if (index == id && array[index]) 1028c2ecf20Sopenharmony_ci return array[index]; 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci return "unknown"; 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic int hisi_pcie_port_reset(struct platform_device *pdev, 1098c2ecf20Sopenharmony_ci u32 chip_id, u32 port_id) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 1128c2ecf20Sopenharmony_ci acpi_handle handle = ACPI_HANDLE(dev); 1138c2ecf20Sopenharmony_ci union acpi_object arg[3]; 1148c2ecf20Sopenharmony_ci struct acpi_object_list arg_list; 1158c2ecf20Sopenharmony_ci acpi_status s; 1168c2ecf20Sopenharmony_ci unsigned long long data = 0; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci arg[0].type = ACPI_TYPE_INTEGER; 1198c2ecf20Sopenharmony_ci arg[0].integer.value = chip_id; 1208c2ecf20Sopenharmony_ci arg[1].type = ACPI_TYPE_INTEGER; 1218c2ecf20Sopenharmony_ci arg[1].integer.value = HISI_PCIE_CORE_ID(port_id); 1228c2ecf20Sopenharmony_ci arg[2].type = ACPI_TYPE_INTEGER; 1238c2ecf20Sopenharmony_ci arg[2].integer.value = HISI_PCIE_CORE_PORT_ID(port_id); 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci arg_list.count = 3; 1268c2ecf20Sopenharmony_ci arg_list.pointer = arg; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci s = acpi_evaluate_integer(handle, "RST", &arg_list, &data); 1298c2ecf20Sopenharmony_ci if (ACPI_FAILURE(s)) { 1308c2ecf20Sopenharmony_ci dev_err(dev, "No RST method\n"); 1318c2ecf20Sopenharmony_ci return -EIO; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if (data) { 1358c2ecf20Sopenharmony_ci dev_err(dev, "Failed to Reset\n"); 1368c2ecf20Sopenharmony_ci return -EIO; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci return 0; 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic int hisi_pcie_port_do_recovery(struct platform_device *dev, 1438c2ecf20Sopenharmony_ci u32 chip_id, u32 port_id) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci acpi_status s; 1468c2ecf20Sopenharmony_ci struct device *device = &dev->dev; 1478c2ecf20Sopenharmony_ci acpi_handle root_handle = ACPI_HANDLE(device); 1488c2ecf20Sopenharmony_ci struct acpi_pci_root *pci_root; 1498c2ecf20Sopenharmony_ci struct pci_bus *root_bus; 1508c2ecf20Sopenharmony_ci struct pci_dev *pdev; 1518c2ecf20Sopenharmony_ci u32 domain, busnr, devfn; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci s = acpi_get_parent(root_handle, &root_handle); 1548c2ecf20Sopenharmony_ci if (ACPI_FAILURE(s)) 1558c2ecf20Sopenharmony_ci return -ENODEV; 1568c2ecf20Sopenharmony_ci pci_root = acpi_pci_find_root(root_handle); 1578c2ecf20Sopenharmony_ci if (!pci_root) 1588c2ecf20Sopenharmony_ci return -ENODEV; 1598c2ecf20Sopenharmony_ci root_bus = pci_root->bus; 1608c2ecf20Sopenharmony_ci domain = pci_root->segment; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci busnr = root_bus->number; 1638c2ecf20Sopenharmony_ci devfn = PCI_DEVFN(port_id, 0); 1648c2ecf20Sopenharmony_ci pdev = pci_get_domain_bus_and_slot(domain, busnr, devfn); 1658c2ecf20Sopenharmony_ci if (!pdev) { 1668c2ecf20Sopenharmony_ci dev_info(device, "Fail to get root port %04x:%02x:%02x.%d device\n", 1678c2ecf20Sopenharmony_ci domain, busnr, PCI_SLOT(devfn), PCI_FUNC(devfn)); 1688c2ecf20Sopenharmony_ci return -ENODEV; 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci pci_stop_and_remove_bus_device_locked(pdev); 1728c2ecf20Sopenharmony_ci pci_dev_put(pdev); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (hisi_pcie_port_reset(dev, chip_id, port_id)) 1758c2ecf20Sopenharmony_ci return -EIO; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci /* 1788c2ecf20Sopenharmony_ci * The initialization time of subordinate devices after 1798c2ecf20Sopenharmony_ci * hot reset is no more than 1s, which is required by 1808c2ecf20Sopenharmony_ci * the PCI spec v5.0 sec 6.6.1. The time will shorten 1818c2ecf20Sopenharmony_ci * if Readiness Notifications mechanisms are used. But 1828c2ecf20Sopenharmony_ci * wait 1s here to adapt any conditions. 1838c2ecf20Sopenharmony_ci */ 1848c2ecf20Sopenharmony_ci ssleep(1UL); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci /* add root port and downstream devices */ 1878c2ecf20Sopenharmony_ci pci_lock_rescan_remove(); 1888c2ecf20Sopenharmony_ci pci_rescan_bus(root_bus); 1898c2ecf20Sopenharmony_ci pci_unlock_rescan_remove(); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci return 0; 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic void hisi_pcie_handle_error(struct platform_device *pdev, 1958c2ecf20Sopenharmony_ci const struct hisi_pcie_error_data *edata) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 1988c2ecf20Sopenharmony_ci int idx, rc; 1998c2ecf20Sopenharmony_ci const unsigned long valid_bits[] = {BITMAP_FROM_U64(edata->val_bits)}; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (edata->val_bits == 0) { 2028c2ecf20Sopenharmony_ci dev_warn(dev, "%s: no valid error information\n", __func__); 2038c2ecf20Sopenharmony_ci return; 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci dev_info(dev, "\nHISI : HIP : PCIe controller error\n"); 2078c2ecf20Sopenharmony_ci if (edata->val_bits & HISI_PCIE_LOCAL_VALID_SOC_ID) 2088c2ecf20Sopenharmony_ci dev_info(dev, "Table version = %d\n", edata->version); 2098c2ecf20Sopenharmony_ci if (edata->val_bits & HISI_PCIE_LOCAL_VALID_SOCKET_ID) 2108c2ecf20Sopenharmony_ci dev_info(dev, "Socket ID = %d\n", edata->socket_id); 2118c2ecf20Sopenharmony_ci if (edata->val_bits & HISI_PCIE_LOCAL_VALID_NIMBUS_ID) 2128c2ecf20Sopenharmony_ci dev_info(dev, "Nimbus ID = %d\n", edata->nimbus_id); 2138c2ecf20Sopenharmony_ci if (edata->val_bits & HISI_PCIE_LOCAL_VALID_SUB_MODULE_ID) 2148c2ecf20Sopenharmony_ci dev_info(dev, "Sub Module = %s\n", 2158c2ecf20Sopenharmony_ci hisi_pcie_get_string(hisi_pcie_sub_module, 2168c2ecf20Sopenharmony_ci ARRAY_SIZE(hisi_pcie_sub_module), 2178c2ecf20Sopenharmony_ci edata->sub_module_id)); 2188c2ecf20Sopenharmony_ci if (edata->val_bits & HISI_PCIE_LOCAL_VALID_CORE_ID) 2198c2ecf20Sopenharmony_ci dev_info(dev, "Core ID = core%d\n", edata->core_id); 2208c2ecf20Sopenharmony_ci if (edata->val_bits & HISI_PCIE_LOCAL_VALID_PORT_ID) 2218c2ecf20Sopenharmony_ci dev_info(dev, "Port ID = port%d\n", edata->port_id); 2228c2ecf20Sopenharmony_ci if (edata->val_bits & HISI_PCIE_LOCAL_VALID_ERR_SEVERITY) 2238c2ecf20Sopenharmony_ci dev_info(dev, "Error severity = %s\n", 2248c2ecf20Sopenharmony_ci hisi_pcie_get_string(hisi_pcie_error_sev, 2258c2ecf20Sopenharmony_ci ARRAY_SIZE(hisi_pcie_error_sev), 2268c2ecf20Sopenharmony_ci edata->err_severity)); 2278c2ecf20Sopenharmony_ci if (edata->val_bits & HISI_PCIE_LOCAL_VALID_ERR_TYPE) 2288c2ecf20Sopenharmony_ci dev_info(dev, "Error type = 0x%x\n", edata->err_type); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci dev_info(dev, "Reg Dump:\n"); 2318c2ecf20Sopenharmony_ci idx = HISI_PCIE_LOCAL_VALID_ERR_MISC; 2328c2ecf20Sopenharmony_ci for_each_set_bit_from(idx, valid_bits, 2338c2ecf20Sopenharmony_ci HISI_PCIE_LOCAL_VALID_ERR_MISC + HISI_PCIE_ERR_MISC_REGS) 2348c2ecf20Sopenharmony_ci dev_info(dev, "ERR_MISC_%d = 0x%x\n", idx - HISI_PCIE_LOCAL_VALID_ERR_MISC, 2358c2ecf20Sopenharmony_ci edata->err_misc[idx - HISI_PCIE_LOCAL_VALID_ERR_MISC]); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci if (edata->err_severity != HISI_PCIE_ERR_SEV_RECOVERABLE) 2388c2ecf20Sopenharmony_ci return; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci /* Recovery for the PCIe controller errors, try reset 2418c2ecf20Sopenharmony_ci * PCI port for the error recovery 2428c2ecf20Sopenharmony_ci */ 2438c2ecf20Sopenharmony_ci rc = hisi_pcie_port_do_recovery(pdev, edata->socket_id, 2448c2ecf20Sopenharmony_ci HISI_PCIE_PORT_ID(edata->core_id, edata->port_id)); 2458c2ecf20Sopenharmony_ci if (rc) 2468c2ecf20Sopenharmony_ci dev_info(dev, "fail to do hisi pcie port reset\n"); 2478c2ecf20Sopenharmony_ci} 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic int hisi_pcie_notify_error(struct notifier_block *nb, 2508c2ecf20Sopenharmony_ci unsigned long event, void *data) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci struct acpi_hest_generic_data *gdata = data; 2538c2ecf20Sopenharmony_ci const struct hisi_pcie_error_data *error_data = acpi_hest_get_payload(gdata); 2548c2ecf20Sopenharmony_ci struct hisi_pcie_error_private *priv; 2558c2ecf20Sopenharmony_ci struct device *dev; 2568c2ecf20Sopenharmony_ci struct platform_device *pdev; 2578c2ecf20Sopenharmony_ci guid_t err_sec_guid; 2588c2ecf20Sopenharmony_ci u8 socket; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci import_guid(&err_sec_guid, gdata->section_type); 2618c2ecf20Sopenharmony_ci if (!guid_equal(&err_sec_guid, &hisi_pcie_sec_guid)) 2628c2ecf20Sopenharmony_ci return NOTIFY_DONE; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci priv = container_of(nb, struct hisi_pcie_error_private, nb); 2658c2ecf20Sopenharmony_ci dev = priv->dev; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci if (device_property_read_u8(dev, "socket", &socket)) 2688c2ecf20Sopenharmony_ci return NOTIFY_DONE; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci if (error_data->socket_id != socket) 2718c2ecf20Sopenharmony_ci return NOTIFY_DONE; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci pdev = container_of(dev, struct platform_device, dev); 2748c2ecf20Sopenharmony_ci hisi_pcie_handle_error(pdev, error_data); 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci return NOTIFY_OK; 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_cistatic int hisi_pcie_error_handler_probe(struct platform_device *pdev) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci struct hisi_pcie_error_private *priv; 2828c2ecf20Sopenharmony_ci int ret; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 2858c2ecf20Sopenharmony_ci if (!priv) 2868c2ecf20Sopenharmony_ci return -ENOMEM; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci priv->nb.notifier_call = hisi_pcie_notify_error; 2898c2ecf20Sopenharmony_ci priv->dev = &pdev->dev; 2908c2ecf20Sopenharmony_ci ret = ghes_register_vendor_record_notifier(&priv->nb); 2918c2ecf20Sopenharmony_ci if (ret) { 2928c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 2938c2ecf20Sopenharmony_ci "Failed to register hisi pcie controller error handler with apei\n"); 2948c2ecf20Sopenharmony_ci return ret; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, priv); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci return 0; 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistatic int hisi_pcie_error_handler_remove(struct platform_device *pdev) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci struct hisi_pcie_error_private *priv = platform_get_drvdata(pdev); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci ghes_unregister_vendor_record_notifier(&priv->nb); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci return 0; 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_cistatic const struct acpi_device_id hisi_pcie_acpi_match[] = { 3128c2ecf20Sopenharmony_ci { "HISI0361", 0 }, 3138c2ecf20Sopenharmony_ci { } 3148c2ecf20Sopenharmony_ci}; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic struct platform_driver hisi_pcie_error_handler_driver = { 3178c2ecf20Sopenharmony_ci .driver = { 3188c2ecf20Sopenharmony_ci .name = "hisi-pcie-error-handler", 3198c2ecf20Sopenharmony_ci .acpi_match_table = hisi_pcie_acpi_match, 3208c2ecf20Sopenharmony_ci }, 3218c2ecf20Sopenharmony_ci .probe = hisi_pcie_error_handler_probe, 3228c2ecf20Sopenharmony_ci .remove = hisi_pcie_error_handler_remove, 3238c2ecf20Sopenharmony_ci}; 3248c2ecf20Sopenharmony_cimodule_platform_driver(hisi_pcie_error_handler_driver); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("HiSilicon HIP PCIe controller error handling driver"); 3278c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 328