1 #include "hw/acpi/memory_hotplug.h"
2 #include "hw/acpi/pc-hotplug.h"
3 #include "hw/mem/pc-dimm.h"
7 static uint64_t acpi_memory_hotplug_read(void *opaque
, hwaddr addr
,
11 MemHotplugState
*mem_st
= opaque
;
15 if (mem_st
->selector
>= mem_st
->dev_count
) {
16 trace_mhp_acpi_invalid_slot_selected(mem_st
->selector
);
20 mdev
= &mem_st
->devs
[mem_st
->selector
];
21 o
= OBJECT(mdev
->dimm
);
23 case 0x0: /* Lo part of phys address where DIMM is mapped */
24 val
= o
? object_property_get_int(o
, PC_DIMM_ADDR_PROP
, NULL
) : 0;
25 trace_mhp_acpi_read_addr_lo(mem_st
->selector
, val
);
27 case 0x4: /* Hi part of phys address where DIMM is mapped */
28 val
= o
? object_property_get_int(o
, PC_DIMM_ADDR_PROP
, NULL
) >> 32 : 0;
29 trace_mhp_acpi_read_addr_hi(mem_st
->selector
, val
);
31 case 0x8: /* Lo part of DIMM size */
32 val
= o
? object_property_get_int(o
, PC_DIMM_SIZE_PROP
, NULL
) : 0;
33 trace_mhp_acpi_read_size_lo(mem_st
->selector
, val
);
35 case 0xc: /* Hi part of DIMM size */
36 val
= o
? object_property_get_int(o
, PC_DIMM_SIZE_PROP
, NULL
) >> 32 : 0;
37 trace_mhp_acpi_read_size_hi(mem_st
->selector
, val
);
39 case 0x10: /* node proximity for _PXM method */
40 val
= o
? object_property_get_int(o
, PC_DIMM_NODE_PROP
, NULL
) : 0;
41 trace_mhp_acpi_read_pxm(mem_st
->selector
, val
);
43 case 0x14: /* pack and return is_* fields */
44 val
|= mdev
->is_enabled
? 1 : 0;
45 val
|= mdev
->is_inserting
? 2 : 0;
46 trace_mhp_acpi_read_flags(mem_st
->selector
, val
);
55 static void acpi_memory_hotplug_write(void *opaque
, hwaddr addr
, uint64_t data
,
58 MemHotplugState
*mem_st
= opaque
;
61 if (!mem_st
->dev_count
) {
66 if (mem_st
->selector
>= mem_st
->dev_count
) {
67 trace_mhp_acpi_invalid_slot_selected(mem_st
->selector
);
73 case 0x0: /* DIMM slot selector */
74 mem_st
->selector
= data
;
75 trace_mhp_acpi_write_slot(mem_st
->selector
);
77 case 0x4: /* _OST event */
78 mdev
= &mem_st
->devs
[mem_st
->selector
];
80 /* TODO: handle device insert OST event */
81 } else if (data
== 3) {
82 /* TODO: handle device remove OST event */
84 mdev
->ost_event
= data
;
85 trace_mhp_acpi_write_ost_ev(mem_st
->selector
, mdev
->ost_event
);
87 case 0x8: /* _OST status */
88 mdev
= &mem_st
->devs
[mem_st
->selector
];
89 mdev
->ost_status
= data
;
90 trace_mhp_acpi_write_ost_status(mem_st
->selector
, mdev
->ost_status
);
91 /* TODO: report async error */
92 /* TODO: implement memory removal on guest signal */
95 mdev
= &mem_st
->devs
[mem_st
->selector
];
96 if (data
& 2) { /* clear insert event */
97 mdev
->is_inserting
= false;
98 trace_mhp_acpi_clear_insert_evt(mem_st
->selector
);
104 static const MemoryRegionOps acpi_memory_hotplug_ops
= {
105 .read
= acpi_memory_hotplug_read
,
106 .write
= acpi_memory_hotplug_write
,
107 .endianness
= DEVICE_LITTLE_ENDIAN
,
109 .min_access_size
= 1,
110 .max_access_size
= 4,
114 void acpi_memory_hotplug_init(MemoryRegion
*as
, Object
*owner
,
115 MemHotplugState
*state
)
117 MachineState
*machine
= MACHINE(qdev_get_machine());
119 state
->dev_count
= machine
->ram_slots
;
120 if (!state
->dev_count
) {
124 state
->devs
= g_malloc0(sizeof(*state
->devs
) * state
->dev_count
);
125 memory_region_init_io(&state
->io
, owner
, &acpi_memory_hotplug_ops
, state
,
126 "apci-mem-hotplug", ACPI_MEMORY_HOTPLUG_IO_LEN
);
127 memory_region_add_subregion(as
, ACPI_MEMORY_HOTPLUG_BASE
, &state
->io
);
130 void acpi_memory_plug_cb(ACPIREGS
*ar
, qemu_irq irq
, MemHotplugState
*mem_st
,
131 DeviceState
*dev
, Error
**errp
)
134 Error
*local_err
= NULL
;
135 int slot
= object_property_get_int(OBJECT(dev
), "slot", &local_err
);
138 error_propagate(errp
, local_err
);
142 if (slot
>= mem_st
->dev_count
) {
143 char *dev_path
= object_get_canonical_path(OBJECT(dev
));
144 error_setg(errp
, "acpi_memory_plug_cb: "
145 "device [%s] returned invalid memory slot[%d]",
151 mdev
= &mem_st
->devs
[slot
];
153 mdev
->is_enabled
= true;
154 mdev
->is_inserting
= true;
157 ar
->gpe
.sts
[0] |= ACPI_MEMORY_HOTPLUG_STATUS
;
158 acpi_update_sci(ar
, irq
);