version 1.28, 2017/06/01 02:45:11 |
version 1.29, 2017/08/02 08:39:14 |
Line 43 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 43 __KERNEL_RCSID(0, "$NetBSD$"); |
|
|
|
#define VIRTIO_PRIVATE |
#define VIRTIO_PRIVATE |
|
|
#include <dev/pci/virtioreg.h> |
#include <dev/pci/virtioreg.h> /* XXX: move to non-pci */ |
#include <dev/pci/virtiovar.h> |
#include <dev/pci/virtiovar.h> /* XXX: move to non-pci */ |
|
|
#define MINSEG_INDIRECT 2 /* use indirect if nsegs >= this value */ |
#define MINSEG_INDIRECT 2 /* use indirect if nsegs >= this value */ |
|
|
static int virtio_match(device_t, cfdata_t, void *); |
|
static void virtio_attach(device_t, device_t, void *); |
|
static int virtio_rescan(device_t, const char *, const int *); |
|
static int virtio_detach(device_t, int); |
|
static int virtio_intr(void *arg); |
static int virtio_intr(void *arg); |
static int virtio_msix_queue_intr(void *); |
static int virtio_msix_queue_intr(void *); |
static int virtio_msix_config_intr(void *); |
static int virtio_msix_config_intr(void *); |
Line 66 static void virtio_soft_intr(void *arg); |
|
Line 62 static void virtio_soft_intr(void *arg); |
|
static void virtio_init_vq(struct virtio_softc *, |
static void virtio_init_vq(struct virtio_softc *, |
struct virtqueue *, const bool); |
struct virtqueue *, const bool); |
|
|
CFATTACH_DECL3_NEW(virtio, sizeof(struct virtio_softc), |
|
virtio_match, virtio_attach, virtio_detach, NULL, virtio_rescan, NULL, |
|
DVF_DETACH_SHUTDOWN); |
|
|
|
/* we use the legacy virtio spec, so the pci registers are host native |
/* we use the legacy virtio spec, so the pci registers are host native |
* byte order, not pci (i.e. LE) byte order */ |
* byte order, not pci (i.e. LE) byte order */ |
Line 109 nbo_bus_space_write_4(bus_space_tag_t sp |
|
Line 102 nbo_bus_space_write_4(bus_space_tag_t sp |
|
#define REG_LO_OFF 0 |
#define REG_LO_OFF 0 |
#endif |
#endif |
|
|
static void |
void |
virtio_set_status(struct virtio_softc *sc, int status) |
virtio_set_status(struct virtio_softc *sc, int status) |
{ |
{ |
int old = 0; |
int old = 0; |
Line 121 virtio_set_status(struct virtio_softc *s |
|
Line 114 virtio_set_status(struct virtio_softc *s |
|
status|old); |
status|old); |
} |
} |
|
|
#define virtio_device_reset(sc) virtio_set_status((sc), 0) |
|
|
|
static int |
|
virtio_match(device_t parent, cfdata_t match, void *aux) |
|
{ |
|
struct pci_attach_args *pa; |
|
|
|
pa = (struct pci_attach_args *)aux; |
|
switch (PCI_VENDOR(pa->pa_id)) { |
|
case PCI_VENDOR_QUMRANET: |
|
if ((PCI_PRODUCT_QUMRANET_VIRTIO_1000 <= |
|
PCI_PRODUCT(pa->pa_id)) && |
|
(PCI_PRODUCT(pa->pa_id) <= |
|
PCI_PRODUCT_QUMRANET_VIRTIO_103F)) |
|
return 1; |
|
break; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
static const char *virtio_device_name[] = { |
|
"Unknown (0)", /* 0 */ |
|
"Network", /* 1 */ |
|
"Block", /* 2 */ |
|
"Console", /* 3 */ |
|
"Entropy", /* 4 */ |
|
"Memory Balloon", /* 5 */ |
|
"I/O Memory", /* 6 */ |
|
"Remote Processor Messaging", /* 7 */ |
|
"SCSI", /* 8 */ |
|
"9P Transport", /* 9 */ |
|
"mac80211 wlan", /* 10 */ |
|
}; |
|
#define NDEVNAMES __arraycount(virtio_device_name) |
|
|
|
#define VIRTIO_MSIX_CONFIG_VECTOR_INDEX 0 |
#define VIRTIO_MSIX_CONFIG_VECTOR_INDEX 0 |
#define VIRTIO_MSIX_QUEUE_VECTOR_INDEX 1 |
#define VIRTIO_MSIX_QUEUE_VECTOR_INDEX 1 |
|
|
Line 383 virtio_free_interrupts(struct virtio_sof |
|
Line 340 virtio_free_interrupts(struct virtio_sof |
|
sc->sc_ihs_num = 0; |
sc->sc_ihs_num = 0; |
} |
} |
|
|
static void |
|
virtio_attach(device_t parent, device_t self, void *aux) |
|
{ |
|
struct virtio_softc *sc = device_private(self); |
|
struct pci_attach_args *pa = (struct pci_attach_args *)aux; |
|
pci_chipset_tag_t pc = pa->pa_pc; |
|
pcitag_t tag = pa->pa_tag; |
|
int revision; |
|
pcireg_t id; |
|
|
|
revision = PCI_REVISION(pa->pa_class); |
|
if (revision != 0) { |
|
aprint_normal(": unknown revision 0x%02x; giving up\n", |
|
revision); |
|
return; |
|
} |
|
aprint_normal("\n"); |
|
aprint_naive("\n"); |
|
|
|
/* subsystem ID shows what I am */ |
|
id = pci_conf_read(pc, tag, PCI_SUBSYS_ID_REG); |
|
aprint_normal_dev(self, "Virtio %s Device (rev. 0x%02x)\n", |
|
(PCI_SUBSYS_ID(id) < NDEVNAMES? |
|
virtio_device_name[PCI_SUBSYS_ID(id)] : "Unknown"), |
|
revision); |
|
|
|
sc->sc_dev = self; |
|
sc->sc_pc = pc; |
|
sc->sc_tag = tag; |
|
sc->sc_iot = pa->pa_iot; |
|
if (pci_dma64_available(pa)) |
|
sc->sc_dmat = pa->pa_dmat64; |
|
else |
|
sc->sc_dmat = pa->pa_dmat; |
|
sc->sc_config_offset = VIRTIO_CONFIG_DEVICE_CONFIG_NOMSI; |
|
|
|
if (pci_mapreg_map(pa, PCI_MAPREG_START, PCI_MAPREG_TYPE_IO, 0, |
|
&sc->sc_iot, &sc->sc_ioh, NULL, &sc->sc_iosize)) { |
|
aprint_error_dev(self, "can't map i/o space\n"); |
|
return; |
|
} |
|
|
|
virtio_device_reset(sc); |
|
virtio_set_status(sc, VIRTIO_CONFIG_DEVICE_STATUS_ACK); |
|
virtio_set_status(sc, VIRTIO_CONFIG_DEVICE_STATUS_DRIVER); |
|
|
|
sc->sc_childdevid = PCI_SUBSYS_ID(id); |
|
sc->sc_child = NULL; |
|
sc->sc_pa = *pa; |
|
virtio_rescan(self, "virtio", 0); |
|
return; |
|
} |
|
|
|
/* ARGSUSED */ |
|
static int |
|
virtio_rescan(device_t self, const char *attr, const int *scan_flags) |
|
{ |
|
struct virtio_softc *sc; |
|
struct virtio_attach_args va; |
|
|
|
sc = device_private(self); |
|
if (sc->sc_child) /* Child already attached? */ |
|
return 0; |
|
|
|
memset(&va, 0, sizeof(va)); |
|
va.sc_childdevid = sc->sc_childdevid; |
|
|
|
config_found_ia(self, attr, &va, NULL); |
|
|
|
if (sc->sc_child == NULL) { |
|
aprint_error_dev(self, |
|
"no matching child driver; not configured\n"); |
|
return 0; |
|
} |
|
|
|
if (sc->sc_child == VIRTIO_CHILD_FAILED) { |
|
aprint_error_dev(self, |
|
"virtio configuration failed\n"); |
|
return 0; |
|
} |
|
|
|
/* |
|
* Make sure child drivers initialize interrupts via call |
|
* to virtio_child_attach_finish(). |
|
*/ |
|
KASSERT(sc->sc_ihs_num != 0); |
|
|
|
return 0; |
|
} |
|
|
|
static int |
|
virtio_detach(device_t self, int flags) |
|
{ |
|
struct virtio_softc *sc = device_private(self); |
|
int r; |
|
|
|
if (sc->sc_child != NULL) { |
|
r = config_detach(sc->sc_child, flags); |
|
if (r) |
|
return r; |
|
} |
|
|
|
/* Check that child detached properly */ |
|
KASSERT(sc->sc_child == NULL); |
|
KASSERT(sc->sc_vqs == NULL); |
|
KASSERT(sc->sc_ihs_num == 0); |
|
|
|
if (sc->sc_iosize) |
|
bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_iosize); |
|
sc->sc_iosize = 0; |
|
|
|
return 0; |
|
} |
|
|
|
/* |
/* |
* Reset the device. |
* Reset the device. |