0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021 #define pr_fmt(fmt) "ACPI: IOAPIC: " fmt
0022
0023 #include <linux/slab.h>
0024 #include <linux/acpi.h>
0025 #include <linux/pci.h>
0026 #include <acpi/acpi.h>
0027
0028 struct acpi_pci_ioapic {
0029 acpi_handle root_handle;
0030 acpi_handle handle;
0031 u32 gsi_base;
0032 struct resource res;
0033 struct pci_dev *pdev;
0034 struct list_head list;
0035 };
0036
0037 static LIST_HEAD(ioapic_list);
0038 static DEFINE_MUTEX(ioapic_list_lock);
0039
0040 static acpi_status setup_res(struct acpi_resource *acpi_res, void *data)
0041 {
0042 struct resource *res = data;
0043 struct resource_win win;
0044
0045
0046
0047
0048
0049 memset(&win, 0, sizeof(win));
0050
0051 res->flags = 0;
0052 if (acpi_dev_filter_resource_type(acpi_res, IORESOURCE_MEM))
0053 return AE_OK;
0054
0055 if (!acpi_dev_resource_memory(acpi_res, res)) {
0056 if (acpi_dev_resource_address_space(acpi_res, &win) ||
0057 acpi_dev_resource_ext_address_space(acpi_res, &win))
0058 *res = win.res;
0059 }
0060 if ((res->flags & IORESOURCE_PREFETCH) ||
0061 (res->flags & IORESOURCE_DISABLED))
0062 res->flags = 0;
0063
0064 return AE_CTRL_TERMINATE;
0065 }
0066
0067 static bool acpi_is_ioapic(acpi_handle handle, char **type)
0068 {
0069 acpi_status status;
0070 struct acpi_device_info *info;
0071 char *hid = NULL;
0072 bool match = false;
0073
0074 if (!acpi_has_method(handle, "_GSB"))
0075 return false;
0076
0077 status = acpi_get_object_info(handle, &info);
0078 if (ACPI_SUCCESS(status)) {
0079 if (info->valid & ACPI_VALID_HID)
0080 hid = info->hardware_id.string;
0081 if (hid) {
0082 if (strcmp(hid, "ACPI0009") == 0) {
0083 *type = "IOxAPIC";
0084 match = true;
0085 } else if (strcmp(hid, "ACPI000A") == 0) {
0086 *type = "IOAPIC";
0087 match = true;
0088 }
0089 }
0090 kfree(info);
0091 }
0092
0093 return match;
0094 }
0095
0096 static acpi_status handle_ioapic_add(acpi_handle handle, u32 lvl,
0097 void *context, void **rv)
0098 {
0099 acpi_status status;
0100 unsigned long long gsi_base;
0101 struct acpi_pci_ioapic *ioapic;
0102 struct pci_dev *dev = NULL;
0103 struct resource *res = NULL, *pci_res = NULL, *crs_res;
0104 char *type = NULL;
0105
0106 if (!acpi_is_ioapic(handle, &type))
0107 return AE_OK;
0108
0109 mutex_lock(&ioapic_list_lock);
0110 list_for_each_entry(ioapic, &ioapic_list, list)
0111 if (ioapic->handle == handle) {
0112 mutex_unlock(&ioapic_list_lock);
0113 return AE_OK;
0114 }
0115
0116 status = acpi_evaluate_integer(handle, "_GSB", NULL, &gsi_base);
0117 if (ACPI_FAILURE(status)) {
0118 acpi_handle_warn(handle, "failed to evaluate _GSB method\n");
0119 goto exit;
0120 }
0121
0122 ioapic = kzalloc(sizeof(*ioapic), GFP_KERNEL);
0123 if (!ioapic) {
0124 pr_err("cannot allocate memory for new IOAPIC\n");
0125 goto exit;
0126 } else {
0127 ioapic->root_handle = (acpi_handle)context;
0128 ioapic->handle = handle;
0129 ioapic->gsi_base = (u32)gsi_base;
0130 INIT_LIST_HEAD(&ioapic->list);
0131 }
0132
0133 if (acpi_ioapic_registered(handle, (u32)gsi_base))
0134 goto done;
0135
0136 dev = acpi_get_pci_dev(handle);
0137 if (dev && pci_resource_len(dev, 0)) {
0138 if (pci_enable_device(dev) < 0)
0139 goto exit_put;
0140 pci_set_master(dev);
0141 if (pci_request_region(dev, 0, type))
0142 goto exit_disable;
0143 pci_res = &dev->resource[0];
0144 ioapic->pdev = dev;
0145 } else {
0146 pci_dev_put(dev);
0147 dev = NULL;
0148 }
0149
0150 crs_res = &ioapic->res;
0151 acpi_walk_resources(handle, METHOD_NAME__CRS, setup_res, crs_res);
0152 crs_res->name = type;
0153 crs_res->flags |= IORESOURCE_BUSY;
0154 if (crs_res->flags == 0) {
0155 acpi_handle_warn(handle, "failed to get resource\n");
0156 goto exit_release;
0157 } else if (insert_resource(&iomem_resource, crs_res)) {
0158 acpi_handle_warn(handle, "failed to insert resource\n");
0159 goto exit_release;
0160 }
0161
0162
0163 res = pci_res;
0164 if (!res || !res->flags)
0165 res = crs_res;
0166
0167 if (acpi_register_ioapic(handle, res->start, (u32)gsi_base)) {
0168 acpi_handle_warn(handle, "failed to register IOAPIC\n");
0169 goto exit_release;
0170 }
0171 done:
0172 list_add(&ioapic->list, &ioapic_list);
0173 mutex_unlock(&ioapic_list_lock);
0174
0175 if (dev)
0176 dev_info(&dev->dev, "%s at %pR, GSI %u\n",
0177 type, res, (u32)gsi_base);
0178 else
0179 acpi_handle_info(handle, "%s at %pR, GSI %u\n",
0180 type, res, (u32)gsi_base);
0181
0182 return AE_OK;
0183
0184 exit_release:
0185 if (dev)
0186 pci_release_region(dev, 0);
0187 if (ioapic->res.flags && ioapic->res.parent)
0188 release_resource(&ioapic->res);
0189 exit_disable:
0190 if (dev)
0191 pci_disable_device(dev);
0192 exit_put:
0193 pci_dev_put(dev);
0194 kfree(ioapic);
0195 exit:
0196 mutex_unlock(&ioapic_list_lock);
0197 *(acpi_status *)rv = AE_ERROR;
0198 return AE_OK;
0199 }
0200
0201 int acpi_ioapic_add(acpi_handle root_handle)
0202 {
0203 acpi_status status, retval = AE_OK;
0204
0205 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, root_handle,
0206 UINT_MAX, handle_ioapic_add, NULL,
0207 root_handle, (void **)&retval);
0208
0209 return ACPI_SUCCESS(status) && ACPI_SUCCESS(retval) ? 0 : -ENODEV;
0210 }
0211
0212 void pci_ioapic_remove(struct acpi_pci_root *root)
0213 {
0214 struct acpi_pci_ioapic *ioapic, *tmp;
0215
0216 mutex_lock(&ioapic_list_lock);
0217 list_for_each_entry_safe(ioapic, tmp, &ioapic_list, list) {
0218 if (root->device->handle != ioapic->root_handle)
0219 continue;
0220 if (ioapic->pdev) {
0221 pci_release_region(ioapic->pdev, 0);
0222 pci_disable_device(ioapic->pdev);
0223 pci_dev_put(ioapic->pdev);
0224 }
0225 }
0226 mutex_unlock(&ioapic_list_lock);
0227 }
0228
0229 int acpi_ioapic_remove(struct acpi_pci_root *root)
0230 {
0231 int retval = 0;
0232 struct acpi_pci_ioapic *ioapic, *tmp;
0233
0234 mutex_lock(&ioapic_list_lock);
0235 list_for_each_entry_safe(ioapic, tmp, &ioapic_list, list) {
0236 if (root->device->handle != ioapic->root_handle)
0237 continue;
0238 if (acpi_unregister_ioapic(ioapic->handle, ioapic->gsi_base))
0239 retval = -EBUSY;
0240 if (ioapic->res.flags && ioapic->res.parent)
0241 release_resource(&ioapic->res);
0242 list_del(&ioapic->list);
0243 kfree(ioapic);
0244 }
0245 mutex_unlock(&ioapic_list_lock);
0246
0247 return retval;
0248 }