]>
Commit | Line | Data |
---|---|---|
13176bbf MW |
1 | /* |
2 | * Support for Core System Resources Table (CSRT) | |
3 | * | |
4 | * Copyright (C) 2013, Intel Corporation | |
5 | * Authors: Mika Westerberg <[email protected]> | |
6 | * Andy Shevchenko <[email protected]> | |
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 | } |