|
|
1.1 root 1: /*
2: * Copyright (c) 1994 Shantanu Goel
3: * All Rights Reserved.
4: *
5: * Permission to use, copy, modify and distribute this software and its
6: * documentation is hereby granted, provided that both the copyright
7: * notice and this permission notice appear in all copies of the
8: * software, derivative works or modified versions, and any portions
9: * thereof, and that both notices appear in supporting documentation.
10: *
11: * THE AUTHOR ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
12: * CONDITION. THE AUTHOR DISCLAIMS ANY LIABILITY OF ANY KIND FOR
13: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
14: */
15:
16: /*
17: * Written 1993 by Donald Becker.
18: *
19: * Copyright 1993 United States Government as represented by the
20: * Director, National Security Agency. This software may be used and
21: * distributed according to the terms of the GNU Public License,
22: * incorporated herein by reference.
23: *
24: * The Author may be reached as [email protected] or
25: * C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
26: */
27:
28: #include <wd.h>
29: #include <ul.h>
30: #if NUL > 0
31: /*
32: * Driver for SMC Ultra ethernet adaptor.
33: * Derived from the Linux driver by Donald Becker.
34: *
35: * Shantanu Goel ([email protected])
36: */
37: #include <mach/sa/sys/types.h>
38: #include "vm_param.h"
39: #include <kern/time_out.h>
40: #include <device/device_types.h>
41: #include <device/errno.h>
42: #include <device/io_req.h>
43: #include <device/if_hdr.h>
44: #include <device/if_ether.h>
45: #include <device/net_status.h>
46: #include <device/net_io.h>
47: #include <chips/busses.h>
48: #include <i386/machspl.h>
49: #include <i386/pio.h>
50: #include <i386at/gpl/if_nsreg.h>
51:
52: #define START_PG 0x00 /* first page of TX buffer */
53: #define ULTRA_CMDREG 0 /* offset of ASIC command register */
54: #define ULTRA_RESET 0x80 /* board reset in ULTRA_CMDREG */
55: #define ULTRA_MEMEN 0x40 /* enable shared memory */
56: #define ULTRA_NIC_OFF 16 /* NIC register offset */
57:
58: #define ulunit(dev) minor(dev)
59:
60: /*
61: * Autoconfiguration stuff.
62: */
63: int ulprobe();
64: void ulattach();
65: int ulstd[] = { 0x200, 0x220, 0x240, 0x280, 0x300, 0x340, 0x380, 0 };
66: struct bus_device *ulinfo[NUL];
67: struct bus_driver uldriver = {
68: ulprobe, 0, ulattach, 0, ulstd, "ul", ulinfo, 0, 0, 0
69: };
70:
71: /*
72: * NS8390 state.
73: */
74: struct nssoftc ulnssoftc[NUL];
75:
76: /*
77: * Ultra state.
78: */
79: struct ulsoftc {
80: int sc_mstart; /* start of board's RAM */
81: int sc_mend; /* end of board's RAM */
82: int sc_rmstart; /* start of receive RAM */
83: int sc_rmend; /* end of receive RAM */
84: } ulsoftc[NUL];
85:
86: void ulstart(int);
87: void ul_reset(struct nssoftc *sc);
88: void ul_input(struct nssoftc *sc, int, char *, int);
89: int ul_output(struct nssoftc *sc, int, char *, int);
90:
91: /*
92: * Watchdog.
93: */
94: int ulwstart = 0;
95: void ulwatch(void);
96:
97: #define ULDEBUG
98: #ifdef ULDEBUG
99: int uldebug = 0;
100: #define DEBUGF(stmt) { if (uldebug) stmt; }
101: #else
102: #define DEBUGF(stmt)
103: #endif
104:
105: /*
106: * Probe for the Ultra.
107: * This looks like an 8013 with the station address PROM
108: * at I/O ports <base>+8 to <base>+13, with a checksum following.
109: */
110: int
111: ulprobe(xxx, ui)
112: int xxx;
113: struct bus_device *ui;
114: {
115: int *port;
116:
117: if (ui->unit >= NUL) {
118: printf("ul%d: not configured\n", ui->unit);
119: return (0);
120: }
121: for (port = ulstd; *port; port++) {
122: if (*port < 0)
123: continue;
124: /*
125: * Check chip ID nibble.
126: */
127: if ((inb(*port + 7) & 0xf0) != 0x20)
128: continue;
129: if (ulprobe1(*port, ui)) {
130: ui->address = *port;
131: *port = -1;
132: #if NWD > 0
133: /*
134: * XXX: The Western Digital/SMC driver can sometimes
135: * probe the Ultra incorrectly. Remove the Ultra's
136: * port from it's list to avoid the problem.
137: */
138: {
139: int i;
140: extern int wdstd[];
141:
142: for (i = 0; wdstd[i]; i++) {
143: if (wdstd[i] == ui->address) {
144: wdstd[i] = -1;
145: break;
146: }
147: }
148: }
149: #endif
150: return (1);
151: }
152: }
153: return (0);
154: }
155:
156: int
157: ulprobe1(port, ui)
158: int port;
159: struct bus_device *ui;
160: {
161: u_char num_pages, irqreg, addr, reg4;
162: u_char irqmap[] = { 0, 9, 3, 5, 7, 10, 11, 15 };
163: short num_pages_tbl[4] = { 0x20, 0x40, 0x80, 0xff };
164: int i, irq, checksum = 0;
165: int addr_tbl[4] = { 0x0c0000, 0x0e0000, 0xfc0000, 0xfe0000 };
166: struct ulsoftc *ul = &ulsoftc[ui->unit];
167: struct nssoftc *ns = &ulnssoftc[ui->unit];
168: struct ifnet *ifp = &ns->sc_if;
169:
170: /*
171: * Select the station address register set.
172: */
173: reg4 = inb(port + 4) & 0x7f;
174: outb(port + 4, reg4);
175:
176: for (i = 0; i < 8; i++)
177: checksum += inb(port + 8 + i);
178: if ((checksum & 0xff) != 0xff)
179: return (0);
180:
181: /*
182: * Use 2 transmit buffers.
183: */
184: ns->sc_pingpong = 1;
185:
186: printf("ul%d: SMC Ultra at 0x%03x, ", ui->unit, port);
187: for (i = 0; i < ETHER_ADDR_LEN; i++) {
188: if (i == 0)
189: printf("%02x", ns->sc_addr[i] = inb(port + 8 + i));
190: else
191: printf(":%02x", ns->sc_addr[i] = inb(port + 8 + i));
192: }
193: /*
194: * Switch from station address to alternate register set
195: * and read useful registers there.
196: */
197: outb(port + 4, 0x80 | reg4);
198:
199: /*
200: * Enable FINE16 mode to avoid BIOS ROM width mismatches
201: * during reboot.
202: */
203: outb(port + 0x0c, 0x80 | inb(port + 0x0c));
204: irqreg = inb(port + 0x0d);
205: addr = inb(port + 0x0b);
206:
207: /*
208: * Switch back to station address register set so the MSDOG
209: * driver can find the card after a warm boot.
210: */
211: outb(port + 4, reg4);
212:
213: /*
214: * Determine IRQ. The IRQ bits are split.
215: */
216: irq = irqmap[((irqreg & 0x40) >> 4) + ((irqreg & 0x0c) >> 2)];
217: if (irq == 0) {
218: printf(", failed to detect IRQ line.\n");
219: return (0);
220: }
221: ui->sysdep1 = irq;
222: take_dev_irq(ui);
223: printf(", irq %d", irq);
224:
225: /*
226: * Determine board's RAM location.
227: */
228: ul->sc_mstart = ((addr & 0x0f) << 13) + addr_tbl[(addr >> 6) & 3];
229: num_pages = num_pages_tbl[(addr >> 4) & 3];
230: ul->sc_rmstart = ul->sc_mstart + TX_PAGES(ns) * 256;
231: ul->sc_mend = ul->sc_rmend
232: = ul->sc_mstart + (num_pages - START_PG) * 256;
233: printf(", memory 0x%05x-0x%05x\n", ul->sc_mstart, ul->sc_mend);
234:
235: /*
236: * Initialize 8390 state.
237: */
238: ns->sc_name = ui->name;
239: ns->sc_unit = ui->unit;
240: ns->sc_port = port + ULTRA_NIC_OFF;
241: ns->sc_word16 = 1;
242: ns->sc_txstrtpg = START_PG;
243: ns->sc_rxstrtpg = START_PG + TX_PAGES(ns);
244: ns->sc_stoppg = num_pages;
245: ns->sc_reset = ul_reset;
246: ns->sc_input = ul_input;
247: ns->sc_output = ul_output;
248:
249: DEBUGF(printf("ul%d: txstrtpg %d rxstrtpg %d num_pages %d\n",
250: ui->unit, ns->sc_txstrtpg, ns->sc_rxstrtpg, num_pages));
251:
252: /*
253: * Initialize interface header.
254: */
255: ifp->if_unit = ui->unit;
256: ifp->if_mtu = ETHERMTU;
257: ifp->if_flags = IFF_BROADCAST;
258: ifp->if_header_size = sizeof(struct ether_header);
259: ifp->if_header_format = HDR_ETHERNET;
260: ifp->if_address_size = ETHER_ADDR_LEN;
261: ifp->if_address = ns->sc_addr;
262: if_init_queues(ifp);
263:
264: return (1);
265: }
266:
267: void
268: ulattach(ui)
269: struct bus_device *ui;
270: {
271: /*
272: * void
273: */
274: }
275:
276: int
277: ulopen(dev, flag)
278: dev_t dev;
279: int flag;
280: {
281: int unit = ulunit(dev), s;
282: struct bus_device *ui;
283:
284: if (unit >= NUL || (ui = ulinfo[unit]) == 0 || ui->alive == 0)
285: return (ENXIO);
286:
287: /*
288: * Start watchdog.
289: */
290: if (!ulwstart) {
291: ulwstart++;
292: timeout(ulwatch, 0, hz);
293: }
294: ulnssoftc[unit].sc_if.if_flags |= IFF_UP;
295: s = splimp();
296: outb(ui->address, ULTRA_MEMEN); /* enable memory, 16 bit mode */
297: outb(ui->address + 5, 0x80);
298: outb(ui->address + 6, 0x01); /* enable interrupts and memory */
299: nsinit(&ulnssoftc[unit]);
300: splx(s);
301: return (0);
302: }
303:
304: int
305: uloutput(dev, ior)
306: dev_t dev;
307: io_req_t ior;
308: {
309: int unit = ulunit(dev);
310: struct bus_device *ui;
311:
312: if (unit >= NUL || (ui = ulinfo[unit]) == 0 || ui->alive == 0)
313: return (ENXIO);
314:
315: return (net_write(&ulnssoftc[unit].sc_if, ulstart, ior));
316: }
317:
318: int
319: ulsetinput(dev, receive_port, priority, filter, filter_count)
320: dev_t dev;
321: mach_port_t receive_port;
322: int priority;
323: filter_t *filter;
324: unsigned filter_count;
325: {
326: int unit = ulunit(dev);
327: struct bus_device *ui;
328:
329: if (unit >= NUL || (ui = ulinfo[unit]) == 0 || ui->alive == 0)
330: return (ENXIO);
331:
332: return (net_set_filter(&ulnssoftc[unit].sc_if, receive_port,
333: priority, filter, filter_count));
334: }
335:
336: int
337: ulgetstat(dev, flavor, status, count)
338: dev_t dev;
339: int flavor;
340: dev_status_t status;
341: unsigned *count;
342: {
343: int unit = ulunit(dev);
344: struct bus_device *ui;
345:
346: if (unit >= NUL || (ui = ulinfo[unit]) == 0 || ui->alive == 0)
347: return (ENXIO);
348:
349: return (net_getstat(&ulnssoftc[unit].sc_if, flavor, status, count));
350: }
351:
352: int
353: ulsetstat(dev, flavor, status, count)
354: dev_t dev;
355: int flavor;
356: dev_status_t status;
357: unsigned count;
358: {
359: int unit = ulunit(dev), oflags, s;
360: struct bus_device *ui;
361: struct ifnet *ifp;
362: struct net_status *ns;
363:
364: if (unit >= NUL || (ui = ulinfo[unit]) == 0 || ui->alive == 0)
365: return (ENXIO);
366:
367: ifp = &ulnssoftc[unit].sc_if;
368:
369: switch (flavor) {
370:
371: case NET_STATUS:
372: if (count < NET_STATUS_COUNT)
373: return (D_INVALID_SIZE);
374: ns = (struct net_status *)status;
375: oflags = ifp->if_flags & (IFF_ALLMULTI|IFF_PROMISC);
376: ifp->if_flags &= ~(IFF_ALLMULTI|IFF_PROMISC);
377: ifp->if_flags |= ns->flags & (IFF_ALLMULTI|IFF_PROMISC);
378: if ((ifp->if_flags & (IFF_ALLMULTI|IFF_PROMISC)) != oflags) {
379: s = splimp();
380: nsinit(&ulnssoftc[unit]);
381: splx(s);
382: }
383: break;
384:
385: default:
386: return (D_INVALID_OPERATION);
387: }
388: return (D_SUCCESS);
389: }
390:
391: void
392: ulintr(unit)
393: int unit;
394: {
395: nsintr(&ulnssoftc[unit]);
396: }
397:
398: void
399: ulstart(unit)
400: int unit;
401: {
402: nsstart(&ulnssoftc[unit]);
403: }
404:
405: void
406: ul_reset(ns)
407: struct nssoftc *ns;
408: {
409: int port = ns->sc_port - ULTRA_NIC_OFF; /* ASIC base address */
410:
411: outb(port, ULTRA_RESET);
412: outb(0x80, 0); /* I/O delay */
413: outb(port, ULTRA_MEMEN);
414: }
415:
416: void
417: ul_input(ns, count, buf, ring_offset)
418: struct nssoftc *ns;
419: int count;
420: char *buf;
421: int ring_offset;
422: {
423: int xfer_start;
424: struct ulsoftc *ul = &ulsoftc[ns->sc_unit];
425:
426: DEBUGF(printf("ul%d: ring_offset = %d\n", ns->sc_unit, ring_offset));
427:
428: xfer_start = ul->sc_mstart + ring_offset - (START_PG << 8);
429: if (xfer_start + count > ul->sc_rmend) {
430: int semi_count = ul->sc_rmend - xfer_start;
431:
432: /*
433: * Input move must be wrapped.
434: */
435: bcopy((char *)phystokv(xfer_start), buf, semi_count);
436: count -= semi_count;
437: bcopy((char *)phystokv(ul->sc_rmstart), buf+semi_count, count);
438: } else
439: bcopy((char *)phystokv(xfer_start), buf, count);
440: }
441:
442: int
443: ul_output(ns, count, buf, start_page)
444: struct nssoftc *ns;
445: int count;
446: char *buf;
447: int start_page;
448: {
449: char *shmem;
450: int i;
451: struct ulsoftc *ul = &ulsoftc[ns->sc_unit];
452:
453: DEBUGF(printf("ul%d: start_page = %d\n", ns->sc_unit, start_page));
454:
455: shmem = (char *)phystokv(ul->sc_mstart + ((start_page-START_PG) << 8));
456: bcopy(buf, shmem, count);
457: while (count < ETHERMIN + sizeof(struct ether_header)) {
458: *(shmem + count) = 0;
459: count++;
460: }
461: return (count);
462: }
463:
464: /*
465: * Watchdog.
466: * Check for hung transmissions.
467: */
468: void
469: ulwatch()
470: {
471: int unit, s;
472: struct nssoftc *ns;
473:
474: timeout(ulwatch, 0, hz);
475:
476: s = splimp();
477: for (unit = 0; unit < NUL; unit++) {
478: if (ulinfo[unit] == 0 || ulinfo[unit]->alive == 0)
479: continue;
480: ns = &ulnssoftc[unit];
481: if (ns->sc_timer && --ns->sc_timer == 0) {
482: printf("ul%d: transmission timeout\n", unit);
483: nsinit(ns);
484: }
485: }
486: splx(s);
487: }
488:
489: #endif /* NUL > 0 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.