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_impl.h> 34 35 static ACPI_STATUS acpidev_scope_probe(acpidev_walk_info_t *infop); 36 static acpidev_filter_result_t acpidev_scope_filter(acpidev_walk_info_t *infop, 37 char *devname, int maxlen); 38 static ACPI_STATUS acpidev_scope_init(acpidev_walk_info_t *infop); 39 40 /* 41 * Default class driver for ACPI scope objects. 42 * This class driver is used to handle predefined ACPI SCOPE objects 43 * under the ACPI root object, such as _PR_, _SB_ and _TZ_ etc. 44 * The default policy for ACPI SCOPE objects is SKIP. 45 */ 46 acpidev_class_t acpidev_class_scope = { 47 0, /* adc_refcnt */ 48 ACPIDEV_CLASS_REV1, /* adc_version */ 49 ACPIDEV_CLASS_ID_SCOPE, /* adc_class_id */ 50 "ACPI Scope", /* adc_class_name */ 51 ACPIDEV_TYPE_SCOPE, /* adc_dev_type */ 52 NULL, /* adc_private */ 53 NULL, /* adc_pre_probe */ 54 NULL, /* adc_post_probe */ 55 acpidev_scope_probe, /* adc_probe */ 56 acpidev_scope_filter, /* adc_filter */ 57 acpidev_scope_init, /* adc_init */ 58 NULL, /* adc_fini */ 59 }; 60 61 acpidev_class_list_t *acpidev_class_list_scope = NULL; 62 63 /* 64 * All SCOPE objects share a global pseudo unit address space across the system. 65 */ 66 static uint32_t acpidev_scope_unitaddr = 0; 67 68 /* Filter rule table for ACPI SCOPE objects. */ 69 static acpidev_filter_rule_t acpidev_scope_filters[] = { 70 { /* For safety, _SB_ is hardcoded as DEVICE by acpica */ 71 NULL, 72 0, 73 ACPIDEV_FILTER_DEFAULT, 74 &acpidev_class_list_device, 75 1, 76 1, 77 ACPIDEV_OBJECT_NAME_SB, 78 ACPIDEV_NODE_NAME_MODULE_SBD, 79 }, 80 { /* Handle _PR_ object. */ 81 NULL, 82 0, 83 ACPIDEV_FILTER_SCAN, 84 &acpidev_class_list_scope, 85 1, 86 1, 87 ACPIDEV_OBJECT_NAME_PR, 88 ACPIDEV_NODE_NAME_PROCESSOR, 89 }, 90 { /* Ignore all other scope objects. */ 91 NULL, 92 0, 93 ACPIDEV_FILTER_SKIP, 94 NULL, 95 1, 96 INT_MAX, 97 NULL, 98 NULL, 99 } 100 }; 101 102 static ACPI_STATUS 103 acpidev_scope_probe(acpidev_walk_info_t *infop) 104 { 105 ACPI_STATUS rc; 106 int flags; 107 108 ASSERT(infop != NULL); 109 ASSERT(infop->awi_hdl != NULL); 110 ASSERT(infop->awi_info != NULL); 111 if (infop->awi_info->Type != ACPI_TYPE_LOCAL_SCOPE) { 112 return (AE_OK); 113 } 114 115 if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE) { 116 flags = ACPIDEV_PROCESS_FLAG_SCAN | ACPIDEV_PROCESS_FLAG_CREATE; 117 rc = acpidev_process_object(infop, flags); 118 } else if (infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE) { 119 flags = ACPIDEV_PROCESS_FLAG_SCAN; 120 rc = acpidev_process_object(infop, flags); 121 } else if (infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) { 122 flags = ACPIDEV_PROCESS_FLAG_SCAN; 123 rc = acpidev_process_object(infop, flags); 124 } else { 125 ACPIDEV_DEBUG(CE_WARN, "acpidev: unknown operation type %u " 126 "in acpidev_scope_probe().", infop->awi_op_type); 127 rc = AE_BAD_PARAMETER; 128 } 129 if (ACPI_FAILURE(rc) && rc != AE_NOT_EXIST && rc != AE_ALREADY_EXISTS) { 130 cmn_err(CE_WARN, 131 "!acpidev: failed to process scope object %s.", 132 infop->awi_name); 133 } else { 134 rc = AE_OK; 135 } 136 137 return (rc); 138 } 139 140 static acpidev_filter_result_t 141 acpidev_scope_filter(acpidev_walk_info_t *infop, char *devname, int maxlen) 142 { 143 acpidev_filter_result_t res; 144 145 ASSERT(infop != NULL); 146 if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE || 147 infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE || 148 infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) { 149 res = acpidev_filter_device(infop, infop->awi_hdl, 150 ACPIDEV_ARRAY_PARAM(acpidev_scope_filters), 151 devname, maxlen); 152 } else { 153 ACPIDEV_DEBUG(CE_WARN, "acpidev: unknown operation type %u " 154 "in acpidev_scope_filter().", infop->awi_op_type); 155 res = ACPIDEV_FILTER_FAILED; 156 } 157 158 return (res); 159 } 160 161 /*ARGSUSED*/ 162 static ACPI_STATUS 163 acpidev_scope_init(acpidev_walk_info_t *infop) 164 { 165 char unitaddr[32]; 166 char *compatible[] = { 167 ACPIDEV_HID_SCOPE, 168 ACPIDEV_TYPE_SCOPE, 169 ACPIDEV_HID_VIRTNEX, 170 ACPIDEV_TYPE_VIRTNEX, 171 }; 172 173 ASSERT(infop != NULL); 174 ASSERT(infop->awi_hdl != NULL); 175 ASSERT(infop->awi_dip != NULL); 176 if (ACPI_FAILURE(acpidev_set_compatible(infop, 177 ACPIDEV_ARRAY_PARAM(compatible)))) { 178 return (AE_ERROR); 179 } 180 (void) snprintf(unitaddr, sizeof (unitaddr), "%u", 181 atomic_inc_32_nv(&acpidev_scope_unitaddr) - 1); 182 if (ACPI_FAILURE(acpidev_set_unitaddr(infop, NULL, 0, unitaddr))) { 183 return (AE_ERROR); 184 } 185 186 return (AE_OK); 187 } 188