Print this page
PANKOVs restructure
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/i86pc/io/acpi/acpidev/acpidev_util.c
+++ new/usr/src/uts/i86pc/io/acpi/acpidev/acpidev_util.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26 /*
↓ open down ↓ |
26 lines elided |
↑ open up ↑ |
27 27 * Copyright (c) 2009-2010, Intel Corporation.
28 28 * All rights reserved.
29 29 */
30 30
31 31 #include <sys/types.h>
32 32 #include <sys/cmn_err.h>
33 33 #include <sys/note.h>
34 34 #include <sys/sysmacros.h>
35 35 #include <sys/sunddi.h>
36 36 #include <sys/sunndi.h>
37 -#include <sys/acpi/acpi.h>
37 +#include <acpica/include/acpi.h>
38 38 #include <sys/acpica.h>
39 39 #include <sys/acpidev.h>
40 40 #include <sys/acpidev_impl.h>
41 41 #include <util/sscanf.h>
42 42
43 43 /* Data structures used to extract the numeric unit address from string _UID. */
44 44 static acpidev_pseudo_uid_head_t acpidev_uid_heads[ACPIDEV_CLASS_ID_MAX];
45 45 static char *acpidev_uid_formats[] = {
46 46 "%u",
47 47 };
48 48
49 49 static char *acpidev_unknown_object_name = "<unknown>";
50 50
51 51 int
52 52 acpidev_query_device_status(ACPI_HANDLE hdl)
53 53 {
54 54 int status;
55 55
56 56 ASSERT(hdl != NULL);
57 57 if (hdl == NULL) {
58 58 ACPIDEV_DEBUG(CE_WARN,
59 59 "!acpidev: hdl is NULL in acpidev_query_device_status().");
60 60 return (0);
61 61 }
62 62
63 63 if (ACPI_FAILURE(acpica_eval_int(hdl, METHOD_NAME__STA, &status))) {
64 64 /*
65 65 * Set the default value according to ACPI3.0b sec 6.3.7:
66 66 * If a device object (including the processor object) does
67 67 * not have an _STA object, then OSPM assumes that all of the
68 68 * above bits are set (in other words, the device is present,
69 69 * enabled, shown in the UI, and functioning).
70 70 */
71 71 status = 0xF;
72 72 }
73 73
74 74 return (status);
75 75 }
76 76
77 77 boolean_t
78 78 acpidev_check_device_present(int status)
79 79 {
80 80 /*
81 81 * According to ACPI3.0 Spec, if either the ACPI_STA_DEVICE_PRESENT bit
82 82 * or the ACPI_STA_DEVICE_FUNCTIONING bit is set, the device exists.
83 83 */
84 84 if (status & (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_FUNCTIONING)) {
85 85 return (B_TRUE);
86 86 }
87 87
88 88 return (B_FALSE);
89 89 }
90 90
91 91 boolean_t
92 92 acpidev_check_device_enabled(int stat)
93 93 {
94 94 /*
95 95 * According to ACPI3.0 Spec, if either the ACPI_STA_DEVICE_PRESENT bit
96 96 * or the ACPI_STA_DEVICE_FUNCTIONING bit is set, the device exists.
97 97 * Return true if device exists and has been enabled.
98 98 */
99 99 if ((stat & (ACPI_STA_DEVICE_PRESENT | ACPI_STA_DEVICE_FUNCTIONING)) &&
100 100 (stat & ACPI_STA_DEVICE_ENABLED)) {
101 101 return (B_TRUE);
102 102 }
103 103
104 104 return (B_FALSE);
105 105 }
106 106
107 107 boolean_t
108 108 acpidev_match_device_id(ACPI_DEVICE_INFO *infop, char **ids, int count)
109 109 {
110 110 int i, j;
111 111
112 112 ASSERT(infop != NULL);
113 113 ASSERT(ids != NULL || count == 0);
114 114 /* Special case to match all devices if count is 0. */
115 115 if (count == 0) {
116 116 return (B_TRUE);
117 117 } else if (infop == NULL || ids == NULL) {
118 118 ACPIDEV_DEBUG(CE_WARN, "!acpidev: invalid parameters in "
119 119 "acpidev_match_device_id().");
120 120 return (B_FALSE);
121 121 }
122 122
123 123 /* Match _HID first. */
124 124 if (infop->Valid & ACPI_VALID_HID) {
125 125 for (i = 0; i < count; i++) {
126 126 if (strncmp(ids[i], infop->HardwareId.String,
127 127 infop->HardwareId.Length) == 0) {
128 128 return (B_TRUE);
129 129 }
130 130 }
131 131 }
132 132
133 133 /* Match _CID next. */
134 134 if (infop->Valid & ACPI_VALID_CID) {
135 135 for (i = 0; i < count; i++) {
136 136 for (j = 0; j < infop->CompatibleIdList.Count; j++) {
137 137 if (strncmp(ids[i],
138 138 infop->CompatibleIdList.Ids[j].String,
139 139 infop->CompatibleIdList.Ids[j].Length)
140 140 == 0) {
141 141 return (B_TRUE);
142 142 }
143 143 }
144 144 }
145 145 }
146 146
147 147 return (B_FALSE);
148 148 }
149 149
150 150 struct acpidev_get_device_arg {
151 151 boolean_t skip_non_exist;
152 152 int id_count;
153 153 char **device_ids;
154 154 void *user_arg;
155 155 ACPI_WALK_CALLBACK user_func;
156 156 };
157 157
158 158 static ACPI_STATUS
159 159 acpidev_get_device_callback(ACPI_HANDLE hdl, UINT32 level, void *arg,
160 160 void **retval)
161 161 {
162 162 ACPI_STATUS rc;
163 163 ACPI_DEVICE_INFO *infop;
164 164 struct acpidev_get_device_arg *argp;
165 165
166 166 argp = (struct acpidev_get_device_arg *)arg;
167 167 ASSERT(argp != NULL);
168 168 ASSERT(hdl != NULL);
169 169
170 170 /* Query object information. */
171 171 rc = AcpiGetObjectInfo(hdl, &infop);
172 172 if (ACPI_FAILURE(rc)) {
173 173 cmn_err(CE_WARN, "!acpidev: failed to get ACPI object info "
174 174 "in acpidev_get_device_callback().");
175 175 return (AE_CTRL_DEPTH);
176 176 }
177 177
178 178 /*
179 179 * Skip scanning of children if the device is neither PRESENT nor
180 180 * FUNCTIONING.
181 181 * Please refer to ACPI Spec3.0b Sec 6.3.1 and 6.5.1.
182 182 */
183 183 if (argp->skip_non_exist && (infop->Valid & ACPI_VALID_STA) &&
184 184 !acpidev_check_device_present(infop->CurrentStatus)) {
185 185 rc = AE_CTRL_DEPTH;
186 186 /* Call user callback if matched. */
187 187 } else if (acpidev_match_device_id(infop, argp->device_ids,
188 188 argp->id_count)) {
189 189 rc = argp->user_func(hdl, level, argp->user_arg, retval);
190 190 } else {
191 191 rc = AE_OK;
192 192 }
193 193
194 194 /* Free ACPI object info buffer. */
195 195 AcpiOsFree(infop);
196 196
197 197 return (rc);
198 198 }
199 199
200 200 ACPI_STATUS
201 201 acpidev_get_device_by_id(ACPI_HANDLE hdl, char **ids, int count,
202 202 int maxdepth, boolean_t skip_non_exist,
203 203 ACPI_WALK_CALLBACK userfunc, void *userarg, void **retval)
204 204 {
205 205 ACPI_STATUS rc;
206 206 struct acpidev_get_device_arg arg;
207 207
208 208 ASSERT(userfunc != NULL);
209 209 if (hdl == NULL || userfunc == NULL || (ids == NULL && count != 0)) {
210 210 ACPIDEV_DEBUG(CE_WARN, "!acpidev: invalid parameters "
211 211 "in acpidev_get_device_by_id().");
212 212 return (AE_BAD_PARAMETER);
213 213 }
214 214
215 215 /* Enumerate all descendant objects. */
216 216 arg.skip_non_exist = skip_non_exist;
217 217 arg.device_ids = ids;
218 218 arg.id_count = count;
219 219 arg.user_arg = userarg;
220 220 arg.user_func = userfunc;
221 221 rc = AcpiWalkNamespace(ACPI_TYPE_DEVICE, hdl, maxdepth,
222 222 &acpidev_get_device_callback, NULL, &arg, retval);
223 223
224 224 return (rc);
225 225 }
226 226
227 227 ACPI_STATUS
228 228 acpidev_walk_apic(ACPI_BUFFER *bufp, ACPI_HANDLE hdl, char *method,
229 229 acpidev_apic_walker_t func, void *context)
230 230 {
231 231 ACPI_STATUS rc;
232 232 ssize_t len;
233 233 ACPI_BUFFER buf;
234 234 ACPI_OBJECT *obj;
235 235 ACPI_SUBTABLE_HEADER *ap;
236 236 ACPI_TABLE_MADT *mp = NULL;
237 237
238 238 ASSERT(func != NULL);
239 239 if (func == NULL) {
240 240 ACPIDEV_DEBUG(CE_WARN,
241 241 "!acpidev: invalid parameters for acpidev_walk_apic().");
242 242 return (AE_BAD_PARAMETER);
243 243 }
244 244
245 245 buf.Pointer = NULL;
246 246 buf.Length = ACPI_ALLOCATE_BUFFER;
247 247
248 248 /* A walk buffer was passed in if bufp isn't NULL. */
249 249 if (bufp != NULL) {
250 250 ap = (ACPI_SUBTABLE_HEADER *)(bufp->Pointer);
251 251 len = bufp->Length;
252 252 } else if (method != NULL) {
253 253 /*
254 254 * Otherwise, if we have an evaluate method, we get the walk
255 255 * buffer from a successful invocation of
256 256 * AcpiEvaluateObjectTyped().
257 257 */
258 258 ASSERT(hdl != NULL);
259 259 rc = AcpiEvaluateObjectTyped(hdl, method, NULL, &buf,
260 260 ACPI_TYPE_BUFFER);
261 261 if (ACPI_SUCCESS(rc)) {
262 262 ASSERT(buf.Length >= sizeof (*obj));
263 263 obj = buf.Pointer;
264 264 ap = (ACPI_SUBTABLE_HEADER *)obj->Buffer.Pointer;
265 265 len = obj->Buffer.Length;
266 266 } else {
267 267 if (rc != AE_NOT_FOUND)
268 268 cmn_err(CE_WARN, "!acpidev: failed to evaluate "
269 269 "%s in acpidev_walk_apic().", method);
270 270 return (rc);
271 271 }
272 272 } else {
273 273 /* As a last resort, walk the MADT table. */
274 274 rc = AcpiGetTable(ACPI_SIG_MADT, 1, (ACPI_TABLE_HEADER **)&mp);
275 275 if (ACPI_FAILURE(rc)) {
276 276 cmn_err(CE_WARN, "!acpidev: failed to get MADT table "
277 277 "in acpidev_walk_apic().");
278 278 return (rc);
279 279 }
280 280 ap = (ACPI_SUBTABLE_HEADER *)(mp + 1);
281 281 len = mp->Header.Length - sizeof (*mp);
282 282 }
283 283
284 284 ASSERT(len >= 0);
285 285 for (rc = AE_OK; len > 0 && ACPI_SUCCESS(rc); len -= ap->Length,
286 286 ap = (ACPI_SUBTABLE_HEADER *)(((char *)ap) + ap->Length)) {
287 287 ASSERT(len >= sizeof (ACPI_SUBTABLE_HEADER));
288 288 if (len <= sizeof (ACPI_SUBTABLE_HEADER) ||
289 289 ap->Length <= sizeof (ACPI_SUBTABLE_HEADER) ||
290 290 len < ap->Length) {
291 291 cmn_err(CE_WARN,
292 292 "!acpidev: invalid APIC entry in MADT/_MAT.");
293 293 break;
294 294 }
295 295 rc = (*func)(ap, context);
296 296 }
297 297
298 298 if (buf.Pointer != NULL) {
299 299 AcpiOsFree(buf.Pointer);
300 300 }
301 301
302 302 return (rc);
303 303 }
304 304
305 305 char *
306 306 acpidev_get_object_name(ACPI_HANDLE hdl)
307 307 {
308 308 ACPI_BUFFER buf;
309 309 char *objname = acpidev_unknown_object_name;
310 310
311 311 buf.Length = ACPI_ALLOCATE_BUFFER;
312 312 buf.Pointer = NULL;
313 313 if (ACPI_SUCCESS(AcpiGetName(hdl, ACPI_FULL_PATHNAME, &buf))) {
314 314 ASSERT(buf.Pointer != NULL);
315 315 objname = (char *)buf.Pointer;
316 316 }
317 317
318 318 return (objname);
319 319 }
320 320
321 321 void
322 322 acpidev_free_object_name(char *objname)
323 323 {
324 324 if (objname != acpidev_unknown_object_name && objname != NULL) {
325 325 AcpiOsFree(objname);
326 326 }
327 327 }
328 328
329 329 acpidev_walk_info_t *
330 330 acpidev_alloc_walk_info(acpidev_op_type_t op_type, int lvl, ACPI_HANDLE hdl,
331 331 acpidev_class_list_t **listpp, acpidev_walk_info_t *pinfop)
332 332 {
333 333 acpidev_walk_info_t *infop = NULL;
334 334 acpidev_data_handle_t datap = NULL;
335 335
336 336 ASSERT(0 <= lvl && lvl < ACPIDEV_MAX_ENUM_LEVELS);
337 337 infop = kmem_zalloc(sizeof (*infop), KM_SLEEP);
338 338 infop->awi_op_type = op_type;
339 339 infop->awi_level = lvl;
340 340 infop->awi_parent = pinfop;
341 341 infop->awi_class_list = listpp;
342 342 infop->awi_hdl = hdl;
343 343 infop->awi_name = acpidev_get_object_name(hdl);
344 344
345 345 /* Cache ACPI device information. */
346 346 if (ACPI_FAILURE(AcpiGetObjectInfo(hdl, &infop->awi_info))) {
347 347 cmn_err(CE_WARN, "!acpidev: failed to get object info for %s "
348 348 "in acpidev_alloc_walk_info().", infop->awi_name);
349 349 acpidev_free_object_name(infop->awi_name);
350 350 kmem_free(infop, sizeof (*infop));
351 351 return (NULL);
352 352 }
353 353
354 354 /*
355 355 * Get or create an ACPI object data handle, which will be used to
356 356 * maintain object status information.
357 357 */
358 358 if ((datap = acpidev_data_get_handle(hdl)) != NULL) {
359 359 ASSERT(datap->aod_hdl == hdl);
360 360 ASSERT(datap->aod_level == lvl);
361 361 } else if ((datap = acpidev_data_create_handle(hdl)) != NULL) {
362 362 datap->aod_level = lvl;
363 363 datap->aod_hdl = hdl;
364 364 } else {
365 365 ACPIDEV_DEBUG(CE_WARN, "!acpidev: failed to create object "
366 366 "handle for %s in acpidev_alloc_walk_info().",
367 367 infop->awi_name);
368 368 AcpiOsFree(infop->awi_info);
369 369 acpidev_free_object_name(infop->awi_name);
370 370 kmem_free(infop, sizeof (*infop));
371 371 return (NULL);
372 372 }
373 373 infop->awi_data = datap;
374 374 /* Sync DEVICE_CREATED flag. */
375 375 if (datap->aod_iflag & ACPIDEV_ODF_DEVINFO_CREATED) {
376 376 ASSERT(datap->aod_dip != NULL);
377 377 ASSERT(datap->aod_class != NULL);
378 378 infop->awi_dip = datap->aod_dip;
379 379 infop->awi_flags |= ACPIDEV_WI_DEVICE_CREATED;
380 380 }
381 381
382 382 return (infop);
383 383 }
384 384
385 385 void
386 386 acpidev_free_walk_info(acpidev_walk_info_t *infop)
387 387 {
388 388 /*
389 389 * The ACPI object data handle will only be released when the
390 390 * corresponding object is going to be destroyed.
391 391 */
392 392 if (infop != NULL) {
393 393 if (infop->awi_info != NULL) {
394 394 AcpiOsFree(infop->awi_info);
395 395 }
396 396 if (infop->awi_name != NULL) {
397 397 acpidev_free_object_name(infop->awi_name);
398 398 }
399 399 kmem_free(infop, sizeof (*infop));
400 400 }
401 401 }
402 402
403 403 dev_info_t *
404 404 acpidev_walk_info_get_pdip(acpidev_walk_info_t *infop)
405 405 {
406 406 while (infop != NULL) {
407 407 if (infop->awi_dip != NULL) {
408 408 return (infop->awi_dip);
409 409 }
410 410 infop = infop->awi_parent;
411 411 }
412 412
413 413 return (NULL);
414 414 }
415 415
416 416 /*
417 417 * Called to release resources when the corresponding object is going
418 418 * to be destroyed.
419 419 */
420 420 static void
421 421 acpidev_free_object_handler(ACPI_HANDLE hdl, void *data)
422 422 {
423 423 _NOTE(ARGUNUSED(hdl));
424 424
425 425 acpidev_data_handle_t objhdl = data;
426 426
427 427 if (objhdl->aod_class != NULL) {
428 428 atomic_dec_32(&objhdl->aod_class->adc_refcnt);
429 429 objhdl->aod_class = NULL;
430 430 }
431 431 kmem_free(objhdl, sizeof (acpidev_data_handle_t));
432 432 }
433 433
434 434 acpidev_data_handle_t
435 435 acpidev_data_get_handle(ACPI_HANDLE hdl)
436 436 {
437 437 void *ptr;
438 438 acpidev_data_handle_t objhdl = NULL;
439 439
440 440 if (ACPI_SUCCESS(AcpiGetData(hdl, acpidev_free_object_handler, &ptr))) {
441 441 objhdl = (acpidev_data_handle_t)ptr;
442 442 }
443 443
444 444 return (objhdl);
445 445 }
446 446
447 447 acpidev_data_handle_t
448 448 acpidev_data_create_handle(ACPI_HANDLE hdl)
449 449 {
450 450 acpidev_data_handle_t objhdl;
451 451
452 452 objhdl = kmem_zalloc(sizeof (*objhdl), KM_SLEEP);
453 453 objhdl->aod_bdtype = ACPIDEV_INVALID_BOARD;
454 454 objhdl->aod_bdnum = UINT32_MAX;
455 455 objhdl->aod_portid = UINT32_MAX;
456 456 objhdl->aod_class_id = ACPIDEV_CLASS_ID_INVALID;
457 457
458 458 if (ACPI_FAILURE(AcpiAttachData(hdl, acpidev_free_object_handler,
459 459 (void *)objhdl))) {
460 460 cmn_err(CE_WARN,
461 461 "!acpidev: failed to attach handle data to object.");
462 462 kmem_free(objhdl, sizeof (*objhdl));
463 463 return (NULL);
464 464 }
465 465
466 466 return (objhdl);
467 467 }
468 468
469 469 void
470 470 acpidev_data_destroy_handle(ACPI_HANDLE hdl)
471 471 {
472 472 void *ptr;
473 473 acpidev_data_handle_t objhdl = NULL;
474 474
475 475 if (ACPI_SUCCESS(AcpiGetData(hdl, acpidev_free_object_handler, &ptr)) &&
476 476 ACPI_SUCCESS(AcpiDetachData(hdl, acpidev_free_object_handler))) {
477 477 objhdl = ptr;
478 478 if (objhdl->aod_class != NULL) {
479 479 atomic_dec_32(&objhdl->aod_class->adc_refcnt);
480 480 objhdl->aod_class = NULL;
481 481 }
482 482 kmem_free(ptr, sizeof (acpidev_data_handle_t));
483 483 }
484 484 }
485 485
486 486 ACPI_HANDLE
487 487 acpidev_data_get_object(acpidev_data_handle_t hdl)
488 488 {
489 489 ASSERT(hdl != NULL);
490 490 return ((hdl != NULL) ? hdl->aod_hdl : NULL);
491 491 }
492 492
493 493 dev_info_t *
494 494 acpidev_data_get_devinfo(acpidev_data_handle_t hdl)
495 495 {
496 496 ASSERT(hdl != NULL);
497 497 if (hdl == NULL ||
498 498 (hdl->aod_iflag & ACPIDEV_ODF_DEVINFO_CREATED) == 0) {
499 499 return (NULL);
500 500 } else {
501 501 ASSERT(hdl->aod_dip != NULL);
502 502 return (hdl->aod_dip);
503 503 }
504 504 }
505 505
506 506 int
507 507 acpidev_data_get_status(acpidev_data_handle_t hdl)
508 508 {
509 509 ASSERT(hdl != NULL);
510 510 if (hdl == NULL ||
511 511 (hdl->aod_iflag & ACPIDEV_ODF_STATUS_VALID) == 0) {
512 512 return (0);
513 513 } else {
514 514 return (hdl->aod_status);
515 515 }
516 516 }
517 517
518 518 void
519 519 acpidev_data_set_flag(acpidev_data_handle_t hdl, uint32_t flag)
520 520 {
521 521 ASSERT(hdl != NULL);
522 522 atomic_or_32(&hdl->aod_eflag, flag);
523 523 }
524 524
525 525 void
526 526 acpidev_data_clear_flag(acpidev_data_handle_t hdl, uint32_t flag)
527 527 {
528 528 ASSERT(hdl != NULL);
529 529 atomic_and_32(&hdl->aod_eflag, ~flag);
530 530 }
531 531
532 532 uint32_t
533 533 acpidev_data_get_flag(acpidev_data_handle_t hdl, uint32_t flag)
534 534 {
535 535 ASSERT(hdl != NULL);
536 536 return (hdl->aod_eflag & flag);
537 537 }
538 538
539 539 boolean_t
540 540 acpidev_data_dr_capable(acpidev_data_handle_t hdl)
541 541 {
542 542 ASSERT(hdl != NULL);
543 543 return (hdl->aod_iflag & ACPIDEV_ODF_HOTPLUG_CAPABLE);
544 544 }
545 545
546 546 boolean_t
547 547 acpidev_data_dr_ready(acpidev_data_handle_t hdl)
548 548 {
549 549 ASSERT(hdl != NULL);
550 550 return (hdl->aod_iflag & ACPIDEV_ODF_HOTPLUG_READY);
551 551 }
552 552
553 553 boolean_t
554 554 acpidev_data_dr_failed(acpidev_data_handle_t hdl)
555 555 {
556 556 ASSERT(hdl != NULL);
557 557 return (hdl->aod_iflag & ACPIDEV_ODF_HOTPLUG_FAILED);
558 558 }
559 559
560 560 static char *
561 561 acpidev_generate_pseudo_unitaddr(char *uid, acpidev_class_id_t cid,
562 562 char *buf, size_t len)
563 563 {
564 564 acpidev_pseudo_uid_t *up, **pp;
565 565
566 566 ASSERT(len >= 64);
567 567 ASSERT(cid >= 0 && cid < ACPIDEV_CLASS_ID_MAX);
568 568 if (cid < 0 || cid >= ACPIDEV_CLASS_ID_MAX) {
569 569 return (NULL);
570 570 }
571 571
572 572 mutex_enter(&acpidev_uid_heads[cid].apuh_lock);
573 573 for (pp = &acpidev_uid_heads[cid].apuh_first; *pp != NULL;
574 574 pp = &(*pp)->apu_next) {
575 575 if (strcmp(uid, (*pp)->apu_uid) == 0 &&
576 576 (*pp)->apu_cid == cid) {
577 577 break;
578 578 }
579 579 }
580 580 /* uid doesn't exist, create one and insert it into the list. */
581 581 if (*pp == NULL) {
582 582 up = kmem_zalloc(sizeof (*up), KM_SLEEP);
583 583 up->apu_uid = ddi_strdup(uid, KM_SLEEP);
584 584 up->apu_cid = cid;
585 585 up->apu_nid = acpidev_uid_heads[cid].apuh_id++;
586 586 *pp = up;
587 587 }
588 588 ASSERT(*pp != NULL);
589 589 mutex_exit(&acpidev_uid_heads[cid].apuh_lock);
590 590
591 591 /*
592 592 * Generate a special format unit address with three fields to
593 593 * guarantee uniqueness. Normal unit addresses for ACPI devices have
594 594 * either one or two fields.
595 595 */
596 596 if (snprintf(buf, len, "%u,%u,0", (*pp)->apu_nid, cid) > len) {
597 597 return (NULL);
598 598 }
599 599
600 600 return (buf);
601 601 }
602 602
603 603 static char *
604 604 acpidev_gen_unitaddr(char *uid, char *fmt, char *buf, size_t len)
605 605 {
606 606 size_t i, cnt;
607 607 uint_t id1, id2;
608 608
609 609 ASSERT(len >= 64);
610 610 if (fmt == NULL || strlen(fmt) == 0) {
611 611 return (NULL);
612 612 }
613 613
614 614 /*
615 615 * Count '%' in format string to protect sscanf().
616 616 * Only support '%u' and '%x', and maximum 2 conversions.
617 617 */
618 618 for (cnt = 0, i = 0; fmt[i] != 0 && cnt <= 2; i++) {
619 619 if (fmt[i] != '%') {
620 620 continue;
621 621 } else if (fmt[i + 1] == 'u' || fmt[i + 1] == 'x') {
622 622 /* Skip next character. */
623 623 i++;
624 624 cnt++;
625 625 } else {
626 626 /* Invalid conversion, stop walking. */
627 627 cnt = SIZE_MAX;
628 628 }
629 629 }
630 630 if (cnt != 1 && cnt != 2) {
631 631 ACPIDEV_DEBUG(CE_WARN,
632 632 "!acpidev: invalid uid format string '%s'.", fmt);
633 633 return (NULL);
634 634 }
635 635
636 636 /* Scan uid and generate unitaddr. */
637 637 if (sscanf(uid, fmt, &id1, &id2) != cnt) {
638 638 return (NULL);
639 639 }
640 640 /*
641 641 * Reverse the order of the two IDs to match the requirements of the
642 642 * hotplug driver.
643 643 */
644 644 if (cnt == 2 && snprintf(buf, len, "%u,%u", id2, id1) >= len) {
645 645 ACPIDEV_DEBUG(CE_WARN,
646 646 "!acpidev: generated unitaddr is too long.");
647 647 return (NULL);
648 648 } else if (cnt == 1 && snprintf(buf, len, "%u", id1) >= len) {
649 649 ACPIDEV_DEBUG(CE_WARN,
650 650 "!acpidev: generated unitaddr is too long.");
651 651 return (NULL);
652 652 }
653 653
654 654 return (buf);
655 655 }
656 656
657 657 char *
658 658 acpidev_generate_unitaddr(char *uid, char **fmts, size_t nfmt,
659 659 char *buf, size_t len)
660 660 {
661 661 size_t i;
662 662 uint_t count = 0;
663 663 ulong_t val;
664 664 char **formats = NULL;
665 665 char *rbuf = NULL;
666 666 char *endp = NULL;
667 667
668 668 ASSERT(len >= 64);
669 669
670 670 /* Use _UID as unit address if it's a decimal integer. */
671 671 if (ddi_strtoul(uid, &endp, 10, &val) == 0 &&
672 672 (endp == NULL || *endp == 0)) {
673 673 if (snprintf(buf, len, "%s", uid) >= len) {
674 674 return (NULL);
675 675 } else {
676 676 return (buf);
677 677 }
678 678 }
679 679
680 680 /* First handle uid format strings from device property. */
681 681 if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, ddi_root_node(),
682 682 DDI_PROP_DONTPASS,
683 683 ACPIDEV_PROP_NAME_UID_FORMAT, &formats, &count) == DDI_SUCCESS) {
684 684 /* Walk through format strings and try to generate unitaddr. */
685 685 for (i = 0; i < count && rbuf == NULL; i++) {
686 686 rbuf = acpidev_gen_unitaddr(uid, formats[i], buf, len);
687 687 }
688 688 ddi_prop_free(formats);
689 689 }
690 690
691 691 /* Then handle embedded uid format strings. */
692 692 if (fmts != NULL) {
693 693 for (i = 0; i < nfmt && rbuf == NULL; i++) {
694 694 rbuf = acpidev_gen_unitaddr(uid, fmts[i], buf, len);
695 695 }
696 696 }
697 697
698 698 return (rbuf);
699 699 }
700 700
701 701 /*
702 702 * The Solaris device "unit-address" property is composed of a comma-delimited
703 703 * list of hexadecimal values. According to the ACPI spec, the ACPI _UID method
704 704 * could return an integer or a string. If it returns an integer, it is used
705 705 * as the unit-address as is. If _UID returns a string, we try to extract some
706 706 * meaningful integers to compose the unit-address property. If we fail to
707 707 * extract any integers, a pseudo-sequential number will be generated for the
708 708 * unit-address.
709 709 */
710 710 ACPI_STATUS
711 711 acpidev_set_unitaddr(acpidev_walk_info_t *infop, char **fmts, size_t nfmt,
712 712 char *unitaddr)
713 713 {
714 714 char unit[64];
715 715
716 716 ASSERT(infop != NULL);
717 717 ASSERT(infop->awi_dip != NULL);
718 718 ASSERT(infop->awi_info != NULL);
719 719 if (infop == NULL || infop->awi_dip == NULL ||
720 720 infop->awi_info == NULL) {
721 721 ACPIDEV_DEBUG(CE_WARN,
722 722 "!acpidev: invalid parameters in acpidev_set_unitaddr().");
723 723 return (AE_BAD_PARAMETER);
724 724 }
725 725
726 726 if (infop->awi_info->Valid & ACPI_VALID_UID) {
727 727 if (ndi_prop_update_string(DDI_DEV_T_NONE, infop->awi_dip,
728 728 ACPIDEV_PROP_NAME_ACPI_UID,
729 729 infop->awi_info->UniqueId.String) != NDI_SUCCESS) {
730 730 cmn_err(CE_WARN,
731 731 "!acpidev: failed to set UID property for %s.",
732 732 infop->awi_name);
733 733 return (AE_ERROR);
734 734 }
735 735 }
736 736
737 737 if (unitaddr == NULL && (infop->awi_info->Valid & ACPI_VALID_UID)) {
738 738 /* Try to generate unit address from _UID. */
739 739 if (fmts == NULL) {
740 740 fmts = acpidev_uid_formats;
741 741 nfmt = sizeof (acpidev_uid_formats) / sizeof (char *);
742 742 }
743 743 unitaddr = acpidev_generate_unitaddr(
744 744 infop->awi_info->UniqueId.String, fmts, nfmt,
745 745 unit, sizeof (unit));
746 746 /* Generate pseudo sequential unit address. */
747 747 if (unitaddr == NULL) {
748 748 unitaddr = acpidev_generate_pseudo_unitaddr(
749 749 infop->awi_info->UniqueId.String,
750 750 infop->awi_class_curr->adc_class_id,
751 751 unit, sizeof (unit));
752 752 }
753 753 if (unitaddr == NULL) {
754 754 cmn_err(CE_WARN, "!acpidev: failed to generate unit "
755 755 "address from %s.",
756 756 infop->awi_info->UniqueId.String);
757 757 return (AE_ERROR);
758 758 }
759 759 }
760 760 if (unitaddr == NULL) {
761 761 /*
762 762 * Some ACPI objects may have no _UID method available, so we
763 763 * can't generate the "unit-address" property for them.
764 764 * On the other hand, it's legal to support such a device
765 765 * without a unit address, so return success here.
766 766 */
767 767 return (AE_OK);
768 768 }
769 769
770 770 if (ndi_prop_update_string(DDI_DEV_T_NONE, infop->awi_dip,
771 771 ACPIDEV_PROP_NAME_UNIT_ADDR, unitaddr) != NDI_SUCCESS) {
772 772 cmn_err(CE_WARN, "!acpidev: failed to set unitaddr for %s.",
773 773 infop->awi_name);
774 774 return (AE_ERROR);
775 775 }
776 776
777 777 return (AE_OK);
778 778 }
779 779
780 780 ACPI_STATUS
781 781 acpidev_set_compatible(acpidev_walk_info_t *infop, char **compat, int acount)
782 782 {
783 783 int count, i, j;
784 784 char **compatible = NULL;
785 785 ACPI_DEVICE_INFO *di;
786 786
787 787 /*
788 788 * Generate compatible list for device based on:
789 789 * * Device HID if available
790 790 * * Device CIDs if available
791 791 * * property array passed in
792 792 */
793 793 ASSERT(infop != NULL);
794 794 ASSERT(infop->awi_dip != NULL);
795 795 ASSERT(infop->awi_info != NULL);
796 796 ASSERT(compat != NULL || acount == 0);
797 797 if (infop == NULL || infop->awi_dip == NULL ||
798 798 infop->awi_info == NULL || (compat == NULL && acount != 0)) {
799 799 ACPIDEV_DEBUG(CE_WARN, "!acpidev: invalid parameters "
800 800 "in acpidev_set_compatible().");
801 801 return (AE_BAD_PARAMETER);
802 802 }
803 803
804 804 /* Compute string count. */
805 805 count = acount;
806 806 di = infop->awi_info;
807 807 if (di->Valid & ACPI_VALID_HID) {
808 808 count++;
809 809 }
810 810 if (di->Valid & ACPI_VALID_CID) {
811 811 count += di->CompatibleIdList.Count;
812 812 }
813 813 compatible = kmem_zalloc(sizeof (char *) * count, KM_SLEEP);
814 814
815 815 /* Generate string array. */
816 816 i = 0;
817 817 if (di->Valid & ACPI_VALID_HID) {
818 818 compatible[i++] = di->HardwareId.String;
819 819 }
820 820 if (di->Valid & ACPI_VALID_CID) {
821 821 for (j = 0; j < di->CompatibleIdList.Count; j++) {
822 822 compatible[i++] = di->CompatibleIdList.Ids[j].String;
823 823 }
824 824 }
825 825 for (j = 0; j < acount; j++) {
826 826 compatible[i++] = compat[j];
827 827 }
828 828 ASSERT(i == count);
829 829
830 830 /* Set "compatible" property. */
831 831 if (ndi_prop_update_string_array(DDI_DEV_T_NONE, infop->awi_dip,
832 832 OBP_COMPATIBLE, compatible, count) != NDI_SUCCESS) {
833 833 cmn_err(CE_WARN, "!acpidev: failed to set compatible "
834 834 "property for %s in acpidev_set_compatible().",
835 835 infop->awi_name);
836 836 kmem_free(compatible, count * sizeof (char *));
837 837 return (AE_ERROR);
838 838 }
839 839 kmem_free(compatible, count * sizeof (char *));
840 840
841 841 return (AE_OK);
842 842 }
843 843
844 844 /* Evaluate _OST method under object, which is used to support hotplug event. */
845 845 ACPI_STATUS
846 846 acpidev_eval_ost(ACPI_HANDLE hdl, uint32_t code, uint32_t status,
847 847 char *bufp, size_t len)
848 848 {
849 849 ACPI_STATUS rc;
850 850 ACPI_OBJECT args[3];
851 851 ACPI_OBJECT_LIST arglist;
852 852
853 853 args[0].Type = ACPI_TYPE_INTEGER;
854 854 args[0].Integer.Value = code;
855 855 args[1].Type = ACPI_TYPE_INTEGER;
856 856 args[1].Integer.Value = status;
857 857 args[2].Type = ACPI_TYPE_BUFFER;
858 858 args[2].Buffer.Pointer = (UINT8 *)bufp;
859 859 args[2].Buffer.Length = (UINT32)len;
860 860 if (bufp == NULL || len == 0) {
861 861 arglist.Count = 2;
862 862 } else {
863 863 arglist.Count = 3;
864 864 }
865 865 arglist.Pointer = args;
866 866 rc = AcpiEvaluateObject(hdl, ACPIDEV_METHOD_NAME_OST, &arglist, NULL);
867 867 if (rc != AE_OK && rc != AE_NOT_FOUND) {
868 868 ACPIDEV_DEBUG(CE_WARN,
869 869 "!acpidev: failed to evaluate _OST method, code 0x%x.", rc);
870 870 }
871 871
872 872 return (rc);
873 873 }
874 874
875 875 ACPI_STATUS
876 876 acpidev_eval_ej0(ACPI_HANDLE hdl)
877 877 {
878 878 ACPI_STATUS rc;
879 879 ACPI_OBJECT args[1];
880 880 ACPI_OBJECT_LIST arglist;
881 881
882 882 /*
883 883 * Quotation from ACPI spec 4.0 section 6.3.3.
884 884 * Arg0 An Integer containing a device ejection control
885 885 * 0 Cancel a mark for ejection request (EJ0 will never be called
886 886 * with this value)
887 887 * 1 Hot eject or mark for ejection
888 888 */
889 889 args[0].Type = ACPI_TYPE_INTEGER;
890 890 args[0].Integer.Value = 1;
891 891 arglist.Count = 1;
892 892 arglist.Pointer = args;
893 893 rc = AcpiEvaluateObject(hdl, ACPIDEV_METHOD_NAME_EJ0, &arglist, NULL);
894 894 if (rc != AE_OK) {
895 895 ACPIDEV_DEBUG(CE_WARN,
896 896 "!acpidev: failed to evaluate _EJ0 method, code 0x%x.", rc);
897 897 }
898 898
899 899 return (rc);
900 900 }
901 901
902 902 ACPI_STATUS
903 903 acpidev_eval_pxm(ACPI_HANDLE hdl, uint32_t *idp)
904 904 {
905 905 int pxmid;
906 906
907 907 ASSERT(idp != NULL);
908 908
909 909 /*
910 910 * Try to evaluate ACPI _PXM method to get proximity doamin id.
911 911 * Quotation from ACPI4.0:
912 912 * If the Local APIC ID / Local SAPIC ID / Local x2APIC ID of a
913 913 * dynamically added processor is not present in the System Resource
914 914 * Affinity Table (SRAT), a _PXM object must exist for the processor's
915 915 * device or one of its ancestors in the ACPI Namespace.
916 916 */
917 917 while (hdl != NULL) {
918 918 if (ACPI_SUCCESS(acpica_eval_int(hdl,
919 919 ACPIDEV_METHOD_NAME_PXM, &pxmid))) {
920 920 *idp = (uint32_t)pxmid;
921 921 return (AE_OK);
922 922 }
923 923 if (ACPI_FAILURE(AcpiGetParent(hdl, &hdl))) {
924 924 break;
925 925 }
926 926 }
927 927
928 928 return (AE_NOT_FOUND);
929 929 }
↓ open down ↓ |
882 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX