linux/drivers/acpi/acpi_memhotplug.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2004 Intel Corporation <naveen.b.s@intel.com>
   3 *
   4 * All rights reserved.
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by
   8 * the Free Software Foundation; either version 2 of the License, or (at
   9 * your option) any later version.
  10 *
  11 * This program is distributed in the hope that it will be useful, but
  12 * WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
  14 * NON INFRINGEMENT.  See the GNU General Public License for more
  15 * details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, write to the Free Software
  19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20 *
  21 *
  22 * ACPI based HotPlug driver that supports Memory Hotplug
  23 * This driver fields notifications from firmware for memory add
  24 * and remove operations and alerts the VM of the affected memory
  25 * ranges.
  26 */
  27
  28#include <linux/kernel.h>
  29#include <linux/module.h>
  30#include <linux/init.h>
  31#include <linux/types.h>
  32#include <linux/memory_hotplug.h>
  33#include <linux/slab.h>
  34#include <acpi/acpi_drivers.h>
  35
  36#define ACPI_MEMORY_DEVICE_CLASS                "memory"
  37#define ACPI_MEMORY_DEVICE_HID                  "PNP0C80"
  38#define ACPI_MEMORY_DEVICE_NAME                 "Hotplug Mem Device"
  39
  40#define _COMPONENT              ACPI_MEMORY_DEVICE_COMPONENT
  41
  42#undef PREFIX
  43#define         PREFIX          "ACPI:memory_hp:"
  44
  45ACPI_MODULE_NAME("acpi_memhotplug");
  46MODULE_AUTHOR("Naveen B S <naveen.b.s@intel.com>");
  47MODULE_DESCRIPTION("Hotplug Mem Driver");
  48MODULE_LICENSE("GPL");
  49
  50/* Memory Device States */
  51#define MEMORY_INVALID_STATE    0
  52#define MEMORY_POWER_ON_STATE   1
  53#define MEMORY_POWER_OFF_STATE  2
  54
  55static int acpi_memory_device_add(struct acpi_device *device);
  56static int acpi_memory_device_remove(struct acpi_device *device, int type);
  57
  58static const struct acpi_device_id memory_device_ids[] = {
  59        {ACPI_MEMORY_DEVICE_HID, 0},
  60        {"", 0},
  61};
  62MODULE_DEVICE_TABLE(acpi, memory_device_ids);
  63
  64static struct acpi_driver acpi_memory_device_driver = {
  65        .name = "acpi_memhotplug",
  66        .class = ACPI_MEMORY_DEVICE_CLASS,
  67        .ids = memory_device_ids,
  68        .ops = {
  69                .add = acpi_memory_device_add,
  70                .remove = acpi_memory_device_remove,
  71                },
  72};
  73
  74struct acpi_memory_info {
  75        struct list_head list;
  76        u64 start_addr;         /* Memory Range start physical addr */
  77        u64 length;             /* Memory Range length */
  78        unsigned short caching; /* memory cache attribute */
  79        unsigned short write_protect;   /* memory read/write attribute */
  80        unsigned int enabled:1;
  81};
  82
  83struct acpi_memory_device {
  84        struct acpi_device * device;
  85        unsigned int state;     /* State of the memory device */
  86        struct list_head res_list;
  87};
  88
  89static int acpi_hotmem_initialized;
  90
  91static acpi_status
  92acpi_memory_get_resource(struct acpi_resource *resource, void *context)
  93{
  94        struct acpi_memory_device *mem_device = context;
  95        struct acpi_resource_address64 address64;
  96        struct acpi_memory_info *info, *new;
  97        acpi_status status;
  98
  99        status = acpi_resource_to_address64(resource, &address64);
 100        if (ACPI_FAILURE(status) ||
 101            (address64.resource_type != ACPI_MEMORY_RANGE))
 102                return AE_OK;
 103
 104        list_for_each_entry(info, &mem_device->res_list, list) {
 105                /* Can we combine the resource range information? */
 106                if ((info->caching == address64.info.mem.caching) &&
 107                    (info->write_protect == address64.info.mem.write_protect) &&
 108                    (info->start_addr + info->length == address64.minimum)) {
 109                        info->length += address64.address_length;
 110                        return AE_OK;
 111                }
 112        }
 113
 114        new = kzalloc(sizeof(struct acpi_memory_info), GFP_KERNEL);
 115        if (!new)
 116                return AE_ERROR;
 117
 118        INIT_LIST_HEAD(&new->list);
 119        new->caching = address64.info.mem.caching;
 120        new->write_protect = address64.info.mem.write_protect;
 121        new->start_addr = address64.minimum;
 122        new->length = address64.address_length;
 123        list_add_tail(&new->list, &mem_device->res_list);
 124
 125        return AE_OK;
 126}
 127
 128static int
 129acpi_memory_get_device_resources(struct acpi_memory_device *mem_device)
 130{
 131        acpi_status status;
 132        struct acpi_memory_info *info, *n;
 133
 134
 135        if (!list_empty(&mem_device->res_list))
 136                return 0;
 137
 138        status = acpi_walk_resources(mem_device->device->handle, METHOD_NAME__CRS,
 139                                     acpi_memory_get_resource, mem_device);
 140        if (ACPI_FAILURE(status)) {
 141                list_for_each_entry_safe(info, n, &mem_device->res_list, list)
 142                        kfree(info);
 143                INIT_LIST_HEAD(&mem_device->res_list);
 144                return -EINVAL;
 145        }
 146
 147        return 0;
 148}
 149
 150static int
 151acpi_memory_get_device(acpi_handle handle,
 152                       struct acpi_memory_device **mem_device)
 153{
 154        acpi_status status;
 155        acpi_handle phandle;
 156        struct acpi_device *device = NULL;
 157        struct acpi_device *pdevice = NULL;
 158        int result;
 159
 160
 161        if (!acpi_bus_get_device(handle, &device) && device)
 162                goto end;
 163
 164        status = acpi_get_parent(handle, &phandle);
 165        if (ACPI_FAILURE(status)) {
 166                ACPI_EXCEPTION((AE_INFO, status, "Cannot find acpi parent"));
 167                return -EINVAL;
 168        }
 169
 170        /* Get the parent device */
 171        result = acpi_bus_get_device(phandle, &pdevice);
 172        if (result) {
 173                printk(KERN_WARNING PREFIX "Cannot get acpi bus device");
 174                return -EINVAL;
 175        }
 176
 177        /*
 178         * Now add the notified device.  This creates the acpi_device
 179         * and invokes .add function
 180         */
 181        result = acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE);
 182        if (result) {
 183                printk(KERN_WARNING PREFIX "Cannot add acpi bus");
 184                return -EINVAL;
 185        }
 186
 187      end:
 188        *mem_device = acpi_driver_data(device);
 189        if (!(*mem_device)) {
 190                printk(KERN_ERR "\n driver data not found");
 191                return -ENODEV;
 192        }
 193
 194        return 0;
 195}
 196
 197static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
 198{
 199        unsigned long long current_status;
 200
 201        /* Get device present/absent information from the _STA */
 202        if (ACPI_FAILURE(acpi_evaluate_integer(mem_device->device->handle, "_STA",
 203                                               NULL, &current_status)))
 204                return -ENODEV;
 205        /*
 206         * Check for device status. Device should be
 207         * present/enabled/functioning.
 208         */
 209        if (!((current_status & ACPI_STA_DEVICE_PRESENT)
 210              && (current_status & ACPI_STA_DEVICE_ENABLED)
 211              && (current_status & ACPI_STA_DEVICE_FUNCTIONING)))
 212                return -ENODEV;
 213
 214        return 0;
 215}
 216
 217static int acpi_memory_enable_device(struct acpi_memory_device *mem_device)
 218{
 219        int result, num_enabled = 0;
 220        struct acpi_memory_info *info;
 221        int node;
 222
 223
 224        /* Get the range from the _CRS */
 225        result = acpi_memory_get_device_resources(mem_device);
 226        if (result) {
 227                printk(KERN_ERR PREFIX "get_device_resources failed\n");
 228                mem_device->state = MEMORY_INVALID_STATE;
 229                return result;
 230        }
 231
 232        node = acpi_get_node(mem_device->device->handle);
 233        /*
 234         * Tell the VM there is more memory here...
 235         * Note: Assume that this function returns zero on success
 236         * We don't have memory-hot-add rollback function,now.
 237         * (i.e. memory-hot-remove function)
 238         */
 239        list_for_each_entry(info, &mem_device->res_list, list) {
 240                if (info->enabled) { /* just sanity check...*/
 241                        num_enabled++;
 242                        continue;
 243                }
 244                /*
 245                 * If the memory block size is zero, please ignore it.
 246                 * Don't try to do the following memory hotplug flowchart.
 247                 */
 248                if (!info->length)
 249                        continue;
 250                if (node < 0)
 251                        node = memory_add_physaddr_to_nid(info->start_addr);
 252
 253                result = add_memory(node, info->start_addr, info->length);
 254                if (result)
 255                        continue;
 256                info->enabled = 1;
 257                num_enabled++;
 258        }
 259        if (!num_enabled) {
 260                printk(KERN_ERR PREFIX "add_memory failed\n");
 261                mem_device->state = MEMORY_INVALID_STATE;
 262                return -EINVAL;
 263        }
 264        /*
 265         * Sometimes the memory device will contain several memory blocks.
 266         * When one memory block is hot-added to the system memory, it will
 267         * be regarded as a success.
 268         * Otherwise if the last memory block can't be hot-added to the system
 269         * memory, it will be failure and the memory device can't be bound with
 270         * driver.
 271         */
 272        return 0;
 273}
 274
 275static int acpi_memory_powerdown_device(struct acpi_memory_device *mem_device)
 276{
 277        acpi_status status;
 278        struct acpi_object_list arg_list;
 279        union acpi_object arg;
 280        unsigned long long current_status;
 281
 282
 283        /* Issue the _EJ0 command */
 284        arg_list.count = 1;
 285        arg_list.pointer = &arg;
 286        arg.type = ACPI_TYPE_INTEGER;
 287        arg.integer.value = 1;
 288        status = acpi_evaluate_object(mem_device->device->handle,
 289                                      "_EJ0", &arg_list, NULL);
 290        /* Return on _EJ0 failure */
 291        if (ACPI_FAILURE(status)) {
 292                ACPI_EXCEPTION((AE_INFO, status, "_EJ0 failed"));
 293                return -ENODEV;
 294        }
 295
 296        /* Evalute _STA to check if the device is disabled */
 297        status = acpi_evaluate_integer(mem_device->device->handle, "_STA",
 298                                       NULL, &current_status);
 299        if (ACPI_FAILURE(status))
 300                return -ENODEV;
 301
 302        /* Check for device status.  Device should be disabled */
 303        if (current_status & ACPI_STA_DEVICE_ENABLED)
 304                return -EINVAL;
 305
 306        return 0;
 307}
 308
 309static int acpi_memory_disable_device(struct acpi_memory_device *mem_device)
 310{
 311        int result;
 312        struct acpi_memory_info *info, *n;
 313
 314
 315        /*
 316         * Ask the VM to offline this memory range.
 317         * Note: Assume that this function returns zero on success
 318         */
 319        list_for_each_entry_safe(info, n, &mem_device->res_list, list) {
 320                if (info->enabled) {
 321                        result = remove_memory(info->start_addr, info->length);
 322                        if (result)
 323                                return result;
 324                }
 325                kfree(info);
 326        }
 327
 328        /* Power-off and eject the device */
 329        result = acpi_memory_powerdown_device(mem_device);
 330        if (result) {
 331                /* Set the status of the device to invalid */
 332                mem_device->state = MEMORY_INVALID_STATE;
 333                return result;
 334        }
 335
 336        mem_device->state = MEMORY_POWER_OFF_STATE;
 337        return result;
 338}
 339
 340static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
 341{
 342        struct acpi_memory_device *mem_device;
 343        struct acpi_device *device;
 344        u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
 345
 346        switch (event) {
 347        case ACPI_NOTIFY_BUS_CHECK:
 348                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 349                                  "\nReceived BUS CHECK notification for device\n"));
 350                /* Fall Through */
 351        case ACPI_NOTIFY_DEVICE_CHECK:
 352                if (event == ACPI_NOTIFY_DEVICE_CHECK)
 353                        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 354                                          "\nReceived DEVICE CHECK notification for device\n"));
 355                if (acpi_memory_get_device(handle, &mem_device)) {
 356                        printk(KERN_ERR PREFIX "Cannot find driver data\n");
 357                        break;
 358                }
 359
 360                if (acpi_memory_check_device(mem_device))
 361                        break;
 362
 363                if (acpi_memory_enable_device(mem_device)) {
 364                        printk(KERN_ERR PREFIX "Cannot enable memory device\n");
 365                        break;
 366                }
 367
 368                ost_code = ACPI_OST_SC_SUCCESS;
 369                break;
 370
 371        case ACPI_NOTIFY_EJECT_REQUEST:
 372                ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 373                                  "\nReceived EJECT REQUEST notification for device\n"));
 374
 37L356" id="L356" class="line" name="L356"> 356busy_get_device" class="sref">acpie" name="L364"reak;
