Coverage Report

Created: 2017-10-25 09:10

/root/src/xen/xen/drivers/acpi/hwregs.c
Line
Count
Source (jump to first uncovered line)
1
2
/*******************************************************************************
3
 *
4
 * Module Name: hwregs - Read/write access functions for the various ACPI
5
 *                       control and status registers.
6
 *
7
 ******************************************************************************/
8
9
/*
10
 * Copyright (C) 2000 - 2006, R. Byron Moore
11
 * All rights reserved.
12
 *
13
 * Redistribution and use in source and binary forms, with or without
14
 * modification, are permitted provided that the following conditions
15
 * are met:
16
 * 1. Redistributions of source code must retain the above copyright
17
 *    notice, this list of conditions, and the following disclaimer,
18
 *    without modification.
19
 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
20
 *    substantially similar to the "NO WARRANTY" disclaimer below
21
 *    ("Disclaimer") and any redistribution must be conditioned upon
22
 *    including a substantially similar Disclaimer requirement for further
23
 *    binary redistribution.
24
 * 3. Neither the names of the above-listed copyright holders nor the names
25
 *    of any contributors may be used to endorse or promote products derived
26
 *    from this software without specific prior written permission.
27
 *
28
 * Alternatively, this software may be distributed under the terms of the
29
 * GNU General Public License ("GPL") version 2 as published by the Free
30
 * Software Foundation.
31
 *
32
 * NO WARRANTY
33
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
34
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
35
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
36
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
37
 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
42
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
43
 * POSSIBILITY OF SUCH DAMAGES.
44
 */
45
46
#include <asm/io.h>
47
#include <xen/init.h>
48
#include <xen/types.h>
49
#include <xen/errno.h>
50
#include <acpi/acpi.h>
51
52
#define _COMPONENT          ACPI_HARDWARE
53
ACPI_MODULE_NAME("hwregs")
54
55
/*******************************************************************************
56
 *
57
 * FUNCTION:    acpi_hw_get_register_bit_mask
58
 *
59
 * PARAMETERS:  register_id         - Index of ACPI Register to access
60
 *
61
 * RETURN:      The bitmask to be used when accessing the register
62
 *
63
 * DESCRIPTION: Map register_id into a register bitmask.
64
 *
65
 ******************************************************************************/
66
static struct acpi_bit_register_info *
67
acpi_hw_get_bit_register_info(u32 register_id)
68
0
{
69
0
  ACPI_FUNCTION_ENTRY();
70
0
71
0
  if (register_id > ACPI_BITREG_MAX) {
72
0
    ACPI_DEBUG_PRINT((AE_INFO, "Invalid BitRegister ID: %X",
73
0
          register_id));
74
0
    return (NULL);
75
0
  }
76
0
77
0
  return (&acpi_gbl_bit_register_info[register_id]);
78
0
}
79
80
/*******************************************************************************
81
 *
82
 * FUNCTION:    acpi_get_register
83
 *
84
 * PARAMETERS:  register_id     - ID of ACPI bit_register to access
85
 *              return_value    - Value that was read from the register
86
 *
87
 * RETURN:      Status and the value read from specified Register. Value
88
 *              returned is normalized to bit0 (is shifted all the way right)
89
 *
90
 * DESCRIPTION: ACPI bit_register read function.
91
 *
92
 ******************************************************************************/
93
94
acpi_status acpi_get_register(u32 register_id, u32 * return_value)
95
0
{
96
0
  u32 register_value = 0;
97
0
  struct acpi_bit_register_info *bit_reg_info;
98
0
  acpi_status status;
99
0
100
0
  ACPI_FUNCTION_TRACE(acpi_get_register);
101
0
102
0
  /* Get the info structure corresponding to the requested ACPI Register */
103
0
104
0
  bit_reg_info = acpi_hw_get_bit_register_info(register_id);
105
0
  if (!bit_reg_info) {
106
0
    return_ACPI_STATUS(AE_BAD_PARAMETER);
107
0
  }
108
0
109
0
  /* Read from the register */
110
0
111
0
  status = acpi_hw_register_read(bit_reg_info->parent_register,
112
0
               &register_value);
113
0
114
0
  if (ACPI_SUCCESS(status)) {
115
0
116
0
    /* Normalize the value that was read */
117
0
118
0
    register_value =
119
0
        ((register_value & bit_reg_info->access_bit_mask)
120
0
         >> bit_reg_info->bit_position);
121
0
122
0
    *return_value = register_value;
123
0
124
0
    ACPI_DEBUG_PRINT((ACPI_DB_IO, "Read value %8.8X register %X\n",
125
0
          register_value,
126
0
          bit_reg_info->parent_register));
127
0
  }
128
0
129
0
  return_ACPI_STATUS(status);
130
0
}
131
132
/*******************************************************************************
133
 *
134
 * FUNCTION:    acpi_set_register
135
 *
136
 * PARAMETERS:  register_id     - ID of ACPI bit_register to access
137
 *              Value           - (only used on write) value to write to the
138
 *                                Register, NOT pre-normalized to the bit pos
139
 *
140
 * RETURN:      Status
141
 *
142
 * DESCRIPTION: ACPI Bit Register write function.
143
 *
144
 ******************************************************************************/
