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 */ 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_dr.h> 35 #include <sys/acpidev_impl.h> 36 37 static ACPI_STATUS acpidev_memory_probe(acpidev_walk_info_t *infop); 38 static acpidev_filter_result_t acpidev_memory_filter( 39 acpidev_walk_info_t *infop, char *devname, int maxlen); 40 static ACPI_STATUS acpidev_memory_init(acpidev_walk_info_t *infop); 41 42 /* 43 * Default class driver for ACPI memory objects. 44 */ 45 acpidev_class_t acpidev_class_memory = { 46 0, /* adc_refcnt */ 47 ACPIDEV_CLASS_REV1, /* adc_version */ 48 ACPIDEV_CLASS_ID_MEMORY, /* adc_class_id */ 49 "ACPI memory", /* adc_class_name */ 50 ACPIDEV_TYPE_MEMORY, /* adc_dev_type */ 51 NULL, /* adc_private */ 52 NULL, /* adc_pre_probe */ 53 NULL, /* adc_post_probe */ 54 acpidev_memory_probe, /* adc_probe */ 55 acpidev_memory_filter, /* adc_filter */ 56 acpidev_memory_init, /* adc_init */ 57 NULL, /* adc_fini */ 58 }; 59 60 /* 61 * List of class drivers which will be called in order when handling 62 * children of ACPI memory objects. 63 */ 64 acpidev_class_list_t *acpidev_class_list_memory = NULL; 65 66 static char *acpidev_memory_device_ids[] = { 67 ACPIDEV_HID_MEMORY, 68 }; 69 70 static char *acpidev_memory_uid_formats[] = { 71 "MEM%x-%x", 72 }; 73 74 /* Filter rule table for memory objects. */ 75 static acpidev_filter_rule_t acpidev_memory_filters[] = { 76 { /* Ignore all memory objects under the ACPI root object */ 77 NULL, 78 0, 79 ACPIDEV_FILTER_SKIP, 80 NULL, 81 1, 82 1, 83 NULL, 84 NULL, 85 }, 86 { /* Create node and scan child for all other memory objects */ 87 NULL, 88 0, 89 ACPIDEV_FILTER_DEFAULT, 90 &acpidev_class_list_device, 91 2, 92 INT_MAX, 93 NULL, 94 ACPIDEV_NODE_NAME_MEMORY, 95 } 96 }; 97 98 static ACPI_STATUS 99 acpidev_memory_probe(acpidev_walk_info_t *infop) 100 { 101 ACPI_STATUS rc = AE_OK; 102 int flags; 103 104 ASSERT(infop != NULL); 105 ASSERT(infop->awi_hdl != NULL); 106 ASSERT(infop->awi_info != NULL); 107 if (infop->awi_info->Type != ACPI_TYPE_DEVICE || 108 acpidev_match_device_id(infop->awi_info, 109 ACPIDEV_ARRAY_PARAM(acpidev_memory_device_ids)) == 0) { 110 return (AE_OK); 111 } 112 113 flags = ACPIDEV_PROCESS_FLAG_SCAN; 114 switch (infop->awi_op_type) { 115 case ACPIDEV_OP_BOOT_PROBE: 116 if (acpica_get_devcfg_feature(ACPI_DEVCFG_MEMORY)) { 117 flags |= ACPIDEV_PROCESS_FLAG_CREATE; 118 acpidev_dr_check(infop); 119 } 120 break; 121 122 case ACPIDEV_OP_BOOT_REPROBE: 123 break; 124 125 case ACPIDEV_OP_HOTPLUG_PROBE: 126 if (acpica_get_devcfg_feature(ACPI_DEVCFG_MEMORY)) { 127 flags |= ACPIDEV_PROCESS_FLAG_CREATE | 128 ACPIDEV_PROCESS_FLAG_SYNCSTATUS | 129 ACPIDEV_PROCESS_FLAG_HOLDBRANCH; 130 } 131 break; 132 133 default: 134 ACPIDEV_DEBUG(CE_WARN, "!acpidev: unknown operation type %u " 135 "in acpidev_memory_probe.", infop->awi_op_type); 136 rc = AE_BAD_PARAMETER; 137 break; 138 } 139 140 if (rc == AE_OK) { 141 rc = acpidev_process_object(infop, flags); 142 } 143 if (ACPI_FAILURE(rc) && rc != AE_NOT_EXIST && rc != AE_ALREADY_EXISTS) { 144 cmn_err(CE_WARN, 145 "!acpidev: failed to process memory object %s.", 146 infop->awi_name); 147 } else { 148 rc = AE_OK; 149 } 150 151 return (rc); 152 } 153 154 static acpidev_filter_result_t 155 acpidev_memory_filter(acpidev_walk_info_t *infop, char *devname, int maxlen) 156 { 157 acpidev_filter_result_t res; 158 159 ASSERT(infop != NULL); 160 if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE || 161 infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE || 162 infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) { 163 res = acpidev_filter_device(infop, infop->awi_hdl, 164 ACPIDEV_ARRAY_PARAM(acpidev_memory_filters), 165 devname, maxlen); 166 } else { 167 res = ACPIDEV_FILTER_FAILED; 168 } 169 170 return (res); 171 } 172 173 static ACPI_STATUS 174 acpidev_memory_init(acpidev_walk_info_t *infop) 175 { 176 char *compatible[] = { 177 ACPIDEV_TYPE_MEMORY, 178 "mem" 179 }; 180 181 ASSERT(infop != NULL); 182 ASSERT(infop->awi_hdl != NULL); 183 ASSERT(infop->awi_dip != NULL); 184 if (ACPI_FAILURE(acpidev_resource_process(infop, B_TRUE))) { 185 cmn_err(CE_WARN, "!acpidev: failed to process resources of " 186 "memory device %s.", infop->awi_name); 187 return (AE_ERROR); 188 } 189 190 if (ACPI_FAILURE(acpidev_set_compatible(infop, 191 ACPIDEV_ARRAY_PARAM(compatible)))) { 192 return (AE_ERROR); 193 } 194 195 if (ACPI_FAILURE(acpidev_set_unitaddr(infop, 196 ACPIDEV_ARRAY_PARAM(acpidev_memory_uid_formats), NULL))) { 197 return (AE_ERROR); 198 } 199 200 return (AE_OK); 201 }