@@ -195,17 +195,19 @@ acpi_hw_validate_register(struct acpi_generic_address *reg,
195
195
* 64-bit values is not needed.
196
196
*
197
197
* LIMITATIONS: <These limitations also apply to acpi_hw_write>
198
- * bit_width must be exactly 8, 16, or 32.
199
198
* space_ID must be system_memory or system_IO.
200
- * bit_offset and access_width are currently ignored, as there has
201
- * not been a need to implement these.
202
199
*
203
200
******************************************************************************/
204
201
205
202
acpi_status acpi_hw_read (u32 * value , struct acpi_generic_address * reg )
206
203
{
207
204
u64 address ;
205
+ u8 access_width ;
206
+ u32 bit_width ;
207
+ u8 bit_offset ;
208
208
u64 value64 ;
209
+ u32 value32 ;
210
+ u8 index ;
209
211
acpi_status status ;
210
212
211
213
ACPI_FUNCTION_NAME (hw_read );
@@ -217,28 +219,75 @@ acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg)
217
219
return (status );
218
220
}
219
221
220
- /* Initialize entire 32-bit return value to zero */
221
-
222
+ /*
223
+ * Initialize entire 32-bit return value to zero, convert access_width
224
+ * into number of bits based
225
+ */
222
226
* value = 0 ;
227
+ access_width = acpi_hw_get_access_bit_width (reg , 32 );
228
+ bit_width = reg -> bit_offset + reg -> bit_width ;
229
+ bit_offset = reg -> bit_offset ;
223
230
224
231
/*
225
232
* Two address spaces supported: Memory or IO. PCI_Config is
226
233
* not supported here because the GAS structure is insufficient
227
234
*/
228
- if (reg -> space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY ) {
229
- status = acpi_os_read_memory ((acpi_physical_address )
230
- address , & value64 , reg -> bit_width );
235
+ index = 0 ;
236
+ while (bit_width ) {
237
+ if (bit_offset >= access_width ) {
238
+ value32 = 0 ;
239
+ bit_offset -= access_width ;
240
+ } else {
241
+ if (reg -> space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY ) {
242
+ status =
243
+ acpi_os_read_memory ((acpi_physical_address )
244
+ address +
245
+ index *
246
+ ACPI_DIV_8
247
+ (access_width ),
248
+ & value64 , access_width );
249
+ value32 = (u32 )value64 ;
250
+ } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
251
+
252
+ status = acpi_hw_read_port ((acpi_io_address )
253
+ address +
254
+ index *
255
+ ACPI_DIV_8
256
+ (access_width ),
257
+ & value32 ,
258
+ access_width );
259
+ }
231
260
232
- * value = (u32 )value64 ;
233
- } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
261
+ /*
262
+ * Use offset style bit masks because:
263
+ * bit_offset < access_width/bit_width < access_width, and
264
+ * access_width is ensured to be less than 32-bits by
265
+ * acpi_hw_validate_register().
266
+ */
267
+ if (bit_offset ) {
268
+ value32 &= ACPI_MASK_BITS_BELOW (bit_offset );
269
+ bit_offset = 0 ;
270
+ }
271
+ if (bit_width < access_width ) {
272
+ value32 &= ACPI_MASK_BITS_ABOVE (bit_width );
273
+ }
274
+ }
275
+
276
+ /*
277
+ * Use offset style bit writes because "Index * AccessWidth" is
278
+ * ensured to be less than 32-bits by acpi_hw_validate_register().
279
+ */
280
+ ACPI_SET_BITS (value , index * access_width ,
281
+ ACPI_MASK_BITS_ABOVE_32 (access_width ), value32 );
234
282
235
- status = acpi_hw_read_port ((acpi_io_address )
236
- address , value , reg -> bit_width );
283
+ bit_width -=
284
+ bit_width > access_width ? access_width : bit_width ;
285
+ index ++ ;
237
286
}
238
287
239
288
ACPI_DEBUG_PRINT ((ACPI_DB_IO ,
240
289
"Read: %8.8X width %2d from %8.8X%8.8X (%s)\n" ,
241
- * value , reg -> bit_width , ACPI_FORMAT_UINT64 (address ),
290
+ * value , access_width , ACPI_FORMAT_UINT64 (address ),
242
291
acpi_ut_get_region_name (reg -> space_id )));
243
292
244
293
return (status );
0 commit comments