145
acpi_status acpi_set_register(u32 register_id, u32 value)
146
0
{
147
0
  u32 register_value = 0;
148
0
  struct acpi_bit_register_info *bit_reg_info;
149
0
  acpi_status status;
150
0
151
0
  ACPI_FUNCTION_TRACE_U32(acpi_set_register, register_id);
152
0
153
0
  /* Get the info structure corresponding to the requested ACPI Register */
154
0
155
0
  bit_reg_info = acpi_hw_get_bit_register_info(register_id);
156
0
  if (!bit_reg_info) {
157
0
    ACPI_DEBUG_PRINT((AE_INFO, "Bad ACPI HW RegisterId: %X",
158
0
          register_id));
159
0
    return_ACPI_STATUS(AE_BAD_PARAMETER);
160
0
  }
161
0
162
0
  /* Always do a register read first so we can insert the new bits  */
163
0
164
0
  status = acpi_hw_register_read(bit_reg_info->parent_register,
165
0
               &register_value);
166
0
  if (ACPI_FAILURE(status)) {
167
0
    goto unlock_and_exit;
168
0
  }
169
0
170
0
  /*
171
0
   * Decode the Register ID
172
0
   * Register ID = [Register block ID] | [bit ID]
173
0
   *
174
0
   * Check bit ID to fine locate Register offset.
175
0
   * Check Mask to determine Register offset, and then read-write.
176
0
   */
177
0
  switch (bit_reg_info->parent_register) {
178
0
  case ACPI_REGISTER_PM1_STATUS:
179
0
180
0
    /*
181
0
     * Status Registers are different from the rest. Clear by
182
0
     * writing 1, and writing 0 has no effect. So, the only relevant
183
0
     * information is the single bit we're interested in, all others should
184
0
     * be written as 0 so they will be left unchanged.
185
0
     */
186
0
    value = ACPI_REGISTER_PREPARE_BITS(value,
187
0
               bit_reg_info->bit_position,
188
0
               bit_reg_info->
189
0
               access_bit_mask);
190
0
    if (value) {
191
0
      status = acpi_hw_register_write(ACPI_REGISTER_PM1_STATUS,
192
0
              (u16) value);
193
0
      register_value = 0;
194
0
    }
195
0
    break;
196
0
197
0
  case ACPI_REGISTER_PM1_ENABLE:
198
0
199
0
    ACPI_REGISTER_INSERT_VALUE(register_value,
200
0
             bit_reg_info->bit_position,
201
0
             bit_reg_info->access_bit_mask,
202
0
             value);
203
0
204
0
    status = acpi_hw_register_write(ACPI_REGISTER_PM1_ENABLE,
205
0
            (u16) register_value);
206
0
    break;
207
0
208
0
  case ACPI_REGISTER_PM1_CONTROL:
209
0
210
0
    /*
211
0
     * Write the PM1 Control register.
212
0
     * Note that at this level, the fact that there are actually TWO
213
0
     * registers (A and B - and B may not exist) is abstracted.
214
0
     */
215
0
    ACPI_DEBUG_PRINT((ACPI_DB_IO, "PM1 control: Read %X\n",
216
0
          register_value));
217
0
218
0
    ACPI_REGISTER_INSERT_VALUE(register_value,
219
0
             bit_reg_info->bit_position,
220
0
             bit_reg_info->access_bit_mask,
221
0
             value);
222
0
223
0
    status = acpi_hw_register_write(ACPI_REGISTER_PM1_CONTROL,
224
0
            (u16) register_value);
225
0
    break;
226
0
227
0
  case ACPI_REGISTER_PM2_CONTROL:
228
0
229
0
#if 0 /* Redundant read in original Linux code. */
230
    status = acpi_hw_register_read(ACPI_REGISTER_PM2_CONTROL,
231
                 &register_value);
232
    if (ACPI_FAILURE(status)) {
233
      goto unlock_and_exit;
234
    }
235
#endif
236
0
237
0
    ACPI_DEBUG_PRINT((ACPI_DB_IO,
238
0
          "PM2 control: Read %X from %8.8X%8.8X\n",
239
0
          register_value,
240
0
          ACPI_FORMAT_UINT64(acpi_gbl_FADT.
241
0
                 xpm2_control_block.
242
0
                 address)));
243
0
244
0
    ACPI_REGISTER_INSERT_VALUE(register_value,
245
0
             bit_reg_info->bit_position,
246
0
             bit_reg_info->access_bit_mask,
247
0
             value);
248
0
249
0
    ACPI_DEBUG_PRINT((ACPI_DB_IO,
250
0
          "About to write %4.4X to %8.8X%8.8X\n",
251
0
          register_value,
252
0
          ACPI_FORMAT_UINT64(acpi_gbl_FADT.
253
0
                 xpm2_control_block.
254
0
                 address)));
255
0
256
0
    status = acpi_hw_register_write(ACPI_REGISTER_PM2_CONTROL,
257
0
            (u8) (register_value));
258
0
    break;
259
0
260
0
  default:
261
0
    break;
262
0
  }
263
0
264
0
      unlock_and_exit:
265
0
266
0
  /* Normalize the value that was read */
267
0
268
0
  ACPI_DEBUG_EXEC(register_value =
269
0
      ((register_value & bit_reg_info->access_bit_mask) >>
270
0
       bit_reg_info->bit_position));
271
0
272
0
  ACPI_DEBUG_PRINT((ACPI_DB_IO,
273
0
        "Set bits: %8.8X actual %8.8X register %X\n", value,
274
0
        register_value, bit_reg_info->parent_register));
275
0
  return_ACPI_STATUS(status);
276
0
}
277
278
/******************************************************************************
279
 *
280
 * FUNCTION:    acpi_hw_register_read
281
 *
282
 * PARAMETERS:  register_id         - ACPI Register ID
283
 *              return_value        - Where the register value is returned
284
 *
285
 * RETURN:      Status and the value read.
286
 *
287
 * DESCRIPTION: Read from the specified ACPI register
288
 *
289
 ******************************************************************************/
