xref: /openbsd/sys/arch/sparc64/dev/ldc.c (revision 6c66ff3a)
1*6c66ff3aStom /*	$OpenBSD: ldc.c,v 1.14 2016/10/13 18:40:47 tom Exp $	*/
2d9889caeSkettenis /*
3d9889caeSkettenis  * Copyright (c) 2009 Mark Kettenis
4d9889caeSkettenis  *
5d9889caeSkettenis  * Permission to use, copy, modify, and distribute this software for any
6d9889caeSkettenis  * purpose with or without fee is hereby granted, provided that the above
7d9889caeSkettenis  * copyright notice and this permission notice appear in all copies.
8d9889caeSkettenis  *
9d9889caeSkettenis  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10d9889caeSkettenis  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11d9889caeSkettenis  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12d9889caeSkettenis  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13d9889caeSkettenis  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14d9889caeSkettenis  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15d9889caeSkettenis  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16d9889caeSkettenis  */
17d9889caeSkettenis 
18d9889caeSkettenis #include <sys/param.h>
19d9889caeSkettenis #include <sys/malloc.h>
20d9889caeSkettenis #include <sys/systm.h>
21d9889caeSkettenis 
22d9889caeSkettenis #include <machine/bus.h>
23d9889caeSkettenis #include <machine/hypervisor.h>
24d9889caeSkettenis 
25d9889caeSkettenis #include <sparc64/dev/ldcvar.h>
26d9889caeSkettenis 
27d9889caeSkettenis #ifdef LDC_DEBUG
28d9889caeSkettenis #define DPRINTF(x)	printf x
29d9889caeSkettenis #else
30d9889caeSkettenis #define DPRINTF(x)
31d9889caeSkettenis #endif
32d9889caeSkettenis 
33d9889caeSkettenis void	ldc_rx_ctrl_vers(struct ldc_conn *, struct ldc_pkt *);
34d9889caeSkettenis void	ldc_rx_ctrl_rtr(struct ldc_conn *, struct ldc_pkt *);
35d9889caeSkettenis void	ldc_rx_ctrl_rts(struct ldc_conn *, struct ldc_pkt *);
3612668c27Skettenis void	ldc_rx_ctrl_rdx(struct ldc_conn *, struct ldc_pkt *);
37d9889caeSkettenis 
3812668c27Skettenis void	ldc_send_ack(struct ldc_conn *);
39d9889caeSkettenis void	ldc_send_rtr(struct ldc_conn *);
40d9889caeSkettenis void	ldc_send_rts(struct ldc_conn *);
41d9889caeSkettenis void	ldc_send_rdx(struct ldc_conn *);
42d9889caeSkettenis 
43d9889caeSkettenis void
ldc_rx_ctrl(struct ldc_conn * lc,struct ldc_pkt * lp)44d9889caeSkettenis ldc_rx_ctrl(struct ldc_conn *lc, struct ldc_pkt *lp)
45d9889caeSkettenis {
46d9889caeSkettenis 	switch (lp->ctrl) {
47d9889caeSkettenis 	case LDC_VERS:
48d9889caeSkettenis 		ldc_rx_ctrl_vers(lc, lp);
49d9889caeSkettenis 		break;
50d9889caeSkettenis 
51d9889caeSkettenis 	case LDC_RTS:
52d9889caeSkettenis 		ldc_rx_ctrl_rts(lc, lp);
53d9889caeSkettenis 		break;
54d9889caeSkettenis 
55d9889caeSkettenis 	case LDC_RTR:
56d9889caeSkettenis 		ldc_rx_ctrl_rtr(lc, lp);
57d9889caeSkettenis 		break;
58d9889caeSkettenis 
5912668c27Skettenis 	case LDC_RDX:
6012668c27Skettenis 		ldc_rx_ctrl_rdx(lc, lp);
6112668c27Skettenis 		break;
6212668c27Skettenis 
63d9889caeSkettenis 	default:
64d9889caeSkettenis 		DPRINTF(("CTRL/0x%02x/0x%02x\n", lp->stype, lp->ctrl));
65d9889caeSkettenis 		ldc_reset(lc);
66d9889caeSkettenis 		break;
67d9889caeSkettenis 	}
68d9889caeSkettenis }
69d9889caeSkettenis 
70d9889caeSkettenis void
ldc_rx_ctrl_vers(struct ldc_conn * lc,struct ldc_pkt * lp)71d9889caeSkettenis ldc_rx_ctrl_vers(struct ldc_conn *lc, struct ldc_pkt *lp)
72d9889caeSkettenis {
73d9889caeSkettenis 	switch (lp->stype) {
74d9889caeSkettenis 	case LDC_INFO:
75b27564dcSkettenis 		DPRINTF(("CTRL/INFO/VERS\n"));
7662d37fceSkettenis 		if (lp->major == LDC_VERSION_MAJOR &&
7762d37fceSkettenis 		    lp->minor == LDC_VERSION_MINOR)
7862d37fceSkettenis 			ldc_send_ack(lc);
7962d37fceSkettenis 		else
80d9889caeSkettenis 			/* XXX do nothing for now. */
81cd6eff39Skettenis 			;
82d9889caeSkettenis 		break;
83d9889caeSkettenis 
84d9889caeSkettenis 	case LDC_ACK:
85d9889caeSkettenis 		if (lc->lc_state != LDC_SND_VERS) {
86d9889caeSkettenis 			DPRINTF(("Spurious CTRL/ACK/VERS: state %d\n",
87d9889caeSkettenis 			    lc->lc_state));
88d9889caeSkettenis 			ldc_reset(lc);
89d9889caeSkettenis 			return;
90d9889caeSkettenis 		}
91d9889caeSkettenis 		DPRINTF(("CTRL/ACK/VERS\n"));
92d9889caeSkettenis 		ldc_send_rts(lc);
93d9889caeSkettenis 		break;
94d9889caeSkettenis 
95d9889caeSkettenis 	case LDC_NACK:
96d9889caeSkettenis 		DPRINTF(("CTRL/NACK/VERS\n"));
97d9889caeSkettenis 		ldc_reset(lc);
98d9889caeSkettenis 		break;
99d9889caeSkettenis 
100d9889caeSkettenis 	default:
101d9889caeSkettenis 		DPRINTF(("CTRL/0x%02x/VERS\n", lp->stype));
102d9889caeSkettenis 		ldc_reset(lc);
103d9889caeSkettenis 		break;
104d9889caeSkettenis 	}
105d9889caeSkettenis }
106d9889caeSkettenis 
107d9889caeSkettenis void
ldc_rx_ctrl_rts(struct ldc_conn * lc,struct ldc_pkt * lp)108d9889caeSkettenis ldc_rx_ctrl_rts(struct ldc_conn *lc, struct ldc_pkt *lp)
109d9889caeSkettenis {
110d9889caeSkettenis 	switch (lp->stype) {
111d9889caeSkettenis 	case LDC_INFO:
112d9889caeSkettenis 		if (lc->lc_state != LDC_RCV_VERS) {
113f8d292b7Skettenis 			DPRINTF(("Spurious CTRL/INFO/RTS: state %d\n",
114d9889caeSkettenis 			    lc->lc_state));
115d9889caeSkettenis 			ldc_reset(lc);
116d9889caeSkettenis 			return;
117d9889caeSkettenis 		}
118d9889caeSkettenis 		DPRINTF(("CTRL/INFO/RTS\n"));
119d9889caeSkettenis 		ldc_send_rtr(lc);
120d9889caeSkettenis 		break;
121d9889caeSkettenis 
122d9889caeSkettenis 	case LDC_ACK:
123d9889caeSkettenis 		DPRINTF(("CTRL/ACK/RTS\n"));
124d9889caeSkettenis 		ldc_reset(lc);
125d9889caeSkettenis 		break;
126d9889caeSkettenis 
127d9889caeSkettenis 	case LDC_NACK:
128d9889caeSkettenis 		DPRINTF(("CTRL/NACK/RTS\n"));
129d9889caeSkettenis 		ldc_reset(lc);
130d9889caeSkettenis 		break;
131d9889caeSkettenis 
132d9889caeSkettenis 	default:
133d9889caeSkettenis 		DPRINTF(("CTRL/0x%02x/RTS\n", lp->stype));
134d9889caeSkettenis 		ldc_reset(lc);
135d9889caeSkettenis 		break;
136d9889caeSkettenis 	}
137d9889caeSkettenis }
138d9889caeSkettenis 
139d9889caeSkettenis void
ldc_rx_ctrl_rtr(struct ldc_conn * lc,struct ldc_pkt * lp)140d9889caeSkettenis ldc_rx_ctrl_rtr(struct ldc_conn *lc, struct ldc_pkt *lp)
141d9889caeSkettenis {
142d9889caeSkettenis 	switch (lp->stype) {
143d9889caeSkettenis 	case LDC_INFO:
144d9889caeSkettenis 		if (lc->lc_state != LDC_SND_RTS) {
145d9889caeSkettenis 			DPRINTF(("Spurious CTRL/INFO/RTR: state %d\n",
146d9889caeSkettenis 			    lc->lc_state));
147d9889caeSkettenis 			ldc_reset(lc);
148d9889caeSkettenis 			return;
149d9889caeSkettenis 		}
150d9889caeSkettenis 		DPRINTF(("CTRL/INFO/RTR\n"));
151d9889caeSkettenis 		ldc_send_rdx(lc);
152401f82beSkettenis 		lc->lc_start(lc);
153d9889caeSkettenis 		break;
154d9889caeSkettenis 
155d9889caeSkettenis 	case LDC_ACK:
156d9889caeSkettenis 		DPRINTF(("CTRL/ACK/RTR\n"));
157d9889caeSkettenis 		ldc_reset(lc);
158d9889caeSkettenis 		break;
159d9889caeSkettenis 
160d9889caeSkettenis 	case LDC_NACK:
161d9889caeSkettenis 		DPRINTF(("CTRL/NACK/RTR\n"));
162d9889caeSkettenis 		ldc_reset(lc);
163d9889caeSkettenis 		break;
164d9889caeSkettenis 
165d9889caeSkettenis 	default:
166d9889caeSkettenis 		DPRINTF(("CTRL/0x%02x/RTR\n", lp->stype));
167d9889caeSkettenis 		ldc_reset(lc);
168d9889caeSkettenis 		break;
169d9889caeSkettenis 	}
170d9889caeSkettenis }
171d9889caeSkettenis 
172d9889caeSkettenis void
ldc_rx_ctrl_rdx(struct ldc_conn * lc,struct ldc_pkt * lp)17312668c27Skettenis ldc_rx_ctrl_rdx(struct ldc_conn *lc, struct ldc_pkt *lp)
17412668c27Skettenis {
17512668c27Skettenis 	switch (lp->stype) {
17612668c27Skettenis 	case LDC_INFO:
17712668c27Skettenis 		if (lc->lc_state != LDC_SND_RTR) {
17812668c27Skettenis 			DPRINTF(("Spurious CTRL/INFO/RTR: state %d\n",
17912668c27Skettenis 			    lc->lc_state));
18012668c27Skettenis 			ldc_reset(lc);
18112668c27Skettenis 			return;
18212668c27Skettenis 		}
18312668c27Skettenis 		DPRINTF(("CTRL/INFO/RDX\n"));
18412668c27Skettenis 		lc->lc_start(lc);
18512668c27Skettenis 		break;
18612668c27Skettenis 
18712668c27Skettenis 	case LDC_ACK:
18812668c27Skettenis 		DPRINTF(("CTRL/ACK/RDX\n"));
18912668c27Skettenis 		ldc_reset(lc);
19012668c27Skettenis 		break;
19112668c27Skettenis 
19212668c27Skettenis 	case LDC_NACK:
19312668c27Skettenis 		DPRINTF(("CTRL/NACK/RDX\n"));
19412668c27Skettenis 		ldc_reset(lc);
19512668c27Skettenis 		break;
19612668c27Skettenis 
19712668c27Skettenis 	default:
19812668c27Skettenis 		DPRINTF(("CTRL/0x%02x/RDX\n", lp->stype));
19912668c27Skettenis 		ldc_reset(lc);
20012668c27Skettenis 		break;
20112668c27Skettenis 	}
20212668c27Skettenis }
20312668c27Skettenis 
20412668c27Skettenis void
ldc_rx_data(struct ldc_conn * lc,struct ldc_pkt * lp)205d9889caeSkettenis ldc_rx_data(struct ldc_conn *lc, struct ldc_pkt *lp)
206d9889caeSkettenis {
207b27564dcSkettenis 	size_t len;
208b27564dcSkettenis 
209d9889caeSkettenis 	if (lp->stype != LDC_INFO) {
210d9889caeSkettenis 		DPRINTF(("DATA/0x%02x\n", lp->stype));
211d9889caeSkettenis 		ldc_reset(lc);
212d9889caeSkettenis 		return;
213d9889caeSkettenis 	}
214d9889caeSkettenis 
215d9889caeSkettenis 	if (lc->lc_state != LDC_SND_RTR &&
216d9889caeSkettenis 	    lc->lc_state != LDC_SND_RDX) {
217d9889caeSkettenis 		DPRINTF(("Spurious DATA/INFO: state %d\n", lc->lc_state));
218d9889caeSkettenis 		ldc_reset(lc);
219d9889caeSkettenis 		return;
220d9889caeSkettenis 	}
221d9889caeSkettenis 
222b27564dcSkettenis 	if (lp->env & LDC_FRAG_START) {
223b27564dcSkettenis 		lc->lc_len = (lp->env & LDC_LEN_MASK) + 8;
224b27564dcSkettenis 		KASSERT(lc->lc_len <= sizeof(lc->lc_msg));
225b27564dcSkettenis 		memcpy((uint8_t *)lc->lc_msg, lp, lc->lc_len);
226b27564dcSkettenis 	} else {
227b27564dcSkettenis 		len = (lp->env & LDC_LEN_MASK);
228b27564dcSkettenis 		if (lc->lc_len + len > sizeof(lc->lc_msg)) {
229b27564dcSkettenis 			DPRINTF(("Buffer overrun\n"));
230b27564dcSkettenis 			ldc_reset(lc);
231b27564dcSkettenis 			return;
232b27564dcSkettenis 		}
233b27564dcSkettenis 		memcpy(((uint8_t *)lc->lc_msg) + lc->lc_len, &lp->major, len);
234b27564dcSkettenis 		lc->lc_len += len;
235b27564dcSkettenis 	}
236b27564dcSkettenis 
237b27564dcSkettenis 	if (lp->env & LDC_FRAG_STOP)
238b27564dcSkettenis 		lc->lc_rx_data(lc, (struct ldc_pkt *)lc->lc_msg);
239d9889caeSkettenis }
240d9889caeSkettenis 
241d9889caeSkettenis void
ldc_send_vers(struct ldc_conn * lc)242d9889caeSkettenis ldc_send_vers(struct ldc_conn *lc)
243d9889caeSkettenis {
244d9889caeSkettenis 	struct ldc_pkt *lp;
245d9889caeSkettenis 	uint64_t tx_head, tx_tail, tx_state;
246d9889caeSkettenis 	int err;
247d9889caeSkettenis 
248678c28a9Skettenis 	mtx_enter(&lc->lc_txq->lq_mtx);
249d9889caeSkettenis 	err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
250678c28a9Skettenis 	if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
251678c28a9Skettenis 		mtx_leave(&lc->lc_txq->lq_mtx);
252d9889caeSkettenis 		return;
253678c28a9Skettenis 	}
254d9889caeSkettenis 
255d9889caeSkettenis 	lp = (struct ldc_pkt *)(lc->lc_txq->lq_va + tx_tail);
256d9889caeSkettenis 	bzero(lp, sizeof(struct ldc_pkt));
257d9889caeSkettenis 	lp->type = LDC_CTRL;
258d9889caeSkettenis 	lp->stype = LDC_INFO;
259d9889caeSkettenis 	lp->ctrl = LDC_VERS;
260d9889caeSkettenis 	lp->major = 1;
261d9889caeSkettenis 	lp->minor = 0;
262d9889caeSkettenis 
263d9889caeSkettenis 	tx_tail += sizeof(*lp);
264d9889caeSkettenis 	tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
265d9889caeSkettenis 	err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
266d9889caeSkettenis 	if (err != H_EOK) {
267d9889caeSkettenis 		printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
268678c28a9Skettenis 		mtx_leave(&lc->lc_txq->lq_mtx);
269d9889caeSkettenis 		return;
270d9889caeSkettenis 	}
271d9889caeSkettenis 
272d9889caeSkettenis 	lc->lc_state = LDC_SND_VERS;
273678c28a9Skettenis 	mtx_leave(&lc->lc_txq->lq_mtx);
274d9889caeSkettenis }
275d9889caeSkettenis 
276d9889caeSkettenis void
ldc_send_ack(struct ldc_conn * lc)27712668c27Skettenis ldc_send_ack(struct ldc_conn *lc)
27812668c27Skettenis {
27912668c27Skettenis 	struct ldc_pkt *lp;
28012668c27Skettenis 	uint64_t tx_head, tx_tail, tx_state;
28112668c27Skettenis 	int err;
28212668c27Skettenis 
283678c28a9Skettenis 	mtx_enter(&lc->lc_txq->lq_mtx);
28412668c27Skettenis 	err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
285678c28a9Skettenis 	if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
286678c28a9Skettenis 		mtx_leave(&lc->lc_txq->lq_mtx);
28712668c27Skettenis 		return;
288678c28a9Skettenis 	}
28912668c27Skettenis 
29012668c27Skettenis 	lp = (struct ldc_pkt *)(lc->lc_txq->lq_va + tx_tail);
29112668c27Skettenis 	bzero(lp, sizeof(struct ldc_pkt));
29212668c27Skettenis 	lp->type = LDC_CTRL;
29312668c27Skettenis 	lp->stype = LDC_ACK;
29412668c27Skettenis 	lp->ctrl = LDC_VERS;
29512668c27Skettenis 	lp->major = 1;
29612668c27Skettenis 	lp->minor = 0;
29712668c27Skettenis 
29812668c27Skettenis 	tx_tail += sizeof(*lp);
29912668c27Skettenis 	tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
30012668c27Skettenis 	err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
30112668c27Skettenis 	if (err != H_EOK) {
30212668c27Skettenis 		printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
303678c28a9Skettenis 		mtx_leave(&lc->lc_txq->lq_mtx);
30412668c27Skettenis 		return;
30512668c27Skettenis 	}
30612668c27Skettenis 
30712668c27Skettenis 	lc->lc_state = LDC_RCV_VERS;
308678c28a9Skettenis 	mtx_leave(&lc->lc_txq->lq_mtx);
30912668c27Skettenis }
31012668c27Skettenis 
31112668c27Skettenis void
ldc_send_rts(struct ldc_conn * lc)312d9889caeSkettenis ldc_send_rts(struct ldc_conn *lc)
313d9889caeSkettenis {
314d9889caeSkettenis 	struct ldc_pkt *lp;
315d9889caeSkettenis 	uint64_t tx_head, tx_tail, tx_state;
316d9889caeSkettenis 	int err;
317d9889caeSkettenis 
318678c28a9Skettenis 	mtx_enter(&lc->lc_txq->lq_mtx);
319d9889caeSkettenis 	err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
320678c28a9Skettenis 	if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
321678c28a9Skettenis 		mtx_leave(&lc->lc_txq->lq_mtx);
322d9889caeSkettenis 		return;
323678c28a9Skettenis 	}
324d9889caeSkettenis 
325d9889caeSkettenis 	lp = (struct ldc_pkt *)(lc->lc_txq->lq_va + tx_tail);
326d9889caeSkettenis 	bzero(lp, sizeof(struct ldc_pkt));
327d9889caeSkettenis 	lp->type = LDC_CTRL;
328d9889caeSkettenis 	lp->stype = LDC_INFO;
329d9889caeSkettenis 	lp->ctrl = LDC_RTS;
330d9889caeSkettenis 	lp->env = LDC_MODE_UNRELIABLE;
331d9889caeSkettenis 	lp->seqid = lc->lc_tx_seqid++;
332d9889caeSkettenis 
333d9889caeSkettenis 	tx_tail += sizeof(*lp);
334d9889caeSkettenis 	tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
335d9889caeSkettenis 	err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
336d9889caeSkettenis 	if (err != H_EOK) {
337d9889caeSkettenis 		printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
338678c28a9Skettenis 		mtx_leave(&lc->lc_txq->lq_mtx);
339d9889caeSkettenis 		return;
340d9889caeSkettenis 	}
341d9889caeSkettenis 
342d9889caeSkettenis 	lc->lc_state = LDC_SND_RTS;
343678c28a9Skettenis 	mtx_leave(&lc->lc_txq->lq_mtx);
344d9889caeSkettenis }
345d9889caeSkettenis 
346d9889caeSkettenis void
ldc_send_rtr(struct ldc_conn * lc)347d9889caeSkettenis ldc_send_rtr(struct ldc_conn *lc)
348d9889caeSkettenis {
349d9889caeSkettenis 	struct ldc_pkt *lp;
350d9889caeSkettenis 	uint64_t tx_head, tx_tail, tx_state;
351d9889caeSkettenis 	int err;
352d9889caeSkettenis 
353678c28a9Skettenis 	mtx_enter(&lc->lc_txq->lq_mtx);
354d9889caeSkettenis 	err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
355678c28a9Skettenis 	if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
356678c28a9Skettenis 		mtx_leave(&lc->lc_txq->lq_mtx);
357d9889caeSkettenis 		return;
358678c28a9Skettenis 	}
359d9889caeSkettenis 
360d9889caeSkettenis 	lp = (struct ldc_pkt *)(lc->lc_txq->lq_va + tx_tail);
361d9889caeSkettenis 	bzero(lp, sizeof(struct ldc_pkt));
362d9889caeSkettenis 	lp->type = LDC_CTRL;
363d9889caeSkettenis 	lp->stype = LDC_INFO;
364d9889caeSkettenis 	lp->ctrl = LDC_RTR;
365d9889caeSkettenis 	lp->env = LDC_MODE_UNRELIABLE;
366d9889caeSkettenis 	lp->seqid = lc->lc_tx_seqid++;
367d9889caeSkettenis 
368d9889caeSkettenis 	tx_tail += sizeof(*lp);
369d9889caeSkettenis 	tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
370d9889caeSkettenis 	err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
371678c28a9Skettenis 	if (err != H_EOK) {
372d9889caeSkettenis 		printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
373678c28a9Skettenis 		mtx_leave(&lc->lc_txq->lq_mtx);
374678c28a9Skettenis 		return;
375678c28a9Skettenis 	}
376d9889caeSkettenis 
377d9889caeSkettenis 	lc->lc_state = LDC_SND_RTR;
378678c28a9Skettenis 	mtx_leave(&lc->lc_txq->lq_mtx);
379d9889caeSkettenis }
380d9889caeSkettenis 
381d9889caeSkettenis void
ldc_send_rdx(struct ldc_conn * lc)382d9889caeSkettenis ldc_send_rdx(struct ldc_conn *lc)
383d9889caeSkettenis {
384d9889caeSkettenis 	struct ldc_pkt *lp;
385d9889caeSkettenis 	uint64_t tx_head, tx_tail, tx_state;
386d9889caeSkettenis 	int err;
387d9889caeSkettenis 
388678c28a9Skettenis 	mtx_enter(&lc->lc_txq->lq_mtx);
389d9889caeSkettenis 	err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
390678c28a9Skettenis 	if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
391678c28a9Skettenis 		mtx_leave(&lc->lc_txq->lq_mtx);
392d9889caeSkettenis 		return;
393678c28a9Skettenis 	}
394d9889caeSkettenis 
395d9889caeSkettenis 	lp = (struct ldc_pkt *)(lc->lc_txq->lq_va + tx_tail);
396d9889caeSkettenis 	bzero(lp, sizeof(struct ldc_pkt));
397d9889caeSkettenis 	lp->type = LDC_CTRL;
398d9889caeSkettenis 	lp->stype = LDC_INFO;
399d9889caeSkettenis 	lp->ctrl = LDC_RDX;
400d9889caeSkettenis 	lp->env = LDC_MODE_UNRELIABLE;
401d9889caeSkettenis 	lp->seqid = lc->lc_tx_seqid++;
402d9889caeSkettenis 
403d9889caeSkettenis 	tx_tail += sizeof(*lp);
404d9889caeSkettenis 	tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
405d9889caeSkettenis 	err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
406678c28a9Skettenis 	if (err != H_EOK) {
407d9889caeSkettenis 		printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
408678c28a9Skettenis 		mtx_leave(&lc->lc_txq->lq_mtx);
409678c28a9Skettenis 		return;
410678c28a9Skettenis 	}
411d9889caeSkettenis 
412d9889caeSkettenis 	lc->lc_state = LDC_SND_RDX;
413678c28a9Skettenis 	mtx_leave(&lc->lc_txq->lq_mtx);
414d9889caeSkettenis }
415d9889caeSkettenis 
4166943088aSkettenis int
ldc_send_unreliable(struct ldc_conn * lc,void * msg,size_t len)4176943088aSkettenis ldc_send_unreliable(struct ldc_conn *lc, void *msg, size_t len)
4186943088aSkettenis {
4196943088aSkettenis 	struct ldc_pkt *lp;
4206943088aSkettenis 	uint64_t tx_head, tx_tail, tx_state;
4216943088aSkettenis 	uint64_t tx_avail;
4226943088aSkettenis 	uint8_t *p = msg;
4236943088aSkettenis 	int err;
4246943088aSkettenis 
425678c28a9Skettenis 	mtx_enter(&lc->lc_txq->lq_mtx);
4266943088aSkettenis 	err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
427678c28a9Skettenis 	if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
428678c28a9Skettenis 		mtx_leave(&lc->lc_txq->lq_mtx);
4296943088aSkettenis 		return (EIO);
430678c28a9Skettenis 	}
4316943088aSkettenis 
4326943088aSkettenis 	tx_avail = (tx_head - tx_tail) / sizeof(*lp) +
4336943088aSkettenis 	    lc->lc_txq->lq_nentries - 1;
4346943088aSkettenis 	tx_avail %= lc->lc_txq->lq_nentries;
435678c28a9Skettenis 	if (len > tx_avail * LDC_PKT_PAYLOAD) {
436678c28a9Skettenis 		mtx_leave(&lc->lc_txq->lq_mtx);
4376943088aSkettenis 		return (EWOULDBLOCK);
438678c28a9Skettenis 	}
4396943088aSkettenis 
4406943088aSkettenis 	while (len > 0) {
4416943088aSkettenis 		lp = (struct ldc_pkt *)(lc->lc_txq->lq_va + tx_tail);
4426943088aSkettenis 		bzero(lp, sizeof(struct ldc_pkt));
4436943088aSkettenis 		lp->type = LDC_DATA;
4446943088aSkettenis 		lp->stype = LDC_INFO;
4456943088aSkettenis 		lp->env = min(len, LDC_PKT_PAYLOAD);
4466943088aSkettenis 		if (p == msg)
4476943088aSkettenis 			lp->env |= LDC_FRAG_START;
4486943088aSkettenis 		if (len <= LDC_PKT_PAYLOAD)
4496943088aSkettenis 			lp->env |= LDC_FRAG_STOP;
4506943088aSkettenis 		lp->seqid = lc->lc_tx_seqid++;
4516943088aSkettenis 		bcopy(p, &lp->major, min(len, LDC_PKT_PAYLOAD));
4526943088aSkettenis 
4536943088aSkettenis 		tx_tail += sizeof(*lp);
4546943088aSkettenis 		tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
4556943088aSkettenis 		err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
456678c28a9Skettenis 		if (err != H_EOK) {
4576943088aSkettenis 			printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
458678c28a9Skettenis 			mtx_leave(&lc->lc_txq->lq_mtx);
459678c28a9Skettenis 			return (EIO);
460678c28a9Skettenis 		}
4616943088aSkettenis 		p += min(len, LDC_PKT_PAYLOAD);
4626943088aSkettenis 		len -= min(len, LDC_PKT_PAYLOAD);
4636943088aSkettenis 	}
4646943088aSkettenis 
465678c28a9Skettenis 	mtx_leave(&lc->lc_txq->lq_mtx);
4666943088aSkettenis 	return (0);
4676943088aSkettenis }
4686943088aSkettenis 
469d9889caeSkettenis void
ldc_reset(struct ldc_conn * lc)470d9889caeSkettenis ldc_reset(struct ldc_conn *lc)
471d9889caeSkettenis {
472d9889caeSkettenis 	int err;
473d9889caeSkettenis 
474d9889caeSkettenis 	DPRINTF(("Resetting connection\n"));
475678c28a9Skettenis 
476678c28a9Skettenis 	mtx_enter(&lc->lc_txq->lq_mtx);
477d9889caeSkettenis 	err = hv_ldc_tx_qconf(lc->lc_id,
478d9889caeSkettenis 	    lc->lc_txq->lq_map->dm_segs[0].ds_addr, lc->lc_txq->lq_nentries);
479d9889caeSkettenis 	if (err != H_EOK)
480d9889caeSkettenis 		printf("%s: hv_ldc_tx_qconf %d\n", __func__, err);
481d9889caeSkettenis 
482d9889caeSkettenis 	err = hv_ldc_rx_qconf(lc->lc_id,
483d9889caeSkettenis 	    lc->lc_rxq->lq_map->dm_segs[0].ds_addr, lc->lc_rxq->lq_nentries);
484d9889caeSkettenis 	if (err != H_EOK)
485d9889caeSkettenis 		printf("%s: hv_ldc_rx_qconf %d\n", __func__, err);
486d9889caeSkettenis 
487d9889caeSkettenis 	lc->lc_tx_seqid = 0;
488d9889caeSkettenis 	lc->lc_state = 0;
489f09d1088Skettenis 	lc->lc_tx_state = lc->lc_rx_state = LDC_CHANNEL_DOWN;
490678c28a9Skettenis 	mtx_leave(&lc->lc_txq->lq_mtx);
491678c28a9Skettenis 
492d9889caeSkettenis 	lc->lc_reset(lc);
493d9889caeSkettenis }
494d9889caeSkettenis 
495d9889caeSkettenis struct ldc_queue *
ldc_queue_alloc(bus_dma_tag_t t,int nentries)496d9889caeSkettenis ldc_queue_alloc(bus_dma_tag_t t, int nentries)
497d9889caeSkettenis {
498d9889caeSkettenis 	struct ldc_queue *lq;
499d9889caeSkettenis 	bus_size_t size;
500d9889caeSkettenis 	caddr_t va;
501d9889caeSkettenis 	int nsegs;
502d9889caeSkettenis 
503d9889caeSkettenis 	lq = malloc(sizeof(struct ldc_queue), M_DEVBUF, M_NOWAIT);
504d9889caeSkettenis 	if (lq == NULL)
505d9889caeSkettenis 		return NULL;
506d9889caeSkettenis 
507678c28a9Skettenis 	mtx_init(&lq->lq_mtx, IPL_TTY);
508678c28a9Skettenis 
509d9889caeSkettenis 	size = roundup(nentries * sizeof(struct ldc_pkt), PAGE_SIZE);
510d9889caeSkettenis 
511d9889caeSkettenis 	if (bus_dmamap_create(t, size, 1, size, 0,
512d9889caeSkettenis 	    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &lq->lq_map) != 0)
5131bce55bfStom 		goto error;
514d9889caeSkettenis 
515d9889caeSkettenis 	if (bus_dmamem_alloc(t, size, PAGE_SIZE, 0, &lq->lq_seg, 1,
516d9889caeSkettenis 	    &nsegs, BUS_DMA_NOWAIT) != 0)
517d9889caeSkettenis 		goto destroy;
518d9889caeSkettenis 
519d9889caeSkettenis 	if (bus_dmamem_map(t, &lq->lq_seg, 1, size, &va,
520d9889caeSkettenis 	    BUS_DMA_NOWAIT) != 0)
521d9889caeSkettenis 		goto free;
522d9889caeSkettenis 
523d9889caeSkettenis 	if (bus_dmamap_load(t, lq->lq_map, va, size, NULL,
524d9889caeSkettenis 	    BUS_DMA_NOWAIT) != 0)
525d9889caeSkettenis 		goto unmap;
526d9889caeSkettenis 
527d9889caeSkettenis 	lq->lq_va = va;
528d9889caeSkettenis 	lq->lq_nentries = nentries;
529d9889caeSkettenis 	return (lq);
530d9889caeSkettenis 
531d9889caeSkettenis unmap:
532d9889caeSkettenis 	bus_dmamem_unmap(t, va, size);
533d9889caeSkettenis free:
534d9889caeSkettenis 	bus_dmamem_free(t, &lq->lq_seg, 1);
535d9889caeSkettenis destroy:
536d9889caeSkettenis 	bus_dmamap_destroy(t, lq->lq_map);
5371bce55bfStom error:
5381bce55bfStom 	free(lq, M_DEVBUF, sizeof(struct ldc_queue));
539d9889caeSkettenis 
540d9889caeSkettenis 	return (NULL);
541d9889caeSkettenis }
542d9889caeSkettenis 
543d9889caeSkettenis void
ldc_queue_free(bus_dma_tag_t t,struct ldc_queue * lq)544d9889caeSkettenis ldc_queue_free(bus_dma_tag_t t, struct ldc_queue *lq)
545d9889caeSkettenis {
546d9889caeSkettenis 	bus_size_t size;
547d9889caeSkettenis 
548d9889caeSkettenis 	size = roundup(lq->lq_nentries * sizeof(struct ldc_pkt), PAGE_SIZE);
549d9889caeSkettenis 
550d9889caeSkettenis 	bus_dmamap_unload(t, lq->lq_map);
551d9889caeSkettenis 	bus_dmamem_unmap(t, lq->lq_va, size);
552d9889caeSkettenis 	bus_dmamem_free(t, &lq->lq_seg, 1);
553d9889caeSkettenis 	bus_dmamap_destroy(t, lq->lq_map);
554f8e6c425Stedu 	free(lq, M_DEVBUF, 0);
555d9889caeSkettenis }
556d9889caeSkettenis 
557d9889caeSkettenis struct ldc_map *
ldc_map_alloc(bus_dma_tag_t t,int nentries)558d9889caeSkettenis ldc_map_alloc(bus_dma_tag_t t, int nentries)
559d9889caeSkettenis {
560d9889caeSkettenis 	struct ldc_map *lm;
561d9889caeSkettenis 	bus_size_t size;
562d9889caeSkettenis 	caddr_t va;
563d9889caeSkettenis 	int nsegs;
564d9889caeSkettenis 
565d9889caeSkettenis 	lm = malloc(sizeof(struct ldc_map), M_DEVBUF, M_NOWAIT);
566d9889caeSkettenis 	if (lm == NULL)
567d9889caeSkettenis 		return NULL;
568d9889caeSkettenis 
569d9889caeSkettenis 	size = roundup(nentries * sizeof(struct ldc_map_slot), PAGE_SIZE);
570d9889caeSkettenis 
571d9889caeSkettenis 	if (bus_dmamap_create(t, size, 1, size, 0,
572d9889caeSkettenis 	    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &lm->lm_map) != 0)
573*6c66ff3aStom 		goto error;
574d9889caeSkettenis 
575d9889caeSkettenis 	if (bus_dmamem_alloc(t, size, PAGE_SIZE, 0, &lm->lm_seg, 1,
576d9889caeSkettenis 	    &nsegs, BUS_DMA_NOWAIT) != 0)
577d9889caeSkettenis 		goto destroy;
578d9889caeSkettenis 
579d9889caeSkettenis 	if (bus_dmamem_map(t, &lm->lm_seg, 1, size, &va,
580d9889caeSkettenis 	    BUS_DMA_NOWAIT) != 0)
581d9889caeSkettenis 		goto free;
582d9889caeSkettenis 
583d9889caeSkettenis 	if (bus_dmamap_load(t, lm->lm_map, va, size, NULL,
584d9889caeSkettenis 	    BUS_DMA_NOWAIT) != 0)
585d9889caeSkettenis 		goto unmap;
586d9889caeSkettenis 
587d9889caeSkettenis 	lm->lm_slot = (struct ldc_map_slot *)va;
588d9889caeSkettenis 	lm->lm_nentries = nentries;
589d9889caeSkettenis 	bzero(lm->lm_slot, nentries * sizeof(struct ldc_map_slot));
590d9889caeSkettenis 	return (lm);
591d9889caeSkettenis 
592d9889caeSkettenis unmap:
593d9889caeSkettenis 	bus_dmamem_unmap(t, va, size);
594d9889caeSkettenis free:
595d9889caeSkettenis 	bus_dmamem_free(t, &lm->lm_seg, 1);
596d9889caeSkettenis destroy:
597d9889caeSkettenis 	bus_dmamap_destroy(t, lm->lm_map);
598*6c66ff3aStom error:
599*6c66ff3aStom 	free(lm, M_DEVBUF, sizeof(struct ldc_map));
600d9889caeSkettenis 
601d9889caeSkettenis 	return (NULL);
602d9889caeSkettenis }
603d9889caeSkettenis 
604d9889caeSkettenis void
ldc_map_free(bus_dma_tag_t t,struct ldc_map * lm)605d9889caeSkettenis ldc_map_free(bus_dma_tag_t t, struct ldc_map *lm)
606d9889caeSkettenis {
607d9889caeSkettenis 	bus_size_t size;
608d9889caeSkettenis 
609d9889caeSkettenis 	size = lm->lm_nentries * sizeof(struct ldc_map_slot);
610d9889caeSkettenis 	size = roundup(size, PAGE_SIZE);
611d9889caeSkettenis 
612d9889caeSkettenis 	bus_dmamap_unload(t, lm->lm_map);
613d9889caeSkettenis 	bus_dmamem_unmap(t, (caddr_t)lm->lm_slot, size);
614d9889caeSkettenis 	bus_dmamem_free(t, &lm->lm_seg, 1);
615d9889caeSkettenis 	bus_dmamap_destroy(t, lm->lm_map);
616f8e6c425Stedu 	free(lm, M_DEVBUF, 0);
617d9889caeSkettenis }
618