1*12004Sjiang.liu@intel.com /*
2*12004Sjiang.liu@intel.com * CDDL HEADER START
3*12004Sjiang.liu@intel.com *
4*12004Sjiang.liu@intel.com * The contents of this file are subject to the terms of the
5*12004Sjiang.liu@intel.com * Common Development and Distribution License (the "License").
6*12004Sjiang.liu@intel.com * You may not use this file except in compliance with the License.
7*12004Sjiang.liu@intel.com *
8*12004Sjiang.liu@intel.com * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*12004Sjiang.liu@intel.com * or http://www.opensolaris.org/os/licensing.
10*12004Sjiang.liu@intel.com * See the License for the specific language governing permissions
11*12004Sjiang.liu@intel.com * and limitations under the License.
12*12004Sjiang.liu@intel.com *
13*12004Sjiang.liu@intel.com * When distributing Covered Code, include this CDDL HEADER in each
14*12004Sjiang.liu@intel.com * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*12004Sjiang.liu@intel.com * If applicable, add the following below this CDDL HEADER, with the
16*12004Sjiang.liu@intel.com * fields enclosed by brackets "[]" replaced with your own identifying
17*12004Sjiang.liu@intel.com * information: Portions Copyright [yyyy] [name of copyright owner]
18*12004Sjiang.liu@intel.com *
19*12004Sjiang.liu@intel.com * CDDL HEADER END
20*12004Sjiang.liu@intel.com */
21*12004Sjiang.liu@intel.com
22*12004Sjiang.liu@intel.com /*
23*12004Sjiang.liu@intel.com * Copyright (c) 2010, Intel Corporation.
24*12004Sjiang.liu@intel.com * All rights reserved.
25*12004Sjiang.liu@intel.com */
26*12004Sjiang.liu@intel.com
27*12004Sjiang.liu@intel.com #include <sys/types.h>
28*12004Sjiang.liu@intel.com #include <sys/atomic.h>
29*12004Sjiang.liu@intel.com #include <sys/bitmap.h>
30*12004Sjiang.liu@intel.com #include <sys/cmn_err.h>
31*12004Sjiang.liu@intel.com #include <sys/note.h>
32*12004Sjiang.liu@intel.com #include <sys/sunndi.h>
33*12004Sjiang.liu@intel.com #include <sys/fastboot_impl.h>
34*12004Sjiang.liu@intel.com #include <sys/sysevent.h>
35*12004Sjiang.liu@intel.com #include <sys/sysevent/dr.h>
36*12004Sjiang.liu@intel.com #include <sys/sysevent/eventdefs.h>
37*12004Sjiang.liu@intel.com #include <sys/acpi/acpi.h>
38*12004Sjiang.liu@intel.com #include <sys/acpica.h>
39*12004Sjiang.liu@intel.com #include <sys/acpidev.h>
40*12004Sjiang.liu@intel.com #include <sys/acpidev_dr.h>
41*12004Sjiang.liu@intel.com #include <sys/acpinex.h>
42*12004Sjiang.liu@intel.com
43*12004Sjiang.liu@intel.com int acpinex_event_support_remove = 0;
44*12004Sjiang.liu@intel.com
45*12004Sjiang.liu@intel.com static volatile uint_t acpinex_dr_event_cnt = 0;
46*12004Sjiang.liu@intel.com static ulong_t acpinex_object_type_mask[BT_BITOUL(ACPI_TYPE_NS_NODE_MAX + 1)];
47*12004Sjiang.liu@intel.com
48*12004Sjiang.liu@intel.com /*
49*12004Sjiang.liu@intel.com * Generate DR_REQ event to syseventd.
50*12004Sjiang.liu@intel.com * Please refer to sys/sysevent/dr.h for message definition.
51*12004Sjiang.liu@intel.com */
52*12004Sjiang.liu@intel.com static int
acpinex_event_generate_event(dev_info_t * dip,ACPI_HANDLE hdl,int req,int event,char * objname)53*12004Sjiang.liu@intel.com acpinex_event_generate_event(dev_info_t *dip, ACPI_HANDLE hdl, int req,
54*12004Sjiang.liu@intel.com int event, char *objname)
55*12004Sjiang.liu@intel.com {
56*12004Sjiang.liu@intel.com int rv = 0;
57*12004Sjiang.liu@intel.com sysevent_id_t eid;
58*12004Sjiang.liu@intel.com sysevent_value_t evnt_val;
59*12004Sjiang.liu@intel.com sysevent_attr_list_t *evnt_attr_list = NULL;
60*12004Sjiang.liu@intel.com char *attach_pnt;
61*12004Sjiang.liu@intel.com char event_type[32];
62*12004Sjiang.liu@intel.com
63*12004Sjiang.liu@intel.com /* Add "attachment point" attribute. */
64*12004Sjiang.liu@intel.com attach_pnt = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
65*12004Sjiang.liu@intel.com if (ACPI_FAILURE(acpidev_dr_get_attachment_point(hdl,
66*12004Sjiang.liu@intel.com attach_pnt, MAXPATHLEN))) {
67*12004Sjiang.liu@intel.com cmn_err(CE_WARN,
68*12004Sjiang.liu@intel.com "!acpinex: failed to generate AP name for %s.", objname);
69*12004Sjiang.liu@intel.com kmem_free(attach_pnt, MAXPATHLEN);
70*12004Sjiang.liu@intel.com return (-1);
71*12004Sjiang.liu@intel.com }
72*12004Sjiang.liu@intel.com ASSERT(attach_pnt[0] != '\0');
73*12004Sjiang.liu@intel.com evnt_val.value_type = SE_DATA_TYPE_STRING;
74*12004Sjiang.liu@intel.com evnt_val.value.sv_string = attach_pnt;
75*12004Sjiang.liu@intel.com rv = sysevent_add_attr(&evnt_attr_list, DR_AP_ID, &evnt_val, KM_SLEEP);
76*12004Sjiang.liu@intel.com if (rv != 0) {
77*12004Sjiang.liu@intel.com cmn_err(CE_WARN,
78*12004Sjiang.liu@intel.com "!acpinex: failed to add attr [%s] for %s event.",
79*12004Sjiang.liu@intel.com DR_AP_ID, EC_DR);
80*12004Sjiang.liu@intel.com kmem_free(attach_pnt, MAXPATHLEN);
81*12004Sjiang.liu@intel.com return (rv);
82*12004Sjiang.liu@intel.com }
83*12004Sjiang.liu@intel.com
84*12004Sjiang.liu@intel.com /* Add "request type" attribute. */
85*12004Sjiang.liu@intel.com evnt_val.value_type = SE_DATA_TYPE_STRING;
86*12004Sjiang.liu@intel.com evnt_val.value.sv_string = SE_REQ2STR(req);
87*12004Sjiang.liu@intel.com rv = sysevent_add_attr(&evnt_attr_list, DR_REQ_TYPE, &evnt_val,
88*12004Sjiang.liu@intel.com KM_SLEEP);
89*12004Sjiang.liu@intel.com if (rv != 0) {
90*12004Sjiang.liu@intel.com cmn_err(CE_WARN,
91*12004Sjiang.liu@intel.com "!acpinex: failed to add attr [%s] for %s event.",
92*12004Sjiang.liu@intel.com DR_REQ_TYPE, EC_DR);
93*12004Sjiang.liu@intel.com sysevent_free_attr(evnt_attr_list);
94*12004Sjiang.liu@intel.com kmem_free(attach_pnt, MAXPATHLEN);
95*12004Sjiang.liu@intel.com return (rv);
96*12004Sjiang.liu@intel.com }
97*12004Sjiang.liu@intel.com
98*12004Sjiang.liu@intel.com /* Add "acpi-event-type" attribute. */
99*12004Sjiang.liu@intel.com switch (event) {
100*12004Sjiang.liu@intel.com case ACPI_NOTIFY_BUS_CHECK:
101*12004Sjiang.liu@intel.com (void) snprintf(event_type, sizeof (event_type),
102*12004Sjiang.liu@intel.com ACPIDEV_EVENT_TYPE_BUS_CHECK);
103*12004Sjiang.liu@intel.com break;
104*12004Sjiang.liu@intel.com case ACPI_NOTIFY_DEVICE_CHECK:
105*12004Sjiang.liu@intel.com (void) snprintf(event_type, sizeof (event_type),
106*12004Sjiang.liu@intel.com ACPIDEV_EVENT_TYPE_DEVICE_CHECK);
107*12004Sjiang.liu@intel.com break;
108*12004Sjiang.liu@intel.com case ACPI_NOTIFY_DEVICE_CHECK_LIGHT:
109*12004Sjiang.liu@intel.com (void) snprintf(event_type, sizeof (event_type),
110*12004Sjiang.liu@intel.com ACPIDEV_EVENT_TYPE_DEVICE_CHECK_LIGHT);
111*12004Sjiang.liu@intel.com break;
112*12004Sjiang.liu@intel.com case ACPI_NOTIFY_EJECT_REQUEST:
113*12004Sjiang.liu@intel.com (void) snprintf(event_type, sizeof (event_type),
114*12004Sjiang.liu@intel.com ACPIDEV_EVENT_TYPE_EJECT_REQUEST);
115*12004Sjiang.liu@intel.com break;
116*12004Sjiang.liu@intel.com default:
117*12004Sjiang.liu@intel.com cmn_err(CE_WARN,
118*12004Sjiang.liu@intel.com "!acpinex: unknown ACPI event type %d.", event);
119*12004Sjiang.liu@intel.com sysevent_free_attr(evnt_attr_list);
120*12004Sjiang.liu@intel.com kmem_free(attach_pnt, MAXPATHLEN);
121*12004Sjiang.liu@intel.com return (-1);
122*12004Sjiang.liu@intel.com }
123*12004Sjiang.liu@intel.com evnt_val.value_type = SE_DATA_TYPE_STRING;
124*12004Sjiang.liu@intel.com evnt_val.value.sv_string = event_type;
125*12004Sjiang.liu@intel.com rv = sysevent_add_attr(&evnt_attr_list, ACPIDEV_EVENT_TYPE_ATTR_NAME,
126*12004Sjiang.liu@intel.com &evnt_val, KM_SLEEP);
127*12004Sjiang.liu@intel.com if (rv != 0) {
128*12004Sjiang.liu@intel.com cmn_err(CE_WARN,
129*12004Sjiang.liu@intel.com "!acpinex: failed to add attr [%s] for %s event.",
130*12004Sjiang.liu@intel.com ACPIDEV_EVENT_TYPE_ATTR_NAME, EC_DR);
131*12004Sjiang.liu@intel.com sysevent_free_attr(evnt_attr_list);
132*12004Sjiang.liu@intel.com kmem_free(attach_pnt, MAXPATHLEN);
133*12004Sjiang.liu@intel.com return (rv);
134*12004Sjiang.liu@intel.com }
135*12004Sjiang.liu@intel.com
136*12004Sjiang.liu@intel.com rv = ddi_log_sysevent(dip, DDI_VENDOR_SUNW, EC_DR, ESC_DR_REQ,
137*12004Sjiang.liu@intel.com evnt_attr_list, &eid, KM_SLEEP);
138*12004Sjiang.liu@intel.com if (rv != DDI_SUCCESS) {
139*12004Sjiang.liu@intel.com cmn_err(CE_WARN,
140*12004Sjiang.liu@intel.com "!acpinex: failed to log DR_REQ event for %s.", objname);
141*12004Sjiang.liu@intel.com rv = -1;
142*12004Sjiang.liu@intel.com }
143*12004Sjiang.liu@intel.com
144*12004Sjiang.liu@intel.com nvlist_free(evnt_attr_list);
145*12004Sjiang.liu@intel.com kmem_free(attach_pnt, MAXPATHLEN);
146*12004Sjiang.liu@intel.com
147*12004Sjiang.liu@intel.com return (rv);
148*12004Sjiang.liu@intel.com }
149*12004Sjiang.liu@intel.com
150*12004Sjiang.liu@intel.com /*
151*12004Sjiang.liu@intel.com * Event handler for ACPI EJECT_REQUEST notifications.
152*12004Sjiang.liu@intel.com * EJECT_REQUEST notifications should be generated on the device to be ejected,
153*12004Sjiang.liu@intel.com * so no need to scan subtree of it.
154*12004Sjiang.liu@intel.com * It also invokes ACPI _OST method to update event status if call_ost is true.
155*12004Sjiang.liu@intel.com */
156*12004Sjiang.liu@intel.com static void
acpinex_event_handle_eject_request(ACPI_HANDLE hdl,acpinex_softstate_t * sp,boolean_t call_ost)157*12004Sjiang.liu@intel.com acpinex_event_handle_eject_request(ACPI_HANDLE hdl, acpinex_softstate_t *sp,
158*12004Sjiang.liu@intel.com boolean_t call_ost)
159*12004Sjiang.liu@intel.com {
160*12004Sjiang.liu@intel.com int code;
161*12004Sjiang.liu@intel.com char *objname;
162*12004Sjiang.liu@intel.com
163*12004Sjiang.liu@intel.com ASSERT(hdl != NULL);
164*12004Sjiang.liu@intel.com objname = acpidev_get_object_name(hdl);
165*12004Sjiang.liu@intel.com
166*12004Sjiang.liu@intel.com ASSERT(sp != NULL);
167*12004Sjiang.liu@intel.com ASSERT(sp->ans_dip != NULL && sp->ans_hdl != NULL);
168*12004Sjiang.liu@intel.com if (sp == NULL || sp->ans_dip == NULL || sp->ans_hdl == NULL) {
169*12004Sjiang.liu@intel.com if (call_ost) {
170*12004Sjiang.liu@intel.com (void) acpidev_eval_ost(hdl, ACPI_NOTIFY_EJECT_REQUEST,
171*12004Sjiang.liu@intel.com ACPI_OST_STA_FAILURE, NULL, 0);
172*12004Sjiang.liu@intel.com }
173*12004Sjiang.liu@intel.com ACPINEX_DEBUG(CE_WARN,
174*12004Sjiang.liu@intel.com "!acpinex: softstate data structure is invalid.");
175*12004Sjiang.liu@intel.com cmn_err(CE_WARN,
176*12004Sjiang.liu@intel.com "!acpinex: failed to handle EJECT_REQUEST event from %s.",
177*12004Sjiang.liu@intel.com objname);
178*12004Sjiang.liu@intel.com acpidev_free_object_name(objname);
179*12004Sjiang.liu@intel.com return;
180*12004Sjiang.liu@intel.com }
181*12004Sjiang.liu@intel.com
182*12004Sjiang.liu@intel.com if (acpinex_event_support_remove == 0) {
183*12004Sjiang.liu@intel.com cmn_err(CE_WARN,
184*12004Sjiang.liu@intel.com "!acpinex: hot-removing of device %s is unsupported.",
185*12004Sjiang.liu@intel.com objname);
186*12004Sjiang.liu@intel.com code = ACPI_OST_STA_EJECT_NOT_SUPPORT;
187*12004Sjiang.liu@intel.com } else if (acpinex_event_generate_event(sp->ans_dip, hdl,
188*12004Sjiang.liu@intel.com SE_OUTGOING_RES, ACPI_NOTIFY_EJECT_REQUEST, objname) != 0) {
189*12004Sjiang.liu@intel.com cmn_err(CE_WARN, "!acpinex: failed to generate ESC_DR_REQ "
190*12004Sjiang.liu@intel.com "event for device eject request from %s.", objname);
191*12004Sjiang.liu@intel.com code = ACPI_OST_STA_FAILURE;
192*12004Sjiang.liu@intel.com } else {
193*12004Sjiang.liu@intel.com cmn_err(CE_NOTE, "!acpinex: generate ESC_DR_REQ event for "
194*12004Sjiang.liu@intel.com "device eject request from %s.", objname);
195*12004Sjiang.liu@intel.com code = ACPI_OST_STA_EJECT_IN_PROGRESS;
196*12004Sjiang.liu@intel.com }
197*12004Sjiang.liu@intel.com if (call_ost) {
198*12004Sjiang.liu@intel.com (void) acpidev_eval_ost(hdl, ACPI_NOTIFY_EJECT_REQUEST,
199*12004Sjiang.liu@intel.com code, NULL, 0);
200*12004Sjiang.liu@intel.com }
201*12004Sjiang.liu@intel.com
202*12004Sjiang.liu@intel.com acpidev_free_object_name(objname);
203*12004Sjiang.liu@intel.com }
204*12004Sjiang.liu@intel.com
205*12004Sjiang.liu@intel.com struct acpinex_event_check_arg {
206*12004Sjiang.liu@intel.com acpinex_softstate_t *softstatep;
207*12004Sjiang.liu@intel.com int event_type;
208*12004Sjiang.liu@intel.com uint32_t device_insert;
209*12004Sjiang.liu@intel.com uint32_t device_remove;
210*12004Sjiang.liu@intel.com uint32_t device_fail;
211*12004Sjiang.liu@intel.com };
212*12004Sjiang.liu@intel.com
213*12004Sjiang.liu@intel.com static ACPI_STATUS
acpinex_event_handle_check_one(ACPI_HANDLE hdl,UINT32 lvl,void * ctx,void ** retval)214*12004Sjiang.liu@intel.com acpinex_event_handle_check_one(ACPI_HANDLE hdl, UINT32 lvl, void *ctx,
215*12004Sjiang.liu@intel.com void **retval)
216*12004Sjiang.liu@intel.com {
217*12004Sjiang.liu@intel.com _NOTE(ARGUNUSED(lvl, retval));
218*12004Sjiang.liu@intel.com
219*12004Sjiang.liu@intel.com char *objname;
220*12004Sjiang.liu@intel.com int status, psta, csta;
221*12004Sjiang.liu@intel.com acpidev_data_handle_t dhdl;
222*12004Sjiang.liu@intel.com struct acpinex_event_check_arg *argp;
223*12004Sjiang.liu@intel.com
224*12004Sjiang.liu@intel.com ASSERT(hdl != NULL);
225*12004Sjiang.liu@intel.com ASSERT(ctx != NULL);
226*12004Sjiang.liu@intel.com argp = (struct acpinex_event_check_arg *)ctx;
227*12004Sjiang.liu@intel.com
228*12004Sjiang.liu@intel.com dhdl = acpidev_data_get_handle(hdl);
229*12004Sjiang.liu@intel.com if (dhdl == NULL) {
230*12004Sjiang.liu@intel.com /* Skip subtree if failed to get the data handle. */
231*12004Sjiang.liu@intel.com ACPINEX_DEBUG(CE_NOTE,
232*12004Sjiang.liu@intel.com "!acpinex: failed to get data associated with %p.", hdl);
233*12004Sjiang.liu@intel.com return (AE_CTRL_DEPTH);
234*12004Sjiang.liu@intel.com } else if (!acpidev_data_dr_capable(dhdl)) {
235*12004Sjiang.liu@intel.com return (AE_OK);
236*12004Sjiang.liu@intel.com }
237*12004Sjiang.liu@intel.com
238*12004Sjiang.liu@intel.com objname = acpidev_get_object_name(hdl);
239*12004Sjiang.liu@intel.com
240*12004Sjiang.liu@intel.com status = 0;
241*12004Sjiang.liu@intel.com /* Query previous device status. */
242*12004Sjiang.liu@intel.com psta = acpidev_data_get_status(dhdl);
243*12004Sjiang.liu@intel.com if (acpidev_check_device_enabled(psta)) {
244*12004Sjiang.liu@intel.com status |= 0x1;
245*12004Sjiang.liu@intel.com }
246*12004Sjiang.liu@intel.com /* Query current device status. */
247*12004Sjiang.liu@intel.com csta = acpidev_query_device_status(hdl);
248*12004Sjiang.liu@intel.com if (acpidev_check_device_enabled(csta)) {
249*12004Sjiang.liu@intel.com status |= 0x2;
250*12004Sjiang.liu@intel.com }
251*12004Sjiang.liu@intel.com
252*12004Sjiang.liu@intel.com switch (status) {
253*12004Sjiang.liu@intel.com case 0x0:
254*12004Sjiang.liu@intel.com /*FALLTHROUGH*/
255*12004Sjiang.liu@intel.com case 0x3:
256*12004Sjiang.liu@intel.com /* No status changes, keep on walking. */
257*12004Sjiang.liu@intel.com acpidev_free_object_name(objname);
258*12004Sjiang.liu@intel.com return (AE_OK);
259*12004Sjiang.liu@intel.com
260*12004Sjiang.liu@intel.com case 0x1:
261*12004Sjiang.liu@intel.com /* Surprising removal. */
262*12004Sjiang.liu@intel.com cmn_err(CE_WARN,
263*12004Sjiang.liu@intel.com "!acpinex: device %s has been surprisingly removed.",
264*12004Sjiang.liu@intel.com objname);
265*12004Sjiang.liu@intel.com if (argp->event_type == ACPI_NOTIFY_BUS_CHECK) {
266*12004Sjiang.liu@intel.com /*
267*12004Sjiang.liu@intel.com * According to ACPI spec, BUS_CHECK notification
268*12004Sjiang.liu@intel.com * should be triggered for hot-adding events only.
269*12004Sjiang.liu@intel.com */
270*12004Sjiang.liu@intel.com ACPINEX_DEBUG(CE_WARN,
271*12004Sjiang.liu@intel.com "!acpinex: device %s has been surprisingly removed "
272*12004Sjiang.liu@intel.com "when handling BUS_CHECK event.", objname);
273*12004Sjiang.liu@intel.com }
274*12004Sjiang.liu@intel.com acpidev_free_object_name(objname);
275*12004Sjiang.liu@intel.com argp->device_remove++;
276*12004Sjiang.liu@intel.com return (AE_CTRL_DEPTH);
277*12004Sjiang.liu@intel.com
278*12004Sjiang.liu@intel.com case 0x2:
279*12004Sjiang.liu@intel.com /* Hot-adding. */
280*12004Sjiang.liu@intel.com ACPINEX_DEBUG(CE_NOTE,
281*12004Sjiang.liu@intel.com "!acpinex: device %s has been inserted.", objname);
282*12004Sjiang.liu@intel.com argp->device_insert++;
283*12004Sjiang.liu@intel.com if (acpinex_event_generate_event(argp->softstatep->ans_dip, hdl,
284*12004Sjiang.liu@intel.com SE_INCOMING_RES, argp->event_type, objname) != 0) {
285*12004Sjiang.liu@intel.com cmn_err(CE_WARN,
286*12004Sjiang.liu@intel.com "!acpinex: failed to generate ESC_DR_REQ event for "
287*12004Sjiang.liu@intel.com "device insert request from %s.", objname);
288*12004Sjiang.liu@intel.com argp->device_fail++;
289*12004Sjiang.liu@intel.com } else {
290*12004Sjiang.liu@intel.com cmn_err(CE_NOTE, "!acpinex: generate ESC_DR_REQ event "
291*12004Sjiang.liu@intel.com "for device insert request from %s.", objname);
292*12004Sjiang.liu@intel.com }
293*12004Sjiang.liu@intel.com acpidev_free_object_name(objname);
294*12004Sjiang.liu@intel.com return (AE_OK);
295*12004Sjiang.liu@intel.com
296*12004Sjiang.liu@intel.com default:
297*12004Sjiang.liu@intel.com ASSERT(0);
298*12004Sjiang.liu@intel.com break;
299*12004Sjiang.liu@intel.com }
300*12004Sjiang.liu@intel.com
301*12004Sjiang.liu@intel.com return (AE_ERROR);
302*12004Sjiang.liu@intel.com }
303*12004Sjiang.liu@intel.com
304*12004Sjiang.liu@intel.com /*
305*12004Sjiang.liu@intel.com * Event handler for BUS_CHECK/DEVICE_CHECK/DEVICE_CHECK_LIGHT notifications.
306*12004Sjiang.liu@intel.com * These events may be signaled on parent/ancestor of devices to be hot-added,
307*12004Sjiang.liu@intel.com * so need to scan ACPI namespace to figure out devices in question.
308*12004Sjiang.liu@intel.com * It also invokes ACPI _OST method to update event status if call_ost is true.
309*12004Sjiang.liu@intel.com */
310*12004Sjiang.liu@intel.com static void
acpinex_event_handle_check_request(int event,ACPI_HANDLE hdl,acpinex_softstate_t * sp,boolean_t call_ost)311*12004Sjiang.liu@intel.com acpinex_event_handle_check_request(int event, ACPI_HANDLE hdl,
312*12004Sjiang.liu@intel.com acpinex_softstate_t *sp, boolean_t call_ost)
313*12004Sjiang.liu@intel.com {
314*12004Sjiang.liu@intel.com ACPI_STATUS rv;
315*12004Sjiang.liu@intel.com int code;
316*12004Sjiang.liu@intel.com char *objname;
317*12004Sjiang.liu@intel.com struct acpinex_event_check_arg arg;
318*12004Sjiang.liu@intel.com
319*12004Sjiang.liu@intel.com ASSERT(hdl != NULL);
320*12004Sjiang.liu@intel.com objname = acpidev_get_object_name(hdl);
321*12004Sjiang.liu@intel.com
322*12004Sjiang.liu@intel.com ASSERT(sp != NULL);
323*12004Sjiang.liu@intel.com ASSERT(sp->ans_dip != NULL && sp->ans_hdl != NULL);
324*12004Sjiang.liu@intel.com if (sp == NULL || sp->ans_dip == NULL || sp->ans_hdl == NULL) {
325*12004Sjiang.liu@intel.com if (call_ost) {
326*12004Sjiang.liu@intel.com (void) acpidev_eval_ost(hdl, event,
327*12004Sjiang.liu@intel.com ACPI_OST_STA_FAILURE, NULL, 0);
328*12004Sjiang.liu@intel.com }
329*12004Sjiang.liu@intel.com ACPINEX_DEBUG(CE_WARN,
330*12004Sjiang.liu@intel.com "!acpinex: softstate data structure is invalid.");
331*12004Sjiang.liu@intel.com cmn_err(CE_WARN, "!acpinex: failed to handle "
332*12004Sjiang.liu@intel.com "BUS/DEVICE_CHECK event from %s.", objname);
333*12004Sjiang.liu@intel.com acpidev_free_object_name(objname);
334*12004Sjiang.liu@intel.com return;
335*12004Sjiang.liu@intel.com }
336*12004Sjiang.liu@intel.com
337*12004Sjiang.liu@intel.com bzero(&arg, sizeof (arg));
338*12004Sjiang.liu@intel.com arg.event_type = event;
339*12004Sjiang.liu@intel.com arg.softstatep = sp;
340*12004Sjiang.liu@intel.com rv = acpinex_event_handle_check_one(hdl, 0, &arg, NULL);
341*12004Sjiang.liu@intel.com if (ACPI_SUCCESS(rv)) {
342*12004Sjiang.liu@intel.com rv = AcpiWalkNamespace(ACPI_TYPE_DEVICE, hdl,
343*12004Sjiang.liu@intel.com ACPIDEV_MAX_ENUM_LEVELS,
344*12004Sjiang.liu@intel.com &acpinex_event_handle_check_one, NULL, &arg, NULL);
345*12004Sjiang.liu@intel.com }
346*12004Sjiang.liu@intel.com
347*12004Sjiang.liu@intel.com if (ACPI_FAILURE(rv)) {
348*12004Sjiang.liu@intel.com /* Failed to scan the ACPI namespace. */
349*12004Sjiang.liu@intel.com cmn_err(CE_WARN, "!acpinex: failed to handle event %d from %s.",
350*12004Sjiang.liu@intel.com event, objname);
351*12004Sjiang.liu@intel.com code = ACPI_OST_STA_FAILURE;
352*12004Sjiang.liu@intel.com } else if (arg.device_remove != 0) {
353*12004Sjiang.liu@intel.com /* Surprising removal happened. */
354*12004Sjiang.liu@intel.com ACPINEX_DEBUG(CE_WARN,
355*12004Sjiang.liu@intel.com "!acpinex: some devices have been surprisingly removed.");
356*12004Sjiang.liu@intel.com code = ACPI_OST_STA_NOT_SUPPORT;
357*12004Sjiang.liu@intel.com } else if (arg.device_fail != 0) {
358*12004Sjiang.liu@intel.com /* Failed to handle some devices. */
359*12004Sjiang.liu@intel.com ACPINEX_DEBUG(CE_WARN,
360*12004Sjiang.liu@intel.com "!acpinex: failed to check status of some devices.");
361*12004Sjiang.liu@intel.com code = ACPI_OST_STA_FAILURE;
362*12004Sjiang.liu@intel.com } else if (arg.device_insert == 0) {
363*12004Sjiang.liu@intel.com /* No hot-added devices found. */
364*12004Sjiang.liu@intel.com cmn_err(CE_WARN,
365*12004Sjiang.liu@intel.com "!acpinex: no hot-added devices under %s found.", objname);
366*12004Sjiang.liu@intel.com code = ACPI_OST_STA_FAILURE;
367*12004Sjiang.liu@intel.com } else {
368*12004Sjiang.liu@intel.com code = ACPI_OST_STA_INSERT_IN_PROGRESS;
369*12004Sjiang.liu@intel.com }
370*12004Sjiang.liu@intel.com if (call_ost) {
371*12004Sjiang.liu@intel.com (void) acpidev_eval_ost(hdl, event, code, NULL, 0);
372*12004Sjiang.liu@intel.com }
373*12004Sjiang.liu@intel.com
374*12004Sjiang.liu@intel.com acpidev_free_object_name(objname);
375*12004Sjiang.liu@intel.com }
376*12004Sjiang.liu@intel.com
377*12004Sjiang.liu@intel.com static void
acpinex_event_system_handler(ACPI_HANDLE hdl,UINT32 type,void * arg)378*12004Sjiang.liu@intel.com acpinex_event_system_handler(ACPI_HANDLE hdl, UINT32 type, void *arg)
379*12004Sjiang.liu@intel.com {
380*12004Sjiang.liu@intel.com acpinex_softstate_t *sp;
381*12004Sjiang.liu@intel.com
382*12004Sjiang.liu@intel.com ASSERT(hdl != NULL);
383*12004Sjiang.liu@intel.com ASSERT(arg != NULL);
384*12004Sjiang.liu@intel.com sp = (acpinex_softstate_t *)arg;
385*12004Sjiang.liu@intel.com
386*12004Sjiang.liu@intel.com acpidev_dr_lock_all();
387*12004Sjiang.liu@intel.com mutex_enter(&sp->ans_lock);
388*12004Sjiang.liu@intel.com
389*12004Sjiang.liu@intel.com switch (type) {
390*12004Sjiang.liu@intel.com case ACPI_NOTIFY_BUS_CHECK:
391*12004Sjiang.liu@intel.com /*
392*12004Sjiang.liu@intel.com * Bus Check. This notification is performed on a device object
393*12004Sjiang.liu@intel.com * to indicate to OSPM that it needs to perform the Plug and
394*12004Sjiang.liu@intel.com * Play re-enumeration operation on the device tree starting
395*12004Sjiang.liu@intel.com * from the point where it has been notified. OSPM will only
396*12004Sjiang.liu@intel.com * perform this operation at boot, and when notified. It is
397*12004Sjiang.liu@intel.com * the responsibility of the ACPI AML code to notify OSPM at
398*12004Sjiang.liu@intel.com * any other times that this operation is required. The more
399*12004Sjiang.liu@intel.com * accurately and closer to the actual device tree change the
400*12004Sjiang.liu@intel.com * notification can be done, the more efficient the operating
401*12004Sjiang.liu@intel.com * system response will be; however, it can also be an issue
402*12004Sjiang.liu@intel.com * when a device change cannot be confirmed. For example, if
403*12004Sjiang.liu@intel.com * the hardware cannot notice a device change for a particular
404*12004Sjiang.liu@intel.com * location during a system sleeping state, it issues a Bus
405*12004Sjiang.liu@intel.com * Check notification on wake to inform OSPM that it needs to
406*12004Sjiang.liu@intel.com * check the configuration for a device change.
407*12004Sjiang.liu@intel.com */
408*12004Sjiang.liu@intel.com /*FALLTHROUGH*/
409*12004Sjiang.liu@intel.com case ACPI_NOTIFY_DEVICE_CHECK:
410*12004Sjiang.liu@intel.com /*
411*12004Sjiang.liu@intel.com * Device Check. Used to notify OSPM that the device either
412*12004Sjiang.liu@intel.com * appeared or disappeared. If the device has appeared, OSPM
413*12004Sjiang.liu@intel.com * will re-enumerate from the parent. If the device has
414*12004Sjiang.liu@intel.com * disappeared, OSPM will invalidate the state of the device.
415*12004Sjiang.liu@intel.com * OSPM may optimize out re-enumeration. If _DCK is present,
416*12004Sjiang.liu@intel.com * then Notify(object,1) is assumed to indicate an undock
417*12004Sjiang.liu@intel.com * request.
418*12004Sjiang.liu@intel.com */
419*12004Sjiang.liu@intel.com /*FALLTHROUGH*/
420*12004Sjiang.liu@intel.com case ACPI_NOTIFY_DEVICE_CHECK_LIGHT:
421*12004Sjiang.liu@intel.com /*
422*12004Sjiang.liu@intel.com * Device Check Light. Used to notify OSPM that the device
423*12004Sjiang.liu@intel.com * either appeared or disappeared. If the device has appeared,
424*12004Sjiang.liu@intel.com * OSPM will re-enumerate from the device itself, not the
425*12004Sjiang.liu@intel.com * parent. If the device has disappeared, OSPM will invalidate
426*12004Sjiang.liu@intel.com * the state of the device.
427*12004Sjiang.liu@intel.com */
428*12004Sjiang.liu@intel.com atomic_inc_uint(&acpinex_dr_event_cnt);
429*12004Sjiang.liu@intel.com acpinex_event_handle_check_request(type, hdl, sp, B_TRUE);
430*12004Sjiang.liu@intel.com break;
431*12004Sjiang.liu@intel.com
432*12004Sjiang.liu@intel.com case ACPI_NOTIFY_EJECT_REQUEST:
433*12004Sjiang.liu@intel.com /*
434*12004Sjiang.liu@intel.com * Eject Request. Used to notify OSPM that the device should
435*12004Sjiang.liu@intel.com * be ejected, and that OSPM needs to perform the Plug and Play
436*12004Sjiang.liu@intel.com * ejection operation. OSPM will run the _EJx method.
437*12004Sjiang.liu@intel.com */
438*12004Sjiang.liu@intel.com atomic_inc_uint(&acpinex_dr_event_cnt);
439*12004Sjiang.liu@intel.com acpinex_event_handle_eject_request(hdl, sp, B_TRUE);
440*12004Sjiang.liu@intel.com break;
441*12004Sjiang.liu@intel.com
442*12004Sjiang.liu@intel.com default:
443*12004Sjiang.liu@intel.com ACPINEX_DEBUG(CE_NOTE,
444*12004Sjiang.liu@intel.com "!acpinex: unhandled event(%d) on hdl %p under %s.",
445*12004Sjiang.liu@intel.com type, hdl, sp->ans_path);
446*12004Sjiang.liu@intel.com (void) acpidev_eval_ost(hdl, type, ACPI_OST_STA_NOT_SUPPORT,
447*12004Sjiang.liu@intel.com NULL, 0);
448*12004Sjiang.liu@intel.com break;
449*12004Sjiang.liu@intel.com }
450*12004Sjiang.liu@intel.com
451*12004Sjiang.liu@intel.com if (acpinex_dr_event_cnt != 0) {
452*12004Sjiang.liu@intel.com /*
453*12004Sjiang.liu@intel.com * Disable fast reboot if a CPU/MEM/IOH hotplug event happens.
454*12004Sjiang.liu@intel.com * Note: this is a temporary solution and will be revised when
455*12004Sjiang.liu@intel.com * fast reboot can support CPU/MEM/IOH DR operations in the
456*12004Sjiang.liu@intel.com * future.
457*12004Sjiang.liu@intel.com *
458*12004Sjiang.liu@intel.com * ACPI BIOS generates some static ACPI tables, such as MADT,
459*12004Sjiang.liu@intel.com * SRAT and SLIT, to describe the system hardware configuration
460*12004Sjiang.liu@intel.com * on power-on. When a CPU/MEM/IOH hotplug event happens, those
461*12004Sjiang.liu@intel.com * static tables won't be updated and will become stale.
462*12004Sjiang.liu@intel.com *
463*12004Sjiang.liu@intel.com * If we reset the system by fast reboot, BIOS will have no
464*12004Sjiang.liu@intel.com * chance to regenerate those staled static tables. Fast reboot
465*12004Sjiang.liu@intel.com * can't tolerate such inconsistency between staled ACPI tables
466*12004Sjiang.liu@intel.com * and real hardware configuration yet.
467*12004Sjiang.liu@intel.com *
468*12004Sjiang.liu@intel.com * A temporary solution is introduced to disable fast reboot if
469*12004Sjiang.liu@intel.com * CPU/MEM/IOH hotplug event happens. This solution should be
470*12004Sjiang.liu@intel.com * revised when fast reboot is enhanced to support CPU/MEM/IOH
471*12004Sjiang.liu@intel.com * DR operations.
472*12004Sjiang.liu@intel.com */
473*12004Sjiang.liu@intel.com fastreboot_disable(FBNS_HOTPLUG);
474*12004Sjiang.liu@intel.com }
475*12004Sjiang.liu@intel.com
476*12004Sjiang.liu@intel.com mutex_exit(&sp->ans_lock);
477*12004Sjiang.liu@intel.com acpidev_dr_unlock_all();
478*12004Sjiang.liu@intel.com }
479*12004Sjiang.liu@intel.com
480*12004Sjiang.liu@intel.com /*
481*12004Sjiang.liu@intel.com * Install event handler for ACPI system events.
482*12004Sjiang.liu@intel.com * Acpinex driver handles ACPI system events for its children,
483*12004Sjiang.liu@intel.com * device specific events will be handled by device drivers.
484*12004Sjiang.liu@intel.com * Return DDI_SUCCESS on success, and DDI_FAILURE on failure.
485*12004Sjiang.liu@intel.com */
486*12004Sjiang.liu@intel.com static int
acpinex_event_install_handler(ACPI_HANDLE hdl,void * arg,ACPI_DEVICE_INFO * infop,acpidev_data_handle_t dhdl)487*12004Sjiang.liu@intel.com acpinex_event_install_handler(ACPI_HANDLE hdl, void *arg,
488*12004Sjiang.liu@intel.com ACPI_DEVICE_INFO *infop, acpidev_data_handle_t dhdl)
489*12004Sjiang.liu@intel.com {
490*12004Sjiang.liu@intel.com int rc = DDI_SUCCESS;
491*12004Sjiang.liu@intel.com
492*12004Sjiang.liu@intel.com ASSERT(hdl != NULL);
493*12004Sjiang.liu@intel.com ASSERT(dhdl != NULL);
494*12004Sjiang.liu@intel.com ASSERT(infop != NULL);
495*12004Sjiang.liu@intel.com
496*12004Sjiang.liu@intel.com /*
497*12004Sjiang.liu@intel.com * Check whether the event handler has already been installed on the
498*12004Sjiang.liu@intel.com * device object. With the introduction of ACPI Alias objects, which are
499*12004Sjiang.liu@intel.com * similar to symlinks in file systems, there may be multiple name
500*12004Sjiang.liu@intel.com * objects in the ACPI namespace pointing to the same underlying device
501*12004Sjiang.liu@intel.com * object. Those Alias objects need to be filtered out, otherwise
502*12004Sjiang.liu@intel.com * it will attempt to install the event handler multiple times on the
503*12004Sjiang.liu@intel.com * same device object which will fail.
504*12004Sjiang.liu@intel.com */
505*12004Sjiang.liu@intel.com if (acpidev_data_get_flag(dhdl, ACPIDEV_DATA_HANDLER_READY)) {
506*12004Sjiang.liu@intel.com return (DDI_SUCCESS);
507*12004Sjiang.liu@intel.com }
508*12004Sjiang.liu@intel.com if (ACPI_SUCCESS(AcpiInstallNotifyHandler(hdl, ACPI_SYSTEM_NOTIFY,
509*12004Sjiang.liu@intel.com acpinex_event_system_handler, arg))) {
510*12004Sjiang.liu@intel.com acpidev_data_set_flag(dhdl, ACPIDEV_DATA_HANDLER_READY);
511*12004Sjiang.liu@intel.com } else {
512*12004Sjiang.liu@intel.com char *objname;
513*12004Sjiang.liu@intel.com
514*12004Sjiang.liu@intel.com objname = acpidev_get_object_name(hdl);
515*12004Sjiang.liu@intel.com cmn_err(CE_WARN,
516*12004Sjiang.liu@intel.com "!acpinex: failed to install system event handler for %s.",
517*12004Sjiang.liu@intel.com objname);
518*12004Sjiang.liu@intel.com acpidev_free_object_name(objname);
519*12004Sjiang.liu@intel.com rc = DDI_FAILURE;
520*12004Sjiang.liu@intel.com }
521*12004Sjiang.liu@intel.com
522*12004Sjiang.liu@intel.com return (rc);
523*12004Sjiang.liu@intel.com }
524*12004Sjiang.liu@intel.com
525*12004Sjiang.liu@intel.com /*
526*12004Sjiang.liu@intel.com * Uninstall event handler for ACPI system events.
527*12004Sjiang.liu@intel.com * Return DDI_SUCCESS on success, and DDI_FAILURE on failure.
528*12004Sjiang.liu@intel.com */
529*12004Sjiang.liu@intel.com static int
acpinex_event_uninstall_handler(ACPI_HANDLE hdl,ACPI_DEVICE_INFO * infop,acpidev_data_handle_t dhdl)530*12004Sjiang.liu@intel.com acpinex_event_uninstall_handler(ACPI_HANDLE hdl, ACPI_DEVICE_INFO *infop,
531*12004Sjiang.liu@intel.com acpidev_data_handle_t dhdl)
532*12004Sjiang.liu@intel.com {
533*12004Sjiang.liu@intel.com ASSERT(hdl != NULL);
534*12004Sjiang.liu@intel.com ASSERT(dhdl != NULL);
535*12004Sjiang.liu@intel.com ASSERT(infop != NULL);
536*12004Sjiang.liu@intel.com
537*12004Sjiang.liu@intel.com if (!acpidev_data_get_flag(dhdl, ACPIDEV_DATA_HANDLER_READY)) {
538*12004Sjiang.liu@intel.com return (DDI_SUCCESS);
539*12004Sjiang.liu@intel.com }
540*12004Sjiang.liu@intel.com if (ACPI_SUCCESS(AcpiRemoveNotifyHandler(hdl, ACPI_SYSTEM_NOTIFY,
541*12004Sjiang.liu@intel.com acpinex_event_system_handler))) {
542*12004Sjiang.liu@intel.com acpidev_data_clear_flag(dhdl, ACPIDEV_DATA_HANDLER_READY);
543*12004Sjiang.liu@intel.com } else {
544*12004Sjiang.liu@intel.com char *objname;
545*12004Sjiang.liu@intel.com
546*12004Sjiang.liu@intel.com objname = acpidev_get_object_name(hdl);
547*12004Sjiang.liu@intel.com cmn_err(CE_WARN, "!acpinex: failed to uninstall system event "
548*12004Sjiang.liu@intel.com "handler for %s.", objname);
549*12004Sjiang.liu@intel.com acpidev_free_object_name(objname);
550*12004Sjiang.liu@intel.com return (DDI_FAILURE);
551*12004Sjiang.liu@intel.com }
552*12004Sjiang.liu@intel.com
553*12004Sjiang.liu@intel.com return (DDI_SUCCESS);
554*12004Sjiang.liu@intel.com }
555*12004Sjiang.liu@intel.com
556*12004Sjiang.liu@intel.com /*
557*12004Sjiang.liu@intel.com * Install/uninstall ACPI system event handler for child objects of hdl.
558*12004Sjiang.liu@intel.com * Return DDI_SUCCESS on success, and DDI_FAILURE on failure.
559*12004Sjiang.liu@intel.com */
560*12004Sjiang.liu@intel.com static int
acpinex_event_walk(boolean_t init,acpinex_softstate_t * sp,ACPI_HANDLE hdl)561*12004Sjiang.liu@intel.com acpinex_event_walk(boolean_t init, acpinex_softstate_t *sp, ACPI_HANDLE hdl)
562*12004Sjiang.liu@intel.com {
563*12004Sjiang.liu@intel.com int rc;
564*12004Sjiang.liu@intel.com int retval = DDI_SUCCESS;
565*12004Sjiang.liu@intel.com dev_info_t *dip;
566*12004Sjiang.liu@intel.com ACPI_HANDLE child = NULL;
567*12004Sjiang.liu@intel.com ACPI_OBJECT_TYPE type;
568*12004Sjiang.liu@intel.com ACPI_DEVICE_INFO *infop;
569*12004Sjiang.liu@intel.com acpidev_data_handle_t dhdl;
570*12004Sjiang.liu@intel.com
571*12004Sjiang.liu@intel.com /* Walk all child objects. */
572*12004Sjiang.liu@intel.com ASSERT(hdl != NULL);
573*12004Sjiang.liu@intel.com while (ACPI_SUCCESS(AcpiGetNextObject(ACPI_TYPE_ANY, hdl, child,
574*12004Sjiang.liu@intel.com &child))) {
575*12004Sjiang.liu@intel.com /* Skip unwanted object types. */
576*12004Sjiang.liu@intel.com if (ACPI_FAILURE(AcpiGetType(child, &type)) ||
577*12004Sjiang.liu@intel.com type > ACPI_TYPE_NS_NODE_MAX ||
578*12004Sjiang.liu@intel.com BT_TEST(acpinex_object_type_mask, type) == 0) {
579*12004Sjiang.liu@intel.com continue;
580*12004Sjiang.liu@intel.com }
581*12004Sjiang.liu@intel.com
582*12004Sjiang.liu@intel.com /* Get data associated with the object. Skip it if fails. */
583*12004Sjiang.liu@intel.com dhdl = acpidev_data_get_handle(child);
584*12004Sjiang.liu@intel.com if (dhdl == NULL) {
585*12004Sjiang.liu@intel.com ACPINEX_DEBUG(CE_NOTE, "!acpinex: failed to get data "
586*12004Sjiang.liu@intel.com "associated with %p, skip.", child);
587*12004Sjiang.liu@intel.com continue;
588*12004Sjiang.liu@intel.com }
589*12004Sjiang.liu@intel.com
590*12004Sjiang.liu@intel.com /* Query ACPI object info for the object. */
591*12004Sjiang.liu@intel.com if (ACPI_FAILURE(AcpiGetObjectInfo(child, &infop))) {
592*12004Sjiang.liu@intel.com cmn_err(CE_WARN,
593*12004Sjiang.liu@intel.com "!acpidnex: failed to get object info for %p.",
594*12004Sjiang.liu@intel.com child);
595*12004Sjiang.liu@intel.com continue;
596*12004Sjiang.liu@intel.com }
597*12004Sjiang.liu@intel.com
598*12004Sjiang.liu@intel.com if (init) {
599*12004Sjiang.liu@intel.com rc = acpinex_event_install_handler(child, sp, infop,
600*12004Sjiang.liu@intel.com dhdl);
601*12004Sjiang.liu@intel.com if (rc != DDI_SUCCESS) {
602*12004Sjiang.liu@intel.com ACPINEX_DEBUG(CE_WARN, "!acpinex: failed to "
603*12004Sjiang.liu@intel.com "install handler for child %p of %s.",
604*12004Sjiang.liu@intel.com child, sp->ans_path);
605*12004Sjiang.liu@intel.com retval = DDI_FAILURE;
606*12004Sjiang.liu@intel.com /*
607*12004Sjiang.liu@intel.com * Try to handle descendants if both of the
608*12004Sjiang.liu@intel.com * following two conditions are true:
609*12004Sjiang.liu@intel.com * 1) Device corresponding to the current object is
610*12004Sjiang.liu@intel.com * enabled. If the device is absent/disabled,
611*12004Sjiang.liu@intel.com * no notification should be generated from
612*12004Sjiang.liu@intel.com * descendant objects of it.
613*12004Sjiang.liu@intel.com * 2) No Solaris device node has been created for the
614*12004Sjiang.liu@intel.com * current object yet. If the device node has been
615*12004Sjiang.liu@intel.com * created for the current object, notification
616*12004Sjiang.liu@intel.com * events from child objects should be handled by
617*12004Sjiang.liu@intel.com * the corresponding driver.
618*12004Sjiang.liu@intel.com */
619*12004Sjiang.liu@intel.com } else if (acpidev_check_device_enabled(
620*12004Sjiang.liu@intel.com acpidev_data_get_status(dhdl)) &&
621*12004Sjiang.liu@intel.com ACPI_FAILURE(acpica_get_devinfo(child, &dip))) {
622*12004Sjiang.liu@intel.com rc = acpinex_event_walk(B_TRUE, sp, child);
623*12004Sjiang.liu@intel.com if (rc != DDI_SUCCESS) {
624*12004Sjiang.liu@intel.com ACPINEX_DEBUG(CE_WARN,
625*12004Sjiang.liu@intel.com "!acpinex: failed to install "
626*12004Sjiang.liu@intel.com "handler for descendants of %s.",
627*12004Sjiang.liu@intel.com sp->ans_path);
628*12004Sjiang.liu@intel.com retval = DDI_FAILURE;
629*12004Sjiang.liu@intel.com }
630*12004Sjiang.liu@intel.com }
631*12004Sjiang.liu@intel.com } else {
632*12004Sjiang.liu@intel.com rc = DDI_SUCCESS;
633*12004Sjiang.liu@intel.com /* Uninstall handler for descendants if needed. */
634*12004Sjiang.liu@intel.com if (ACPI_FAILURE(acpica_get_devinfo(child, &dip))) {
635*12004Sjiang.liu@intel.com rc = acpinex_event_walk(B_FALSE, sp, child);
636*12004Sjiang.liu@intel.com }
637*12004Sjiang.liu@intel.com if (rc == DDI_SUCCESS) {
638*12004Sjiang.liu@intel.com rc = acpinex_event_uninstall_handler(child,
639*12004Sjiang.liu@intel.com infop, dhdl);
640*12004Sjiang.liu@intel.com }
641*12004Sjiang.liu@intel.com /* Undo will be done by caller in case of failure. */
642*12004Sjiang.liu@intel.com if (rc != DDI_SUCCESS) {
643*12004Sjiang.liu@intel.com ACPINEX_DEBUG(CE_WARN, "!acpinex: failed to "
644*12004Sjiang.liu@intel.com "uninstall handler for descendants of %s.",
645*12004Sjiang.liu@intel.com sp->ans_path);
646*12004Sjiang.liu@intel.com AcpiOsFree(infop);
647*12004Sjiang.liu@intel.com retval = DDI_FAILURE;
648*12004Sjiang.liu@intel.com break;
649*12004Sjiang.liu@intel.com }
650*12004Sjiang.liu@intel.com }
651*12004Sjiang.liu@intel.com
652*12004Sjiang.liu@intel.com /* Release cached resources. */
653*12004Sjiang.liu@intel.com AcpiOsFree(infop);
654*12004Sjiang.liu@intel.com }
655*12004Sjiang.liu@intel.com
656*12004Sjiang.liu@intel.com return (retval);
657*12004Sjiang.liu@intel.com }
658*12004Sjiang.liu@intel.com
659*12004Sjiang.liu@intel.com int
acpinex_event_scan(acpinex_softstate_t * sp,boolean_t init)660*12004Sjiang.liu@intel.com acpinex_event_scan(acpinex_softstate_t *sp, boolean_t init)
661*12004Sjiang.liu@intel.com {
662*12004Sjiang.liu@intel.com int rc;
663*12004Sjiang.liu@intel.com
664*12004Sjiang.liu@intel.com ASSERT(sp != NULL);
665*12004Sjiang.liu@intel.com ASSERT(sp->ans_hdl != NULL);
666*12004Sjiang.liu@intel.com ASSERT(sp->ans_dip != NULL);
667*12004Sjiang.liu@intel.com if (sp == NULL || sp->ans_hdl == NULL || sp->ans_dip == NULL) {
668*12004Sjiang.liu@intel.com ACPINEX_DEBUG(CE_WARN,
669*12004Sjiang.liu@intel.com "!acpinex: invalid parameter to acpinex_event_scan().");
670*12004Sjiang.liu@intel.com return (DDI_FAILURE);
671*12004Sjiang.liu@intel.com }
672*12004Sjiang.liu@intel.com
673*12004Sjiang.liu@intel.com /* Lock current device node and walk all child device nodes of it. */
674*12004Sjiang.liu@intel.com mutex_enter(&sp->ans_lock);
675*12004Sjiang.liu@intel.com
676*12004Sjiang.liu@intel.com rc = acpinex_event_walk(init, sp, sp->ans_hdl);
677*12004Sjiang.liu@intel.com if (rc != DDI_SUCCESS) {
678*12004Sjiang.liu@intel.com if (init) {
679*12004Sjiang.liu@intel.com ACPINEX_DEBUG(CE_WARN, "!acpinex: failed to "
680*12004Sjiang.liu@intel.com "configure child objects of %s.", sp->ans_path);
681*12004Sjiang.liu@intel.com rc = DDI_FAILURE;
682*12004Sjiang.liu@intel.com } else {
683*12004Sjiang.liu@intel.com ACPINEX_DEBUG(CE_WARN, "!acpinex: failed to "
684*12004Sjiang.liu@intel.com "unconfigure child objects of %s.", sp->ans_path);
685*12004Sjiang.liu@intel.com /* Undo in case of errors */
686*12004Sjiang.liu@intel.com (void) acpinex_event_walk(B_TRUE, sp, sp->ans_hdl);
687*12004Sjiang.liu@intel.com rc = DDI_FAILURE;
688*12004Sjiang.liu@intel.com }
689*12004Sjiang.liu@intel.com }
690*12004Sjiang.liu@intel.com
691*12004Sjiang.liu@intel.com mutex_exit(&sp->ans_lock);
692*12004Sjiang.liu@intel.com
693*12004Sjiang.liu@intel.com return (rc);
694*12004Sjiang.liu@intel.com }
695*12004Sjiang.liu@intel.com
696*12004Sjiang.liu@intel.com void
acpinex_event_init(void)697*12004Sjiang.liu@intel.com acpinex_event_init(void)
698*12004Sjiang.liu@intel.com {
699*12004Sjiang.liu@intel.com /*
700*12004Sjiang.liu@intel.com * According to ACPI specifications, notification is only supported on
701*12004Sjiang.liu@intel.com * Device, Processor and ThermalZone. Currently we only need to handle
702*12004Sjiang.liu@intel.com * Device and Processor objects.
703*12004Sjiang.liu@intel.com */
704*12004Sjiang.liu@intel.com BT_SET(acpinex_object_type_mask, ACPI_TYPE_PROCESSOR);
705*12004Sjiang.liu@intel.com BT_SET(acpinex_object_type_mask, ACPI_TYPE_DEVICE);
706*12004Sjiang.liu@intel.com }
707*12004Sjiang.liu@intel.com
708*12004Sjiang.liu@intel.com void
acpinex_event_fini(void)709*12004Sjiang.liu@intel.com acpinex_event_fini(void)
710*12004Sjiang.liu@intel.com {
711*12004Sjiang.liu@intel.com bzero(acpinex_object_type_mask, sizeof (acpinex_object_type_mask));
712*12004Sjiang.liu@intel.com }
713