290
acpi_status
291
acpi_hw_register_read(u32 register_id, u32 * return_value)
292
0
{
293
0
  u32 value1 = 0;
294
0
  u32 value2 = 0;
295
0
  acpi_status status;
296
0
297
0
  ACPI_FUNCTION_TRACE(hw_register_read);
298
0
299
0
  switch (register_id) {
300
0
  case ACPI_REGISTER_PM1_STATUS: /* 16-bit access */
301
0
302
0
    status =
303
0
        acpi_hw_low_level_read(16, &value1,
304
0
             &acpi_gbl_FADT.xpm1a_event_block);
305
0
    if (ACPI_FAILURE(status)) {
306
0
      goto exit;
307
0
    }
308
0
309
0
    /* PM1B is optional */
310
0
311
0
    status =
312
0
        acpi_hw_low_level_read(16, &value2,
313
0
             &acpi_gbl_FADT.xpm1b_event_block);
314
0
    value1 |= value2;
315
0
    break;
316
0
317
0
  case ACPI_REGISTER_PM1_ENABLE: /* 16-bit access */
318
0
319
0
    status =
320
0
        acpi_hw_low_level_read(16, &value1, &acpi_gbl_xpm1a_enable);
321
0
    if (ACPI_FAILURE(status)) {
322
0
      goto exit;
323
0
    }
324
0
325
0
    /* PM1B is optional */
326
0
327
0
    status =
328
0
        acpi_hw_low_level_read(16, &value2, &acpi_gbl_xpm1b_enable);
329
0
    value1 |= value2;
330
0
    break;
331
0
332
0
  case ACPI_REGISTER_PM1_CONTROL: /* 16-bit access */
333
0
334
0
    status =
335
0
        acpi_hw_low_level_read(16, &value1,
336
0
             &acpi_gbl_FADT.xpm1a_control_block);
337
0
    if (ACPI_FAILURE(status)) {
338
0
      goto exit;
339
0
    }
340
0
341
0
    status =
342
0
        acpi_hw_low_level_read(16, &value2,
343
0
             &acpi_gbl_FADT.xpm1b_control_block);
344
0
    value1 |= value2;
345
0
    break;
346
0
347
0
  case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */
348
0
349
0
    status =
350
0
        acpi_hw_low_level_read(8, &value1,
351
0
             &acpi_gbl_FADT.xpm2_control_block);
352
0
    break;
353
0
354
0
  case ACPI_REGISTER_PM_TIMER: /* 32-bit access */
355
0
356
0
    status =
357
0
        acpi_hw_low_level_read(32, &value1,
358
0
             &acpi_gbl_FADT.xpm_timer_block);
359
0
    break;
360
0
361
0
  case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */
362
0
363
0
    status =
364
0
        acpi_os_read_port(acpi_gbl_FADT.smi_command, &value1, 8);
365
0
    break;
366
0
367
0
  case ACPI_REGISTER_SLEEP_STATUS:
368
0
369
0
    status =
370
0
        acpi_hw_low_level_read(acpi_gbl_FADT.sleep_status.bit_width,
371
0
             &value1,
372
0
             &acpi_gbl_FADT.sleep_status);
373
0
    break;
374
0
375
0
  default:
376
0
    ACPI_DEBUG_PRINT((AE_INFO, "Unknown Register ID: %X", register_id));
377
0
    status = AE_BAD_PARAMETER;
378
0
    break;
379
0
  }
380
0
381
0
      exit:
382
0
383
0
  if (ACPI_SUCCESS(status)) {
384
0
    *return_value = value1;
385
0
  }
386
0
387
0
  return_ACPI_STATUS(status);
388
0
}
389
390
/******************************************************************************
391
 *
392
 * FUNCTION:    acpi_hw_register_write
393
 *
394
 * PARAMETERS:  register_id         - ACPI Register ID
395
 *              Value               - The value to write
396
 *
397
 * RETURN:      Status
398
 *
399
 * DESCRIPTION: Write to the specified ACPI register
400
 *
401
 * NOTE: In accordance with the ACPI specification, this function automatically
402
 * preserves the value of the following bits, meaning that these bits cannot be
403
 * changed via this interface:
404
 *
405
 * PM1_CONTROL[0] = SCI_EN
406
 * PM1_CONTROL[9]
407
 * PM1_STATUS[11]
408
 *
409
 * ACPI References:
410
 * 1) Hardware Ignored Bits: When software writes to a register with ignored
411
 *      bit fields, it preserves the ignored bit fields
412
 * 2) SCI_EN: OSPM always preserves this bit position
413
 *
414
 ******************************************************************************/
