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