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