415
416
acpi_status acpi_hw_register_write(u32 register_id, u32 value)
417
0
{
418
0
  acpi_status status;
419
0
  u32 read_value;
420
0
421
0
  ACPI_FUNCTION_TRACE(hw_register_write);
422
0
423
0
  switch (register_id) {
424
0
  case ACPI_REGISTER_PM1_STATUS: /* 16-bit access */
425
0
426
0
    /* Perform a read first to preserve certain bits (per ACPI spec) */
427
0
428
0
    status = acpi_hw_register_read(ACPI_REGISTER_PM1_STATUS,
429
0
                 &read_value);
430
0
    if (ACPI_FAILURE(status)) {
431
0
      goto exit;
432
0
    }
433
0
434
0
    /* Insert the bits to be preserved */
435
0
436
0
    ACPI_INSERT_BITS(value, ACPI_PM1_STATUS_PRESERVED_BITS,
437
0
         read_value);
438
0
439
0
    /* Now we can write the data */
440
0
441
0
    status =
442
0
        acpi_hw_low_level_write(16, value,
443
0
              &acpi_gbl_FADT.xpm1a_event_block);
444
0
    if (ACPI_FAILURE(status)) {
445
0
      goto exit;
446
0
    }
447
0
448
0
    /* PM1B is optional */
449
0
450
0
    status =
451
0
        acpi_hw_low_level_write(16, value,
452
0
              &acpi_gbl_FADT.xpm1b_event_block);
453
0
    break;
454
0
455
0
  case ACPI_REGISTER_PM1_ENABLE: /* 16-bit access */
456
0
457
0
    status =
458
0
        acpi_hw_low_level_write(16, value, &acpi_gbl_xpm1a_enable);
459
0
    if (ACPI_FAILURE(status)) {
460
0
      goto exit;
461
0
    }
462
0
463
0
    /* PM1B is optional */
464
0
465
0
    status =
466
0
        acpi_hw_low_level_write(16, value, &acpi_gbl_xpm1b_enable);
467
0
    break;
468
0
469
0
  case ACPI_REGISTER_PM1_CONTROL: /* 16-bit access */
470
0
471
0
    /*
472
0
     * Perform a read first to preserve certain bits (per ACPI spec)
473
0
     */
474
0
    status = acpi_hw_register_read(ACPI_REGISTER_PM1_CONTROL,
475
0
                 &read_value);
476
0
    if (ACPI_FAILURE(status)) {
477
0
      goto exit;
478
0
    }
479
0
480
0
    /* Insert the bits to be preserved */
481
0
482
0
    ACPI_INSERT_BITS(value, ACPI_PM1_CONTROL_PRESERVED_BITS,
483
0
         read_value);
484
0
485
0
    /* Now we can write the data */
486
0
487
0
    status =
488
0
        acpi_hw_low_level_write(16, value,
489
0
              &acpi_gbl_FADT.xpm1a_control_block);
490
0
    if (ACPI_FAILURE(status)) {
491
0
      goto exit;
492
0
    }
493
0
494
0
    status =
495
0
        acpi_hw_low_level_write(16, value,
496
0
              &acpi_gbl_FADT.xpm1b_control_block);
497
0
    break;
498
0
499
0
  case ACPI_REGISTER_PM1A_CONTROL: /* 16-bit access */
500
0
501
0
    status =
502
0
        acpi_hw_low_level_write(16, value,
503
0
              &acpi_gbl_FADT.xpm1a_control_block);
504
0
    break;
505
0
506
0
  case ACPI_REGISTER_PM1B_CONTROL: /* 16-bit access */
507
0
508
0
    status =
509
0
        acpi_hw_low_level_write(16, value,
510
0
              &acpi_gbl_FADT.xpm1b_control_block);
511
0
    break;
512
0
513
0
  case ACPI_REGISTER_PM2_CONTROL: /* 8-bit access */
514
0
515
0
    status =
516
0
        acpi_hw_low_level_write(8, value,
517
0
              &acpi_gbl_FADT.xpm2_control_block);
518
0
    break;
519
0
520
0
  case ACPI_REGISTER_PM_TIMER: /* 32-bit access */
521
0
522
0
    status =
523
0
        acpi_hw_low_level_write(32, value,
524
0
              &acpi_gbl_FADT.xpm_timer_block);
525
0
    break;
526
0
527
0
  case ACPI_REGISTER_SMI_COMMAND_BLOCK: /* 8-bit access */
528
0
529
0
    /* SMI_CMD is currently always in IO space */
530
0
531
0
    status =
532
0
        acpi_os_write_port(acpi_gbl_FADT.smi_command, value, 8);
533
0
    break;
534
0
535
0
  case ACPI_REGISTER_SLEEP_CONTROL:
536
0
537
0
    status =
538
0
        acpi_hw_low_level_write(acpi_gbl_FADT.sleep_control.bit_width,
539
0
              value,
540
0
              &acpi_gbl_FADT.sleep_control);
541
0
    break;
542
0
543
0
  default:
544
0
    status = AE_BAD_PARAMETER;
545
0
    break;
546
0
  }
547
0
548
0
      exit:
549
0
  return_ACPI_STATUS(status);
550
0
}
551
552
/******************************************************************************
553
 *
554
 * FUNCTION:    acpi_hw_low_level_read
555
 *
556
 * PARAMETERS:  Width               - 8, 16, or 32
557
 *              Value               - Where the value is returned
558
 *              Reg                 - GAS register structure
559
 *
560
 * RETURN:      Status
561
 *
562
 * DESCRIPTION: Read from either memory or IO space.
563
 *
564
 ******************************************************************************/
