1 /*
   2  * Copyright (c) 2009, Intel Corporation.
   3  * All rights reserved.
   4  */
   5 
   6 #include <sys/types.h>
   7 #include <sys/atomic.h>
   8 #include <sys/sunddi.h>
   9 #include <sys/sunndi.h>
  10 #include <sys/acpi/acpi.h>
  11 #include <sys/acpica.h>
  12 #include <sys/acpidev.h>
  13 #include <sys/acpidev_rsc.h>
  14 #include <sys/acpidev_impl.h>
  15 
  16 static ACPI_STATUS acpidev_memory_probe(acpidev_walk_info_t *infop);
  17 static acpidev_filter_result_t acpidev_memory_filter(
  18     acpidev_walk_info_t *infop, char *devname, int maxlen);
  19 static ACPI_STATUS acpidev_memory_init(acpidev_walk_info_t *infop);
  20 
  21 /*
  22  * Default class driver for ACPI memory objects.
  23  */
  24 acpidev_class_t acpidev_class_memory = {
  25         0,                              /* adc_refcnt */
  26         ACPIDEV_CLASS_REV1,             /* adc_version */
  27         ACPIDEV_CLASS_ID_MEMORY,        /* adc_class_id */
  28         "ACPI memory",                  /* adc_class_name */
  29         ACPIDEV_TYPE_MEMORY,            /* adc_dev_type */
  30         NULL,                           /* adc_private */
  31         NULL,                           /* adc_pre_probe */
  32         NULL,                           /* adc_post_probe */
  33         acpidev_memory_probe,           /* adc_probe */
  34         acpidev_memory_filter,          /* adc_filter */
  35         acpidev_memory_init,            /* adc_init */
  36         NULL,                           /* adc_fini */
  37 };
  38 
  39 /*
  40  * List head of class drivers which will be called in order when handling
  41  * children of ACPI memory object.
  42  */
  43 acpidev_class_list_t *acpidev_class_list_memory = NULL;
  44 
  45 static char *acpidev_memory_device_ids[] = {
  46         ACPIDEV_HID_MEMORY,
  47 };
  48 
  49 static char *acpidev_memory_uid_formats[] = {
  50         "MEM%x-%x",
  51 };
  52 
  53 /* Filter rule table for memory objects. */
  54 static acpidev_filter_rule_t acpidev_memory_filters[] = {
  55         {       /* Ignore all memory objects under ACPI root object */
  56                 NULL,
  57                 0,
  58                 ACPIDEV_FILTER_SKIP,
  59                 NULL,
  60                 1,
  61                 1,
  62                 NULL,
  63                 NULL,
  64         },
  65         {       /* Create node and scan child for all other memory objects */
  66                 NULL,
  67                 0,
  68                 ACPIDEV_FILTER_DEFAULT,
  69                 &acpidev_class_list_device,
  70                 2,
  71                 INT_MAX,
  72                 NULL,
  73                 ACPIDEV_NODE_NAME_MEMORY,
  74         }
  75 };
  76 
  77 static ACPI_STATUS
  78 acpidev_memory_probe(acpidev_walk_info_t *infop)
  79 {
  80         ACPI_STATUS rc;
  81         int flags;
  82 
  83         ASSERT(infop != NULL);
  84         ASSERT(infop->awi_hdl != NULL);
  85         ASSERT(infop->awi_info != NULL);
  86         if (infop->awi_info->Type != ACPI_TYPE_DEVICE ||
  87             acpidev_match_device_id(infop->awi_info,
  88             ACPIDEV_ARRAY_PARAM(acpidev_memory_device_ids)) == 0) {
  89                 return (AE_OK);
  90         }
  91 
  92         if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE) {
  93                 flags = ACPIDEV_PROCESS_FLAG_SCAN | ACPIDEV_PROCESS_FLAG_CREATE;
  94                 rc = acpidev_process_object(infop, flags);
  95         } else if (infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE) {
  96                 flags = ACPIDEV_PROCESS_FLAG_SCAN;
  97                 rc = acpidev_process_object(infop, flags);
  98         } else if (infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
  99                 flags = ACPIDEV_PROCESS_FLAG_SCAN | ACPIDEV_PROCESS_FLAG_CREATE;
 100                 rc = acpidev_process_object(infop, flags);
 101         } else {
 102                 ACPIDEV_DEBUG(CE_WARN,
 103                     "acpidev: unknown operation type %u in memory_probe.",
 104                     infop->awi_op_type);
 105                 rc = AE_BAD_PARAMETER;
 106         }
 107         if (ACPI_FAILURE(rc) && rc != AE_NOT_EXIST && rc != AE_ALREADY_EXISTS) {
 108                 cmn_err(CE_CONT,
 109                     "acpidev: failed to process memory object %s.\n",
 110                     infop->awi_name);
 111         } else {
 112                 rc = AE_OK;
 113         }
 114 
 115         return (rc);
 116 }
 117 
 118 static acpidev_filter_result_t
 119 acpidev_memory_filter(acpidev_walk_info_t *infop, char *devname, int maxlen)
 120 {
 121         acpidev_filter_result_t res;
 122 
 123         ASSERT(infop != NULL);
 124         if (infop->awi_op_type == ACPIDEV_OP_BOOT_PROBE ||
 125             infop->awi_op_type == ACPIDEV_OP_BOOT_REPROBE ||
 126             infop->awi_op_type == ACPIDEV_OP_HOTPLUG_PROBE) {
 127                 res = acpidev_filter_device(infop, infop->awi_hdl,
 128                     ACPIDEV_ARRAY_PARAM(acpidev_memory_filters),
 129                     devname, maxlen);
 130         } else {
 131                 res = ACPIDEV_FILTER_FAILED;
 132         }
 133 
 134         return (res);
 135 }
 136 
 137 /*ARGSUSED*/
 138 static ACPI_STATUS
 139 acpidev_memory_init(acpidev_walk_info_t *infop)
 140 {
 141         char *compatibles[] = {
 142                 ACPIDEV_TYPE_MEMORY,
 143                 "mem"
 144         };
 145 
 146         ASSERT(infop != NULL);
 147         ASSERT(infop->awi_hdl != NULL);
 148         ASSERT(infop->awi_dip != NULL);
 149         if (ACPI_FAILURE(acpidev_resource_process(infop, B_TRUE))) {
 150                 cmn_err(CE_WARN,
 151                     "acpidev: failed to process resources of memory device %s.",
 152                     infop->awi_name);
 153                 return (AE_ERROR);
 154         }
 155 
 156         if (ACPI_FAILURE(acpidev_set_compatibles(infop,
 157             ACPIDEV_ARRAY_PARAM(compatibles)))) {
 158                 return (AE_ERROR);
 159         }
 160 
 161         if (ACPI_FAILURE(acpidev_set_unitaddr(infop,
 162             ACPIDEV_ARRAY_PARAM(acpidev_memory_uid_formats), NULL))) {
 163                 return (AE_ERROR);
 164         }
 165 
 166         return (AE_OK);
 167 }