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