565
566
acpi_status
567
acpi_hw_low_level_read(u32 width, u32 * value, struct acpi_generic_address *reg)
568
0
{
569
0
  u64 address;
570
0
  acpi_status status;
571
0
572
0
  ACPI_FUNCTION_NAME(hw_low_level_read);
573
0
574
0
  /*
575
0
   * Must have a valid pointer to a GAS structure, and
576
0
   * a non-zero address within. However, don't return an error
577
0
   * because the PM1A/B code must not fail if B isn't present.
578
0
   */
579
0
  if (!reg) {
580
0
    return (AE_OK);
581
0
  }
582
0
583
0
  /* Get a local copy of the address. Handles possible alignment issues */
584
0
585
0
  ACPI_MOVE_64_TO_64(&address, &reg->address);
586
0
  if (!address) {
587
0
    return (AE_OK);
588
0
  }
589
0
  *value = 0;
590
0
591
0
  /*
592
0
   * Two address spaces supported: Memory or IO.
593
0
   * PCI_Config is not supported here because the GAS struct is insufficient
594
0
   */
595
0
  switch (reg->space_id) {
596
0
  case ACPI_ADR_SPACE_SYSTEM_MEMORY:
597
0
598
0
    status = acpi_os_read_memory((acpi_physical_address) address,
599
0
               value, width);
600
0
    break;
601
0
602
0
  case ACPI_ADR_SPACE_SYSTEM_IO:
603
0
604
0
    status = acpi_os_read_port((acpi_io_address) address,
605
0
             value, width);
606
0
    break;
607
0
608
0
  default:
609
0
610
0
    return (AE_BAD_PARAMETER);
611
0
  }
612
0
613
0
  ACPI_DEBUG_PRINT((ACPI_DB_IO,
614
0
        "Read:  %8.8X width %2d from %8.8X%8.8X (%s)\n",
615
0
        *value, width,
616
0
        ACPI_FORMAT_UINT64(address),
617
0
        acpi_ut_get_region_name(reg->address_space_id)));
618
0
619
0
  return (status);
620
0
}
621
622
/******************************************************************************
623
 *
624
 * FUNCTION:    acpi_hw_low_level_write
625
 *
626
 * PARAMETERS:  Width               - 8, 16, or 32
627
 *              Value               - To be written
628
 *              Reg                 - GAS register structure
629
 *
630
 * RETURN:      Status
631
 *
632
 * DESCRIPTION: Write to either memory or IO space.
633
 *
634
 ******************************************************************************/
