source: trunk/minix/drivers/lance/lance.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 51.4 KB
Line 
1/*
2 * lance.c
3 *
4 * This file contains a ethernet device driver for AMD LANCE based ethernet
5 * cards.
6 *
7 * The valid messages and their parameters are:
8 *
9 * m_type DL_PORT DL_PROC DL_COUNT DL_MODE DL_ADDR
10 * |------------+----------+---------+----------+---------+---------|
11 * | HARDINT | | | | | |
12 * |------------|----------|---------|----------|---------|---------|
13 * | DL_WRITE | port nr | proc nr | count | mode | address |
14 * |------------|----------|---------|----------|---------|---------|
15 * | DL_WRITEV | port nr | proc nr | count | mode | address |
16 * |------------|----------|---------|----------|---------|---------|
17 * | DL_READ | port nr | proc nr | count | | address |
18 * |------------|----------|---------|----------|---------|---------|
19 * | DL_READV | port nr | proc nr | count | | address |
20 * |------------|----------|---------|----------|---------|---------|
21 * | DL_INIT | port nr | proc nr | mode | | address |
22 * |------------|----------|---------|----------|---------|---------|
23 * | DL_GETSTAT | port nr | proc nr | | | address |
24 * |------------|----------|---------|----------|---------|---------|
25 * | DL_STOP | port_nr | | | | |
26 * |------------|----------|---------|----------|---------|---------|
27 *
28 * The messages sent are:
29 *
30 * m-type DL_POR T DL_PROC DL_COUNT DL_STAT DL_CLCK
31 * |------------|----------|---------|----------|---------|---------|
32 * |DL_TASK_REPL| port nr | proc nr | rd-count | err|stat| clock |
33 * |------------|----------|---------|----------|---------|---------|
34 *
35 * m_type m3_i1 m3_i2 m3_ca1
36 * |------------+---------+-----------+---------------|
37 * |DL_INIT_REPL| port nr | last port | ethernet addr |
38 * |------------|---------|-----------|---------------|
39 *
40 * Created: Jul 27, 2002 by Kazuya Kodama <kazuya@nii.ac.jp>
41 * Adapted for Minix 3: Sep 05, 2005 by Joren l'Ami <jwlami@cs.vu.nl>
42 */
43
44#define VERBOSE 0
45
46#include "../drivers.h"
47
48#include <minix/keymap.h>
49#include <net/hton.h>
50#include <net/gen/ether.h>
51#include <net/gen/eth_io.h>
52#include <assert.h>
53
54#include <minix/syslib.h>
55#include <ibm/pci.h>
56
57#include "lance.h"
58/*#include "proc.h"*/
59
60#include <sys/ioc_memory.h>
61
62/* new I/O functions in Minix 3 */
63#define out_byte( x, y ) sys_outb( x, y )
64#define out_word( x, y ) sys_outw( x, y )
65
66static U8_t in_byte(U16_t port)
67{
68 unsigned long value;
69 int s;
70 if ((s=sys_inb(port, &value)) != OK)
71 printf( "lance: warning, sys_inb failed: %d\n", s );
72 return (U8_t) value;
73}
74
75static U16_t in_word( U16_t port)
76{
77 unsigned long value;
78 int s;
79 if ((s=sys_inw(port, &value)) != OK)
80 printf( "lance: warning, sys_inw failed: %d\n", s );
81 return (U16_t) value;
82}
83/*
84#define in_byte( x ) inb( x )
85#define in_word( x ) inw( x )
86*/
87
88static ether_card_t ec_table[EC_PORT_NR_MAX];
89static int eth_tasknr= ANY;
90static u16_t eth_ign_proto;
91
92/* Configuration */
93typedef struct ec_conf
94{
95 port_t ec_port;
96 int ec_irq;
97 phys_bytes ec_mem;
98 char *ec_envvar;
99} ec_conf_t;
100
101/* We hardly use these. Just "LANCE0=on/off" "LANCE1=on/off" mean. */
102ec_conf_t ec_conf[]= /* Card addresses */
103{
104 /* I/O port, IRQ, Buffer address, Env. var, Buf selector. */
105 { 0x1000, 9, 0x00000, "LANCE0" },
106 { 0xD000, 15, 0x00000, "LANCE1" },
107};
108
109/* Actually, we use PCI-BIOS info. */
110PRIVATE struct pcitab
111{
112 u16_t vid;
113 u16_t did;
114 int checkclass;
115} pcitab[]=
116{
117 { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, 0 }, /* AMD LANCE */
118
119 { 0x0000, 0x0000, 0 }
120};
121/*
122struct pci_device pci_dev_list[] = {
123 { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE,
124 "AMD Lance/PCI", 0, 0, 0, 0, 0, 0},
125 { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE,
126 "AMD Lance/PCI", 0, 0, 0, 0, 0, 0},
127 {0, 0, NULL, 0, 0, 0, 0, 0, 0}
128};
129*/
130
131/* General */
132_PROTOTYPE( static void do_init, (message *mp) );
133_PROTOTYPE( static void ec_init, (ether_card_t *ec) );
134_PROTOTYPE( static void ec_confaddr, (ether_card_t *ec) );
135_PROTOTYPE( static void ec_reinit, (ether_card_t *ec) );
136_PROTOTYPE( static void ec_check_ints, (ether_card_t *ec) );
137_PROTOTYPE( static void conf_hw, (ether_card_t *ec) );
138/*_PROTOTYPE( static int ec_handler, (irq_hook_t *hook) );*/
139_PROTOTYPE( static void update_conf, (ether_card_t *ec, ec_conf_t *ecp) );
140_PROTOTYPE( static void mess_reply, (message *req, message *reply) );
141_PROTOTYPE( static void do_int, (ether_card_t *ec) );
142_PROTOTYPE( static void reply,
143 (ether_card_t *ec, int err, int may_block) );
144_PROTOTYPE( static void ec_reset, (ether_card_t *ec) );
145_PROTOTYPE( static void ec_send, (ether_card_t *ec) );
146_PROTOTYPE( static void ec_recv, (ether_card_t *ec) );
147_PROTOTYPE( static void do_vwrite,
148 (message *mp, int from_int, int vectored) );
149_PROTOTYPE( static void do_vread, (message *mp, int vectored) );
150_PROTOTYPE( static void get_userdata,
151 (int user_proc, vir_bytes user_addr,
152 vir_bytes count, void *loc_addr) );
153_PROTOTYPE( static void ec_user2nic,
154 (ether_card_t *dep, iovec_dat_t *iovp,
155 vir_bytes offset, int nic_addr,
156 vir_bytes count) );
157_PROTOTYPE( static void ec_nic2user,
158 (ether_card_t *ec, int nic_addr,
159 iovec_dat_t *iovp, vir_bytes offset,
160 vir_bytes count) );
161_PROTOTYPE( static int calc_iovec_size, (iovec_dat_t *iovp) );
162_PROTOTYPE( static void ec_next_iovec, (iovec_dat_t *iovp) );
163_PROTOTYPE( static void do_getstat, (message *mp) );
164_PROTOTYPE( static void put_userdata,
165 (int user_proc,
166 vir_bytes user_addr, vir_bytes count,
167 void *loc_addr) );
168_PROTOTYPE( static void do_stop, (message *mp) );
169_PROTOTYPE( static void do_getname, (message *mp) );
170
171_PROTOTYPE( static void lance_dump, (void) );
172_PROTOTYPE( static void lance_stop, (void) );
173_PROTOTYPE( static void getAddressing, (int devind, ether_card_t *ec) );
174
175/* probe+init LANCE cards */
176_PROTOTYPE( static int lance_probe, (ether_card_t *ec) );
177_PROTOTYPE( static void lance_init_card, (ether_card_t *ec) );
178
179/* --- LANCE --- */
180/* General */
181#define Address unsigned long
182
183
184/* Minix 3 */
185#define virt_to_bus(x) (vir2phys((unsigned long)x))
186unsigned long vir2phys( unsigned long x )
187{
188 int r;
189 unsigned long value;
190
191 if ( (r=sys_umap( SELF, D, x, 4, &value )) != OK )
192 panic( "lance", "sys_umap failed", r );
193
194 return value;
195}
196
197/* DMA limitations */
198#define DMA_ADDR_MASK 0xFFFFFF /* mask to verify DMA address is 24-bit */
199
200#define CORRECT_DMA_MEM() ( (virt_to_bus(lance + sizeof(lance)) & ~DMA_ADDR_MASK) == 0 )
201
202#define ETH_FRAME_LEN 1518
203
204#define LANCE_MUST_PAD 0x00000001
205#define LANCE_ENABLE_AUTOSELECT 0x00000002
206#define LANCE_SELECT_PHONELINE 0x00000004
207#define LANCE_MUST_UNRESET 0x00000008
208
209static const struct lance_chip_type
210{
211 int id_number;
212 const char *name;
213 int flags;
214} chip_table[] = {
215 {0x0000, "LANCE 7990", /* Ancient lance chip. */
216 LANCE_MUST_PAD + LANCE_MUST_UNRESET},
217 {0x0003, "PCnet/ISA 79C960", /* 79C960 PCnet/ISA. */
218 LANCE_ENABLE_AUTOSELECT},
219 {0x2260, "PCnet/ISA+ 79C961", /* 79C961 PCnet/ISA+, Plug-n-Play. */
220 LANCE_ENABLE_AUTOSELECT},
221 {0x2420, "PCnet/PCI 79C970", /* 79C970 or 79C974 PCnet-SCSI, PCI. */
222 LANCE_ENABLE_AUTOSELECT},
223 {0x2430, "PCnet32", /* 79C965 PCnet for VL bus. */
224 LANCE_ENABLE_AUTOSELECT},
225 {0x2621, "PCnet/PCI-II 79C970A", /* 79C970A PCInetPCI II. */
226 LANCE_ENABLE_AUTOSELECT},
227 {0x2625, "PCnet-FAST III 79C973",/* 79C973 PCInet-FAST III. */
228 LANCE_ENABLE_AUTOSELECT},
229 {0x2626, "PCnet/HomePNA 79C978",
230 LANCE_ENABLE_AUTOSELECT|LANCE_SELECT_PHONELINE},
231 {0x0, "PCnet (unknown)",
232 LANCE_ENABLE_AUTOSELECT},
233};
234
235/* ############## for LANCE device ############## */
236#define LANCE_ETH_ADDR 0x0
237#define LANCE_DATA 0x10
238#define LANCE_ADDR 0x12
239#define LANCE_RESET 0x14
240#define LANCE_BUS_IF 0x16
241#define LANCE_TOTAL_SIZE 0x18
242
243/* Use 2^4=16 {Rx,Tx} buffers */
244#define LANCE_LOG_RX_BUFFERS 4
245#define RX_RING_SIZE (1 << (LANCE_LOG_RX_BUFFERS))
246#define RX_RING_MOD_MASK (RX_RING_SIZE - 1)
247#define RX_RING_LEN_BITS ((LANCE_LOG_RX_BUFFERS) << 29)
248
249#define LANCE_LOG_TX_BUFFERS 4
250#define TX_RING_SIZE (1 << (LANCE_LOG_TX_BUFFERS))
251#define TX_RING_MOD_MASK (TX_RING_SIZE - 1)
252#define TX_RING_LEN_BITS ((LANCE_LOG_TX_BUFFERS) << 29)
253
254/* for lance_interface */
255struct lance_init_block
256{
257 unsigned short mode;
258 unsigned char phys_addr[6];
259 unsigned long filter[2];
260 Address rx_ring;
261 Address tx_ring;
262};
263
264struct lance_rx_head
265{
266 union {
267 Address base;
268 unsigned char addr[4];
269 } u;
270 short buf_length; /* 2s complement */
271 short msg_length;
272};
273
274struct lance_tx_head
275{
276 union {
277 Address base;
278 unsigned char addr[4];
279 } u;
280 short buf_length; /* 2s complement */
281 short misc;
282};
283
284struct lance_interface
285{
286 struct lance_init_block init_block;
287 struct lance_rx_head rx_ring[RX_RING_SIZE];
288 struct lance_tx_head tx_ring[TX_RING_SIZE];
289 unsigned char rbuf[RX_RING_SIZE][ETH_FRAME_LEN];
290 unsigned char tbuf[TX_RING_SIZE][ETH_FRAME_LEN];
291};
292
293/* =============== global variables =============== */
294static struct lance_interface *lp;
295static char lance[sizeof(struct lance_interface)+8];
296static int rx_slot_nr = 0; /* Rx-slot number */
297static int tx_slot_nr = 0; /* Tx-slot number */
298static int cur_tx_slot_nr = 0; /* Tx-slot number */
299static char isstored[TX_RING_SIZE]; /* Tx-slot in-use */
300static char *progname;
301
302
303/*===========================================================================*
304 * lance_task *
305 *===========================================================================*/
306void main( int argc, char **argv )
307{
308 message m;
309 int i,irq,r, tasknr;
310 ether_card_t *ec;
311 long v;
312 int fkeys, sfkeys;
313 (progname=strrchr(argv[0],'/')) ? progname++ : (progname=argv[0]);
314
315 env_setargs( argc, argv );
316
317 fkeys = sfkeys = 0; bit_set( sfkeys, 7 );
318
319#if 0
320 if ( (r = fkey_map(&fkeys, &sfkeys)) != OK )
321 printf( "Error registering key\n" );
322#endif
323
324 if((eth_tasknr=getprocnr()) < 0)
325 panic("lance","couldn't get own proc nr", i);
326
327 v= 0;
328 (void) env_parse("ETH_IGN_PROTO", "x", 0, &v, 0x0000L, 0xFFFFL);
329 eth_ign_proto= htons((u16_t) v);
330
331 /* Try to notify inet that we are present (again) */
332 r = _pm_findproc("inet", &tasknr);
333 if (r == OK)
334 notify(tasknr);
335
336 while (TRUE)
337 {
338 for (i=0;i<EC_PORT_NR_MAX;++i)
339 {
340 ec= &ec_table[i];
341 if (ec->ec_irq != 0)
342 sys_irqenable(&ec->ec_hook);
343 }
344
345 if ((r= receive(ANY, &m)) != OK)
346 panic( "lance", "receive failed", r);
347
348 for (i=0;i<EC_PORT_NR_MAX;++i)
349 {
350 ec= &ec_table[i];
351 if (ec->ec_irq != 0)
352 sys_irqdisable(&ec->ec_hook);
353 }
354
355/*printf( "." );*/
356
357 switch (m.m_type){
358 case DEV_PING: notify(m.m_source); continue;
359 case DL_WRITE: do_vwrite(&m, FALSE, FALSE); break;
360 case DL_WRITEV: do_vwrite(&m, FALSE, TRUE); break;
361 case DL_READ: do_vread(&m, FALSE); break;
362 case DL_READV: do_vread(&m, TRUE); break;
363 case DL_INIT: do_init(&m); break;
364 case DL_GETSTAT: do_getstat(&m); break;
365 case DL_STOP: do_stop(&m); break;
366 case DL_GETNAME: do_getname(&m); break;
367 case FKEY_PRESSED: lance_dump(); break;
368 /*case HARD_STOP: lance_stop(); break;*/
369 case SYS_SIG:
370 {
371 sigset_t set = m.NOTIFY_ARG;
372 if ( sigismember( &set, SIGKSTOP ) )
373 lance_stop();
374 }
375 break;
376 case HARD_INT:
377 for (i=0;i<EC_PORT_NR_MAX;++i)
378 {
379 ec= &ec_table[i];
380 if (ec->mode != EC_ENABLED)
381 continue;
382
383 /*
384 printf( "#.\n" );
385 */
386
387 irq=ec->ec_irq;
388 /*if (ec->ec_int_pending)*/
389 {
390 ec->ec_int_pending = 0;
391 ec_check_ints(ec);
392 do_int(ec);
393 }
394 }
395 break;
396 case PROC_EVENT:
397 break;
398 default:
399 panic( "lance", "illegal message", m.m_type);
400 }
401 }
402}
403
404/*===========================================================================*
405 * lance_dump *
406 *===========================================================================*/
407static void lance_dump()
408{
409 ether_card_t *ec;
410 int i, isr;
411 unsigned short ioaddr;
412
413 printf("\n");
414 for (i= 0, ec = &ec_table[0]; i<EC_PORT_NR_MAX; i++, ec++)
415 {
416 if (ec->mode == EC_DISABLED)
417 printf("lance port %d is disabled\n", i);
418 else if (ec->mode == EC_SINK)
419 printf("lance port %d is in sink mode\n", i);
420
421 if (ec->mode != EC_ENABLED)
422 continue;
423
424 printf("lance statistics of port %d:\n", i);
425
426 printf("recvErr :%8ld\t", ec->eth_stat.ets_recvErr);
427 printf("sendErr :%8ld\t", ec->eth_stat.ets_sendErr);
428 printf("OVW :%8ld\n", ec->eth_stat.ets_OVW);
429
430 printf("CRCerr :%8ld\t", ec->eth_stat.ets_CRCerr);
431 printf("frameAll :%8ld\t", ec->eth_stat.ets_frameAll);
432 printf("missedP :%8ld\n", ec->eth_stat.ets_missedP);
433
434 printf("packetR :%8ld\t", ec->eth_stat.ets_packetR);
435 printf("packetT :%8ld\t", ec->eth_stat.ets_packetT);
436 printf("transDef :%8ld\n", ec->eth_stat.ets_transDef);
437
438 printf("collision :%8ld\t", ec->eth_stat.ets_collision);
439 printf("transAb :%8ld\t", ec->eth_stat.ets_transAb);
440 printf("carrSense :%8ld\n", ec->eth_stat.ets_carrSense);
441
442 printf("fifoUnder :%8ld\t", ec->eth_stat.ets_fifoUnder);
443 printf("fifoOver :%8ld\t", ec->eth_stat.ets_fifoOver);
444 printf("CDheartbeat:%8ld\n", ec->eth_stat.ets_CDheartbeat);
445
446 printf("OWC :%8ld\t", ec->eth_stat.ets_OWC);
447
448 ioaddr = ec->ec_port;
449 out_word(ioaddr+LANCE_ADDR, 0x00);
450 isr=in_word(ioaddr+LANCE_DATA);
451 printf("isr = 0x%x + 0x%x, flags = 0x%x\n", isr,
452 in_word(ioaddr+LANCE_DATA), ec->flags);
453
454 printf("irq = %d\tioadr = %d\n", ec->ec_irq, ec->ec_port);
455 }
456}
457
458/*===========================================================================*
459 * lance_stop *
460 *===========================================================================*/
461static void lance_stop()
462{
463 message mess;
464 int i;
465
466 for (i= 0; i<EC_PORT_NR_MAX; i++)
467 {
468 if (ec_table[i].mode != EC_ENABLED)
469 continue;
470 mess.m_type= DL_STOP;
471 mess.DL_PORT= i;
472 do_stop(&mess);
473 }
474
475 /*printf("LANCE driver stopped.\n");*/
476
477 sys_exit( 0 );
478}
479
480
481/*===========================================================================*
482 * do_init *
483 *===========================================================================*/
484static void do_init(mp)
485message *mp;
486{
487 int port;
488 ether_card_t *ec;
489 message reply_mess;
490
491pci_init();
492
493 port = mp->DL_PORT;
494 if (port < 0 || port >= EC_PORT_NR_MAX)
495 {
496 reply_mess.m_type= DL_INIT_REPLY;
497 reply_mess.m3_i1= ENXIO;
498 mess_reply(mp, &reply_mess);
499 return;
500 }
501 ec= &ec_table[port];
502 strcpy(ec->port_name, "eth_card#0");
503 ec->port_name[9] += port;
504 if (ec->mode == EC_DISABLED)
505 {
506 /* This is the default, try to (re)locate the device. */
507 /* only try to enable if memory is correct for DMA */
508 if ( CORRECT_DMA_MEM() )
509 {
510 conf_hw(ec);
511 }
512 else
513 {
514 report( "LANCE", "DMA denied because address out of range", NO_NUM );
515 }
516
517 if (ec->mode == EC_DISABLED)
518 {
519 /* Probe failed, or the device is configured off. */
520 reply_mess.m_type= DL_INIT_REPLY;
521 reply_mess.m3_i1= ENXIO;
522 mess_reply(mp, &reply_mess);
523 return;
524 }
525 if (ec->mode == EC_ENABLED)
526 ec_init(ec);
527 }
528
529 if (ec->mode == EC_SINK)
530 {
531 ec->mac_address.ea_addr[0] =
532 ec->mac_address.ea_addr[1] =
533 ec->mac_address.ea_addr[2] =
534 ec->mac_address.ea_addr[3] =
535 ec->mac_address.ea_addr[4] =
536 ec->mac_address.ea_addr[5] = 0;
537 ec_confaddr(ec);
538 reply_mess.m_type = DL_INIT_REPLY;
539 reply_mess.m3_i1 = mp->DL_PORT;
540 reply_mess.m3_i2 = EC_PORT_NR_MAX;
541 *(ether_addr_t *) reply_mess.m3_ca1 = ec->mac_address;
542 mess_reply(mp, &reply_mess);
543 return;
544 }
545 assert(ec->mode == EC_ENABLED);
546 assert(ec->flags & ECF_ENABLED);
547
548 ec->flags &= ~(ECF_PROMISC | ECF_MULTI | ECF_BROAD);
549
550 if (mp->DL_MODE & DL_PROMISC_REQ)
551 ec->flags |= ECF_PROMISC | ECF_MULTI | ECF_BROAD;
552 if (mp->DL_MODE & DL_MULTI_REQ)
553 ec->flags |= ECF_MULTI;
554 if (mp->DL_MODE & DL_BROAD_REQ)
555 ec->flags |= ECF_BROAD;
556
557 ec->client = mp->m_source;
558 ec_reinit(ec);
559
560 reply_mess.m_type = DL_INIT_REPLY;
561 reply_mess.m3_i1 = mp->DL_PORT;
562 reply_mess.m3_i2 = EC_PORT_NR_MAX;
563 *(ether_addr_t *) reply_mess.m3_ca1 = ec->mac_address;
564
565 mess_reply(mp, &reply_mess);
566}
567
568
569/*===========================================================================*
570 * do_int *
571 *===========================================================================*/
572static void do_int(ec)
573ether_card_t *ec;
574{
575 if (ec->flags & (ECF_PACK_SEND | ECF_PACK_RECV))
576 reply(ec, OK, TRUE);
577}
578
579#if 0
580/*===========================================================================*
581 * ec_handler *
582 *===========================================================================*/
583static int ec_handler(hook)
584irq_hook_t *hook;
585{
586 /* LANCE interrupt, send message and reenable interrupts. */
587#if 0
588 printf(">> ec_handler(): \n");
589#endif
590
591 structof(ether_card_t, ec_hook, hook)->ec_int_pending= 1;
592
593 notify(eth_tasknr);
594
595 return 0;
596}
597#endif
598
599/*===========================================================================*
600 * conf_hw *
601 *===========================================================================*/
602static void conf_hw(ec)
603ether_card_t *ec;
604{
605 static eth_stat_t empty_stat = {0, 0, 0, 0, 0, 0 /* ,... */ };
606
607 int ifnr;
608 ec_conf_t *ecp;
609
610 ec->mode= EC_DISABLED; /* Superfluous */
611 ifnr= ec-ec_table;
612
613 ecp= &ec_conf[ifnr];
614 update_conf(ec, ecp);
615 if (ec->mode != EC_ENABLED)
616 return;
617
618 if (!lance_probe(ec))
619 {
620 printf("%s: No ethernet card found on PCI-BIOS info.\n",
621 ec->port_name);
622 ec->mode= EC_DISABLED;
623 return;
624 }
625
626 /* Allocate a memory segment, programmed I/O should set the
627 * memory segment (linmem) to zero.
628 */
629 if (ec->ec_linmem != 0)
630 {
631 assert( 0 );
632 /*phys2seg(&ec->ec_memseg, &ec->ec_memoff, ec->ec_linmem);*/
633 }
634
635/* XXX */ if (ec->ec_linmem == 0) ec->ec_linmem= 0xFFFF0000;
636
637 ec->flags = ECF_EMPTY;
638 ec->eth_stat = empty_stat;
639}
640
641
642/*===========================================================================*
643 * update_conf *
644 *===========================================================================*/
645static void update_conf(ec, ecp)
646ether_card_t *ec;
647ec_conf_t *ecp;
648{
649 long v;
650 static char ec_fmt[] = "x:d:x:x";
651
652 /* Get the default settings and modify them from the environment. */
653 ec->mode= EC_SINK;
654 v= ecp->ec_port;
655 switch (env_parse(ecp->ec_envvar, ec_fmt, 0, &v, 0x0000L, 0xFFFFL)) {
656 case EP_OFF:
657 ec->mode= EC_DISABLED;
658 break;
659 case EP_ON:
660 case EP_SET:
661 ec->mode= EC_ENABLED; /* Might become disabled if
662 * all probes fail */
663 break;
664 }
665
666 ec->ec_port= v;
667
668 v= ecp->ec_irq | DEI_DEFAULT;
669 (void) env_parse(ecp->ec_envvar, ec_fmt, 1, &v, 0L,
670 (long) NR_IRQ_VECTORS - 1);
671 ec->ec_irq= v;
672
673 v= ecp->ec_mem;
674 (void) env_parse(ecp->ec_envvar, ec_fmt, 2, &v, 0L, 0xFFFFFL);
675 ec->ec_linmem= v;
676
677 v= 0;
678 (void) env_parse(ecp->ec_envvar, ec_fmt, 3, &v, 0x2000L, 0x8000L);
679 ec->ec_ramsize= v;
680}
681
682
683/*===========================================================================*
684 * ec_init *
685 *===========================================================================*/
686static void ec_init(ec)
687ether_card_t *ec;
688{
689 int i, r;
690
691 /* General initialization */
692 ec->flags = ECF_EMPTY;
693 /*disable_irq(ec->ec_irq);*/
694 lance_init_card(ec); /* Get mac_address, etc ...*/
695
696 ec_confaddr(ec);
697
698#if VERBOSE
699 printf("%s: Ethernet address ", ec->port_name);
700 for (i= 0; i < 6; i++)
701 printf("%x%c", ec->mac_address.ea_addr[i],
702 i < 5 ? ':' : '\n');
703#endif
704
705 /* Finish the initialization */
706 ec->flags |= ECF_ENABLED;
707
708 /* Set the interrupt handler */
709 /*put_irq_handler(&ec->ec_hook, ec->ec_irq, ec_handler);*/
710 ec->ec_hook = ec->ec_irq;
711 if ((r=sys_irqsetpolicy(ec->ec_irq, 0, &ec->ec_hook)) != OK)
712 printf("lance: error, couldn't set IRQ policy: %d\n", r);
713
714/* enable_irq(ec->ec_irq); */
715
716/* enter_kdebug(">> ec_init():"); */
717
718 return;
719}
720
721
722/*===========================================================================*
723 * reply *
724 *===========================================================================*/
725static void reply(ec, err, may_block)
726ether_card_t *ec;
727int err;
728int may_block;
729{
730 message reply;
731 int status,r;
732 clock_t now;
733
734 status = 0;
735 if (ec->flags & ECF_PACK_SEND)
736 status |= DL_PACK_SEND;
737 if (ec->flags & ECF_PACK_RECV)
738 status |= DL_PACK_RECV;
739
740 reply.m_type = DL_TASK_REPLY;
741 reply.DL_PORT = ec - ec_table;
742 reply.DL_PROC = ec->client;
743 reply.DL_STAT = status | ((u32_t) err << 16);
744 reply.DL_COUNT = ec->read_s;
745#if 1
746 if ((r=getuptime(&now)) != OK)
747 panic("lance", "getuptime() failed:", r);
748 reply.DL_CLCK = now;
749#else
750 reply.DL_CLCK = 0;
751#endif
752
753 r = send(ec->client, &reply);
754#if 1
755 if (r == ELOCKED && may_block)
756 {
757/* enter_kdebug(">> lance_task: ELOCKED!"); */
758 return;
759 }
760#endif
761 if (r < 0)
762 panic( "lance", "send failed:", r);
763
764 ec->read_s = 0;
765 ec->flags &= ~(ECF_PACK_SEND | ECF_PACK_RECV);
766}
767
768
769/*===========================================================================*
770 * mess_reply *
771 *===========================================================================*/
772static void mess_reply(req, reply_mess)
773message *req;
774message *reply_mess;
775{
776 if (send(req->m_source, reply_mess) != OK)
777 panic( "lance", "unable to mess_reply", NO_NUM);
778}
779
780
781/*===========================================================================*
782 * ec_confaddr *
783 *===========================================================================*/
784static void ec_confaddr(ec)
785ether_card_t *ec;
786{
787 int i;
788 char eakey[16];
789 static char eafmt[]= "x:x:x:x:x:x";
790 long v;
791
792 /* User defined ethernet address? */
793 strcpy(eakey, ec_conf[ec-ec_table].ec_envvar);
794 strcat(eakey, "_EA");
795
796 for (i= 0; i < 6; i++)
797 {
798 v= ec->mac_address.ea_addr[i];
799 if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET)
800 break;
801 ec->mac_address.ea_addr[i]= v;
802 }
803
804 if (i != 0 && i != 6)
805 {
806 /* It's all or nothing; force a panic. */
807 (void) env_parse(eakey, "?", 0, &v, 0L, 0L);
808 }
809}
810
811
812/*===========================================================================*
813 * ec_reinit *
814 *===========================================================================*/
815static void ec_reinit(ec)
816ether_card_t *ec;
817{
818 int i;
819 unsigned short ioaddr = ec->ec_port;
820
821 out_word(ioaddr+LANCE_ADDR, 0x0);
822 (void)in_word(ioaddr+LANCE_ADDR);
823 out_word(ioaddr+LANCE_DATA, 0x4); /* stop */
824
825 /* purge Tx-ring */
826 tx_slot_nr = cur_tx_slot_nr = 0;
827 for (i=0; i<TX_RING_SIZE; i++) {
828 lp->tx_ring[i].u.base = 0;
829 isstored[i]=0;
830 }
831
832 /* re-init Rx-ring */
833 rx_slot_nr = 0;
834 for (i=0; i<RX_RING_SIZE; i++)
835 {
836 lp->rx_ring[i].buf_length = -ETH_FRAME_LEN;
837 lp->rx_ring[i].u.addr[3] |= 0x80;
838 }
839
840 /* Set 'Receive Mode' */
841 if (ec->flags & ECF_PROMISC)
842 {
843 out_word(ioaddr+LANCE_ADDR, 0xf);
844 out_word(ioaddr+LANCE_DATA, 0x8000);
845 }
846 else
847 {
848 if (ec->flags & (ECF_BROAD | ECF_MULTI))
849 {
850 out_word(ioaddr+LANCE_ADDR, 0xf);
851 out_word(ioaddr+LANCE_DATA, 0x0000);
852 }
853 else
854 {
855 out_word(ioaddr+LANCE_ADDR, 0xf);
856 out_word(ioaddr+LANCE_DATA, 0x4000);
857 }
858 }
859
860 out_word(ioaddr+LANCE_ADDR, 0x0);
861 (void)in_word(ioaddr+LANCE_ADDR);
862 out_word(ioaddr+LANCE_DATA, 0x142); /* start && enable interrupt */
863
864 return;
865}
866
867/*===========================================================================*
868 * ec_check_ints *
869 *===========================================================================*/
870static void ec_check_ints(ec)
871ether_card_t *ec;
872{
873 int must_restart=0;
874 int check,status;
875 int isr=0x0000;
876 unsigned short ioaddr = ec->ec_port;
877
878 if (!(ec->flags & ECF_ENABLED))
879 panic( "lance", "got premature interrupt", NO_NUM);
880
881 for (;;)
882 {
883#if 0
884 printf("ETH: Reading ISR...");
885#endif
886 out_word(ioaddr+LANCE_ADDR, 0x00);
887 isr=in_word(ioaddr+LANCE_DATA);
888 if (isr & 0x8600)
889 out_word( ioaddr+LANCE_DATA, isr & ~0x004f);
890 out_word(ioaddr+LANCE_DATA, 0x7940);
891#if 0
892 printf("ISR=0x%x...",in_word(ioaddr+LANCE_DATA));
893#endif
894#define ISR_WINT 0x0200
895#define ISR_RINT 0x0400
896#define ISR_RERR 0x1000
897#define ISR_WERR 0x4000
898#define ISR_ERR 0x8000
899#define ISR_RST 0x0000
900
901 if ((isr & (ISR_WINT|ISR_RINT|ISR_RERR|ISR_WERR|ISR_ERR)) == 0x0000)
902 {
903#if 0
904 printf("OK\n");
905#endif
906 break;
907 }
908
909 if (isr & ISR_RERR)
910 {
911#if 0
912 printf("RERR\n");
913#endif
914 ec->eth_stat.ets_recvErr++;
915 }
916 if ((isr & ISR_WERR) || (isr & ISR_WINT))
917 {
918 if (isr & ISR_WERR)
919 {
920#if 0
921 printf("WERR\n");
922#endif
923 ec->eth_stat.ets_sendErr++;
924 }
925 if (isr & ISR_WINT)
926 {
927#if 0
928 printf("WINT\n");
929#endif
930 /* status check: restart if needed. */
931 status = lp->tx_ring[cur_tx_slot_nr].u.base;
932
933 /* ??? */
934 if (status & 0x40000000)
935 {
936 status = lp->tx_ring[cur_tx_slot_nr].misc;
937 ec->eth_stat.ets_sendErr++;
938 if (status & 0x0400)
939 ec->eth_stat.ets_transAb++;
940 if (status & 0x0800)
941 ec->eth_stat.ets_carrSense++;
942 if (status & 0x1000)
943 ec->eth_stat.ets_OWC++;
944 if (status & 0x4000)
945 {
946 ec->eth_stat.ets_fifoUnder++;
947 must_restart=1;
948 }
949 }
950 else
951 {
952 if (status & 0x18000000)
953 ec->eth_stat.ets_collision++;
954 ec->eth_stat.ets_packetT++;
955 }
956 }
957 /* transmit a packet on the next slot if it exists. */
958 check = 0;
959 if (isstored[cur_tx_slot_nr]==1)
960 {
961 /* free the tx-slot just transmitted */
962 isstored[cur_tx_slot_nr]=0;
963 cur_tx_slot_nr = (++cur_tx_slot_nr) & TX_RING_MOD_MASK;
964
965 /* next tx-slot is ready? */
966 if (isstored[cur_tx_slot_nr]==1)
967 check=1;
968 else
969 check=0;
970 }
971 else
972 {
973 panic( "lance", "got premature WINT...", NO_NUM);
974 }
975 if (check==1)
976 {
977 lp->tx_ring[cur_tx_slot_nr].u.addr[3] = 0x83;
978 out_word(ioaddr+LANCE_ADDR, 0x0000);
979 out_word(ioaddr+LANCE_DATA, 0x0048);
980 }
981 else
982 if (check==-1)
983 continue;
984 /* we set a buffered message in the slot if it exists. */
985 /* and transmit it, if needed. */
986 if (ec->flags & ECF_SEND_AVAIL)
987 ec_send(ec);
988 }
989 if (isr & ISR_RINT)
990 {
991#if 0
992 printf("RINT\n");
993#endif
994 ec_recv(ec);
995 }
996
997 if (isr & ISR_RST)
998 {
999 ec->flags = ECF_STOPPED;
1000 break;
1001 }
1002
1003 /* ??? cf. lance driver on linux */
1004 if (must_restart == 1)
1005 {
1006#if 0
1007 printf("ETH: restarting...\n");
1008#endif
1009 out_word(ioaddr+LANCE_ADDR, 0x0);
1010 (void)in_word(ioaddr+LANCE_ADDR);
1011 out_word(ioaddr+LANCE_DATA, 0x4); /* stop */
1012 out_word(ioaddr+LANCE_DATA, 0x2); /* start */
1013 }
1014 }
1015
1016 if ((ec->flags & (ECF_READING|ECF_STOPPED)) == (ECF_READING|ECF_STOPPED))
1017 {
1018#if 0
1019 printf("ETH: resetting...\n");
1020#endif
1021 ec_reset(ec);
1022 }
1023}
1024
1025/*===========================================================================*
1026 * ec_reset *
1027 *===========================================================================*/
1028static void ec_reset(ec)
1029ether_card_t *ec;
1030{
1031 /* Stop/start the chip, and clear all RX,TX-slots */
1032 unsigned short ioaddr = ec->ec_port;
1033 int i;
1034
1035 out_word(ioaddr+LANCE_ADDR, 0x0);
1036 (void)in_word(ioaddr+LANCE_ADDR);
1037 out_word(ioaddr+LANCE_DATA, 0x4); /* stop */
1038 out_word(ioaddr+LANCE_DATA, 0x2); /* start */
1039
1040 /* purge Tx-ring */
1041 tx_slot_nr = cur_tx_slot_nr = 0;
1042 for (i=0; i<TX_RING_SIZE; i++) {
1043 lp->tx_ring[i].u.base = 0;
1044 isstored[i]=0;
1045 }
1046
1047 /* re-init Rx-ring */
1048 rx_slot_nr = 0;
1049 for (i=0; i<RX_RING_SIZE; i++)
1050 {
1051 lp->rx_ring[i].buf_length = -ETH_FRAME_LEN;
1052 lp->rx_ring[i].u.addr[3] |= 0x80;
1053 }
1054
1055 /* store a buffered message on the slot if exists */
1056 ec_send(ec);
1057 ec->flags &= ~ECF_STOPPED;
1058}
1059
1060/*===========================================================================*
1061 * ec_send *
1062 *===========================================================================*/
1063static void ec_send(ec)
1064ether_card_t *ec;
1065{
1066 /* from ec_check_ints() or ec_reset(). */
1067 /* this function proccesses the buffered message. (slot/transmit) */
1068 if (!(ec->flags & ECF_SEND_AVAIL))
1069 return;
1070
1071 ec->flags &= ~ECF_SEND_AVAIL;
1072 switch(ec->sendmsg.m_type)
1073 {
1074 case DL_WRITE: do_vwrite(&ec->sendmsg, TRUE, FALSE); break;
1075 case DL_WRITEV: do_vwrite(&ec->sendmsg, TRUE, TRUE); break;
1076 default:
1077 panic( "lance", "wrong type:", ec->sendmsg.m_type);
1078 break;
1079 }
1080}
1081
1082/*===========================================================================*
1083 * do_vread *
1084 *===========================================================================*/
1085static void do_vread(mp, vectored)
1086message *mp;
1087int vectored;
1088{
1089 int port, count, size;
1090 ether_card_t *ec;
1091
1092 port = mp->DL_PORT;
1093 count = mp->DL_COUNT;
1094 ec= &ec_table[port];
1095 ec->client= mp->DL_PROC;
1096
1097 if (vectored)
1098 {
1099 get_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
1100 (count > IOVEC_NR ? IOVEC_NR : count) *
1101 sizeof(iovec_t), ec->read_iovec.iod_iovec);
1102 ec->read_iovec.iod_iovec_s = count;
1103 ec->read_iovec.iod_proc_nr = mp->DL_PROC;
1104 ec->read_iovec.iod_iovec_addr = (vir_bytes) mp->DL_ADDR;
1105
1106 ec->tmp_iovec = ec->read_iovec;
1107 size= calc_iovec_size(&ec->tmp_iovec);
1108 }
1109 else
1110 {
1111 ec->read_iovec.iod_iovec[0].iov_addr = (vir_bytes) mp->DL_ADDR;
1112 ec->read_iovec.iod_iovec[0].iov_size = mp->DL_COUNT;
1113 ec->read_iovec.iod_iovec_s = 1;
1114 ec->read_iovec.iod_proc_nr = mp->DL_PROC;
1115 ec->read_iovec.iod_iovec_addr = 0;
1116
1117 size= count;
1118 }
1119 ec->flags |= ECF_READING;
1120
1121 ec_recv(ec);
1122
1123 if ((ec->flags & (ECF_READING|ECF_STOPPED)) == (ECF_READING|ECF_STOPPED))
1124 ec_reset(ec);
1125 reply(ec, OK, FALSE);
1126}
1127
1128/*===========================================================================*
1129 * ec_recv *
1130 *===========================================================================*/
1131static void ec_recv(ec)
1132ether_card_t *ec;
1133{
1134 vir_bytes length;
1135 int packet_processed;
1136 int status;
1137 unsigned short ioaddr = ec->ec_port;
1138
1139 if ((ec->flags & ECF_READING)==0)
1140 return;
1141 if (!(ec->flags & ECF_ENABLED))
1142 return;
1143
1144 /* we check all the received slots until find a properly received packet */
1145 packet_processed = FALSE;
1146 while (!packet_processed)
1147 {
1148 status = lp->rx_ring[rx_slot_nr].u.base >> 24;
1149 if ( (status & 0x80) == 0x00 )
1150 {
1151 status = lp->rx_ring[rx_slot_nr].u.base >> 24;
1152
1153 /* ??? */
1154 if (status != 0x03)
1155 {
1156 if (status & 0x01)
1157 ec->eth_stat.ets_recvErr++;
1158 if (status & 0x04)
1159 ec->eth_stat.ets_fifoOver++;
1160 if (status & 0x08)
1161 ec->eth_stat.ets_CRCerr++;
1162 if (status & 0x10)
1163 ec->eth_stat.ets_OVW++;
1164 if (status & 0x20)
1165 ec->eth_stat.ets_frameAll++;
1166 length = 0;
1167 }
1168 else
1169 {
1170 ec->eth_stat.ets_packetR++;
1171 length = lp->rx_ring[rx_slot_nr].msg_length;
1172 }
1173 if (length > 0)
1174 {
1175 ec_nic2user(ec, (int)(lp->rbuf[rx_slot_nr]),
1176 &ec->read_iovec, 0, length);
1177
1178 ec->read_s = length;
1179 ec->flags |= ECF_PACK_RECV;
1180 ec->flags &= ~ECF_READING;
1181 packet_processed = TRUE;
1182 }
1183 /* set up this slot again, and we move to the next slot */
1184 lp->rx_ring[rx_slot_nr].buf_length = -ETH_FRAME_LEN;
1185 lp->rx_ring[rx_slot_nr].u.addr[3] |= 0x80;
1186
1187 out_word(ioaddr+LANCE_ADDR, 0x00);
1188 out_word(ioaddr+LANCE_DATA, 0x7940);
1189
1190 rx_slot_nr = (++rx_slot_nr) & RX_RING_MOD_MASK;
1191 }
1192 else
1193 break;
1194 }
1195}
1196
1197/*===========================================================================*
1198 * do_vwrite *
1199 *===========================================================================*/
1200static void do_vwrite(mp, from_int, vectored)
1201message *mp;
1202int from_int;
1203int vectored;
1204{
1205 int port, count, check;
1206 ether_card_t *ec;
1207 unsigned short ioaddr;
1208
1209 port = mp->DL_PORT;
1210 count = mp->DL_COUNT;
1211 ec = &ec_table[port];
1212 ec->client= mp->DL_PROC;
1213
1214 if (isstored[tx_slot_nr]==1)
1215 {
1216 /* all slots are used, so this message is buffered */
1217 ec->sendmsg= *mp;
1218 ec->flags |= ECF_SEND_AVAIL;
1219 reply(ec, OK, FALSE);
1220 return;
1221 }
1222
1223 /* convert the message to write_iovec */
1224 if (vectored)
1225 {
1226 get_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
1227 (count > IOVEC_NR ? IOVEC_NR : count) *
1228 sizeof(iovec_t), ec->write_iovec.iod_iovec);
1229
1230 ec->write_iovec.iod_iovec_s = count;
1231 ec->write_iovec.iod_proc_nr = mp->DL_PROC;
1232 ec->write_iovec.iod_iovec_addr = (vir_bytes) mp->DL_ADDR;
1233
1234 ec->tmp_iovec = ec->write_iovec;
1235 ec->write_s = calc_iovec_size(&ec->tmp_iovec);
1236 }
1237 else
1238 {
1239 ec->write_iovec.iod_iovec[0].iov_addr = (vir_bytes) mp->DL_ADDR;
1240 ec->write_iovec.iod_iovec[0].iov_size = mp->DL_COUNT;
1241
1242 ec->write_iovec.iod_iovec_s = 1;
1243 ec->write_iovec.iod_proc_nr = mp->DL_PROC;
1244 ec->write_iovec.iod_iovec_addr = 0;
1245
1246 ec->write_s = mp->DL_COUNT;
1247 }
1248
1249 /* copy write_iovec to the slot on DMA address */
1250 ec_user2nic(ec, &ec->write_iovec, 0,
1251 (int)(lp->tbuf[tx_slot_nr]), ec->write_s);
1252 /* set-up for transmitting, and transmit it if needed. */
1253 lp->tx_ring[tx_slot_nr].buf_length = -ec->write_s;
1254 lp->tx_ring[tx_slot_nr].misc = 0x0;
1255 lp->tx_ring[tx_slot_nr].u.base
1256 = virt_to_bus(lp->tbuf[tx_slot_nr]) & 0xffffff;
1257 isstored[tx_slot_nr]=1;
1258 if (cur_tx_slot_nr == tx_slot_nr)
1259 check=1;
1260 else
1261 check=0;
1262 tx_slot_nr = (++tx_slot_nr) & TX_RING_MOD_MASK;
1263
1264 if (check == 1)
1265 {
1266 ioaddr = ec->ec_port;
1267 lp->tx_ring[cur_tx_slot_nr].u.addr[3] = 0x83;
1268 out_word(ioaddr+LANCE_ADDR, 0x0000);
1269 out_word(ioaddr+LANCE_DATA, 0x0048);
1270 }
1271
1272 ec->flags |= ECF_PACK_SEND;
1273
1274 /* reply by calling do_int() if this function is called from interrupt. */
1275 if (from_int)
1276 return;
1277 reply(ec, OK, FALSE);
1278}
1279
1280
1281/*===========================================================================*
1282 * get_userdata *
1283 *===========================================================================*/
1284static void get_userdata(user_proc, user_addr, count, loc_addr)
1285int user_proc;
1286vir_bytes user_addr;
1287vir_bytes count;
1288void *loc_addr;
1289{
1290 /*
1291 phys_bytes src;
1292
1293 src = numap_local(user_proc, user_addr, count);
1294 if (!src)
1295 panic( "lance", "umap failed", NO_NUM);
1296
1297 phys_copy(src, vir2phys(loc_addr), (phys_bytes) count);
1298 */
1299 int cps;
1300 cps = sys_datacopy(user_proc, user_addr, SELF, (vir_bytes) loc_addr, count);
1301 if (cps != OK) printf("lance: warning, scopy failed: %d\n", cps);
1302}
1303
1304/*===========================================================================*
1305 * ec_user2nic *
1306 *===========================================================================*/
1307static void ec_user2nic(ec, iovp, offset, nic_addr, count)
1308ether_card_t *ec;
1309iovec_dat_t *iovp;
1310vir_bytes offset;
1311int nic_addr;
1312vir_bytes count;
1313{
1314 /*phys_bytes phys_hw, phys_user;*/
1315 int bytes, i, r;
1316
1317 /*
1318 phys_hw = vir2phys(nic_addr);
1319 */
1320 i= 0;
1321 while (count > 0)
1322 {
1323 if (i >= IOVEC_NR)
1324 {
1325 ec_next_iovec(iovp);
1326 i= 0;
1327 continue;
1328 }
1329 if (offset >= iovp->iod_iovec[i].iov_size)
1330 {
1331 offset -= iovp->iod_iovec[i].iov_size;
1332 i++;
1333 continue;
1334 }
1335 bytes = iovp->iod_iovec[i].iov_size - offset;
1336 if (bytes > count)
1337 bytes = count;
1338
1339 /*
1340 phys_user = numap_local(iovp->iod_proc_nr,
1341 iovp->iod_iovec[i].iov_addr + offset, bytes);
1342
1343 phys_copy(phys_user, phys_hw, (phys_bytes) bytes);
1344 */
1345 if ( (r=sys_datacopy(iovp->iod_proc_nr, iovp->iod_iovec[i].iov_addr + offset,
1346 SELF, nic_addr, count )) != OK )
1347 panic( "lance", "sys_datacopy failed", r );
1348
1349 count -= bytes;
1350 nic_addr += bytes;
1351 offset += bytes;
1352 }
1353}
1354
1355/*===========================================================================*
1356 * ec_nic2user *
1357 *===========================================================================*/
1358static void ec_nic2user(ec, nic_addr, iovp, offset, count)
1359ether_card_t *ec;
1360int nic_addr;
1361iovec_dat_t *iovp;
1362vir_bytes offset;
1363vir_bytes count;
1364{
1365 /*phys_bytes phys_hw, phys_user;*/
1366 int bytes, i, r;
1367
1368 /*phys_hw = vir2phys(nic_addr);*/
1369
1370 i= 0;
1371 while (count > 0)
1372 {
1373 if (i >= IOVEC_NR)
1374 {
1375 ec_next_iovec(iovp);
1376 i= 0;
1377 continue;
1378 }
1379 if (offset >= iovp->iod_iovec[i].iov_size)
1380 {
1381 offset -= iovp->iod_iovec[i].iov_size;
1382 i++;
1383 continue;
1384 }
1385 bytes = iovp->iod_iovec[i].iov_size - offset;
1386 if (bytes > count)
1387 bytes = count;
1388 /*
1389 phys_user = numap_local(iovp->iod_proc_nr,
1390 iovp->iod_iovec[i].iov_addr + offset, bytes);
1391
1392 phys_copy(phys_hw, phys_user, (phys_bytes) bytes);
1393 */
1394 if ( (r=sys_datacopy( SELF, nic_addr, iovp->iod_proc_nr, iovp->iod_iovec[i].iov_addr + offset, bytes )) != OK )
1395 panic( "lance", "sys_datacopy failed: ", r );
1396
1397 count -= bytes;
1398 nic_addr += bytes;
1399 offset += bytes;
1400 }
1401}
1402
1403
1404/*===========================================================================*
1405 * calc_iovec_size *
1406 *===========================================================================*/
1407static int calc_iovec_size(iovp)
1408iovec_dat_t *iovp;
1409{
1410 int size,i;
1411
1412 size = i = 0;
1413
1414 while (i < iovp->iod_iovec_s)
1415 {
1416 if (i >= IOVEC_NR)
1417 {
1418 ec_next_iovec(iovp);
1419 i= 0;
1420 continue;
1421 }
1422 size += iovp->iod_iovec[i].iov_size;
1423 i++;
1424 }
1425
1426 return size;
1427}
1428
1429/*===========================================================================*
1430 * ec_next_iovec *
1431 *===========================================================================*/
1432static void ec_next_iovec(iovp)
1433iovec_dat_t *iovp;
1434{
1435 iovp->iod_iovec_s -= IOVEC_NR;
1436 iovp->iod_iovec_addr += IOVEC_NR * sizeof(iovec_t);
1437
1438 get_userdata(iovp->iod_proc_nr, iovp->iod_iovec_addr,
1439 (iovp->iod_iovec_s > IOVEC_NR ?
1440 IOVEC_NR : iovp->iod_iovec_s) * sizeof(iovec_t),
1441 iovp->iod_iovec);
1442}
1443
1444
1445/*===========================================================================*
1446 * do_getstat *
1447 *===========================================================================*/
1448static void do_getstat(mp)
1449message *mp;
1450{
1451 int port;
1452 ether_card_t *ec;
1453
1454 port = mp->DL_PORT;
1455 if (port < 0 || port >= EC_PORT_NR_MAX)
1456 panic( "lance", "illegal port", port);
1457
1458 ec= &ec_table[port];
1459 ec->client= mp->DL_PROC;
1460
1461 put_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
1462 (vir_bytes) sizeof(ec->eth_stat), &ec->eth_stat);
1463 reply(ec, OK, FALSE);
1464}
1465
1466/*===========================================================================*
1467 * put_userdata *
1468 *===========================================================================*/
1469static void put_userdata(user_proc, user_addr, count, loc_addr)
1470int user_proc;
1471vir_bytes user_addr;
1472vir_bytes count;
1473void *loc_addr;
1474{
1475 /*phys_bytes dst;
1476
1477 dst = numap_local(user_proc, user_addr, count);
1478 if (!dst)
1479 panic( "lance", "umap failed", NO_NUM);
1480
1481 phys_copy(vir2phys(loc_addr), dst, (phys_bytes) count);
1482 */
1483 int cps;
1484 cps = sys_datacopy(SELF, (vir_bytes) loc_addr, user_proc, user_addr, count);
1485 if (cps != OK) printf("lance: warning, scopy failed: %d\n", cps);
1486}
1487
1488/*===========================================================================*
1489 * do_stop *
1490 *===========================================================================*/
1491static void do_stop(mp)
1492message *mp;
1493{
1494 int port;
1495 ether_card_t *ec;
1496 unsigned short ioaddr;
1497
1498 port = mp->DL_PORT;
1499 if (port < 0 || port >= EC_PORT_NR_MAX)
1500 panic( "lance", "illegal port", port);
1501 ec = &ec_table[port];
1502
1503 if (!(ec->flags & ECF_ENABLED))
1504 return;
1505
1506 ioaddr = ec->ec_port;
1507
1508 out_word(ioaddr+LANCE_ADDR, 0x0);
1509 (void)in_word(ioaddr+LANCE_ADDR);
1510 out_word(ioaddr+LANCE_DATA, 0x4); /* stop */
1511 out_word(ioaddr+LANCE_RESET, in_word(ioaddr+LANCE_RESET)); /* reset */
1512
1513 ec->flags = ECF_EMPTY;
1514}
1515
1516static void getAddressing(devind, ec)
1517int devind;
1518ether_card_t *ec;
1519{
1520 unsigned int membase, ioaddr;
1521 int reg, irq;
1522
1523 for (reg = PCI_BASE_ADDRESS_0; reg <= PCI_BASE_ADDRESS_5; reg += 4)
1524 {
1525 ioaddr = pci_attr_r32(devind, reg);
1526
1527 if ((ioaddr & PCI_BASE_ADDRESS_IO_MASK) == 0
1528 || (ioaddr & PCI_BASE_ADDRESS_SPACE_IO) == 0)
1529 continue;
1530 /* Strip the I/O address out of the returned value */
1531 ioaddr &= PCI_BASE_ADDRESS_IO_MASK;
1532 /* Get the memory base address */
1533 membase = pci_attr_r32(devind, PCI_BASE_ADDRESS_1);
1534 /* KK: Get the IRQ number */
1535 irq = pci_attr_r8(devind, PCI_INTERRUPT_PIN);
1536 if (irq)
1537 irq = pci_attr_r8(devind, PCI_INTERRUPT_LINE);
1538 /* Get the ROM base address */
1539 /*pci_attr_r32(devind, PCI_ROM_ADDRESS, &romaddr);
1540 romaddr >>= 10;*/
1541 /* Take the first one or the one that matches in boot ROM address */
1542 /*if (pci_ioaddr == 0
1543 || romaddr == ((unsigned long) rom.rom_segment << 4)) {*/
1544 ec->ec_linmem = membase;
1545 ec->ec_port = ioaddr;
1546 ec->ec_irq = irq;
1547 /*}*/
1548 }
1549}
1550
1551/*===========================================================================*
1552 * lance_probe *
1553 *===========================================================================*/
1554static int lance_probe(ec)
1555ether_card_t *ec;
1556{
1557 unsigned short pci_cmd, attached = 0;
1558 unsigned short ioaddr;
1559 int lance_version, chip_version;
1560 int devind, just_one, i, r;
1561
1562 u16_t vid, did;
1563 u32_t bar;
1564 u8_t ilr;
1565 char *dname;
1566
1567 if ((ec->ec_pcibus | ec->ec_pcidev | ec->ec_pcifunc) != 0)
1568 {
1569 /* Look for specific PCI device */
1570 r= pci_find_dev(ec->ec_pcibus, ec->ec_pcidev,
1571 ec->ec_pcifunc, &devind);
1572 if (r == 0)
1573 {
1574 printf("%s: no PCI found at %d.%d.%d\n",
1575 ec->port_name, ec->ec_pcibus,
1576 ec->ec_pcidev, ec->ec_pcifunc);
1577 return 0;
1578 }
1579 pci_ids(devind, &vid, &did);
1580 just_one= TRUE;
1581 }
1582 else
1583 {
1584 r= pci_first_dev(&devind, &vid, &did);
1585 if (r == 0)
1586 return 0;
1587 just_one= FALSE;
1588 }
1589
1590 for(;;)
1591 {
1592 for (i= 0; pcitab[i].vid != 0; i++)
1593 {
1594 if (pcitab[i].vid != vid)
1595 continue;
1596 if (pcitab[i].did != did)
1597 continue;
1598 if (pcitab[i].checkclass)
1599 {
1600 panic("lance",
1601 "class check not implemented", NO_NUM);
1602 }
1603 break;
1604 }
1605 if (pcitab[i].vid != 0)
1606 break;
1607
1608 if (just_one)
1609 {
1610 printf(
1611 "%s: wrong PCI device (%04x/%04x) found at %d.%d.%d\n",
1612 ec->port_name, vid, did,
1613 ec->ec_pcibus,
1614 ec->ec_pcidev, ec->ec_pcifunc);
1615 return 0;
1616 }
1617
1618 r= pci_next_dev(&devind, &vid, &did);
1619 if (!r)
1620 return 0;
1621 }
1622
1623 dname= pci_dev_name(vid, did);
1624 if (!dname)
1625 dname= "unknown device";
1626
1627 /*
1628 printf("%s: ", ec->port_name);
1629 printf("%s ", dname);
1630 printf("(%x/", vid);
1631 printf("%x) ", did);
1632 printf("at %s\n", pci_slot_name(devind));
1633 */
1634 pci_reserve(devind);
1635
1636/* for (i = 0; pci_dev_list[i].vendor != 0; i++) {
1637 if (pci_dev_list[i].suffix == 1)
1638 {
1639 ec->ec_port = pci_dev_list[i].ioaddr;
1640 ec->ec_irq = pci_dev_list[i].irq;
1641 ec->ec_linmem = pci_dev_list[i].membase;
1642 ec->ec_bus = pci_dev_list[i].bus;
1643 ec->ec_dev = pci_dev_list[i].devfn;
1644 ec->ec_fnc =
1645 pci_dev_list[i].suffix = -1;
1646 attached = 1;
1647 break;
1648 }
1649 }
1650 if (attached == 0)
1651 return 0;
1652*/
1653 getAddressing(devind, ec);
1654
1655 /* ===== Bus Master ? ===== */
1656 /*pcibios_read_config_word(ec->ec_bus, ec->ec_devfn, PCI_COMMAND, &pci_cmd);*/
1657 pci_cmd = pci_attr_r32(devind, PCI_CR);
1658 if (!(pci_cmd & PCI_COMMAND_MASTER)) {
1659 pci_cmd |= PCI_COMMAND_MASTER;
1660 /*pcibios_write_config_word(ec->ec_bus, ec->ec_devfn, PCI_COMMAND, pci_cmd);*/
1661 pci_attr_w32(devind, PCI_CR, pci_cmd);
1662 }
1663
1664 /* ===== Probe Details ===== */
1665 ioaddr = ec->ec_port;
1666
1667 out_word(ioaddr+LANCE_RESET, in_word(ioaddr+LANCE_RESET)); /* Reset */
1668 out_word(ioaddr+LANCE_ADDR, 0x0); /* Sw to win 0 */
1669 if (in_word(ioaddr+LANCE_DATA) != 0x4)
1670 {
1671 ec->mode=EC_DISABLED;
1672 }
1673 /* Probe Chip Version */
1674 out_word(ioaddr+LANCE_ADDR, 88); /* Get the version of the chip */
1675 if (in_word(ioaddr+LANCE_ADDR) != 88)
1676 lance_version = 0;
1677 else
1678 {
1679 chip_version = in_word(ioaddr+LANCE_DATA);
1680 out_word(ioaddr+LANCE_ADDR, 89);
1681 chip_version |= in_word(ioaddr+LANCE_DATA) << 16;
1682 if ((chip_version & 0xfff) != 0x3)
1683 {
1684 ec->mode=EC_DISABLED;
1685 }
1686 chip_version = (chip_version >> 12) & 0xffff;
1687 for (lance_version = 1; chip_table[lance_version].id_number != 0;
1688 ++lance_version)
1689 if (chip_table[lance_version].id_number == chip_version)
1690 break;
1691 }
1692
1693#if 0
1694 printf("%s: %s at %X:%d\n",
1695 ec->port_name, chip_table[lance_version].name,
1696 ec->ec_port, ec->ec_irq);
1697#endif
1698
1699 return lance_version;
1700}
1701
1702/*===========================================================================*
1703 * do_getname *
1704 *===========================================================================*/
1705static void do_getname(mp)
1706message *mp;
1707{
1708 int r;
1709
1710 strncpy(mp->DL_NAME, progname, sizeof(mp->DL_NAME));
1711 mp->DL_NAME[sizeof(mp->DL_NAME)-1]= '\0';
1712 mp->m_type= DL_NAME_REPLY;
1713 r= send(mp->m_source, mp);
1714 if (r != OK)
1715 panic("LANCE", "do_getname: send failed", r);
1716}
1717
1718/*===========================================================================*
1719 * lance_init_card *
1720 *===========================================================================*/
1721static void lance_init_card(ec)
1722ether_card_t *ec;
1723{
1724 int i;
1725 Address l;
1726 unsigned short ioaddr = ec->ec_port;
1727
1728 /* ============= setup init_block(cf. lance_probe1) ================ */
1729 /* make sure data structure is 8-byte aligned */
1730 l = ((Address)lance + 7) & ~7;
1731 lp = (struct lance_interface *)l;
1732 lp->init_block.mode = 0x3; /* disable Rx and Tx */
1733 lp->init_block.filter[0] = lp->init_block.filter[1] = 0x0;
1734 /* using multiple Rx/Tx buffer */
1735 lp->init_block.rx_ring
1736 = (virt_to_bus(&lp->rx_ring) & 0xffffff) | RX_RING_LEN_BITS;
1737 lp->init_block.tx_ring
1738 = (virt_to_bus(&lp->tx_ring) & 0xffffff) | TX_RING_LEN_BITS;
1739
1740 l = virt_to_bus(&lp->init_block);
1741 out_word(ioaddr+LANCE_ADDR, 0x1);
1742 (void)in_word(ioaddr+LANCE_ADDR);
1743 out_word(ioaddr+LANCE_DATA, (unsigned short)l);
1744 out_word(ioaddr+LANCE_ADDR, 0x2);
1745 (void)in_word(ioaddr+LANCE_ADDR);
1746 out_word(ioaddr+LANCE_DATA, (unsigned short)(l >> 16));
1747 out_word(ioaddr+LANCE_ADDR, 0x4);
1748 (void)in_word(ioaddr+LANCE_ADDR);
1749 out_word(ioaddr+LANCE_DATA, 0x915);
1750 out_word(ioaddr+LANCE_ADDR, 0x0);
1751 (void)in_word(ioaddr+LANCE_ADDR);
1752
1753 /* ============= Get MAC address (cf. lance_probe1) ================ */
1754 for (i = 0; i < 6; ++i)
1755 ec->mac_address.ea_addr[i]=in_byte(ioaddr+LANCE_ETH_ADDR+i);
1756
1757 /* ============ (re)start init_block(cf. lance_reset) =============== */
1758 /* Reset the LANCE */
1759 (void)in_word(ioaddr+LANCE_RESET);
1760
1761 /* ----- Re-initialize the LANCE ----- */
1762 /* Set station address */
1763 for (i = 0; i < 6; ++i)
1764 lp->init_block.phys_addr[i] = ec->mac_address.ea_addr[i];
1765 /* Preset the receive ring headers */
1766 for (i=0; i<RX_RING_SIZE; i++) {
1767 lp->rx_ring[i].buf_length = -ETH_FRAME_LEN;
1768 /* OWN */
1769 lp->rx_ring[i].u.base = virt_to_bus(lp->rbuf[i]) & 0xffffff;
1770 /* we set the top byte as the very last thing */
1771 lp->rx_ring[i].u.addr[3] = 0x80;
1772 }
1773 /* Preset the transmitting ring headers */
1774 for (i=0; i<TX_RING_SIZE; i++) {
1775 lp->tx_ring[i].u.base = 0;
1776 isstored[i] = 0;
1777 }
1778 lp->init_block.mode = 0x0; /* enable Rx and Tx */
1779
1780 l = (Address)virt_to_bus(&lp->init_block);
1781 out_word(ioaddr+LANCE_ADDR, 0x1);
1782 (void)in_word(ioaddr+LANCE_ADDR);
1783 out_word(ioaddr+LANCE_DATA, (short)l);
1784 out_word(ioaddr+LANCE_ADDR, 0x2);
1785 (void)in_word(ioaddr+LANCE_ADDR);
1786 out_word(ioaddr+LANCE_DATA, (short)(l >> 16));
1787 out_word(ioaddr+LANCE_ADDR, 0x4);
1788 (void)in_word(ioaddr+LANCE_ADDR);
1789 out_word(ioaddr+LANCE_DATA, 0x915);
1790 out_word(ioaddr+LANCE_ADDR, 0x0);
1791 (void)in_word(ioaddr+LANCE_ADDR);
1792
1793 /* ----- start when init done. ----- */
1794 out_word(ioaddr+LANCE_DATA, 0x4); /* stop */
1795 out_word(ioaddr+LANCE_DATA, 0x1); /* init */
1796 for (i = 10000; i > 0; --i)
1797 if (in_word(ioaddr+LANCE_DATA) & 0x100)
1798 break;
1799
1800 /* Set 'Multicast Table' */
1801 for (i=0;i<4;++i)
1802 {
1803 out_word(ioaddr+LANCE_ADDR, 0x8 + i);
1804 out_word(ioaddr+LANCE_DATA, 0xffff);
1805 }
1806
1807 /* Set 'Receive Mode' */
1808 if (ec->flags & ECF_PROMISC)
1809 {
1810 out_word(ioaddr+LANCE_ADDR, 0xf);
1811 out_word(ioaddr+LANCE_DATA, 0x8000);
1812 }
1813 else
1814 {
1815 if (ec->flags & (ECF_BROAD | ECF_MULTI))
1816 {
1817 out_word(ioaddr+LANCE_ADDR, 0xf);
1818 out_word(ioaddr+LANCE_DATA, 0x0000);
1819 }
1820 else
1821 {
1822 out_word(ioaddr+LANCE_ADDR, 0xf);
1823 out_word(ioaddr+LANCE_DATA, 0x4000);
1824 }
1825 }
1826
1827 out_word(ioaddr+LANCE_ADDR, 0x0);
1828 (void)in_word(ioaddr+LANCE_ADDR);
1829 out_word(ioaddr+LANCE_DATA, 0x142); /* start && enable interrupt */
1830
1831 return;
1832}
Note: See TracBrowser for help on using the repository browser.