1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * ACPI support for platform bus type. 4 * 5 * Copyright (C) 2012, Intel Corporation 6 * Authors: Mika Westerberg <mika.westerberg@linux.intel.com> 7 * Mathias Nyman <mathias.nyman@linux.intel.com> 8 * Rafael J. Wysocki <rafael.j.wysocki@intel.com> 9 */ 10 11 #include <linux/acpi.h> 12 #include <linux/bits.h> 13 #include <linux/device.h> 14 #include <linux/err.h> 15 #include <linux/ioport.h> 16 #include <linux/kernel.h> 17 #include <linux/module.h> 18 #include <linux/dma-mapping.h> 19 #include <linux/pci.h> 20 #include <linux/platform_device.h> 21 22 #include "internal.h" 23 24 /* Exclude devices that have no _CRS resources provided */ 25 #define ACPI_ALLOW_WO_RESOURCES BIT(0) 26 27 static const struct acpi_device_id forbidden_id_list[] = { 28 {"ACPI0009", 0}, /* IOxAPIC */ 29 {"ACPI000A", 0}, /* IOAPIC */ 30 {"PNP0000", 0}, /* PIC */ 31 {"PNP0100", 0}, /* Timer */ 32 {"PNP0200", 0}, /* AT DMA Controller */ 33 {ACPI_SMBUS_MS_HID, ACPI_ALLOW_WO_RESOURCES}, /* ACPI SMBUS virtual device */ 34 { } 35 }; 36 37 static struct platform_device *acpi_platform_device_find_by_companion(struct acpi_device *adev) 38 { 39 struct device *dev; 40 41 dev = bus_find_device_by_acpi_dev(&platform_bus_type, adev); 42 return dev ? to_platform_device(dev) : NULL; 43 } 44 45 static int acpi_platform_device_remove_notify(struct notifier_block *nb, 46 unsigned long value, void *arg) 47 { 48 struct acpi_device *adev = arg; 49 struct platform_device *pdev; 50 51 switch (value) { 52 case ACPI_RECONFIG_DEVICE_ADD: 53 /* Nothing to do here */ 54 break; 55 case ACPI_RECONFIG_DEVICE_REMOVE: 56 if (!acpi_device_enumerated(adev)) 57 break; 58 59 pdev = acpi_platform_device_find_by_companion(adev); 60 if (!pdev) 61 break; 62 63 platform_device_unregister(pdev); 64 put_device(&pdev->dev); 65 break; 66 } 67 68 return NOTIFY_OK; 69 } 70 71 static struct notifier_block acpi_platform_notifier = { 72 .notifier_call = acpi_platform_device_remove_notify, 73 }; 74 75 static unsigned int acpi_platform_adjust_resources(struct acpi_device *adev, 76 struct resource *new_res, 77 struct resource *resources, 78 unsigned int count) 79 { 80 unsigned int i; 81 82 if (!(new_res->flags & (IORESOURCE_IO | IORESOURCE_MEM))) 83 return count; 84 85 for (i = 0; i < count; ) { 86 struct resource *res = &resources[i]; 87 88 /* 89 * Look for overlaps of resources of the same type that would 90 * cause resource insertion to fail down the road. 91 */ 92 if (__resource_contains_unbound(res, new_res) || 93 __resource_contains_unbound(new_res, res) || 94 resource_type(new_res) != resource_type(res) || 95 !resource_union(new_res, res, new_res)) { 96 i++; 97 continue; 98 } 99 100 dev_info(&adev->dev, "%pR expanded due to overlap\n", new_res); 101 /* 102 * Eliminate the previously processed resource that overlapped 103 * with the new one because it is not necessary any more. 104 */ 105 memmove(res, res + 1, (--count - i) * sizeof(*res)); 106 } 107 108 return count; 109 } 110 111 static void acpi_platform_fill_resource(struct device *parent, 112 const struct resource *src, 113 struct resource *dest) 114 { 115 *dest = *src; 116 /* 117 * If the device has parent we need to take its resources into 118 * account as well because this device might consume part of those. 119 */ 120 if (parent && dev_is_pci(parent)) 121 dest->parent = pci_find_resource(to_pci_dev(parent), dest); 122 } 123 124 static unsigned int acpi_platform_resource_count(struct acpi_resource *ares, void *data) 125 { 126 bool *has_resources = data; 127 128 *has_resources = true; 129 130 return AE_CTRL_TERMINATE; 131 } 132 133 /** 134 * acpi_create_platform_device - Create platform device for ACPI device node 135 * @adev: ACPI device node to create a platform device for. 136 * @properties: Optional collection of build-in properties. 137 * 138 * Check if the given @adev can be represented as a platform device and, if 139 * that's the case, create and register a platform device, populate its common 140 * resources and returns a pointer to it. Otherwise, return %NULL. 141 * 142 * Name of the platform device will be the same as @adev's. 143 */ 144 struct platform_device *acpi_create_platform_device(struct acpi_device *adev, 145 const struct property_entry *properties) 146 { 147 struct acpi_device *p = acpi_dev_parent(adev); 148 struct device *parent __free(put_device) = acpi_bus_get_primary_device(p); 149 struct platform_device *pdev = NULL; 150 struct platform_device_info pdevinfo; 151 const struct acpi_device_id *match; 152 struct resource *resources = NULL; 153 int count = 0; 154 155 /* If the ACPI node already has a physical device attached, skip it. */ 156 if (adev->physical_node_count && !adev->pnp.type.backlight) 157 return NULL; 158 159 match = acpi_match_acpi_device(forbidden_id_list, adev); 160 if (match) { 161 if (match->driver_data & ACPI_ALLOW_WO_RESOURCES) { 162 bool has_resources = false; 163 164 acpi_walk_resources(adev->handle, METHOD_NAME__CRS, 165 acpi_platform_resource_count, &has_resources); 166 if (has_resources) 167 return ERR_PTR(-EINVAL); 168 } else { 169 return ERR_PTR(-EINVAL); 170 } 171 } 172 173 if (adev->device_type == ACPI_BUS_TYPE_DEVICE) { 174 LIST_HEAD(resource_list); 175 176 count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL); 177 if (count < 0) 178 return ERR_PTR(-ENODATA); 179 180 if (count > 0) { 181 struct resource_entry *rentry; 182 183 resources = kzalloc_objs(*resources, count); 184 if (!resources) { 185 acpi_dev_free_resource_list(&resource_list); 186 return ERR_PTR(-ENOMEM); 187 } 188 count = 0; 189 list_for_each_entry(rentry, &resource_list, node) { 190 count = acpi_platform_adjust_resources(adev, 191 rentry->res, 192 resources, 193 count); 194 acpi_platform_fill_resource(parent, rentry->res, 195 &resources[count++]); 196 } 197 acpi_dev_free_resource_list(&resource_list); 198 } 199 } 200 201 memset(&pdevinfo, 0, sizeof(pdevinfo)); 202 /* 203 * If the ACPI node has a parent and that parent has a physical device 204 * attached to it, that physical device should be the parent of the 205 * platform device we are about to create. 206 */ 207 pdevinfo.parent = parent; 208 pdevinfo.name = dev_name(&adev->dev); 209 pdevinfo.id = PLATFORM_DEVID_NONE; 210 pdevinfo.res = resources; 211 pdevinfo.num_res = count; 212 pdevinfo.fwnode = acpi_fwnode_handle(adev); 213 pdevinfo.properties = properties; 214 215 if (acpi_dma_supported(adev)) 216 pdevinfo.dma_mask = DMA_BIT_MASK(32); 217 else 218 pdevinfo.dma_mask = 0; 219 220 pdev = platform_device_register_full(&pdevinfo); 221 if (IS_ERR(pdev)) 222 dev_err(&adev->dev, "platform device creation failed: %ld\n", 223 PTR_ERR(pdev)); 224 else { 225 set_dev_node(&pdev->dev, acpi_get_node(adev->handle)); 226 dev_dbg(&adev->dev, "created platform device %s\n", 227 dev_name(&pdev->dev)); 228 } 229 230 kfree(resources); 231 232 return pdev; 233 } 234 EXPORT_SYMBOL_GPL(acpi_create_platform_device); 235 236 void __init acpi_platform_init(void) 237 { 238 acpi_reconfig_notifier_register(&acpi_platform_notifier); 239 } 240