mem_device)) {
 356                        printk(KERN_ERR PREFIX);
                        break;
acpi_ob3ect_list ACPI_OST_SC_S63"> 363                if (, acpie"a href="drivers/acpi/acpi_memhotplug.c#L357"ct" class3"sref">acpi_object <3 href38lass="line" name="L359"> 58        }
             if (enabled) {
 356                        printk(KERN_ERR PREFIXlength);
/38ion for device\n"));
arg_list. 314
pointer = &<3 href38s zero, please ignore it.

 317integer. 317acpi_ob3">device->
 317arg_list, /39led" class="sref">ena2"> 362
 363                if (acpi_memory_en"sref">AC3I_FAILURE(staame="L37a {
 356                        printk(KERN_ERR PREFIXs3atus,  314
/*

/*
 316
/* Evalute _STA to c3eck i39ind driver data\n" 362

 336             mem_device->acpi_memoryle" class3"sref">handle, "_STA",
PREFIXacpi_ob3 358                }
4CPI_FAILURE(sssssssss>);
ena  continue;
                        break;
 314
/*

meuress="line" name="L317"> 317/*
/* Evalute _STA to c4" nam40d" class="sref">enable));
handle, "_STA&quOWER_OPREFIX<4s/acpi/ac4i_memhotplug.c#L308" id=4L308"40"L358"> 358                }
 371        case );
 372                ACPI_D4"L311"> 341        int staame="L37ref">enable));
(KERN_ERRce_notify(PREFIX<4"+code=in4o" class="sref">info4 *n;
 243                }
PREFIX<4" class="4ine" name="L315"> 315info);
         * Ask the4VM to41"L366"> 366                }
 327
 302         3184span 4lass="comment"(dle")emhotplug.c#L297" id="L297" cl 37L356" id="L356" class="line" _notify(("_EJ0", &res_list, PREFIX<4ss="sref"4info->info);
info->                        break;
 308
mem_device;
 343  emory_check_device" class="sref">acpi_memor4         4          return acpi_memory_e4tplug.c#L424" id="L324" class="lin4" nam4="L324"> 324 310{
kfree( 341{
 342        struct "_hotplug.c#L311" id="L311" class="line" name4klass="co4lug.c#L326" id="L326" cl4ss="l4ne" name="L326"> 326        }
 307}
/* 4ower-42e" name="L258"> 258        }
s="line" name="L343"> 343  emory_check_device" class="sref">acpi_memor4erdown_de4ice(status))
 3044330"> 3304/a>        if (ENODEV;
/* Set the s4atus 4f the device tss="line" name="L342"> 342        struct  309static int , &        }
             if ( 243      tatus))
 30443plug.c#L4lug.c#L334" id="L334" cl4ss="l4ne" name="L334"> 334        }
 335INIT_LIST_HEA       if (list_for_each_entry_safe(info, n, &(info, s="line" name="L343"> 343  _memhotplug.c#L329s="line" name="L343"> 343        struct  337<4a>        return value =tplugfss="line" name="tplugfs="line" name="L375"emhotplug.c_acpie">mem_device->mem_def (, &acpie">mem_device-> 368      >mem_def (acpi_evaluate_integer(, , & 3304ef">event, void *ENODEV;
 301
 302         * 310{
 363                if ( *mem_device);
 324                }
mem_devOWER_OFF_STATE;
 346        switch (info);
 307}
 328&qu4t;\nReceived BUS CHECK n4tific450 and eject the device */
 336        mem_device-Nt;state =  350                ENODEV;
 356<#L372class="sref">printk(KERN_ERRce_notify(acpie"mJ0", &n;
 314
"4nReceived DEVICE CHECK n4tific45 /*
 3164 &/*
 316 346"4annot45ffline this memory range.
 317 316
 328m58        }
 name328i/acinitializeders/acpi/acpi_memhot328i/acinitializedi_mem0", &mem_dame="L305"> 305
        }
emhot"L329" pi/acpi_memhotplug.c#L360" id="L360" class="line" name="L360"> 360                if (mem_devsult) {
 328"4lass="string">"Cann4t ena4le memory device\n&quoL310"> 310{
 363                if ( 305
 3224tplug.c#L466" id="L366" class="lin4" nam46ind driver data\n" 356                         3224tid="L3574i_memhotplug.c#L367" id=4L367"4class="line" name="L36s="sref">mem_devsult) {
(KERN_ERR PREFIX<4 ACPI_s="sref">info);
;
info);
(( 308
mem_device;
 343  , name="L308"> 308typn22" id="L322" class="line" name="L322"> 3224">"\4Received EJECT REQUEST n4tific47resuly_enable_device" class="sref">acpi_memory_e4s/acpi/ac4i_memhotplug.c#L374" id=4L374"4class="line" nme="L341"> 341{
 342        struct "_hotplug.c#L311" id="L311" class="line" name4memory_de4ice * 326        }
acpi_status            "> 258        }
s="line" name="L343"> 343   || 58        }
emhot
, acpie"id="L322" class="line" name="L322"> 3224" ACPI_OST_SC_Status))
 3044ct" class4"sref">acpi_object <4 href48"> 369                break;
 342        struct acpie"04" id="L304" class="line" name="L304"> 3044cde=ACPI_4i_memhotplug.c#L281" id=4L281"48 the device tss="line" name=href="drivers/acpi/acpi_memhotplug.c#L325" id             if (n;
/484=list" classOWER_OF05"> 305
arg_list.info);
pointer = &<4 href48lass=ug.c#L350" id="L350" class="line" name="L34 acpi/acp4ef="+code=ACPI_TYPE_INTE4ER" c48memory hotplug flowchart.integer.device-> 328arg_list, , acpi_memory_deviid="L322" class="line" name="L322"> 3224> 2904       /49ode=data" class="sref">data)
AC4I_FAILURE( 3044="sref">s4atus,  310{emhot/acpi_/a>, ,  3044= 2834         return -mem_device;
 3044=ass="sre4lug.c#L294" id="L294" cl4ss="l49e" name="L334"> 334        }
 335/acpi_/a>,  37L356" id="L356" class="line" name="L356"> 356busy="L325" class="line" name="L325"> 325                /* Evalute _STA to c4eck i49ind driver da>);
u32 ,  3224le" class4"sref">handle, "_STA&quOWER_OFF_STATE;
,  3044= 358                }
5CPI_FAILURE(m5        result = (HI       if (HI cpi_meotplug.c#L330" id="L330" class="line" name="5/a>      5         return -enass="line" name=href="drivers/acpi/acpi_memhotplug.c#L325" id="L325" class="line" name="L325"> 325                staOWER_OFF_STATE;
One" name="L356">AEOn    04" id="L304" class="line" name="L304"> 3045"comment"5/* Check for device stat5s.  D50lass="line" ns="sref">info);
      5         return - 335hardwar/_iders/acpi/acpi_mhardwar/_idc#L3_memhotplug.c#L329"+code=result" class="sref">result = ;
(,  3045"6>      5 _memhotplug.c#L295" id=5L305"506" class="sref">mine" name="L375"> rdwar/_iders/acpi/acpi_mhardwar/_idc#L3_mmemhotplug.c#L329span class="string">"_) ||4" id="L304" class="line" name="L304"> 3045"7>      5 t">/* Evalute _STA to c5" nam50d" class="sref">e
 rdwar/_iders/acpi/acpi_mhardwar/_idc#L3ce_notify(mem_def (mem_def ( 3225s8acpi/ac5isref">handle, "_STA&quame="L335"> 335/acpi_/a>, AEOn    04" id="L304" class="line" name="L304"> 3045"9acpi/ac5ia href="+code=current_s5L308"50"L358"> 358                }
 325                ;
,  3045"L311"> 351        int info);
info5 *n;
, n;
 341{
acpi_memory_devi+code=ACPI_DEBUG_PRINT" class="sref">ACPI_D5" class="5ine" name="L315"> 315mem_device)quot;_STA&quame="L335"> 335/a>;
hanctx="drivers/acpi/actx=c#L3cedle" cclass="sref">hanOWEv"drivers/acpi/acptvdeviid="L322" class="line" name="L322"> 3225class="co5ment">         * Ask the5VM to51"L366tplug.c#L330" id="L330" class="line" name="5>        5* Note: Assume that this5funct51lue" class="sref">value emhot/acpi_/a>, ,  3045 class="l5ne" name="L318"> 3185span 51"L358"> 358                }
res_list,  369                break;
->, acpi_memory_devii04" id="L304" class="line" name="L304"> 3045class="sr5f">info->u32 ,  3225         5             if ( 352      E) {
 328));
 335/acpi_/a>,  37L356" id="L356" class="line" u32 ACPI_D5kfree" cl5ss="sref">kfree(mem_device)quot;_STA&qut;_STA&quame="L335"> 335ug.c#L342" id="L34lass="l="line" name="L>
"_EJ0", & 328;
 352      E 328/* 5ower-52e" nas="sref">info);
 369                break;
 3305/a>        if (, n;
/* Set the s5atus 5rs/acpame="L335"> 335ug.c#L342" id=registerlass="le=acpi_ri/acpi_memhotplug.c#L342" id=registerlass="le=acpi_rs="line" name="L375"emhotstatic void acpi_memory_devi+code=ACPI_DEBUG_PRINT" class="sref">ACPI_D5a href="+5ode=MEMORY_INVALID_STATE5 clas53lass="line" name="L25)quot;_STA&qut;_STA&quame="L335"> 335/a>;
hanctx="drivers/acpi/actx=c#L3cedle" cclass="sref">hanOWEv"drivers/acpi/acptvdeviid="L322" class="line" name="L322"> 3225a        5          return acpi_memory_e53plug.c#L5lug.c#L334" id="L334" cl5ss="l535ass="line" name="L335"> 335emhot/acpi_/a>, ,  3045s/acpi/ac5i_memhotplug.c#L335" id=5L335"53lass=ug.c#L350" id="L350" class="line" name="L35alass="co5MEMORY_POWER_OFF_STATE" 5lass=53e" name="L326"> 326        }
 337<5a>        return value =acpi_/a>, acpi_memory_devii04" id="L304" class="line" name="L304"> 3045a        5_memhotplug.c#L338" id="5338" 53e" name="L258"> 2u32 ,  3225s/acpi/ac5i_memhotplug.c#L339" id=5L339"54tatus" class="sref">status;
 352      E) {
 328 3305ef">event, void *ENODEV;
,  37L356" id="L356" class="line"V" class="sref">ENODEV;
 *u32 ACPI_D5s        5acpi_device *mem_dev)quot;_STA&qut;_STA&quvice tss="line" name=ug.c#L342" id="L34lass="l="line" name="L>
 3045ST_SC_NON5SPECIFIC_FAILURE;  334        }
;
 352      E) {
 328        switch (info);
 307}
 308 352     _cinit                    >
 352     >
 307}
&qu5t;\nReceived BUS CHECK n5tific550 andy_enable_device" class="sref">acpi_memory_e50"> 350                 310{
, ,  3045+code=ACP5_NOTIFY_DEVICE_CHECK" cl5ss="s55ef="+code=n" class="sref">n;
));
"5nReceived DEVICE CHECK n5tific555ass="line" name="L335"> 335
,  356busy>
,  3045andle5 & 346"5annot55ind driver da>);
 307}
"_STA&quOWER_OFa>))
 3045+UG_PRINT558" id="L358" class="lin5" nam55"L358"> 358                }
,  u32 u32 ACPI_D5_check_de5ice(mem_dSTA&qut;_STA&quvice tss="line" name=     UINT32_MAa href="+code=pr     UINT32_MAadevi+code=ACPI_DEBUG_PRINT" class="sref">ACPI_D5_code=ACP5 class="line" name="L3615> 36156tus" class="sref">staame="L37ref">enable tss="line" name=ug.c#L342" iregisterlass="le=acpi_ri/acpi_memhotplug.c#L342" iregisterlass="le=acpi_rs="l" "_+code=ACPI_DEBUG_PRINT" class="sref">ACPI_D5_code=ACP5i_memhotplug.c#L362" id=5L362"56lass="line" name="L25)quot;_STA&qut;_STA&q"_+ "_EJ0", &));
"5lass="string">"Cann5t ena5le memory devi"> 2u32 , u32  372          Emem_device-> 346,  356busy>
,  3045tid="L3575i_memhotplug.c#L367" id=5L367"5class="line" name="L36OWER_OFa>))
 3045 ACPI_s="sref">info);
 369                break;
 3045ode=ACPI_5OTIFY_EJECT_REQUEST" cla5s="sr57tus" class="sOWER_OF05"> 305
info);
 308 352     _cexit                    >
 352     >
 307}
, ,  3045ass="sref5>acpi_status  307}
  358                }
acpi_object <5 href580 and eject th hotplug flowchart.

 316
 328 2835       /584=list" classhe device */,  u32 u32  328/acpi/ac5">arg_list.ACPI_D5 class="s5ef">pointer = &<5 href58 class="sref">mem_device)quot;_STA&qutame="L335"> 335ug.c#L342" id=registerlass="le=acpi_ri/acpi_memhotplug.c#L342" id=registerlass="le=acpi_rs="l" "_+code=ACPI_DEBUG_PRINT" class="sref">ACPI_D5 acpi/acp5ef="+code=ACPI_TYPE_INTE5ER" c58ind driver data\n" 335span class="string">"_+ "_EJ0", &integer. 307}
device-> 2u32 ,  3225t" class=5sref">arg_list, su32  372          Emem_device-> 3225tlong lon5       /59ENODEV" class="sref">ENODEV;
AC5I_FAILURE(,  356busy>
,  3045="sref">s5atus, n;
 3045=/acpi/ac5lug.c#L294" id="L294" cl5ss="l59lass=s="sref">info);
/* Evalute _STA to c5eck i59ind d"L356"> 356busymodulclinit"> 352     modulclinit="sr
 352     >
 3045=lass="sr5"sref">handle,  356busymodulclexit"> 352     modulclexit="sr
 352     >
 3045=


Tcpioriginal LXR softwar/aby acpi" id="L30http://aourceme=ge.net/proi/acs/lxr">LXR sysunitlline" otis_experistemal clas" n by " id="L30m=AEto:lxr@odeux.no">lxr@odeux.noline.
lxr.odeux.no kicpiy host" cby " id="L30http://www.redpill-odepro.no">Redpill Ldepro ASline" provid=r emhLdeuxvconacpit;