1 /*
2 * Copyright (c) 2009, Intel Corporation.
3 * All rights reserved.
4 */
5
6 #include <sys/types.h>
7 #include <sys/atomic.h>
8 #include <sys/sunddi.h>
9 #include <sys/sunndi.h>
10 #include <sys/acpi/acpi.h>
11 #include <sys/acpica.h>
12 #include <sys/acpidev.h>
13 #include <sys/acpidev_rsc.h>
14 #include <sys/acpidev_impl.h>
15
16 static ACPI_STATUS acpidev_memory_probe(acpidev_walk_info_t *infop);
17 static acpidev_filter_result_t acpidev_memory_filter(
18 acpidev_walk_info_t *infop, char *devname, int maxlen);
19 static ACPI_STATUS acpidev_memory_init(acpidev_walk_info_t *infop);
20
21 /*
22 * Default class driver for ACPI memory objects.
23 */
24 acpidev_class_t acpidev_class_memory = {
25 0, /* adc_refcnt */
26 ACPIDEV_CLASS_REV1, /* adc_version */
27 ACPIDEV_CLASS_ID_MEMORY, /* adc_class_id */
28 "ACPI memory", /* adc_class_name */
29 ACPIDEV_TYPE_MEMORY, /* adc_dev_type */
30 NULL, /* adc_private */
31 NULL, /* adc_pre_probe */
32 NULL, /* adc_post_probe */
33 acpidev_memory_probe, /* adc_probe */
34 acpidev_memory_filter, /* adc_filter */
35 acpidev_memory_init, /* adc_init */
36 NULL, /* adc_fini */
37 };
38
39 /*
40 * List head of class drivers which will be called in order when handling
41 * children of ACPI memory object.
42 */
43 acpidev_class_list_t *acpidev_class_list_memory = NULL;
44
45 static char *acpidev_memory_device_ids[] = {
46 ACPIDEV_HID_MEMORY,
47 };
48
49 static char *acpidev_memory_uid_formats[] = {
50 "MEM%x-%x",
51 };
52
53 /* Filter rule table for memory objects. */
54 static acpidev_filter_rule_t acpidev_memory_filters[] = {
55 { /* Ignore all memory objects under ACPI root object */
56 NULL,
57 0,
58 ACPIDEV_FILTER_SKIP,
59 NULL,
60 1,
61 1,
62 NULL,
63 NULL,
64 },
65 { /* Create node and scan child for all other memory objects */
66 NULL,
67 0,
68 ACPIDEV_FILTER_DEFAULT,
69 &acpidev_class_list_device,
70 2,
71 INT_MAX,
72 NULL,
73 ACPIDEV_NODE_NAME_MEMORY,
74 }
75 };
76
77 static ACPI_STATUS
78 acpidev_memory_probe(acpidev_walk_info_t *infop)
79 {
80 ACPI_STATUS rc;
81 int flags;
82
83 ASSERT(infop != NULL);
84 ASSERT(infop->awi_hdl != NULL);
85 ASSERT(infop->awi_info != NULL);
86 if (infop->awi_info->Type != ACPI_TYPE_DEVICE ||
87 acpidev_match_device_id(infop->awi_info,
88 ACPIDEV_ARRAY_PARAM(acpidev_memory_device_ids)) == 0) {
89 return (AE_OK);
90 }
91
92 if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE) {
93 flags = ACPIDEV_PROCESS_FLAG_SCAN | ACPIDEV_PROCESS_FLAG_CREATE;
94 rc = acpidev_process_object(infop, flags);
95 } else if (infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE) {
96 flags = ACPIDEV_PROCESS_FLAG_SCAN;
97 rc = acpidev_process_object(infop, flags);
98 } else if (infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
99 flags = ACPIDEV_PROCESS_FLAG_SCAN | ACPIDEV_PROCESS_FLAG_CREATE;
100 rc = acpidev_process_object(infop, flags);
101 } else {
102 ACPIDEV_DEBUG(CE_WARN,
103 "acpidev: unknown operation type %u in memory_probe.",
104 infop->awi_op_type);
105 rc = AE_BAD_PARAMETER;
106 }
107 if (ACPI_FAILURE(rc) && rc != AE_NOT_EXIST && rc != AE_ALREADY_EXISTS) {
108 cmn_err(CE_CONT,
109 "acpidev: failed to process memory object %s.\n",
110 infop->awi_name);
111 } else {
112 rc = AE_OK;
113 }
114
115 return (rc);
116 }
117
118 static acpidev_filter_result_t
119 acpidev_memory_filter(acpidev_walk_info_t *infop, char *devname, int maxlen)
120 {
121 acpidev_filter_result_t res;
122
123 ASSERT(infop != NULL);
124 if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE ||
125 infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE ||
126 infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
127 res = acpidev_filter_device(infop, infop->awi_hdl,
128 ACPIDEV_ARRAY_PARAM(acpidev_memory_filters),
129 devname, maxlen);
130 } else {
131 res = ACPIDEV_FILTER_FAILED;
132 }
133
134 return (res);
135 }
136
137 /*ARGSUSED*/
138 static ACPI_STATUS
139 acpidev_memory_init(acpidev_walk_info_t *infop)
140 {
141 char *compatibles[] = {
142 ACPIDEV_TYPE_MEMORY,
143 "mem"
144 };
145
146 ASSERT(infop != NULL);
147 ASSERT(infop->awi_hdl != NULL);
148 ASSERT(infop->awi_dip != NULL);
149 if (ACPI_FAILURE(acpidev_resource_process(infop, B_TRUE))) {
150 cmn_err(CE_WARN,
151 "acpidev: failed to process resources of memory device %s.",
152 infop->awi_name);
153 return (AE_ERROR);
154 }
155
156 if (ACPI_FAILURE(acpidev_set_compatibles(infop,
157 ACPIDEV_ARRAY_PARAM(compatibles)))) {
158 return (AE_ERROR);
159 }
160
161 if (ACPI_FAILURE(acpidev_set_unitaddr(infop,
162 ACPIDEV_ARRAY_PARAM(acpidev_memory_uid_formats), NULL))) {
163 return (AE_ERROR);
164 }
165
166 return (AE_OK);
167 }