]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blobdiff - drivers/acpi/scan.c
Merge tag 'devprop-4.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
[mirror_ubuntu-hirsute-kernel.git] / drivers / acpi / scan.c
index 943536c9a2a89c93424ce402a4d7320302c1f61d..602f8ff212f2c699f1d897a54d7c6a90cbdfe9f3 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/dmi.h>
 #include <linux/nls.h>
 #include <linux/dma-mapping.h>
+#include <linux/platform_data/x86/apple.h>
 
 #include <asm/pgtable.h>
 
@@ -1359,6 +1360,85 @@ enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev)
                return DEV_DMA_NON_COHERENT;
 }
 
+/**
+ * acpi_dma_get_range() - Get device DMA parameters.
+ *
+ * @dev: device to configure
+ * @dma_addr: pointer device DMA address result
+ * @offset: pointer to the DMA offset result
+ * @size: pointer to DMA range size result
+ *
+ * Evaluate DMA regions and return respectively DMA region start, offset
+ * and size in dma_addr, offset and size on parsing success; it does not
+ * update the passed in values on failure.
+ *
+ * Return 0 on success, < 0 on failure.
+ */
+int acpi_dma_get_range(struct device *dev, u64 *dma_addr, u64 *offset,
+                      u64 *size)
+{
+       struct acpi_device *adev;
+       LIST_HEAD(list);
+       struct resource_entry *rentry;
+       int ret;
+       struct device *dma_dev = dev;
+       u64 len, dma_start = U64_MAX, dma_end = 0, dma_offset = 0;
+
+       /*
+        * Walk the device tree chasing an ACPI companion with a _DMA
+        * object while we go. Stop if we find a device with an ACPI
+        * companion containing a _DMA method.
+        */
+       do {
+               adev = ACPI_COMPANION(dma_dev);
+               if (adev && acpi_has_method(adev->handle, METHOD_NAME__DMA))
+                       break;
+
+               dma_dev = dma_dev->parent;
+       } while (dma_dev);
+
+       if (!dma_dev)
+               return -ENODEV;
+
+       if (!acpi_has_method(adev->handle, METHOD_NAME__CRS)) {
+               acpi_handle_warn(adev->handle, "_DMA is valid only if _CRS is present\n");
+               return -EINVAL;
+       }
+
+       ret = acpi_dev_get_dma_resources(adev, &list);
+       if (ret > 0) {
+               list_for_each_entry(rentry, &list, node) {
+                       if (dma_offset && rentry->offset != dma_offset) {
+                               ret = -EINVAL;
+                               dev_warn(dma_dev, "Can't handle multiple windows with different offsets\n");
+                               goto out;
+                       }
+                       dma_offset = rentry->offset;
+
+                       /* Take lower and upper limits */
+                       if (rentry->res->start < dma_start)
+                               dma_start = rentry->res->start;
+                       if (rentry->res->end > dma_end)
+                               dma_end = rentry->res->end;
+               }
+
+               if (dma_start >= dma_end) {
+                       ret = -EINVAL;
+                       dev_dbg(dma_dev, "Invalid DMA regions configuration\n");
+                       goto out;
+               }
+
+               *dma_addr = dma_start - dma_offset;
+               len = dma_end - dma_start;
+               *size = max(len, len + 1);
+               *offset = dma_offset;
+       }
+ out:
+       acpi_dev_free_resource_list(&list);
+
+       return ret >= 0 ? 0 : ret;
+}
+
 /**
  * acpi_dma_configure - Set-up DMA configuration for the device.
  * @dev: The pointer to the device
@@ -1367,20 +1447,16 @@ enum dev_dma_attr acpi_get_dma_attr(struct acpi_device *adev)
 int acpi_dma_configure(struct device *dev, enum dev_dma_attr attr)
 {
        const struct iommu_ops *iommu;
-       u64 size;
+       u64 dma_addr = 0, size = 0;
 
-       iort_set_dma_mask(dev);
+       iort_dma_setup(dev, &dma_addr, &size);
 
        iommu = iort_iommu_configure(dev);
        if (IS_ERR(iommu) && PTR_ERR(iommu) == -EPROBE_DEFER)
                return -EPROBE_DEFER;
 
-       size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1);
-       /*
-        * Assume dma valid range starts at 0 and covers the whole
-        * coherent_dma_mask.
-        */
-       arch_setup_dma_ops(dev, 0, size, iommu, attr == DEV_DMA_COHERENT);
+       arch_setup_dma_ops(dev, dma_addr, size,
+                               iommu, attr == DEV_DMA_COHERENT);
 
        return 0;
 }
@@ -1452,6 +1528,12 @@ static bool acpi_is_spi_i2c_slave(struct acpi_device *device)
        struct list_head resource_list;
        bool is_spi_i2c_slave = false;
 
+       /* Macs use device properties in lieu of _CRS resources */
+       if (x86_apple_machine &&
+           (fwnode_property_present(&device->fwnode, "spiSclkPeriod") ||
+            fwnode_property_present(&device->fwnode, "i2cAddress")))
+               return true;
+
        INIT_LIST_HEAD(&resource_list);
        acpi_dev_get_resources(device, &resource_list, acpi_check_spi_i2c_slave,
                               &is_spi_i2c_slave);
@@ -2057,6 +2139,9 @@ int __init acpi_scan_init(void)
                        acpi_get_spcr_uart_addr();
        }
 
+       acpi_gpe_apply_masked_gpes();
+       acpi_update_all_gpes();
+
        mutex_lock(&acpi_scan_lock);
        /*
         * Enumerate devices in the ACPI namespace.
@@ -2081,10 +2166,6 @@ int __init acpi_scan_init(void)
                }
        }
 
-       acpi_gpe_apply_masked_gpes();
-       acpi_update_all_gpes();
-       acpi_ec_ecdt_start();
-
        acpi_scan_initialized = true;
 
  out: