diff options
author | Bob Moore <robert.moore@intel.com> | 2009-06-23 21:44:06 -0400 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2009-08-27 10:17:14 -0400 |
commit | c6b5774caafa4c12b6019366e2fdaaff117e95a4 (patch) | |
tree | 04a9439010ba84fd2ab787d6d43dbcebe2020a1e /drivers/acpi/acpica/hwxface.c | |
parent | f8d80cdf40fe4d2393159012b38ce9f85a488686 (diff) |
ACPICA: Add 64-bit support to acpi_read and acpi_write
Needed by drivers for new ACPi tables. Internal versions of
these functions still use 32-bit max transfers, in order to
minimize disruption and stack use for the standard ACPI registers
(FADT-based).
Signed-off-by: Bob Moore <robert.moore@intel.com>
Signed-off-by: Lin Ming <ming.m.lin@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/acpica/hwxface.c')
-rw-r--r-- | drivers/acpi/acpica/hwxface.c | 166 |
1 files changed, 99 insertions, 67 deletions
diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c index 9829979f2bdd..4ead85f29215 100644 --- a/drivers/acpi/acpica/hwxface.c +++ b/drivers/acpi/acpica/hwxface.c | |||
@@ -80,7 +80,7 @@ acpi_status acpi_reset(void) | |||
80 | 80 | ||
81 | /* Write the reset value to the reset register */ | 81 | /* Write the reset value to the reset register */ |
82 | 82 | ||
83 | status = acpi_write(acpi_gbl_FADT.reset_value, reset_reg); | 83 | status = acpi_hw_write(acpi_gbl_FADT.reset_value, reset_reg); |
84 | return_ACPI_STATUS(status); | 84 | return_ACPI_STATUS(status); |
85 | } | 85 | } |
86 | 86 | ||
@@ -97,67 +97,92 @@ ACPI_EXPORT_SYMBOL(acpi_reset) | |||
97 | * | 97 | * |
98 | * DESCRIPTION: Read from either memory or IO space. | 98 | * DESCRIPTION: Read from either memory or IO space. |
99 | * | 99 | * |
100 | * LIMITATIONS: <These limitations also apply to acpi_write> | ||
101 | * bit_width must be exactly 8, 16, 32, or 64. | ||
102 | * space_iD must be system_memory or system_iO. | ||
103 | * bit_offset and access_width are currently ignored, as there has | ||
104 | * not been a need to implement these. | ||
105 | * | ||
100 | ******************************************************************************/ | 106 | ******************************************************************************/ |
101 | acpi_status acpi_read(u32 *value, struct acpi_generic_address *reg) | 107 | acpi_status acpi_read(u64 *return_value, struct acpi_generic_address *reg) |
102 | { | 108 | { |
109 | u32 value; | ||
103 | u32 width; | 110 | u32 width; |
104 | u64 address; | 111 | u64 address; |
105 | acpi_status status; | 112 | acpi_status status; |
106 | 113 | ||
107 | ACPI_FUNCTION_NAME(acpi_read); | 114 | ACPI_FUNCTION_NAME(acpi_read); |
108 | 115 | ||
109 | /* | 116 | 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); | 117 | return (AE_BAD_PARAMETER); |
115 | } | 118 | } |
116 | 119 | ||
117 | /* Get a local copy of the address. Handles possible alignment issues */ | 120 | /* Validate contents of the GAS register. Allow 64-bit transfers */ |
118 | 121 | ||
119 | ACPI_MOVE_64_TO_64(&address, ®->address); | 122 | status = acpi_hw_validate_register(reg, 64, &address); |
120 | if (!address) { | 123 | if (ACPI_FAILURE(status)) { |
121 | return (AE_BAD_ADDRESS); | 124 | return (status); |
122 | } | 125 | } |
123 | 126 | ||
124 | /* Supported widths are 8/16/32 */ | ||
125 | |||
126 | width = reg->bit_width; | 127 | width = reg->bit_width; |
127 | if ((width != 8) && (width != 16) && (width != 32)) { | 128 | if (width == 64) { |
128 | return (AE_SUPPORT); | 129 | width = 32; /* Break into two 32-bit transfers */ |
129 | } | 130 | } |
130 | 131 | ||
131 | /* Initialize entire 32-bit return value to zero */ | 132 | /* Initialize entire 64-bit return value to zero */ |
132 | 133 | ||
133 | *value = 0; | 134 | *return_value = 0; |
135 | value = 0; | ||
134 | 136 | ||
135 | /* | 137 | /* |
136 | * Two address spaces supported: Memory or IO. PCI_Config is | 138 | * Two address spaces supported: Memory or IO. PCI_Config is |
137 | * not supported here because the GAS structure is insufficient | 139 | * not supported here because the GAS structure is insufficient |
138 | */ | 140 | */ |
139 | switch (reg->space_id) { | 141 | if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { |
140 | case ACPI_ADR_SPACE_SYSTEM_MEMORY: | 142 | status = acpi_os_read_memory((acpi_physical_address) |
143 | address, &value, width); | ||
144 | if (ACPI_FAILURE(status)) { | ||
145 | return (status); | ||
146 | } | ||
147 | *return_value = value; | ||
148 | |||
149 | if (reg->bit_width == 64) { | ||
141 | 150 | ||
142 | status = acpi_os_read_memory((acpi_physical_address) address, | 151 | /* Read the top 32 bits */ |
143 | value, width); | ||
144 | break; | ||
145 | 152 | ||
146 | case ACPI_ADR_SPACE_SYSTEM_IO: | 153 | status = acpi_os_read_memory((acpi_physical_address) |
154 | (address + 4), &value, 32); | ||
155 | if (ACPI_FAILURE(status)) { | ||
156 | return (status); | ||
157 | } | ||
158 | *return_value |= ((u64)value << 32); | ||
159 | } | ||
160 | } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ | ||
147 | 161 | ||
148 | status = | 162 | status = acpi_hw_read_port((acpi_io_address) |
149 | acpi_hw_read_port((acpi_io_address) address, value, width); | 163 | address, &value, width); |
150 | break; | 164 | if (ACPI_FAILURE(status)) { |
165 | return (status); | ||
166 | } | ||
167 | *return_value = value; | ||
151 | 168 | ||
152 | default: | 169 | if (reg->bit_width == 64) { |
153 | ACPI_ERROR((AE_INFO, | 170 | |
154 | "Unsupported address space: %X", reg->space_id)); | 171 | /* Read the top 32 bits */ |
155 | return (AE_BAD_PARAMETER); | 172 | |
173 | status = acpi_hw_read_port((acpi_io_address) | ||
174 | (address + 4), &value, 32); | ||
175 | if (ACPI_FAILURE(status)) { | ||
176 | return (status); | ||
177 | } | ||
178 | *return_value |= ((u64)value << 32); | ||
179 | } | ||
156 | } | 180 | } |
157 | 181 | ||
158 | ACPI_DEBUG_PRINT((ACPI_DB_IO, | 182 | ACPI_DEBUG_PRINT((ACPI_DB_IO, |
159 | "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n", | 183 | "Read: %8.8X%8.8X width %2d from %8.8X%8.8X (%s)\n", |
160 | *value, width, ACPI_FORMAT_UINT64(address), | 184 | ACPI_FORMAT_UINT64(*return_value), reg->bit_width, |
185 | ACPI_FORMAT_UINT64(address), | ||
161 | acpi_ut_get_region_name(reg->space_id))); | 186 | acpi_ut_get_region_name(reg->space_id))); |
162 | 187 | ||
163 | return (status); | 188 | return (status); |
@@ -169,7 +194,7 @@ ACPI_EXPORT_SYMBOL(acpi_read) | |||
169 | * | 194 | * |
170 | * FUNCTION: acpi_write | 195 | * FUNCTION: acpi_write |
171 | * | 196 | * |
172 | * PARAMETERS: Value - To be written | 197 | * PARAMETERS: Value - Value to be written |
173 | * Reg - GAS register structure | 198 | * Reg - GAS register structure |
174 | * | 199 | * |
175 | * RETURN: Status | 200 | * RETURN: Status |
@@ -177,7 +202,7 @@ ACPI_EXPORT_SYMBOL(acpi_read) | |||
177 | * DESCRIPTION: Write to either memory or IO space. | 202 | * DESCRIPTION: Write to either memory or IO space. |
178 | * | 203 | * |
179 | ******************************************************************************/ | 204 | ******************************************************************************/ |
180 | acpi_status acpi_write(u32 value, struct acpi_generic_address *reg) | 205 | acpi_status acpi_write(u64 value, struct acpi_generic_address *reg) |
181 | { | 206 | { |
182 | u32 width; | 207 | u32 width; |
183 | u64 address; | 208 | u64 address; |
@@ -185,54 +210,61 @@ acpi_status acpi_write(u32 value, struct acpi_generic_address *reg) | |||
185 | 210 | ||
186 | ACPI_FUNCTION_NAME(acpi_write); | 211 | ACPI_FUNCTION_NAME(acpi_write); |
187 | 212 | ||
188 | /* | 213 | /* 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 | 214 | ||
196 | /* Get a local copy of the address. Handles possible alignment issues */ | 215 | status = acpi_hw_validate_register(reg, 64, &address); |
197 | 216 | if (ACPI_FAILURE(status)) { | |
198 | ACPI_MOVE_64_TO_64(&address, ®->address); | 217 | return (status); |
199 | if (!address) { | ||
200 | return (AE_BAD_ADDRESS); | ||
201 | } | 218 | } |
202 | 219 | ||
203 | /* Supported widths are 8/16/32 */ | ||
204 | |||
205 | width = reg->bit_width; | 220 | width = reg->bit_width; |
206 | if ((width != 8) && (width != 16) && (width != 32)) { | 221 | if (width == 64) { |
207 | return (AE_SUPPORT); | 222 | width = 32; /* Break into two 32-bit transfers */ |
208 | } | 223 | } |
209 | 224 | ||
210 | /* | 225 | /* |
211 | * Two address spaces supported: Memory or IO. | 226 | * Two address spaces supported: Memory or IO. PCI_Config is |
212 | * PCI_Config is not supported here because the GAS struct is insufficient | 227 | * not supported here because the GAS structure is insufficient |
213 | */ | 228 | */ |
214 | switch (reg->space_id) { | 229 | if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) { |
215 | case ACPI_ADR_SPACE_SYSTEM_MEMORY: | 230 | status = acpi_os_write_memory((acpi_physical_address) |
216 | 231 | address, ACPI_LODWORD(value), | |
217 | status = acpi_os_write_memory((acpi_physical_address) address, | 232 | width); |
218 | value, width); | 233 | if (ACPI_FAILURE(status)) { |
219 | break; | 234 | return (status); |
235 | } | ||
220 | 236 | ||
221 | case ACPI_ADR_SPACE_SYSTEM_IO: | 237 | if (reg->bit_width == 64) { |
238 | status = acpi_os_write_memory((acpi_physical_address) | ||
239 | (address + 4), | ||
240 | ACPI_HIDWORD(value), 32); | ||
241 | if (ACPI_FAILURE(status)) { | ||
242 | return (status); | ||
243 | } | ||
244 | } | ||
245 | } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */ | ||
222 | 246 | ||
223 | status = acpi_hw_write_port((acpi_io_address) address, value, | 247 | status = acpi_hw_write_port((acpi_io_address) |
248 | address, ACPI_LODWORD(value), | ||
224 | width); | 249 | width); |
225 | break; | 250 | if (ACPI_FAILURE(status)) { |
251 | return (status); | ||
252 | } | ||
226 | 253 | ||
227 | default: | 254 | if (reg->bit_width == 64) { |
228 | ACPI_ERROR((AE_INFO, | 255 | status = acpi_hw_write_port((acpi_io_address) |
229 | "Unsupported address space: %X", reg->space_id)); | 256 | (address + 4), |
230 | return (AE_BAD_PARAMETER); | 257 | ACPI_HIDWORD(value), 32); |
258 | if (ACPI_FAILURE(status)) { | ||
259 | return (status); | ||
260 | } | ||
261 | } | ||
231 | } | 262 | } |
232 | 263 | ||
233 | ACPI_DEBUG_PRINT((ACPI_DB_IO, | 264 | ACPI_DEBUG_PRINT((ACPI_DB_IO, |
234 | "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", | 265 | "Wrote: %8.8X%8.8X width %2d to %8.8X%8.8X (%s)\n", |
235 | value, width, ACPI_FORMAT_UINT64(address), | 266 | ACPI_FORMAT_UINT64(value), reg->bit_width, |
267 | ACPI_FORMAT_UINT64(address), | ||
236 | acpi_ut_get_region_name(reg->space_id))); | 268 | acpi_ut_get_region_name(reg->space_id))); |
237 | 269 | ||
238 | return (status); | 270 | return (status); |