xref: /illumos-gate/usr/src/uts/i86pc/io/acpi/acpidev/acpidev_memory.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2009, Intel Corporation.
23  * All rights reserved.
24  */
25 
26 #include <sys/types.h>
27 #include <sys/atomic.h>
28 #include <sys/sunddi.h>
29 #include <sys/sunndi.h>
30 #include <sys/acpi/acpi.h>
31 #include <sys/acpica.h>
32 #include <sys/acpidev.h>
33 #include <sys/acpidev_rsc.h>
34 #include <sys/acpidev_impl.h>
35 
36 static ACPI_STATUS acpidev_memory_probe(acpidev_walk_info_t *infop);
37 static acpidev_filter_result_t acpidev_memory_filter(
38     acpidev_walk_info_t *infop, char *devname, int maxlen);
39 static ACPI_STATUS acpidev_memory_init(acpidev_walk_info_t *infop);
40 
41 /*
42  * Default class driver for ACPI memory objects.
43  */
44 acpidev_class_t acpidev_class_memory = {
45 	0,				/* adc_refcnt */
46 	ACPIDEV_CLASS_REV1,		/* adc_version */
47 	ACPIDEV_CLASS_ID_MEMORY,	/* adc_class_id */
48 	"ACPI memory",			/* adc_class_name */
49 	ACPIDEV_TYPE_MEMORY,		/* adc_dev_type */
50 	NULL,				/* adc_private */
51 	NULL,				/* adc_pre_probe */
52 	NULL,				/* adc_post_probe */
53 	acpidev_memory_probe,		/* adc_probe */
54 	acpidev_memory_filter,		/* adc_filter */
55 	acpidev_memory_init,		/* adc_init */
56 	NULL,				/* adc_fini */
57 };
58 
59 /*
60  * List of class drivers which will be called in order when handling
61  * children of ACPI memory objects.
62  */
63 acpidev_class_list_t *acpidev_class_list_memory = NULL;
64 
65 static char *acpidev_memory_device_ids[] = {
66 	ACPIDEV_HID_MEMORY,
67 };
68 
69 static char *acpidev_memory_uid_formats[] = {
70 	"MEM%x-%x",
71 };
72 
73 /* Filter rule table for memory objects. */
74 static acpidev_filter_rule_t acpidev_memory_filters[] = {
75 	{	/* Ignore all memory objects under the ACPI root object */
76 		NULL,
77 		0,
78 		ACPIDEV_FILTER_SKIP,
79 		NULL,
80 		1,
81 		1,
82 		NULL,
83 		NULL,
84 	},
85 	{	/* Create node and scan child for all other memory objects */
86 		NULL,
87 		0,
88 		ACPIDEV_FILTER_DEFAULT,
89 		&acpidev_class_list_device,
90 		2,
91 		INT_MAX,
92 		NULL,
93 		ACPIDEV_NODE_NAME_MEMORY,
94 	}
95 };
96 
97 static ACPI_STATUS
98 acpidev_memory_probe(acpidev_walk_info_t *infop)
99 {
100 	ACPI_STATUS rc;
101 	int flags;
102 
103 	ASSERT(infop != NULL);
104 	ASSERT(infop->awi_hdl != NULL);
105 	ASSERT(infop->awi_info != NULL);
106 	if (infop->awi_info->Type != ACPI_TYPE_DEVICE ||
107 	    acpidev_match_device_id(infop->awi_info,
108 	    ACPIDEV_ARRAY_PARAM(acpidev_memory_device_ids)) == 0) {
109 		return (AE_OK);
110 	}
111 
112 	if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE) {
113 		flags = ACPIDEV_PROCESS_FLAG_SCAN | ACPIDEV_PROCESS_FLAG_CREATE;
114 		rc = acpidev_process_object(infop, flags);
115 	} else if (infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE) {
116 		flags = ACPIDEV_PROCESS_FLAG_SCAN;
117 		rc = acpidev_process_object(infop, flags);
118 	} else if (infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
119 		flags = ACPIDEV_PROCESS_FLAG_SCAN | ACPIDEV_PROCESS_FLAG_CREATE;
120 		rc = acpidev_process_object(infop, flags);
121 	} else {
122 		ACPIDEV_DEBUG(CE_WARN, "acpidev: unknown operation type %u "
123 		    "in acpidev_memory_probe.", infop->awi_op_type);
124 		rc = AE_BAD_PARAMETER;
125 	}
126 	if (ACPI_FAILURE(rc) && rc != AE_NOT_EXIST && rc != AE_ALREADY_EXISTS) {
127 		cmn_err(CE_WARN,
128 		    "!acpidev: failed to process memory object %s.",
129 		    infop->awi_name);
130 	} else {
131 		rc = AE_OK;
132 	}
133 
134 	return (rc);
135 }
136 
137 static acpidev_filter_result_t
138 acpidev_memory_filter(acpidev_walk_info_t *infop, char *devname, int maxlen)
139 {
140 	acpidev_filter_result_t res;
141 
142 	ASSERT(infop != NULL);
143 	if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE ||
144 	    infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE ||
145 	    infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
146 		res = acpidev_filter_device(infop, infop->awi_hdl,
147 		    ACPIDEV_ARRAY_PARAM(acpidev_memory_filters),
148 		    devname, maxlen);
149 	} else {
150 		res = ACPIDEV_FILTER_FAILED;
151 	}
152 
153 	return (res);
154 }
155 
156 /*ARGSUSED*/
157 static ACPI_STATUS
158 acpidev_memory_init(acpidev_walk_info_t *infop)
159 {
160 	char *compatible[] = {
161 		ACPIDEV_TYPE_MEMORY,
162 		"mem"
163 	};
164 
165 	ASSERT(infop != NULL);
166 	ASSERT(infop->awi_hdl != NULL);
167 	ASSERT(infop->awi_dip != NULL);
168 	if (ACPI_FAILURE(acpidev_resource_process(infop, B_TRUE))) {
169 		cmn_err(CE_WARN, "!acpidev: failed to process resources of "
170 		    "memory device %s.", infop->awi_name);
171 		return (AE_ERROR);
172 	}
173 
174 	if (ACPI_FAILURE(acpidev_set_compatible(infop,
175 	    ACPIDEV_ARRAY_PARAM(compatible)))) {
176 		return (AE_ERROR);
177 	}
178 
179 	if (ACPI_FAILURE(acpidev_set_unitaddr(infop,
180 	    ACPIDEV_ARRAY_PARAM(acpidev_memory_uid_formats), NULL))) {
181 		return (AE_ERROR);
182 	}
183 
184 	return (AE_OK);
185 }
186