Home | History | Annotate | Line # | Download | only in pci
virtio_pci.c revision 1.1
      1  1.1  cherry /* $NetBSD: virtio_pci.c,v 1.1 2017/08/02 08:39:14 cherry Exp $ */
      2  1.1  cherry 
      3  1.1  cherry /*
      4  1.1  cherry  * Copyright (c) 2010 Minoura Makoto.
      5  1.1  cherry  * All rights reserved.
      6  1.1  cherry  *
      7  1.1  cherry  * Redistribution and use in source and binary forms, with or without
      8  1.1  cherry  * modification, are permitted provided that the following conditions
      9  1.1  cherry  * are met:
     10  1.1  cherry  * 1. Redistributions of source code must retain the above copyright
     11  1.1  cherry  *    notice, this list of conditions and the following disclaimer.
     12  1.1  cherry  * 2. Redistributions in binary form must reproduce the above copyright
     13  1.1  cherry  *    notice, this list of conditions and the following disclaimer in the
     14  1.1  cherry  *    documentation and/or other materials provided with the distribution.
     15  1.1  cherry  *
     16  1.1  cherry  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17  1.1  cherry  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18  1.1  cherry  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19  1.1  cherry  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  1.1  cherry  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     21  1.1  cherry  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     22  1.1  cherry  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     23  1.1  cherry  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24  1.1  cherry  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     25  1.1  cherry  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  1.1  cherry  */
     27  1.1  cherry 
     28  1.1  cherry #include <sys/cdefs.h>
     29  1.1  cherry __KERNEL_RCSID(0, "$NetBSD");
     30  1.1  cherry 
     31  1.1  cherry #include <sys/param.h>
     32  1.1  cherry #include <sys/systm.h>
     33  1.1  cherry 
     34  1.1  cherry #include <sys/device.h>
     35  1.1  cherry 
     36  1.1  cherry #include <dev/pci/pcidevs.h>
     37  1.1  cherry #include <dev/pci/pcireg.h>
     38  1.1  cherry #include <dev/pci/pcivar.h>
     39  1.1  cherry 
     40  1.1  cherry #define VIRTIO_PRIVATE
     41  1.1  cherry 
     42  1.1  cherry #include <dev/pci/virtioreg.h> /* XXX: move to non-pci */
     43  1.1  cherry #include <dev/pci/virtiovar.h> /* XXX: move to non-pci */
     44  1.1  cherry 
     45  1.1  cherry static int	virtio_match(device_t, cfdata_t, void *);
     46  1.1  cherry static void	virtio_attach(device_t, device_t, void *);
     47  1.1  cherry static int	virtio_rescan(device_t, const char *, const int *);
     48  1.1  cherry static int	virtio_detach(device_t, int);
     49  1.1  cherry 
     50  1.1  cherry static const char *virtio_device_name[] = {
     51  1.1  cherry 	"Unknown (0)",			/* 0 */
     52  1.1  cherry 	"Network",			/* 1 */
     53  1.1  cherry 	"Block",			/* 2 */
     54  1.1  cherry 	"Console",			/* 3 */
     55  1.1  cherry 	"Entropy",			/* 4 */
     56  1.1  cherry 	"Memory Balloon",		/* 5 */
     57  1.1  cherry 	"I/O Memory",			/* 6 */
     58  1.1  cherry 	"Remote Processor Messaging",	/* 7 */
     59  1.1  cherry 	"SCSI",				/* 8 */
     60  1.1  cherry 	"9P Transport",			/* 9 */
     61  1.1  cherry 	"mac80211 wlan",		/* 10 */
     62  1.1  cherry };
     63  1.1  cherry #define NDEVNAMES	__arraycount(virtio_device_name)
     64  1.1  cherry 
     65  1.1  cherry CFATTACH_DECL3_NEW(virtio_pci, sizeof(struct virtio_softc),
     66  1.1  cherry     virtio_match, virtio_attach, virtio_detach, NULL, virtio_rescan, NULL,
     67  1.1  cherry     DVF_DETACH_SHUTDOWN);
     68  1.1  cherry 
     69  1.1  cherry static int
     70  1.1  cherry virtio_match(device_t parent, cfdata_t match, void *aux)
     71  1.1  cherry {
     72  1.1  cherry 	struct pci_attach_args *pa;
     73  1.1  cherry 
     74  1.1  cherry 	pa = (struct pci_attach_args *)aux;
     75  1.1  cherry 	switch (PCI_VENDOR(pa->pa_id)) {
     76  1.1  cherry 	case PCI_VENDOR_QUMRANET:
     77  1.1  cherry 		if ((PCI_PRODUCT_QUMRANET_VIRTIO_1000 <=
     78  1.1  cherry 		     PCI_PRODUCT(pa->pa_id)) &&
     79  1.1  cherry 		    (PCI_PRODUCT(pa->pa_id) <=
     80  1.1  cherry 		     PCI_PRODUCT_QUMRANET_VIRTIO_103F))
     81  1.1  cherry 			return 1;
     82  1.1  cherry 		break;
     83  1.1  cherry 	}
     84  1.1  cherry 
     85  1.1  cherry 	return 0;
     86  1.1  cherry }
     87  1.1  cherry 
     88  1.1  cherry static void
     89  1.1  cherry virtio_attach(device_t parent, device_t self, void *aux)
     90  1.1  cherry {
     91  1.1  cherry 	struct virtio_softc *sc = device_private(self);
     92  1.1  cherry 	struct pci_attach_args *pa = (struct pci_attach_args *)aux;
     93  1.1  cherry 	pci_chipset_tag_t pc = pa->pa_pc;
     94  1.1  cherry 	pcitag_t tag = pa->pa_tag;
     95  1.1  cherry 	int revision;
     96  1.1  cherry 	pcireg_t id;
     97  1.1  cherry 
     98  1.1  cherry 	revision = PCI_REVISION(pa->pa_class);
     99  1.1  cherry 	if (revision != 0) {
    100  1.1  cherry 		aprint_normal(": unknown revision 0x%02x; giving up\n",
    101  1.1  cherry 			      revision);
    102  1.1  cherry 		return;
    103  1.1  cherry 	}
    104  1.1  cherry 	aprint_normal("\n");
    105  1.1  cherry 	aprint_naive("\n");
    106  1.1  cherry 
    107  1.1  cherry 	/* subsystem ID shows what I am */
    108  1.1  cherry 	id = pci_conf_read(pc, tag, PCI_SUBSYS_ID_REG);
    109  1.1  cherry 	aprint_normal_dev(self, "Virtio %s Device (rev. 0x%02x)\n",
    110  1.1  cherry 			  (PCI_SUBSYS_ID(id) < NDEVNAMES?
    111  1.1  cherry 			   virtio_device_name[PCI_SUBSYS_ID(id)] : "Unknown"),
    112  1.1  cherry 			  revision);
    113  1.1  cherry 
    114  1.1  cherry 	sc->sc_dev = self;
    115  1.1  cherry 	sc->sc_pc = pc;
    116  1.1  cherry 	sc->sc_tag = tag;
    117  1.1  cherry 	sc->sc_iot = pa->pa_iot;
    118  1.1  cherry 	if (pci_dma64_available(pa))
    119  1.1  cherry 		sc->sc_dmat = pa->pa_dmat64;
    120  1.1  cherry 	else
    121  1.1  cherry 		sc->sc_dmat = pa->pa_dmat;
    122  1.1  cherry 	sc->sc_config_offset = VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI;
    123  1.1  cherry 
    124  1.1  cherry 	if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_IO, 0,
    125  1.1  cherry 			   &sc->sc_iot, &sc->sc_ioh, NULL, &sc->sc_iosize)) {
    126  1.1  cherry 		aprint_error_dev(self, "can't map i/o space\n");
    127  1.1  cherry 		return;
    128  1.1  cherry 	}
    129  1.1  cherry 
    130  1.1  cherry 	virtio_device_reset(sc);
    131  1.1  cherry 	virtio_set_status(sc, VIRTIO_CONFIG_DEVICE_STATUS_ACK);
    132  1.1  cherry 	virtio_set_status(sc, VIRTIO_CONFIG_DEVICE_STATUS_DRIVER);
    133  1.1  cherry 
    134  1.1  cherry 	sc->sc_childdevid = PCI_SUBSYS_ID(id);
    135  1.1  cherry 	sc->sc_child = NULL;
    136  1.1  cherry 	sc->sc_pa = *pa;
    137  1.1  cherry 	virtio_rescan(self, "virtio", 0);
    138  1.1  cherry 	return;
    139  1.1  cherry }
    140  1.1  cherry 
    141  1.1  cherry /* ARGSUSED */
    142  1.1  cherry static int
    143  1.1  cherry virtio_rescan(device_t self, const char *attr, const int *scan_flags)
    144  1.1  cherry {
    145  1.1  cherry 	struct virtio_softc *sc;
    146  1.1  cherry 	struct virtio_attach_args va;
    147  1.1  cherry 
    148  1.1  cherry 	sc = device_private(self);
    149  1.1  cherry 	if (sc->sc_child)	/* Child already attached? */
    150  1.1  cherry 		return 0;
    151  1.1  cherry 
    152  1.1  cherry 	memset(&va, 0, sizeof(va));
    153  1.1  cherry 	va.sc_childdevid = sc->sc_childdevid;
    154  1.1  cherry 
    155  1.1  cherry 	config_found_ia(self, attr, &va, NULL);
    156  1.1  cherry 
    157  1.1  cherry 	if (sc->sc_child == NULL) {
    158  1.1  cherry 		aprint_error_dev(self,
    159  1.1  cherry 				 "no matching child driver; not configured\n");
    160  1.1  cherry 		return 0;
    161  1.1  cherry 	}
    162  1.1  cherry 
    163  1.1  cherry 	if (sc->sc_child == VIRTIO_CHILD_FAILED) {
    164  1.1  cherry 		aprint_error_dev(self,
    165  1.1  cherry 				 "virtio configuration failed\n");
    166  1.1  cherry 		return 0;
    167  1.1  cherry 	}
    168  1.1  cherry 
    169  1.1  cherry 	/*
    170  1.1  cherry 	 * Make sure child drivers initialize interrupts via call
    171  1.1  cherry 	 * to virtio_child_attach_finish().
    172  1.1  cherry 	 */
    173  1.1  cherry 	KASSERT(sc->sc_ihs_num != 0);
    174  1.1  cherry 
    175  1.1  cherry 	return 0;
    176  1.1  cherry }
    177  1.1  cherry 
    178  1.1  cherry 
    179  1.1  cherry static int
    180  1.1  cherry virtio_detach(device_t self, int flags)
    181  1.1  cherry {
    182  1.1  cherry 	struct virtio_softc *sc = device_private(self);
    183  1.1  cherry 	int r;
    184  1.1  cherry 
    185  1.1  cherry 	if (sc->sc_child != NULL) {
    186  1.1  cherry 		r = config_detach(sc->sc_child, flags);
    187  1.1  cherry 		if (r)
    188  1.1  cherry 			return r;
    189  1.1  cherry 	}
    190  1.1  cherry 
    191  1.1  cherry 	/* Check that child detached properly */
    192  1.1  cherry 	KASSERT(sc->sc_child == NULL);
    193  1.1  cherry 	KASSERT(sc->sc_vqs == NULL);
    194  1.1  cherry 	KASSERT(sc->sc_ihs_num == 0);
    195  1.1  cherry 
    196  1.1  cherry 	if (sc->sc_iosize)
    197  1.1  cherry 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_iosize);
    198  1.1  cherry 	sc->sc_iosize = 0;
    199  1.1  cherry 
    200  1.1  cherry 	return 0;
    201  1.1  cherry }
    202