1 #include "hw/acpi/memory_hotplug.h" 2 #include "hw/acpi/pc-hotplug.h" 3 #include "hw/mem/pc-dimm.h" 4 #include "hw/boards.h" 5 6 static uint64_t acpi_memory_hotplug_read(void *opaque, hwaddr addr, 7 unsigned int size) 8 { 9 uint32_t val = 0; 10 MemHotplugState *mem_st = opaque; 11 MemStatus *mdev; 12 Object *o; 13 14 if (mem_st->selector >= mem_st->dev_count) { 15 return 0; 16 } 17 18 mdev = &mem_st->devs[mem_st->selector]; 19 o = OBJECT(mdev->dimm); 20 switch (addr) { 21 case 0x0: /* Lo part of phys address where DIMM is mapped */ 22 val = o ? object_property_get_int(o, PC_DIMM_ADDR_PROP, NULL) : 0; 23 break; 24 case 0x4: /* Hi part of phys address where DIMM is mapped */ 25 val = o ? object_property_get_int(o, PC_DIMM_ADDR_PROP, NULL) >> 32 : 0; 26 break; 27 case 0x8: /* Lo part of DIMM size */ 28 val = o ? object_property_get_int(o, PC_DIMM_SIZE_PROP, NULL) : 0; 29 break; 30 case 0xc: /* Hi part of DIMM size */ 31 val = o ? object_property_get_int(o, PC_DIMM_SIZE_PROP, NULL) >> 32 : 0; 32 break; 33 case 0x10: /* node proximity for _PXM method */ 34 val = o ? object_property_get_int(o, PC_DIMM_NODE_PROP, NULL) : 0; 35 break; 36 case 0x14: /* pack and return is_* fields */ 37 val |= mdev->is_enabled ? 1 : 0; 38 val |= mdev->is_inserting ? 2 : 0; 39 break; 40 default: 41 val = ~0; 42 break; 43 } 44 return val; 45 } 46 47 static void acpi_memory_hotplug_write(void *opaque, hwaddr addr, uint64_t data, 48 unsigned int size) 49 { 50 MemHotplugState *mem_st = opaque; 51 MemStatus *mdev; 52 53 if (!mem_st->dev_count) { 54 return; 55 } 56 57 if (addr) { 58 if (mem_st->selector >= mem_st->dev_count) { 59 return; 60 } 61 } 62 63 switch (addr) { 64 case 0x0: /* DIMM slot selector */ 65 mem_st->selector = data; 66 break; 67 case 0x4: /* _OST event */ 68 mdev = &mem_st->devs[mem_st->selector]; 69 if (data == 1) { 70 /* TODO: handle device insert OST event */ 71 } else if (data == 3) { 72 /* TODO: handle device remove OST event */ 73 } 74 mdev->ost_event = data; 75 break; 76 case 0x8: /* _OST status */ 77 mdev = &mem_st->devs[mem_st->selector]; 78 mdev->ost_status = data; 79 /* TODO: report async error */ 80 /* TODO: implement memory removal on guest signal */ 81 break; 82 case 0x14: 83 mdev = &mem_st->devs[mem_st->selector]; 84 if (data & 2) { /* clear insert event */ 85 mdev->is_inserting = false; 86 } 87 break; 88 } 89 90 } 91 static const MemoryRegionOps acpi_memory_hotplug_ops = { 92 .read = acpi_memory_hotplug_read, 93 .write = acpi_memory_hotplug_write, 94 .endianness = DEVICE_LITTLE_ENDIAN, 95 .valid = { 96 .min_access_size = 1, 97 .max_access_size = 4, 98 }, 99 }; 100 101 void acpi_memory_hotplug_init(MemoryRegion *as, Object *owner, 102 MemHotplugState *state) 103 { 104 MachineState *machine = MACHINE(qdev_get_machine()); 105 106 state->dev_count = machine->ram_slots; 107 if (!state->dev_count) { 108 return; 109 } 110 111 state->devs = g_malloc0(sizeof(*state->devs) * state->dev_count); 112 memory_region_init_io(&state->io, owner, &acpi_memory_hotplug_ops, state, 113 "apci-mem-hotplug", ACPI_MEMORY_HOTPLUG_IO_LEN); 114 memory_region_add_subregion(as, ACPI_MEMORY_HOTPLUG_BASE, &state->io); 115 } 116 117 void acpi_memory_plug_cb(ACPIREGS *ar, qemu_irq irq, MemHotplugState *mem_st, 118 DeviceState *dev, Error **errp) 119 { 120 MemStatus *mdev; 121 Error *local_err = NULL; 122 int slot = object_property_get_int(OBJECT(dev), "slot", &local_err); 123 124 if (local_err) { 125 error_propagate(errp, local_err); 126 return; 127 } 128 129 if (slot >= mem_st->dev_count) { 130 char *dev_path = object_get_canonical_path(OBJECT(dev)); 131 error_setg(errp, "acpi_memory_plug_cb: " 132 "device [%s] returned invalid memory slot[%d]", 133 dev_path, slot); 134 g_free(dev_path); 135 return; 136 } 137 138 mdev = &mem_st->devs[slot]; 139 mdev->dimm = dev; 140 mdev->is_enabled = true; 141 mdev->is_inserting = true; 142 143 /* do ACPI magic */ 144 ar->gpe.sts[0] |= ACPI_MEMORY_HOTPLUG_STATUS; 145 acpi_update_sci(ar, irq); 146 return; 147 } 148