635
636
acpi_status
637
acpi_hw_low_level_write(u32 width, u32 value, struct acpi_generic_address * reg)
638
0
{
639
0
  u64 address;
640
0
  acpi_status status;
641
0
642
0
  ACPI_FUNCTION_NAME(hw_low_level_write);
643
0
644
0
  /*
645
0
   * Must have a valid pointer to a GAS structure, and
646
0
   * a non-zero address within. However, don't return an error
647
0
   * because the PM1A/B code must not fail if B isn't present.
648
0
   */
649
0
  if (!reg) {
650
0
    return (AE_OK);
651
0
  }
652
0
653
0
  /* Get a local copy of the address. Handles possible alignment issues */
654
0
655
0
  ACPI_MOVE_64_TO_64(&address, &reg->address);
656
0
  if (!address) {
657
0
    return (AE_OK);
658
0
  }
659
0
660
0
  /*
661
0
   * Two address spaces supported: Memory or IO.
662
0
   * PCI_Config is not supported here because the GAS struct is insufficient
663
0
   */
664
0
  switch (reg->space_id) {
665
0
  case ACPI_ADR_SPACE_SYSTEM_MEMORY:
666
0
667
0
    status = acpi_os_write_memory((acpi_physical_address) address,
668
0
                value, width);
669
0
    break;
670
0
671
0
  case ACPI_ADR_SPACE_SYSTEM_IO:
672
0
673
0
    status = acpi_os_write_port((acpi_io_address) address,
674
0
              value, width);
675
0
    break;
676
0
677
0
  default:
678
0
    return (AE_BAD_PARAMETER);
679
0
  }
680
0
681
0
  ACPI_DEBUG_PRINT((ACPI_DB_IO,
682
0
        "Wrote: %8.8X width %2d   to %8.8X%8.8X (%s)\n",
683
0
        value, width,
684
0
        ACPI_FORMAT_UINT64(address),
685
0
        acpi_ut_get_region_name(reg->address_space_id)));
686
0
687
0
  return (status);
688
0
}
689