1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * IOAPIC/IOxAPIC/IOSAPIC driver 4 * 5 * Copyright (C) 2009 Fujitsu Limited. 6 * (c) Copyright 2009 Hewlett-Packard Development Company, L.P. 7 * 8 * Copyright (C) 2014 Intel Corporation 9 * 10 * Based on original drivers/pci/ioapic.c 11 * Yinghai Lu <yinghai@kernel.org> 12 * Jiang Liu <jiang.liu@intel.com> 13 */ 14 15 /* 16 * This driver manages I/O APICs added by hotplug after boot. 17 * We try to claim all I/O APIC devices, but those present at boot were 18 * registered when we parsed the ACPI MADT. 19 */ 20 21 #define pr_fmt(fmt) "ACPI: IOAPIC: " fmt 22 23 #include <linux/slab.h> 24 #include <linux/acpi.h> 25 #include <linux/pci.h> 26 #include <acpi/acpi.h> 27 #include "internal.h" 28 29 struct acpi_pci_ioapic { 30 acpi_handle root_handle; 31 acpi_handle handle; 32 u32 gsi_base; 33 struct resource res; 34 struct pci_dev *pdev; 35 struct list_head list; 36 }; 37 38 static LIST_HEAD(ioapic_list); 39 static DEFINE_MUTEX(ioapic_list_lock); 40 41 static acpi_status setup_res(struct acpi_resource *acpi_res, void *data) 42 { 43 struct resource *res = data; 44 struct resource_win win; 45 46 /* 47 * We might assign this to 'res' later, make sure all pointers are 48 * cleared before the resource is added to the global list 49 */ 50 memset(&win, 0, sizeof(win)); 51 52 res->flags = 0; 53 if (acpi_dev_filter_resource_type(acpi_res, IORESOURCE_MEM)) 54 return AE_OK; 55 56 if (!acpi_dev_resource_memory(acpi_res, res)) { 57 if (acpi_dev_resource_address_space(acpi_res, &win) || 58 acpi_dev_resource_ext_address_space(acpi_res, &win)) 59 *res = win.res; 60 } 61 if ((res->flags & IORESOURCE_PREFETCH) || 62 (res->flags & IORESOURCE_DISABLED)) 63 res->flags = 0; 64 65 return AE_CTRL_TERMINATE; 66 } 67 68 static bool acpi_is_ioapic(acpi_handle handle, char **type) 69 { 70 acpi_status status; 71 struct acpi_device_info *info; 72 char *hid = NULL; 73 bool match = false; 74 75 if (!acpi_has_method(handle, "_GSB")) 76 return false; 77 78 status = acpi_get_object_info(handle, &info); 79 if (ACPI_SUCCESS(status)) { 80 if (info->valid & ACPI_VALID_HID) 81 hid = info->hardware_id.string; 82 if (hid) { 83 if (strcmp(hid, "ACPI0009") == 0) { 84 *type = "IOxAPIC"; 85 match = true; 86 } else if (strcmp(hid, "ACPI000A") == 0) { 87 *type = "IOAPIC"; 88 match = true; 89 } 90 } 91 kfree(info); 92 } 93 94 return match; 95 } 96 97 static acpi_status handle_ioapic_add(acpi_handle handle, u32 lvl, 98 void *context, void **rv) 99 { 100 acpi_status status; 101 unsigned long long gsi_base; 102 struct acpi_pci_ioapic *ioapic; 103 struct pci_dev *dev = NULL; 104 struct resource *res = NULL, *pci_res = NULL, *crs_res; 105 char *type = NULL; 106 107 if (!acpi_is_ioapic(handle, &type)) 108 return AE_OK; 109 110 mutex_lock(&ioapic_list_lock); 111 list_for_each_entry(ioapic, &ioapic_list, list) 112 if (ioapic->handle == handle) { 113 mutex_unlock(&ioapic_list_lock); 114 return AE_OK; 115 } 116 117 status = acpi_evaluate_integer(handle, "_GSB", NULL, &gsi_base); 118 if (ACPI_FAILURE(status)) { 119 acpi_handle_warn(handle, "failed to evaluate _GSB method\n"); 120 goto exit; 121 } 122 123 ioapic = kzalloc(sizeof(*ioapic), GFP_KERNEL); 124 if (!ioapic) { 125 pr_err("cannot allocate memory for new IOAPIC\n"); 126 goto exit; 127 } else { 128 ioapic->root_handle = (acpi_handle)context; 129 ioapic->handle = handle; 130 ioapic->gsi_base = (u32)gsi_base; 131 INIT_LIST_HEAD(&ioapic->list); 132 } 133 134 if (acpi_ioapic_registered(handle, (u32)gsi_base)) 135 goto done; 136 137 dev = acpi_get_pci_dev(handle); 138 if (dev && pci_resource_len(dev, 0)) { 139 if (pci_enable_device(dev) < 0) 140 goto exit_put; 141 pci_set_master(dev); 142 if (pci_request_region(dev, 0, type)) 143 goto exit_disable; 144 pci_res = &dev->resource[0]; 145 ioapic->pdev = dev; 146 } else { 147 pci_dev_put(dev); 148 dev = NULL; 149 } 150 151 crs_res = &ioapic->res; 152 acpi_walk_resources(handle, METHOD_NAME__CRS, setup_res, crs_res); 153 crs_res->name = type; 154 crs_res->flags |= IORESOURCE_BUSY; 155 if (crs_res->flags == 0) { 156 acpi_handle_warn(handle, "failed to get resource\n"); 157 goto exit_release; 158 } else if (insert_resource(&iomem_resource, crs_res)) { 159 acpi_handle_warn(handle, "failed to insert resource\n"); 160 goto exit_release; 161 } 162 163 /* try pci resource first, then "_CRS" resource */ 164 res = pci_res; 165 if (!res || !res->flags) 166 res = crs_res; 167 168 if (acpi_register_ioapic(handle, res->start, (u32)gsi_base)) { 169 acpi_handle_warn(handle, "failed to register IOAPIC\n"); 170 goto exit_release; 171 } 172 done: 173 list_add(&ioapic->list, &ioapic_list); 174 mutex_unlock(&ioapic_list_lock); 175 176 if (dev) 177 dev_info(&dev->dev, "%s at %pR, GSI %u\n", 178 type, res, (u32)gsi_base); 179 else 180 acpi_handle_info(handle, "%s at %pR, GSI %u\n", 181 type, res, (u32)gsi_base); 182 183 return AE_OK; 184 185 exit_release: 186 if (dev) 187 pci_release_region(dev, 0); 188 if (ioapic->res.flags && ioapic->res.parent) 189 release_resource(&ioapic->res); 190 exit_disable: 191 if (dev) 192 pci_disable_device(dev); 193 exit_put: 194 pci_dev_put(dev); 195 kfree(ioapic); 196 exit: 197 mutex_unlock(&ioapic_list_lock); 198 *(acpi_status *)rv = AE_ERROR; 199 return AE_OK; 200 } 201 202 int acpi_ioapic_add(acpi_handle root_handle) 203 { 204 acpi_status status, retval = AE_OK; 205 206 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, root_handle, 207 UINT_MAX, handle_ioapic_add, NULL, 208 root_handle, (void **)&retval); 209 210 return ACPI_SUCCESS(status) && ACPI_SUCCESS(retval) ? 0 : -ENODEV; 211 } 212 213 void pci_ioapic_remove(struct acpi_pci_root *root) 214 { 215 struct acpi_pci_ioapic *ioapic, *tmp; 216 217 mutex_lock(&ioapic_list_lock); 218 list_for_each_entry_safe(ioapic, tmp, &ioapic_list, list) { 219 if (root->device->handle != ioapic->root_handle) 220 continue; 221 if (ioapic->pdev) { 222 pci_release_region(ioapic->pdev, 0); 223 pci_disable_device(ioapic->pdev); 224 pci_dev_put(ioapic->pdev); 225 } 226 } 227 mutex_unlock(&ioapic_list_lock); 228 } 229 230 int acpi_ioapic_remove(struct acpi_pci_root *root) 231 { 232 int retval = 0; 233 struct acpi_pci_ioapic *ioapic, *tmp; 234 235 mutex_lock(&ioapic_list_lock); 236 list_for_each_entry_safe(ioapic, tmp, &ioapic_list, list) { 237 if (root->device->handle != ioapic->root_handle) 238 continue; 239 if (acpi_unregister_ioapic(ioapic->handle, ioapic->gsi_base)) 240 retval = -EBUSY; 241 if (ioapic->res.flags && ioapic->res.parent) 242 release_resource(&ioapic->res); 243 list_del(&ioapic->list); 244 kfree(ioapic); 245 } 246 mutex_unlock(&ioapic_list_lock); 247 248 return retval; 249 } 250