diff options
Diffstat (limited to 'drivers/acpi/acpica/hwxface.c')
-rw-r--r-- | drivers/acpi/acpica/hwxface.c | 181 |
1 files changed, 113 insertions, 68 deletions
diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c index 9829979f2bdd..647c7b6e6756 100644 --- a/drivers/acpi/acpica/hwxface.c +++ b/drivers/acpi/acpica/hwxface.c | |||
@@ -78,9 +78,22 @@ acpi_status acpi_reset(void) | |||
78 | return_ACPI_STATUS(AE_NOT_EXIST); | 78 | return_ACPI_STATUS(AE_NOT_EXIST); |
79 | } | 79 | } |
80 | 80 | ||
81 | /* Write the reset value to the reset register */ | 81 | if (reset_reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) { |
82 | /* | ||
83 | * For I/O space, write directly to the OSL. This bypasses the port | ||
84 | * validation mechanism, which may block a valid write to the reset | ||
85 | * register. | ||
86 | */ | ||
87 | status = | ||
88 | acpi_os_write_port((acpi_io_address) reset_reg->address, | ||
89 | acpi_gbl_FADT.reset_value, | ||
90 | reset_reg->bit_width); | ||
91 | } else { | ||
92 | /* Write the reset value to the reset register */ | ||
93 | |||
94 | status = acpi_hw_write(acpi_gbl_FADT.reset_value, reset_reg); | ||
95 | } | ||
82 | 96 | ||
83 | status = acpi_write(acpi_gbl_FADT.reset_value, reset_reg); | ||
84 | return_ACPI_STATUS(status); | 97 | return_ACPI_STATUS(status); |
85 | } | 98 | } |
86 | 99 | ||
@@ -97,67 +110,92 @@ ACPI_EXPORT_SYMBOL(acpi_reset) | |||
97 | * | 110 | * |
98 | * DESCRIPTION: Read from either memory or IO space. | 111 | * DESCRIPTION: Read from either memory or IO space. |
99 | * | 112 | * |
113 | * LIMITATIONS: <These limitations also apply to acpi_write> | ||
114 | * bit_width must be exactly 8, 16, 32, or 64. | ||
115 | * space_iD must be system_memory or system_iO. | ||
116 | * bit_offset and access_width are currently ignored, as there has | ||
117 | * not been a need to implement these. | ||
118 | * | ||
100 | ******************************************************************************/ | 119 | ******************************************************************************/ |
101 | acpi_status acpi_read(u32 *value, struct acpi_generic_address *reg) | 120 | acpi_status acpi_read(u64 *return_value, struct acpi_generic_address *reg) |
102 | { | 121 | { |
122 | u32 value; | ||
103 | u32 width; | 123 | u32 width; |
104 | u64 address; | 124 | u64 address; |
105 | acpi_status status; | 125 | acpi_status status; |
106 | 126 | ||
107 | ACPI_FUNCTION_NAME(acpi_read); | 127 | ACPI_FUNCTION_NAME(acpi_read); |
108 | 128 | ||
109 | /* | 129 | if (!return_value) { |
110 | * Must have a valid pointer to a GAS structure, and a non-zero address | ||
111 | * within. | ||
112 | */ | ||
113 | if (!reg) { | ||
114 | return (AE_BAD_PARAMETER); | 130 | return (AE_BAD_PARAMETER); |
115 | } | 131 | } |
116 | 132 | ||
117 | /* Get a local copy of the address. Handles possible alignment issues */ | 133 | /* Validate contents of the GAS register. Allow 64-bit transfers */ |
118 | 134 | ||
119 | ACPI_MOVE_64_TO_64(&address, ®->address); | 135 | status = acpi_hw_validate_register(reg, 64, &address); |
120 | if (!address) { | 136 | if (ACPI_FAILURE(status)) { |
121 | return (AE_BAD_ADDRESS); | 137 | return (status); |
122 | } | 138 | } |
123 | 139 | ||
124 | /* Supported widths are 8/16/32 */ | ||
125 | |||
126 | width = reg->bit_width; | 140 | width = reg->bit_width; |
127 | if ((width != 8) && (width != 16) && (width != 32)) { | 141 | if (width == 64) { |
128 | return (AE_SUPPORT); | 142 | width = 32; /* Break into two 32-bit transfers */ |
129 | } | 143 | } |
130 | 144 | ||
131 | /* Initialize entire 32-bit return value to zero */ | 145 | /* Initialize entire 64-bit return value to zero */ |
132 | 146 | ||
133 | *value = 0; | 147 | *return_value = 0; |
148 | value = 0; | ||
134 | 149 | ||
135 | /* | 150 | /* |
136 | * Two address spaces supported: Memory or IO. PCI_Config is | 151 | * Two address spaces supported: Memory or IO. PCI_Config is |
137 | * not supported here because the GAS structure is insufficient | 152 | * not supported here because the GAS structure is insufficient |
138 | */ | 153 | */ |
139 | switch (reg->space_id) { | 154 | if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { |
140 | case ACPI_ADR_SPACE_SYSTEM_MEMORY: | 155 | status = acpi_os_read_memory((acpi_physical_address) |
156 | address, &value, width); | ||
157 | if (ACPI_FAILURE(status)) { | ||
158 | return (status); | ||
159 | } | ||
160 | *return_value = value; | ||
141 | 161 | ||
142 | status = acpi_os_read_memory((acpi_physical_address) address, | 162 | if (reg->bit_width == 64) { |
143 | value, width); | ||
144 | break; | ||
145 | 163 | ||
146 | case ACPI_ADR_SPACE_SYSTEM_IO: | 164 | /* Read the top 32 bits */ |
147 | 165 | ||
148 | status = | 166 | status = acpi_os_read_memory((acpi_physical_address) |
149 | acpi_hw_read_port((acpi_io_address) address, value, width); | 167 | (address + 4), &value, 32); |
150 | break; | 168 | if (ACPI_FAILURE(status)) { |
169 | return (status); | ||
170 | } | ||
171 | *return_value |= ((u64)value << 32); | ||
172 | } | ||
173 | } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ | ||
151 | 174 | ||
152 | default: | 175 | status = acpi_hw_read_port((acpi_io_address) |
153 | ACPI_ERROR((AE_INFO, | 176 | address, &value, width); |
154 | "Unsupported address space: %X", reg->space_id)); | 177 | if (ACPI_FAILURE(status)) { |
155 | return (AE_BAD_PARAMETER); | 178 | return (status); |
179 | } | ||
180 | *return_value = value; | ||
181 | |||
182 | if (reg->bit_width == 64) { | ||
183 | |||
184 | /* Read the top 32 bits */ | ||
185 | |||
186 | status = acpi_hw_read_port((acpi_io_address) | ||
187 | (address + 4), &value, 32); | ||
188 | if (ACPI_FAILURE(status)) { | ||
189 | return (status); | ||
190 | } | ||
191 | *return_value |= ((u64)value << 32); | ||
192 | } | ||
156 | } | 193 | } |
157 | 194 | ||
158 | ACPI_DEBUG_PRINT((ACPI_DB_IO, | 195 | ACPI_DEBUG_PRINT((ACPI_DB_IO, |
159 | "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n", | 196 | "Read: %8.8X%8.8X width %2d from %8.8X%8.8X (%s)\n", |
160 | *value, width, ACPI_FORMAT_UINT64(address), | 197 | ACPI_FORMAT_UINT64(*return_value), reg->bit_width, |
198 | ACPI_FORMAT_UINT64(address), | ||
161 | acpi_ut_get_region_name(reg->space_id))); | 199 | acpi_ut_get_region_name(reg->space_id))); |
162 | 200 | ||
163 | return (status); | 201 | return (status); |
@@ -169,7 +207,7 @@ ACPI_EXPORT_SYMBOL(acpi_read) | |||
169 | * | 207 | * |
170 | * FUNCTION: acpi_write | 208 | * FUNCTION: acpi_write |
171 | * | 209 | * |
172 | * PARAMETERS: Value - To be written | 210 | * PARAMETERS: Value - Value to be written |
173 | * Reg - GAS register structure | 211 | * Reg - GAS register structure |
174 | * | 212 | * |
175 | * RETURN: Status | 213 | * RETURN: Status |
@@ -177,7 +215,7 @@ ACPI_EXPORT_SYMBOL(acpi_read) | |||
177 | * DESCRIPTION: Write to either memory or IO space. | 215 | * DESCRIPTION: Write to either memory or IO space. |
178 | * | 216 | * |
179 | ******************************************************************************/ | 217 | ******************************************************************************/ |
180 | acpi_status acpi_write(u32 value, struct acpi_generic_address *reg) | 218 | acpi_status acpi_write(u64 value, struct acpi_generic_address *reg) |
181 | { | 219 | { |
182 | u32 width; | 220 | u32 width; |
183 | u64 address; | 221 | u64 address; |
@@ -185,54 +223,61 @@ acpi_status acpi_write(u32 value, struct acpi_generic_address *reg) | |||
185 | 223 | ||
186 | ACPI_FUNCTION_NAME(acpi_write); | 224 | ACPI_FUNCTION_NAME(acpi_write); |
187 | 225 | ||
188 | /* | 226 | /* Validate contents of the GAS register. Allow 64-bit transfers */ |
189 | * Must have a valid pointer to a GAS structure, and a non-zero address | ||
190 | * within. | ||
191 | */ | ||
192 | if (!reg) { | ||
193 | return (AE_BAD_PARAMETER); | ||
194 | } | ||
195 | |||
196 | /* Get a local copy of the address. Handles possible alignment issues */ | ||
197 | 227 | ||
198 | ACPI_MOVE_64_TO_64(&address, ®->address); | 228 | status = acpi_hw_validate_register(reg, 64, &address); |
199 | if (!address) { | 229 | if (ACPI_FAILURE(status)) { |
200 | return (AE_BAD_ADDRESS); | 230 | return (status); |
201 | } | 231 | } |
202 | 232 | ||
203 | /* Supported widths are 8/16/32 */ | ||
204 | |||
205 | width = reg->bit_width; | 233 | width = reg->bit_width; |
206 | if ((width != 8) && (width != 16) && (width != 32)) { | 234 | if (width == 64) { |
207 | return (AE_SUPPORT); | 235 | width = 32; /* Break into two 32-bit transfers */ |
208 | } | 236 | } |
209 | 237 | ||
210 | /* | 238 | /* |
211 | * Two address spaces supported: Memory or IO. | 239 | * Two address spaces supported: Memory or IO. PCI_Config is |
212 | * PCI_Config is not supported here because the GAS struct is insufficient | 240 | * not supported here because the GAS structure is insufficient |
213 | */ | 241 | */ |
214 | switch (reg->space_id) { | 242 | if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { |
215 | case ACPI_ADR_SPACE_SYSTEM_MEMORY: | 243 | status = acpi_os_write_memory((acpi_physical_address) |
216 | 244 | address, ACPI_LODWORD(value), | |
217 | status = acpi_os_write_memory((acpi_physical_address) address, | 245 | width); |
218 | value, width); | 246 | if (ACPI_FAILURE(status)) { |
219 | break; | 247 | return (status); |
248 | } | ||
220 | 249 | ||
221 | case ACPI_ADR_SPACE_SYSTEM_IO: | 250 | if (reg->bit_width == 64) { |
251 | status = acpi_os_write_memory((acpi_physical_address) | ||
252 | (address + 4), | ||
253 | ACPI_HIDWORD(value), 32); | ||
254 | if (ACPI_FAILURE(status)) { | ||
255 | return (status); | ||
256 | } | ||
257 | } | ||
258 | } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ | ||
222 | 259 | ||
223 | status = acpi_hw_write_port((acpi_io_address) address, value, | 260 | status = acpi_hw_write_port((acpi_io_address) |
261 | address, ACPI_LODWORD(value), | ||
224 | width); | 262 | width); |
225 | break; | 263 | if (ACPI_FAILURE(status)) { |
264 | return (status); | ||
265 | } | ||
226 | 266 | ||
227 | default: | 267 | if (reg->bit_width == 64) { |
228 | ACPI_ERROR((AE_INFO, | 268 | status = acpi_hw_write_port((acpi_io_address) |
229 | "Unsupported address space: %X", reg->space_id)); | 269 | (address + 4), |
230 | return (AE_BAD_PARAMETER); | 270 | ACPI_HIDWORD(value), 32); |
271 | if (ACPI_FAILURE(status)) { | ||
272 | return (status); | ||
273 | } | ||
274 | } | ||
231 | } | 275 | } |
232 | 276 | ||
233 | ACPI_DEBUG_PRINT((ACPI_DB_IO, | 277 | ACPI_DEBUG_PRINT((ACPI_DB_IO, |
234 | "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", | 278 | "Wrote: %8.8X%8.8X width %2d to %8.8X%8.8X (%s)\n", |
235 | value, width, ACPI_FORMAT_UINT64(address), | 279 | ACPI_FORMAT_UINT64(value), reg->bit_width, |
280 | ACPI_FORMAT_UINT64(address), | ||
236 | acpi_ut_get_region_name(reg->space_id))); | 281 | acpi_ut_get_region_name(reg->space_id))); |
237 | 282 | ||
238 | return (status); | 283 | return (status); |