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 if (resource_type(new_res) != resource_type(res) || 89 !resource_union(new_res, res, new_res)) { 90 i++; 91 continue; 92 } 93 94 dev_info(&adev->dev, "%pR expanded due to overlap\n", new_res); 95 /* 96 * Eliminate the previously processed resource that overlapped 97 * with the new one because it is not necessary any more. 98 */ 99 memmove(res, res + 1, (--count - i) * sizeof(*res)); 100 } 101 102 return count; 103 } 104 105 static void acpi_platform_fill_resource(struct acpi_device *adev, 106 const struct resource *src, struct resource *dest) 107 { 108 struct device *parent; 109 110 *dest = *src; 111 112 /* 113 * If the device has parent we need to take its resources into 114 * account as well because this device might consume part of those. 115 */ 116 parent = acpi_get_first_physical_node(acpi_dev_parent(adev)); 117 if (parent && dev_is_pci(parent)) 118 dest->parent = pci_find_resource(to_pci_dev(parent), dest); 119 } 120 121 static unsigned int acpi_platform_resource_count(struct acpi_resource *ares, void *data) 122 { 123 bool *has_resources = data; 124 125 *has_resources = true; 126 127 return AE_CTRL_TERMINATE; 128 } 129 130 /** 131 * acpi_create_platform_device - Create platform device for ACPI device node 132 * @adev: ACPI device node to create a platform device for. 133 * @properties: Optional collection of build-in properties. 134 * 135 * Check if the given @adev can be represented as a platform device and, if 136 * that's the case, create and register a platform device, populate its common 137 * resources and returns a pointer to it. Otherwise, return %NULL. 138 * 139 * Name of the platform device will be the same as @adev's. 140 */ 141 struct platform_device *acpi_create_platform_device(struct acpi_device *adev, 142 const struct property_entry *properties) 143 { 144 struct acpi_device *parent = acpi_dev_parent(adev); 145 struct platform_device *pdev = NULL; 146 struct platform_device_info pdevinfo; 147 const struct acpi_device_id *match; 148 struct resource *resources = NULL; 149 int count = 0; 150 151 /* If the ACPI node already has a physical device attached, skip it. */ 152 if (adev->physical_node_count && !adev->pnp.type.backlight) 153 return NULL; 154 155 match = acpi_match_acpi_device(forbidden_id_list, adev); 156 if (match) { 157 if (match->driver_data & ACPI_ALLOW_WO_RESOURCES) { 158 bool has_resources = false; 159 160 acpi_walk_resources(adev->handle, METHOD_NAME__CRS, 161 acpi_platform_resource_count, &has_resources); 162 if (has_resources) 163 return ERR_PTR(-EINVAL); 164 } else { 165 return ERR_PTR(-EINVAL); 166 } 167 } 168 169 if (adev->device_type == ACPI_BUS_TYPE_DEVICE) { 170 LIST_HEAD(resource_list); 171 172 count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL); 173 if (count < 0) 174 return ERR_PTR(-ENODATA); 175 176 if (count > 0) { 177 struct resource_entry *rentry; 178 179 resources = kzalloc_objs(*resources, count); 180 if (!resources) { 181 acpi_dev_free_resource_list(&resource_list); 182 return ERR_PTR(-ENOMEM); 183 } 184 count = 0; 185 list_for_each_entry(rentry, &resource_list, node) { 186 count = acpi_platform_adjust_resources(adev, 187 rentry->res, 188 resources, 189 count); 190 acpi_platform_fill_resource(adev, rentry->res, 191 &resources[count++]); 192 } 193 acpi_dev_free_resource_list(&resource_list); 194 } 195 } 196 197 memset(&pdevinfo, 0, sizeof(pdevinfo)); 198 /* 199 * If the ACPI node has a parent and that parent has a physical device 200 * attached to it, that physical device should be the parent of the 201 * platform device we are about to create. 202 */ 203 pdevinfo.parent = parent ? acpi_get_first_physical_node(parent) : NULL; 204 pdevinfo.name = dev_name(&adev->dev); 205 pdevinfo.id = PLATFORM_DEVID_NONE; 206 pdevinfo.res = resources; 207 pdevinfo.num_res = count; 208 pdevinfo.fwnode = acpi_fwnode_handle(adev); 209 pdevinfo.properties = properties; 210 211 if (acpi_dma_supported(adev)) 212 pdevinfo.dma_mask = DMA_BIT_MASK(32); 213 else 214 pdevinfo.dma_mask = 0; 215 216 pdev = platform_device_register_full(&pdevinfo); 217 if (IS_ERR(pdev)) 218 dev_err(&adev->dev, "platform device creation failed: %ld\n", 219 PTR_ERR(pdev)); 220 else { 221 set_dev_node(&pdev->dev, acpi_get_node(adev->handle)); 222 dev_dbg(&adev->dev, "created platform device %s\n", 223 dev_name(&pdev->dev)); 224 } 225 226 kfree(resources); 227 228 return pdev; 229 } 230 EXPORT_SYMBOL_GPL(acpi_create_platform_device); 231 232 void __init acpi_platform_init(void) 233 { 234 acpi_reconfig_notifier_register(&acpi_platform_notifier); 235 } 236