void vnet_stop(struct ifnet *ifp) { struct vnet_softc *sc = ifp->if_softc; struct ldc_conn *lc = &sc->sc_lc; ifp->if_flags &= ~IFF_RUNNING; ifq_clr_oactive(&ifp->if_snd); ifp->if_timer = 0; cbus_intr_setenabled(sc->sc_bustag, sc->sc_tx_ino, INTR_DISABLED); cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino, INTR_DISABLED); intr_barrier(sc->sc_tx_ih); intr_barrier(sc->sc_rx_ih); hv_ldc_tx_qconf(lc->lc_id, 0, 0); hv_ldc_rx_qconf(lc->lc_id, 0, 0); lc->lc_tx_seqid = 0; lc->lc_state = 0; lc->lc_tx_state = lc->lc_rx_state = LDC_CHANNEL_DOWN; vnet_ldc_reset(lc); free(sc->sc_vsd, M_DEVBUF, VNET_NUM_SOFT_DESC * sizeof(*sc->sc_vsd)); vnet_dring_free(sc->sc_dmatag, sc->sc_vd); hv_ldc_set_map_table(lc->lc_id, 0, 0); ldc_map_free(sc->sc_dmatag, sc->sc_lm); }
void vnet_init(struct ifnet *ifp) { struct vnet_softc *sc = ifp->if_softc; struct ldc_conn *lc = &sc->sc_lc; int err; sc->sc_lm = ldc_map_alloc(sc->sc_dmatag, 2048); if (sc->sc_lm == NULL) return; err = hv_ldc_set_map_table(lc->lc_id, sc->sc_lm->lm_map->dm_segs[0].ds_addr, sc->sc_lm->lm_nentries); if (err != H_EOK) { printf("hv_ldc_set_map_table %d\n", err); return; } sc->sc_vd = vnet_dring_alloc(sc->sc_dmatag, VNET_NUM_SOFT_DESC); if (sc->sc_vd == NULL) return; sc->sc_vsd = malloc(VNET_NUM_SOFT_DESC * sizeof(*sc->sc_vsd), M_DEVBUF, M_NOWAIT|M_ZERO); if (sc->sc_vsd == NULL) return; sc->sc_lm->lm_slot[0].entry = sc->sc_vd->vd_map->dm_segs[0].ds_addr; sc->sc_lm->lm_slot[0].entry &= LDC_MTE_RA_MASK; sc->sc_lm->lm_slot[0].entry |= LDC_MTE_CPR | LDC_MTE_CPW; sc->sc_lm->lm_next = 1; sc->sc_lm->lm_count = 1; err = hv_ldc_tx_qconf(lc->lc_id, lc->lc_txq->lq_map->dm_segs[0].ds_addr, lc->lc_txq->lq_nentries); if (err != H_EOK) printf("hv_ldc_tx_qconf %d\n", err); err = hv_ldc_rx_qconf(lc->lc_id, lc->lc_rxq->lq_map->dm_segs[0].ds_addr, lc->lc_rxq->lq_nentries); if (err != H_EOK) printf("hv_ldc_rx_qconf %d\n", err); cbus_intr_setenabled(sc->sc_bustag, sc->sc_tx_ino, INTR_ENABLED); cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino, INTR_ENABLED); ldc_send_vers(lc); ifp->if_flags |= IFF_RUNNING; }
int vldcpread(dev_t dev, struct uio *uio, int ioflag) { struct vldcp_softc *sc; struct ldc_conn *lc; uint64_t rx_head, rx_tail, rx_state; int err, ret; int s; sc = vldcp_lookup(dev); if (sc == NULL) return (ENXIO); lc = &sc->sc_lc; if (uio->uio_resid != 64) { device_unref(&sc->sc_dv); return (EINVAL); } s = spltty(); retry: err = hv_ldc_rx_get_state(lc->lc_id, &rx_head, &rx_tail, &rx_state); if (err != H_EOK) { splx(s); printf("%s: hv_ldc_rx_get_state %d\n", __func__, err); device_unref(&sc->sc_dv); return (EIO); } if (rx_state != LDC_CHANNEL_UP) { splx(s); device_unref(&sc->sc_dv); return (EIO); } DPRINTF(("rx head %llx, rx tail %llx\n", rx_head, rx_tail)); if (rx_head == rx_tail) { cbus_intr_setenabled(sc->sc_rx_sysino, INTR_ENABLED); ret = tsleep(lc->lc_rxq, PWAIT | PCATCH, "hvrd", 0); if (ret) { splx(s); device_unref(&sc->sc_dv); return (ret); } goto retry; } splx(s); ret = uiomove(lc->lc_rxq->lq_va + rx_head, 64, uio); rx_head += 64; rx_head &= ((lc->lc_rxq->lq_nentries * 64) - 1); err = hv_ldc_rx_set_qhead(lc->lc_id, rx_head); if (err != H_EOK) printf("%s: hv_ldc_rx_set_qhead %d\n", __func__, err); device_unref(&sc->sc_dv); return (ret); }
int vldcp_tx_intr(void *arg) { struct vldcp_softc *sc = arg; struct ldc_conn *lc = &sc->sc_lc; uint64_t tx_head, tx_tail, tx_state; int err; err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state); if (err != H_EOK) { printf("%s: hv_ldc_tx_get_state %d\n", __func__, err); return (0); } if (tx_state != lc->lc_tx_state) { switch (tx_state) { case LDC_CHANNEL_DOWN: DPRINTF(("Tx link down\n")); break; case LDC_CHANNEL_UP: DPRINTF(("Tx link up\n")); break; case LDC_CHANNEL_RESET: DPRINTF(("Tx link reset\n")); break; } lc->lc_tx_state = tx_state; } cbus_intr_setenabled(sc->sc_tx_sysino, INTR_DISABLED); selwakeup(&sc->sc_wsel); wakeup(lc->lc_txq); return (1); }
int vldcpclose(dev_t dev, int flag, int mode, struct proc *p) { struct vldcp_softc *sc; sc = vldcp_lookup(dev); if (sc == NULL) return (ENXIO); cbus_intr_setenabled(sc->sc_tx_sysino, INTR_DISABLED); cbus_intr_setenabled(sc->sc_rx_sysino, INTR_DISABLED); hv_ldc_tx_qconf(sc->sc_lc.lc_id, 0, 0); hv_ldc_rx_qconf(sc->sc_lc.lc_id, 0, 0); device_unref(&sc->sc_dv); return (0); }
int vldcppoll(dev_t dev, int events, struct proc *p) { struct vldcp_softc *sc; struct ldc_conn *lc; uint64_t head, tail, state; int revents = 0; int s, err; sc = vldcp_lookup(dev); if (sc == NULL) return (ENXIO); lc = &sc->sc_lc; s = spltty(); if (events & (POLLIN | POLLRDNORM)) { err = hv_ldc_rx_get_state(lc->lc_id, &head, &tail, &state); if (err == 0 && state == LDC_CHANNEL_UP && head != tail) revents |= events & (POLLIN | POLLRDNORM); } if (events & (POLLOUT | POLLWRNORM)) { err = hv_ldc_tx_get_state(lc->lc_id, &head, &tail, &state); if (err == 0 && state == LDC_CHANNEL_UP && head != tail) revents |= events & (POLLOUT | POLLWRNORM); } if (revents == 0) { if (events & (POLLIN | POLLRDNORM)) { cbus_intr_setenabled(sc->sc_rx_sysino, INTR_ENABLED); selrecord(p, &sc->sc_rsel); } if (events & (POLLOUT | POLLWRNORM)) { cbus_intr_setenabled(sc->sc_tx_sysino, INTR_ENABLED); selrecord(p, &sc->sc_wsel); } } splx(s); return revents; }
void vnet_stop(struct ifnet *ifp) { struct vnet_softc *sc = ifp->if_softc; struct ldc_conn *lc = &sc->sc_lc; ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); ifp->if_timer = 0; cbus_intr_setenabled(sc->sc_bustag, sc->sc_tx_ino, INTR_DISABLED); cbus_intr_setenabled(sc->sc_bustag, sc->sc_rx_ino, INTR_DISABLED); hv_ldc_tx_qconf(lc->lc_id, 0, 0); hv_ldc_rx_qconf(lc->lc_id, 0, 0); lc->lc_tx_seqid = 0; lc->lc_state = 0; lc->lc_tx_state = lc->lc_rx_state = LDC_CHANNEL_DOWN; vnet_ldc_reset(lc); vnet_dring_free(sc->sc_dmatag, sc->sc_vd); hv_ldc_set_map_table(lc->lc_id, 0, 0); ldc_map_free(sc->sc_dmatag, sc->sc_lm); }
void vdsk_attach(struct device *parent, struct device *self, void *aux) { struct vdsk_softc *sc = (struct vdsk_softc *)self; struct cbus_attach_args *ca = aux; struct scsibus_attach_args saa; struct ldc_conn *lc; uint64_t sysino[2]; int err, s; int timeout; sc->sc_bustag = ca->ca_bustag; sc->sc_dmatag = ca->ca_dmatag; if (cbus_intr_map(ca->ca_node, ca->ca_tx_ino, &sysino[0]) || cbus_intr_map(ca->ca_node, ca->ca_rx_ino, &sysino[1])) { printf(": can't map interrupt\n"); return; } printf(": ivec 0x%lx, 0x%lx", sysino[0], sysino[1]); /* * Un-configure queues before registering interrupt handlers, * such that we dont get any stale LDC packets or events. */ hv_ldc_tx_qconf(ca->ca_id, 0, 0); hv_ldc_rx_qconf(ca->ca_id, 0, 0); sc->sc_tx_ih = bus_intr_establish(ca->ca_bustag, sysino[0], IPL_BIO, 0, vdsk_tx_intr, sc, sc->sc_dv.dv_xname); sc->sc_rx_ih = bus_intr_establish(ca->ca_bustag, sysino[1], IPL_BIO, 0, vdsk_rx_intr, sc, sc->sc_dv.dv_xname); if (sc->sc_tx_ih == NULL || sc->sc_rx_ih == NULL) { printf(", can't establish interrupt\n"); return; } lc = &sc->sc_lc; lc->lc_id = ca->ca_id; lc->lc_sc = sc; lc->lc_reset = vdsk_ldc_reset; lc->lc_start = vdsk_ldc_start; lc->lc_rx_data = vdsk_rx_data; lc->lc_txq = ldc_queue_alloc(sc->sc_dmatag, VDSK_TX_ENTRIES); if (lc->lc_txq == NULL) { printf(", can't allocate tx queue\n"); return; } lc->lc_rxq = ldc_queue_alloc(sc->sc_dmatag, VDSK_RX_ENTRIES); if (lc->lc_rxq == NULL) { printf(", can't allocate rx queue\n"); goto free_txqueue; } sc->sc_lm = ldc_map_alloc(sc->sc_dmatag, 2048); if (sc->sc_lm == NULL) { printf(", can't allocate LDC mapping table\n"); goto free_rxqueue; } err = hv_ldc_set_map_table(lc->lc_id, sc->sc_lm->lm_map->dm_segs[0].ds_addr, sc->sc_lm->lm_nentries); if (err != H_EOK) { printf("hv_ldc_set_map_table %d\n", err); goto free_map; } sc->sc_vd = vdsk_dring_alloc(sc->sc_dmatag, 32); if (sc->sc_vd == NULL) { printf(", can't allocate dring\n"); goto free_map; } sc->sc_vsd = malloc(32 * sizeof(*sc->sc_vsd), M_DEVBUF, M_NOWAIT); if (sc->sc_vsd == NULL) { printf(", can't allocate software ring\n"); goto free_dring; } sc->sc_lm->lm_slot[0].entry = sc->sc_vd->vd_map->dm_segs[0].ds_addr; sc->sc_lm->lm_slot[0].entry &= LDC_MTE_RA_MASK; sc->sc_lm->lm_slot[0].entry |= LDC_MTE_CPR | LDC_MTE_CPW; sc->sc_lm->lm_slot[0].entry |= LDC_MTE_R | LDC_MTE_W; sc->sc_lm->lm_next = 1; sc->sc_lm->lm_count = 1; err = hv_ldc_tx_qconf(lc->lc_id, lc->lc_txq->lq_map->dm_segs[0].ds_addr, lc->lc_txq->lq_nentries); if (err != H_EOK) printf("hv_ldc_tx_qconf %d\n", err); err = hv_ldc_rx_qconf(lc->lc_id, lc->lc_rxq->lq_map->dm_segs[0].ds_addr, lc->lc_rxq->lq_nentries); if (err != H_EOK) printf("hv_ldc_rx_qconf %d\n", err); cbus_intr_setenabled(sysino[0], INTR_ENABLED); cbus_intr_setenabled(sysino[1], INTR_ENABLED); ldc_send_vers(lc); printf("\n"); /* * Interrupts aren't enabled during autoconf, so poll for VIO * peer-to-peer hanshake completion. */ s = splbio(); timeout = 1000; do { if (vdsk_rx_intr(sc) && sc->sc_vio_state == VIO_ESTABLISHED) break; delay(1000); } while(--timeout > 0); splx(s); if (sc->sc_vio_state != VIO_ESTABLISHED) return; scsi_iopool_init(&sc->sc_iopool, sc, vdsk_io_get, vdsk_io_put); sc->sc_switch.scsi_cmd = vdsk_scsi_cmd; sc->sc_switch.scsi_minphys = scsi_minphys; sc->sc_switch.dev_probe = vdsk_dev_probe; sc->sc_switch.dev_free = vdsk_dev_free; sc->sc_link.adapter = &sc->sc_switch; sc->sc_link.adapter_softc = self; sc->sc_link.adapter_buswidth = 2; sc->sc_link.luns = 1; /* XXX slices should be presented as luns? */ sc->sc_link.adapter_target = 2; sc->sc_link.openings = sc->sc_vd->vd_nentries - 1; sc->sc_link.pool = &sc->sc_iopool; bzero(&saa, sizeof(saa)); saa.saa_sc_link = &sc->sc_link; config_found(self, &saa, scsiprint); return; free_dring: vdsk_dring_free(sc->sc_dmatag, sc->sc_vd); free_map: hv_ldc_set_map_table(lc->lc_id, 0, 0); ldc_map_free(sc->sc_dmatag, sc->sc_lm); free_rxqueue: ldc_queue_free(sc->sc_dmatag, lc->lc_rxq); free_txqueue: ldc_queue_free(sc->sc_dmatag, lc->lc_txq); }
int vldcpwrite(dev_t dev, struct uio *uio, int ioflag) { struct vldcp_softc *sc; struct ldc_conn *lc; uint64_t tx_head, tx_tail, tx_state; uint64_t next_tx_tail; int err, ret; int s; sc = vldcp_lookup(dev); if (sc == NULL) return (ENXIO); lc = &sc->sc_lc; if (uio->uio_resid != 64) { device_unref(&sc->sc_dv); return (EINVAL); } s = spltty(); retry: err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state); if (err != H_EOK) { splx(s); printf("%s: hv_ldc_tx_get_state %d\n", __func__, err); device_unref(&sc->sc_dv); return (EIO); } if (tx_state != LDC_CHANNEL_UP) { splx(s); device_unref(&sc->sc_dv); return (EIO); } DPRINTF(("tx head %llx, tx tail %llx\n", tx_head, tx_tail)); next_tx_tail = tx_tail + 64; next_tx_tail &= ((lc->lc_txq->lq_nentries * 64) - 1); if (tx_head == next_tx_tail) { cbus_intr_setenabled(sc->sc_tx_sysino, INTR_ENABLED); ret = tsleep(lc->lc_txq, PWAIT | PCATCH, "hvwr", 0); if (ret) { splx(s); device_unref(&sc->sc_dv); return (ret); } goto retry; } splx(s); ret = uiomove(lc->lc_txq->lq_va + tx_tail, 64, uio); err = hv_ldc_tx_set_qtail(lc->lc_id, next_tx_tail); if (err != H_EOK) { printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err); device_unref(&sc->sc_dv); return (EIO); } device_unref(&sc->sc_dv); return (ret); }