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