4 * Copyright (C) 2018-2019 Red Hat, Inc.
7 * Pankaj Gupta <pagupta@redhat.com>
8 * David Hildenbrand <david@redhat.com>
10 * This work is licensed under the terms of the GNU GPL, version 2.
11 * See the COPYING file in the top-level directory.
14 #include "qemu/osdep.h"
15 #include "qapi/error.h"
16 #include "qemu-common.h"
17 #include "qemu/error-report.h"
18 #include "qemu/main-loop.h"
19 #include "hw/virtio/virtio-pmem.h"
20 #include "hw/virtio/virtio-access.h"
21 #include "standard-headers/linux/virtio_ids.h"
22 #include "standard-headers/linux/virtio_pmem.h"
23 #include "block/aio.h"
24 #include "block/thread-pool.h"
26 typedef struct VirtIODeviceRequest
{
27 VirtQueueElement elem
;
31 struct virtio_pmem_req req
;
32 struct virtio_pmem_resp resp
;
33 } VirtIODeviceRequest
;
35 static int worker_cb(void *opaque
)
37 VirtIODeviceRequest
*req_data
= opaque
;
40 /* flush raw backing image */
41 err
= fsync(req_data
->fd
);
46 virtio_stw_p(req_data
->vdev
, &req_data
->resp
.ret
, err
);
51 static void done_cb(void *opaque
, int ret
)
53 VirtIODeviceRequest
*req_data
= opaque
;
54 int len
= iov_from_buf(req_data
->elem
.in_sg
, req_data
->elem
.in_num
, 0,
55 &req_data
->resp
, sizeof(struct virtio_pmem_resp
));
57 /* Callbacks are serialized, so no need to use atomic ops. */
58 virtqueue_push(req_data
->pmem
->rq_vq
, &req_data
->elem
, len
);
59 virtio_notify((VirtIODevice
*)req_data
->pmem
, req_data
->pmem
->rq_vq
);
63 static void virtio_pmem_flush(VirtIODevice
*vdev
, VirtQueue
*vq
)
65 VirtIODeviceRequest
*req_data
;
66 VirtIOPMEM
*pmem
= VIRTIO_PMEM(vdev
);
67 HostMemoryBackend
*backend
= MEMORY_BACKEND(pmem
->memdev
);
68 ThreadPool
*pool
= aio_get_thread_pool(qemu_get_aio_context());
70 req_data
= virtqueue_pop(vq
, sizeof(VirtIODeviceRequest
));
72 virtio_error(vdev
, "virtio-pmem missing request data");
76 if (req_data
->elem
.out_num
< 1 || req_data
->elem
.in_num
< 1) {
77 virtio_error(vdev
, "virtio-pmem request not proper");
81 req_data
->fd
= memory_region_get_fd(&backend
->mr
);
82 req_data
->pmem
= pmem
;
83 req_data
->vdev
= vdev
;
84 thread_pool_submit_aio(pool
, worker_cb
, req_data
, done_cb
, req_data
);
87 static void virtio_pmem_get_config(VirtIODevice
*vdev
, uint8_t *config
)
89 VirtIOPMEM
*pmem
= VIRTIO_PMEM(vdev
);
90 struct virtio_pmem_config
*pmemcfg
= (struct virtio_pmem_config
*) config
;
92 virtio_stq_p(vdev
, &pmemcfg
->start
, pmem
->start
);
93 virtio_stq_p(vdev
, &pmemcfg
->size
, memory_region_size(&pmem
->memdev
->mr
));
96 static uint64_t virtio_pmem_get_features(VirtIODevice
*vdev
, uint64_t features
,
102 static void virtio_pmem_realize(DeviceState
*dev
, Error
**errp
)
104 VirtIODevice
*vdev
= VIRTIO_DEVICE(dev
);
105 VirtIOPMEM
*pmem
= VIRTIO_PMEM(dev
);
108 error_setg(errp
, "virtio-pmem memdev not set");
112 if (host_memory_backend_is_mapped(pmem
->memdev
)) {
113 char *path
= object_get_canonical_path_component(OBJECT(pmem
->memdev
));
114 error_setg(errp
, "can't use already busy memdev: %s", path
);
119 host_memory_backend_set_mapped(pmem
->memdev
, true);
120 virtio_init(vdev
, TYPE_VIRTIO_PMEM
, VIRTIO_ID_PMEM
,
121 sizeof(struct virtio_pmem_config
));
122 pmem
->rq_vq
= virtio_add_queue(vdev
, 128, virtio_pmem_flush
);
125 static void virtio_pmem_unrealize(DeviceState
*dev
, Error
**errp
)
127 VirtIODevice
*vdev
= VIRTIO_DEVICE(dev
);
128 VirtIOPMEM
*pmem
= VIRTIO_PMEM(dev
);
130 host_memory_backend_set_mapped(pmem
->memdev
, false);
131 virtio_cleanup(vdev
);
134 static void virtio_pmem_fill_device_info(const VirtIOPMEM
*pmem
,
135 VirtioPMEMDeviceInfo
*vi
)
137 vi
->memaddr
= pmem
->start
;
138 vi
->size
= memory_region_size(&pmem
->memdev
->mr
);
139 vi
->memdev
= object_get_canonical_path(OBJECT(pmem
->memdev
));
142 static MemoryRegion
*virtio_pmem_get_memory_region(VirtIOPMEM
*pmem
,
146 error_setg(errp
, "'%s' property must be set", VIRTIO_PMEM_MEMDEV_PROP
);
150 return &pmem
->memdev
->mr
;
153 static Property virtio_pmem_properties
[] = {
154 DEFINE_PROP_UINT64(VIRTIO_PMEM_ADDR_PROP
, VirtIOPMEM
, start
, 0),
155 DEFINE_PROP_LINK(VIRTIO_PMEM_MEMDEV_PROP
, VirtIOPMEM
, memdev
,
156 TYPE_MEMORY_BACKEND
, HostMemoryBackend
*),
157 DEFINE_PROP_END_OF_LIST(),
160 static void virtio_pmem_class_init(ObjectClass
*klass
, void *data
)
162 DeviceClass
*dc
= DEVICE_CLASS(klass
);
163 VirtioDeviceClass
*vdc
= VIRTIO_DEVICE_CLASS(klass
);
164 VirtIOPMEMClass
*vpc
= VIRTIO_PMEM_CLASS(klass
);
166 dc
->props
= virtio_pmem_properties
;
168 vdc
->realize
= virtio_pmem_realize
;
169 vdc
->unrealize
= virtio_pmem_unrealize
;
170 vdc
->get_config
= virtio_pmem_get_config
;
171 vdc
->get_features
= virtio_pmem_get_features
;
173 vpc
->fill_device_info
= virtio_pmem_fill_device_info
;
174 vpc
->get_memory_region
= virtio_pmem_get_memory_region
;
177 static TypeInfo virtio_pmem_info
= {
178 .name
= TYPE_VIRTIO_PMEM
,
179 .parent
= TYPE_VIRTIO_DEVICE
,
180 .class_size
= sizeof(VirtIOPMEMClass
),
181 .class_init
= virtio_pmem_class_init
,
182 .instance_size
= sizeof(VirtIOPMEM
),
185 static void virtio_register_types(void)
187 type_register_static(&virtio_pmem_info
);
190 type_init(virtio_register_types
)