xref: /openbsd-src/sys/arch/sparc64/dev/ldc.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: ldc.c,v 1.3 2009/01/16 16:58:09 kettenis Exp $	*/
2 /*
3  * Copyright (c) 2009 Mark Kettenis
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/malloc.h>
20 #include <sys/systm.h>
21 
22 #include <machine/bus.h>
23 #include <machine/hypervisor.h>
24 
25 #include <sparc64/dev/ldcvar.h>
26 
27 #ifdef LDC_DEBUG
28 #define DPRINTF(x)	printf x
29 #else
30 #define DPRINTF(x)
31 #endif
32 
33 void	ldc_rx_ctrl_vers(struct ldc_conn *, struct ldc_pkt *);
34 void	ldc_rx_ctrl_rtr(struct ldc_conn *, struct ldc_pkt *);
35 void	ldc_rx_ctrl_rts(struct ldc_conn *, struct ldc_pkt *);
36 
37 void	ldc_send_rtr(struct ldc_conn *);
38 void	ldc_send_rts(struct ldc_conn *);
39 void	ldc_send_rdx(struct ldc_conn *);
40 
41 void
42 ldc_rx_ctrl(struct ldc_conn *lc, struct ldc_pkt *lp)
43 {
44 	switch (lp->ctrl) {
45 	case LDC_VERS:
46 		ldc_rx_ctrl_vers(lc, lp);
47 		break;
48 
49 	case LDC_RTS:
50 		ldc_rx_ctrl_rts(lc, lp);
51 		break;
52 
53 	case LDC_RTR:
54 		ldc_rx_ctrl_rtr(lc, lp);
55 		break;
56 
57 	default:
58 		DPRINTF(("CTRL/0x%02x/0x%02x\n", lp->stype, lp->ctrl));
59 		ldc_reset(lc);
60 		break;
61 	}
62 }
63 
64 void
65 ldc_rx_ctrl_vers(struct ldc_conn *lc, struct ldc_pkt *lp)
66 {
67 	switch (lp->stype) {
68 	case LDC_INFO:
69 		/* XXX do nothing for now. */
70 		break;
71 
72 	case LDC_ACK:
73 		if (lc->lc_state != LDC_SND_VERS) {
74 			DPRINTF(("Spurious CTRL/ACK/VERS: state %d\n",
75 			    lc->lc_state));
76 			ldc_reset(lc);
77 			return;
78 		}
79 		DPRINTF(("CTRL/ACK/VERS\n"));
80 		ldc_send_rts(lc);
81 		break;
82 
83 	case LDC_NACK:
84 		DPRINTF(("CTRL/NACK/VERS\n"));
85 		ldc_reset(lc);
86 		break;
87 
88 	default:
89 		DPRINTF(("CTRL/0x%02x/VERS\n", lp->stype));
90 		ldc_reset(lc);
91 		break;
92 	}
93 }
94 
95 void
96 ldc_rx_ctrl_rts(struct ldc_conn *lc, struct ldc_pkt *lp)
97 {
98 	switch (lp->stype) {
99 	case LDC_INFO:
100 		if (lc->lc_state != LDC_RCV_VERS) {
101 			DPRINTF(("Suprious CTRL/INFO/RTS: state %d\n",
102 			    lc->lc_state));
103 			ldc_reset(lc);
104 			return;
105 		}
106 		DPRINTF(("CTRL/INFO/RTS\n"));
107 		ldc_send_rtr(lc);
108 		break;
109 
110 	case LDC_ACK:
111 		DPRINTF(("CTRL/ACK/RTS\n"));
112 		ldc_reset(lc);
113 		break;
114 
115 	case LDC_NACK:
116 		DPRINTF(("CTRL/NACK/RTS\n"));
117 		ldc_reset(lc);
118 		break;
119 
120 	default:
121 		DPRINTF(("CTRL/0x%02x/RTS\n", lp->stype));
122 		ldc_reset(lc);
123 		break;
124 	}
125 }
126 
127 void
128 ldc_rx_ctrl_rtr(struct ldc_conn *lc, struct ldc_pkt *lp)
129 {
130 	switch (lp->stype) {
131 	case LDC_INFO:
132 		if (lc->lc_state != LDC_SND_RTS) {
133 			DPRINTF(("Spurious CTRL/INFO/RTR: state %d\n",
134 			    lc->lc_state));
135 			ldc_reset(lc);
136 			return;
137 		}
138 		DPRINTF(("CTRL/INFO/RTR\n"));
139 		ldc_send_rdx(lc);
140 		lc->lc_start(lc);
141 		break;
142 
143 	case LDC_ACK:
144 		DPRINTF(("CTRL/ACK/RTR\n"));
145 		ldc_reset(lc);
146 		break;
147 
148 	case LDC_NACK:
149 		DPRINTF(("CTRL/NACK/RTR\n"));
150 		ldc_reset(lc);
151 		break;
152 
153 	default:
154 		DPRINTF(("CTRL/0x%02x/RTR\n", lp->stype));
155 		ldc_reset(lc);
156 		break;
157 	}
158 }
159 
160 void
161 ldc_rx_data(struct ldc_conn *lc, struct ldc_pkt *lp)
162 {
163 	if (lp->stype != LDC_INFO) {
164 		DPRINTF(("DATA/0x%02x\n", lp->stype));
165 		ldc_reset(lc);
166 		return;
167 	}
168 
169 	if (lc->lc_state != LDC_SND_RTR &&
170 	    lc->lc_state != LDC_SND_RDX) {
171 		DPRINTF(("Spurious DATA/INFO: state %d\n", lc->lc_state));
172 		ldc_reset(lc);
173 		return;
174 	}
175 
176 	lc->lc_rx_data(lc, lp);
177 }
178 
179 void
180 ldc_send_vers(struct ldc_conn *lc)
181 {
182 	struct ldc_pkt *lp;
183 	uint64_t tx_head, tx_tail, tx_state;
184 	int err;
185 
186 	err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
187 	if (err != H_EOK || tx_state != LDC_CHANNEL_UP)
188 		return;
189 
190 	lp = (struct ldc_pkt *)(lc->lc_txq->lq_va + tx_tail);
191 	bzero(lp, sizeof(struct ldc_pkt));
192 	lp->type = LDC_CTRL;
193 	lp->stype = LDC_INFO;
194 	lp->ctrl = LDC_VERS;
195 	lp->major = 1;
196 	lp->minor = 0;
197 
198 	tx_tail += sizeof(*lp);
199 	tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
200 	err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
201 	if (err != H_EOK) {
202 		printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
203 		return;
204 	}
205 
206 	lc->lc_state = LDC_SND_VERS;
207 }
208 
209 void
210 ldc_send_rts(struct ldc_conn *lc)
211 {
212 	struct ldc_pkt *lp;
213 	uint64_t tx_head, tx_tail, tx_state;
214 	int err;
215 
216 	err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
217 	if (err != H_EOK || tx_state != LDC_CHANNEL_UP)
218 		return;
219 
220 	lp = (struct ldc_pkt *)(lc->lc_txq->lq_va + tx_tail);
221 	bzero(lp, sizeof(struct ldc_pkt));
222 	lp->type = LDC_CTRL;
223 	lp->stype = LDC_INFO;
224 	lp->ctrl = LDC_RTS;
225 	lp->env = LDC_MODE_UNRELIABLE;
226 	lp->seqid = lc->lc_tx_seqid++;
227 
228 	tx_tail += sizeof(*lp);
229 	tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
230 	err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
231 	if (err != H_EOK) {
232 		printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
233 		return;
234 	}
235 
236 	lc->lc_state = LDC_SND_RTS;
237 }
238 
239 void
240 ldc_send_rtr(struct ldc_conn *lc)
241 {
242 	struct ldc_pkt *lp;
243 	uint64_t tx_head, tx_tail, tx_state;
244 	int err;
245 
246 	err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
247 	if (err != H_EOK || tx_state != LDC_CHANNEL_UP)
248 		return;
249 
250 	lp = (struct ldc_pkt *)(lc->lc_txq->lq_va + tx_tail);
251 	bzero(lp, sizeof(struct ldc_pkt));
252 	lp->type = LDC_CTRL;
253 	lp->stype = LDC_INFO;
254 	lp->ctrl = LDC_RTR;
255 	lp->env = LDC_MODE_UNRELIABLE;
256 	lp->seqid = lc->lc_tx_seqid++;
257 
258 	tx_tail += sizeof(*lp);
259 	tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
260 	err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
261 	if (err != H_EOK)
262 		printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
263 
264 	lc->lc_state = LDC_SND_RTR;
265 }
266 
267 void
268 ldc_send_rdx(struct ldc_conn *lc)
269 {
270 	struct ldc_pkt *lp;
271 	uint64_t tx_head, tx_tail, tx_state;
272 	int err;
273 
274 	err = hv_ldc_tx_get_state(lc->lc_id, &tx_head, &tx_tail, &tx_state);
275 	if (err != H_EOK || tx_state != LDC_CHANNEL_UP)
276 		return;
277 
278 	lp = (struct ldc_pkt *)(lc->lc_txq->lq_va + tx_tail);
279 	bzero(lp, sizeof(struct ldc_pkt));
280 	lp->type = LDC_CTRL;
281 	lp->stype = LDC_INFO;
282 	lp->ctrl = LDC_RDX;
283 	lp->env = LDC_MODE_UNRELIABLE;
284 	lp->seqid = lc->lc_tx_seqid++;
285 
286 	tx_tail += sizeof(*lp);
287 	tx_tail &= ((lc->lc_txq->lq_nentries * sizeof(*lp)) - 1);
288 	err = hv_ldc_tx_set_qtail(lc->lc_id, tx_tail);
289 	if (err != H_EOK)
290 		printf("%s: hv_ldc_tx_set_qtail: %d\n", __func__, err);
291 
292 	lc->lc_state = LDC_SND_RDX;
293 }
294 
295 void
296 ldc_reset(struct ldc_conn *lc)
297 {
298 	int err;
299 
300 	DPRINTF(("Resetting connection\n"));
301 	hv_ldc_tx_qconf(lc->lc_id, 0, 0);
302 	hv_ldc_rx_qconf(lc->lc_id, 0, 0);
303 	lc->lc_tx_state = lc->lc_rx_state = LDC_CHANNEL_DOWN;
304 
305 	err = hv_ldc_tx_qconf(lc->lc_id,
306 	    lc->lc_txq->lq_map->dm_segs[0].ds_addr, lc->lc_txq->lq_nentries);
307 	if (err != H_EOK)
308 		printf("%s: hv_ldc_tx_qconf %d\n", __func__, err);
309 
310 	err = hv_ldc_rx_qconf(lc->lc_id,
311 	    lc->lc_rxq->lq_map->dm_segs[0].ds_addr, lc->lc_rxq->lq_nentries);
312 	if (err != H_EOK)
313 		printf("%s: hv_ldc_rx_qconf %d\n", __func__, err);
314 
315 	lc->lc_tx_seqid = 0;
316 	lc->lc_state = 0;
317 	lc->lc_reset(lc);
318 }
319 
320 struct ldc_queue *
321 ldc_queue_alloc(bus_dma_tag_t t, int nentries)
322 {
323 	struct ldc_queue *lq;
324 	bus_size_t size;
325 	caddr_t va;
326 	int nsegs;
327 
328 	lq = malloc(sizeof(struct ldc_queue), M_DEVBUF, M_NOWAIT);
329 	if (lq == NULL)
330 		return NULL;
331 
332 	size = roundup(nentries * sizeof(struct ldc_pkt), PAGE_SIZE);
333 
334 	if (bus_dmamap_create(t, size, 1, size, 0,
335 	    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &lq->lq_map) != 0)
336 		return (NULL);
337 
338 	if (bus_dmamem_alloc(t, size, PAGE_SIZE, 0, &lq->lq_seg, 1,
339 	    &nsegs, BUS_DMA_NOWAIT) != 0)
340 		goto destroy;
341 
342 	if (bus_dmamem_map(t, &lq->lq_seg, 1, size, &va,
343 	    BUS_DMA_NOWAIT) != 0)
344 		goto free;
345 
346 	if (bus_dmamap_load(t, lq->lq_map, va, size, NULL,
347 	    BUS_DMA_NOWAIT) != 0)
348 		goto unmap;
349 
350 	lq->lq_va = va;
351 	lq->lq_nentries = nentries;
352 	return (lq);
353 
354 unmap:
355 	bus_dmamem_unmap(t, va, size);
356 free:
357 	bus_dmamem_free(t, &lq->lq_seg, 1);
358 destroy:
359 	bus_dmamap_destroy(t, lq->lq_map);
360 
361 	return (NULL);
362 }
363 
364 void
365 ldc_queue_free(bus_dma_tag_t t, struct ldc_queue *lq)
366 {
367 	bus_size_t size;
368 
369 	size = roundup(lq->lq_nentries * sizeof(struct ldc_pkt), PAGE_SIZE);
370 
371 	bus_dmamap_unload(t, lq->lq_map);
372 	bus_dmamem_unmap(t, lq->lq_va, size);
373 	bus_dmamem_free(t, &lq->lq_seg, 1);
374 	bus_dmamap_destroy(t, lq->lq_map);
375 	free(lq, M_DEVBUF);
376 }
377 
378 struct ldc_map *
379 ldc_map_alloc(bus_dma_tag_t t, int nentries)
380 {
381 	struct ldc_map *lm;
382 	bus_size_t size;
383 	caddr_t va;
384 	int nsegs;
385 
386 	lm = malloc(sizeof(struct ldc_map), M_DEVBUF, M_NOWAIT);
387 	if (lm == NULL)
388 		return NULL;
389 
390 	size = roundup(nentries * sizeof(struct ldc_map_slot), PAGE_SIZE);
391 
392 	if (bus_dmamap_create(t, size, 1, size, 0,
393 	    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &lm->lm_map) != 0)
394 		return (NULL);
395 
396 	if (bus_dmamem_alloc(t, size, PAGE_SIZE, 0, &lm->lm_seg, 1,
397 	    &nsegs, BUS_DMA_NOWAIT) != 0)
398 		goto destroy;
399 
400 	if (bus_dmamem_map(t, &lm->lm_seg, 1, size, &va,
401 	    BUS_DMA_NOWAIT) != 0)
402 		goto free;
403 
404 	if (bus_dmamap_load(t, lm->lm_map, va, size, NULL,
405 	    BUS_DMA_NOWAIT) != 0)
406 		goto unmap;
407 
408 	lm->lm_slot = (struct ldc_map_slot *)va;
409 	lm->lm_nentries = nentries;
410 	bzero(lm->lm_slot, nentries * sizeof(struct ldc_map_slot));
411 	return (lm);
412 
413 unmap:
414 	bus_dmamem_unmap(t, va, size);
415 free:
416 	bus_dmamem_free(t, &lm->lm_seg, 1);
417 destroy:
418 	bus_dmamap_destroy(t, lm->lm_map);
419 
420 	return (NULL);
421 }
422 
423 void
424 ldc_map_free(bus_dma_tag_t t, struct ldc_map *lm)
425 {
426 	bus_size_t size;
427 
428 	size = lm->lm_nentries * sizeof(struct ldc_map_slot);
429 	size = roundup(size, PAGE_SIZE);
430 
431 	bus_dmamap_unload(t, lm->lm_map);
432 	bus_dmamem_unmap(t, (caddr_t)lm->lm_slot, size);
433 	bus_dmamem_free(t, &lm->lm_seg, 1);
434 	bus_dmamap_destroy(t, lm->lm_map);
435 	free(lm, M_DEVBUF);
436 }
437