Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
acpi-ext.c
Go to the documentation of this file.
1 /*
2  * (c) Copyright 2003, 2006 Hewlett-Packard Development Company, L.P.
3  * Alex Williamson <[email protected]>
4  * Bjorn Helgaas <[email protected]>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  */
10 
11 #include <linux/module.h>
12 #include <linux/types.h>
13 #include <linux/slab.h>
14 #include <linux/acpi.h>
15 
16 #include <asm/acpi-ext.h>
17 
18 /*
19  * Device CSRs that do not appear in PCI config space should be described
20  * via ACPI. This would normally be done with Address Space Descriptors
21  * marked as "consumer-only," but old versions of Windows and Linux ignore
22  * the producer/consumer flag, so HP invented a vendor-defined resource to
23  * describe the location and size of CSR space.
24  */
25 
27  .subtype = 2,
28  .data = { 0xf9, 0xad, 0xe9, 0x69, 0x4f, 0x92, 0x5f, 0xab, 0xf6, 0x4a,
29  0x24, 0xd2, 0x01, 0x37, 0x0e, 0xad },
30 };
31 
32 static acpi_status hp_ccsr_locate(acpi_handle obj, u64 *base, u64 *length)
33 {
36  struct acpi_resource *resource;
38 
39  status = acpi_get_vendor_resource(obj, METHOD_NAME__CRS, &hp_ccsr_uuid,
40  &buffer);
41 
42  resource = buffer.pointer;
43  vendor = &resource->data.vendor_typed;
44 
45  if (ACPI_FAILURE(status) || vendor->byte_length < 16) {
46  status = AE_NOT_FOUND;
47  goto exit;
48  }
49 
50  memcpy(base, vendor->byte_data, sizeof(*base));
51  memcpy(length, vendor->byte_data + 8, sizeof(*length));
52 
53  exit:
54  kfree(buffer.pointer);
55  return status;
56 }
57 
58 struct csr_space {
61 };
62 
63 static acpi_status find_csr_space(struct acpi_resource *resource, void *data)
64 {
65  struct csr_space *space = data;
66  struct acpi_resource_address64 addr;
68 
69  status = acpi_resource_to_address64(resource, &addr);
70  if (ACPI_SUCCESS(status) &&
71  addr.resource_type == ACPI_MEMORY_RANGE &&
72  addr.address_length &&
73  addr.producer_consumer == ACPI_CONSUMER) {
74  space->base = addr.minimum;
75  space->length = addr.address_length;
76  return AE_CTRL_TERMINATE;
77  }
78  return AE_OK; /* keep looking */
79 }
80 
81 static acpi_status hp_crs_locate(acpi_handle obj, u64 *base, u64 *length)
82 {
83  struct csr_space space = { 0, 0 };
84 
85  acpi_walk_resources(obj, METHOD_NAME__CRS, find_csr_space, &space);
86  if (!space.length)
87  return AE_NOT_FOUND;
88 
89  *base = space.base;
90  *length = space.length;
91  return AE_OK;
92 }
93 
94 acpi_status hp_acpi_csr_space(acpi_handle obj, u64 *csr_base, u64 *csr_length)
95 {
97 
98  status = hp_ccsr_locate(obj, csr_base, csr_length);
99  if (ACPI_SUCCESS(status))
100  return status;
101 
102  return hp_crs_locate(obj, csr_base, csr_length);
103 }