aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/acpica/hwregs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/acpica/hwregs.c')
-rw-r--r--drivers/acpi/acpica/hwregs.c146
1 files changed, 9 insertions, 137 deletions
diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c
index daceb80022b0..3b7fb99362b6 100644
--- a/drivers/acpi/acpica/hwregs.c
+++ b/drivers/acpi/acpica/hwregs.c
@@ -306,12 +306,6 @@ acpi_status acpi_hw_read(u32 *value, struct acpi_generic_address *reg)
306acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg) 306acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg)
307{ 307{
308 u64 address; 308 u64 address;
309 u8 access_width;
310 u32 bit_width;
311 u8 bit_offset;
312 u64 value64;
313 u32 new_value32, old_value32;
314 u8 index;
315 acpi_status status; 309 acpi_status status;
316 310
317 ACPI_FUNCTION_NAME(hw_write); 311 ACPI_FUNCTION_NAME(hw_write);
@@ -323,145 +317,23 @@ acpi_status acpi_hw_write(u32 value, struct acpi_generic_address *reg)
323 return (status); 317 return (status);
324 } 318 }
325 319
326 /* Convert access_width into number of bits based */
327
328 access_width = acpi_hw_get_access_bit_width(reg, 32);
329 bit_width = reg->bit_offset + reg->bit_width;
330 bit_offset = reg->bit_offset;
331
332 /* 320 /*
333 * Two address spaces supported: Memory or IO. PCI_Config is 321 * Two address spaces supported: Memory or IO. PCI_Config is
334 * not supported here because the GAS structure is insufficient 322 * not supported here because the GAS structure is insufficient
335 */ 323 */
336 index = 0; 324 if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
337 while (bit_width) { 325 status = acpi_os_write_memory((acpi_physical_address)
338 /* 326 address, (u64)value,
339 * Use offset style bit reads because "Index * AccessWidth" is 327 reg->bit_width);
340 * ensured to be less than 32-bits by acpi_hw_validate_register(). 328 } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
341 */ 329
342 new_value32 = ACPI_GET_BITS(&value, index * access_width, 330 status = acpi_hw_write_port((acpi_io_address)
343 ACPI_MASK_BITS_ABOVE_32 331 address, value, reg->bit_width);
344 (access_width));
345
346 if (bit_offset >= access_width) {
347 bit_offset -= access_width;
348 } else {
349 /*
350 * Use offset style bit masks because access_width is ensured
351 * to be less than 32-bits by acpi_hw_validate_register() and
352 * bit_offset/bit_width is less than access_width here.
353 */
354 if (bit_offset) {
355 new_value32 &= ACPI_MASK_BITS_BELOW(bit_offset);
356 }
357 if (bit_width < access_width) {
358 new_value32 &= ACPI_MASK_BITS_ABOVE(bit_width);
359 }
360
361 if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) {
362 if (bit_offset || bit_width < access_width) {
363 /*
364 * Read old values in order not to modify the bits that
365 * are beyond the register bit_width/bit_offset setting.
366 */
367 status =
368 acpi_os_read_memory((acpi_physical_address)
369 address +
370 index *
371 ACPI_DIV_8
372 (access_width),
373 &value64,
374 access_width);
375 old_value32 = (u32)value64;
376
377 /*
378 * Use offset style bit masks because access_width is
379 * ensured to be less than 32-bits by
380 * acpi_hw_validate_register() and bit_offset/bit_width is
381 * less than access_width here.
382 */
383 if (bit_offset) {
384 old_value32 &=
385 ACPI_MASK_BITS_ABOVE
386 (bit_offset);
387 bit_offset = 0;
388 }
389 if (bit_width < access_width) {
390 old_value32 &=
391 ACPI_MASK_BITS_BELOW
392 (bit_width);
393 }
394
395 new_value32 |= old_value32;
396 }
397
398 value64 = (u64)new_value32;
399 status =
400 acpi_os_write_memory((acpi_physical_address)
401 address +
402 index *
403 ACPI_DIV_8
404 (access_width),
405 value64, access_width);
406 } else { /* ACPI_ADR_SPACE_SYSTEM_IO, validated earlier */
407
408 if (bit_offset || bit_width < access_width) {
409 /*
410 * Read old values in order not to modify the bits that
411 * are beyond the register bit_width/bit_offset setting.
412 */
413 status =
414 acpi_hw_read_port((acpi_io_address)
415 address +
416 index *
417 ACPI_DIV_8
418 (access_width),
419 &old_value32,
420 access_width);
421
422 /*
423 * Use offset style bit masks because access_width is
424 * ensured to be less than 32-bits by
425 * acpi_hw_validate_register() and bit_offset/bit_width is
426 * less than access_width here.
427 */
428 if (bit_offset) {
429 old_value32 &=
430 ACPI_MASK_BITS_ABOVE
431 (bit_offset);
432 bit_offset = 0;
433 }
434 if (bit_width < access_width) {
435 old_value32 &=
436 ACPI_MASK_BITS_BELOW
437 (bit_width);
438 }
439
440 new_value32 |= old_value32;
441 }
442
443 status = acpi_hw_write_port((acpi_io_address)
444 address +
445 index *
446 ACPI_DIV_8
447 (access_width),
448 new_value32,
449 access_width);
450 }
451 }
452
453 /*
454 * Index * access_width is ensured to be less than 32-bits by
455 * acpi_hw_validate_register().
456 */
457 bit_width -=
458 bit_width > access_width ? access_width : bit_width;
459 index++;
460 } 332 }
461 333
462 ACPI_DEBUG_PRINT((ACPI_DB_IO, 334 ACPI_DEBUG_PRINT((ACPI_DB_IO,
463 "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n", 335 "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n",
464 value, access_width, ACPI_FORMAT_UINT64(address), 336 value, reg->bit_width, ACPI_FORMAT_UINT64(address),
465 acpi_ut_get_region_name(reg->space_id))); 337 acpi_ut_get_region_name(reg->space_id)));
466 338
467 return (status); 339 return (status);