xref: /dpdk/drivers/bus/vmbus/vmbus_channel.c (revision e12a0166c80f65e35408f4715b2f3a60763c3741)
1831dba47SStephen Hemminger /* SPDX-License-Identifier: BSD-3-Clause
2831dba47SStephen Hemminger  * Copyright (c) 2018, Microsoft Corporation.
3831dba47SStephen Hemminger  * All Rights Reserved.
4831dba47SStephen Hemminger  */
5831dba47SStephen Hemminger 
6831dba47SStephen Hemminger #include <unistd.h>
7831dba47SStephen Hemminger #include <stdint.h>
8831dba47SStephen Hemminger #include <string.h>
9831dba47SStephen Hemminger #include <sys/uio.h>
10831dba47SStephen Hemminger 
11831dba47SStephen Hemminger #include <rte_eal.h>
12831dba47SStephen Hemminger #include <rte_tailq.h>
13831dba47SStephen Hemminger #include <rte_log.h>
14831dba47SStephen Hemminger #include <rte_malloc.h>
15831dba47SStephen Hemminger #include <rte_atomic.h>
16831dba47SStephen Hemminger #include <rte_memory.h>
17831dba47SStephen Hemminger #include <rte_bus_vmbus.h>
18831dba47SStephen Hemminger 
19831dba47SStephen Hemminger #include "private.h"
20831dba47SStephen Hemminger 
21831dba47SStephen Hemminger static inline void
vmbus_sync_set_bit(volatile RTE_ATOMIC (uint32_t)* addr,uint32_t mask)22*e12a0166STyler Retzlaff vmbus_sync_set_bit(volatile RTE_ATOMIC(uint32_t) *addr, uint32_t mask)
23831dba47SStephen Hemminger {
24*e12a0166STyler Retzlaff 	rte_atomic_fetch_or_explicit(addr, mask, rte_memory_order_seq_cst);
25831dba47SStephen Hemminger }
26831dba47SStephen Hemminger 
27831dba47SStephen Hemminger static inline void
vmbus_set_monitor(const struct vmbus_channel * channel,uint32_t monitor_id)287b1a614dSLong Li vmbus_set_monitor(const struct vmbus_channel *channel, uint32_t monitor_id)
29831dba47SStephen Hemminger {
30*e12a0166STyler Retzlaff 	RTE_ATOMIC(uint32_t) *monitor_addr;
31*e12a0166STyler Retzlaff 	uint32_t monitor_mask;
32831dba47SStephen Hemminger 	unsigned int trigger_index;
33831dba47SStephen Hemminger 
34831dba47SStephen Hemminger 	trigger_index = monitor_id / HV_MON_TRIG_LEN;
35831dba47SStephen Hemminger 	monitor_mask = 1u << (monitor_id % HV_MON_TRIG_LEN);
36831dba47SStephen Hemminger 
377b1a614dSLong Li 	monitor_addr = &channel->monitor_page->trigs[trigger_index].pending;
38831dba47SStephen Hemminger 	vmbus_sync_set_bit(monitor_addr, monitor_mask);
39831dba47SStephen Hemminger }
40831dba47SStephen Hemminger 
41831dba47SStephen Hemminger static void
vmbus_set_event(const struct vmbus_channel * chan)427b1a614dSLong Li vmbus_set_event(const struct vmbus_channel *chan)
43831dba47SStephen Hemminger {
447b1a614dSLong Li 	vmbus_set_monitor(chan, chan->monitor_id);
45831dba47SStephen Hemminger }
46831dba47SStephen Hemminger 
47831dba47SStephen Hemminger /*
489d071e5cSStephen Hemminger  * Set the wait between when hypervisor examines the trigger.
499d071e5cSStephen Hemminger  */
509d071e5cSStephen Hemminger void
rte_vmbus_set_latency(const struct rte_vmbus_device * dev,const struct vmbus_channel * chan,uint32_t latency)519d071e5cSStephen Hemminger rte_vmbus_set_latency(const struct rte_vmbus_device *dev,
529d071e5cSStephen Hemminger 		      const struct vmbus_channel *chan,
539d071e5cSStephen Hemminger 		      uint32_t latency)
549d071e5cSStephen Hemminger {
559d071e5cSStephen Hemminger 	uint32_t trig_idx = chan->monitor_id / VMBUS_MONTRIG_LEN;
569d071e5cSStephen Hemminger 	uint32_t trig_offs = chan->monitor_id % VMBUS_MONTRIG_LEN;
579d071e5cSStephen Hemminger 
589d071e5cSStephen Hemminger 	if (latency >= UINT16_MAX * 100) {
599d071e5cSStephen Hemminger 		VMBUS_LOG(ERR, "invalid latency value %u", latency);
609d071e5cSStephen Hemminger 		return;
619d071e5cSStephen Hemminger 	}
629d071e5cSStephen Hemminger 
639d071e5cSStephen Hemminger 	if (trig_idx >= VMBUS_MONTRIGS_MAX) {
649d071e5cSStephen Hemminger 		VMBUS_LOG(ERR, "invalid monitor trigger %u",
659d071e5cSStephen Hemminger 			  trig_idx);
669d071e5cSStephen Hemminger 		return;
679d071e5cSStephen Hemminger 	}
689d071e5cSStephen Hemminger 
699d071e5cSStephen Hemminger 	/* Host value is expressed in 100 nanosecond units */
709d071e5cSStephen Hemminger 	dev->monitor_page->lat[trig_idx][trig_offs] = latency / 100;
719d071e5cSStephen Hemminger }
729d071e5cSStephen Hemminger 
739d071e5cSStephen Hemminger /*
74831dba47SStephen Hemminger  * Notify host that there are data pending on our TX bufring.
75831dba47SStephen Hemminger  *
76831dba47SStephen Hemminger  * Since this in userspace, rely on the monitor page.
77831dba47SStephen Hemminger  * Can't do a hypercall from userspace.
78831dba47SStephen Hemminger  */
79831dba47SStephen Hemminger void
rte_vmbus_chan_signal_tx(const struct vmbus_channel * chan)80831dba47SStephen Hemminger rte_vmbus_chan_signal_tx(const struct vmbus_channel *chan)
81831dba47SStephen Hemminger {
82831dba47SStephen Hemminger 	const struct vmbus_br *tbr = &chan->txbr;
83831dba47SStephen Hemminger 
84831dba47SStephen Hemminger 	/* Make sure all updates are done before signaling host */
85831dba47SStephen Hemminger 	rte_smp_wmb();
86831dba47SStephen Hemminger 
87831dba47SStephen Hemminger 	/* If host is ignoring interrupts? */
88831dba47SStephen Hemminger 	if (tbr->vbr->imask)
89831dba47SStephen Hemminger 		return;
90831dba47SStephen Hemminger 
917b1a614dSLong Li 	vmbus_set_event(chan);
92831dba47SStephen Hemminger }
93831dba47SStephen Hemminger 
94831dba47SStephen Hemminger 
95831dba47SStephen Hemminger /* Do a simple send directly using transmit ring. */
rte_vmbus_chan_send(struct vmbus_channel * chan,uint16_t type,void * data,uint32_t dlen,uint64_t xactid,uint32_t flags,bool * need_sig)96831dba47SStephen Hemminger int rte_vmbus_chan_send(struct vmbus_channel *chan, uint16_t type,
97831dba47SStephen Hemminger 			void *data, uint32_t dlen,
98831dba47SStephen Hemminger 			uint64_t xactid, uint32_t flags, bool *need_sig)
99831dba47SStephen Hemminger {
100831dba47SStephen Hemminger 	struct vmbus_chanpkt pkt;
101831dba47SStephen Hemminger 	unsigned int pktlen, pad_pktlen;
102831dba47SStephen Hemminger 	const uint32_t hlen = sizeof(pkt);
103831dba47SStephen Hemminger 	bool send_evt = false;
104831dba47SStephen Hemminger 	uint64_t pad = 0;
105831dba47SStephen Hemminger 	struct iovec iov[3];
106831dba47SStephen Hemminger 	int error;
107831dba47SStephen Hemminger 
108831dba47SStephen Hemminger 	pktlen = hlen + dlen;
109831dba47SStephen Hemminger 	pad_pktlen = RTE_ALIGN(pktlen, sizeof(uint64_t));
110831dba47SStephen Hemminger 
111831dba47SStephen Hemminger 	pkt.hdr.type = type;
112831dba47SStephen Hemminger 	pkt.hdr.flags = flags;
113831dba47SStephen Hemminger 	pkt.hdr.hlen = hlen >> VMBUS_CHANPKT_SIZE_SHIFT;
114831dba47SStephen Hemminger 	pkt.hdr.tlen = pad_pktlen >> VMBUS_CHANPKT_SIZE_SHIFT;
115831dba47SStephen Hemminger 	pkt.hdr.xactid = xactid;
116831dba47SStephen Hemminger 
117831dba47SStephen Hemminger 	iov[0].iov_base = &pkt;
118831dba47SStephen Hemminger 	iov[0].iov_len = hlen;
119831dba47SStephen Hemminger 	iov[1].iov_base = data;
120831dba47SStephen Hemminger 	iov[1].iov_len = dlen;
121831dba47SStephen Hemminger 	iov[2].iov_base = &pad;
122831dba47SStephen Hemminger 	iov[2].iov_len = pad_pktlen - pktlen;
123831dba47SStephen Hemminger 
124831dba47SStephen Hemminger 	error = vmbus_txbr_write(&chan->txbr, iov, 3, &send_evt);
125831dba47SStephen Hemminger 
126831dba47SStephen Hemminger 	/*
127831dba47SStephen Hemminger 	 * caller sets need_sig to non-NULL if it will handle
128831dba47SStephen Hemminger 	 * signaling if required later.
129831dba47SStephen Hemminger 	 * if need_sig is NULL, signal now if needed.
130831dba47SStephen Hemminger 	 */
131831dba47SStephen Hemminger 	if (need_sig)
132831dba47SStephen Hemminger 		*need_sig |= send_evt;
133831dba47SStephen Hemminger 	else if (error == 0 && send_evt)
134831dba47SStephen Hemminger 		rte_vmbus_chan_signal_tx(chan);
135831dba47SStephen Hemminger 	return error;
136831dba47SStephen Hemminger }
137831dba47SStephen Hemminger 
138831dba47SStephen Hemminger /* Do a scatter/gather send where the descriptor points to data. */
rte_vmbus_chan_send_sglist(struct vmbus_channel * chan,struct vmbus_gpa sg[],uint32_t sglen,void * data,uint32_t dlen,uint64_t xactid,bool * need_sig)139831dba47SStephen Hemminger int rte_vmbus_chan_send_sglist(struct vmbus_channel *chan,
140831dba47SStephen Hemminger 			       struct vmbus_gpa sg[], uint32_t sglen,
141831dba47SStephen Hemminger 			       void *data, uint32_t dlen,
142831dba47SStephen Hemminger 			       uint64_t xactid, bool *need_sig)
143831dba47SStephen Hemminger {
144831dba47SStephen Hemminger 	struct vmbus_chanpkt_sglist pkt;
145831dba47SStephen Hemminger 	unsigned int pktlen, pad_pktlen, hlen;
146831dba47SStephen Hemminger 	bool send_evt = false;
147831dba47SStephen Hemminger 	struct iovec iov[4];
148831dba47SStephen Hemminger 	uint64_t pad = 0;
149831dba47SStephen Hemminger 	int error;
150831dba47SStephen Hemminger 
151831dba47SStephen Hemminger 	hlen = offsetof(struct vmbus_chanpkt_sglist, gpa[sglen]);
152831dba47SStephen Hemminger 	pktlen = hlen + dlen;
153831dba47SStephen Hemminger 	pad_pktlen = RTE_ALIGN(pktlen, sizeof(uint64_t));
154831dba47SStephen Hemminger 
155831dba47SStephen Hemminger 	pkt.hdr.type = VMBUS_CHANPKT_TYPE_GPA;
156831dba47SStephen Hemminger 	pkt.hdr.flags = VMBUS_CHANPKT_FLAG_RC;
157831dba47SStephen Hemminger 	pkt.hdr.hlen = hlen >> VMBUS_CHANPKT_SIZE_SHIFT;
158831dba47SStephen Hemminger 	pkt.hdr.tlen = pad_pktlen >> VMBUS_CHANPKT_SIZE_SHIFT;
159831dba47SStephen Hemminger 	pkt.hdr.xactid = xactid;
160831dba47SStephen Hemminger 	pkt.rsvd = 0;
161831dba47SStephen Hemminger 	pkt.gpa_cnt = sglen;
162831dba47SStephen Hemminger 
163831dba47SStephen Hemminger 	iov[0].iov_base = &pkt;
164831dba47SStephen Hemminger 	iov[0].iov_len = sizeof(pkt);
165831dba47SStephen Hemminger 	iov[1].iov_base = sg;
166831dba47SStephen Hemminger 	iov[1].iov_len = sizeof(struct vmbus_gpa) * sglen;
167831dba47SStephen Hemminger 	iov[2].iov_base = data;
168831dba47SStephen Hemminger 	iov[2].iov_len = dlen;
169831dba47SStephen Hemminger 	iov[3].iov_base = &pad;
170831dba47SStephen Hemminger 	iov[3].iov_len = pad_pktlen - pktlen;
171831dba47SStephen Hemminger 
172831dba47SStephen Hemminger 	error = vmbus_txbr_write(&chan->txbr, iov, 4, &send_evt);
173831dba47SStephen Hemminger 
174831dba47SStephen Hemminger 	/* if caller is batching, just propagate the status */
175831dba47SStephen Hemminger 	if (need_sig)
176831dba47SStephen Hemminger 		*need_sig |= send_evt;
177831dba47SStephen Hemminger 	else if (error == 0 && send_evt)
178831dba47SStephen Hemminger 		rte_vmbus_chan_signal_tx(chan);
179831dba47SStephen Hemminger 	return error;
180831dba47SStephen Hemminger }
181831dba47SStephen Hemminger 
rte_vmbus_chan_rx_empty(const struct vmbus_channel * channel)182831dba47SStephen Hemminger bool rte_vmbus_chan_rx_empty(const struct vmbus_channel *channel)
183831dba47SStephen Hemminger {
184831dba47SStephen Hemminger 	const struct vmbus_br *br = &channel->rxbr;
185831dba47SStephen Hemminger 
1861c33435aSStephen Hemminger 	rte_smp_rmb();
187831dba47SStephen Hemminger 	return br->vbr->rindex == br->vbr->windex;
188831dba47SStephen Hemminger }
189831dba47SStephen Hemminger 
190530af95aSStephen Hemminger /* Signal host after reading N bytes */
rte_vmbus_chan_signal_read(struct vmbus_channel * chan,uint32_t bytes_read)191530af95aSStephen Hemminger void rte_vmbus_chan_signal_read(struct vmbus_channel *chan, uint32_t bytes_read)
192831dba47SStephen Hemminger {
193831dba47SStephen Hemminger 	struct vmbus_br *rbr = &chan->rxbr;
194530af95aSStephen Hemminger 	uint32_t write_sz, pending_sz;
195831dba47SStephen Hemminger 
196831dba47SStephen Hemminger 	/* No need for signaling on older versions */
197831dba47SStephen Hemminger 	if (!rbr->vbr->feature_bits.feat_pending_send_sz)
198530af95aSStephen Hemminger 		return;
199831dba47SStephen Hemminger 
200831dba47SStephen Hemminger 	/* Make sure reading of pending happens after new read index */
20152c9a533SLong Li 	rte_smp_mb();
202831dba47SStephen Hemminger 
203831dba47SStephen Hemminger 	pending_sz = rbr->vbr->pending_send;
204831dba47SStephen Hemminger 	if (!pending_sz)
205530af95aSStephen Hemminger 		return;
206831dba47SStephen Hemminger 
207831dba47SStephen Hemminger 	rte_smp_rmb();
208831dba47SStephen Hemminger 	write_sz = vmbus_br_availwrite(rbr, rbr->vbr->windex);
209831dba47SStephen Hemminger 
210831dba47SStephen Hemminger 	/* If there was space before then host was not blocked */
211831dba47SStephen Hemminger 	if (write_sz - bytes_read > pending_sz)
212530af95aSStephen Hemminger 		return;
213831dba47SStephen Hemminger 
214831dba47SStephen Hemminger 	/* If pending write will not fit */
215831dba47SStephen Hemminger 	if (write_sz <= pending_sz)
216530af95aSStephen Hemminger 		return;
217831dba47SStephen Hemminger 
2187b1a614dSLong Li 	vmbus_set_event(chan);
219831dba47SStephen Hemminger }
220831dba47SStephen Hemminger 
rte_vmbus_chan_recv(struct vmbus_channel * chan,void * data,uint32_t * len,uint64_t * request_id)221831dba47SStephen Hemminger int rte_vmbus_chan_recv(struct vmbus_channel *chan, void *data, uint32_t *len,
222831dba47SStephen Hemminger 			uint64_t *request_id)
223831dba47SStephen Hemminger {
224831dba47SStephen Hemminger 	struct vmbus_chanpkt_hdr pkt;
225831dba47SStephen Hemminger 	uint32_t dlen, hlen, bufferlen = *len;
226831dba47SStephen Hemminger 	int error;
227831dba47SStephen Hemminger 
228831dba47SStephen Hemminger 	*len = 0;
229831dba47SStephen Hemminger 
230831dba47SStephen Hemminger 	error = vmbus_rxbr_peek(&chan->rxbr, &pkt, sizeof(pkt));
231831dba47SStephen Hemminger 	if (error)
232831dba47SStephen Hemminger 		return error;
233831dba47SStephen Hemminger 
234831dba47SStephen Hemminger 	if (unlikely(pkt.hlen < VMBUS_CHANPKT_HLEN_MIN)) {
235831dba47SStephen Hemminger 		VMBUS_LOG(ERR, "VMBUS recv, invalid hlen %u", pkt.hlen);
236831dba47SStephen Hemminger 		/* XXX this channel is dead actually. */
237831dba47SStephen Hemminger 		return -EIO;
238831dba47SStephen Hemminger 	}
239831dba47SStephen Hemminger 
240831dba47SStephen Hemminger 	if (unlikely(pkt.hlen > pkt.tlen)) {
241831dba47SStephen Hemminger 		VMBUS_LOG(ERR, "VMBUS recv,invalid hlen %u and tlen %u",
242831dba47SStephen Hemminger 			  pkt.hlen, pkt.tlen);
243831dba47SStephen Hemminger 		return -EIO;
244831dba47SStephen Hemminger 	}
245831dba47SStephen Hemminger 
246831dba47SStephen Hemminger 	/* Length are in quad words */
247831dba47SStephen Hemminger 	hlen = pkt.hlen << VMBUS_CHANPKT_SIZE_SHIFT;
248831dba47SStephen Hemminger 	dlen = (pkt.tlen << VMBUS_CHANPKT_SIZE_SHIFT) - hlen;
249831dba47SStephen Hemminger 	*len = dlen;
250831dba47SStephen Hemminger 
251831dba47SStephen Hemminger 	/* If caller buffer is not large enough */
252831dba47SStephen Hemminger 	if (unlikely(dlen > bufferlen))
253831dba47SStephen Hemminger 		return -ENOBUFS;
254831dba47SStephen Hemminger 
255831dba47SStephen Hemminger 	if (request_id)
256831dba47SStephen Hemminger 		*request_id = pkt.xactid;
257831dba47SStephen Hemminger 
258530af95aSStephen Hemminger 	/* Read data and skip packet header */
259530af95aSStephen Hemminger 	error = vmbus_rxbr_read(&chan->rxbr, data, dlen, hlen);
260530af95aSStephen Hemminger 	if (error)
261530af95aSStephen Hemminger 		return error;
262530af95aSStephen Hemminger 
263530af95aSStephen Hemminger 	rte_vmbus_chan_signal_read(chan, dlen + hlen + sizeof(uint64_t));
264530af95aSStephen Hemminger 	return 0;
265831dba47SStephen Hemminger }
266831dba47SStephen Hemminger 
267530af95aSStephen Hemminger /* TODO: replace this with inplace ring buffer (no copy) */
rte_vmbus_chan_recv_raw(struct vmbus_channel * chan,void * data,uint32_t * len)268831dba47SStephen Hemminger int rte_vmbus_chan_recv_raw(struct vmbus_channel *chan,
269831dba47SStephen Hemminger 			    void *data, uint32_t *len)
270831dba47SStephen Hemminger {
271831dba47SStephen Hemminger 	struct vmbus_chanpkt_hdr pkt;
272831dba47SStephen Hemminger 	uint32_t dlen, bufferlen = *len;
273831dba47SStephen Hemminger 	int error;
274831dba47SStephen Hemminger 
275831dba47SStephen Hemminger 	error = vmbus_rxbr_peek(&chan->rxbr, &pkt, sizeof(pkt));
276831dba47SStephen Hemminger 	if (error)
277831dba47SStephen Hemminger 		return error;
278831dba47SStephen Hemminger 
279831dba47SStephen Hemminger 	if (unlikely(pkt.hlen < VMBUS_CHANPKT_HLEN_MIN)) {
280831dba47SStephen Hemminger 		VMBUS_LOG(ERR, "VMBUS recv, invalid hlen %u", pkt.hlen);
281831dba47SStephen Hemminger 		/* XXX this channel is dead actually. */
282831dba47SStephen Hemminger 		return -EIO;
283831dba47SStephen Hemminger 	}
284831dba47SStephen Hemminger 
285831dba47SStephen Hemminger 	if (unlikely(pkt.hlen > pkt.tlen)) {
286831dba47SStephen Hemminger 		VMBUS_LOG(ERR, "VMBUS recv,invalid hlen %u and tlen %u",
287831dba47SStephen Hemminger 			pkt.hlen, pkt.tlen);
288831dba47SStephen Hemminger 		return -EIO;
289831dba47SStephen Hemminger 	}
290831dba47SStephen Hemminger 
291831dba47SStephen Hemminger 	/* Length are in quad words */
292831dba47SStephen Hemminger 	dlen = pkt.tlen << VMBUS_CHANPKT_SIZE_SHIFT;
293831dba47SStephen Hemminger 	*len = dlen;
294831dba47SStephen Hemminger 
295831dba47SStephen Hemminger 	/* If caller buffer is not large enough */
296831dba47SStephen Hemminger 	if (unlikely(dlen > bufferlen))
297831dba47SStephen Hemminger 		return -ENOBUFS;
298831dba47SStephen Hemminger 
299530af95aSStephen Hemminger 	/* Read data and skip packet header */
300530af95aSStephen Hemminger 	error = vmbus_rxbr_read(&chan->rxbr, data, dlen, 0);
301530af95aSStephen Hemminger 	if (error)
302530af95aSStephen Hemminger 		return error;
303530af95aSStephen Hemminger 
304530af95aSStephen Hemminger 	/* Return the number of bytes read */
305530af95aSStephen Hemminger 	return dlen + sizeof(uint64_t);
306831dba47SStephen Hemminger }
307831dba47SStephen Hemminger 
vmbus_chan_create(const struct rte_vmbus_device * device,uint16_t relid,uint16_t subid,uint8_t monitor_id,struct vmbus_channel ** new_chan)308831dba47SStephen Hemminger int vmbus_chan_create(const struct rte_vmbus_device *device,
309831dba47SStephen Hemminger 		      uint16_t relid, uint16_t subid, uint8_t monitor_id,
310831dba47SStephen Hemminger 		      struct vmbus_channel **new_chan)
311831dba47SStephen Hemminger {
312831dba47SStephen Hemminger 	struct vmbus_channel *chan;
313831dba47SStephen Hemminger 	int err;
314831dba47SStephen Hemminger 
315831dba47SStephen Hemminger 	chan = rte_zmalloc_socket("VMBUS", sizeof(*chan), RTE_CACHE_LINE_SIZE,
316831dba47SStephen Hemminger 				  device->device.numa_node);
317831dba47SStephen Hemminger 	if (!chan)
318831dba47SStephen Hemminger 		return -ENOMEM;
319831dba47SStephen Hemminger 
320831dba47SStephen Hemminger 	STAILQ_INIT(&chan->subchannel_list);
321831dba47SStephen Hemminger 	chan->device = device;
322831dba47SStephen Hemminger 	chan->subchannel_id = subid;
323831dba47SStephen Hemminger 	chan->relid = relid;
324831dba47SStephen Hemminger 	chan->monitor_id = monitor_id;
3257b1a614dSLong Li 	chan->monitor_page = device->monitor_page;
326831dba47SStephen Hemminger 	*new_chan = chan;
327831dba47SStephen Hemminger 
328831dba47SStephen Hemminger 	err = vmbus_uio_map_rings(chan);
329831dba47SStephen Hemminger 	if (err) {
330831dba47SStephen Hemminger 		rte_free(chan);
331831dba47SStephen Hemminger 		return err;
332831dba47SStephen Hemminger 	}
333831dba47SStephen Hemminger 
334831dba47SStephen Hemminger 	return 0;
335831dba47SStephen Hemminger }
336831dba47SStephen Hemminger 
337831dba47SStephen Hemminger /* Setup the primary channel */
rte_vmbus_chan_open(struct rte_vmbus_device * device,struct vmbus_channel ** new_chan)338831dba47SStephen Hemminger int rte_vmbus_chan_open(struct rte_vmbus_device *device,
339831dba47SStephen Hemminger 			struct vmbus_channel **new_chan)
340831dba47SStephen Hemminger {
3412a28a502SStephen Hemminger 	struct mapped_vmbus_resource *uio_res;
342831dba47SStephen Hemminger 	int err;
343831dba47SStephen Hemminger 
3442a28a502SStephen Hemminger 	uio_res = vmbus_uio_find_resource(device);
3452a28a502SStephen Hemminger 	if (!uio_res) {
3462a28a502SStephen Hemminger 		VMBUS_LOG(ERR, "can't find uio resource");
3472a28a502SStephen Hemminger 		return -EINVAL;
3482a28a502SStephen Hemminger 	}
3492a28a502SStephen Hemminger 
350831dba47SStephen Hemminger 	err = vmbus_chan_create(device, device->relid, 0,
351831dba47SStephen Hemminger 				device->monitor_id, new_chan);
35270cdd92eSLong Li 	if (!err)
353831dba47SStephen Hemminger 		device->primary = *new_chan;
354831dba47SStephen Hemminger 
355831dba47SStephen Hemminger 	return err;
356831dba47SStephen Hemminger }
357831dba47SStephen Hemminger 
rte_vmbus_max_channels(const struct rte_vmbus_device * device)358831dba47SStephen Hemminger int rte_vmbus_max_channels(const struct rte_vmbus_device *device)
359831dba47SStephen Hemminger {
360831dba47SStephen Hemminger 	if (vmbus_uio_subchannels_supported(device, device->primary))
361831dba47SStephen Hemminger 		return VMBUS_MAX_CHANNELS;
362831dba47SStephen Hemminger 	else
363831dba47SStephen Hemminger 		return 1;
364831dba47SStephen Hemminger }
365831dba47SStephen Hemminger 
366831dba47SStephen Hemminger /* Setup secondary channel */
rte_vmbus_subchan_open(struct vmbus_channel * primary,struct vmbus_channel ** new_chan)367831dba47SStephen Hemminger int rte_vmbus_subchan_open(struct vmbus_channel *primary,
368831dba47SStephen Hemminger 			   struct vmbus_channel **new_chan)
369831dba47SStephen Hemminger {
370831dba47SStephen Hemminger 	struct vmbus_channel *chan;
371831dba47SStephen Hemminger 	int err;
372831dba47SStephen Hemminger 
373831dba47SStephen Hemminger 	err = vmbus_uio_get_subchan(primary, &chan);
374831dba47SStephen Hemminger 	if (err)
375831dba47SStephen Hemminger 		return err;
376831dba47SStephen Hemminger 
377831dba47SStephen Hemminger 	STAILQ_INSERT_TAIL(&primary->subchannel_list, chan, next);
378831dba47SStephen Hemminger 	*new_chan = chan;
379831dba47SStephen Hemminger 	return 0;
380831dba47SStephen Hemminger }
381831dba47SStephen Hemminger 
rte_vmbus_sub_channel_index(const struct vmbus_channel * chan)382831dba47SStephen Hemminger uint16_t rte_vmbus_sub_channel_index(const struct vmbus_channel *chan)
383831dba47SStephen Hemminger {
384831dba47SStephen Hemminger 	return chan->subchannel_id;
385831dba47SStephen Hemminger }
386831dba47SStephen Hemminger 
rte_vmbus_chan_close(struct vmbus_channel * chan)387831dba47SStephen Hemminger void rte_vmbus_chan_close(struct vmbus_channel *chan)
388831dba47SStephen Hemminger {
389831dba47SStephen Hemminger 	const struct rte_vmbus_device *device = chan->device;
390831dba47SStephen Hemminger 	struct vmbus_channel *primary = device->primary;
391831dba47SStephen Hemminger 
3922a28a502SStephen Hemminger 	/*
3932a28a502SStephen Hemminger 	 * intentionally leak primary channel because
3942a28a502SStephen Hemminger 	 * secondary may still reference it
3952a28a502SStephen Hemminger 	 */
3962a28a502SStephen Hemminger 	if (chan != primary) {
397831dba47SStephen Hemminger 		STAILQ_REMOVE(&primary->subchannel_list, chan,
398831dba47SStephen Hemminger 			      vmbus_channel, next);
399831dba47SStephen Hemminger 		rte_free(chan);
400831dba47SStephen Hemminger 	}
401831dba47SStephen Hemminger 
4022a28a502SStephen Hemminger }
4032a28a502SStephen Hemminger 
vmbus_dump_ring(FILE * f,const char * id,const struct vmbus_br * br)404831dba47SStephen Hemminger static void vmbus_dump_ring(FILE *f, const char *id, const struct vmbus_br *br)
405831dba47SStephen Hemminger {
406831dba47SStephen Hemminger 	const struct vmbus_bufring *vbr = br->vbr;
407831dba47SStephen Hemminger 	struct vmbus_chanpkt_hdr pkt;
408831dba47SStephen Hemminger 
409831dba47SStephen Hemminger 	fprintf(f, "%s windex=%u rindex=%u mask=%u pending=%u feature=%#x\n",
410831dba47SStephen Hemminger 		id, vbr->windex, vbr->rindex, vbr->imask,
411831dba47SStephen Hemminger 		vbr->pending_send, vbr->feature_bits.value);
412831dba47SStephen Hemminger 	fprintf(f, " size=%u avail write=%u read=%u\n",
413831dba47SStephen Hemminger 		br->dsize, vmbus_br_availwrite(br, vbr->windex),
414831dba47SStephen Hemminger 		vmbus_br_availread(br));
415831dba47SStephen Hemminger 
416831dba47SStephen Hemminger 	if (vmbus_rxbr_peek(br, &pkt, sizeof(pkt)) == 0)
417831dba47SStephen Hemminger 		fprintf(f, "  pkt type %#x len %u flags %#x xactid %#"PRIx64"\n",
418831dba47SStephen Hemminger 			pkt.type,
419831dba47SStephen Hemminger 			pkt.tlen << VMBUS_CHANPKT_SIZE_SHIFT,
420831dba47SStephen Hemminger 			pkt.flags, pkt.xactid);
421831dba47SStephen Hemminger }
422831dba47SStephen Hemminger 
rte_vmbus_chan_dump(FILE * f,const struct vmbus_channel * chan)423831dba47SStephen Hemminger void rte_vmbus_chan_dump(FILE *f, const struct vmbus_channel *chan)
424831dba47SStephen Hemminger {
425831dba47SStephen Hemminger 	fprintf(f, "channel[%u] relid=%u monitor=%u\n",
426831dba47SStephen Hemminger 		chan->subchannel_id, chan->relid, chan->monitor_id);
427831dba47SStephen Hemminger 	vmbus_dump_ring(f, "rxbr", &chan->rxbr);
428831dba47SStephen Hemminger 	vmbus_dump_ring(f, "txbr", &chan->txbr);
429831dba47SStephen Hemminger }
430