1*1dc652efSthorpej /* $NetBSD: ldc.c,v 1.8 2023/12/20 05:33:58 thorpej Exp $ */
2c7863d93Spalle /* $OpenBSD: ldc.c,v 1.12 2015/03/21 18:02:58 kettenis Exp $ */
3c7863d93Spalle /*
4c7863d93Spalle * Copyright (c) 2009 Mark Kettenis
5c7863d93Spalle *
6c7863d93Spalle * Permission to use, copy, modify, and distribute this software for any
7c7863d93Spalle * purpose with or without fee is hereby granted, provided that the above
8c7863d93Spalle * copyright notice and this permission notice appear in all copies.
9c7863d93Spalle *
10c7863d93Spalle * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11c7863d93Spalle * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12c7863d93Spalle * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13c7863d93Spalle * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14c7863d93Spalle * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15c7863d93Spalle * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16c7863d93Spalle * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17c7863d93Spalle */
18c7863d93Spalle
19c7863d93Spalle #include <sys/kmem.h>
20c7863d93Spalle #include <sys/param.h>
21c7863d93Spalle #include <sys/systm.h>
22c7863d93Spalle
23c7863d93Spalle #include <sys/bus.h>
24c7863d93Spalle #include <machine/hypervisor.h>
25c7863d93Spalle
26c7863d93Spalle #include <uvm/uvm_extern.h>
27c7863d93Spalle
28c7863d93Spalle #include <sparc64/dev/ldcvar.h>
29c7863d93Spalle
30c7863d93Spalle #ifdef LDC_DEBUG
31c7863d93Spalle #define DPRINTF(x) printf x
32c7863d93Spalle #else
33c7863d93Spalle #define DPRINTF(x)
34c7863d93Spalle #endif
35c7863d93Spalle
36c7863d93Spalle void ldc_rx_ctrl_vers(struct ldc_conn *, struct ldc_pkt *);
37c7863d93Spalle void ldc_rx_ctrl_rtr(struct ldc_conn *, struct ldc_pkt *);
38c7863d93Spalle void ldc_rx_ctrl_rts(struct ldc_conn *, struct ldc_pkt *);
39c7863d93Spalle void ldc_rx_ctrl_rdx(struct ldc_conn *, struct ldc_pkt *);
40c7863d93Spalle
41c7863d93Spalle void ldc_send_ack(struct ldc_conn *);
42c7863d93Spalle void ldc_send_rtr(struct ldc_conn *);
43c7863d93Spalle void ldc_send_rts(struct ldc_conn *);
44c7863d93Spalle void ldc_send_rdx(struct ldc_conn *);
45c7863d93Spalle
46c7863d93Spalle void
ldc_rx_ctrl(struct ldc_conn * lc,struct ldc_pkt * lp)47c7863d93Spalle ldc_rx_ctrl(struct ldc_conn *lc, struct ldc_pkt *lp)
48c7863d93Spalle {
49c7863d93Spalle switch (lp->ctrl) {
50c7863d93Spalle case LDC_VERS:
51c7863d93Spalle ldc_rx_ctrl_vers(lc, lp);
52c7863d93Spalle break;
53c7863d93Spalle
54c7863d93Spalle case LDC_RTS:
55c7863d93Spalle ldc_rx_ctrl_rts(lc, lp);
56c7863d93Spalle break;
57c7863d93Spalle
58c7863d93Spalle case LDC_RTR:
59c7863d93Spalle ldc_rx_ctrl_rtr(lc, lp);
60c7863d93Spalle break;
61c7863d93Spalle
62c7863d93Spalle case LDC_RDX:
63c7863d93Spalle ldc_rx_ctrl_rdx(lc, lp);
64c7863d93Spalle break;
65c7863d93Spalle
66c7863d93Spalle default:
67c7863d93Spalle DPRINTF(("CTRL/0x%02x/0x%02x\n", lp->stype, lp->ctrl));
68c7863d93Spalle ldc_reset(lc);
69c7863d93Spalle break;
70c7863d93Spalle }
71c7863d93Spalle }
72c7863d93Spalle
73c7863d93Spalle void
ldc_rx_ctrl_vers(struct ldc_conn * lc,struct ldc_pkt * lp)74c7863d93Spalle ldc_rx_ctrl_vers(struct ldc_conn *lc, struct ldc_pkt *lp)
75c7863d93Spalle {
76c7863d93Spalle switch (lp->stype) {
77c7863d93Spalle case LDC_INFO:
78ec3b64e8Spalle DPRINTF(("CTRL/INFO/VERS major %d minor %d\n", lp->major, lp->minor));
79c7863d93Spalle if (lp->major == LDC_VERSION_MAJOR &&
80c7863d93Spalle lp->minor == LDC_VERSION_MINOR)
81c7863d93Spalle ldc_send_ack(lc);
82c7863d93Spalle else {
83c7863d93Spalle /* XXX do nothing for now. */
84ec3b64e8Spalle DPRINTF(("CTRL/INFO/VERS unsupported major/minor\n"));
85c7863d93Spalle }
86c7863d93Spalle break;
87c7863d93Spalle
88c7863d93Spalle case LDC_ACK:
89c7863d93Spalle DPRINTF(("CTRL/ACK/VERS\n"));
90ec3b64e8Spalle if (lc->lc_state != LDC_SND_VERS) {
91ec3b64e8Spalle DPRINTF(("Spurious CTRL/ACK/VERS: state %d major %d minor %d (ignored)\n",
92ec3b64e8Spalle lc->lc_state, lp->major, lp->minor));
93ec3b64e8Spalle }
94ec3b64e8Spalle else {
95c7863d93Spalle ldc_send_rts(lc);
96ec3b64e8Spalle }
97c7863d93Spalle break;
98c7863d93Spalle
99c7863d93Spalle case LDC_NACK:
100c7863d93Spalle DPRINTF(("CTRL/NACK/VERS\n"));
101c7863d93Spalle ldc_reset(lc);
102c7863d93Spalle break;
103c7863d93Spalle
104c7863d93Spalle default:
105c7863d93Spalle DPRINTF(("CTRL/0x%02x/VERS\n", lp->stype));
106c7863d93Spalle ldc_reset(lc);
107c7863d93Spalle break;
108c7863d93Spalle }
109c7863d93Spalle }
110c7863d93Spalle
111c7863d93Spalle void
ldc_rx_ctrl_rts(struct ldc_conn * lc,struct ldc_pkt * lp)112c7863d93Spalle ldc_rx_ctrl_rts(struct ldc_conn *lc, struct ldc_pkt *lp)
113c7863d93Spalle {
114c7863d93Spalle switch (lp->stype) {
115c7863d93Spalle case LDC_INFO:
116c7863d93Spalle if (lc->lc_state != LDC_RCV_VERS) {
117c7863d93Spalle DPRINTF(("Spurious CTRL/INFO/RTS: state %d\n",
118c7863d93Spalle lc->lc_state));
119c7863d93Spalle ldc_reset(lc);
120c7863d93Spalle return;
121c7863d93Spalle }
122c7863d93Spalle DPRINTF(("CTRL/INFO/RTS\n"));
123c7863d93Spalle ldc_send_rtr(lc);
124c7863d93Spalle break;
125c7863d93Spalle
126c7863d93Spalle case LDC_ACK:
127c7863d93Spalle DPRINTF(("CTRL/ACK/RTS\n"));
128c7863d93Spalle ldc_reset(lc);
129c7863d93Spalle break;
130c7863d93Spalle
131c7863d93Spalle case LDC_NACK:
132c7863d93Spalle DPRINTF(("CTRL/NACK/RTS\n"));
133c7863d93Spalle ldc_reset(lc);
134c7863d93Spalle break;
135c7863d93Spalle
136c7863d93Spalle default:
137c7863d93Spalle DPRINTF(("CTRL/0x%02x/RTS\n", lp->stype));
138c7863d93Spalle ldc_reset(lc);
139c7863d93Spalle break;
140c7863d93Spalle }
141c7863d93Spalle }
142c7863d93Spalle
143c7863d93Spalle void
ldc_rx_ctrl_rtr(struct ldc_conn * lc,struct ldc_pkt * lp)144c7863d93Spalle ldc_rx_ctrl_rtr(struct ldc_conn *lc, struct ldc_pkt *lp)
145c7863d93Spalle {
146c7863d93Spalle switch (lp->stype) {
147c7863d93Spalle case LDC_INFO:
148c7863d93Spalle if (lc->lc_state != LDC_SND_RTS) {
149c7863d93Spalle DPRINTF(("Spurious CTRL/INFO/RTR: state %d\n",
150c7863d93Spalle lc->lc_state));
151c7863d93Spalle ldc_reset(lc);
152c7863d93Spalle return;
153c7863d93Spalle }
154c7863d93Spalle DPRINTF(("CTRL/INFO/RTR\n"));
155c7863d93Spalle ldc_send_rdx(lc);
156c7863d93Spalle lc->lc_start(lc);
157c7863d93Spalle break;
158c7863d93Spalle
159c7863d93Spalle case LDC_ACK:
160c7863d93Spalle DPRINTF(("CTRL/ACK/RTR\n"));
161c7863d93Spalle ldc_reset(lc);
162c7863d93Spalle break;
163c7863d93Spalle
164c7863d93Spalle case LDC_NACK:
165c7863d93Spalle DPRINTF(("CTRL/NACK/RTR\n"));
166c7863d93Spalle ldc_reset(lc);
167c7863d93Spalle break;
168c7863d93Spalle
169c7863d93Spalle default:
170c7863d93Spalle DPRINTF(("CTRL/0x%02x/RTR\n", lp->stype));
171c7863d93Spalle ldc_reset(lc);
172c7863d93Spalle break;
173c7863d93Spalle }
174c7863d93Spalle }
175c7863d93Spalle
176c7863d93Spalle void
ldc_rx_ctrl_rdx(struct ldc_conn * lc,struct ldc_pkt * lp)177c7863d93Spalle ldc_rx_ctrl_rdx(struct ldc_conn *lc, struct ldc_pkt *lp)
178c7863d93Spalle {
179c7863d93Spalle switch (lp->stype) {
180c7863d93Spalle case LDC_INFO:
181c7863d93Spalle if (lc->lc_state != LDC_SND_RTR) {
182c7863d93Spalle DPRINTF(("Spurious CTRL/INFO/RTR: state %d\n",
183c7863d93Spalle lc->lc_state));
184c7863d93Spalle ldc_reset(lc);
185c7863d93Spalle return;
186c7863d93Spalle }
187c7863d93Spalle DPRINTF(("CTRL/INFO/RDX\n"));
188c7863d93Spalle lc->lc_start(lc);
189c7863d93Spalle break;
190c7863d93Spalle
191c7863d93Spalle case LDC_ACK:
192c7863d93Spalle DPRINTF(("CTRL/ACK/RDX\n"));
193c7863d93Spalle ldc_reset(lc);
194c7863d93Spalle break;
195c7863d93Spalle
196c7863d93Spalle case LDC_NACK:
197c7863d93Spalle DPRINTF(("CTRL/NACK/RDX\n"));
198c7863d93Spalle ldc_reset(lc);
199c7863d93Spalle break;
200c7863d93Spalle
201c7863d93Spalle default:
202c7863d93Spalle DPRINTF(("CTRL/0x%02x/RDX\n", lp->stype));
203c7863d93Spalle ldc_reset(lc);
204c7863d93Spalle break;
205c7863d93Spalle }
206c7863d93Spalle }
207c7863d93Spalle
208c7863d93Spalle void
ldc_rx_data(struct ldc_conn * lc,struct ldc_pkt * lp)209c7863d93Spalle ldc_rx_data(struct ldc_conn *lc, struct ldc_pkt *lp)
210c7863d93Spalle {
211c7863d93Spalle size_t len;
212c7863d93Spalle
213c7863d93Spalle if (lp->stype != LDC_INFO) {
214c7863d93Spalle DPRINTF(("DATA/0x%02x\n", lp->stype));
215c7863d93Spalle ldc_reset(lc);
216c7863d93Spalle return;
217c7863d93Spalle }
218c7863d93Spalle
219c7863d93Spalle if (lc->lc_state != LDC_SND_RTR &&
220c7863d93Spalle lc->lc_state != LDC_SND_RDX) {
221c7863d93Spalle DPRINTF(("Spurious DATA/INFO: state %d\n", lc->lc_state));
222c7863d93Spalle ldc_reset(lc);
223c7863d93Spalle return;
224c7863d93Spalle }
225c7863d93Spalle
226c7863d93Spalle if (lp->env & LDC_FRAG_START) {
227c7863d93Spalle lc->lc_len = (lp->env & LDC_LEN_MASK) + 8;
228c7863d93Spalle KASSERT(lc->lc_len <= sizeof(lc->lc_msg));
229c7863d93Spalle memcpy((uint8_t *)lc->lc_msg, lp, lc->lc_len);
230c7863d93Spalle } else {
231c7863d93Spalle len = (lp->env & LDC_LEN_MASK);
232c7863d93Spalle if (lc->lc_len + len > sizeof(lc->lc_msg)) {
233c7863d93Spalle DPRINTF(("Buffer overrun\n"));
234c7863d93Spalle ldc_reset(lc);
235c7863d93Spalle return;
236c7863d93Spalle }
237c7863d93Spalle memcpy(((uint8_t *)lc->lc_msg) + lc->lc_len, &lp->major, len);
238c7863d93Spalle lc->lc_len += len;
239c7863d93Spalle }
240c7863d93Spalle
241c7863d93Spalle if (lp->env & LDC_FRAG_STOP)
242c7863d93Spalle lc->lc_rx_data(lc, (struct ldc_pkt *)lc->lc_msg);
243c7863d93Spalle }
244c7863d93Spalle
245c7863d93Spalle void
ldc_send_vers(struct ldc_conn * lc)246c7863d93Spalle ldc_send_vers(struct ldc_conn *lc)
247c7863d93Spalle {
248c7863d93Spalle struct ldc_pkt *lp;
249c7863d93Spalle uint64_t tx_head, tx_tail, tx_state;
250c7863d93Spalle int err;
251c7863d93Spalle
252c7863d93Spalle mutex_enter(&lc->lc_txq->lq_mtx);
253c7863d93Spalle err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
254c7863d93Spalle if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
255c7863d93Spalle mutex_exit(&lc->lc_txq->lq_mtx);
256c7863d93Spalle return;
257c7863d93Spalle }
258c7863d93Spalle
259169b6608Snakayama lp = (struct ldc_pkt *)(uintptr_t)(lc->lc_txq->lq_va + tx_tail);
260c7863d93Spalle bzero(lp, sizeof(struct ldc_pkt));
261c7863d93Spalle lp->type = LDC_CTRL;
262c7863d93Spalle lp->stype = LDC_INFO;
263c7863d93Spalle lp->ctrl = LDC_VERS;
264c7863d93Spalle lp->major = 1;
265c7863d93Spalle lp->minor = 0;
266ec3b64e8Spalle DPRINTF(("ldc_send_vers() major %d minor %d\n", lp->major, lp->minor));
267c7863d93Spalle
268c7863d93Spalle tx_tail += sizeof(*lp);
269c7863d93Spalle tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
270c7863d93Spalle err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
271c7863d93Spalle if (err != H_EOK) {
272c7863d93Spalle printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
273c7863d93Spalle mutex_exit(&lc->lc_txq->lq_mtx);
274c7863d93Spalle return;
275c7863d93Spalle }
276c7863d93Spalle
277c7863d93Spalle lc->lc_state = LDC_SND_VERS;
278ec3b64e8Spalle DPRINTF(("ldc_send_vers() setting lc->lc_state to %d\n", lc->lc_state));
279c7863d93Spalle mutex_exit(&lc->lc_txq->lq_mtx);
280c7863d93Spalle }
281c7863d93Spalle
282c7863d93Spalle void
ldc_send_ack(struct ldc_conn * lc)283c7863d93Spalle ldc_send_ack(struct ldc_conn *lc)
284c7863d93Spalle {
285c7863d93Spalle struct ldc_pkt *lp;
286c7863d93Spalle uint64_t tx_head, tx_tail, tx_state;
287c7863d93Spalle int err;
288c7863d93Spalle
289c7863d93Spalle mutex_enter(&lc->lc_txq->lq_mtx);
290c7863d93Spalle err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
291c7863d93Spalle if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
292c7863d93Spalle mutex_exit(&lc->lc_txq->lq_mtx);
293c7863d93Spalle return;
294c7863d93Spalle }
295c7863d93Spalle
296169b6608Snakayama lp = (struct ldc_pkt *)(uintptr_t)(lc->lc_txq->lq_va + tx_tail);
297c7863d93Spalle bzero(lp, sizeof(struct ldc_pkt));
298c7863d93Spalle lp->type = LDC_CTRL;
299c7863d93Spalle lp->stype = LDC_ACK;
300c7863d93Spalle lp->ctrl = LDC_VERS;
301c7863d93Spalle lp->major = 1;
302c7863d93Spalle lp->minor = 0;
303c7863d93Spalle
304c7863d93Spalle tx_tail += sizeof(*lp);
305c7863d93Spalle tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
306c7863d93Spalle err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
307c7863d93Spalle if (err != H_EOK) {
308c7863d93Spalle printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
309c7863d93Spalle mutex_exit(&lc->lc_txq->lq_mtx);
310c7863d93Spalle return;
311c7863d93Spalle }
312c7863d93Spalle
313c7863d93Spalle lc->lc_state = LDC_RCV_VERS;
314ec3b64e8Spalle DPRINTF(("ldc_send_ack() setting lc->lc_state to %d\n", lc->lc_state));
315c7863d93Spalle mutex_exit(&lc->lc_txq->lq_mtx);
316c7863d93Spalle }
317c7863d93Spalle
318c7863d93Spalle void
ldc_send_rts(struct ldc_conn * lc)319c7863d93Spalle ldc_send_rts(struct ldc_conn *lc)
320c7863d93Spalle {
321c7863d93Spalle struct ldc_pkt *lp;
322c7863d93Spalle uint64_t tx_head, tx_tail, tx_state;
323c7863d93Spalle int err;
324c7863d93Spalle
325c7863d93Spalle mutex_enter(&lc->lc_txq->lq_mtx);
326c7863d93Spalle err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
327c7863d93Spalle if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
328c7863d93Spalle mutex_exit(&lc->lc_txq->lq_mtx);
329c7863d93Spalle return;
330c7863d93Spalle }
331c7863d93Spalle
332169b6608Snakayama lp = (struct ldc_pkt *)(uintptr_t)(lc->lc_txq->lq_va + tx_tail);
333c7863d93Spalle bzero(lp, sizeof(struct ldc_pkt));
334c7863d93Spalle lp->type = LDC_CTRL;
335c7863d93Spalle lp->stype = LDC_INFO;
336c7863d93Spalle lp->ctrl = LDC_RTS;
337c7863d93Spalle lp->env = LDC_MODE_UNRELIABLE;
338c7863d93Spalle lp->seqid = lc->lc_tx_seqid++;
339c7863d93Spalle
340c7863d93Spalle tx_tail += sizeof(*lp);
341c7863d93Spalle tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
342c7863d93Spalle err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
343c7863d93Spalle if (err != H_EOK) {
344c7863d93Spalle printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
345c7863d93Spalle mutex_exit(&lc->lc_txq->lq_mtx);
346c7863d93Spalle return;
347c7863d93Spalle }
348c7863d93Spalle
349c7863d93Spalle lc->lc_state = LDC_SND_RTS;
350ec3b64e8Spalle DPRINTF(("ldc_send_rts() setting lc->lc_state to %d\n", lc->lc_state));
351c7863d93Spalle mutex_exit(&lc->lc_txq->lq_mtx);
352c7863d93Spalle }
353c7863d93Spalle
354c7863d93Spalle void
ldc_send_rtr(struct ldc_conn * lc)355c7863d93Spalle ldc_send_rtr(struct ldc_conn *lc)
356c7863d93Spalle {
357c7863d93Spalle struct ldc_pkt *lp;
358c7863d93Spalle uint64_t tx_head, tx_tail, tx_state;
359c7863d93Spalle int err;
360c7863d93Spalle
361c7863d93Spalle mutex_enter(&lc->lc_txq->lq_mtx);
362c7863d93Spalle err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
363c7863d93Spalle if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
364c7863d93Spalle mutex_exit(&lc->lc_txq->lq_mtx);
365c7863d93Spalle return;
366c7863d93Spalle }
367c7863d93Spalle
368169b6608Snakayama lp = (struct ldc_pkt *)(uintptr_t)(lc->lc_txq->lq_va + tx_tail);
369c7863d93Spalle bzero(lp, sizeof(struct ldc_pkt));
370c7863d93Spalle lp->type = LDC_CTRL;
371c7863d93Spalle lp->stype = LDC_INFO;
372c7863d93Spalle lp->ctrl = LDC_RTR;
373c7863d93Spalle lp->env = LDC_MODE_UNRELIABLE;
374c7863d93Spalle lp->seqid = lc->lc_tx_seqid++;
375c7863d93Spalle
376c7863d93Spalle tx_tail += sizeof(*lp);
377c7863d93Spalle tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
378c7863d93Spalle err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
379c7863d93Spalle if (err != H_EOK) {
380c7863d93Spalle printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
381c7863d93Spalle mutex_exit(&lc->lc_txq->lq_mtx);
382c7863d93Spalle return;
383c7863d93Spalle }
384c7863d93Spalle
385c7863d93Spalle lc->lc_state = LDC_SND_RTR;
386ec3b64e8Spalle DPRINTF(("ldc_send_rtr() setting lc->lc_state to %d\n", lc->lc_state));
387c7863d93Spalle mutex_exit(&lc->lc_txq->lq_mtx);
388c7863d93Spalle }
389c7863d93Spalle
390c7863d93Spalle void
ldc_send_rdx(struct ldc_conn * lc)391c7863d93Spalle ldc_send_rdx(struct ldc_conn *lc)
392c7863d93Spalle {
393c7863d93Spalle struct ldc_pkt *lp;
394c7863d93Spalle uint64_t tx_head, tx_tail, tx_state;
395c7863d93Spalle int err;
396c7863d93Spalle
397c7863d93Spalle mutex_enter(&lc->lc_txq->lq_mtx);
398c7863d93Spalle err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
399c7863d93Spalle if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
400c7863d93Spalle mutex_exit(&lc->lc_txq->lq_mtx);
401c7863d93Spalle return;
402c7863d93Spalle }
403c7863d93Spalle
404169b6608Snakayama lp = (struct ldc_pkt *)(uintptr_t)(lc->lc_txq->lq_va + tx_tail);
405c7863d93Spalle bzero(lp, sizeof(struct ldc_pkt));
406c7863d93Spalle lp->type = LDC_CTRL;
407c7863d93Spalle lp->stype = LDC_INFO;
408c7863d93Spalle lp->ctrl = LDC_RDX;
409c7863d93Spalle lp->env = LDC_MODE_UNRELIABLE;
410c7863d93Spalle lp->seqid = lc->lc_tx_seqid++;
411c7863d93Spalle
412c7863d93Spalle tx_tail += sizeof(*lp);
413c7863d93Spalle tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
414c7863d93Spalle err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
415c7863d93Spalle if (err != H_EOK) {
416c7863d93Spalle printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
417c7863d93Spalle mutex_exit(&lc->lc_txq->lq_mtx);
418c7863d93Spalle return;
419c7863d93Spalle }
420c7863d93Spalle
421c7863d93Spalle lc->lc_state = LDC_SND_RDX;
422ec3b64e8Spalle DPRINTF(("ldc_send_rdx() setting lc->lc_state to %d\n", lc->lc_state));
423c7863d93Spalle mutex_exit(&lc->lc_txq->lq_mtx);
424c7863d93Spalle }
425c7863d93Spalle
426c7863d93Spalle int
ldc_send_unreliable(struct ldc_conn * lc,void * msg,size_t len)427c7863d93Spalle ldc_send_unreliable(struct ldc_conn *lc, void *msg, size_t len)
428c7863d93Spalle {
429c7863d93Spalle struct ldc_pkt *lp;
430c7863d93Spalle uint64_t tx_head, tx_tail, tx_state;
431c7863d93Spalle uint64_t tx_avail;
432c7863d93Spalle uint8_t *p = msg;
433c7863d93Spalle int err;
434c7863d93Spalle
435c7863d93Spalle mutex_enter(&lc->lc_txq->lq_mtx);
436c7863d93Spalle err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
437c7863d93Spalle if (err != H_EOK || tx_state != LDC_CHANNEL_UP) {
438c7863d93Spalle mutex_exit(&lc->lc_txq->lq_mtx);
439c7863d93Spalle return (EIO);
440c7863d93Spalle }
441c7863d93Spalle
442c7863d93Spalle tx_avail = (tx_head - tx_tail) / sizeof(*lp) +
443c7863d93Spalle lc->lc_txq->lq_nentries - 1;
444c7863d93Spalle tx_avail %= lc->lc_txq->lq_nentries;
445c7863d93Spalle if (len > tx_avail * LDC_PKT_PAYLOAD) {
446c7863d93Spalle mutex_exit(&lc->lc_txq->lq_mtx);
447c7863d93Spalle return (EWOULDBLOCK);
448c7863d93Spalle }
449c7863d93Spalle
450c7863d93Spalle while (len > 0) {
451169b6608Snakayama lp = (struct ldc_pkt *)(uintptr_t)(lc->lc_txq->lq_va + tx_tail);
452c7863d93Spalle bzero(lp, sizeof(struct ldc_pkt));
453c7863d93Spalle lp->type = LDC_DATA;
454c7863d93Spalle lp->stype = LDC_INFO;
455d1579b2dSriastradh lp->env = uimin(len, LDC_PKT_PAYLOAD);
456c7863d93Spalle if (p == msg)
457c7863d93Spalle lp->env |= LDC_FRAG_START;
458c7863d93Spalle if (len <= LDC_PKT_PAYLOAD)
459c7863d93Spalle lp->env |= LDC_FRAG_STOP;
460c7863d93Spalle lp->seqid = lc->lc_tx_seqid++;
461d1579b2dSriastradh bcopy(p, &lp->major, uimin(len, LDC_PKT_PAYLOAD));
462c7863d93Spalle
463c7863d93Spalle tx_tail += sizeof(*lp);
464c7863d93Spalle tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
465c7863d93Spalle err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
466c7863d93Spalle if (err != H_EOK) {
467c7863d93Spalle printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
468c7863d93Spalle mutex_exit(&lc->lc_txq->lq_mtx);
469c7863d93Spalle return (EIO);
470c7863d93Spalle }
471d1579b2dSriastradh p += uimin(len, LDC_PKT_PAYLOAD);
472d1579b2dSriastradh len -= uimin(len, LDC_PKT_PAYLOAD);
473c7863d93Spalle }
474c7863d93Spalle
475c7863d93Spalle mutex_exit(&lc->lc_txq->lq_mtx);
476c7863d93Spalle return (0);
477c7863d93Spalle }
478c7863d93Spalle
479c7863d93Spalle void
ldc_reset(struct ldc_conn * lc)480c7863d93Spalle ldc_reset(struct ldc_conn *lc)
481c7863d93Spalle {
482c7863d93Spalle int err;
483c7863d93Spalle vaddr_t va;
484c7863d93Spalle paddr_t pa;
485c7863d93Spalle
486c7863d93Spalle DPRINTF(("Resetting connection\n"));
487c7863d93Spalle
488c7863d93Spalle mutex_enter(&lc->lc_txq->lq_mtx);
489c7863d93Spalle
490c7863d93Spalle #if OPENBSD_BUSDMA
491c7863d93Spalle err = hv_ldc_tx_qconf(lc->lc_id,
492c7863d93Spalle lc->lc_txq->lq_map->dm_segs[0].ds_addr, lc->lc_txq->lq_nentries);
493c7863d93Spalle #else
494c7863d93Spalle va = lc->lc_txq->lq_va;
495c7863d93Spalle pa = 0;
496c7863d93Spalle if (pmap_extract(pmap_kernel(), va, &pa) == FALSE)
497c7863d93Spalle panic("pmap_extract failed %lx\n", va);
498c7863d93Spalle err = hv_ldc_tx_qconf(lc->lc_id, pa, lc->lc_txq->lq_nentries);
499c7863d93Spalle #endif
500c7863d93Spalle if (err != H_EOK)
501c7863d93Spalle printf("%s: hv_ldc_tx_qconf %d\n", __func__, err);
502c7863d93Spalle
503c7863d93Spalle #if OPENBSD_BUSDMA
504c7863d93Spalle err = hv_ldc_rx_qconf(lc->lc_id,
505c7863d93Spalle lc->lc_rxq->lq_map->dm_segs[0].ds_addr, lc->lc_rxq->lq_nentries);
506c7863d93Spalle #else
507c7863d93Spalle va = lc->lc_rxq->lq_va;
508c7863d93Spalle pa = 0;
509c7863d93Spalle if (pmap_extract(pmap_kernel(), va, &pa) == FALSE)
510c7863d93Spalle panic("pmap_extract failed %lx\n", va);
511c7863d93Spalle err = hv_ldc_tx_qconf(lc->lc_id, pa, lc->lc_rxq->lq_nentries);
512c7863d93Spalle #endif
513c7863d93Spalle if (err != H_EOK)
514c7863d93Spalle printf("%s: hv_ldc_rx_qconf %d\n", __func__, err);
515c7863d93Spalle
516c7863d93Spalle lc->lc_tx_seqid = 0;
517c7863d93Spalle lc->lc_state = 0;
518c7863d93Spalle lc->lc_tx_state = lc->lc_rx_state = LDC_CHANNEL_DOWN;
519c7863d93Spalle mutex_exit(&lc->lc_txq->lq_mtx);
520c7863d93Spalle
521c7863d93Spalle lc->lc_reset(lc);
522c7863d93Spalle }
523c7863d93Spalle #if OPENBSD_BUSDMA
524c7863d93Spalle struct ldc_queue *
ldc_queue_alloc(bus_dma_tag_t t,int nentries)525c7863d93Spalle ldc_queue_alloc(bus_dma_tag_t t, int nentries)
526c7863d93Spalle #else
527c7863d93Spalle struct ldc_queue *
528c7863d93Spalle ldc_queue_alloc(int nentries)
529c7863d93Spalle #endif
530c7863d93Spalle {
531c7863d93Spalle struct ldc_queue *lq;
532c7863d93Spalle bus_size_t size;
533c7863d93Spalle vaddr_t va = 0;
534c7863d93Spalle #if OPENBSD_BUSDMA
535c7863d93Spalle int nsegs;
536c7863d93Spalle #endif
537c7863d93Spalle
53802991323Schs lq = kmem_zalloc(sizeof(struct ldc_queue), KM_SLEEP);
539c7863d93Spalle
540c7863d93Spalle mutex_init(&lq->lq_mtx, MUTEX_DEFAULT, IPL_TTY);
541c7863d93Spalle
542c7863d93Spalle size = roundup(nentries * sizeof(struct ldc_pkt), PAGE_SIZE);
543c7863d93Spalle #if OPENBSD_BUSDMA
544c7863d93Spalle if (bus_dmamap_create(t, size, 1, size, 0,
545c7863d93Spalle BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &lq->lq_map) != 0)
546c7863d93Spalle return (NULL);
547c7863d93Spalle
548c7863d93Spalle if (bus_dmamem_alloc(t, size, PAGE_SIZE, 0, &lq->lq_seg, 1,
549c7863d93Spalle &nsegs, BUS_DMA_NOWAIT) != 0)
550c7863d93Spalle goto destroy;
551c7863d93Spalle
552c7863d93Spalle if (bus_dmamem_map(t, &lq->lq_seg, 1, size, (void *)&va,
553c7863d93Spalle BUS_DMA_NOWAIT) != 0)
554c7863d93Spalle goto free;
555c7863d93Spalle
556c7863d93Spalle if (bus_dmamap_load(t, lq->lq_map, (void*)va, size, NULL,
557c7863d93Spalle BUS_DMA_NOWAIT) != 0)
558c7863d93Spalle goto unmap;
559c7863d93Spalle #else
56002991323Schs va = (vaddr_t)kmem_zalloc(size, KM_SLEEP);
561c7863d93Spalle #endif
562c7863d93Spalle lq->lq_va = (vaddr_t)va;
563c7863d93Spalle lq->lq_nentries = nentries;
564c7863d93Spalle return (lq);
565c7863d93Spalle #if OPENBSD_BUSDMA
566c7863d93Spalle unmap:
567c7863d93Spalle bus_dmamem_unmap(t, (void*)va, size);
568c7863d93Spalle free:
569c7863d93Spalle bus_dmamem_free(t, &lq->lq_seg, 1);
570c7863d93Spalle destroy:
571c7863d93Spalle bus_dmamap_destroy(t, lq->lq_map);
572c7863d93Spalle #endif
573c7863d93Spalle return (NULL);
574c7863d93Spalle }
575c7863d93Spalle
576c7863d93Spalle void
577c7863d93Spalle #if OPENBSD_BUSDMA
ldc_queue_free(bus_dma_tag_t t,struct ldc_queue * lq)578c7863d93Spalle ldc_queue_free(bus_dma_tag_t t, struct ldc_queue *lq)
579c7863d93Spalle #else
580c7863d93Spalle ldc_queue_free(struct ldc_queue *lq)
581c7863d93Spalle #endif
582c7863d93Spalle {
583c7863d93Spalle bus_size_t size;
584c7863d93Spalle
585c7863d93Spalle size = roundup(lq->lq_nentries * sizeof(struct ldc_pkt), PAGE_SIZE);
586c7863d93Spalle
587c7863d93Spalle #if OPENBSD_BUSDMA
588c7863d93Spalle bus_dmamap_unload(t, lq->lq_map);
589c7863d93Spalle bus_dmamem_unmap(t, &lq->lq_va, size);
590c7863d93Spalle bus_dmamem_free(t, &lq->lq_seg, 1);
591c7863d93Spalle bus_dmamap_destroy(t, lq->lq_map);
592c7863d93Spalle #else
593c7863d93Spalle kmem_free((void *)lq->lq_va, size);
594c7863d93Spalle #endif
595c7863d93Spalle kmem_free(lq, size);
596c7863d93Spalle }
597c7863d93Spalle
598c7863d93Spalle #if OPENBSD_BUSDMA
599c7863d93Spalle struct ldc_map *
ldc_map_alloc(bus_dma_tag_t t,int nentries)600c7863d93Spalle ldc_map_alloc(bus_dma_tag_t t, int nentries)
601c7863d93Spalle #else
602c7863d93Spalle struct ldc_map *
603c7863d93Spalle ldc_map_alloc(int nentries)
604c7863d93Spalle #endif
605c7863d93Spalle {
606c7863d93Spalle struct ldc_map *lm;
607c7863d93Spalle bus_size_t size;
608c7863d93Spalle vaddr_t va = 0;
609c7863d93Spalle
610c7863d93Spalle #if OPENBSD_BUSDMA
611c7863d93Spalle int nsegs;
612c7863d93Spalle #endif
6130a827a3fSchs lm = kmem_zalloc(sizeof(struct ldc_map), KM_SLEEP);
614c7863d93Spalle size = roundup(nentries * sizeof(struct ldc_map_slot), PAGE_SIZE);
615c7863d93Spalle
616c7863d93Spalle #if OPENBSD_BUSDMA
617c7863d93Spalle if (bus_dmamap_create(t, size, 1, size, 0,
618c7863d93Spalle BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &lm->lm_map) != 0) {
619c7863d93Spalle DPRINTF(("ldc_map_alloc() - bus_dmamap_create() failed\n"));
620c7863d93Spalle return (NULL);
621c7863d93Spalle }
622c7863d93Spalle
623c7863d93Spalle if (bus_dmamem_alloc(t, size, PAGE_SIZE, 0, &lm->lm_seg, 1,
624c7863d93Spalle &nsegs, BUS_DMA_NOWAIT) != 0) {
625c7863d93Spalle DPRINTF(("ldc_map_alloc() - bus_dmamem_alloc() failed\n"));
626c7863d93Spalle goto destroy;
627c7863d93Spalle }
628c7863d93Spalle
629c7863d93Spalle if (bus_dmamem_map(t, &lm->lm_seg, 1, size, (void *)&va,
630c7863d93Spalle BUS_DMA_NOWAIT) != 0) {
631c7863d93Spalle DPRINTF(("ldc_map_alloc() - bus_dmamem_map() failed\n"));
632c7863d93Spalle goto free;
633c7863d93Spalle }
634c7863d93Spalle if (bus_dmamap_load(t, lm->lm_map, (void*)va, size, NULL,
635c7863d93Spalle BUS_DMA_NOWAIT) != 0) {
636c7863d93Spalle DPRINTF(("ldc_map_alloc() - bus_dmamap_load() failed\n"));
637c7863d93Spalle goto unmap;
638c7863d93Spalle }
639c7863d93Spalle #else
6400a827a3fSchs va = (vaddr_t)kmem_zalloc(size, KM_SLEEP);
641c7863d93Spalle #endif
642c7863d93Spalle lm->lm_slot = (struct ldc_map_slot *)va;
643c7863d93Spalle lm->lm_nentries = nentries;
644c7863d93Spalle bzero(lm->lm_slot, nentries * sizeof(struct ldc_map_slot));
645c7863d93Spalle return (lm);
646c7863d93Spalle
647c7863d93Spalle #if OPENBSD_BUSDMA
648c7863d93Spalle unmap:
649c7863d93Spalle bus_dmamem_unmap(t, (void*)va, size);
650c7863d93Spalle free:
651c7863d93Spalle bus_dmamem_free(t, &lm->lm_seg, 1);
652c7863d93Spalle destroy:
653c7863d93Spalle bus_dmamap_destroy(t, lm->lm_map);
654c7863d93Spalle #endif
655c7863d93Spalle return (NULL);
656c7863d93Spalle }
657c7863d93Spalle
658c7863d93Spalle #if OPENBSD_BUSDMA
659c7863d93Spalle void
ldc_map_free(bus_dma_tag_t t,struct ldc_map * lm)660c7863d93Spalle ldc_map_free(bus_dma_tag_t t, struct ldc_map *lm)
661c7863d93Spalle #else
662c7863d93Spalle void
663c7863d93Spalle ldc_map_free(struct ldc_map *lm)
664c7863d93Spalle #endif
665c7863d93Spalle {
666c7863d93Spalle bus_size_t size;
667c7863d93Spalle
668c7863d93Spalle size = lm->lm_nentries * sizeof(struct ldc_map_slot);
669c7863d93Spalle size = roundup(size, PAGE_SIZE);
670c7863d93Spalle
671c7863d93Spalle #if OPENBSD_BUSDMA
672c7863d93Spalle bus_dmamap_unload(t, lm->lm_map);
673c7863d93Spalle bus_dmamem_unmap(t, lm->lm_slot, size);
674c7863d93Spalle bus_dmamem_free(t, &lm->lm_seg, 1);
675c7863d93Spalle bus_dmamap_destroy(t, lm->lm_map);
676c7863d93Spalle #else
677c7863d93Spalle kmem_free(lm->lm_slot, size);
678c7863d93Spalle #endif
679c7863d93Spalle kmem_free(lm, size);
680c7863d93Spalle }
681