Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/hyperv/vmbus/vmbus_br.c
Context not available. | |||||
} | } | ||||
uint32_t | uint32_t | ||||
vmbus_rxbr_available(const struct vmbus_rxbr *rbr) | |||||
{ | |||||
return (vmbus_rxbr_avail(rbr)); | |||||
} | |||||
uint32_t | |||||
vmbus_rxbr_intr_unmask(struct vmbus_rxbr *rbr) | vmbus_rxbr_intr_unmask(struct vmbus_rxbr *rbr) | ||||
{ | { | ||||
rbr->rxbr_imask = 0; | rbr->rxbr_imask = 0; | ||||
Context not available. | |||||
vmbus_br_setup(&tbr->txbr, buf, blen); | vmbus_br_setup(&tbr->txbr, buf, blen); | ||||
} | } | ||||
uint32_t | |||||
vmbus_txbr_get_imask(const struct vmbus_txbr *tbr) | |||||
{ | |||||
mb(); | |||||
return(tbr->txbr_imask); | |||||
} | |||||
/* | /* | ||||
* When we write to the ring buffer, check if the host needs to be | * When we write to the ring buffer, check if the host needs to be | ||||
* signaled. | * signaled. | ||||
Context not available. | |||||
return VMBUS_BR_IDXINC(windex, cplen, br_dsize); | return VMBUS_BR_IDXINC(windex, cplen, br_dsize); | ||||
} | } | ||||
static __inline uint32_t | |||||
vmbus_txbr_copyto_call(const struct vmbus_txbr *tbr, uint32_t windex, | |||||
uint32_t cplen, vmbus_br_copy_callback_t cb, void *cbarg, int *ret) | |||||
{ | |||||
uint8_t *br_data = tbr->txbr_data; | |||||
uint32_t br_dsize = tbr->txbr_dsize; | |||||
int err = 0; | |||||
if (cplen > br_dsize - windex) { | |||||
uint32_t fraglen = br_dsize - windex; | |||||
/* Wrap-around detected */ | |||||
// memcpy(br_data + windex, src, fraglen); | |||||
// memcpy(br_data, src + fraglen, cplen - fraglen); | |||||
err = cb((void *)(br_data + windex), fraglen, cbarg); | |||||
if (!err) | |||||
err = cb((void *)br_data, cplen - fraglen, cbarg); | |||||
} else { | |||||
// memcpy(br_data + windex, src, cplen); | |||||
err = cb((void *)(br_data + windex), cplen, cbarg); | |||||
} | |||||
*ret = err; | |||||
return VMBUS_BR_IDXINC(windex, cplen, br_dsize); | |||||
} | |||||
uint32_t | |||||
vmbus_txbr_available(const struct vmbus_txbr *tbr) | |||||
{ | |||||
return (vmbus_txbr_avail(tbr)); | |||||
} | |||||
/* | /* | ||||
* NOTE: | |||||
* Not holding lock when calling user provided callback routine. | |||||
* Caller should hold lock to serialize ring buffer accesses. | |||||
*/ | |||||
int | |||||
vmbus_txbr_write_call(struct vmbus_txbr *tbr, | |||||
const struct iovec iov[], int iovlen, | |||||
vmbus_br_copy_callback_t cb, void *cbarg, | |||||
boolean_t *need_sig) | |||||
{ | |||||
uint32_t old_windex, windex, total; | |||||
uint64_t save_windex; | |||||
int i; | |||||
int cb_ret = 0; | |||||
total = 0; | |||||
for (i = 0; i < iovlen; i++) | |||||
total += iov[i].iov_len; | |||||
total += sizeof(save_windex); | |||||
/* | |||||
* NOTE: | |||||
* If this write is going to make br_windex same as br_rindex, | |||||
* i.e. the available space for write is same as the write size, | |||||
* we can't do it then, since br_windex == br_rindex means that | |||||
* the bufring is empty. | |||||
*/ | |||||
if (vmbus_txbr_avail(tbr) <= total) { | |||||
return (EAGAIN); | |||||
} | |||||
/* Save br_windex for later use */ | |||||
old_windex = tbr->txbr_windex; | |||||
/* | |||||
* Copy the scattered channel packet to the TX bufring. | |||||
*/ | |||||
windex = old_windex; | |||||
for (i = 0; i < iovlen; i++) { | |||||
if (iov[i].iov_base != NULL) { | |||||
windex = vmbus_txbr_copyto(tbr, windex, | |||||
iov[i].iov_base, iov[i].iov_len); | |||||
} else if (cb != NULL) { | |||||
windex = vmbus_txbr_copyto_call(tbr, windex, | |||||
iov[i].iov_len, cb, cbarg, &cb_ret); | |||||
/* | |||||
* If callback fails, return without updating | |||||
* write index. | |||||
*/ | |||||
if (cb_ret) | |||||
return (cb_ret); | |||||
} | |||||
} | |||||
mtx_lock_spin(&tbr->txbr_lock); | |||||
/* | |||||
* Set the offset of the current channel packet. | |||||
*/ | |||||
save_windex = ((uint64_t)old_windex) << 32; | |||||
windex = vmbus_txbr_copyto(tbr, windex, &save_windex, | |||||
sizeof(save_windex)); | |||||
/* | |||||
* Update the write index _after_ the channel packet | |||||
* is copied. | |||||
*/ | |||||
__compiler_membar(); | |||||
tbr->txbr_windex = windex; | |||||
mtx_unlock_spin(&tbr->txbr_lock); | |||||
if (need_sig) | |||||
*need_sig = vmbus_txbr_need_signal(tbr, old_windex); | |||||
return (0); | |||||
} | |||||
/* | |||||
* Write scattered channel packet to TX bufring. | * Write scattered channel packet to TX bufring. | ||||
* | * | ||||
* The offset of this channel packet is written as a 64bits value | * The offset of this channel packet is written as a 64bits value | ||||
Context not available. | |||||
return VMBUS_BR_IDXINC(rindex, cplen, br_dsize); | return VMBUS_BR_IDXINC(rindex, cplen, br_dsize); | ||||
} | } | ||||
static __inline uint32_t | |||||
vmbus_rxbr_copyfrom_call(const struct vmbus_rxbr *rbr, uint32_t rindex, | |||||
int cplen, vmbus_br_copy_callback_t cb, void *cbarg) | |||||
{ | |||||
uint8_t *br_data = rbr->rxbr_data; | |||||
uint32_t br_dsize = rbr->rxbr_dsize; | |||||
int error = 0; | |||||
if (cplen > br_dsize - rindex) { | |||||
uint32_t fraglen = br_dsize - rindex; | |||||
/* Wrap-around detected. */ | |||||
error = cb((void *)(br_data + rindex), fraglen, cbarg); | |||||
if (!error) | |||||
error = cb((void *)br_data, cplen - fraglen, cbarg); | |||||
} else { | |||||
error = cb((void *)(br_data + rindex), cplen, cbarg); | |||||
} | |||||
return (error); | |||||
} | |||||
int | int | ||||
vmbus_rxbr_peek(struct vmbus_rxbr *rbr, void *data, int dlen) | vmbus_rxbr_peek(struct vmbus_rxbr *rbr, void *data, int dlen) | ||||
{ | { | ||||
Context not available. | |||||
/* | /* | ||||
* NOTE: | * NOTE: | ||||
* We only hold spin lock to check the ring buffer space. It is | |||||
* released before calling user provided callback routine. | |||||
* Caller should hold lock to serialize ring buffer accesses. | |||||
*/ | |||||
int | |||||
vmbus_rxbr_peek_call(struct vmbus_rxbr *rbr, int dlen, uint32_t skip, | |||||
vmbus_br_copy_callback_t cb, void *cbarg) | |||||
{ | |||||
uint32_t rindex, br_dsize0 = rbr->rxbr_dsize; | |||||
int ret; | |||||
mtx_lock_spin(&rbr->rxbr_lock); | |||||
/* | |||||
* The requested data + skip and the 64bits channel packet | |||||
* offset should be there at least. | |||||
*/ | |||||
if (vmbus_rxbr_avail(rbr) < skip + dlen + sizeof(uint64_t)) { | |||||
mtx_unlock_spin(&rbr->rxbr_lock); | |||||
return (EAGAIN); | |||||
} | |||||
rindex = VMBUS_BR_IDXINC(rbr->rxbr_rindex, skip, br_dsize0); | |||||
mtx_unlock_spin(&rbr->rxbr_lock); | |||||
ret = vmbus_rxbr_copyfrom_call(rbr, rindex, dlen, cb, cbarg); | |||||
return (ret); | |||||
} | |||||
/* | |||||
* NOTE: | |||||
* We assume idx_adv == sizeof(channel packet). | |||||
*/ | |||||
int | |||||
vmbus_rxbr_idxadv_peek(struct vmbus_rxbr *rbr, void *data, int dlen, | |||||
uint32_t idx_adv) | |||||
{ | |||||
uint32_t rindex, br_dsize = rbr->rxbr_dsize; | |||||
mtx_lock_spin(&rbr->rxbr_lock); | |||||
/* | |||||
* Make sure it has enough data to read. | |||||
*/ | |||||
if (vmbus_rxbr_avail(rbr) < idx_adv + sizeof(uint64_t) + dlen) { | |||||
mtx_unlock_spin(&rbr->rxbr_lock); | |||||
return (EAGAIN); | |||||
} | |||||
if (idx_adv > 0) { | |||||
/* | |||||
* Advance the read index first, including the channel's 64bit | |||||
* previous write offset. | |||||
*/ | |||||
rindex = VMBUS_BR_IDXINC(rbr->rxbr_rindex, | |||||
idx_adv + sizeof(uint64_t), br_dsize); | |||||
__compiler_membar(); | |||||
rbr->rxbr_rindex = rindex; | |||||
} | |||||
vmbus_rxbr_copyfrom(rbr, rbr->rxbr_rindex, data, dlen); | |||||
mtx_unlock_spin(&rbr->rxbr_lock); | |||||
return (0); | |||||
} | |||||
/* | |||||
* NOTE: | |||||
* Just update the RX rb index. | |||||
*/ | |||||
int | |||||
vmbus_rxbr_idxadv(struct vmbus_rxbr *rbr, uint32_t idx_adv) | |||||
{ | |||||
uint32_t rindex, br_dsize = rbr->rxbr_dsize; | |||||
mtx_lock_spin(&rbr->rxbr_lock); | |||||
/* | |||||
* Make sure it has enough space to advance. | |||||
*/ | |||||
if (vmbus_rxbr_avail(rbr) < idx_adv + sizeof(uint64_t)) { | |||||
mtx_unlock_spin(&rbr->rxbr_lock); | |||||
return (EAGAIN); | |||||
} | |||||
/* | |||||
* Advance the read index, including the channel's 64bit | |||||
* previous write offset. | |||||
*/ | |||||
rindex = VMBUS_BR_IDXINC(rbr->rxbr_rindex, | |||||
idx_adv + sizeof(uint64_t), br_dsize); | |||||
__compiler_membar(); | |||||
rbr->rxbr_rindex = rindex; | |||||
mtx_unlock_spin(&rbr->rxbr_lock); | |||||
return (0); | |||||
} | |||||
/* | |||||
* NOTE: | |||||
* We assume (dlen + skip) == sizeof(channel packet). | * We assume (dlen + skip) == sizeof(channel packet). | ||||
*/ | */ | ||||
int | int | ||||
Context not available. |