1 /* $OpenBSD: if_ie_gsc.c,v 1.30 2022/03/13 08:04:38 mpi Exp $ */
2
3 /*
4 * Copyright (c) 1998-2004 Michael Shalayeff
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 AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 * THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /*
30 * References:
31 * 1. 82596DX and 82596SX High-Performance 32-bit Local Area Network Coprocessor
32 * Intel Corporation, November 1996, Order Number: 290219-006
33 *
34 * 2. 712 I/O Subsystem ERS Rev 1.0
35 * Hewlett-Packard, June 17 1992, Dwg No. A-A2263-66510-31
36 */
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/device.h>
40 #include <sys/socket.h>
41 #include <sys/sockio.h>
42
43 #include <net/if.h>
44 #include <net/if_media.h>
45
46 #include <netinet/in.h>
47 #include <netinet/if_ether.h>
48
49 #include <machine/bus.h>
50 #include <machine/intr.h>
51 #include <machine/iomod.h>
52 #include <machine/autoconf.h>
53
54 #include <hppa/dev/cpudevs.h>
55 #include <hppa/gsc/gscbusvar.h>
56
57 #include <dev/ic/i82596reg.h>
58 #include <dev/ic/i82596var.h>
59
60 #define IEGSC_GECKO IEMD_FLAG0
61
62 struct ie_gsc_regs {
63 u_int32_t ie_reset;
64 u_int32_t ie_port;
65 u_int32_t ie_attn;
66 };
67
68 #define IE_SIZE 0x8000
69
70 int ie_gsc_probe(struct device *, void *, void *);
71 void ie_gsc_attach(struct device *, struct device *, void *);
72
73 const struct cfattach ie_gsc_ca = {
74 sizeof(struct ie_softc), ie_gsc_probe, ie_gsc_attach
75 };
76
77 static uint64_t ie_gsc_media[] = {
78 IFM_ETHER | IFM_10_2,
79 };
80 #define IE_NMEDIA (sizeof(ie_gsc_media) / sizeof(ie_gsc_media[0]))
81
82 char *ie_mem;
83
84 void ie_gsc_reset(struct ie_softc *sc, int what);
85 void ie_gsc_attend(struct ie_softc *sc);
86 void ie_gsc_run(struct ie_softc *sc);
87 void ie_gsc_port(struct ie_softc *sc, u_int);
88 #ifdef USELEDS
89 int ie_gsc_intrhook(struct ie_softc *sc, int what);
90 #endif
91 u_int16_t ie_gsc_read16(struct ie_softc *sc, int offset);
92 void ie_gsc_write16(struct ie_softc *sc, int offset, u_int16_t v);
93 void ie_gsc_write24(struct ie_softc *sc, int offset, int addr);
94 void ie_gsc_memcopyin(struct ie_softc *sc, void *p, int offset, size_t);
95 void ie_gsc_memcopyout(struct ie_softc *sc, const void *p, int, size_t);
96
97
98 void
ie_gsc_reset(sc,what)99 ie_gsc_reset(sc, what)
100 struct ie_softc *sc;
101 int what;
102 {
103 volatile struct ie_gsc_regs *r = (struct ie_gsc_regs *)sc->ioh;
104 int i;
105
106 r->ie_reset = 0;
107 /*
108 * per [2] 4.6.2.1
109 * delay for 10 system clocks + 5 transmit clocks,
110 * NB: works for system clocks over 10MHz
111 */
112 DELAY(1000);
113
114 switch (what) {
115 case IE_CHIP_PROBE:
116 break;
117
118 case IE_CARD_RESET:
119 /*
120 * after the hardware reset:
121 * inform i825[89]6 about new SCP address,
122 * maddr must be at least 16-byte aligned
123 */
124 ie_gsc_port(sc, IE_PORT_SCP);
125 ie_gsc_attend(sc);
126
127 for (i = 9000; i-- && ie_gsc_read16(sc, IE_ISCP_BUSY(sc->iscp));
128 DELAY(100))
129 pdcache(0, sc->sc_maddr + sc->iscp, IE_ISCP_SZ);
130
131 #ifdef I82596_DEBUG
132 if (i < 0) {
133 printf("timeout for PORT command (%x)%s\n",
134 ie_gsc_read16(sc, IE_ISCP_BUSY(sc->iscp)),
135 (sc->sc_flags & IEGSC_GECKO)? " on gecko":"");
136 return;
137 }
138 #endif
139 break;
140 }
141 }
142
143 void
ie_gsc_attend(sc)144 ie_gsc_attend(sc)
145 struct ie_softc *sc;
146 {
147 volatile struct ie_gsc_regs *r = (struct ie_gsc_regs *)sc->ioh;
148
149 fdcache(0, (vaddr_t)ie_mem, IE_SIZE);
150 DELAY(1);
151 r->ie_attn = 0;
152 DELAY(1);
153 }
154
155 void
ie_gsc_run(sc)156 ie_gsc_run(sc)
157 struct ie_softc *sc;
158 {
159 }
160
161 void
ie_gsc_port(sc,cmd)162 ie_gsc_port(sc, cmd)
163 struct ie_softc *sc;
164 u_int cmd;
165 {
166 switch (cmd) {
167 case IE_PORT_RESET:
168 cmd = 0;
169 break;
170 case IE_PORT_TEST:
171 cmd = ((u_int)sc->sc_maddr + sc->scp) | 1;
172 break;
173 case IE_PORT_SCP:
174 cmd = ((u_int)sc->sc_maddr + sc->scp) | 2;
175 break;
176 case IE_PORT_DUMP:
177 cmd = 3;
178 break;
179 }
180
181 if (sc->sc_flags & IEGSC_GECKO) {
182 volatile struct ie_gsc_regs *r = (struct ie_gsc_regs *)sc->ioh;
183 r->ie_port = cmd & 0xffff;
184 DELAY(1000);
185 r->ie_port = cmd >> 16;
186 DELAY(1000);
187 } else {
188 volatile struct ie_gsc_regs *r = (struct ie_gsc_regs *)sc->ioh;
189 r->ie_port = cmd >> 16;
190 DELAY(1000);
191 r->ie_port = cmd & 0xffff;
192 DELAY(1000);
193 }
194 }
195
196 #ifdef USELEDS
197 int
ie_gsc_intrhook(sc,where)198 ie_gsc_intrhook(sc, where)
199 struct ie_softc *sc;
200 int where;
201 {
202 switch (where) {
203 case IE_INTR_ENRCV:
204 ledctl(PALED_NETRCV, 0, 0);
205 break;
206 case IE_INTR_ENSND:
207 ledctl(PALED_NETSND, 0, 0);
208 break;
209 case IE_INTR_EXIT:
210 case IE_INTR_LOOP:
211 fdcache(0, (vaddr_t)ie_mem, IE_SIZE);
212 break;
213 }
214 return 0;
215 }
216 #endif
217
218 u_int16_t
ie_gsc_read16(sc,offset)219 ie_gsc_read16(sc, offset)
220 struct ie_softc *sc;
221 int offset;
222 {
223 volatile u_int16_t *addr = (volatile u_int16_t *)(sc->bh + offset);
224
225 asm volatile ("fdc %%r0(%%sr0, %0)" :: "r" (addr));
226 return *addr;
227 }
228
229 void
ie_gsc_write16(sc,offset,v)230 ie_gsc_write16(sc, offset, v)
231 struct ie_softc *sc;
232 int offset;
233 u_int16_t v;
234 {
235 volatile u_int16_t *addr = (volatile u_int16_t *)(sc->bh + offset);
236
237 *addr = v;
238 asm volatile ("fdc %%r0(%%sr0, %0)" :: "r" (addr));
239 }
240
241 void
ie_gsc_write24(sc,offset,v)242 ie_gsc_write24(sc, offset, v)
243 struct ie_softc *sc;
244 int offset;
245 int v;
246 {
247 volatile u_int16_t *addr = (volatile u_int16_t *)(sc->bh + offset);
248
249 addr[0] = (v ) & 0xffff;
250 addr[1] = (v >> 16) & 0xffff;
251 asm volatile ("fdc %%r0(%%sr0, %0)" :: "r" (addr+0));
252 asm volatile ("fdc %%r0(%%sr0, %0)" :: "r" (addr+1));
253 }
254
255 void
ie_gsc_memcopyin(sc,p,offset,size)256 ie_gsc_memcopyin(sc, p, offset, size)
257 struct ie_softc *sc;
258 void *p;
259 int offset;
260 size_t size;
261 {
262 pdcache(0, sc->bh + offset, size);
263 bcopy ((void *)((u_long)sc->bh + offset), p, size);
264 }
265
266 void
ie_gsc_memcopyout(sc,p,offset,size)267 ie_gsc_memcopyout(sc, p, offset, size)
268 struct ie_softc *sc;
269 const void *p;
270 int offset;
271 size_t size;
272 {
273 bcopy (p, (void *)((u_long)sc->bh + offset), size);
274 fdcache(0, sc->bh + offset, size);
275 }
276
277 int
ie_gsc_probe(parent,match,aux)278 ie_gsc_probe(parent, match, aux)
279 struct device *parent;
280 void *match, *aux;
281 {
282 struct gsc_attach_args *ga = aux;
283
284 if (ga->ga_type.iodc_type != HPPA_TYPE_FIO ||
285 (ga->ga_type.iodc_sv_model != HPPA_FIO_LAN &&
286 ga->ga_type.iodc_sv_model != HPPA_FIO_GLAN))
287 return 0;
288
289 return 1;
290 }
291
292 void
ie_gsc_attach(parent,self,aux)293 ie_gsc_attach(parent, self, aux)
294 struct device *parent, *self;
295 void *aux;
296 {
297 struct pdc_lan_station_id pdc_mac PDC_ALIGNMENT;
298 struct ie_softc *sc = (struct ie_softc *)self;
299 struct gsc_attach_args *ga = aux;
300 /*bus_dma_segment_t seg;
301 int rseg;*/
302 int rv;
303 #ifdef PMAPDEBUG
304 extern int pmapdebug;
305 int opmapdebug = pmapdebug;
306 pmapdebug = 0;
307 #endif
308
309 sc->iot = sc->bt = ga->ga_iot;
310 if (bus_space_map(sc->iot, ga->ga_hpa, IOMOD_HPASIZE, 0, &sc->ioh)) {
311 printf(": can't map IO space\n");
312 return;
313 }
314
315 if (ga->ga_type.iodc_sv_model == HPPA_FIO_GLAN)
316 sc->sc_flags |= IEGSC_GECKO;
317
318 sc->sc_msize = IE_SIZE;
319 /* XXX memory must be under 16M until the mi part is fixed */
320 #if 0
321 if (bus_dmamem_alloc(ga->ga_dmatag, sc->sc_msize, NBPG, 0,
322 &seg, 1, &rseg, BUS_DMA_NOWAIT)) {
323 printf (": cannot allocate %d bytes of DMA memory\n",
324 sc->sc_msize);
325 return;
326 }
327 if (bus_dmamem_map(ga->ga_dmatag, &seg, rseg, sc->sc_msize,
328 (caddr_t *)&sc->bh, BUS_DMA_NOWAIT)) {
329 printf (": cannot map DMA memory\n");
330 bus_dmamem_free(ga->ga_dmatag, &seg, rseg);
331 return;
332 }
333
334 bzero((void *)sc->bh, sc->sc_msize);
335 sc->sc_maddr = kvtop((caddr_t)sc->bh);
336
337 #else
338 sc->bh = (u_int)ie_mem;
339 sc->sc_maddr = sc->bh;
340 #endif
341 sc->sysbus = 0x40 | IE_SYSBUS_82586 | IE_SYSBUS_INTLOW | IE_SYSBUS_TRG | IE_SYSBUS_BE;
342
343 sc->do_xmitnopchain = 0;
344 sc->hwreset = ie_gsc_reset;
345 sc->chan_attn = ie_gsc_attend;
346 sc->port = ie_gsc_port;
347 sc->hwinit = ie_gsc_run;
348 sc->memcopyout = ie_gsc_memcopyout;
349 sc->memcopyin = ie_gsc_memcopyin;
350 sc->ie_bus_read16 = ie_gsc_read16;
351 sc->ie_bus_write16 = ie_gsc_write16;
352 sc->ie_bus_write24 = ie_gsc_write24;
353 #ifdef USELEDS
354 sc->intrhook = ie_gsc_intrhook;
355 #else
356 sc->intrhook = NULL;
357 #endif
358
359 #ifdef I82596_DEBUG
360 printf(" mem %x[%p]/%x", sc->bh, sc->sc_maddr, sc->sc_msize);
361 sc->sc_debug = IED_ALL;
362 #endif
363 rv = i82596_probe(sc);
364 if (!rv) {
365 /*bus_dmamem_free(ga->ga_dmatag, &seg, sc->sc_msize);*/
366 }
367 #ifdef PMAPDEBUG
368 pmapdebug = opmapdebug;
369 #endif
370 if (!rv) {
371 printf("\n");
372 return;
373 }
374
375 if (pdc_call((iodcio_t)pdc, 0, PDC_LAN_STATION_ID,
376 PDC_LAN_STATION_ID_READ, &pdc_mac, ga->ga_hpa) < 0)
377 bcopy((void *)ASP_PROM, sc->sc_arpcom.ac_enaddr,
378 ETHER_ADDR_LEN);
379 else
380 bcopy(pdc_mac.addr, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN);
381
382 printf(":");
383
384 sc->iscp = 0;
385 sc->scp = 32;
386 sc->scb = 94;
387 sc->buf_area = 256;
388 sc->buf_area_sz = sc->sc_msize - sc->buf_area;
389 sc->sc_type = sc->sc_flags & IEGSC_GECKO? "LASI/i82596CA" : "i82596DX";
390 sc->sc_vers = ga->ga_type.iodc_model * 10 + ga->ga_type.iodc_sv_rev;
391 i82596_attach(sc, sc->sc_type, (char *)sc->sc_arpcom.ac_enaddr,
392 ie_gsc_media, IE_NMEDIA, ie_gsc_media[0]);
393
394 sc->sc_ih = gsc_intr_establish((struct gsc_softc *)parent,
395 ga->ga_irq, IPL_NET, i82596_intr, sc, sc->sc_dev.dv_xname);
396 }
397