1 /* $NetBSD: octeon_fpa.c,v 1.10 2021/03/24 08:10:14 simonb 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 REGENTS 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 REGENTS 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 #undef FPADEBUG 30 31 #include <sys/cdefs.h> 32 __KERNEL_RCSID(0, "$NetBSD: octeon_fpa.c,v 1.10 2021/03/24 08:10:14 simonb Exp $"); 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/types.h> 37 #include <sys/kmem.h> 38 39 #include <sys/bus.h> 40 #include <machine/locore.h> 41 #include <machine/vmparam.h> 42 43 #include <mips/cavium/octeonvar.h> 44 #include <mips/cavium/include/iobusvar.h> 45 #include <mips/cavium/dev/octeon_fpareg.h> 46 #include <mips/cavium/dev/octeon_fpavar.h> 47 48 #ifdef FPADEBUG 49 #define DPRINTF(x) printf x 50 #else 51 #define DPRINTF(x) 52 #endif 53 54 #define _DMA_NSEGS 1 55 #define _DMA_BUFLEN 0x01000000 56 57 struct octfpa_softc { 58 int sc_initialized; 59 60 bus_space_tag_t sc_regt; 61 bus_space_handle_t sc_regh; 62 63 bus_space_tag_t sc_opst; 64 bus_space_handle_t sc_opsh; 65 66 bus_dma_tag_t sc_dmat; 67 }; 68 69 void octfpa_bootstrap(struct octeon_config *); 70 void octfpa_reset(void); 71 void octfpa_int_enable(struct octfpa_softc *, int); 72 void octfpa_buf_dma_alloc(struct octfpa_buf *); 73 74 static void octfpa_init(struct octfpa_softc *); 75 #ifdef notyet 76 static uint64_t octfpa_iobdma(struct octfpa_softc *, int, int); 77 #endif 78 79 static struct octfpa_softc octfpa_softc; 80 81 /* ---- global functions */ 82 83 void 84 octfpa_bootstrap(struct octeon_config *mcp) 85 { 86 struct octfpa_softc *sc = &octfpa_softc; 87 88 sc->sc_regt = &mcp->mc_iobus_bust; 89 sc->sc_opst = &mcp->mc_iobus_bust; 90 sc->sc_dmat = &mcp->mc_iobus_dmat; 91 92 octfpa_init(sc); 93 } 94 95 void 96 octfpa_reset(void) 97 { 98 /* XXX */ 99 } 100 101 int 102 octfpa_buf_init(int poolno, size_t size, size_t nelems, struct octfpa_buf **rfb) 103 { 104 struct octfpa_softc *sc = &octfpa_softc; 105 struct octfpa_buf *fb; 106 int nsegs; 107 paddr_t paddr; 108 109 nsegs = 1/* XXX */; 110 fb = kmem_zalloc(sizeof(*fb) + sizeof(*fb->fb_dma_segs) * nsegs, 111 KM_SLEEP); 112 fb->fb_poolno = poolno; 113 fb->fb_size = size; 114 fb->fb_nelems = nelems; 115 fb->fb_len = size * nelems; 116 fb->fb_dmat = sc->sc_dmat; 117 fb->fb_dma_segs = (void *)(fb + 1); 118 fb->fb_dma_nsegs = nsegs; 119 120 octfpa_buf_dma_alloc(fb); 121 122 for (paddr = fb->fb_paddr; paddr < fb->fb_paddr + fb->fb_len; 123 paddr += fb->fb_size) 124 octfpa_buf_put_paddr(fb, paddr); 125 126 *rfb = fb; 127 128 return 0; 129 } 130 131 void * 132 octfpa_buf_get(struct octfpa_buf *fb) 133 { 134 paddr_t paddr; 135 vaddr_t addr; 136 137 paddr = octfpa_buf_get_paddr(fb); 138 if (paddr == 0) 139 addr = 0; 140 else 141 addr = fb->fb_addr + (vaddr_t/* XXX */)(paddr - fb->fb_paddr); 142 return (void *)addr; 143 } 144 145 void 146 octfpa_buf_dma_alloc(struct octfpa_buf *fb) 147 { 148 int status; 149 int nsegs; 150 void *va; 151 152 status = bus_dmamap_create(fb->fb_dmat, fb->fb_len, 153 fb->fb_len / PAGE_SIZE, /* # of segments */ 154 fb->fb_len, /* we don't use s/g for FPA buf */ 155 PAGE_SIZE, /* OCTEON hates >PAGE_SIZE boundary */ 156 0, &fb->fb_dmah); 157 if (status != 0) 158 panic("%s failed", "bus_dmamap_create"); 159 160 status = bus_dmamem_alloc(fb->fb_dmat, fb->fb_len, 128, 0, 161 fb->fb_dma_segs, fb->fb_dma_nsegs, &nsegs, 0); 162 if (status != 0 || fb->fb_dma_nsegs != nsegs) 163 panic("%s failed", "bus_dmamem_alloc"); 164 165 status = bus_dmamem_map(fb->fb_dmat, fb->fb_dma_segs, fb->fb_dma_nsegs, 166 fb->fb_len, &va, 0); 167 if (status != 0) 168 panic("%s failed", "bus_dmamem_map"); 169 170 status = bus_dmamap_load(fb->fb_dmat, fb->fb_dmah, va, fb->fb_len, 171 NULL, /* kernel */ 172 0); 173 if (status != 0) 174 panic("%s failed", "bus_dmamap_load"); 175 176 fb->fb_addr = (vaddr_t)va; 177 fb->fb_paddr = fb->fb_dma_segs[0].ds_addr; 178 } 179 180 uint64_t 181 octfpa_query(int poolno) 182 { 183 struct octfpa_softc *sc = &octfpa_softc; 184 185 return bus_space_read_8(sc->sc_regt, sc->sc_regh, 186 FPA_QUE0_AVAILABLE_OFFSET + sizeof(uint64_t) * poolno); 187 } 188 189 /* ---- local functions */ 190 191 static inline void octfpa_init_bus(struct octfpa_softc *); 192 static inline void octfpa_init_bus_space(struct octfpa_softc *); 193 static inline void octfpa_init_regs(struct octfpa_softc *); 194 195 void 196 octfpa_init(struct octfpa_softc *sc) 197 { 198 if (sc->sc_initialized != 0) 199 panic("%s: already initialized", __func__); 200 sc->sc_initialized = 1; 201 202 octfpa_init_bus(sc); 203 octfpa_init_regs(sc); 204 } 205 206 void 207 octfpa_init_bus(struct octfpa_softc *sc) 208 { 209 210 octfpa_init_bus_space(sc); 211 } 212 213 void 214 octfpa_init_bus_space(struct octfpa_softc *sc) 215 { 216 int status; 217 218 status = bus_space_map(sc->sc_regt, FPA_BASE, FPA_SIZE, 0, &sc->sc_regh); 219 if (status != 0) 220 panic("can't map %s space", "register"); 221 222 status = bus_space_map(sc->sc_opst, 223 0x0001180028000000ULL/* XXX */, 0x0200/* XXX */, 0, &sc->sc_opsh); 224 if (status != 0) 225 panic("can't map %s space", "operations"); 226 } 227 228 void 229 octfpa_init_regs(struct octfpa_softc *sc) 230 { 231 232 bus_space_write_8(sc->sc_regt, sc->sc_regh, FPA_CTL_STATUS_OFFSET, 233 FPA_CTL_STATUS_ENB); 234 } 235 236 int 237 octfpa_available_fpa_pool(int *available, int pool_no) { 238 struct octfpa_softc *sc = &octfpa_softc; 239 size_t offset; 240 uint64_t tmp; 241 242 switch (pool_no) { 243 case OCTEON_POOL_NO_PKT: 244 offset = FPA_QUE0_AVAILABLE_OFFSET; 245 break; 246 case OCTEON_POOL_NO_WQE: 247 offset = FPA_QUE1_AVAILABLE_OFFSET; 248 break; 249 case OCTEON_POOL_NO_CMD: 250 offset = FPA_QUE2_AVAILABLE_OFFSET; 251 break; 252 case OCTEON_POOL_NO_SG: 253 offset = FPA_QUE3_AVAILABLE_OFFSET; 254 break; 255 case OCTEON_POOL_NO_XXX_4: 256 offset = FPA_QUE4_AVAILABLE_OFFSET; 257 break; 258 case OCTEON_POOL_NO_XXX_5: 259 offset = FPA_QUE5_AVAILABLE_OFFSET; 260 break; 261 case OCTEON_POOL_NO_XXX_6: 262 offset = FPA_QUE6_AVAILABLE_OFFSET; 263 break; 264 case OCTEON_POOL_NO_DUMP: 265 offset = FPA_QUE7_AVAILABLE_OFFSET; 266 break; 267 default: 268 return EINVAL; 269 } 270 tmp = bus_space_read_8(sc->sc_regt, sc->sc_regh, offset); 271 if (available) { 272 *available = (int)(tmp & FPA_QUEX_AVAILABLE_QUE_SIZ); 273 } 274 275 return 0; 276 } 277