xref: /openbsd/sys/arch/sparc64/dev/msi.c (revision 1d9e937e)
1 /*	$OpenBSD: msi.c,v 1.5 2020/06/23 01:21:29 jmatthew Exp $	*/
2 /*
3  * Copyright (c) 2011 Mark Kettenis <kettenis@openbsd.org>
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/device.h>
20 #include <sys/malloc.h>
21 
22 #include <machine/bus.h>
23 
24 #include <sparc64/dev/msivar.h>
25 
26 struct msi_msg {
27 	uint64_t mm_data[8];
28 };
29 
30 struct msi_eq *
msi_eq_alloc(bus_dma_tag_t t,int msi_eq_size,int num_eq)31 msi_eq_alloc(bus_dma_tag_t t, int msi_eq_size, int num_eq)
32 {
33 	struct msi_eq *meq;
34 	bus_size_t eqsize, size;
35 	caddr_t va;
36 	int nsegs;
37 
38 	meq = malloc(sizeof(struct msi_eq), M_DEVBUF, M_NOWAIT);
39 	if (meq == NULL)
40 		return NULL;
41 
42 	eqsize = roundup(msi_eq_size * sizeof(struct msi_msg),
43 	    PAGE_SIZE);
44 	size = num_eq * eqsize;
45 
46 	if (bus_dmamap_create(t, size, 1, size, 0,
47 	    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &meq->meq_map) != 0)
48 		return (NULL);
49 
50 	if (bus_dmamem_alloc(t, size, eqsize, 0, &meq->meq_seg, 1,
51 	    &nsegs, BUS_DMA_NOWAIT) != 0)
52 		goto destroy;
53 
54 	if (bus_dmamem_map(t, &meq->meq_seg, 1, size, &va,
55 	    BUS_DMA_NOWAIT) != 0)
56 		goto free;
57 
58 	if (bus_dmamap_load(t, meq->meq_map, va, size, NULL,
59 	    BUS_DMA_NOWAIT) != 0)
60 		goto unmap;
61 
62 	meq->meq_va = va;
63 	meq->meq_nentries = msi_eq_size;
64 	meq->meq_queuesize = eqsize;
65 	meq->meq_nqueues = num_eq;
66 	return (meq);
67 
68 unmap:
69 	bus_dmamem_unmap(t, va, size);
70 free:
71 	bus_dmamem_free(t, &meq->meq_seg, 1);
72 destroy:
73 	bus_dmamap_destroy(t, meq->meq_map);
74 
75 	return (NULL);
76 }
77 
78 void
msi_eq_free(bus_dma_tag_t t,struct msi_eq * meq)79 msi_eq_free(bus_dma_tag_t t, struct msi_eq *meq)
80 {
81 	bus_dmamap_unload(t, meq->meq_map);
82 	bus_dmamem_unmap(t, meq->meq_va, meq->meq_nqueues * meq->meq_queuesize);
83 	bus_dmamem_free(t, &meq->meq_seg, 1);
84 	bus_dmamap_destroy(t, meq->meq_map);
85 	free(meq, M_DEVBUF, sizeof *meq);
86 }
87 
88 size_t
msi_eq_offset(struct msi_eq * meq,int eq)89 msi_eq_offset(struct msi_eq *meq, int eq)
90 {
91 	return (meq->meq_queuesize * eq);
92 }
93