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