15f503cd9SPankaj Gupta /*
25f503cd9SPankaj Gupta * Virtio PMEM device
35f503cd9SPankaj Gupta *
45f503cd9SPankaj Gupta * Copyright (C) 2018-2019 Red Hat, Inc.
55f503cd9SPankaj Gupta *
65f503cd9SPankaj Gupta * Authors:
75f503cd9SPankaj Gupta * Pankaj Gupta <pagupta@redhat.com>
85f503cd9SPankaj Gupta * David Hildenbrand <david@redhat.com>
95f503cd9SPankaj Gupta *
105f503cd9SPankaj Gupta * This work is licensed under the terms of the GNU GPL, version 2.
115f503cd9SPankaj Gupta * See the COPYING file in the top-level directory.
125f503cd9SPankaj Gupta */
135f503cd9SPankaj Gupta
145f503cd9SPankaj Gupta #include "qemu/osdep.h"
155f503cd9SPankaj Gupta #include "qapi/error.h"
165f503cd9SPankaj Gupta #include "qemu/error-report.h"
17e2c1c34fSMarkus Armbruster #include "qemu/iov.h"
18db725815SMarkus Armbruster #include "qemu/main-loop.h"
195f503cd9SPankaj Gupta #include "hw/virtio/virtio-pmem.h"
20a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
215f503cd9SPankaj Gupta #include "hw/virtio/virtio-access.h"
225f503cd9SPankaj Gupta #include "standard-headers/linux/virtio_ids.h"
235f503cd9SPankaj Gupta #include "standard-headers/linux/virtio_pmem.h"
247969dd91SMarkus Armbruster #include "sysemu/hostmem.h"
255f503cd9SPankaj Gupta #include "block/aio.h"
265f503cd9SPankaj Gupta #include "block/thread-pool.h"
2773b12307SPankaj Gupta #include "trace.h"
285f503cd9SPankaj Gupta
295f503cd9SPankaj Gupta typedef struct VirtIODeviceRequest {
305f503cd9SPankaj Gupta VirtQueueElement elem;
315f503cd9SPankaj Gupta int fd;
325f503cd9SPankaj Gupta VirtIOPMEM *pmem;
335f503cd9SPankaj Gupta VirtIODevice *vdev;
345f503cd9SPankaj Gupta struct virtio_pmem_req req;
355f503cd9SPankaj Gupta struct virtio_pmem_resp resp;
365f503cd9SPankaj Gupta } VirtIODeviceRequest;
375f503cd9SPankaj Gupta
worker_cb(void * opaque)385f503cd9SPankaj Gupta static int worker_cb(void *opaque)
395f503cd9SPankaj Gupta {
405f503cd9SPankaj Gupta VirtIODeviceRequest *req_data = opaque;
415f503cd9SPankaj Gupta int err = 0;
425f503cd9SPankaj Gupta
435f503cd9SPankaj Gupta /* flush raw backing image */
445f503cd9SPankaj Gupta err = fsync(req_data->fd);
4573b12307SPankaj Gupta trace_virtio_pmem_flush_done(err);
465f503cd9SPankaj Gupta if (err != 0) {
475f503cd9SPankaj Gupta err = 1;
485f503cd9SPankaj Gupta }
495f503cd9SPankaj Gupta
50d2adda34SWang Liang virtio_stl_p(req_data->vdev, &req_data->resp.ret, err);
515f503cd9SPankaj Gupta
525f503cd9SPankaj Gupta return 0;
535f503cd9SPankaj Gupta }
545f503cd9SPankaj Gupta
done_cb(void * opaque,int ret)555f503cd9SPankaj Gupta static void done_cb(void *opaque, int ret)
565f503cd9SPankaj Gupta {
575f503cd9SPankaj Gupta VirtIODeviceRequest *req_data = opaque;
585f503cd9SPankaj Gupta int len = iov_from_buf(req_data->elem.in_sg, req_data->elem.in_num, 0,
595f503cd9SPankaj Gupta &req_data->resp, sizeof(struct virtio_pmem_resp));
605f503cd9SPankaj Gupta
615f503cd9SPankaj Gupta /* Callbacks are serialized, so no need to use atomic ops. */
625f503cd9SPankaj Gupta virtqueue_push(req_data->pmem->rq_vq, &req_data->elem, len);
635f503cd9SPankaj Gupta virtio_notify((VirtIODevice *)req_data->pmem, req_data->pmem->rq_vq);
6473b12307SPankaj Gupta trace_virtio_pmem_response();
655f503cd9SPankaj Gupta g_free(req_data);
665f503cd9SPankaj Gupta }
675f503cd9SPankaj Gupta
virtio_pmem_flush(VirtIODevice * vdev,VirtQueue * vq)685f503cd9SPankaj Gupta static void virtio_pmem_flush(VirtIODevice *vdev, VirtQueue *vq)
695f503cd9SPankaj Gupta {
705f503cd9SPankaj Gupta VirtIODeviceRequest *req_data;
715f503cd9SPankaj Gupta VirtIOPMEM *pmem = VIRTIO_PMEM(vdev);
725f503cd9SPankaj Gupta HostMemoryBackend *backend = MEMORY_BACKEND(pmem->memdev);
735f503cd9SPankaj Gupta
7473b12307SPankaj Gupta trace_virtio_pmem_flush_request();
755f503cd9SPankaj Gupta req_data = virtqueue_pop(vq, sizeof(VirtIODeviceRequest));
765f503cd9SPankaj Gupta if (!req_data) {
775f503cd9SPankaj Gupta virtio_error(vdev, "virtio-pmem missing request data");
785f503cd9SPankaj Gupta return;
795f503cd9SPankaj Gupta }
805f503cd9SPankaj Gupta
815f503cd9SPankaj Gupta if (req_data->elem.out_num < 1 || req_data->elem.in_num < 1) {
825f503cd9SPankaj Gupta virtio_error(vdev, "virtio-pmem request not proper");
832bc9e0daSLi Qiang virtqueue_detach_element(vq, (VirtQueueElement *)req_data, 0);
845f503cd9SPankaj Gupta g_free(req_data);
855f503cd9SPankaj Gupta return;
865f503cd9SPankaj Gupta }
875f503cd9SPankaj Gupta req_data->fd = memory_region_get_fd(&backend->mr);
885f503cd9SPankaj Gupta req_data->pmem = pmem;
895f503cd9SPankaj Gupta req_data->vdev = vdev;
90aef04fc7SEmanuele Giuseppe Esposito thread_pool_submit_aio(worker_cb, req_data, done_cb, req_data);
915f503cd9SPankaj Gupta }
925f503cd9SPankaj Gupta
virtio_pmem_get_config(VirtIODevice * vdev,uint8_t * config)935f503cd9SPankaj Gupta static void virtio_pmem_get_config(VirtIODevice *vdev, uint8_t *config)
945f503cd9SPankaj Gupta {
955f503cd9SPankaj Gupta VirtIOPMEM *pmem = VIRTIO_PMEM(vdev);
965f503cd9SPankaj Gupta struct virtio_pmem_config *pmemcfg = (struct virtio_pmem_config *) config;
975f503cd9SPankaj Gupta
985f503cd9SPankaj Gupta virtio_stq_p(vdev, &pmemcfg->start, pmem->start);
995f503cd9SPankaj Gupta virtio_stq_p(vdev, &pmemcfg->size, memory_region_size(&pmem->memdev->mr));
1005f503cd9SPankaj Gupta }
1015f503cd9SPankaj Gupta
virtio_pmem_get_features(VirtIODevice * vdev,uint64_t features,Error ** errp)1025f503cd9SPankaj Gupta static uint64_t virtio_pmem_get_features(VirtIODevice *vdev, uint64_t features,
1035f503cd9SPankaj Gupta Error **errp)
1045f503cd9SPankaj Gupta {
1055f503cd9SPankaj Gupta return features;
1065f503cd9SPankaj Gupta }
1075f503cd9SPankaj Gupta
virtio_pmem_realize(DeviceState * dev,Error ** errp)1085f503cd9SPankaj Gupta static void virtio_pmem_realize(DeviceState *dev, Error **errp)
1095f503cd9SPankaj Gupta {
1105f503cd9SPankaj Gupta VirtIODevice *vdev = VIRTIO_DEVICE(dev);
1115f503cd9SPankaj Gupta VirtIOPMEM *pmem = VIRTIO_PMEM(dev);
1125f503cd9SPankaj Gupta
1135f503cd9SPankaj Gupta if (!pmem->memdev) {
1145f503cd9SPankaj Gupta error_setg(errp, "virtio-pmem memdev not set");
1155f503cd9SPankaj Gupta return;
1165f503cd9SPankaj Gupta }
1175f503cd9SPankaj Gupta
1185f503cd9SPankaj Gupta if (host_memory_backend_is_mapped(pmem->memdev)) {
1197a309cc9SMarkus Armbruster error_setg(errp, "can't use already busy memdev: %s",
1207a309cc9SMarkus Armbruster object_get_canonical_path_component(OBJECT(pmem->memdev)));
1215f503cd9SPankaj Gupta return;
1225f503cd9SPankaj Gupta }
1235f503cd9SPankaj Gupta
1245f503cd9SPankaj Gupta host_memory_backend_set_mapped(pmem->memdev, true);
1253857cd5cSJonah Palmer virtio_init(vdev, VIRTIO_ID_PMEM, sizeof(struct virtio_pmem_config));
1265f503cd9SPankaj Gupta pmem->rq_vq = virtio_add_queue(vdev, 128, virtio_pmem_flush);
1275f503cd9SPankaj Gupta }
1285f503cd9SPankaj Gupta
virtio_pmem_unrealize(DeviceState * dev)129b69c3c21SMarkus Armbruster static void virtio_pmem_unrealize(DeviceState *dev)
1305f503cd9SPankaj Gupta {
1315f503cd9SPankaj Gupta VirtIODevice *vdev = VIRTIO_DEVICE(dev);
1325f503cd9SPankaj Gupta VirtIOPMEM *pmem = VIRTIO_PMEM(dev);
1335f503cd9SPankaj Gupta
1345f503cd9SPankaj Gupta host_memory_backend_set_mapped(pmem->memdev, false);
1359861546eSPan Nengyuan virtio_delete_queue(pmem->rq_vq);
1365f503cd9SPankaj Gupta virtio_cleanup(vdev);
1375f503cd9SPankaj Gupta }
1385f503cd9SPankaj Gupta
virtio_pmem_fill_device_info(const VirtIOPMEM * pmem,VirtioPMEMDeviceInfo * vi)1395f503cd9SPankaj Gupta static void virtio_pmem_fill_device_info(const VirtIOPMEM *pmem,
1405f503cd9SPankaj Gupta VirtioPMEMDeviceInfo *vi)
1415f503cd9SPankaj Gupta {
1425f503cd9SPankaj Gupta vi->memaddr = pmem->start;
1437b8a8474SPankaj Gupta vi->size = memory_region_size(&pmem->memdev->mr);
1445f503cd9SPankaj Gupta vi->memdev = object_get_canonical_path(OBJECT(pmem->memdev));
1455f503cd9SPankaj Gupta }
1465f503cd9SPankaj Gupta
virtio_pmem_get_memory_region(VirtIOPMEM * pmem,Error ** errp)1475f503cd9SPankaj Gupta static MemoryRegion *virtio_pmem_get_memory_region(VirtIOPMEM *pmem,
1485f503cd9SPankaj Gupta Error **errp)
1495f503cd9SPankaj Gupta {
150*2d7f1081SMaciej S. Szmigiero if (!pmem->memdev) {
151*2d7f1081SMaciej S. Szmigiero error_setg(errp, "'%s' property must be set", VIRTIO_PMEM_MEMDEV_PROP);
152*2d7f1081SMaciej S. Szmigiero return NULL;
153*2d7f1081SMaciej S. Szmigiero }
1545f503cd9SPankaj Gupta
1555f503cd9SPankaj Gupta return &pmem->memdev->mr;
1565f503cd9SPankaj Gupta }
1575f503cd9SPankaj Gupta
1585f503cd9SPankaj Gupta static Property virtio_pmem_properties[] = {
1595f503cd9SPankaj Gupta DEFINE_PROP_UINT64(VIRTIO_PMEM_ADDR_PROP, VirtIOPMEM, start, 0),
1605f503cd9SPankaj Gupta DEFINE_PROP_LINK(VIRTIO_PMEM_MEMDEV_PROP, VirtIOPMEM, memdev,
1615f503cd9SPankaj Gupta TYPE_MEMORY_BACKEND, HostMemoryBackend *),
1625f503cd9SPankaj Gupta DEFINE_PROP_END_OF_LIST(),
1635f503cd9SPankaj Gupta };
1645f503cd9SPankaj Gupta
virtio_pmem_class_init(ObjectClass * klass,void * data)1655f503cd9SPankaj Gupta static void virtio_pmem_class_init(ObjectClass *klass, void *data)
1665f503cd9SPankaj Gupta {
1675f503cd9SPankaj Gupta DeviceClass *dc = DEVICE_CLASS(klass);
1685f503cd9SPankaj Gupta VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
1695f503cd9SPankaj Gupta VirtIOPMEMClass *vpc = VIRTIO_PMEM_CLASS(klass);
1705f503cd9SPankaj Gupta
1714f67d30bSMarc-André Lureau device_class_set_props(dc, virtio_pmem_properties);
1725f503cd9SPankaj Gupta
1735f503cd9SPankaj Gupta vdc->realize = virtio_pmem_realize;
1745f503cd9SPankaj Gupta vdc->unrealize = virtio_pmem_unrealize;
1755f503cd9SPankaj Gupta vdc->get_config = virtio_pmem_get_config;
1765f503cd9SPankaj Gupta vdc->get_features = virtio_pmem_get_features;
1775f503cd9SPankaj Gupta
1785f503cd9SPankaj Gupta vpc->fill_device_info = virtio_pmem_fill_device_info;
1795f503cd9SPankaj Gupta vpc->get_memory_region = virtio_pmem_get_memory_region;
180d3649bfcSGan Qixin set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
1815f503cd9SPankaj Gupta }
1825f503cd9SPankaj Gupta
1835e78c98bSBernhard Beschow static const TypeInfo virtio_pmem_info = {
1845f503cd9SPankaj Gupta .name = TYPE_VIRTIO_PMEM,
1855f503cd9SPankaj Gupta .parent = TYPE_VIRTIO_DEVICE,
1865f503cd9SPankaj Gupta .class_size = sizeof(VirtIOPMEMClass),
1875f503cd9SPankaj Gupta .class_init = virtio_pmem_class_init,
1885f503cd9SPankaj Gupta .instance_size = sizeof(VirtIOPMEM),
1895f503cd9SPankaj Gupta };
1905f503cd9SPankaj Gupta
virtio_register_types(void)1915f503cd9SPankaj Gupta static void virtio_register_types(void)
1925f503cd9SPankaj Gupta {
1935f503cd9SPankaj Gupta type_register_static(&virtio_pmem_info);
1945f503cd9SPankaj Gupta }
1955f503cd9SPankaj Gupta
1965f503cd9SPankaj Gupta type_init(virtio_register_types)
197