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-2010, Intel Corporation. 23 * All rights reserved. 24 * Copyright (c) 2018, Joyent, Inc. 25 */ 26 27 #include <sys/types.h> 28 #include <sys/atomic.h> 29 #include <sys/sunddi.h> 30 #include <sys/sunndi.h> 31 #include <sys/acpi/acpi.h> 32 #include <sys/acpica.h> 33 #include <sys/acpidev.h> 34 #include <sys/acpidev_impl.h> 35 #include <sys/pci.h> 36 37 static ACPI_STATUS acpidev_device_probe(acpidev_walk_info_t *infop); 38 static acpidev_filter_result_t acpidev_device_filter(acpidev_walk_info_t *infop, 39 char *devname, int maxlen); 40 static acpidev_filter_result_t acpidev_device_filter_usb(acpidev_walk_info_t *, 41 ACPI_HANDLE, acpidev_filter_rule_t *, char *, int); 42 static ACPI_STATUS acpidev_device_init(acpidev_walk_info_t *infop); 43 44 static uint32_t acpidev_device_unitaddr = 0; 45 46 /* 47 * Default class driver for ACPI DEVICE objects. 48 * The default policy for DEVICE objects is to scan child objects without 49 * creating device nodes. But some special DEVICE objects will have device 50 * nodes created for them. 51 */ 52 acpidev_class_t acpidev_class_device = { 53 0, /* adc_refcnt */ 54 ACPIDEV_CLASS_REV1, /* adc_version */ 55 ACPIDEV_CLASS_ID_DEVICE, /* adc_class_id */ 56 "ACPI Device", /* adc_class_name */ 57 ACPIDEV_TYPE_DEVICE, /* adc_dev_type */ 58 NULL, /* adc_private */ 59 NULL, /* adc_pre_probe */ 60 NULL, /* adc_post_probe */ 61 acpidev_device_probe, /* adc_probe */ 62 acpidev_device_filter, /* adc_filter */ 63 acpidev_device_init, /* adc_init */ 64 NULL, /* adc_fini */ 65 }; 66 67 /* 68 * List of class drivers which will be called in order when handling 69 * children of ACPI DEVICE objects. 70 */ 71 acpidev_class_list_t *acpidev_class_list_device = NULL; 72 73 /* Filter rule table for boot. */ 74 static acpidev_filter_rule_t acpidev_device_filters[] = { 75 { /* _SB_ object type is hardcoded to DEVICE by acpica */ 76 NULL, 77 0, 78 ACPIDEV_FILTER_DEFAULT, 79 &acpidev_class_list_device, 80 1, 81 1, 82 ACPIDEV_OBJECT_NAME_SB, 83 ACPIDEV_NODE_NAME_MODULE_SBD, 84 }, 85 { /* Ignore other device objects under ACPI root object */ 86 NULL, 87 0, 88 ACPIDEV_FILTER_SKIP, 89 NULL, 90 1, 91 1, 92 NULL, 93 NULL, 94 }, 95 { /* Scan a device attempting to find a USB node */ 96 acpidev_device_filter_usb, 97 0, 98 ACPIDEV_FILTER_SCAN, 99 &acpidev_class_list_usbport, 100 2, 101 INT_MAX, 102 NULL, 103 NULL 104 }, 105 { /* Scan other device objects not directly under ACPI root */ 106 NULL, 107 0, 108 ACPIDEV_FILTER_SCAN, 109 &acpidev_class_list_device, 110 2, 111 INT_MAX, 112 NULL, 113 NULL, 114 } 115 }; 116 117 static ACPI_STATUS 118 acpidev_device_probe(acpidev_walk_info_t *infop) 119 { 120 ACPI_STATUS rc = AE_OK; 121 int flags; 122 123 ASSERT(infop != NULL); 124 ASSERT(infop->awi_hdl != NULL); 125 ASSERT(infop->awi_info != NULL); 126 127 if (infop->awi_info->Type != ACPI_TYPE_DEVICE) { 128 return (AE_OK); 129 } 130 131 flags = ACPIDEV_PROCESS_FLAG_SCAN; 132 switch (infop->awi_op_type) { 133 case ACPIDEV_OP_BOOT_PROBE: 134 flags |= ACPIDEV_PROCESS_FLAG_CREATE; 135 break; 136 137 case ACPIDEV_OP_BOOT_REPROBE: 138 break; 139 140 case ACPIDEV_OP_HOTPLUG_PROBE: 141 flags |= ACPIDEV_PROCESS_FLAG_CREATE | 142 ACPIDEV_PROCESS_FLAG_SYNCSTATUS | 143 ACPIDEV_PROCESS_FLAG_HOLDBRANCH; 144 break; 145 146 default: 147 ACPIDEV_DEBUG(CE_WARN, 148 "!acpidev: unknown operation type %u in " 149 "acpi_device_probe().", infop->awi_op_type); 150 rc = AE_BAD_PARAMETER; 151 break; 152 } 153 154 if (rc == AE_OK) { 155 rc = acpidev_process_object(infop, flags); 156 } 157 if (ACPI_FAILURE(rc) && rc != AE_NOT_EXIST && rc != AE_ALREADY_EXISTS) { 158 cmn_err(CE_WARN, 159 "!acpidev: failed to process device object %s.", 160 infop->awi_name); 161 } else { 162 rc = AE_OK; 163 } 164 165 return (rc); 166 } 167 168 /* 169 * Attempt to determine which devices here correspond to an HCI for a USB 170 * controller. 171 */ 172 static acpidev_filter_result_t 173 acpidev_device_filter_usb(acpidev_walk_info_t *infop, ACPI_HANDLE hdl, 174 acpidev_filter_rule_t *afrp, char *devname, int len) 175 { 176 dev_info_t *dip; 177 char **compat; 178 uint_t ncompat, i; 179 180 if (infop->awi_op_type != ACPIDEV_OP_BOOT_REPROBE) 181 return (ACPIDEV_FILTER_SKIP); 182 183 /* 184 * If we don't find a dip that matches this one, then let's not worry 185 * about it. This means that it may not be a device we care about in any 186 * way. 187 */ 188 if (ACPI_FAILURE(acpica_get_devinfo(hdl, &dip))) { 189 return (ACPIDEV_FILTER_SKIP); 190 } 191 192 /* 193 * To determine if this is a PCI USB class controller, we grab its 194 * compatible array and look for an instance of pciclass,0c03 or 195 * pciexclass,0c03. The class code 0c03 is used to indicate a USB 196 * controller. 197 */ 198 if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 199 "compatible", &compat, &ncompat) != DDI_SUCCESS) { 200 return (ACPIDEV_FILTER_SKIP); 201 } 202 203 for (i = 0; i < ncompat; i++) { 204 if (strcmp(compat[i], "pciclass,0c03") == 0 || 205 strcmp(compat[i], "pciexclass,0c03") == 0) { 206 ddi_prop_free(compat); 207 /* 208 * We've found a PCI based USB controller. Switch to the 209 * USB specific parser. 210 */ 211 return (ACPIDEV_FILTER_SCAN); 212 } 213 } 214 215 ddi_prop_free(compat); 216 return (ACPIDEV_FILTER_SKIP); 217 } 218 219 static acpidev_filter_result_t 220 acpidev_device_filter(acpidev_walk_info_t *infop, char *devname, int maxlen) 221 { 222 acpidev_filter_result_t res; 223 224 ASSERT(infop != NULL); 225 if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE || 226 infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE || 227 infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) { 228 res = acpidev_filter_device(infop, infop->awi_hdl, 229 ACPIDEV_ARRAY_PARAM(acpidev_device_filters), 230 devname, maxlen); 231 } else { 232 ACPIDEV_DEBUG(CE_WARN, "!acpidev: unknown operation type %u " 233 "in acpidev_device_filter().", infop->awi_op_type); 234 res = ACPIDEV_FILTER_FAILED; 235 } 236 237 return (res); 238 } 239 240 static ACPI_STATUS 241 acpidev_device_init(acpidev_walk_info_t *infop) 242 { 243 char unitaddr[32]; 244 char *compatible[] = { 245 ACPIDEV_TYPE_DEVICE, 246 ACPIDEV_HID_VIRTNEX, 247 ACPIDEV_TYPE_VIRTNEX, 248 }; 249 250 if (ACPI_FAILURE(acpidev_set_compatible(infop, 251 ACPIDEV_ARRAY_PARAM(compatible)))) { 252 return (AE_ERROR); 253 } 254 (void) snprintf(unitaddr, sizeof (unitaddr), "%u", 255 atomic_inc_32_nv(&acpidev_device_unitaddr) - 1); 256 if (ACPI_FAILURE(acpidev_set_unitaddr(infop, NULL, 0, unitaddr))) { 257 return (AE_ERROR); 258 } 259 260 return (AE_OK); 261 } 262