1 /* $OpenBSD: cn30xxfpa.c,v 1.11 2024/05/20 23:13:33 jsg Exp $ */
2
3 /*
4 * Copyright (c) 2007 Internet Initiative Japan, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/malloc.h>
32
33 #include <machine/bus.h>
34 #include <machine/vmparam.h>
35 #include <machine/octeonvar.h>
36
37 #include <octeon/dev/cn30xxfpavar.h>
38 #include <octeon/dev/cn30xxfpareg.h>
39
40 struct cn30xxfpa_softc {
41 int sc_initialized;
42
43 bus_space_tag_t sc_regt;
44 bus_space_handle_t sc_regh;
45
46 bus_dma_tag_t sc_dmat;
47 };
48
49 void cn30xxfpa_bootstrap(struct octeon_config *);
50 void cn30xxfpa_reset(void);
51 void cn30xxfpa_buf_dma_alloc(struct cn30xxfpa_buf *);
52
53 void cn30xxfpa_init(struct cn30xxfpa_softc *);
54 #ifdef notyet
55 uint64_t cn30xxfpa_iobdma(struct cn30xxfpa_softc *, int, int);
56 #endif
57
58 static struct cn30xxfpa_softc cn30xxfpa_softc;
59
60 /* ---- global functions */
61
62 void
cn30xxfpa_bootstrap(struct octeon_config * mcp)63 cn30xxfpa_bootstrap(struct octeon_config *mcp)
64 {
65 struct cn30xxfpa_softc *sc = &cn30xxfpa_softc;
66
67 sc->sc_regt = mcp->mc_iobus_bust;
68 sc->sc_dmat = mcp->mc_iobus_dmat;
69
70 cn30xxfpa_init(sc);
71 }
72
73 void
cn30xxfpa_reset(void)74 cn30xxfpa_reset(void)
75 {
76 /* XXX */
77 }
78
79 int
cn30xxfpa_buf_init(int poolno,size_t size,size_t nelems,struct cn30xxfpa_buf ** rfb)80 cn30xxfpa_buf_init(int poolno, size_t size, size_t nelems,
81 struct cn30xxfpa_buf **rfb)
82 {
83 struct cn30xxfpa_softc *sc = &cn30xxfpa_softc;
84 struct cn30xxfpa_buf *fb;
85 int nsegs;
86 paddr_t paddr;
87
88 nsegs = 1/* XXX */;
89 fb = malloc(sizeof(*fb) + sizeof(*fb->fb_dma_segs) * nsegs, M_DEVBUF,
90 M_WAITOK | M_ZERO);
91 if (fb == NULL)
92 return 1;
93 fb->fb_poolno = poolno;
94 fb->fb_size = size;
95 fb->fb_nelems = nelems;
96 fb->fb_len = size * nelems;
97 fb->fb_dmat = sc->sc_dmat;
98 fb->fb_dma_segs = (void *)(fb + 1);
99 fb->fb_dma_nsegs = nsegs;
100
101 cn30xxfpa_buf_dma_alloc(fb);
102
103 for (paddr = fb->fb_paddr; paddr < fb->fb_paddr + fb->fb_len;
104 paddr += fb->fb_size)
105 cn30xxfpa_buf_put_paddr(fb, paddr);
106
107 *rfb = fb;
108
109 return 0;
110 }
111
112 void *
cn30xxfpa_buf_get(struct cn30xxfpa_buf * fb)113 cn30xxfpa_buf_get(struct cn30xxfpa_buf *fb)
114 {
115 paddr_t paddr;
116 vaddr_t addr;
117
118 paddr = cn30xxfpa_buf_get_paddr(fb);
119 if (paddr == 0)
120 addr = 0;
121 else
122 addr = fb->fb_addr + (vaddr_t/* XXX */)(paddr - fb->fb_paddr);
123 return (void *)addr;
124 }
125
126 void
cn30xxfpa_buf_dma_alloc(struct cn30xxfpa_buf * fb)127 cn30xxfpa_buf_dma_alloc(struct cn30xxfpa_buf *fb)
128 {
129 int status;
130 int nsegs;
131 caddr_t va;
132
133 status = bus_dmamap_create(fb->fb_dmat, fb->fb_len,
134 fb->fb_len / PAGE_SIZE, /* # of segments */
135 fb->fb_len, /* we don't use s/g for FPA buf */
136 PAGE_SIZE, /* OCTEON hates >PAGE_SIZE boundary */
137 0, &fb->fb_dmah);
138 if (status != 0)
139 panic("%s failed", "bus_dmamap_create");
140
141 status = bus_dmamem_alloc(fb->fb_dmat, fb->fb_len, CACHELINESIZE, 0,
142 fb->fb_dma_segs, fb->fb_dma_nsegs, &nsegs, 0);
143 if (status != 0 || fb->fb_dma_nsegs != nsegs)
144 panic("%s failed", "bus_dmamem_alloc");
145
146 status = bus_dmamem_map(fb->fb_dmat, fb->fb_dma_segs, fb->fb_dma_nsegs,
147 fb->fb_len, &va, 0);
148 if (status != 0)
149 panic("%s failed", "bus_dmamem_map");
150
151 status = bus_dmamap_load(fb->fb_dmat, fb->fb_dmah, va, fb->fb_len,
152 NULL, /* kernel */
153 0);
154 if (status != 0)
155 panic("%s failed", "bus_dmamap_load");
156
157 fb->fb_addr = (vaddr_t)va;
158 fb->fb_paddr = fb->fb_dma_segs[0].ds_addr;
159 }
160
161 uint64_t
cn30xxfpa_query(int poolno)162 cn30xxfpa_query(int poolno)
163 {
164 struct cn30xxfpa_softc *sc = &cn30xxfpa_softc;
165
166 return bus_space_read_8(sc->sc_regt, sc->sc_regh,
167 FPA_QUE0_AVAILABLE_OFFSET + sizeof(uint64_t) * poolno);
168 }
169
170 /* ---- local functions */
171
172 void cn30xxfpa_init_regs(struct cn30xxfpa_softc *);
173
174 void
cn30xxfpa_init(struct cn30xxfpa_softc * sc)175 cn30xxfpa_init(struct cn30xxfpa_softc *sc)
176 {
177 if (sc->sc_initialized != 0)
178 panic("%s: already initialized", __func__);
179 sc->sc_initialized = 1;
180
181 cn30xxfpa_init_regs(sc);
182 }
183
184 void
cn30xxfpa_init_regs(struct cn30xxfpa_softc * sc)185 cn30xxfpa_init_regs(struct cn30xxfpa_softc *sc)
186 {
187 int status;
188
189 status = bus_space_map(sc->sc_regt, FPA_BASE, FPA_SIZE, 0,
190 &sc->sc_regh);
191 if (status != 0)
192 panic("%s: could not map FPA registers", __func__);
193
194 bus_space_write_8(sc->sc_regt, sc->sc_regh, FPA_CTL_STATUS_OFFSET,
195 FPA_CTL_STATUS_ENB);
196 }
197