Merge tag 'trace-printf-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
[drm/drm-misc.git] / drivers / nvdimm / nd_virtio.c
blobc3f07be4aa22adbedfcc5ee30bee9762c5d55e64
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * virtio_pmem.c: Virtio pmem Driver
5 * Discovers persistent memory range information
6 * from host and provides a virtio based flushing
7 * interface.
8 */
9 #include "virtio_pmem.h"
10 #include "nd.h"
12 /* The interrupt handler */
13 void virtio_pmem_host_ack(struct virtqueue *vq)
15 struct virtio_pmem *vpmem = vq->vdev->priv;
16 struct virtio_pmem_request *req_data, *req_buf;
17 unsigned long flags;
18 unsigned int len;
20 spin_lock_irqsave(&vpmem->pmem_lock, flags);
21 while ((req_data = virtqueue_get_buf(vq, &len)) != NULL) {
22 req_data->done = true;
23 wake_up(&req_data->host_acked);
25 if (!list_empty(&vpmem->req_list)) {
26 req_buf = list_first_entry(&vpmem->req_list,
27 struct virtio_pmem_request, list);
28 req_buf->wq_buf_avail = true;
29 wake_up(&req_buf->wq_buf);
30 list_del(&req_buf->list);
33 spin_unlock_irqrestore(&vpmem->pmem_lock, flags);
35 EXPORT_SYMBOL_GPL(virtio_pmem_host_ack);
37 /* The request submission function */
38 static int virtio_pmem_flush(struct nd_region *nd_region)
40 struct virtio_device *vdev = nd_region->provider_data;
41 struct virtio_pmem *vpmem = vdev->priv;
42 struct virtio_pmem_request *req_data;
43 struct scatterlist *sgs[2], sg, ret;
44 unsigned long flags;
45 int err, err1;
48 * Don't bother to submit the request to the device if the device is
49 * not activated.
51 if (vdev->config->get_status(vdev) & VIRTIO_CONFIG_S_NEEDS_RESET) {
52 dev_info(&vdev->dev, "virtio pmem device needs a reset\n");
53 return -EIO;
56 might_sleep();
57 req_data = kmalloc(sizeof(*req_data), GFP_KERNEL);
58 if (!req_data)
59 return -ENOMEM;
61 req_data->done = false;
62 init_waitqueue_head(&req_data->host_acked);
63 init_waitqueue_head(&req_data->wq_buf);
64 INIT_LIST_HEAD(&req_data->list);
65 req_data->req.type = cpu_to_le32(VIRTIO_PMEM_REQ_TYPE_FLUSH);
66 sg_init_one(&sg, &req_data->req, sizeof(req_data->req));
67 sgs[0] = &sg;
68 sg_init_one(&ret, &req_data->resp.ret, sizeof(req_data->resp));
69 sgs[1] = &ret;
71 spin_lock_irqsave(&vpmem->pmem_lock, flags);
73 * If virtqueue_add_sgs returns -ENOSPC then req_vq virtual
74 * queue does not have free descriptor. We add the request
75 * to req_list and wait for host_ack to wake us up when free
76 * slots are available.
78 while ((err = virtqueue_add_sgs(vpmem->req_vq, sgs, 1, 1, req_data,
79 GFP_ATOMIC)) == -ENOSPC) {
81 dev_info(&vdev->dev, "failed to send command to virtio pmem device, no free slots in the virtqueue\n");
82 req_data->wq_buf_avail = false;
83 list_add_tail(&req_data->list, &vpmem->req_list);
84 spin_unlock_irqrestore(&vpmem->pmem_lock, flags);
86 /* A host response results in "host_ack" getting called */
87 wait_event(req_data->wq_buf, req_data->wq_buf_avail);
88 spin_lock_irqsave(&vpmem->pmem_lock, flags);
90 err1 = virtqueue_kick(vpmem->req_vq);
91 spin_unlock_irqrestore(&vpmem->pmem_lock, flags);
93 * virtqueue_add_sgs failed with error different than -ENOSPC, we can't
94 * do anything about that.
96 if (err || !err1) {
97 dev_info(&vdev->dev, "failed to send command to virtio pmem device\n");
98 err = -EIO;
99 } else {
100 /* A host response results in "host_ack" getting called */
101 wait_event(req_data->host_acked, req_data->done);
102 err = le32_to_cpu(req_data->resp.ret);
105 kfree(req_data);
106 return err;
109 /* The asynchronous flush callback function */
110 int async_pmem_flush(struct nd_region *nd_region, struct bio *bio)
113 * Create child bio for asynchronous flush and chain with
114 * parent bio. Otherwise directly call nd_region flush.
116 if (bio && bio->bi_iter.bi_sector != -1) {
117 struct bio *child = bio_alloc(bio->bi_bdev, 0,
118 REQ_OP_WRITE | REQ_PREFLUSH,
119 GFP_ATOMIC);
121 if (!child)
122 return -ENOMEM;
123 bio_clone_blkg_association(child, bio);
124 child->bi_iter.bi_sector = -1;
125 bio_chain(child, bio);
126 submit_bio(child);
127 return 0;
129 if (virtio_pmem_flush(nd_region))
130 return -EIO;
132 return 0;
134 EXPORT_SYMBOL_GPL(async_pmem_flush);
135 MODULE_DESCRIPTION("Virtio Persistent Memory Driver");
136 MODULE_LICENSE("GPL");