qemu/hw/acpi/memory_hotplug_acpi_table.c
<<
>>
Prefs
   1/*
   2 * Memory hotplug AML code of DSDT ACPI table
   3 *
   4 * Copyright (C) 2015 Red Hat Inc
   5 *
   6 * Author: Igor Mammedov <imammedo@redhat.com>
   7 *
   8 * This work is licensed under the terms of the GNU GPL, version 2 or later.
   9 * See the COPYING file in the top-level directory.
  10 */
  11
  12#include "qemu/osdep.h"
  13#include "hw/acpi/memory_hotplug.h"
  14#include "include/hw/acpi/pc-hotplug.h"
  15#include "hw/boards.h"
  16
  17void build_memory_hotplug_aml(Aml *ctx, uint32_t nr_mem,
  18                              uint16_t io_base, uint16_t io_len)
  19{
  20    Aml *ifctx;
  21    Aml *method;
  22    Aml *pci_scope;
  23    Aml *mem_ctrl_dev;
  24
  25    /* scope for memory hotplug controller device node */
  26    pci_scope = aml_scope("_SB.PCI0");
  27    mem_ctrl_dev = aml_device(MEMORY_HOTPLUG_DEVICE);
  28    {
  29        Aml *one = aml_int(1);
  30        Aml *zero = aml_int(0);
  31        Aml *ret_val = aml_local(0);
  32        Aml *slot_arg0 = aml_arg(0);
  33        Aml *slots_nr = aml_name(MEMORY_SLOTS_NUMBER);
  34        Aml *ctrl_lock = aml_name(MEMORY_SLOT_LOCK);
  35        Aml *slot_selector = aml_name(MEMORY_SLOT_SLECTOR);
  36
  37        aml_append(mem_ctrl_dev, aml_name_decl("_HID", aml_string("PNP0A06")));
  38        aml_append(mem_ctrl_dev,
  39            aml_name_decl("_UID", aml_string("Memory hotplug resources")));
  40
  41        method = aml_method("_STA", 0, AML_NOTSERIALIZED);
  42        ifctx = aml_if(aml_equal(slots_nr, zero));
  43        {
  44            aml_append(ifctx, aml_return(zero));
  45        }
  46        aml_append(method, ifctx);
  47        /* present, functioning, decoding, not shown in UI */
  48        aml_append(method, aml_return(aml_int(0xB)));
  49        aml_append(mem_ctrl_dev, method);
  50
  51        aml_append(mem_ctrl_dev, aml_mutex(MEMORY_SLOT_LOCK, 0));
  52
  53        method = aml_method(MEMORY_SLOT_SCAN_METHOD, 0, AML_NOTSERIALIZED);
  54        {
  55            Aml *else_ctx;
  56            Aml *while_ctx;
  57            Aml *idx = aml_local(0);
  58            Aml *eject_req = aml_int(3);
  59            Aml *dev_chk = aml_int(1);
  60
  61            ifctx = aml_if(aml_equal(slots_nr, zero));
  62            {
  63                aml_append(ifctx, aml_return(zero));
  64            }
  65            aml_append(method, ifctx);
  66
  67            aml_append(method, aml_store(zero, idx));
  68            aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
  69            /* build AML that:
  70             * loops over all slots and Notifies DIMMs with
  71             * Device Check or Eject Request notifications if
  72             * slot has corresponding status bit set and clears
  73             * slot status.
  74             */
  75            while_ctx = aml_while(aml_lless(idx, slots_nr));
  76            {
  77                Aml *ins_evt = aml_name(MEMORY_SLOT_INSERT_EVENT);
  78                Aml *rm_evt = aml_name(MEMORY_SLOT_REMOVE_EVENT);
  79
  80                aml_append(while_ctx, aml_store(idx, slot_selector));
  81                ifctx = aml_if(aml_equal(ins_evt, one));
  82                {
  83                    aml_append(ifctx,
  84                               aml_call2(MEMORY_SLOT_NOTIFY_METHOD,
  85                                         idx, dev_chk));
  86                    aml_append(ifctx, aml_store(one, ins_evt));
  87                }
  88                aml_append(while_ctx, ifctx);
  89
  90                else_ctx = aml_else();
  91                ifctx = aml_if(aml_equal(rm_evt, one));
  92                {
  93                    aml_append(ifctx,
  94                        aml_call2(MEMORY_SLOT_NOTIFY_METHOD,
  95                                  idx, eject_req));
  96                    aml_append(ifctx, aml_store(one, rm_evt));
  97                }
  98                aml_append(else_ctx, ifctx);
  99                aml_append(while_ctx, else_ctx);
 100
 101                aml_append(while_ctx, aml_add(idx, one, idx));
 102            }
 103            aml_append(method, while_ctx);
 104            aml_append(method, aml_release(ctrl_lock));
 105            aml_append(method, aml_return(one));
 106        }
 107        aml_append(mem_ctrl_dev, method);
 108
 109        method = aml_method(MEMORY_SLOT_STATUS_METHOD, 1, AML_NOTSERIALIZED);
 110        {
 111            Aml *slot_enabled = aml_name(MEMORY_SLOT_ENABLED);
 112
 113            aml_append(method, aml_store(zero, ret_val));
 114            aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
 115            aml_append(method,
 116                aml_store(aml_to_integer(slot_arg0), slot_selector));
 117
 118            ifctx = aml_if(aml_equal(slot_enabled, one));
 119            {
 120                aml_append(ifctx, aml_store(aml_int(0xF), ret_val));
 121            }
 122            aml_append(method, ifctx);
 123
 124            aml_append(method, aml_release(ctrl_lock));
 125            aml_append(method, aml_return(ret_val));
 126        }
 127        aml_append(mem_ctrl_dev, method);
 128
 129        method = aml_method(MEMORY_SLOT_CRS_METHOD, 1, AML_SERIALIZED);
 130        {
 131            Aml *mr64 = aml_name("MR64");
 132            Aml *mr32 = aml_name("MR32");
 133            Aml *crs_tmpl = aml_resource_template();
 134            Aml *minl = aml_name("MINL");
 135            Aml *minh = aml_name("MINH");
 136            Aml *maxl =  aml_name("MAXL");
 137            Aml *maxh =  aml_name("MAXH");
 138            Aml *lenl = aml_name("LENL");
 139            Aml *lenh = aml_name("LENH");
 140
 141            aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
 142            aml_append(method, aml_store(aml_to_integer(slot_arg0),
 143                                         slot_selector));
 144
 145            aml_append(crs_tmpl,
 146                aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
 147                                 AML_CACHEABLE, AML_READ_WRITE,
 148                                 0, 0x0, 0xFFFFFFFFFFFFFFFEULL, 0,
 149                                 0xFFFFFFFFFFFFFFFFULL));
 150            aml_append(method, aml_name_decl("MR64", crs_tmpl));
 151            aml_append(method,
 152                aml_create_dword_field(mr64, aml_int(14), "MINL"));
 153            aml_append(method,
 154                aml_create_dword_field(mr64, aml_int(18), "MINH"));
 155            aml_append(method,
 156                aml_create_dword_field(mr64, aml_int(38), "LENL"));
 157            aml_append(method,
 158                aml_create_dword_field(mr64, aml_int(42), "LENH"));
 159            aml_append(method,
 160                aml_create_dword_field(mr64, aml_int(22), "MAXL"));
 161            aml_append(method,
 162                aml_create_dword_field(mr64, aml_int(26), "MAXH"));
 163
 164            aml_append(method,
 165                aml_store(aml_name(MEMORY_SLOT_ADDR_HIGH), minh));
 166            aml_append(method,
 167                aml_store(aml_name(MEMORY_SLOT_ADDR_LOW), minl));
 168            aml_append(method,
 169                aml_store(aml_name(MEMORY_SLOT_SIZE_HIGH), lenh));
 170            aml_append(method,
 171                aml_store(aml_name(MEMORY_SLOT_SIZE_LOW), lenl));
 172
 173            /* 64-bit math: MAX = MIN + LEN - 1 */
 174            aml_append(method, aml_add(minl, lenl, maxl));
 175            aml_append(method, aml_add(minh, lenh, maxh));
 176            ifctx = aml_if(aml_lless(maxl, minl));
 177            {
 178                aml_append(ifctx, aml_add(maxh, one, maxh));
 179            }
 180            aml_append(method, ifctx);
 181            ifctx = aml_if(aml_lless(maxl, one));
 182            {
 183                aml_append(ifctx, aml_subtract(maxh, one, maxh));
 184            }
 185            aml_append(method, ifctx);
 186            aml_append(method, aml_subtract(maxl, one, maxl));
 187
 188            /* return 32-bit _CRS if addr/size is in low mem */
 189            /* TODO: remove it since all hotplugged DIMMs are in high mem */
 190            ifctx = aml_if(aml_equal(maxh, zero));
 191            {
 192                crs_tmpl = aml_resource_template();
 193                aml_append(crs_tmpl,
 194                    aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED,
 195                                     AML_MAX_FIXED, AML_CACHEABLE,
 196                                     AML_READ_WRITE,
 197                                     0, 0x0, 0xFFFFFFFE, 0,
 198                                     0xFFFFFFFF));
 199                aml_append(ifctx, aml_name_decl("MR32", crs_tmpl));
 200                aml_append(ifctx,
 201                    aml_create_dword_field(mr32, aml_int(10), "MIN"));
 202                aml_append(ifctx,
 203                    aml_create_dword_field(mr32, aml_int(14), "MAX"));
 204                aml_append(ifctx,
 205                    aml_create_dword_field(mr32, aml_int(22), "LEN"));
 206                aml_append(ifctx, aml_store(minl, aml_name("MIN")));
 207                aml_append(ifctx, aml_store(maxl, aml_name("MAX")));
 208                aml_append(ifctx, aml_store(lenl, aml_name("LEN")));
 209
 210                aml_append(ifctx, aml_release(ctrl_lock));
 211                aml_append(ifctx, aml_return(mr32));
 212            }
 213            aml_append(method, ifctx);
 214
 215            aml_append(method, aml_release(ctrl_lock));
 216            aml_append(method, aml_return(mr64));
 217        }
 218        aml_append(mem_ctrl_dev, method);
 219
 220        method = aml_method(MEMORY_SLOT_PROXIMITY_METHOD, 1,
 221                            AML_NOTSERIALIZED);
 222        {
 223            Aml *proximity = aml_name(MEMORY_SLOT_PROXIMITY);
 224
 225            aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
 226            aml_append(method, aml_store(aml_to_integer(slot_arg0),
 227                                         slot_selector));
 228            aml_append(method, aml_store(proximity, ret_val));
 229            aml_append(method, aml_release(ctrl_lock));
 230            aml_append(method, aml_return(ret_val));
 231        }
 232        aml_append(mem_ctrl_dev, method);
 233
 234        method = aml_method(MEMORY_SLOT_OST_METHOD, 4, AML_NOTSERIALIZED);
 235        {
 236            Aml *ost_evt = aml_name(MEMORY_SLOT_OST_EVENT);
 237            Aml *ost_status = aml_name(MEMORY_SLOT_OST_STATUS);
 238
 239            aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
 240            aml_append(method, aml_store(aml_to_integer(slot_arg0),
 241                                         slot_selector));
 242            aml_append(method, aml_store(aml_arg(1), ost_evt));
 243            aml_append(method, aml_store(aml_arg(2), ost_status));
 244            aml_append(method, aml_release(ctrl_lock));
 245        }
 246        aml_append(mem_ctrl_dev, method);
 247
 248        method = aml_method(MEMORY_SLOT_EJECT_METHOD, 2, AML_NOTSERIALIZED);
 249        {
 250            Aml *eject = aml_name(MEMORY_SLOT_EJECT);
 251
 252            aml_append(method, aml_acquire(ctrl_lock, 0xFFFF));
 253            aml_append(method, aml_store(aml_to_integer(slot_arg0),
 254                                         slot_selector));
 255            aml_append(method, aml_store(one, eject));
 256            aml_append(method, aml_release(ctrl_lock));
 257        }
 258        aml_append(mem_ctrl_dev, method);
 259    }
 260    aml_append(pci_scope, mem_ctrl_dev);
 261    aml_append(ctx, pci_scope);
 262}
 263