xref: /linux/arch/um/drivers/virtio_pcidev.c (revision 1260ed77798502de9c98020040d2995008de10cc)
1*24ffa71bSTiwei Bie // SPDX-License-Identifier: GPL-2.0
2*24ffa71bSTiwei Bie /*
3*24ffa71bSTiwei Bie  * Copyright (C) 2020 Intel Corporation
4*24ffa71bSTiwei Bie  * Author: Johannes Berg <johannes@sipsolutions.net>
5*24ffa71bSTiwei Bie  */
6*24ffa71bSTiwei Bie #include <linux/module.h>
7*24ffa71bSTiwei Bie #include <linux/pci.h>
8*24ffa71bSTiwei Bie #include <linux/virtio.h>
9*24ffa71bSTiwei Bie #include <linux/virtio_config.h>
10*24ffa71bSTiwei Bie #include <linux/logic_iomem.h>
11*24ffa71bSTiwei Bie #include <linux/of_platform.h>
12*24ffa71bSTiwei Bie #include <linux/irqdomain.h>
13*24ffa71bSTiwei Bie #include <linux/virtio_pcidev.h>
14*24ffa71bSTiwei Bie #include <linux/virtio-uml.h>
15*24ffa71bSTiwei Bie #include <linux/delay.h>
16*24ffa71bSTiwei Bie #include <linux/msi.h>
17*24ffa71bSTiwei Bie #include <linux/unaligned.h>
18*24ffa71bSTiwei Bie #include <irq_kern.h>
19*24ffa71bSTiwei Bie 
20*24ffa71bSTiwei Bie #include "virt-pci.h"
21*24ffa71bSTiwei Bie 
22*24ffa71bSTiwei Bie #define to_virtio_pcidev(_pdev) \
23*24ffa71bSTiwei Bie 	container_of(_pdev, struct virtio_pcidev_device, pdev)
24*24ffa71bSTiwei Bie 
25*24ffa71bSTiwei Bie /* for MSI-X we have a 32-bit payload */
26*24ffa71bSTiwei Bie #define MAX_IRQ_MSG_SIZE (sizeof(struct virtio_pcidev_msg) + sizeof(u32))
27*24ffa71bSTiwei Bie #define NUM_IRQ_MSGS	10
28*24ffa71bSTiwei Bie 
29*24ffa71bSTiwei Bie struct virtio_pcidev_message_buffer {
30*24ffa71bSTiwei Bie 	struct virtio_pcidev_msg hdr;
31*24ffa71bSTiwei Bie 	u8 data[8];
32*24ffa71bSTiwei Bie };
33*24ffa71bSTiwei Bie 
34*24ffa71bSTiwei Bie struct virtio_pcidev_device {
35*24ffa71bSTiwei Bie 	struct um_pci_device pdev;
36*24ffa71bSTiwei Bie 	struct virtio_device *vdev;
37*24ffa71bSTiwei Bie 
38*24ffa71bSTiwei Bie 	struct virtqueue *cmd_vq, *irq_vq;
39*24ffa71bSTiwei Bie 
40*24ffa71bSTiwei Bie #define VIRTIO_PCIDEV_WRITE_BUFS	20
41*24ffa71bSTiwei Bie 	struct virtio_pcidev_message_buffer bufs[VIRTIO_PCIDEV_WRITE_BUFS + 1];
42*24ffa71bSTiwei Bie 	void *extra_ptrs[VIRTIO_PCIDEV_WRITE_BUFS + 1];
43*24ffa71bSTiwei Bie 	DECLARE_BITMAP(used_bufs, VIRTIO_PCIDEV_WRITE_BUFS);
44*24ffa71bSTiwei Bie 
45*24ffa71bSTiwei Bie #define UM_PCI_STAT_WAITING	0
46*24ffa71bSTiwei Bie 	unsigned long status;
47*24ffa71bSTiwei Bie 
48*24ffa71bSTiwei Bie 	bool platform;
49*24ffa71bSTiwei Bie };
50*24ffa71bSTiwei Bie 
51*24ffa71bSTiwei Bie static unsigned int virtio_pcidev_max_delay_us = 40000;
52*24ffa71bSTiwei Bie module_param_named(max_delay_us, virtio_pcidev_max_delay_us, uint, 0644);
53*24ffa71bSTiwei Bie 
54*24ffa71bSTiwei Bie static int virtio_pcidev_get_buf(struct virtio_pcidev_device *dev, bool *posted)
55*24ffa71bSTiwei Bie {
56*24ffa71bSTiwei Bie 	int i;
57*24ffa71bSTiwei Bie 
58*24ffa71bSTiwei Bie 	for (i = 0; i < VIRTIO_PCIDEV_WRITE_BUFS; i++) {
59*24ffa71bSTiwei Bie 		if (!test_and_set_bit(i, dev->used_bufs))
60*24ffa71bSTiwei Bie 			return i;
61*24ffa71bSTiwei Bie 	}
62*24ffa71bSTiwei Bie 
63*24ffa71bSTiwei Bie 	*posted = false;
64*24ffa71bSTiwei Bie 	return VIRTIO_PCIDEV_WRITE_BUFS;
65*24ffa71bSTiwei Bie }
66*24ffa71bSTiwei Bie 
67*24ffa71bSTiwei Bie static void virtio_pcidev_free_buf(struct virtio_pcidev_device *dev, void *buf)
68*24ffa71bSTiwei Bie {
69*24ffa71bSTiwei Bie 	int i;
70*24ffa71bSTiwei Bie 
71*24ffa71bSTiwei Bie 	if (buf == &dev->bufs[VIRTIO_PCIDEV_WRITE_BUFS]) {
72*24ffa71bSTiwei Bie 		kfree(dev->extra_ptrs[VIRTIO_PCIDEV_WRITE_BUFS]);
73*24ffa71bSTiwei Bie 		dev->extra_ptrs[VIRTIO_PCIDEV_WRITE_BUFS] = NULL;
74*24ffa71bSTiwei Bie 		return;
75*24ffa71bSTiwei Bie 	}
76*24ffa71bSTiwei Bie 
77*24ffa71bSTiwei Bie 	for (i = 0; i < VIRTIO_PCIDEV_WRITE_BUFS; i++) {
78*24ffa71bSTiwei Bie 		if (buf == &dev->bufs[i]) {
79*24ffa71bSTiwei Bie 			kfree(dev->extra_ptrs[i]);
80*24ffa71bSTiwei Bie 			dev->extra_ptrs[i] = NULL;
81*24ffa71bSTiwei Bie 			WARN_ON(!test_and_clear_bit(i, dev->used_bufs));
82*24ffa71bSTiwei Bie 			return;
83*24ffa71bSTiwei Bie 		}
84*24ffa71bSTiwei Bie 	}
85*24ffa71bSTiwei Bie 
86*24ffa71bSTiwei Bie 	WARN_ON(1);
87*24ffa71bSTiwei Bie }
88*24ffa71bSTiwei Bie 
89*24ffa71bSTiwei Bie static int virtio_pcidev_send_cmd(struct virtio_pcidev_device *dev,
90*24ffa71bSTiwei Bie 				  struct virtio_pcidev_msg *cmd,
91*24ffa71bSTiwei Bie 				  unsigned int cmd_size,
92*24ffa71bSTiwei Bie 				  const void *extra, unsigned int extra_size,
93*24ffa71bSTiwei Bie 				  void *out, unsigned int out_size)
94*24ffa71bSTiwei Bie {
95*24ffa71bSTiwei Bie 	struct scatterlist out_sg, extra_sg, in_sg;
96*24ffa71bSTiwei Bie 	struct scatterlist *sgs_list[] = {
97*24ffa71bSTiwei Bie 		[0] = &out_sg,
98*24ffa71bSTiwei Bie 		[1] = extra ? &extra_sg : &in_sg,
99*24ffa71bSTiwei Bie 		[2] = extra ? &in_sg : NULL,
100*24ffa71bSTiwei Bie 	};
101*24ffa71bSTiwei Bie 	struct virtio_pcidev_message_buffer *buf;
102*24ffa71bSTiwei Bie 	int delay_count = 0;
103*24ffa71bSTiwei Bie 	bool bounce_out;
104*24ffa71bSTiwei Bie 	int ret, len;
105*24ffa71bSTiwei Bie 	int buf_idx;
106*24ffa71bSTiwei Bie 	bool posted;
107*24ffa71bSTiwei Bie 
108*24ffa71bSTiwei Bie 	if (WARN_ON(cmd_size < sizeof(*cmd) || cmd_size > sizeof(*buf)))
109*24ffa71bSTiwei Bie 		return -EINVAL;
110*24ffa71bSTiwei Bie 
111*24ffa71bSTiwei Bie 	switch (cmd->op) {
112*24ffa71bSTiwei Bie 	case VIRTIO_PCIDEV_OP_CFG_WRITE:
113*24ffa71bSTiwei Bie 	case VIRTIO_PCIDEV_OP_MMIO_WRITE:
114*24ffa71bSTiwei Bie 	case VIRTIO_PCIDEV_OP_MMIO_MEMSET:
115*24ffa71bSTiwei Bie 		/* in PCI, writes are posted, so don't wait */
116*24ffa71bSTiwei Bie 		posted = !out;
117*24ffa71bSTiwei Bie 		WARN_ON(!posted);
118*24ffa71bSTiwei Bie 		break;
119*24ffa71bSTiwei Bie 	default:
120*24ffa71bSTiwei Bie 		posted = false;
121*24ffa71bSTiwei Bie 		break;
122*24ffa71bSTiwei Bie 	}
123*24ffa71bSTiwei Bie 
124*24ffa71bSTiwei Bie 	bounce_out = !posted && cmd_size <= sizeof(*cmd) &&
125*24ffa71bSTiwei Bie 		     out && out_size <= sizeof(buf->data);
126*24ffa71bSTiwei Bie 
127*24ffa71bSTiwei Bie 	buf_idx = virtio_pcidev_get_buf(dev, &posted);
128*24ffa71bSTiwei Bie 	buf = &dev->bufs[buf_idx];
129*24ffa71bSTiwei Bie 	memcpy(buf, cmd, cmd_size);
130*24ffa71bSTiwei Bie 
131*24ffa71bSTiwei Bie 	if (posted && extra && extra_size > sizeof(buf) - cmd_size) {
132*24ffa71bSTiwei Bie 		dev->extra_ptrs[buf_idx] = kmemdup(extra, extra_size,
133*24ffa71bSTiwei Bie 						   GFP_ATOMIC);
134*24ffa71bSTiwei Bie 
135*24ffa71bSTiwei Bie 		if (!dev->extra_ptrs[buf_idx]) {
136*24ffa71bSTiwei Bie 			virtio_pcidev_free_buf(dev, buf);
137*24ffa71bSTiwei Bie 			return -ENOMEM;
138*24ffa71bSTiwei Bie 		}
139*24ffa71bSTiwei Bie 		extra = dev->extra_ptrs[buf_idx];
140*24ffa71bSTiwei Bie 	} else if (extra && extra_size <= sizeof(buf) - cmd_size) {
141*24ffa71bSTiwei Bie 		memcpy((u8 *)buf + cmd_size, extra, extra_size);
142*24ffa71bSTiwei Bie 		cmd_size += extra_size;
143*24ffa71bSTiwei Bie 		extra_size = 0;
144*24ffa71bSTiwei Bie 		extra = NULL;
145*24ffa71bSTiwei Bie 		cmd = (void *)buf;
146*24ffa71bSTiwei Bie 	} else {
147*24ffa71bSTiwei Bie 		cmd = (void *)buf;
148*24ffa71bSTiwei Bie 	}
149*24ffa71bSTiwei Bie 
150*24ffa71bSTiwei Bie 	sg_init_one(&out_sg, cmd, cmd_size);
151*24ffa71bSTiwei Bie 	if (extra)
152*24ffa71bSTiwei Bie 		sg_init_one(&extra_sg, extra, extra_size);
153*24ffa71bSTiwei Bie 	/* allow stack for small buffers */
154*24ffa71bSTiwei Bie 	if (bounce_out)
155*24ffa71bSTiwei Bie 		sg_init_one(&in_sg, buf->data, out_size);
156*24ffa71bSTiwei Bie 	else if (out)
157*24ffa71bSTiwei Bie 		sg_init_one(&in_sg, out, out_size);
158*24ffa71bSTiwei Bie 
159*24ffa71bSTiwei Bie 	/* add to internal virtio queue */
160*24ffa71bSTiwei Bie 	ret = virtqueue_add_sgs(dev->cmd_vq, sgs_list,
161*24ffa71bSTiwei Bie 				extra ? 2 : 1,
162*24ffa71bSTiwei Bie 				out ? 1 : 0,
163*24ffa71bSTiwei Bie 				cmd, GFP_ATOMIC);
164*24ffa71bSTiwei Bie 	if (ret) {
165*24ffa71bSTiwei Bie 		virtio_pcidev_free_buf(dev, buf);
166*24ffa71bSTiwei Bie 		return ret;
167*24ffa71bSTiwei Bie 	}
168*24ffa71bSTiwei Bie 
169*24ffa71bSTiwei Bie 	if (posted) {
170*24ffa71bSTiwei Bie 		virtqueue_kick(dev->cmd_vq);
171*24ffa71bSTiwei Bie 		return 0;
172*24ffa71bSTiwei Bie 	}
173*24ffa71bSTiwei Bie 
174*24ffa71bSTiwei Bie 	/* kick and poll for getting a response on the queue */
175*24ffa71bSTiwei Bie 	set_bit(UM_PCI_STAT_WAITING, &dev->status);
176*24ffa71bSTiwei Bie 	virtqueue_kick(dev->cmd_vq);
177*24ffa71bSTiwei Bie 	ret = 0;
178*24ffa71bSTiwei Bie 
179*24ffa71bSTiwei Bie 	while (1) {
180*24ffa71bSTiwei Bie 		void *completed = virtqueue_get_buf(dev->cmd_vq, &len);
181*24ffa71bSTiwei Bie 
182*24ffa71bSTiwei Bie 		if (completed == buf)
183*24ffa71bSTiwei Bie 			break;
184*24ffa71bSTiwei Bie 
185*24ffa71bSTiwei Bie 		if (completed)
186*24ffa71bSTiwei Bie 			virtio_pcidev_free_buf(dev, completed);
187*24ffa71bSTiwei Bie 
188*24ffa71bSTiwei Bie 		if (WARN_ONCE(virtqueue_is_broken(dev->cmd_vq) ||
189*24ffa71bSTiwei Bie 			      ++delay_count > virtio_pcidev_max_delay_us,
190*24ffa71bSTiwei Bie 			      "um virt-pci delay: %d", delay_count)) {
191*24ffa71bSTiwei Bie 			ret = -EIO;
192*24ffa71bSTiwei Bie 			break;
193*24ffa71bSTiwei Bie 		}
194*24ffa71bSTiwei Bie 		udelay(1);
195*24ffa71bSTiwei Bie 	}
196*24ffa71bSTiwei Bie 	clear_bit(UM_PCI_STAT_WAITING, &dev->status);
197*24ffa71bSTiwei Bie 
198*24ffa71bSTiwei Bie 	if (bounce_out)
199*24ffa71bSTiwei Bie 		memcpy(out, buf->data, out_size);
200*24ffa71bSTiwei Bie 
201*24ffa71bSTiwei Bie 	virtio_pcidev_free_buf(dev, buf);
202*24ffa71bSTiwei Bie 
203*24ffa71bSTiwei Bie 	return ret;
204*24ffa71bSTiwei Bie }
205*24ffa71bSTiwei Bie 
206*24ffa71bSTiwei Bie static unsigned long virtio_pcidev_cfgspace_read(struct um_pci_device *pdev,
207*24ffa71bSTiwei Bie 						 unsigned int offset, int size)
208*24ffa71bSTiwei Bie {
209*24ffa71bSTiwei Bie 	struct virtio_pcidev_device *dev = to_virtio_pcidev(pdev);
210*24ffa71bSTiwei Bie 	struct virtio_pcidev_msg hdr = {
211*24ffa71bSTiwei Bie 		.op = VIRTIO_PCIDEV_OP_CFG_READ,
212*24ffa71bSTiwei Bie 		.size = size,
213*24ffa71bSTiwei Bie 		.addr = offset,
214*24ffa71bSTiwei Bie 	};
215*24ffa71bSTiwei Bie 	/* max 8, we might not use it all */
216*24ffa71bSTiwei Bie 	u8 data[8];
217*24ffa71bSTiwei Bie 
218*24ffa71bSTiwei Bie 	memset(data, 0xff, sizeof(data));
219*24ffa71bSTiwei Bie 
220*24ffa71bSTiwei Bie 	/* size has been checked in um_pci_cfgspace_read() */
221*24ffa71bSTiwei Bie 	if (virtio_pcidev_send_cmd(dev, &hdr, sizeof(hdr), NULL, 0, data, size))
222*24ffa71bSTiwei Bie 		return ULONG_MAX;
223*24ffa71bSTiwei Bie 
224*24ffa71bSTiwei Bie 	switch (size) {
225*24ffa71bSTiwei Bie 	case 1:
226*24ffa71bSTiwei Bie 		return data[0];
227*24ffa71bSTiwei Bie 	case 2:
228*24ffa71bSTiwei Bie 		return le16_to_cpup((void *)data);
229*24ffa71bSTiwei Bie 	case 4:
230*24ffa71bSTiwei Bie 		return le32_to_cpup((void *)data);
231*24ffa71bSTiwei Bie #ifdef CONFIG_64BIT
232*24ffa71bSTiwei Bie 	case 8:
233*24ffa71bSTiwei Bie 		return le64_to_cpup((void *)data);
234*24ffa71bSTiwei Bie #endif
235*24ffa71bSTiwei Bie 	default:
236*24ffa71bSTiwei Bie 		return ULONG_MAX;
237*24ffa71bSTiwei Bie 	}
238*24ffa71bSTiwei Bie }
239*24ffa71bSTiwei Bie 
240*24ffa71bSTiwei Bie static void virtio_pcidev_cfgspace_write(struct um_pci_device *pdev,
241*24ffa71bSTiwei Bie 					 unsigned int offset, int size,
242*24ffa71bSTiwei Bie 					 unsigned long val)
243*24ffa71bSTiwei Bie {
244*24ffa71bSTiwei Bie 	struct virtio_pcidev_device *dev = to_virtio_pcidev(pdev);
245*24ffa71bSTiwei Bie 	struct {
246*24ffa71bSTiwei Bie 		struct virtio_pcidev_msg hdr;
247*24ffa71bSTiwei Bie 		/* maximum size - we may only use parts of it */
248*24ffa71bSTiwei Bie 		u8 data[8];
249*24ffa71bSTiwei Bie 	} msg = {
250*24ffa71bSTiwei Bie 		.hdr = {
251*24ffa71bSTiwei Bie 			.op = VIRTIO_PCIDEV_OP_CFG_WRITE,
252*24ffa71bSTiwei Bie 			.size = size,
253*24ffa71bSTiwei Bie 			.addr = offset,
254*24ffa71bSTiwei Bie 		},
255*24ffa71bSTiwei Bie 	};
256*24ffa71bSTiwei Bie 
257*24ffa71bSTiwei Bie 	/* size has been checked in um_pci_cfgspace_write() */
258*24ffa71bSTiwei Bie 	switch (size) {
259*24ffa71bSTiwei Bie 	case 1:
260*24ffa71bSTiwei Bie 		msg.data[0] = (u8)val;
261*24ffa71bSTiwei Bie 		break;
262*24ffa71bSTiwei Bie 	case 2:
263*24ffa71bSTiwei Bie 		put_unaligned_le16(val, (void *)msg.data);
264*24ffa71bSTiwei Bie 		break;
265*24ffa71bSTiwei Bie 	case 4:
266*24ffa71bSTiwei Bie 		put_unaligned_le32(val, (void *)msg.data);
267*24ffa71bSTiwei Bie 		break;
268*24ffa71bSTiwei Bie #ifdef CONFIG_64BIT
269*24ffa71bSTiwei Bie 	case 8:
270*24ffa71bSTiwei Bie 		put_unaligned_le64(val, (void *)msg.data);
271*24ffa71bSTiwei Bie 		break;
272*24ffa71bSTiwei Bie #endif
273*24ffa71bSTiwei Bie 	}
274*24ffa71bSTiwei Bie 
275*24ffa71bSTiwei Bie 	WARN_ON(virtio_pcidev_send_cmd(dev, &msg.hdr, sizeof(msg), NULL, 0, NULL, 0));
276*24ffa71bSTiwei Bie }
277*24ffa71bSTiwei Bie 
278*24ffa71bSTiwei Bie static void virtio_pcidev_bar_copy_from(struct um_pci_device *pdev,
279*24ffa71bSTiwei Bie 					int bar, void *buffer,
280*24ffa71bSTiwei Bie 					unsigned int offset, int size)
281*24ffa71bSTiwei Bie {
282*24ffa71bSTiwei Bie 	struct virtio_pcidev_device *dev = to_virtio_pcidev(pdev);
283*24ffa71bSTiwei Bie 	struct virtio_pcidev_msg hdr = {
284*24ffa71bSTiwei Bie 		.op = VIRTIO_PCIDEV_OP_MMIO_READ,
285*24ffa71bSTiwei Bie 		.bar = bar,
286*24ffa71bSTiwei Bie 		.size = size,
287*24ffa71bSTiwei Bie 		.addr = offset,
288*24ffa71bSTiwei Bie 	};
289*24ffa71bSTiwei Bie 
290*24ffa71bSTiwei Bie 	memset(buffer, 0xff, size);
291*24ffa71bSTiwei Bie 
292*24ffa71bSTiwei Bie 	virtio_pcidev_send_cmd(dev, &hdr, sizeof(hdr), NULL, 0, buffer, size);
293*24ffa71bSTiwei Bie }
294*24ffa71bSTiwei Bie 
295*24ffa71bSTiwei Bie static unsigned long virtio_pcidev_bar_read(struct um_pci_device *pdev, int bar,
296*24ffa71bSTiwei Bie 					    unsigned int offset, int size)
297*24ffa71bSTiwei Bie {
298*24ffa71bSTiwei Bie 	/* 8 is maximum size - we may only use parts of it */
299*24ffa71bSTiwei Bie 	u8 data[8];
300*24ffa71bSTiwei Bie 
301*24ffa71bSTiwei Bie 	/* size has been checked in um_pci_bar_read() */
302*24ffa71bSTiwei Bie 	virtio_pcidev_bar_copy_from(pdev, bar, data, offset, size);
303*24ffa71bSTiwei Bie 
304*24ffa71bSTiwei Bie 	switch (size) {
305*24ffa71bSTiwei Bie 	case 1:
306*24ffa71bSTiwei Bie 		return data[0];
307*24ffa71bSTiwei Bie 	case 2:
308*24ffa71bSTiwei Bie 		return le16_to_cpup((void *)data);
309*24ffa71bSTiwei Bie 	case 4:
310*24ffa71bSTiwei Bie 		return le32_to_cpup((void *)data);
311*24ffa71bSTiwei Bie #ifdef CONFIG_64BIT
312*24ffa71bSTiwei Bie 	case 8:
313*24ffa71bSTiwei Bie 		return le64_to_cpup((void *)data);
314*24ffa71bSTiwei Bie #endif
315*24ffa71bSTiwei Bie 	default:
316*24ffa71bSTiwei Bie 		return ULONG_MAX;
317*24ffa71bSTiwei Bie 	}
318*24ffa71bSTiwei Bie }
319*24ffa71bSTiwei Bie 
320*24ffa71bSTiwei Bie static void virtio_pcidev_bar_copy_to(struct um_pci_device *pdev,
321*24ffa71bSTiwei Bie 				      int bar, unsigned int offset,
322*24ffa71bSTiwei Bie 				      const void *buffer, int size)
323*24ffa71bSTiwei Bie {
324*24ffa71bSTiwei Bie 	struct virtio_pcidev_device *dev = to_virtio_pcidev(pdev);
325*24ffa71bSTiwei Bie 	struct virtio_pcidev_msg hdr = {
326*24ffa71bSTiwei Bie 		.op = VIRTIO_PCIDEV_OP_MMIO_WRITE,
327*24ffa71bSTiwei Bie 		.bar = bar,
328*24ffa71bSTiwei Bie 		.size = size,
329*24ffa71bSTiwei Bie 		.addr = offset,
330*24ffa71bSTiwei Bie 	};
331*24ffa71bSTiwei Bie 
332*24ffa71bSTiwei Bie 	virtio_pcidev_send_cmd(dev, &hdr, sizeof(hdr), buffer, size, NULL, 0);
333*24ffa71bSTiwei Bie }
334*24ffa71bSTiwei Bie 
335*24ffa71bSTiwei Bie static void virtio_pcidev_bar_write(struct um_pci_device *pdev, int bar,
336*24ffa71bSTiwei Bie 				    unsigned int offset, int size,
337*24ffa71bSTiwei Bie 				    unsigned long val)
338*24ffa71bSTiwei Bie {
339*24ffa71bSTiwei Bie 	/* maximum size - we may only use parts of it */
340*24ffa71bSTiwei Bie 	u8 data[8];
341*24ffa71bSTiwei Bie 
342*24ffa71bSTiwei Bie 	/* size has been checked in um_pci_bar_write() */
343*24ffa71bSTiwei Bie 	switch (size) {
344*24ffa71bSTiwei Bie 	case 1:
345*24ffa71bSTiwei Bie 		data[0] = (u8)val;
346*24ffa71bSTiwei Bie 		break;
347*24ffa71bSTiwei Bie 	case 2:
348*24ffa71bSTiwei Bie 		put_unaligned_le16(val, (void *)data);
349*24ffa71bSTiwei Bie 		break;
350*24ffa71bSTiwei Bie 	case 4:
351*24ffa71bSTiwei Bie 		put_unaligned_le32(val, (void *)data);
352*24ffa71bSTiwei Bie 		break;
353*24ffa71bSTiwei Bie #ifdef CONFIG_64BIT
354*24ffa71bSTiwei Bie 	case 8:
355*24ffa71bSTiwei Bie 		put_unaligned_le64(val, (void *)data);
356*24ffa71bSTiwei Bie 		break;
357*24ffa71bSTiwei Bie #endif
358*24ffa71bSTiwei Bie 	}
359*24ffa71bSTiwei Bie 
360*24ffa71bSTiwei Bie 	virtio_pcidev_bar_copy_to(pdev, bar, offset, data, size);
361*24ffa71bSTiwei Bie }
362*24ffa71bSTiwei Bie 
363*24ffa71bSTiwei Bie static void virtio_pcidev_bar_set(struct um_pci_device *pdev, int bar,
364*24ffa71bSTiwei Bie 				  unsigned int offset, u8 value, int size)
365*24ffa71bSTiwei Bie {
366*24ffa71bSTiwei Bie 	struct virtio_pcidev_device *dev = to_virtio_pcidev(pdev);
367*24ffa71bSTiwei Bie 	struct {
368*24ffa71bSTiwei Bie 		struct virtio_pcidev_msg hdr;
369*24ffa71bSTiwei Bie 		u8 data;
370*24ffa71bSTiwei Bie 	} msg = {
371*24ffa71bSTiwei Bie 		.hdr = {
372*24ffa71bSTiwei Bie 			.op = VIRTIO_PCIDEV_OP_CFG_WRITE,
373*24ffa71bSTiwei Bie 			.bar = bar,
374*24ffa71bSTiwei Bie 			.size = size,
375*24ffa71bSTiwei Bie 			.addr = offset,
376*24ffa71bSTiwei Bie 		},
377*24ffa71bSTiwei Bie 		.data = value,
378*24ffa71bSTiwei Bie 	};
379*24ffa71bSTiwei Bie 
380*24ffa71bSTiwei Bie 	virtio_pcidev_send_cmd(dev, &msg.hdr, sizeof(msg), NULL, 0, NULL, 0);
381*24ffa71bSTiwei Bie }
382*24ffa71bSTiwei Bie 
383*24ffa71bSTiwei Bie static const struct um_pci_ops virtio_pcidev_um_pci_ops = {
384*24ffa71bSTiwei Bie 	.cfgspace_read	= virtio_pcidev_cfgspace_read,
385*24ffa71bSTiwei Bie 	.cfgspace_write	= virtio_pcidev_cfgspace_write,
386*24ffa71bSTiwei Bie 	.bar_read	= virtio_pcidev_bar_read,
387*24ffa71bSTiwei Bie 	.bar_write	= virtio_pcidev_bar_write,
388*24ffa71bSTiwei Bie 	.bar_copy_from	= virtio_pcidev_bar_copy_from,
389*24ffa71bSTiwei Bie 	.bar_copy_to	= virtio_pcidev_bar_copy_to,
390*24ffa71bSTiwei Bie 	.bar_set	= virtio_pcidev_bar_set,
391*24ffa71bSTiwei Bie };
392*24ffa71bSTiwei Bie 
393*24ffa71bSTiwei Bie static void virtio_pcidev_irq_vq_addbuf(struct virtqueue *vq, void *buf, bool kick)
394*24ffa71bSTiwei Bie {
395*24ffa71bSTiwei Bie 	struct scatterlist sg[1];
396*24ffa71bSTiwei Bie 
397*24ffa71bSTiwei Bie 	sg_init_one(sg, buf, MAX_IRQ_MSG_SIZE);
398*24ffa71bSTiwei Bie 	if (virtqueue_add_inbuf(vq, sg, 1, buf, GFP_ATOMIC))
399*24ffa71bSTiwei Bie 		kfree(buf);
400*24ffa71bSTiwei Bie 	else if (kick)
401*24ffa71bSTiwei Bie 		virtqueue_kick(vq);
402*24ffa71bSTiwei Bie }
403*24ffa71bSTiwei Bie 
404*24ffa71bSTiwei Bie static void virtio_pcidev_handle_irq_message(struct virtqueue *vq,
405*24ffa71bSTiwei Bie 					     struct virtio_pcidev_msg *msg)
406*24ffa71bSTiwei Bie {
407*24ffa71bSTiwei Bie 	struct virtio_device *vdev = vq->vdev;
408*24ffa71bSTiwei Bie 	struct virtio_pcidev_device *dev = vdev->priv;
409*24ffa71bSTiwei Bie 
410*24ffa71bSTiwei Bie 	if (!dev->pdev.irq)
411*24ffa71bSTiwei Bie 		return;
412*24ffa71bSTiwei Bie 
413*24ffa71bSTiwei Bie 	/* we should properly chain interrupts, but on ARCH=um we don't care */
414*24ffa71bSTiwei Bie 
415*24ffa71bSTiwei Bie 	switch (msg->op) {
416*24ffa71bSTiwei Bie 	case VIRTIO_PCIDEV_OP_INT:
417*24ffa71bSTiwei Bie 		generic_handle_irq(dev->pdev.irq);
418*24ffa71bSTiwei Bie 		break;
419*24ffa71bSTiwei Bie 	case VIRTIO_PCIDEV_OP_MSI:
420*24ffa71bSTiwei Bie 		/* our MSI message is just the interrupt number */
421*24ffa71bSTiwei Bie 		if (msg->size == sizeof(u32))
422*24ffa71bSTiwei Bie 			generic_handle_irq(le32_to_cpup((void *)msg->data));
423*24ffa71bSTiwei Bie 		else
424*24ffa71bSTiwei Bie 			generic_handle_irq(le16_to_cpup((void *)msg->data));
425*24ffa71bSTiwei Bie 		break;
426*24ffa71bSTiwei Bie 	case VIRTIO_PCIDEV_OP_PME:
427*24ffa71bSTiwei Bie 		/* nothing to do - we already woke up due to the message */
428*24ffa71bSTiwei Bie 		break;
429*24ffa71bSTiwei Bie 	default:
430*24ffa71bSTiwei Bie 		dev_err(&vdev->dev, "unexpected virt-pci message %d\n", msg->op);
431*24ffa71bSTiwei Bie 		break;
432*24ffa71bSTiwei Bie 	}
433*24ffa71bSTiwei Bie }
434*24ffa71bSTiwei Bie 
435*24ffa71bSTiwei Bie static void virtio_pcidev_cmd_vq_cb(struct virtqueue *vq)
436*24ffa71bSTiwei Bie {
437*24ffa71bSTiwei Bie 	struct virtio_device *vdev = vq->vdev;
438*24ffa71bSTiwei Bie 	struct virtio_pcidev_device *dev = vdev->priv;
439*24ffa71bSTiwei Bie 	void *cmd;
440*24ffa71bSTiwei Bie 	int len;
441*24ffa71bSTiwei Bie 
442*24ffa71bSTiwei Bie 	if (test_bit(UM_PCI_STAT_WAITING, &dev->status))
443*24ffa71bSTiwei Bie 		return;
444*24ffa71bSTiwei Bie 
445*24ffa71bSTiwei Bie 	while ((cmd = virtqueue_get_buf(vq, &len)))
446*24ffa71bSTiwei Bie 		virtio_pcidev_free_buf(dev, cmd);
447*24ffa71bSTiwei Bie }
448*24ffa71bSTiwei Bie 
449*24ffa71bSTiwei Bie static void virtio_pcidev_irq_vq_cb(struct virtqueue *vq)
450*24ffa71bSTiwei Bie {
451*24ffa71bSTiwei Bie 	struct virtio_pcidev_msg *msg;
452*24ffa71bSTiwei Bie 	int len;
453*24ffa71bSTiwei Bie 
454*24ffa71bSTiwei Bie 	while ((msg = virtqueue_get_buf(vq, &len))) {
455*24ffa71bSTiwei Bie 		if (len >= sizeof(*msg))
456*24ffa71bSTiwei Bie 			virtio_pcidev_handle_irq_message(vq, msg);
457*24ffa71bSTiwei Bie 
458*24ffa71bSTiwei Bie 		/* recycle the message buffer */
459*24ffa71bSTiwei Bie 		virtio_pcidev_irq_vq_addbuf(vq, msg, true);
460*24ffa71bSTiwei Bie 	}
461*24ffa71bSTiwei Bie }
462*24ffa71bSTiwei Bie 
463*24ffa71bSTiwei Bie static int virtio_pcidev_init_vqs(struct virtio_pcidev_device *dev)
464*24ffa71bSTiwei Bie {
465*24ffa71bSTiwei Bie 	struct virtqueue_info vqs_info[] = {
466*24ffa71bSTiwei Bie 		{ "cmd", virtio_pcidev_cmd_vq_cb },
467*24ffa71bSTiwei Bie 		{ "irq", virtio_pcidev_irq_vq_cb },
468*24ffa71bSTiwei Bie 	};
469*24ffa71bSTiwei Bie 	struct virtqueue *vqs[2];
470*24ffa71bSTiwei Bie 	int err, i;
471*24ffa71bSTiwei Bie 
472*24ffa71bSTiwei Bie 	err = virtio_find_vqs(dev->vdev, 2, vqs, vqs_info, NULL);
473*24ffa71bSTiwei Bie 	if (err)
474*24ffa71bSTiwei Bie 		return err;
475*24ffa71bSTiwei Bie 
476*24ffa71bSTiwei Bie 	dev->cmd_vq = vqs[0];
477*24ffa71bSTiwei Bie 	dev->irq_vq = vqs[1];
478*24ffa71bSTiwei Bie 
479*24ffa71bSTiwei Bie 	virtio_device_ready(dev->vdev);
480*24ffa71bSTiwei Bie 
481*24ffa71bSTiwei Bie 	for (i = 0; i < NUM_IRQ_MSGS; i++) {
482*24ffa71bSTiwei Bie 		void *msg = kzalloc(MAX_IRQ_MSG_SIZE, GFP_KERNEL);
483*24ffa71bSTiwei Bie 
484*24ffa71bSTiwei Bie 		if (msg)
485*24ffa71bSTiwei Bie 			virtio_pcidev_irq_vq_addbuf(dev->irq_vq, msg, false);
486*24ffa71bSTiwei Bie 	}
487*24ffa71bSTiwei Bie 
488*24ffa71bSTiwei Bie 	virtqueue_kick(dev->irq_vq);
489*24ffa71bSTiwei Bie 
490*24ffa71bSTiwei Bie 	return 0;
491*24ffa71bSTiwei Bie }
492*24ffa71bSTiwei Bie 
493*24ffa71bSTiwei Bie static void __virtio_pcidev_virtio_platform_remove(struct virtio_device *vdev,
494*24ffa71bSTiwei Bie 						   struct virtio_pcidev_device *dev)
495*24ffa71bSTiwei Bie {
496*24ffa71bSTiwei Bie 	um_pci_platform_device_unregister(&dev->pdev);
497*24ffa71bSTiwei Bie 
498*24ffa71bSTiwei Bie 	virtio_reset_device(vdev);
499*24ffa71bSTiwei Bie 	vdev->config->del_vqs(vdev);
500*24ffa71bSTiwei Bie 
501*24ffa71bSTiwei Bie 	kfree(dev);
502*24ffa71bSTiwei Bie }
503*24ffa71bSTiwei Bie 
504*24ffa71bSTiwei Bie static int virtio_pcidev_virtio_platform_probe(struct virtio_device *vdev,
505*24ffa71bSTiwei Bie 					       struct virtio_pcidev_device *dev)
506*24ffa71bSTiwei Bie {
507*24ffa71bSTiwei Bie 	int err;
508*24ffa71bSTiwei Bie 
509*24ffa71bSTiwei Bie 	dev->platform = true;
510*24ffa71bSTiwei Bie 
511*24ffa71bSTiwei Bie 	err = virtio_pcidev_init_vqs(dev);
512*24ffa71bSTiwei Bie 	if (err)
513*24ffa71bSTiwei Bie 		goto err_free;
514*24ffa71bSTiwei Bie 
515*24ffa71bSTiwei Bie 	err = um_pci_platform_device_register(&dev->pdev);
516*24ffa71bSTiwei Bie 	if (err)
517*24ffa71bSTiwei Bie 		goto err_reset;
518*24ffa71bSTiwei Bie 
519*24ffa71bSTiwei Bie 	err = of_platform_default_populate(vdev->dev.of_node, NULL, &vdev->dev);
520*24ffa71bSTiwei Bie 	if (err)
521*24ffa71bSTiwei Bie 		goto err_unregister;
522*24ffa71bSTiwei Bie 
523*24ffa71bSTiwei Bie 	return 0;
524*24ffa71bSTiwei Bie 
525*24ffa71bSTiwei Bie err_unregister:
526*24ffa71bSTiwei Bie 	um_pci_platform_device_unregister(&dev->pdev);
527*24ffa71bSTiwei Bie err_reset:
528*24ffa71bSTiwei Bie 	virtio_reset_device(vdev);
529*24ffa71bSTiwei Bie 	vdev->config->del_vqs(vdev);
530*24ffa71bSTiwei Bie err_free:
531*24ffa71bSTiwei Bie 	kfree(dev);
532*24ffa71bSTiwei Bie 	return err;
533*24ffa71bSTiwei Bie }
534*24ffa71bSTiwei Bie 
535*24ffa71bSTiwei Bie static int virtio_pcidev_virtio_probe(struct virtio_device *vdev)
536*24ffa71bSTiwei Bie {
537*24ffa71bSTiwei Bie 	struct virtio_pcidev_device *dev;
538*24ffa71bSTiwei Bie 	int err;
539*24ffa71bSTiwei Bie 
540*24ffa71bSTiwei Bie 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
541*24ffa71bSTiwei Bie 	if (!dev)
542*24ffa71bSTiwei Bie 		return -ENOMEM;
543*24ffa71bSTiwei Bie 
544*24ffa71bSTiwei Bie 	dev->vdev = vdev;
545*24ffa71bSTiwei Bie 	vdev->priv = dev;
546*24ffa71bSTiwei Bie 
547*24ffa71bSTiwei Bie 	dev->pdev.ops = &virtio_pcidev_um_pci_ops;
548*24ffa71bSTiwei Bie 
549*24ffa71bSTiwei Bie 	if (of_device_is_compatible(vdev->dev.of_node, "simple-bus"))
550*24ffa71bSTiwei Bie 		return virtio_pcidev_virtio_platform_probe(vdev, dev);
551*24ffa71bSTiwei Bie 
552*24ffa71bSTiwei Bie 	err = virtio_pcidev_init_vqs(dev);
553*24ffa71bSTiwei Bie 	if (err)
554*24ffa71bSTiwei Bie 		goto err_free;
555*24ffa71bSTiwei Bie 
556*24ffa71bSTiwei Bie 	err = um_pci_device_register(&dev->pdev);
557*24ffa71bSTiwei Bie 	if (err)
558*24ffa71bSTiwei Bie 		goto err_reset;
559*24ffa71bSTiwei Bie 
560*24ffa71bSTiwei Bie 	device_set_wakeup_enable(&vdev->dev, true);
561*24ffa71bSTiwei Bie 
562*24ffa71bSTiwei Bie 	/*
563*24ffa71bSTiwei Bie 	 * In order to do suspend-resume properly, don't allow VQs
564*24ffa71bSTiwei Bie 	 * to be suspended.
565*24ffa71bSTiwei Bie 	 */
566*24ffa71bSTiwei Bie 	virtio_uml_set_no_vq_suspend(vdev, true);
567*24ffa71bSTiwei Bie 
568*24ffa71bSTiwei Bie 	return 0;
569*24ffa71bSTiwei Bie 
570*24ffa71bSTiwei Bie err_reset:
571*24ffa71bSTiwei Bie 	virtio_reset_device(vdev);
572*24ffa71bSTiwei Bie 	vdev->config->del_vqs(vdev);
573*24ffa71bSTiwei Bie err_free:
574*24ffa71bSTiwei Bie 	kfree(dev);
575*24ffa71bSTiwei Bie 	return err;
576*24ffa71bSTiwei Bie }
577*24ffa71bSTiwei Bie 
578*24ffa71bSTiwei Bie static void virtio_pcidev_virtio_remove(struct virtio_device *vdev)
579*24ffa71bSTiwei Bie {
580*24ffa71bSTiwei Bie 	struct virtio_pcidev_device *dev = vdev->priv;
581*24ffa71bSTiwei Bie 
582*24ffa71bSTiwei Bie 	if (dev->platform) {
583*24ffa71bSTiwei Bie 		of_platform_depopulate(&vdev->dev);
584*24ffa71bSTiwei Bie 		__virtio_pcidev_virtio_platform_remove(vdev, dev);
585*24ffa71bSTiwei Bie 		return;
586*24ffa71bSTiwei Bie 	}
587*24ffa71bSTiwei Bie 
588*24ffa71bSTiwei Bie 	device_set_wakeup_enable(&vdev->dev, false);
589*24ffa71bSTiwei Bie 
590*24ffa71bSTiwei Bie 	um_pci_device_unregister(&dev->pdev);
591*24ffa71bSTiwei Bie 
592*24ffa71bSTiwei Bie 	/* Stop all virtqueues */
593*24ffa71bSTiwei Bie 	virtio_reset_device(vdev);
594*24ffa71bSTiwei Bie 	dev->cmd_vq = NULL;
595*24ffa71bSTiwei Bie 	dev->irq_vq = NULL;
596*24ffa71bSTiwei Bie 	vdev->config->del_vqs(vdev);
597*24ffa71bSTiwei Bie 
598*24ffa71bSTiwei Bie 	kfree(dev);
599*24ffa71bSTiwei Bie }
600*24ffa71bSTiwei Bie 
601*24ffa71bSTiwei Bie static struct virtio_device_id id_table[] = {
602*24ffa71bSTiwei Bie 	{ CONFIG_UML_PCI_OVER_VIRTIO_DEVICE_ID, VIRTIO_DEV_ANY_ID },
603*24ffa71bSTiwei Bie 	{ 0 },
604*24ffa71bSTiwei Bie };
605*24ffa71bSTiwei Bie MODULE_DEVICE_TABLE(virtio, id_table);
606*24ffa71bSTiwei Bie 
607*24ffa71bSTiwei Bie static struct virtio_driver virtio_pcidev_virtio_driver = {
608*24ffa71bSTiwei Bie 	.driver.name = "virtio-pci",
609*24ffa71bSTiwei Bie 	.id_table = id_table,
610*24ffa71bSTiwei Bie 	.probe = virtio_pcidev_virtio_probe,
611*24ffa71bSTiwei Bie 	.remove = virtio_pcidev_virtio_remove,
612*24ffa71bSTiwei Bie };
613*24ffa71bSTiwei Bie 
614*24ffa71bSTiwei Bie static int __init virtio_pcidev_init(void)
615*24ffa71bSTiwei Bie {
616*24ffa71bSTiwei Bie 	if (WARN(CONFIG_UML_PCI_OVER_VIRTIO_DEVICE_ID < 0,
617*24ffa71bSTiwei Bie 		 "No virtio device ID configured for PCI - no PCI support\n"))
618*24ffa71bSTiwei Bie 		return 0;
619*24ffa71bSTiwei Bie 
620*24ffa71bSTiwei Bie 	return register_virtio_driver(&virtio_pcidev_virtio_driver);
621*24ffa71bSTiwei Bie }
622*24ffa71bSTiwei Bie late_initcall(virtio_pcidev_init);
623*24ffa71bSTiwei Bie 
624*24ffa71bSTiwei Bie static void __exit virtio_pcidev_exit(void)
625*24ffa71bSTiwei Bie {
626*24ffa71bSTiwei Bie 	unregister_virtio_driver(&virtio_pcidev_virtio_driver);
627*24ffa71bSTiwei Bie }
628*24ffa71bSTiwei Bie module_exit(virtio_pcidev_exit);
629