virtio_pci.c revision 1.9
1/*	$OpenBSD: virtio_pci.c,v 1.9 2015/03/14 03:38:49 jsg Exp $	*/
2/*	$NetBSD: virtio.c,v 1.3 2011/11/02 23:05:52 njoly Exp $	*/
3
4/*
5 * Copyright (c) 2012 Stefan Fritsch.
6 * Copyright (c) 2010 Minoura Makoto.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in the
16 *    documentation and/or other materials provided with the distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/device.h>
33#include <sys/mutex.h>
34
35#include <dev/pci/pcidevs.h>
36#include <dev/pci/pcireg.h>
37#include <dev/pci/pcivar.h>
38
39#include <dev/pci/virtioreg.h>
40#include <dev/pci/virtiovar.h>
41
42/*
43 * XXX: Before being used on big endian arches, the access to config registers
44 * XXX: needs to be reviewed/fixed. The non-device specific registers are
45 * XXX: PCI-endian while the device specific registers are native endian.
46 */
47
48#define virtio_set_status(sc, s) virtio_pci_set_status(sc, s)
49#define virtio_device_reset(sc) virtio_set_status((sc), 0)
50
51int		virtio_pci_match(struct device *, void *, void *);
52void		virtio_pci_attach(struct device *, struct device *, void *);
53int		virtio_pci_detach(struct device *, int);
54
55void		virtio_pci_kick(struct virtio_softc *, uint16_t);
56uint8_t		virtio_pci_read_device_config_1(struct virtio_softc *, int);
57uint16_t	virtio_pci_read_device_config_2(struct virtio_softc *, int);
58uint32_t	virtio_pci_read_device_config_4(struct virtio_softc *, int);
59uint64_t	virtio_pci_read_device_config_8(struct virtio_softc *, int);
60void		virtio_pci_write_device_config_1(struct virtio_softc *, int, uint8_t);
61void		virtio_pci_write_device_config_2(struct virtio_softc *, int, uint16_t);
62void		virtio_pci_write_device_config_4(struct virtio_softc *, int, uint32_t);
63void		virtio_pci_write_device_config_8(struct virtio_softc *, int, uint64_t);
64uint16_t	virtio_pci_read_queue_size(struct virtio_softc *, uint16_t);
65void		virtio_pci_setup_queue(struct virtio_softc *, uint16_t, uint32_t);
66void		virtio_pci_set_status(struct virtio_softc *, int);
67uint32_t	virtio_pci_negotiate_features(struct virtio_softc *, uint32_t,
68					      const struct virtio_feature_name *);
69int		virtio_pci_intr(void *);
70
71struct virtio_pci_softc {
72	struct virtio_softc	sc_sc;
73	pci_chipset_tag_t	sc_pc;
74
75	bus_space_tag_t		sc_iot;
76	bus_space_handle_t	sc_ioh;
77	bus_size_t		sc_iosize;
78
79	void                    *sc_ih;
80
81	int			sc_config_offset;
82};
83
84struct cfattach virtio_pci_ca = {
85	sizeof(struct virtio_pci_softc),
86	virtio_pci_match,
87	virtio_pci_attach,
88	virtio_pci_detach,
89	NULL
90};
91
92struct virtio_ops virtio_pci_ops = {
93	virtio_pci_kick,
94	virtio_pci_read_device_config_1,
95	virtio_pci_read_device_config_2,
96	virtio_pci_read_device_config_4,
97	virtio_pci_read_device_config_8,
98	virtio_pci_write_device_config_1,
99	virtio_pci_write_device_config_2,
100	virtio_pci_write_device_config_4,
101	virtio_pci_write_device_config_8,
102	virtio_pci_read_queue_size,
103	virtio_pci_setup_queue,
104	virtio_pci_set_status,
105	virtio_pci_negotiate_features,
106	virtio_pci_intr,
107};
108
109uint16_t
110virtio_pci_read_queue_size(struct virtio_softc *vsc, uint16_t idx)
111{
112	struct virtio_pci_softc *sc = (struct virtio_pci_softc *)vsc;
113	bus_space_write_2(sc->sc_iot, sc->sc_ioh, VIRTIO_CONFIG_QUEUE_SELECT,
114	    idx);
115	return bus_space_read_2(sc->sc_iot, sc->sc_ioh,
116	    VIRTIO_CONFIG_QUEUE_SIZE);
117}
118
119void
120virtio_pci_setup_queue(struct virtio_softc *vsc, uint16_t idx, uint32_t addr)
121{
122	struct virtio_pci_softc *sc = (struct virtio_pci_softc *)vsc;
123	bus_space_write_2(sc->sc_iot, sc->sc_ioh, VIRTIO_CONFIG_QUEUE_SELECT,
124	    idx);
125	bus_space_write_4(sc->sc_iot, sc->sc_ioh, VIRTIO_CONFIG_QUEUE_ADDRESS,
126	    addr);
127}
128
129void
130virtio_pci_set_status(struct virtio_softc *vsc, int status)
131{
132	struct virtio_pci_softc *sc = (struct virtio_pci_softc *)vsc;
133	int old = 0;
134
135	if (status != 0)
136		old = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
137				       VIRTIO_CONFIG_DEVICE_STATUS);
138	bus_space_write_1(sc->sc_iot, sc->sc_ioh, VIRTIO_CONFIG_DEVICE_STATUS,
139			  status|old);
140}
141
142int
143virtio_pci_match(struct device *parent, void *match, void *aux)
144{
145	struct pci_attach_args *pa;
146
147	pa = (struct pci_attach_args *)aux;
148	if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_QUMRANET &&
149	    PCI_PRODUCT(pa->pa_id) >= 0x1000 &&
150	    PCI_PRODUCT(pa->pa_id) <= 0x103f &&
151	    PCI_REVISION(pa->pa_class) == 0)
152		return 1;
153	return 0;
154}
155
156void
157virtio_pci_attach(struct device *parent, struct device *self, void *aux)
158{
159	struct virtio_pci_softc *sc = (struct virtio_pci_softc *)self;
160	struct virtio_softc *vsc = &sc->sc_sc;
161	struct pci_attach_args *pa = (struct pci_attach_args *)aux;
162	pci_chipset_tag_t pc = pa->pa_pc;
163	pcitag_t tag = pa->pa_tag;
164	int revision;
165	pcireg_t id;
166	char const *intrstr;
167	pci_intr_handle_t ih;
168
169	revision = PCI_REVISION(pa->pa_class);
170	if (revision != 0) {
171		printf("unknown revision 0x%02x; giving up\n", revision);
172		return;
173	}
174
175	/* subsystem ID shows what I am */
176	id = PCI_PRODUCT(pci_conf_read(pc, tag, PCI_SUBSYS_ID_REG));
177	printf(": Virtio %s Device", virtio_device_string(id));
178
179#ifdef notyet
180	if (pci_get_capability(pc, tag, PCI_CAP_MSIX, NULL, NULL))
181		printf(", msix capable");
182#endif
183	printf("\n");
184
185	vsc->sc_ops = &virtio_pci_ops;
186	sc->sc_pc = pc;
187	vsc->sc_dmat = pa->pa_dmat;
188	sc->sc_config_offset = VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI;
189
190	if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_IO, 0,
191			   &sc->sc_iot, &sc->sc_ioh, NULL, &sc->sc_iosize, 0)) {
192		printf("%s: can't map i/o space\n", vsc->sc_dev.dv_xname);
193		return;
194	}
195
196	virtio_device_reset(vsc);
197	virtio_pci_set_status(vsc, VIRTIO_CONFIG_DEVICE_STATUS_ACK);
198	virtio_pci_set_status(vsc, VIRTIO_CONFIG_DEVICE_STATUS_DRIVER);
199
200	/* XXX: use softc as aux... */
201	vsc->sc_childdevid = id;
202	vsc->sc_child = NULL;
203	config_found(self, sc, NULL);
204	if (vsc->sc_child == NULL) {
205		printf("%s: no matching child driver; not configured\n", vsc->sc_dev.dv_xname);
206		goto fail_1;
207	}
208	if (vsc->sc_child == VIRTIO_CHILD_ERROR) {
209		printf("%s: virtio configuration failed\n", vsc->sc_dev.dv_xname);
210		goto fail_1;
211	}
212
213	if (pci_intr_map_msi(pa, &ih) != 0 && pci_intr_map(pa, &ih) != 0) {
214		printf("%s: couldn't map interrupt\n", vsc->sc_dev.dv_xname);
215		goto fail_2;
216	}
217	intrstr = pci_intr_string(pc, ih);
218	sc->sc_ih = pci_intr_establish(pc, ih, vsc->sc_ipl, virtio_pci_intr, sc, vsc->sc_dev.dv_xname);
219	if (sc->sc_ih == NULL) {
220		printf("%s: couldn't establish interrupt", vsc->sc_dev.dv_xname);
221		if (intrstr != NULL)
222			printf(" at %s", intrstr);
223		printf("\n");
224		goto fail_2;
225	}
226	printf("%s: %s\n", vsc->sc_dev.dv_xname, intrstr);
227
228	virtio_set_status(vsc, VIRTIO_CONFIG_DEVICE_STATUS_DRIVER_OK);
229	return;
230
231fail_2:
232	config_detach(vsc->sc_child, 0);
233fail_1:
234	/* no pci_mapreg_unmap() or pci_intr_unmap() */
235	virtio_set_status(vsc, VIRTIO_CONFIG_DEVICE_STATUS_FAILED);
236}
237
238int
239virtio_pci_detach(struct device *self, int flags)
240{
241	struct virtio_pci_softc *sc = (struct virtio_pci_softc *)self;
242	struct virtio_softc *vsc = &sc->sc_sc;
243	int r;
244
245	if (vsc->sc_child != 0 && vsc->sc_child != VIRTIO_CHILD_ERROR) {
246		r = config_detach(vsc->sc_child, flags);
247		if (r)
248			return r;
249	}
250	KASSERT(vsc->sc_child == 0 || vsc->sc_child == VIRTIO_CHILD_ERROR);
251	KASSERT(vsc->sc_vqs == 0);
252	pci_intr_disestablish(sc->sc_pc, sc->sc_ih);
253	sc->sc_ih = 0;
254	if (sc->sc_iosize)
255		bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_iosize);
256	sc->sc_iosize = 0;
257
258	return 0;
259}
260
261/*
262 * Feature negotiation.
263 * Prints available / negotiated features if guest_feature_names != NULL and
264 * VIRTIO_DEBUG is 1
265 */
266uint32_t
267virtio_pci_negotiate_features(struct virtio_softc *vsc, uint32_t guest_features,
268			  const struct virtio_feature_name *guest_feature_names)
269{
270	struct virtio_pci_softc *sc = (struct virtio_pci_softc *)vsc;
271	uint32_t host, neg;
272
273	/*
274	 * indirect descriptors can be switched off by setting bit 1 in the
275	 * driver flags, see config(8)
276	 */
277	if (!(vsc->sc_dev.dv_cfdata->cf_flags & 1) &&
278	    !(vsc->sc_child->dv_cfdata->cf_flags & 1)) {
279		guest_features |= VIRTIO_F_RING_INDIRECT_DESC;
280	} else {
281		printf("RingIndirectDesc disabled by UKC\n");
282	}
283	host = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
284				VIRTIO_CONFIG_DEVICE_FEATURES);
285	neg = host & guest_features;
286#if VIRTIO_DEBUG
287	if (guest_feature_names)
288		virtio_log_features(host, neg, guest_feature_names);
289#endif
290	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
291			  VIRTIO_CONFIG_GUEST_FEATURES, neg);
292	vsc->sc_features = neg;
293	if (neg & VIRTIO_F_RING_INDIRECT_DESC)
294		vsc->sc_indirect = 1;
295	else
296		vsc->sc_indirect = 0;
297
298	return neg;
299}
300
301/*
302 * Device configuration registers.
303 */
304uint8_t
305virtio_pci_read_device_config_1(struct virtio_softc *vsc, int index)
306{
307	struct virtio_pci_softc *sc = (struct virtio_pci_softc *)vsc;
308	return bus_space_read_1(sc->sc_iot, sc->sc_ioh,
309				sc->sc_config_offset + index);
310}
311
312uint16_t
313virtio_pci_read_device_config_2(struct virtio_softc *vsc, int index)
314{
315	struct virtio_pci_softc *sc = (struct virtio_pci_softc *)vsc;
316	return bus_space_read_2(sc->sc_iot, sc->sc_ioh,
317				sc->sc_config_offset + index);
318}
319
320uint32_t
321virtio_pci_read_device_config_4(struct virtio_softc *vsc, int index)
322{
323	struct virtio_pci_softc *sc = (struct virtio_pci_softc *)vsc;
324	return bus_space_read_4(sc->sc_iot, sc->sc_ioh,
325				sc->sc_config_offset + index);
326}
327
328uint64_t
329virtio_pci_read_device_config_8(struct virtio_softc *vsc, int index)
330{
331	struct virtio_pci_softc *sc = (struct virtio_pci_softc *)vsc;
332	uint64_t r;
333
334	r = bus_space_read_4(sc->sc_iot, sc->sc_ioh,
335			     sc->sc_config_offset + index + sizeof(uint32_t));
336	r <<= 32;
337	r += bus_space_read_4(sc->sc_iot, sc->sc_ioh,
338			      sc->sc_config_offset + index);
339	return r;
340}
341
342void
343virtio_pci_write_device_config_1(struct virtio_softc *vsc,
344			     int index, uint8_t value)
345{
346	struct virtio_pci_softc *sc = (struct virtio_pci_softc *)vsc;
347	bus_space_write_1(sc->sc_iot, sc->sc_ioh,
348			  sc->sc_config_offset + index, value);
349}
350
351void
352virtio_pci_write_device_config_2(struct virtio_softc *vsc,
353			     int index, uint16_t value)
354{
355	struct virtio_pci_softc *sc = (struct virtio_pci_softc *)vsc;
356	bus_space_write_2(sc->sc_iot, sc->sc_ioh,
357			  sc->sc_config_offset + index, value);
358}
359
360void
361virtio_pci_write_device_config_4(struct virtio_softc *vsc,
362			     int index, uint32_t value)
363{
364	struct virtio_pci_softc *sc = (struct virtio_pci_softc *)vsc;
365	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
366			  sc->sc_config_offset + index, value);
367}
368
369void
370virtio_pci_write_device_config_8(struct virtio_softc *vsc,
371			     int index, uint64_t value)
372{
373	struct virtio_pci_softc *sc = (struct virtio_pci_softc *)vsc;
374	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
375			  sc->sc_config_offset + index,
376			  value & 0xffffffff);
377	bus_space_write_4(sc->sc_iot, sc->sc_ioh,
378			  sc->sc_config_offset + index + sizeof(uint32_t),
379			  value >> 32);
380}
381
382/*
383 * Interrupt handler.
384 */
385int
386virtio_pci_intr(void *arg)
387{
388	struct virtio_pci_softc *sc = arg;
389	struct virtio_softc *vsc = &sc->sc_sc;
390	int isr, r = 0;
391
392	/* check and ack the interrupt */
393	isr = bus_space_read_1(sc->sc_iot, sc->sc_ioh,
394			       VIRTIO_CONFIG_ISR_STATUS);
395	if (isr == 0)
396		return 0;
397	if ((isr & VIRTIO_CONFIG_ISR_CONFIG_CHANGE) &&
398	    (vsc->sc_config_change != NULL))
399		r = (vsc->sc_config_change)(vsc);
400	if (vsc->sc_intrhand != NULL)
401		r |= (vsc->sc_intrhand)(vsc);
402
403	return r;
404}
405
406void
407virtio_pci_kick(struct virtio_softc *vsc, uint16_t idx)
408{
409	struct virtio_pci_softc *sc = (struct virtio_pci_softc *)vsc;
410	bus_space_write_2(sc->sc_iot, sc->sc_ioh, VIRTIO_CONFIG_QUEUE_NOTIFY,
411	    idx);
412}
413