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
26struct msi_msg {
27	uint64_t mm_data[8];
28};
29
30struct msi_eq *
31msi_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
68unmap:
69	bus_dmamem_unmap(t, va, size);
70free:
71	bus_dmamem_free(t, &meq->meq_seg, 1);
72destroy:
73	bus_dmamap_destroy(t, meq->meq_map);
74
75	return (NULL);
76}
77
78void
79msi_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
88size_t
89msi_eq_offset(struct msi_eq *meq, int eq)
90{
91	return (meq->meq_queuesize * eq);
92}
93