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