xref: /openbsd/sys/arch/sparc64/dev/msi.c (revision 898184e3)
1 /*	$OpenBSD: msi.c,v 1.1 2011/07/06 05:35:53 kettenis 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 *
31 msi_eq_alloc(bus_dma_tag_t t, int msi_eq_size)
32 {
33 	struct msi_eq *meq;
34 	bus_size_t 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 	size = roundup(msi_eq_size * sizeof(struct msi_msg), PAGE_SIZE);
43 
44 	if (bus_dmamap_create(t, size, 1, size, 0,
45 	    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW, &meq->meq_map) != 0)
46 		return (NULL);
47 
48 	if (bus_dmamem_alloc(t, size, PAGE_SIZE, 0, &meq->meq_seg, 1,
49 	    &nsegs, BUS_DMA_NOWAIT) != 0)
50 		goto destroy;
51 
52 	if (bus_dmamem_map(t, &meq->meq_seg, 1, size, &va,
53 	    BUS_DMA_NOWAIT) != 0)
54 		goto free;
55 
56 	if (bus_dmamap_load(t, meq->meq_map, va, size, NULL,
57 	    BUS_DMA_NOWAIT) != 0)
58 		goto unmap;
59 
60 	meq->meq_va = va;
61 	meq->meq_nentries = msi_eq_size;
62 	return (meq);
63 
64 unmap:
65 	bus_dmamem_unmap(t, va, size);
66 free:
67 	bus_dmamem_free(t, &meq->meq_seg, 1);
68 destroy:
69 	bus_dmamap_destroy(t, meq->meq_map);
70 
71 	return (NULL);
72 }
73 
74 void
75 msi_eq_free(bus_dma_tag_t t, struct msi_eq *meq)
76 {
77 	bus_size_t size;
78 
79 	size = roundup(meq->meq_nentries * sizeof(struct msi_msg), PAGE_SIZE);
80 
81 	bus_dmamap_unload(t, meq->meq_map);
82 	bus_dmamem_unmap(t, meq->meq_va, size);
83 	bus_dmamem_free(t, &meq->meq_seg, 1);
84 	bus_dmamap_destroy(t, meq->meq_map);
85 	free(meq, M_DEVBUF);
86 }
87