void ldc_send_rdx(struct ldc_conn *lc) { struct ldc_pkt *lp; uint64_t tx_head, tx_tail, tx_state; int err; mutex_enter(&lc->lc_txq->lq_mtx); err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state); if (err != H_EOK || tx_state != LDC_CHANNEL_UP) { mutex_exit(&lc->lc_txq->lq_mtx); return; } lp = (struct ldc_pkt *)(uintptr_t)(lc->lc_txq->lq_va + tx_tail); bzero(lp, sizeof(struct ldc_pkt)); lp->type = LDC_CTRL; lp->stype = LDC_INFO; lp->ctrl = LDC_RDX; lp->env = LDC_MODE_UNRELIABLE; lp->seqid = lc->lc_tx_seqid++; tx_tail += sizeof(*lp); tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1); err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail); if (err != H_EOK) { printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err); mutex_exit(&lc->lc_txq->lq_mtx); return; } lc->lc_state = LDC_SND_RDX; mutex_exit(&lc->lc_txq->lq_mtx); }
void vdsk_sendmsg(struct vdsk_softc *sc, void *msg, size_t len) { struct ldc_conn *lc = &sc->sc_lc; struct ldc_pkt *lp; 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) return; lp = (struct ldc_pkt *)(lc->lc_txq->lq_va + tx_tail); bzero(lp, sizeof(struct ldc_pkt)); lp->type = LDC_DATA; lp->stype = LDC_INFO; KASSERT((len & ~LDC_LEN_MASK) == 0); lp->env = len | LDC_FRAG_STOP | LDC_FRAG_START; lp->seqid = lc->lc_tx_seqid++; bcopy(msg, &lp->major, len); tx_tail += sizeof(*lp); tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1); err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail); if (err != H_EOK) printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err); }
void ldc_send_ack(struct ldc_conn *lc) { struct ldc_pkt *lp; uint64_t tx_head, tx_tail, tx_state; int err; mutex_enter(&lc->lc_txq->lq_mtx); err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state); if (err != H_EOK || tx_state != LDC_CHANNEL_UP) { mutex_exit(&lc->lc_txq->lq_mtx); return; } lp = (struct ldc_pkt *)(uintptr_t)(lc->lc_txq->lq_va + tx_tail); bzero(lp, sizeof(struct ldc_pkt)); lp->type = LDC_CTRL; lp->stype = LDC_ACK; lp->ctrl = LDC_VERS; lp->major = 1; lp->minor = 0; tx_tail += sizeof(*lp); tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1); err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail); if (err != H_EOK) { printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err); mutex_exit(&lc->lc_txq->lq_mtx); return; } lc->lc_state = LDC_RCV_VERS; mutex_exit(&lc->lc_txq->lq_mtx); }
int ldc_send_unreliable(struct ldc_conn *lc, void *msg, size_t len) { struct ldc_pkt *lp; uint64_t tx_head, tx_tail, tx_state; uint64_t tx_avail; uint8_t *p = msg; int err; mutex_enter(&lc->lc_txq->lq_mtx); err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state); if (err != H_EOK || tx_state != LDC_CHANNEL_UP) { mutex_exit(&lc->lc_txq->lq_mtx); return (EIO); } tx_avail = (tx_head - tx_tail) / sizeof(*lp) + lc->lc_txq->lq_nentries - 1; tx_avail %= lc->lc_txq->lq_nentries; if (len > tx_avail * LDC_PKT_PAYLOAD) { mutex_exit(&lc->lc_txq->lq_mtx); return (EWOULDBLOCK); } while (len > 0) { lp = (struct ldc_pkt *)(uintptr_t)(lc->lc_txq->lq_va + tx_tail); bzero(lp, sizeof(struct ldc_pkt)); lp->type = LDC_DATA; lp->stype = LDC_INFO; lp->env = min(len, LDC_PKT_PAYLOAD); if (p == msg) lp->env |= LDC_FRAG_START; if (len <= LDC_PKT_PAYLOAD) lp->env |= LDC_FRAG_STOP; lp->seqid = lc->lc_tx_seqid++; bcopy(p, &lp->major, min(len, LDC_PKT_PAYLOAD)); tx_tail += sizeof(*lp); tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1); err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail); if (err != H_EOK) { printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err); mutex_exit(&lc->lc_txq->lq_mtx); return (EIO); } p += min(len, LDC_PKT_PAYLOAD); len -= min(len, LDC_PKT_PAYLOAD); } mutex_exit(&lc->lc_txq->lq_mtx); return (0); }
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); }