X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fbus%2Fvmbus%2Fvmbus_channel.c;h=119b9b367e1701dd066135ef98b999af9d47f185;hb=a5a0a43bc62ed5c735ae482dbc4d8a7af4b95eab;hp=f9feada9b047368ad319332870fd88c4ac2bbc59;hpb=831dba47bd365b8a539dfb51fffdd01f8a436f6c;p=dpdk.git diff --git a/drivers/bus/vmbus/vmbus_channel.c b/drivers/bus/vmbus/vmbus_channel.c index f9feada9b0..119b9b367e 100644 --- a/drivers/bus/vmbus/vmbus_channel.c +++ b/drivers/bus/vmbus/vmbus_channel.c @@ -26,18 +26,6 @@ vmbus_sync_set_bit(volatile uint32_t *addr, uint32_t mask) __sync_or_and_fetch(addr, mask); } -static inline void -vmbus_send_interrupt(const struct rte_vmbus_device *dev, uint32_t relid) -{ - uint32_t *int_addr; - uint32_t int_mask; - - int_addr = dev->int_page + relid / 32; - int_mask = 1u << (relid % 32); - - vmbus_sync_set_bit(int_addr, int_mask); -} - static inline void vmbus_set_monitor(const struct rte_vmbus_device *dev, uint32_t monitor_id) { @@ -55,10 +43,35 @@ static void vmbus_set_event(const struct rte_vmbus_device *dev, const struct vmbus_channel *chan) { - vmbus_send_interrupt(dev, chan->relid); 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. * @@ -173,52 +186,41 @@ bool rte_vmbus_chan_rx_empty(const struct vmbus_channel *channel) { const struct vmbus_br *br = &channel->rxbr; + rte_smp_rmb(); 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(); + rte_smp_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) { @@ -256,10 +258,16 @@ int rte_vmbus_chan_recv(struct vmbus_channel *chan, void *data, uint32_t *len, 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) { @@ -291,8 +299,13 @@ int rte_vmbus_chan_recv_raw(struct vmbus_channel *chan, 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, @@ -327,8 +340,15 @@ 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) @@ -371,11 +391,16 @@ void rte_vmbus_chan_close(struct vmbus_channel *chan) 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)