Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

dma: acpi-dma: parse CSRT to extract additional resources

Since we have CSRT only to get additional DMA controller resources, let's get
rid of drivers/acpi/csrt.c and move its logic inside ACPI DMA helpers code.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>

authored by

Andy Shevchenko and committed by
Vinod Koul
ee8209fd f722406f

+173 -165
-1
drivers/acpi/Makefile
··· 38 38 acpi-y += ec.o 39 39 acpi-$(CONFIG_ACPI_DOCK) += dock.o 40 40 acpi-y += pci_root.o pci_link.o pci_irq.o 41 - acpi-y += csrt.o 42 41 acpi-$(CONFIG_X86_INTEL_LPSS) += acpi_lpss.o 43 42 acpi-y += acpi_platform.o 44 43 acpi-y += power.o
-159
drivers/acpi/csrt.c
··· 1 - /* 2 - * Support for Core System Resources Table (CSRT) 3 - * 4 - * Copyright (C) 2013, Intel Corporation 5 - * Authors: Mika Westerberg <mika.westerberg@linux.intel.com> 6 - * Andy Shevchenko <andriy.shevchenko@linux.intel.com> 7 - * 8 - * This program is free software; you can redistribute it and/or modify 9 - * it under the terms of the GNU General Public License version 2 as 10 - * published by the Free Software Foundation. 11 - */ 12 - 13 - #define pr_fmt(fmt) "ACPI: CSRT: " fmt 14 - 15 - #include <linux/acpi.h> 16 - #include <linux/device.h> 17 - #include <linux/kernel.h> 18 - #include <linux/module.h> 19 - #include <linux/platform_device.h> 20 - #include <linux/sizes.h> 21 - 22 - ACPI_MODULE_NAME("CSRT"); 23 - 24 - static int __init acpi_csrt_parse_shared_info(struct platform_device *pdev, 25 - const struct acpi_csrt_group *grp) 26 - { 27 - const struct acpi_csrt_shared_info *si; 28 - struct resource res[3]; 29 - size_t nres; 30 - int ret; 31 - 32 - memset(res, 0, sizeof(res)); 33 - nres = 0; 34 - 35 - si = (const struct acpi_csrt_shared_info *)&grp[1]; 36 - /* 37 - * The peripherals that are listed on CSRT typically support only 38 - * 32-bit addresses so we only use the low part of MMIO base for 39 - * now. 40 - */ 41 - if (!si->mmio_base_high && si->mmio_base_low) { 42 - /* 43 - * There is no size of the memory resource in shared_info 44 - * so we assume that it is 4k here. 45 - */ 46 - res[nres].start = si->mmio_base_low; 47 - res[nres].end = res[0].start + SZ_4K - 1; 48 - res[nres++].flags = IORESOURCE_MEM; 49 - } 50 - 51 - if (si->gsi_interrupt) { 52 - int irq = acpi_register_gsi(NULL, si->gsi_interrupt, 53 - si->interrupt_mode, 54 - si->interrupt_polarity); 55 - res[nres].start = irq; 56 - res[nres].end = irq; 57 - res[nres++].flags = IORESOURCE_IRQ; 58 - } 59 - 60 - if (si->base_request_line || si->num_handshake_signals) { 61 - /* 62 - * We pass the driver a DMA resource describing the range 63 - * of request lines the device supports. 64 - */ 65 - res[nres].start = si->base_request_line; 66 - res[nres].end = res[nres].start + si->num_handshake_signals - 1; 67 - res[nres++].flags = IORESOURCE_DMA; 68 - } 69 - 70 - ret = platform_device_add_resources(pdev, res, nres); 71 - if (ret) { 72 - if (si->gsi_interrupt) 73 - acpi_unregister_gsi(si->gsi_interrupt); 74 - return ret; 75 - } 76 - 77 - return 0; 78 - } 79 - 80 - static int __init 81 - acpi_csrt_parse_resource_group(const struct acpi_csrt_group *grp) 82 - { 83 - struct platform_device *pdev; 84 - char vendor[5], name[16]; 85 - int ret, i; 86 - 87 - vendor[0] = grp->vendor_id; 88 - vendor[1] = grp->vendor_id >> 8; 89 - vendor[2] = grp->vendor_id >> 16; 90 - vendor[3] = grp->vendor_id >> 24; 91 - vendor[4] = '\0'; 92 - 93 - if (grp->shared_info_length != sizeof(struct acpi_csrt_shared_info)) 94 - return -ENODEV; 95 - 96 - snprintf(name, sizeof(name), "%s%04X", vendor, grp->device_id); 97 - pdev = platform_device_alloc(name, PLATFORM_DEVID_AUTO); 98 - if (!pdev) 99 - return -ENOMEM; 100 - 101 - /* Add resources based on the shared info */ 102 - ret = acpi_csrt_parse_shared_info(pdev, grp); 103 - if (ret) 104 - goto fail; 105 - 106 - ret = platform_device_add(pdev); 107 - if (ret) 108 - goto fail; 109 - 110 - for (i = 0; i < pdev->num_resources; i++) 111 - dev_dbg(&pdev->dev, "%pR\n", &pdev->resource[i]); 112 - 113 - return 0; 114 - 115 - fail: 116 - platform_device_put(pdev); 117 - return ret; 118 - } 119 - 120 - /* 121 - * CSRT or Core System Resources Table is a proprietary ACPI table 122 - * introduced by Microsoft. This table can contain devices that are not in 123 - * the system DSDT table. In particular DMA controllers might be described 124 - * here. 125 - * 126 - * We present these devices as normal platform devices that don't have ACPI 127 - * IDs or handle. The platform device name will be something like 128 - * <VENDOR><DEVID>.<n>.auto for example: INTL9C06.0.auto. 129 - */ 130 - void __init acpi_csrt_init(void) 131 - { 132 - struct acpi_csrt_group *grp, *end; 133 - struct acpi_table_csrt *csrt; 134 - acpi_status status; 135 - int ret; 136 - 137 - status = acpi_get_table(ACPI_SIG_CSRT, 0, 138 - (struct acpi_table_header **)&csrt); 139 - if (ACPI_FAILURE(status)) { 140 - if (status != AE_NOT_FOUND) 141 - pr_warn("failed to get the CSRT table\n"); 142 - return; 143 - } 144 - 145 - pr_debug("parsing CSRT table for devices\n"); 146 - 147 - grp = (struct acpi_csrt_group *)(csrt + 1); 148 - end = (struct acpi_csrt_group *)((void *)csrt + csrt->header.length); 149 - 150 - while (grp < end) { 151 - ret = acpi_csrt_parse_resource_group(grp); 152 - if (ret) { 153 - pr_warn("error in parsing resource group: %d\n", ret); 154 - return; 155 - } 156 - 157 - grp = (struct acpi_csrt_group *)((void *)grp + grp->length); 158 - } 159 - }
-1
drivers/acpi/internal.h
··· 35 35 void acpi_pci_root_hp_init(void); 36 36 void acpi_platform_init(void); 37 37 int acpi_sysfs_init(void); 38 - void acpi_csrt_init(void); 39 38 #ifdef CONFIG_ACPI_CONTAINER 40 39 void acpi_container_init(void); 41 40 #else
-1
drivers/acpi/scan.c
··· 2042 2042 acpi_pci_link_init(); 2043 2043 acpi_platform_init(); 2044 2044 acpi_lpss_init(); 2045 - acpi_csrt_init(); 2046 2045 acpi_container_init(); 2047 2046 acpi_memory_hotplug_init(); 2048 2047
+169 -3
drivers/dma/acpi-dma.c
··· 4 4 * Based on of-dma.c 5 5 * 6 6 * Copyright (C) 2013, Intel Corporation 7 - * Author: Andy Shevchenko <andriy.shevchenko@linux.intel.com> 7 + * Authors: Andy Shevchenko <andriy.shevchenko@linux.intel.com> 8 + * Mika Westerberg <mika.westerberg@linux.intel.com> 8 9 * 9 10 * This program is free software; you can redistribute it and/or modify 10 11 * it under the terms of the GNU General Public License version 2 as ··· 17 16 #include <linux/list.h> 18 17 #include <linux/mutex.h> 19 18 #include <linux/slab.h> 19 + #include <linux/ioport.h> 20 20 #include <linux/acpi.h> 21 21 #include <linux/acpi_dma.h> 22 22 23 23 static LIST_HEAD(acpi_dma_list); 24 24 static DEFINE_MUTEX(acpi_dma_lock); 25 + 26 + /** 27 + * acpi_dma_parse_resource_group - match device and parse resource group 28 + * @grp: CSRT resource group 29 + * @adev: ACPI device to match with 30 + * @adma: struct acpi_dma of the given DMA controller 31 + * 32 + * Returns 1 on success, 0 when no information is available, or appropriate 33 + * errno value on error. 34 + * 35 + * In order to match a device from DSDT table to the corresponding CSRT device 36 + * we use MMIO address and IRQ. 37 + */ 38 + static int acpi_dma_parse_resource_group(const struct acpi_csrt_group *grp, 39 + struct acpi_device *adev, struct acpi_dma *adma) 40 + { 41 + const struct acpi_csrt_shared_info *si; 42 + struct list_head resource_list; 43 + struct resource_list_entry *rentry; 44 + resource_size_t mem = 0, irq = 0; 45 + u32 vendor_id; 46 + int ret; 47 + 48 + if (grp->shared_info_length != sizeof(struct acpi_csrt_shared_info)) 49 + return -ENODEV; 50 + 51 + INIT_LIST_HEAD(&resource_list); 52 + ret = acpi_dev_get_resources(adev, &resource_list, NULL, NULL); 53 + if (ret <= 0) 54 + return 0; 55 + 56 + list_for_each_entry(rentry, &resource_list, node) { 57 + if (resource_type(&rentry->res) == IORESOURCE_MEM) 58 + mem = rentry->res.start; 59 + else if (resource_type(&rentry->res) == IORESOURCE_IRQ) 60 + irq = rentry->res.start; 61 + } 62 + 63 + acpi_dev_free_resource_list(&resource_list); 64 + 65 + /* Consider initial zero values as resource not found */ 66 + if (mem == 0 && irq == 0) 67 + return 0; 68 + 69 + si = (const struct acpi_csrt_shared_info *)&grp[1]; 70 + 71 + /* Match device by MMIO and IRQ */ 72 + if (si->mmio_base_low != mem || si->gsi_interrupt != irq) 73 + return 0; 74 + 75 + vendor_id = le32_to_cpu(grp->vendor_id); 76 + dev_dbg(&adev->dev, "matches with %.4s%04X (rev %u)\n", 77 + (char *)&vendor_id, grp->device_id, grp->revision); 78 + 79 + /* Check if the request line range is available */ 80 + if (si->base_request_line == 0 && si->num_handshake_signals == 0) 81 + return 0; 82 + 83 + adma->base_request_line = si->base_request_line; 84 + adma->end_request_line = si->base_request_line + 85 + si->num_handshake_signals - 1; 86 + 87 + dev_dbg(&adev->dev, "request line base: 0x%04x end: 0x%04x\n", 88 + adma->base_request_line, adma->end_request_line); 89 + 90 + return 1; 91 + } 92 + 93 + /** 94 + * acpi_dma_parse_csrt - parse CSRT to exctract additional DMA resources 95 + * @adev: ACPI device to match with 96 + * @adma: struct acpi_dma of the given DMA controller 97 + * 98 + * CSRT or Core System Resources Table is a proprietary ACPI table 99 + * introduced by Microsoft. This table can contain devices that are not in 100 + * the system DSDT table. In particular DMA controllers might be described 101 + * here. 102 + * 103 + * We are using this table to get the request line range of the specific DMA 104 + * controller to be used later. 105 + * 106 + */ 107 + static void acpi_dma_parse_csrt(struct acpi_device *adev, struct acpi_dma *adma) 108 + { 109 + struct acpi_csrt_group *grp, *end; 110 + struct acpi_table_csrt *csrt; 111 + acpi_status status; 112 + int ret; 113 + 114 + status = acpi_get_table(ACPI_SIG_CSRT, 0, 115 + (struct acpi_table_header **)&csrt); 116 + if (ACPI_FAILURE(status)) { 117 + if (status != AE_NOT_FOUND) 118 + dev_warn(&adev->dev, "failed to get the CSRT table\n"); 119 + return; 120 + } 121 + 122 + grp = (struct acpi_csrt_group *)(csrt + 1); 123 + end = (struct acpi_csrt_group *)((void *)csrt + csrt->header.length); 124 + 125 + while (grp < end) { 126 + ret = acpi_dma_parse_resource_group(grp, adev, adma); 127 + if (ret < 0) { 128 + dev_warn(&adev->dev, 129 + "error in parsing resource group\n"); 130 + return; 131 + } 132 + 133 + grp = (struct acpi_csrt_group *)((void *)grp + grp->length); 134 + } 135 + } 25 136 26 137 /** 27 138 * acpi_dma_controller_register - Register a DMA controller to ACPI DMA helpers ··· 173 60 adma->dev = dev; 174 61 adma->acpi_dma_xlate = acpi_dma_xlate; 175 62 adma->data = data; 63 + 64 + acpi_dma_parse_csrt(adev, adma); 176 65 177 66 /* Now queue acpi_dma controller structure in list */ 178 67 mutex_lock(&acpi_dma_lock); ··· 264 149 } 265 150 EXPORT_SYMBOL_GPL(devm_acpi_dma_controller_free); 266 151 152 + /** 153 + * acpi_dma_update_dma_spec - prepare dma specifier to pass to translation function 154 + * @adma: struct acpi_dma of DMA controller 155 + * @dma_spec: dma specifier to update 156 + * 157 + * Returns 0, if no information is avaiable, -1 on mismatch, and 1 otherwise. 158 + * 159 + * Accordingly to ACPI 5.0 Specification Table 6-170 "Fixed DMA Resource 160 + * Descriptor": 161 + * DMA Request Line bits is a platform-relative number uniquely 162 + * identifying the request line assigned. Request line-to-Controller 163 + * mapping is done in a controller-specific OS driver. 164 + * That's why we can safely adjust slave_id when the appropriate controller is 165 + * found. 166 + */ 167 + static int acpi_dma_update_dma_spec(struct acpi_dma *adma, 168 + struct acpi_dma_spec *dma_spec) 169 + { 170 + /* Set link to the DMA controller device */ 171 + dma_spec->dev = adma->dev; 172 + 173 + /* Check if the request line range is available */ 174 + if (adma->base_request_line == 0 && adma->end_request_line == 0) 175 + return 0; 176 + 177 + /* Check if slave_id falls to the range */ 178 + if (dma_spec->slave_id < adma->base_request_line || 179 + dma_spec->slave_id > adma->end_request_line) 180 + return -1; 181 + 182 + /* 183 + * Here we adjust slave_id. It should be a relative number to the base 184 + * request line. 185 + */ 186 + dma_spec->slave_id -= adma->base_request_line; 187 + 188 + return 1; 189 + } 190 + 267 191 struct acpi_dma_parser_data { 268 192 struct acpi_dma_spec dma_spec; 269 193 size_t index; ··· 347 193 struct acpi_device *adev; 348 194 struct acpi_dma *adma; 349 195 struct dma_chan *chan = NULL; 196 + int found; 350 197 351 198 /* Check if the device was enumerated by ACPI */ 352 199 if (!dev || !ACPI_HANDLE(dev)) ··· 374 219 mutex_lock(&acpi_dma_lock); 375 220 376 221 list_for_each_entry(adma, &acpi_dma_list, dma_controllers) { 377 - dma_spec->dev = adma->dev; 222 + /* 223 + * We are not going to call translation function if slave_id 224 + * doesn't fall to the request range. 225 + */ 226 + found = acpi_dma_update_dma_spec(adma, dma_spec); 227 + if (found < 0) 228 + continue; 378 229 chan = adma->acpi_dma_xlate(dma_spec, adma); 379 - if (chan) 230 + /* 231 + * Try to get a channel only from the DMA controller that 232 + * matches the slave_id. See acpi_dma_update_dma_spec() 233 + * description for the details. 234 + */ 235 + if (found > 0 || chan) 380 236 break; 381 237 } 382 238
+4
include/linux/acpi_dma.h
··· 37 37 * @dev: struct device of this controller 38 38 * @acpi_dma_xlate: callback function to find a suitable channel 39 39 * @data: private data used by a callback function 40 + * @base_request_line: first supported request line (CSRT) 41 + * @end_request_line: last supported request line (CSRT) 40 42 */ 41 43 struct acpi_dma { 42 44 struct list_head dma_controllers; ··· 46 44 struct dma_chan *(*acpi_dma_xlate) 47 45 (struct acpi_dma_spec *, struct acpi_dma *); 48 46 void *data; 47 + unsigned short base_request_line; 48 + unsigned short end_request_line; 49 49 }; 50 50 51 51 /* Used with acpi_dma_simple_xlate() */