at v3.9-rc2 159 lines 4.2 kB view raw
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 22ACPI_MODULE_NAME("CSRT"); 23 24static 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 80static int __init 81acpi_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 115fail: 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 */ 130void __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}