1 /* $NetBSD: mal.c,v 1.6 2026/06/14 00:02:35 rkujawa Exp $ */ 2 /* 3 * Copyright (c) 2010 KIYOHARA Takashi 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 19 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __KERNEL_RCSID(0, "$NetBSD: mal.c,v 1.6 2026/06/14 00:02:35 rkujawa Exp $"); 30 31 #include <sys/param.h> 32 #include <sys/device.h> 33 #include <sys/cpu.h> 34 #include <sys/intr.h> 35 36 #include <powerpc/ibm4xx/cpu.h> 37 #include <powerpc/ibm4xx/dcr4xx.h> 38 #include <powerpc/ibm4xx/dev/if_emacvar.h> 39 #include <powerpc/ibm4xx/dev/malvar.h> 40 #include <powerpc/ibm4xx/spr.h> 41 42 #define STAT_TO_CHAN(stat) __builtin_clz(stat) 43 44 45 static int mal_txeob_intr(void *); 46 static int mal_rxeob_intr(void *); 47 static int mal_txde_intr(void *); 48 static int mal_rxde_intr(void *); 49 static int mal_serr_intr(void *); 50 51 52 const static struct maltbl { 53 int pvr; 54 int intrs[5]; 55 int flags; 56 #define MAL_GEN2 (1<<0) /* Generation 2 (405EX/EXr/440GP/GX/SP/SPe) */ 57 } maltbl[] = { /* TXEOB RXEOB TXDE RXDE SERR */ 58 { IBM405GP, { 11, 12, 13, 14, 10 }, 0 }, 59 { IBM405GPR, { 11, 12, 13, 14, 10 }, 0 }, 60 { AMCC405EX, { 10, 11, 32+ 1, 32+ 2, 32+ 0 }, MAL_GEN2 }, 61 { AMCC460EX, { 64+ 6, 64+ 7, 64+ 4, 64+ 5, 64+ 3 }, MAL_GEN2 } 62 }; 63 64 /* Max channel is 4 on 440GX. Others is 2 or 1. */ 65 static void *iargs[4]; 66 67 68 void 69 mal_attach(int pvr) 70 { 71 int i, to; 72 73 for (i = 0; i < __arraycount(maltbl); i++) 74 if (maltbl[i].pvr == pvr) 75 break; 76 if (i == __arraycount(maltbl)) { 77 aprint_error("%s: unknown pvr 0x%x\n", __func__, pvr); 78 return; 79 } 80 81 /* 82 * Reset MAL. 83 * We wait for the completion of reset in maximums for five seconds. 84 */ 85 mtdcr(DCR_MAL0_CFG, MAL0_CFG_SR); 86 to = 0; 87 while (mfdcr(DCR_MAL0_CFG) & MAL0_CFG_SR) { 88 if (to > 5000) { 89 aprint_error("%s: Soft reset failed\n", __func__); 90 return; 91 } 92 delay(1000); /* delay 1m sec */ 93 to++; 94 } 95 96 /* establish MAL interrupts */ 97 intr_establish_xname(maltbl[i].intrs[0], IST_LEVEL, IPL_NET, 98 mal_txeob_intr, NULL, "mal txeob"); 99 intr_establish_xname(maltbl[i].intrs[1], IST_LEVEL, IPL_NET, 100 mal_rxeob_intr, NULL, "mal rxeob"); 101 intr_establish_xname(maltbl[i].intrs[2], IST_LEVEL, IPL_NET, 102 mal_txde_intr, NULL, "mal txde"); 103 intr_establish_xname(maltbl[i].intrs[3], IST_LEVEL, IPL_NET, 104 mal_rxde_intr, NULL, "mal rxde"); 105 intr_establish_xname(maltbl[i].intrs[4], IST_LEVEL, IPL_NET, 106 mal_serr_intr, NULL, "mal serr"); 107 108 /* Set the MAL configuration register */ 109 if (maltbl[i].flags & MAL_GEN2) 110 mtdcr(DCR_MAL0_CFG, 111 MAL0_CFG_RMBS_32 | 112 MAL0_CFG_WMBS_32 | 113 MAL0_CFG_PLBLT | 114 MAL0_CFG_EOPIE | 115 MAL0_CFG_PLBB | 116 MAL0_CFG_OPBBL | 117 MAL0_CFG_LEA | 118 MAL0_CFG_SD); 119 else 120 mtdcr(DCR_MAL0_CFG, 121 MAL0_CFG_PLBLT | 122 MAL0_CFG_PLBB | 123 MAL0_CFG_OPBBL | 124 MAL0_CFG_LEA | 125 MAL0_CFG_SD); 126 127 /* Enable MAL SERR Interrupt */ 128 mtdcr(DCR_MAL0_IER, 129 MAL0_IER_PT | 130 MAL0_IER_PRE | 131 MAL0_IER_PWE | 132 MAL0_IER_DE | 133 MAL0_IER_NWE | 134 MAL0_IER_TO | 135 MAL0_IER_OPB | 136 MAL0_IER_PLB); 137 } 138 139 static int 140 mal_txeob_intr(void *arg) 141 { 142 uint32_t tcei; 143 int chan, handled = 0; 144 145 while ((tcei = mfdcr(DCR_MAL0_TXEOBISR))) { 146 chan = STAT_TO_CHAN(tcei); 147 if (iargs[chan] != NULL) { 148 mtdcr(DCR_MAL0_TXEOBISR, MAL0__XCAR_CHAN(chan)); 149 handled |= emac_txeob_intr(iargs[chan]); 150 } 151 } 152 return handled; 153 } 154 155 static int 156 mal_rxeob_intr(void *arg) 157 { 158 uint32_t rcei; 159 int chan, handled = 0; 160 161 while ((rcei = mfdcr(DCR_MAL0_RXEOBISR))) { 162 chan = STAT_TO_CHAN(rcei); 163 if (iargs[chan] != NULL) { 164 /* Clear the interrupt */ 165 mtdcr(DCR_MAL0_RXEOBISR, MAL0__XCAR_CHAN(chan)); 166 167 handled |= emac_rxeob_intr(iargs[chan]); 168 } 169 } 170 return handled; 171 } 172 173 static int 174 mal_txde_intr(void *arg) 175 { 176 uint32_t txde; 177 int chan, handled = 0; 178 179 while ((txde = mfdcr(DCR_MAL0_TXDEIR))) { 180 chan = STAT_TO_CHAN(txde); 181 if (iargs[chan] != NULL) { 182 handled |= emac_txde_intr(iargs[chan]); 183 184 /* Clear the interrupt */ 185 mtdcr(DCR_MAL0_TXDEIR, MAL0__XCAR_CHAN(chan)); 186 } 187 } 188 return handled; 189 } 190 191 static int 192 mal_rxde_intr(void *arg) 193 { 194 uint32_t rxde; 195 int chan, handled = 0; 196 197 while ((rxde = mfdcr(DCR_MAL0_RXDEIR))) { 198 chan = STAT_TO_CHAN(rxde); 199 if (iargs[chan] != NULL) { 200 handled |= emac_rxde_intr(iargs[chan]); 201 202 /* Clear the interrupt */ 203 mtdcr(DCR_MAL0_RXDEIR, MAL0__XCAR_CHAN(chan)); 204 205 /* Reenable the receive channel */ 206 mtdcr(DCR_MAL0_RXCASR, MAL0__XCAR_CHAN(chan)); 207 } 208 } 209 return handled; 210 } 211 212 static int 213 mal_serr_intr(void *arg) 214 { 215 uint32_t esr; 216 217 esr = mfdcr(DCR_MAL0_ESR); 218 219 /* not yet... */ 220 aprint_error("MAL SERR: ESR 0x%08x\n", esr); 221 222 /* Clear the interrupt status bits. */ 223 mtdcr(DCR_MAL0_ESR, esr); 224 225 return 1; 226 } 227 228 229 void 230 mal_intr_establish(int chan, void *arg) 231 { 232 233 if (chan >= __arraycount(iargs)) 234 panic("MAL channel %d not support (max %d)\n", 235 chan, __arraycount(iargs)); 236 237 iargs[chan] = arg; 238 } 239 240 int 241 mal_start(int chan, uint32_t cdtxaddr, uint32_t cdrxaddr) 242 { 243 244 /* 245 * Give the transmit and receive rings to the MAL. 246 * And set the receive channel buffer size (in units of 16 bytes). 247 */ 248 #if MCLBYTES > (4096 - 16) /* XXX! */ 249 # error MCLBYTES > max rx channel buffer size 250 #endif 251 /* The mtdcr() allows only the constant in the first argument... */ 252 switch (chan) { 253 case 0: 254 mtdcr(DCR_MAL0_TXCTP0R, cdtxaddr); 255 mtdcr(DCR_MAL0_RXCTP0R, cdrxaddr); 256 mtdcr(DCR_MAL0_RCBS0, MCLBYTES / 16); 257 break; 258 259 case 1: 260 mtdcr(DCR_MAL0_TXCTP1R, cdtxaddr); 261 mtdcr(DCR_MAL0_RXCTP1R, cdrxaddr); 262 mtdcr(DCR_MAL0_RCBS1, MCLBYTES / 16); 263 break; 264 265 case 2: 266 mtdcr(DCR_MAL0_TXCTP2R, cdtxaddr); 267 mtdcr(DCR_MAL0_RXCTP2R, cdrxaddr); 268 mtdcr(DCR_MAL0_RCBS2, MCLBYTES / 16); 269 break; 270 271 case 3: 272 mtdcr(DCR_MAL0_TXCTP3R, cdtxaddr); 273 mtdcr(DCR_MAL0_RXCTP3R, cdrxaddr); 274 mtdcr(DCR_MAL0_RCBS3, MCLBYTES / 16); 275 break; 276 277 default: 278 aprint_error("MAL unknown channel no.%d\n", chan); 279 return EINVAL; 280 } 281 282 /* Enable the transmit and receive channel on the MAL. */ 283 mtdcr(DCR_MAL0_RXCASR, MAL0__XCAR_CHAN(chan)); 284 mtdcr(DCR_MAL0_TXCASR, MAL0__XCAR_CHAN(chan)); 285 286 return 0; 287 } 288 289 void 290 mal_stop(int chan) 291 { 292 293 /* Disable the receive and transmit channels. */ 294 mtdcr(DCR_MAL0_RXCARR, MAL0__XCAR_CHAN(chan)); 295 mtdcr(DCR_MAL0_TXCARR, MAL0__XCAR_CHAN(chan)); 296 } 297