1 /* $OpenBSD: cn30xxfpa.c,v 1.10 2022/12/28 01:39:21 yasuoka 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_int_enable(struct cn30xxfpa_softc *, int); 52 void cn30xxfpa_buf_dma_alloc(struct cn30xxfpa_buf *); 53 54 void cn30xxfpa_init(struct cn30xxfpa_softc *); 55 #ifdef notyet 56 uint64_t cn30xxfpa_iobdma(struct cn30xxfpa_softc *, int, int); 57 #endif 58 59 static struct cn30xxfpa_softc cn30xxfpa_softc; 60 61 /* ---- global functions */ 62 63 void 64 cn30xxfpa_bootstrap(struct octeon_config *mcp) 65 { 66 struct cn30xxfpa_softc *sc = &cn30xxfpa_softc; 67 68 sc->sc_regt = mcp->mc_iobus_bust; 69 sc->sc_dmat = mcp->mc_iobus_dmat; 70 71 cn30xxfpa_init(sc); 72 } 73 74 void 75 cn30xxfpa_reset(void) 76 { 77 /* XXX */ 78 } 79 80 int 81 cn30xxfpa_buf_init(int poolno, size_t size, size_t nelems, 82 struct cn30xxfpa_buf **rfb) 83 { 84 struct cn30xxfpa_softc *sc = &cn30xxfpa_softc; 85 struct cn30xxfpa_buf *fb; 86 int nsegs; 87 paddr_t paddr; 88 89 nsegs = 1/* XXX */; 90 fb = malloc(sizeof(*fb) + sizeof(*fb->fb_dma_segs) * nsegs, M_DEVBUF, 91 M_WAITOK | M_ZERO); 92 if (fb == NULL) 93 return 1; 94 fb->fb_poolno = poolno; 95 fb->fb_size = size; 96 fb->fb_nelems = nelems; 97 fb->fb_len = size * nelems; 98 fb->fb_dmat = sc->sc_dmat; 99 fb->fb_dma_segs = (void *)(fb + 1); 100 fb->fb_dma_nsegs = nsegs; 101 102 cn30xxfpa_buf_dma_alloc(fb); 103 104 for (paddr = fb->fb_paddr; paddr < fb->fb_paddr + fb->fb_len; 105 paddr += fb->fb_size) 106 cn30xxfpa_buf_put_paddr(fb, paddr); 107 108 *rfb = fb; 109 110 return 0; 111 } 112 113 void * 114 cn30xxfpa_buf_get(struct cn30xxfpa_buf *fb) 115 { 116 paddr_t paddr; 117 vaddr_t addr; 118 119 paddr = cn30xxfpa_buf_get_paddr(fb); 120 if (paddr == 0) 121 addr = 0; 122 else 123 addr = fb->fb_addr + (vaddr_t/* XXX */)(paddr - fb->fb_paddr); 124 return (void *)addr; 125 } 126 127 void 128 cn30xxfpa_buf_dma_alloc(struct cn30xxfpa_buf *fb) 129 { 130 int status; 131 int nsegs; 132 caddr_t va; 133 134 status = bus_dmamap_create(fb->fb_dmat, fb->fb_len, 135 fb->fb_len / PAGE_SIZE, /* # of segments */ 136 fb->fb_len, /* we don't use s/g for FPA buf */ 137 PAGE_SIZE, /* OCTEON hates >PAGE_SIZE boundary */ 138 0, &fb->fb_dmah); 139 if (status != 0) 140 panic("%s failed", "bus_dmamap_create"); 141 142 status = bus_dmamem_alloc(fb->fb_dmat, fb->fb_len, CACHELINESIZE, 0, 143 fb->fb_dma_segs, fb->fb_dma_nsegs, &nsegs, 0); 144 if (status != 0 || fb->fb_dma_nsegs != nsegs) 145 panic("%s failed", "bus_dmamem_alloc"); 146 147 status = bus_dmamem_map(fb->fb_dmat, fb->fb_dma_segs, fb->fb_dma_nsegs, 148 fb->fb_len, &va, 0); 149 if (status != 0) 150 panic("%s failed", "bus_dmamem_map"); 151 152 status = bus_dmamap_load(fb->fb_dmat, fb->fb_dmah, va, fb->fb_len, 153 NULL, /* kernel */ 154 0); 155 if (status != 0) 156 panic("%s failed", "bus_dmamap_load"); 157 158 fb->fb_addr = (vaddr_t)va; 159 fb->fb_paddr = fb->fb_dma_segs[0].ds_addr; 160 } 161 162 uint64_t 163 cn30xxfpa_query(int poolno) 164 { 165 struct cn30xxfpa_softc *sc = &cn30xxfpa_softc; 166 167 return bus_space_read_8(sc->sc_regt, sc->sc_regh, 168 FPA_QUE0_AVAILABLE_OFFSET + sizeof(uint64_t) * poolno); 169 } 170 171 /* ---- local functions */ 172 173 void cn30xxfpa_init_regs(struct cn30xxfpa_softc *); 174 175 void 176 cn30xxfpa_init(struct cn30xxfpa_softc *sc) 177 { 178 if (sc->sc_initialized != 0) 179 panic("%s: already initialized", __func__); 180 sc->sc_initialized = 1; 181 182 cn30xxfpa_init_regs(sc); 183 } 184 185 void 186 cn30xxfpa_init_regs(struct cn30xxfpa_softc *sc) 187 { 188 int status; 189 190 status = bus_space_map(sc->sc_regt, FPA_BASE, FPA_SIZE, 0, 191 &sc->sc_regh); 192 if (status != 0) 193 panic("%s: could not map FPA registers", __func__); 194 195 bus_space_write_8(sc->sc_regt, sc->sc_regh, FPA_CTL_STATUS_OFFSET, 196 FPA_CTL_STATUS_ENB); 197 } 198