vmbus_set_monitor(dev, chan->monitor_id);
}
+/*
+ * Set the wait between when hypervisor examines the trigger.
+ */
+void
+rte_vmbus_set_latency(const struct rte_vmbus_device *dev,
+ const struct vmbus_channel *chan,
+ uint32_t latency)
+{
+ uint32_t trig_idx = chan->monitor_id / VMBUS_MONTRIG_LEN;
+ uint32_t trig_offs = chan->monitor_id % VMBUS_MONTRIG_LEN;
+
+ if (latency >= UINT16_MAX * 100) {
+ VMBUS_LOG(ERR, "invalid latency value %u", latency);
+ return;
+ }
+
+ if (trig_idx >= VMBUS_MONTRIGS_MAX) {
+ VMBUS_LOG(ERR, "invalid monitor trigger %u",
+ trig_idx);
+ return;
+ }
+
+ /* Host value is expressed in 100 nanosecond units */
+ dev->monitor_page->lat[trig_idx][trig_offs] = latency / 100;
+}
+
/*
* Notify host that there are data pending on our TX bufring.
*
return br->vbr->rindex == br->vbr->windex;
}
-static int vmbus_read_and_signal(struct vmbus_channel *chan,
- void *data, size_t dlen, size_t skip)
+/* Signal host after reading N bytes */
+void rte_vmbus_chan_signal_read(struct vmbus_channel *chan, uint32_t bytes_read)
{
struct vmbus_br *rbr = &chan->rxbr;
- uint32_t write_sz, pending_sz, bytes_read;
- int error;
-
- /* Record where host was when we started read (for debug) */
- rbr->windex = rbr->vbr->windex;
-
- /* Read data and skip packet header */
- error = vmbus_rxbr_read(rbr, data, dlen, skip);
- if (error)
- return error;
+ uint32_t write_sz, pending_sz;
/* No need for signaling on older versions */
if (!rbr->vbr->feature_bits.feat_pending_send_sz)
- return 0;
+ return;
/* Make sure reading of pending happens after new read index */
rte_mb();
pending_sz = rbr->vbr->pending_send;
if (!pending_sz)
- return 0;
+ return;
rte_smp_rmb();
write_sz = vmbus_br_availwrite(rbr, rbr->vbr->windex);
- bytes_read = dlen + skip + sizeof(uint64_t);
/* If there was space before then host was not blocked */
if (write_sz - bytes_read > pending_sz)
- return 0;
+ return;
/* If pending write will not fit */
if (write_sz <= pending_sz)
- return 0;
+ return;
vmbus_set_event(chan->device, chan);
- return 0;
}
-/* TODO: replace this with inplace ring buffer (no copy) */
int rte_vmbus_chan_recv(struct vmbus_channel *chan, void *data, uint32_t *len,
uint64_t *request_id)
{
if (request_id)
*request_id = pkt.xactid;
- /* Read data and skip the header */
- return vmbus_read_and_signal(chan, data, dlen, hlen);
+ /* Read data and skip packet header */
+ error = vmbus_rxbr_read(&chan->rxbr, data, dlen, hlen);
+ if (error)
+ return error;
+
+ rte_vmbus_chan_signal_read(chan, dlen + hlen + sizeof(uint64_t));
+ return 0;
}
+/* TODO: replace this with inplace ring buffer (no copy) */
int rte_vmbus_chan_recv_raw(struct vmbus_channel *chan,
void *data, uint32_t *len)
{
if (unlikely(dlen > bufferlen))
return -ENOBUFS;
- /* Put packet header in data buffer */
- return vmbus_read_and_signal(chan, data, dlen, 0);
+ /* Read data and skip packet header */
+ error = vmbus_rxbr_read(&chan->rxbr, data, dlen, 0);
+ if (error)
+ return error;
+
+ /* Return the number of bytes read */
+ return dlen + sizeof(uint64_t);
}
int vmbus_chan_create(const struct rte_vmbus_device *device,
int rte_vmbus_chan_open(struct rte_vmbus_device *device,
struct vmbus_channel **new_chan)
{
+ struct mapped_vmbus_resource *uio_res;
int err;
+ uio_res = vmbus_uio_find_resource(device);
+ if (!uio_res) {
+ VMBUS_LOG(ERR, "can't find uio resource");
+ return -EINVAL;
+ }
+
err = vmbus_chan_create(device, device->relid, 0,
device->monitor_id, new_chan);
- if (!err)
+ if (!err) {
device->primary = *new_chan;
+ uio_res->primary = *new_chan;
+ }
return err;
}
const struct rte_vmbus_device *device = chan->device;
struct vmbus_channel *primary = device->primary;
- if (chan != primary)
+ /*
+ * intentionally leak primary channel because
+ * secondary may still reference it
+ */
+ if (chan != primary) {
STAILQ_REMOVE(&primary->subchannel_list, chan,
vmbus_channel, next);
+ rte_free(chan);
+ }
- rte_free(chan);
}
static void vmbus_dump_ring(FILE *f, const char *id, const struct vmbus_br *br)