diff options
Diffstat (limited to 'drivers/acpi/scan.c')
-rw-r--r-- | drivers/acpi/scan.c | 104 |
1 files changed, 93 insertions, 11 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 70fd5502c284..ac8a8a52ee4a 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/dmi.h> | 13 | #include <linux/dmi.h> |
14 | #include <linux/nls.h> | 14 | #include <linux/nls.h> |
15 | #include <linux/dma-mapping.h> | 15 | #include <linux/dma-mapping.h> |
16 | #include <linux/platform_data/x86/apple.h> | ||
16 | 17 | ||
17 | #include <asm/pgtable.h> | 18 | #include <asm/pgtable.h> |
18 | 19 | ||
@@ -1360,6 +1361,85 @@ enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev) | |||
1360 | } | 1361 | } |
1361 | 1362 | ||
1362 | /** | 1363 | /** |
1364 | * acpi_dma_get_range() - Get device DMA parameters. | ||
1365 | * | ||
1366 | * @dev: device to configure | ||
1367 | * @dma_addr: pointer device DMA address result | ||
1368 | * @offset: pointer to the DMA offset result | ||
1369 | * @size: pointer to DMA range size result | ||
1370 | * | ||
1371 | * Evaluate DMA regions and return respectively DMA region start, offset | ||
1372 | * and size in dma_addr, offset and size on parsing success; it does not | ||
1373 | * update the passed in values on failure. | ||
1374 | * | ||
1375 | * Return 0 on success, < 0 on failure. | ||
1376 | */ | ||
1377 | int acpi_dma_get_range(struct device *dev, u64 *dma_addr, u64 *offset, | ||
1378 | u64 *size) | ||
1379 | { | ||
1380 | struct acpi_device *adev; | ||
1381 | LIST_HEAD(list); | ||
1382 | struct resource_entry *rentry; | ||
1383 | int ret; | ||
1384 | struct device *dma_dev = dev; | ||
1385 | u64 len, dma_start = U64_MAX, dma_end = 0, dma_offset = 0; | ||
1386 | |||
1387 | /* | ||
1388 | * Walk the device tree chasing an ACPI companion with a _DMA | ||
1389 | * object while we go. Stop if we find a device with an ACPI | ||
1390 | * companion containing a _DMA method. | ||
1391 | */ | ||
1392 | do { | ||
1393 | adev = ACPI_COMPANION(dma_dev); | ||
1394 | if (adev && acpi_has_method(adev->handle, METHOD_NAME__DMA)) | ||
1395 | break; | ||
1396 | |||
1397 | dma_dev = dma_dev->parent; | ||
1398 | } while (dma_dev); | ||
1399 | |||
1400 | if (!dma_dev) | ||
1401 | return -ENODEV; | ||
1402 | |||
1403 | if (!acpi_has_method(adev->handle, METHOD_NAME__CRS)) { | ||
1404 | acpi_handle_warn(adev->handle, "_DMA is valid only if _CRS is present\n"); | ||
1405 | return -EINVAL; | ||
1406 | } | ||
1407 | |||
1408 | ret = acpi_dev_get_dma_resources(adev, &list); | ||
1409 | if (ret > 0) { | ||
1410 | list_for_each_entry(rentry, &list, node) { | ||
1411 | if (dma_offset && rentry->offset != dma_offset) { | ||
1412 | ret = -EINVAL; | ||
1413 | dev_warn(dma_dev, "Can't handle multiple windows with different offsets\n"); | ||
1414 | goto out; | ||
1415 | } | ||
1416 | dma_offset = rentry->offset; | ||
1417 | |||
1418 | /* Take lower and upper limits */ | ||
1419 | if (rentry->res->start < dma_start) | ||
1420 | dma_start = rentry->res->start; | ||
1421 | if (rentry->res->end > dma_end) | ||
1422 | dma_end = rentry->res->end; | ||
1423 | } | ||
1424 | |||
1425 | if (dma_start >= dma_end) { | ||
1426 | ret = -EINVAL; | ||
1427 | dev_dbg(dma_dev, "Invalid DMA regions configuration\n"); | ||
1428 | goto out; | ||
1429 | } | ||
1430 | |||
1431 | *dma_addr = dma_start - dma_offset; | ||
1432 | len = dma_end - dma_start; | ||
1433 | *size = max(len, len + 1); | ||
1434 | *offset = dma_offset; | ||
1435 | } | ||
1436 | out: | ||
1437 | acpi_dev_free_resource_list(&list); | ||
1438 | |||
1439 | return ret >= 0 ? 0 : ret; | ||
1440 | } | ||
1441 | |||
1442 | /** | ||
1363 | * acpi_dma_configure - Set-up DMA configuration for the device. | 1443 | * acpi_dma_configure - Set-up DMA configuration for the device. |
1364 | * @dev: The pointer to the device | 1444 | * @dev: The pointer to the device |
1365 | * @attr: device dma attributes | 1445 | * @attr: device dma attributes |
@@ -1367,20 +1447,16 @@ enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev) | |||
1367 | int acpi_dma_configure(struct device *dev, enum dev_dma_attr attr) | 1447 | int acpi_dma_configure(struct device *dev, enum dev_dma_attr attr) |
1368 | { | 1448 | { |
1369 | const struct iommu_ops *iommu; | 1449 | const struct iommu_ops *iommu; |
1370 | u64 size; | 1450 | u64 dma_addr = 0, size = 0; |
1371 | 1451 | ||
1372 | iort_set_dma_mask(dev); | 1452 | iort_dma_setup(dev, &dma_addr, &size); |
1373 | 1453 | ||
1374 | iommu = iort_iommu_configure(dev); | 1454 | iommu = iort_iommu_configure(dev); |
1375 | if (IS_ERR(iommu) && PTR_ERR(iommu) == -EPROBE_DEFER) | 1455 | if (IS_ERR(iommu) && PTR_ERR(iommu) == -EPROBE_DEFER) |
1376 | return -EPROBE_DEFER; | 1456 | return -EPROBE_DEFER; |
1377 | 1457 | ||
1378 | size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1); | 1458 | arch_setup_dma_ops(dev, dma_addr, size, |
1379 | /* | 1459 | iommu, attr == DEV_DMA_COHERENT); |
1380 | * Assume dma valid range starts at 0 and covers the whole | ||
1381 | * coherent_dma_mask. | ||
1382 | */ | ||
1383 | arch_setup_dma_ops(dev, 0, size, iommu, attr == DEV_DMA_COHERENT); | ||
1384 | 1460 | ||
1385 | return 0; | 1461 | return 0; |
1386 | } | 1462 | } |
@@ -1452,6 +1528,12 @@ static bool acpi_is_spi_i2c_slave(struct acpi_device *device) | |||
1452 | struct list_head resource_list; | 1528 | struct list_head resource_list; |
1453 | bool is_spi_i2c_slave = false; | 1529 | bool is_spi_i2c_slave = false; |
1454 | 1530 | ||
1531 | /* Macs use device properties in lieu of _CRS resources */ | ||
1532 | if (x86_apple_machine && | ||
1533 | (fwnode_property_present(&device->fwnode, "spiSclkPeriod") || | ||
1534 | fwnode_property_present(&device->fwnode, "i2cAddress"))) | ||
1535 | return true; | ||
1536 | |||
1455 | INIT_LIST_HEAD(&resource_list); | 1537 | INIT_LIST_HEAD(&resource_list); |
1456 | acpi_dev_get_resources(device, &resource_list, acpi_check_spi_i2c_slave, | 1538 | acpi_dev_get_resources(device, &resource_list, acpi_check_spi_i2c_slave, |
1457 | &is_spi_i2c_slave); | 1539 | &is_spi_i2c_slave); |
@@ -2058,6 +2140,9 @@ int __init acpi_scan_init(void) | |||
2058 | acpi_get_spcr_uart_addr(); | 2140 | acpi_get_spcr_uart_addr(); |
2059 | } | 2141 | } |
2060 | 2142 | ||
2143 | acpi_gpe_apply_masked_gpes(); | ||
2144 | acpi_update_all_gpes(); | ||
2145 | |||
2061 | mutex_lock(&acpi_scan_lock); | 2146 | mutex_lock(&acpi_scan_lock); |
2062 | /* | 2147 | /* |
2063 | * Enumerate devices in the ACPI namespace. | 2148 | * Enumerate devices in the ACPI namespace. |
@@ -2082,9 +2167,6 @@ int __init acpi_scan_init(void) | |||
2082 | } | 2167 | } |
2083 | } | 2168 | } |
2084 | 2169 | ||
2085 | acpi_gpe_apply_masked_gpes(); | ||
2086 | acpi_update_all_gpes(); | ||
2087 | |||
2088 | acpi_scan_initialized = true; | 2170 | acpi_scan_initialized = true; |
2089 | 2171 | ||
2090 | out: | 2172 | out: |