1 /* $NetBSD: octeon_asx.c,v 1.1 2015/04/29 08:32:01 hikaru 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 #include <sys/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: octeon_asx.c,v 1.1 2015/04/29 08:32:01 hikaru Exp $"); 31 32 #include "opt_octeon.h" 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/malloc.h> 37 #include <mips/cavium/octeonvar.h> 38 #include <mips/cavium/dev/octeon_asxreg.h> 39 #include <mips/cavium/dev/octeon_asxvar.h> 40 41 #ifdef OCTEON_ETH_DEBUG 42 void octeon_asx_intr_evcnt_attach(struct octeon_asx_softc *); 43 void octeon_asx_intr_rml(void *); 44 #endif 45 46 #ifdef OCTEON_ETH_DEBUG 47 struct octeon_asx_softc *__octeon_asx_softc; 48 #endif 49 50 /* XXX */ 51 void 52 octeon_asx_init(struct octeon_asx_attach_args *aa, 53 struct octeon_asx_softc **rsc) 54 { 55 struct octeon_asx_softc *sc; 56 int status; 57 58 sc = malloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); 59 if (sc == NULL) 60 panic("can't allocate memory: %s", __func__); 61 62 sc->sc_port = aa->aa_port; 63 sc->sc_regt = aa->aa_regt; 64 65 status = bus_space_map(sc->sc_regt, ASX0_BASE, ASX0_SIZE, 0, 66 &sc->sc_regh); 67 if (status != 0) 68 panic("can't map %s space", "asx register"); 69 70 *rsc = sc; 71 72 #ifdef OCTEON_ETH_DEBUG 73 octeon_asx_intr_evcnt_attach(sc); 74 if (__octeon_asx_softc == NULL) 75 __octeon_asx_softc = sc; 76 #endif 77 } 78 79 #define _ASX_RD8(sc, off) \ 80 bus_space_read_8((sc)->sc_regt, (sc)->sc_regh, (off)) 81 #define _ASX_WR8(sc, off, v) \ 82 bus_space_write_8((sc)->sc_regt, (sc)->sc_regh, (off), (v)) 83 84 static int octeon_asx_enable_tx(struct octeon_asx_softc *, int); 85 static int octeon_asx_enable_rx(struct octeon_asx_softc *, int); 86 #ifdef OCTEON_ETH_DEBUG 87 static int octeon_asx_enable_intr(struct octeon_asx_softc *, int); 88 #endif 89 90 int 91 octeon_asx_enable(struct octeon_asx_softc *sc, int enable) 92 { 93 94 #ifdef OCTEON_ETH_DEBUG 95 octeon_asx_enable_intr(sc, enable); 96 #endif 97 octeon_asx_enable_tx(sc, enable); 98 octeon_asx_enable_rx(sc, enable); 99 return 0; 100 } 101 102 static int 103 octeon_asx_enable_tx(struct octeon_asx_softc *sc, int enable) 104 { 105 uint64_t asx_tx_port; 106 107 asx_tx_port = _ASX_RD8(sc, ASX0_TX_PRT_EN_OFFSET); 108 if (enable) 109 SET(asx_tx_port, 1 << sc->sc_port); 110 else 111 CLR(asx_tx_port, 1 << sc->sc_port); 112 _ASX_WR8(sc, ASX0_TX_PRT_EN_OFFSET, asx_tx_port); 113 return 0; 114 } 115 116 static int 117 octeon_asx_enable_rx(struct octeon_asx_softc *sc, int enable) 118 { 119 uint64_t asx_rx_port; 120 121 asx_rx_port = _ASX_RD8(sc, ASX0_RX_PRT_EN_OFFSET); 122 if (enable) 123 SET(asx_rx_port, 1 << sc->sc_port); 124 else 125 CLR(asx_rx_port, 1 << sc->sc_port); 126 _ASX_WR8(sc, ASX0_RX_PRT_EN_OFFSET, asx_rx_port); 127 return 0; 128 } 129 130 #if defined(OCTEON_ETH_DEBUG) 131 int octeon_asx_intr_rml_verbose; 132 133 static const struct octeon_evcnt_entry octeon_asx_intr_evcnt_entries[] = { 134 #define _ENTRY(name, type, parent, descr) \ 135 OCTEON_EVCNT_ENTRY(struct octeon_asx_softc, name, type, parent, descr) 136 _ENTRY(asxrxpsh, MISC, NULL, "asx tx fifo overflow"), 137 _ENTRY(asxtxpop, MISC, NULL, "asx tx fifo underflow"), 138 _ENTRY(asxovrflw, MISC, NULL, "asx rx fifo overflow"), 139 #undef _ENTRY 140 }; 141 142 void 143 octeon_asx_intr_evcnt_attach(struct octeon_asx_softc *sc) 144 { 145 OCTEON_EVCNT_ATTACH_EVCNTS(sc, octeon_asx_intr_evcnt_entries, "asx0"); 146 } 147 148 void 149 octeon_asx_intr_rml(void *arg) 150 { 151 struct octeon_asx_softc *sc = __octeon_asx_softc; 152 uint64_t reg = 0; 153 154 reg = octeon_asx_int_summary(sc); 155 if (octeon_asx_intr_rml_verbose) 156 printf("%s: ASX_INT_REG=0x%016" PRIx64 "\n", __func__, reg); 157 if (reg & ASX0_INT_REG_TXPSH) 158 OCTEON_EVCNT_INC(sc, asxrxpsh); 159 if (reg & ASX0_INT_REG_TXPOP) 160 OCTEON_EVCNT_INC(sc, asxtxpop); 161 if (reg & ASX0_INT_REG_OVRFLW) 162 OCTEON_EVCNT_INC(sc, asxovrflw); 163 } 164 165 static int 166 octeon_asx_enable_intr(struct octeon_asx_softc *sc, int enable) 167 { 168 uint64_t asx_int_xxx = 0; 169 170 SET(asx_int_xxx, 171 ASX0_INT_REG_TXPSH | 172 ASX0_INT_REG_TXPOP | 173 ASX0_INT_REG_OVRFLW); 174 _ASX_WR8(sc, ASX0_INT_REG_OFFSET, asx_int_xxx); 175 _ASX_WR8(sc, ASX0_INT_EN_OFFSET, enable ? asx_int_xxx : 0); 176 return 0; 177 } 178 #endif 179 180 int 181 octeon_asx_clk_set(struct octeon_asx_softc *sc, int tx_setting, int rx_setting) 182 { 183 _ASX_WR8(sc, ASX0_TX_CLK_SET0_OFFSET + 8 * sc->sc_port, tx_setting); 184 _ASX_WR8(sc, ASX0_RX_CLK_SET0_OFFSET + 8 * sc->sc_port, rx_setting); 185 return 0; 186 } 187 188 #ifdef OCTEON_ETH_DEBUG 189 uint64_t 190 octeon_asx_int_summary(struct octeon_asx_softc *sc) 191 { 192 uint64_t summary; 193 194 summary = _ASX_RD8(sc, ASX0_INT_REG_OFFSET); 195 _ASX_WR8(sc, ASX0_INT_REG_OFFSET, summary); 196 return summary; 197 } 198 199 #define _ENTRY(x) { #x, x##_BITS, x##_OFFSET } 200 201 struct octeon_asx_dump_reg_ { 202 const char *name; 203 const char *format; 204 size_t offset; 205 }; 206 207 void octeon_asx_dump(void); 208 209 static const struct octeon_asx_dump_reg_ octeon_asx_dump_regs_[] = { 210 _ENTRY(ASX0_RX_PRT_EN), 211 _ENTRY(ASX0_TX_PRT_EN), 212 _ENTRY(ASX0_INT_REG), 213 _ENTRY(ASX0_INT_EN), 214 _ENTRY(ASX0_RX_CLK_SET0), 215 _ENTRY(ASX0_RX_CLK_SET1), 216 _ENTRY(ASX0_RX_CLK_SET2), 217 _ENTRY(ASX0_PRT_LOOP), 218 _ENTRY(ASX0_TX_CLK_SET0), 219 _ENTRY(ASX0_TX_CLK_SET1), 220 _ENTRY(ASX0_TX_CLK_SET2), 221 _ENTRY(ASX0_COMP_BYP), 222 _ENTRY(ASX0_TX_HI_WATER000), 223 _ENTRY(ASX0_TX_HI_WATER001), 224 _ENTRY(ASX0_TX_HI_WATER002), 225 _ENTRY(ASX0_GMII_RX_CLK_SET), 226 _ENTRY(ASX0_GMII_RX_DAT_SET), 227 _ENTRY(ASX0_MII_RX_DAT_SET), 228 }; 229 230 void 231 octeon_asx_dump(void) 232 { 233 struct octeon_asx_softc *sc = __octeon_asx_softc; 234 const struct octeon_asx_dump_reg_ *reg; 235 uint64_t tmp; 236 char buf[512]; 237 int i; 238 239 for (i = 0; i < (int)__arraycount(octeon_asx_dump_regs_); i++) { 240 reg = &octeon_asx_dump_regs_[i]; 241 tmp = _ASX_RD8(sc, reg->offset); 242 if (reg->format == NULL) 243 snprintf(buf, sizeof(buf), "%016" PRIx64, tmp); 244 else 245 snprintb(buf, sizeof(buf), reg->format, tmp); 246 printf("\t%-24s: %s\n", reg->name, buf); 247 } 248 } 249 #endif 250