1 /* $NetBSD: mal.c,v 1.5 2023/06/19 08:40:30 msaitoh 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.5 2023/06/19 08:40:30 msaitoh 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 };
62
63 /* Max channel is 4 on 440GX. Others is 2 or 1. */
64 static void *iargs[4];
65
66
67 void
mal_attach(int pvr)68 mal_attach(int pvr)
69 {
70 int i, to;
71
72 for (i = 0; i < __arraycount(maltbl); i++)
73 if (maltbl[i].pvr == pvr)
74 break;
75 if (i == __arraycount(maltbl)) {
76 aprint_error("%s: unknown pvr 0x%x\n", __func__, pvr);
77 return;
78 }
79
80 /*
81 * Reset MAL.
82 * We wait for the completion of reset in maximums for five seconds.
83 */
84 mtdcr(DCR_MAL0_CFG, MAL0_CFG_SR);
85 to = 0;
86 while (mfdcr(DCR_MAL0_CFG) & MAL0_CFG_SR) {
87 if (to > 5000) {
88 aprint_error("%s: Soft reset failed\n", __func__);
89 return;
90 }
91 delay(1000); /* delay 1m sec */
92 to++;
93 }
94
95 /* establish MAL interrupts */
96 intr_establish_xname(maltbl[i].intrs[0], IST_LEVEL, IPL_NET,
97 mal_txeob_intr, NULL, "mal txeob");
98 intr_establish_xname(maltbl[i].intrs[1], IST_LEVEL, IPL_NET,
99 mal_rxeob_intr, NULL, "mal rxeob");
100 intr_establish_xname(maltbl[i].intrs[2], IST_LEVEL, IPL_NET,
101 mal_txde_intr, NULL, "mal txde");
102 intr_establish_xname(maltbl[i].intrs[3], IST_LEVEL, IPL_NET,
103 mal_rxde_intr, NULL, "mal rxde");
104 intr_establish_xname(maltbl[i].intrs[4], IST_LEVEL, IPL_NET,
105 mal_serr_intr, NULL, "mal serr");
106
107 /* Set the MAL configuration register */
108 if (maltbl[i].flags & MAL_GEN2)
109 mtdcr(DCR_MAL0_CFG,
110 MAL0_CFG_RMBS_32 |
111 MAL0_CFG_WMBS_32 |
112 MAL0_CFG_PLBLT |
113 MAL0_CFG_EOPIE |
114 MAL0_CFG_PLBB |
115 MAL0_CFG_OPBBL |
116 MAL0_CFG_LEA |
117 MAL0_CFG_SD);
118 else
119 mtdcr(DCR_MAL0_CFG,
120 MAL0_CFG_PLBLT |
121 MAL0_CFG_PLBB |
122 MAL0_CFG_OPBBL |
123 MAL0_CFG_LEA |
124 MAL0_CFG_SD);
125
126 /* Enable MAL SERR Interrupt */
127 mtdcr(DCR_MAL0_IER,
128 MAL0_IER_PT |
129 MAL0_IER_PRE |
130 MAL0_IER_PWE |
131 MAL0_IER_DE |
132 MAL0_IER_NWE |
133 MAL0_IER_TO |
134 MAL0_IER_OPB |
135 MAL0_IER_PLB);
136 }
137
138 static int
mal_txeob_intr(void * arg)139 mal_txeob_intr(void *arg)
140 {
141 uint32_t tcei;
142 int chan, handled = 0;
143
144 while ((tcei = mfdcr(DCR_MAL0_TXEOBISR))) {
145 chan = STAT_TO_CHAN(tcei);
146 if (iargs[chan] != NULL) {
147 mtdcr(DCR_MAL0_TXEOBISR, MAL0__XCAR_CHAN(chan));
148 handled |= emac_txeob_intr(iargs[chan]);
149 }
150 }
151 return handled;
152 }
153
154 static int
mal_rxeob_intr(void * arg)155 mal_rxeob_intr(void *arg)
156 {
157 uint32_t rcei;
158 int chan, handled = 0;
159
160 while ((rcei = mfdcr(DCR_MAL0_RXEOBISR))) {
161 chan = STAT_TO_CHAN(rcei);
162 if (iargs[chan] != NULL) {
163 /* Clear the interrupt */
164 mtdcr(DCR_MAL0_RXEOBISR, MAL0__XCAR_CHAN(chan));
165
166 handled |= emac_rxeob_intr(iargs[chan]);
167 }
168 }
169 return handled;
170 }
171
172 static int
mal_txde_intr(void * arg)173 mal_txde_intr(void *arg)
174 {
175 uint32_t txde;
176 int chan, handled = 0;
177
178 while ((txde = mfdcr(DCR_MAL0_TXDEIR))) {
179 chan = STAT_TO_CHAN(txde);
180 if (iargs[chan] != NULL) {
181 handled |= emac_txde_intr(iargs[chan]);
182
183 /* Clear the interrupt */
184 mtdcr(DCR_MAL0_TXDEIR, MAL0__XCAR_CHAN(chan));
185 }
186 }
187 return handled;
188 }
189
190 static int
mal_rxde_intr(void * arg)191 mal_rxde_intr(void *arg)
192 {
193 uint32_t rxde;
194 int chan, handled = 0;
195
196 while ((rxde = mfdcr(DCR_MAL0_RXDEIR))) {
197 chan = STAT_TO_CHAN(rxde);
198 if (iargs[chan] != NULL) {
199 handled |= emac_rxde_intr(iargs[chan]);
200
201 /* Clear the interrupt */
202 mtdcr(DCR_MAL0_RXDEIR, MAL0__XCAR_CHAN(chan));
203
204 /* Reenable the receive channel */
205 mtdcr(DCR_MAL0_RXCASR, MAL0__XCAR_CHAN(chan));
206 }
207 }
208 return handled;
209 }
210
211 static int
mal_serr_intr(void * arg)212 mal_serr_intr(void *arg)
213 {
214 uint32_t esr;
215
216 esr = mfdcr(DCR_MAL0_ESR);
217
218 /* not yet... */
219 aprint_error("MAL SERR: ESR 0x%08x\n", esr);
220
221 /* Clear the interrupt status bits. */
222 mtdcr(DCR_MAL0_ESR, esr);
223
224 return 1;
225 }
226
227
228 void
mal_intr_establish(int chan,void * arg)229 mal_intr_establish(int chan, void *arg)
230 {
231
232 if (chan >= __arraycount(iargs))
233 panic("MAL channel %d not support (max %d)\n",
234 chan, __arraycount(iargs));
235
236 iargs[chan] = arg;
237 }
238
239 int
mal_start(int chan,uint32_t cdtxaddr,uint32_t cdrxaddr)240 mal_start(int chan, uint32_t cdtxaddr, uint32_t cdrxaddr)
241 {
242
243 /*
244 * Give the transmit and receive rings to the MAL.
245 * And set the receive channel buffer size (in units of 16 bytes).
246 */
247 #if MCLBYTES > (4096 - 16) /* XXX! */
248 # error MCLBYTES > max rx channel buffer size
249 #endif
250 /* The mtdcr() allows only the constant in the first argument... */
251 switch (chan) {
252 case 0:
253 mtdcr(DCR_MAL0_TXCTP0R, cdtxaddr);
254 mtdcr(DCR_MAL0_RXCTP0R, cdrxaddr);
255 mtdcr(DCR_MAL0_RCBS0, MCLBYTES / 16);
256 break;
257
258 case 1:
259 mtdcr(DCR_MAL0_TXCTP1R, cdtxaddr);
260 mtdcr(DCR_MAL0_RXCTP1R, cdrxaddr);
261 mtdcr(DCR_MAL0_RCBS1, MCLBYTES / 16);
262 break;
263
264 case 2:
265 mtdcr(DCR_MAL0_TXCTP2R, cdtxaddr);
266 mtdcr(DCR_MAL0_RXCTP2R, cdrxaddr);
267 mtdcr(DCR_MAL0_RCBS2, MCLBYTES / 16);
268 break;
269
270 case 3:
271 mtdcr(DCR_MAL0_TXCTP3R, cdtxaddr);
272 mtdcr(DCR_MAL0_RXCTP3R, cdrxaddr);
273 mtdcr(DCR_MAL0_RCBS3, MCLBYTES / 16);
274 break;
275
276 default:
277 aprint_error("MAL unknown channel no.%d\n", chan);
278 return EINVAL;
279 }
280
281 /* Enable the transmit and receive channel on the MAL. */
282 mtdcr(DCR_MAL0_RXCASR, MAL0__XCAR_CHAN(chan));
283 mtdcr(DCR_MAL0_TXCASR, MAL0__XCAR_CHAN(chan));
284
285 return 0;
286 }
287
288 void
mal_stop(int chan)289 mal_stop(int chan)
290 {
291
292 /* Disable the receive and transmit channels. */
293 mtdcr(DCR_MAL0_RXCARR, MAL0__XCAR_CHAN(chan));
294 mtdcr(DCR_MAL0_TXCARR, MAL0__XCAR_CHAN(chan));
295 }
296