source: trunk/minix/drivers/rtl8139/rtl8139.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: 66.1 KB
Line 
1/*
2 * rtl8139.c
3 *
4 * This file contains a ethernet device driver for Realtek rtl8139 based
5 * ethernet 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 * | HARD_INT | | | | | |
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_GETNAME | | | | | |
26 * |------------|----------|---------|----------|---------|---------|
27 * | DL_STOP | port_nr | | | | |
28 * |------------|----------|---------|----------|---------|---------|
29 *
30 * The messages sent are:
31 *
32 * m-type DL_POR T DL_PROC DL_COUNT DL_STAT DL_CLCK
33 * |------------|----------|---------|----------|---------|---------|
34 * |DL_TASK_REPL| port nr | proc nr | rd-count | err|stat| clock |
35 * |------------|----------|---------|----------|---------|---------|
36 *
37 * m_type m3_i1 m3_i2 m3_ca1
38 * |------------+---------+-----------+---------------|
39 * |DL_INIT_REPL| port nr | last port | ethernet addr |
40 * |------------|---------|-----------|---------------|
41 *
42 * Created: Aug 2003 by Philip Homburg <philip@cs.vu.nl>
43 * Changes:
44 * Aug 15, 2004 sync alarms replace watchdogs timers (Jorrit N. Herder)
45 * May 02, 2004 flag alarms replace micro_elapsed() (Jorrit N. Herder)
46 *
47 */
48
49#include "../drivers.h"
50
51#include <stdlib.h>
52#include <stdio.h>
53#include <string.h>
54#include <stddef.h>
55#include <minix/com.h>
56#include <minix/keymap.h>
57#include <minix/syslib.h>
58#include <minix/type.h>
59#include <minix/sysutil.h>
60#include <timers.h>
61#include <ibm/portio.h>
62#include <net/hton.h>
63#include <net/gen/ether.h>
64#include <net/gen/eth_io.h>
65#include <ibm/pci.h>
66
67#include <sys/types.h>
68#include <fcntl.h>
69#include <assert.h>
70#include <unistd.h>
71#include <sys/ioc_memory.h>
72#include "../../kernel/const.h"
73#include "../../kernel/config.h"
74#include "../../kernel/type.h"
75
76#define tmra_ut timer_t
77#define tmra_inittimer(tp) tmr_inittimer(tp)
78#define Proc_number(p) proc_number(p)
79#define debug 0
80#define printW() ((void)0)
81#define vm_1phys2bus(p) (p)
82
83#define VERBOSE 1 /* display message during init */
84
85#include "rtl8139.h"
86
87#define RX_BUFSIZE RL_RCR_RBLEN_64K_SIZE
88#define RX_BUFBITS RL_RCR_RBLEN_64K
89#define N_TX_BUF RL_N_TX
90
91#define RE_PORT_NR 1 /* Minix */
92
93/* I/O vectors are handled IOVEC_NR entries at a time. */
94#define IOVEC_NR 16
95
96/* Configuration */
97#define RL_ENVVAR "RTLETH"
98
99PRIVATE struct pcitab
100{
101 u16_t vid;
102 u16_t did;
103 int checkclass;
104} pcitab[]=
105{
106 { 0x10ec, 0x8139, 0 }, /* Realtek RTL8139 */
107 { 0x1186, 0x1300, 0 }, /* D-Link RTL8139 */
108
109 { 0x0000, 0x0000, 0 }
110};
111
112typedef struct re
113{
114 port_t re_base_port;
115 int re_irq;
116 int re_mode;
117 int re_flags;
118 int re_client;
119 int re_link_up;
120 int re_got_int;
121 int re_send_int;
122 int re_report_link;
123 int re_clear_rx;
124 int re_need_reset;
125 int re_tx_alive;
126 char *re_model;
127
128 /* Rx */
129 phys_bytes re_rx_buf;
130 char *v_re_rx_buf;
131 vir_bytes re_read_s;
132
133 /* Tx */
134 int re_tx_head;
135 int re_tx_tail;
136 struct
137 {
138 int ret_busy;
139 phys_bytes ret_buf;
140 char * v_ret_buf;
141 } re_tx[N_TX_BUF];
142 u32_t re_ertxth; /* Early Tx Threshold */
143
144 /* PCI related */
145 int re_seen; /* TRUE iff device available */
146 u8_t re_pcibus;
147 u8_t re_pcidev;
148 u8_t re_pcifunc;
149
150 /* 'large' items */
151 int re_hook_id; /* IRQ hook id at kernel */
152 eth_stat_t re_stat;
153 ether_addr_t re_address;
154 message re_rx_mess;
155 message re_tx_mess;
156 char re_name[sizeof("rtl8139#n")];
157 iovec_t re_iovec[IOVEC_NR];
158}
159re_t;
160
161#define REM_DISABLED 0x0
162#define REM_ENABLED 0x1
163
164#define REF_PACK_SENT 0x001
165#define REF_PACK_RECV 0x002
166#define REF_SEND_AVAIL 0x004
167#define REF_READING 0x010
168#define REF_EMPTY 0x000
169#define REF_PROMISC 0x040
170#define REF_MULTI 0x080
171#define REF_BROAD 0x100
172#define REF_ENABLED 0x200
173
174static re_t re_table[RE_PORT_NR];
175
176static u16_t eth_ign_proto;
177static tmra_ut rl_watchdog;
178
179FORWARD _PROTOTYPE( unsigned my_inb, (U16_t port) );
180FORWARD _PROTOTYPE( unsigned my_inw, (U16_t port) );
181FORWARD _PROTOTYPE( unsigned my_inl, (U16_t port) );
182static unsigned my_inb(U16_t port) {
183 u32_t value;
184 int s;
185 if ((s=sys_inb(port, &value)) !=OK)
186 printf("RTL8139: warning, sys_inb failed: %d\n", s);
187 return value;
188}
189static unsigned my_inw(U16_t port) {
190 u32_t value;
191 int s;
192 if ((s=sys_inw(port, &value)) !=OK)
193 printf("RTL8139: warning, sys_inw failed: %d\n", s);
194 return value;
195}
196static unsigned my_inl(U16_t port) {
197 U32_t value;
198 int s;
199 if ((s=sys_inl(port, &value)) !=OK)
200 printf("RTL8139: warning, sys_inl failed: %d\n", s);
201 return value;
202}
203#define rl_inb(port, offset) (my_inb((port) + (offset)))
204#define rl_inw(port, offset) (my_inw((port) + (offset)))
205#define rl_inl(port, offset) (my_inl((port) + (offset)))
206
207FORWARD _PROTOTYPE( void my_outb, (U16_t port, U8_t value) );
208FORWARD _PROTOTYPE( void my_outw, (U16_t port, U16_t value) );
209FORWARD _PROTOTYPE( void my_outl, (U16_t port, U32_t value) );
210static void my_outb(U16_t port, U8_t value) {
211 int s;
212 if ((s=sys_outb(port, value)) !=OK)
213 printf("RTL8139: warning, sys_outb failed: %d\n", s);
214}
215static void my_outw(U16_t port, U16_t value) {
216 int s;
217 if ((s=sys_outw(port, value)) !=OK)
218 printf("RTL8139: warning, sys_outw failed: %d\n", s);
219}
220static void my_outl(U16_t port, U32_t value) {
221 int s;
222 if ((s=sys_outl(port, value)) !=OK)
223 printf("RTL8139: warning, sys_outl failed: %d\n", s);
224}
225#define rl_outb(port, offset, value) (my_outb((port) + (offset), (value)))
226#define rl_outw(port, offset, value) (my_outw((port) + (offset), (value)))
227#define rl_outl(port, offset, value) (my_outl((port) + (offset), (value)))
228
229_PROTOTYPE( static void sig_handler, (void) );
230_PROTOTYPE( static void rl_init, (message *mp) );
231_PROTOTYPE( static void rl_pci_conf, (void) );
232_PROTOTYPE( static int rl_probe, (re_t *rep) );
233_PROTOTYPE( static void rl_conf_hw, (re_t *rep) );
234_PROTOTYPE( static void rl_init_buf, (re_t *rep) );
235_PROTOTYPE( static void rl_init_hw, (re_t *rep) );
236_PROTOTYPE( static void rl_reset_hw, (re_t *rep) );
237_PROTOTYPE( static void rl_confaddr, (re_t *rep) );
238_PROTOTYPE( static void rl_rec_mode, (re_t *rep) );
239_PROTOTYPE( static void rl_readv, (message *mp, int from_int,
240 int vectored) );
241_PROTOTYPE( static void rl_writev, (message *mp, int from_int,
242 int vectored) );
243_PROTOTYPE( static void rl_check_ints, (re_t *rep) );
244_PROTOTYPE( static void rl_report_link, (re_t *rep) );
245_PROTOTYPE( static void mii_print_techab, (U16_t techab) );
246_PROTOTYPE( static void mii_print_stat_speed, (U16_t stat,
247 U16_t extstat) );
248_PROTOTYPE( static void rl_clear_rx, (re_t *rep) );
249_PROTOTYPE( static void rl_do_reset, (re_t *rep) );
250_PROTOTYPE( static void rl_getstat, (message *mp) );
251_PROTOTYPE( static void rl_getname, (message *mp) );
252_PROTOTYPE( static void reply, (re_t *rep, int err, int may_block) );
253_PROTOTYPE( static void mess_reply, (message *req, message *reply) );
254_PROTOTYPE( static void put_userdata, (int user_proc,
255 vir_bytes user_addr, vir_bytes count, void *loc_addr) );
256_PROTOTYPE( static void rtl8139_stop, (void) );
257_PROTOTYPE( static void check_int_events, (void) );
258_PROTOTYPE( static int do_hard_int, (void) );
259_PROTOTYPE( static void rtl8139_dump, (message *m) );
260#if 0
261_PROTOTYPE( static void dump_phy, (re_t *rep) );
262#endif
263_PROTOTYPE( static int rl_handler, (re_t *rep) );
264_PROTOTYPE( static void rl_watchdog_f, (timer_t *tp) );
265
266/* The message used in the main loop is made global, so that rl_watchdog_f()
267 * can change its message type to fake a HARD_INT message.
268 */
269PRIVATE message m;
270PRIVATE int int_event_check; /* set to TRUE if events arrived */
271
272static char *progname;
273extern int errno;
274
275/*===========================================================================*
276 * main *
277 *===========================================================================*/
278int main(int argc, char *argv[])
279{
280 int fkeys, sfkeys;
281 int inet_proc_nr;
282 int i, r;
283 re_t *rep;
284 long v;
285
286 env_setargs(argc, argv);
287
288 v= 0;
289 (void) env_parse("ETH_IGN_PROTO", "x", 0, &v, 0x0000L, 0xFFFFL);
290 eth_ign_proto= htons((u16_t) v);
291
292 /* Observe some function key for debug dumps. */
293 fkeys = sfkeys = 0; bit_set(sfkeys, 9);
294 if ((r=fkey_map(&fkeys, &sfkeys)) != OK)
295 printf("Warning: RTL8139 couldn't observe Shift+F9 key: %d\n",r);
296
297 /* Claim buffer memory now under Minix, before MM takes it all. */
298 for (rep= &re_table[0]; rep < re_table+RE_PORT_NR; rep++)
299 rl_init_buf(rep);
300
301 /* Try to notify INET that we are present (again). If INET cannot
302 * be found, assume this is the first time we started and INET is
303 * not yet alive.
304 */
305 (progname=strrchr(argv[0],'/')) ? progname++ : (progname=argv[0]);
306 r = _pm_findproc("inet", &inet_proc_nr);
307 if (r == OK) notify(inet_proc_nr);
308
309
310 while (TRUE)
311 {
312 if ((r= receive(ANY, &m)) != OK)
313 panic("rtl8139","receive failed", r);
314
315 switch (m.m_type)
316 {
317 case DEV_PING: notify(m.m_source); continue;
318 case DL_WRITEV: rl_writev(&m, FALSE, TRUE); break;
319 case DL_WRITE: rl_writev(&m, FALSE, FALSE); break;
320#if 0
321 case DL_READ: do_vread(&m, FALSE); break;
322#endif
323 case DL_READV: rl_readv(&m, FALSE, TRUE); break;
324 case DL_INIT: rl_init(&m); break;
325 case DL_GETSTAT: rl_getstat(&m); break;
326 case DL_GETNAME: rl_getname(&m); break;
327#if 0
328 case DL_STOP: do_stop(&m); break;
329#endif
330 case SYN_ALARM:
331 /* Under MINIX, synchronous alarms are used instead of
332 * watchdog functions. The approach is very different:
333 * MINIX VMD timeouts are handled within the kernel
334 * (the watchdog is executed by CLOCK), and notify()
335 * the driver in some cases.
336 * MINIX timeouts result in a SYN_ALARM message to the
337 * driver and thus are handled where they should be
338 * handled. Locally, watchdog functions are used again.
339 */
340 rl_watchdog_f(NULL);
341 break;
342 case HARD_INT:
343 do_hard_int();
344 if (int_event_check)
345 check_int_events();
346 break ;
347 case FKEY_PRESSED: rtl8139_dump(&m); break;
348 case PROC_EVENT:
349 sig_handler();
350 break;
351 default:
352 panic("rtl8139","illegal message", m.m_type);
353 }
354 }
355}
356
357/*===========================================================================*
358 * sig_handler *
359 *===========================================================================*/
360PRIVATE void sig_handler()
361{
362 sigset_t sigset;
363 int sig;
364
365 /* Try to obtain signal set from PM. */
366 if (getsigset(&sigset) != 0) return;
367
368 /* Check for known signals. */
369 if (sigismember(&sigset, SIGTERM)) {
370 rtl8139_stop();
371 }
372}
373
374/*===========================================================================*
375 * check_int_events *
376 *===========================================================================*/
377static void check_int_events(void)
378{
379 int i;
380 re_t *rep;
381 for (i= 0, rep= &re_table[0]; i<RE_PORT_NR; i++, rep++)
382 {
383 if (rep->re_mode != REM_ENABLED)
384 continue;
385 if (!rep->re_got_int)
386 continue;
387 rep->re_got_int= 0;
388 assert(rep->re_flags & REF_ENABLED);
389 rl_check_ints(rep);
390 }
391}
392
393/*===========================================================================*
394 * rtl8139_stop *
395 *===========================================================================*/
396static void rtl8139_stop()
397{
398 int i;
399 re_t *rep;
400
401 for (i= 0, rep= &re_table[0]; i<RE_PORT_NR; i++, rep++)
402 {
403 if (rep->re_mode != REM_ENABLED)
404 continue;
405 rl_outb(rep->re_base_port, RL_CR, 0);
406 }
407 sys_exit(0);
408}
409
410/*===========================================================================*
411 * rtl8139_dump *
412 *===========================================================================*/
413static void rtl8139_dump(m)
414message *m; /* pointer to request message */
415{
416 re_t *rep;
417 int i;
418
419 printf("\n");
420 for (i= 0, rep = &re_table[0]; i<RE_PORT_NR; i++, rep++)
421 {
422 if (rep->re_mode == REM_DISABLED)
423 printf("Realtek RTL 8139 port %d is disabled\n", i);
424
425 if (rep->re_mode != REM_ENABLED)
426 continue;
427
428 printf("Realtek RTL 8139 statistics of port %d:\n", i);
429
430 printf("recvErr :%8ld\t", rep->re_stat.ets_recvErr);
431 printf("sendErr :%8ld\t", rep->re_stat.ets_sendErr);
432 printf("OVW :%8ld\n", rep->re_stat.ets_OVW);
433
434 printf("CRCerr :%8ld\t", rep->re_stat.ets_CRCerr);
435 printf("frameAll :%8ld\t", rep->re_stat.ets_frameAll);
436 printf("missedP :%8ld\n", rep->re_stat.ets_missedP);
437
438 printf("packetR :%8ld\t", rep->re_stat.ets_packetR);
439 printf("packetT :%8ld\t", rep->re_stat.ets_packetT);
440 printf("transDef :%8ld\n", rep->re_stat.ets_transDef);
441
442 printf("collision :%8ld\t", rep->re_stat.ets_collision);
443 printf("transAb :%8ld\t", rep->re_stat.ets_transAb);
444 printf("carrSense :%8ld\n", rep->re_stat.ets_carrSense);
445
446 printf("fifoUnder :%8ld\t", rep->re_stat.ets_fifoUnder);
447 printf("fifoOver :%8ld\t", rep->re_stat.ets_fifoOver);
448 printf("CDheartbeat:%8ld\n", rep->re_stat.ets_CDheartbeat);
449
450 printf("OWC :%8ld\t", rep->re_stat.ets_OWC);
451
452 printf("re_flags = 0x%x\n", rep->re_flags);
453
454 printf(
455 "TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
456 rl_inw(rep->re_base_port, RL_TSAD),
457 rl_inl(rep->re_base_port, RL_TSD0+0*4),
458 rl_inl(rep->re_base_port, RL_TSD0+1*4),
459 rl_inl(rep->re_base_port, RL_TSD0+2*4),
460 rl_inl(rep->re_base_port, RL_TSD0+3*4));
461 printf("tx_head %d, tx_tail %d, busy: %d %d %d %d\n",
462 rep->re_tx_head, rep->re_tx_tail,
463 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
464 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
465 }
466}
467
468/*===========================================================================*
469 * do_init *
470 *===========================================================================*/
471static void rl_init(mp)
472message *mp;
473{
474 static int first_time= 1;
475
476 int port;
477 re_t *rep;
478 message reply_mess;
479
480 if (first_time)
481 {
482 first_time= 0;
483 rl_pci_conf(); /* Configure PCI devices. */
484
485 tmra_inittimer(&rl_watchdog);
486 /* Use a synchronous alarm instead of a watchdog timer. */
487 sys_setalarm(HZ, 0);
488 }
489
490 port = mp->DL_PORT;
491 if (port < 0 || port >= RE_PORT_NR)
492 {
493 reply_mess.m_type= DL_INIT_REPLY;
494 reply_mess.m3_i1= ENXIO;
495 mess_reply(mp, &reply_mess);
496 return;
497 }
498 rep= &re_table[port];
499 if (rep->re_mode == REM_DISABLED)
500 {
501 /* This is the default, try to (re)locate the device. */
502 rl_conf_hw(rep);
503 if (rep->re_mode == REM_DISABLED)
504 {
505 /* Probe failed, or the device is configured off. */
506 reply_mess.m_type= DL_INIT_REPLY;
507 reply_mess.m3_i1= ENXIO;
508 mess_reply(mp, &reply_mess);
509 return;
510 }
511 if (rep->re_mode == REM_ENABLED)
512 rl_init_hw(rep);
513#if VERBOSE /* load silently ... can always check status later */
514 rl_report_link(rep);
515#endif
516 }
517
518 assert(rep->re_mode == REM_ENABLED);
519 assert(rep->re_flags & REF_ENABLED);
520
521 rep->re_flags &= ~(REF_PROMISC | REF_MULTI | REF_BROAD);
522
523 if (mp->DL_MODE & DL_PROMISC_REQ)
524 rep->re_flags |= REF_PROMISC;
525 if (mp->DL_MODE & DL_MULTI_REQ)
526 rep->re_flags |= REF_MULTI;
527 if (mp->DL_MODE & DL_BROAD_REQ)
528 rep->re_flags |= REF_BROAD;
529
530 rep->re_client = mp->m_source;
531 rl_rec_mode(rep);
532
533 reply_mess.m_type = DL_INIT_REPLY;
534 reply_mess.m3_i1 = mp->DL_PORT;
535 reply_mess.m3_i2 = RE_PORT_NR;
536 *(ether_addr_t *) reply_mess.m3_ca1 = rep->re_address;
537
538 mess_reply(mp, &reply_mess);
539}
540
541/*===========================================================================*
542 * rl_pci_conf *
543 *===========================================================================*/
544static void rl_pci_conf()
545{
546 int i, h;
547 re_t *rep;
548 static char envvar[] = RL_ENVVAR "#";
549 static char envfmt[] = "*:d.d.d";
550 static char val[128];
551 long v;
552
553 for (i= 0, rep= re_table; i<RE_PORT_NR; i++, rep++)
554 {
555 strcpy(rep->re_name, "rtl8139#0");
556 rep->re_name[8] += i;
557 rep->re_seen= FALSE;
558 envvar[sizeof(RL_ENVVAR)-1]= '0'+i;
559 if (0 == env_get_param(envvar, val, sizeof(val)) &&
560 ! env_prefix(envvar, "pci")) {
561 env_panic(envvar);
562 }
563 v= 0;
564 (void) env_parse(envvar, envfmt, 1, &v, 0, 255);
565 rep->re_pcibus= v;
566 v= 0;
567 (void) env_parse(envvar, envfmt, 2, &v, 0, 255);
568 rep->re_pcidev= v;
569 v= 0;
570 (void) env_parse(envvar, envfmt, 3, &v, 0, 255);
571 rep->re_pcifunc= v;
572 }
573
574 pci_init();
575
576 for (h= 1; h >= 0; h--) {
577 for (i= 0, rep= re_table; i<RE_PORT_NR; i++, rep++)
578 {
579 if (((rep->re_pcibus | rep->re_pcidev |
580 rep->re_pcifunc) != 0) != h)
581 {
582 continue;
583 }
584 if (rl_probe(rep))
585 rep->re_seen= TRUE;
586 }
587 }
588}
589
590/*===========================================================================*
591 * rl_probe *
592 *===========================================================================*/
593static int rl_probe(rep)
594re_t *rep;
595{
596 int i, r, devind, just_one;
597 u16_t vid, did;
598 u32_t bar;
599 u8_t ilr;
600 char *dname;
601
602 if ((rep->re_pcibus | rep->re_pcidev | rep->re_pcifunc) != 0)
603 {
604 /* Look for specific PCI device */
605 r= pci_find_dev(rep->re_pcibus, rep->re_pcidev,
606 rep->re_pcifunc, &devind);
607 if (r == 0)
608 {
609 printf("%s: no PCI found at %d.%d.%d\n",
610 rep->re_name, rep->re_pcibus,
611 rep->re_pcidev, rep->re_pcifunc);
612 return 0;
613 }
614 pci_ids(devind, &vid, &did);
615 just_one= TRUE;
616 }
617 else
618 {
619 r= pci_first_dev(&devind, &vid, &did);
620 if (r == 0)
621 return 0;
622 just_one= FALSE;
623 }
624
625 for(;;)
626 {
627 for (i= 0; pcitab[i].vid != 0; i++)
628 {
629 if (pcitab[i].vid != vid)
630 continue;
631 if (pcitab[i].did != did)
632 continue;
633 if (pcitab[i].checkclass)
634 {
635 panic("rtl_probe",
636 "class check not implemented", NO_NUM);
637 }
638 break;
639 }
640 if (pcitab[i].vid != 0)
641 break;
642
643 if (just_one)
644 {
645 printf(
646 "%s: wrong PCI device (%04x/%04x) found at %d.%d.%d\n",
647 rep->re_name, vid, did,
648 rep->re_pcibus,
649 rep->re_pcidev, rep->re_pcifunc);
650 return 0;
651 }
652
653 r= pci_next_dev(&devind, &vid, &did);
654 if (!r)
655 return 0;
656 }
657
658#if VERBOSE /* stay silent at startup, can always get status later */
659 dname= pci_dev_name(vid, did);
660 if (!dname)
661 dname= "unknown device";
662 printf("%s: ", rep->re_name);
663 printf("%s (%x/%x) at %s\n", dname, vid, did, pci_slot_name(devind));
664#endif
665 pci_reserve(devind);
666 /* printf("cr = 0x%x\n", pci_attr_r16(devind, PCI_CR)); */
667 bar= pci_attr_r32(devind, PCI_BAR) & 0xffffffe0;
668 if (bar < 0x400)
669 {
670 panic("rtl_probe",
671 "base address is not properly configured", NO_NUM);
672 }
673 rep->re_base_port= bar;
674
675 ilr= pci_attr_r8(devind, PCI_ILR);
676 rep->re_irq= ilr;
677 if (debug)
678 {
679 printf("%s: using I/O address 0x%lx, IRQ %d\n",
680 rep->re_name, (unsigned long)bar, ilr);
681 }
682
683 return TRUE;
684}
685
686/*===========================================================================*
687 * rl_conf_hw *
688 *===========================================================================*/
689static void rl_conf_hw(rep)
690re_t *rep;
691{
692 static eth_stat_t empty_stat = {0, 0, 0, 0, 0, 0 /* ,... */ };
693
694 rep->re_mode= REM_DISABLED; /* Superfluous */
695
696 if (rep->re_seen)
697 {
698 /* PCI device is present */
699 rep->re_mode= REM_ENABLED;
700 }
701 if (rep->re_mode != REM_ENABLED)
702 return;
703
704 rep->re_flags= REF_EMPTY;
705 rep->re_link_up= -1; /* Unknown */
706 rep->re_got_int= 0;
707 rep->re_send_int= 0;
708 rep->re_report_link= 0;
709 rep->re_clear_rx= 0;
710 rep->re_need_reset= 0;
711 rep->re_tx_alive= 0;
712 rep->re_read_s= 0;
713 rep->re_tx_head= 0;
714 rep->re_tx_tail= 0;
715 rep->re_ertxth= RL_TSD_ERTXTH_8;
716 rep->re_stat= empty_stat;
717}
718
719/*===========================================================================*
720 * rl_init_buf *
721 *===========================================================================*/
722static void rl_init_buf(rep)
723re_t *rep;
724{
725 size_t rx_bufsize, tx_bufsize, tot_bufsize;
726 phys_bytes buf;
727 char *mallocbuf;
728 static struct memory chunk;
729 int fd, s, i, off;
730
731 /* Allocate receive and transmit buffers */
732 tx_bufsize= ETH_MAX_PACK_SIZE_TAGGED;
733 if (tx_bufsize % 4)
734 tx_bufsize += 4-(tx_bufsize % 4); /* Align */
735 rx_bufsize= RX_BUFSIZE;
736 tot_bufsize= N_TX_BUF*tx_bufsize + rx_bufsize;
737
738 /* Now try to allocate a kernel memory buffer. */
739 chunk.size = tot_bufsize;
740
741#define BUF_ALIGNMENT (64*1024)
742
743 if(!(mallocbuf = malloc(BUF_ALIGNMENT + tot_bufsize))) {
744 panic("RTL8139","Couldn't allocate kernel buffer",i);
745 }
746
747 if(OK != (i = sys_umap(SELF, D, (vir_bytes) mallocbuf, tot_bufsize, &buf))) {
748 panic("RTL8139","Couldn't re-map malloced buffer",i);
749 }
750
751 /* click-align mallocced buffer. this is what we used to get
752 * from kmalloc() too.
753 */
754 if((off = buf % BUF_ALIGNMENT)) {
755 mallocbuf += BUF_ALIGNMENT - off;
756 buf += BUF_ALIGNMENT - off;
757 }
758
759 for (i= 0; i<N_TX_BUF; i++)
760 {
761 rep->re_tx[i].ret_buf= buf;
762 rep->re_tx[i].v_ret_buf= mallocbuf;
763 buf += tx_bufsize;
764 mallocbuf += tx_bufsize;
765 }
766 rep->re_rx_buf= buf;
767 rep->v_re_rx_buf= mallocbuf;
768}
769
770/*===========================================================================*
771 * rl_init_hw *
772 *===========================================================================*/
773static void rl_init_hw(rep)
774re_t *rep;
775{
776 int s, i;
777
778 rep->re_flags = REF_EMPTY;
779 rep->re_flags |= REF_ENABLED;
780
781 /* Set the interrupt handler. The policy is to only send HARD_INT
782 * notifications. Don't reenable interrupts automatically. The id
783 * that is passed back is the interrupt line number.
784 */
785 rep->re_hook_id = rep->re_irq;
786 if ((s=sys_irqsetpolicy(rep->re_irq, 0, &rep->re_hook_id)) != OK)
787 printf("RTL8139: error, couldn't set IRQ policy: %d\n", s);
788
789 rl_reset_hw(rep);
790
791 if ((s=sys_irqenable(&rep->re_hook_id)) != OK)
792 printf("RTL8139: error, couldn't enable interrupts: %d\n", s);
793
794#if VERBOSE /* stay silent during startup, can always get status later */
795 if (rep->re_model) {
796 printf("%s: model %s\n", rep->re_name, rep->re_model);
797 } else
798 {
799 printf("%s: unknown model 0x%08x\n",
800 rep->re_name,
801 rl_inl(rep->re_base_port, RL_TCR) &
802 (RL_TCR_HWVER_AM | RL_TCR_HWVER_BM));
803 }
804#endif
805
806 rl_confaddr(rep);
807 if (debug)
808 {
809 printf("%s: Ethernet address ", rep->re_name);
810 for (i= 0; i < 6; i++)
811 {
812 printf("%x%c", rep->re_address.ea_addr[i],
813 i < 5 ? ':' : '\n');
814 }
815 }
816}
817
818/*===========================================================================*
819 * rl_reset_hw *
820 *===========================================================================*/
821static void rl_reset_hw(rep)
822re_t *rep;
823{
824 port_t port;
825 u32_t t;
826 phys_bytes bus_buf;
827 int i;
828 clock_t t0,t1;
829
830 port= rep->re_base_port;
831
832#if 0
833 /* Reset the PHY */
834 rl_outb(port, RL_BMCR, MII_CTRL_RST);
835 getuptime(&t0);
836 do {
837 if (!(rl_inb(port, RL_BMCR) & MII_CTRL_RST))
838 break;
839 } while (getuptime(&t1)==OK && (t1-t0) < HZ);
840 if (rl_inb(port, RL_BMCR) & MII_CTRL_RST)
841 panic("rtl8139","reset PHY failed to complete", NO_NUM);
842#endif
843
844 /* Reset the device */
845 printf("rl_reset_hw: (before reset) port = 0x%x, RL_CR = 0x%x\n",
846 port, rl_inb(port, RL_CR));
847 rl_outb(port, RL_CR, RL_CR_RST);
848 getuptime(&t0);
849 do {
850 if (!(rl_inb(port, RL_CR) & RL_CR_RST))
851 break;
852 } while (getuptime(&t1)==OK && (t1-t0) < HZ);
853 printf("rl_reset_hw: (after reset) port = 0x%x, RL_CR = 0x%x\n",
854 port, rl_inb(port, RL_CR));
855 if (rl_inb(port, RL_CR) & RL_CR_RST)
856 printf("rtl8139: reset failed to complete");
857
858 t= rl_inl(port, RL_TCR);
859 switch(t & (RL_TCR_HWVER_AM | RL_TCR_HWVER_BM))
860 {
861 case RL_TCR_HWVER_RTL8139: rep->re_model= "RTL8139"; break;
862 case RL_TCR_HWVER_RTL8139A: rep->re_model= "RTL8139A"; break;
863 case RL_TCR_HWVER_RTL8139AG:
864 rep->re_model= "RTL8139A-G / RTL8139C";
865 break;
866 case RL_TCR_HWVER_RTL8139B:
867 rep->re_model= "RTL8139B / RTL8130";
868 break;
869 case RL_TCR_HWVER_RTL8100: rep->re_model= "RTL8100"; break;
870 case RL_TCR_HWVER_RTL8100B:
871 rep->re_model= "RTL8100B/RTL8139D";
872 break;
873 case RL_TCR_HWVER_RTL8139CP: rep->re_model= "RTL8139C+"; break;
874 case RL_TCR_HWVER_RTL8101: rep->re_model= "RTL8101"; break;
875 default:
876 rep->re_model= NULL;
877 break;
878 }
879
880#if 0
881 printf("REVID: 0x%02x\n", rl_inb(port, RL_REVID));
882#endif
883
884 /* Intialize Rx */
885
886 /* Should init multicast mask */
887#if 0
88808-0f R/W MAR[0-7] multicast
889#endif
890 bus_buf= vm_1phys2bus(rep->re_rx_buf);
891 rl_outl(port, RL_RBSTART, bus_buf);
892
893 /* Initialize Tx */
894 for (i= 0; i<N_TX_BUF; i++)
895 {
896 rep->re_tx[i].ret_busy= FALSE;
897 bus_buf= vm_1phys2bus(rep->re_tx[i].ret_buf);
898 rl_outl(port, RL_TSAD0+i*4, bus_buf);
899 t= rl_inl(port, RL_TSD0+i*4);
900 assert(t & RL_TSD_OWN);
901 }
902
903#if 0
904 dump_phy(rep);
905#endif
906
907 t= rl_inw(port, RL_IMR);
908 rl_outw(port, RL_IMR, t | (RL_IMR_SERR | RL_IMR_TIMEOUT |
909 RL_IMR_LENCHG));
910
911 t= rl_inw(port, RL_IMR);
912 rl_outw(port, RL_IMR, t | (RL_IMR_FOVW | RL_IMR_PUN |
913 RL_IMR_RXOVW | RL_IMR_RER | RL_IMR_ROK));
914
915 t= rl_inw(port, RL_IMR);
916 rl_outw(port, RL_IMR, t | (RL_IMR_TER | RL_IMR_TOK));
917
918 t= rl_inb(port, RL_CR);
919 rl_outb(port, RL_CR, t | RL_CR_RE);
920
921 t= rl_inb(port, RL_CR);
922 rl_outb(port, RL_CR, t | RL_CR_TE);
923
924 rl_outl(port, RL_RCR, RX_BUFBITS);
925
926 t= rl_inl(port, RL_TCR);
927 rl_outl(port, RL_TCR, t | RL_TCR_IFG_STD);
928}
929
930/*===========================================================================*
931 * rl_confaddr *
932 *===========================================================================*/
933static void rl_confaddr(rep)
934re_t *rep;
935{
936 static char eakey[]= RL_ENVVAR "#_EA";
937 static char eafmt[]= "x:x:x:x:x:x";
938
939 int i;
940 port_t port;
941 u32_t w;
942 long v;
943
944 /* User defined ethernet address? */
945 eakey[sizeof(RL_ENVVAR)-1]= '0' + (rep-re_table);
946
947 port= rep->re_base_port;
948
949 for (i= 0; i < 6; i++)
950 {
951 if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET)
952 break;
953 rep->re_address.ea_addr[i]= v;
954 }
955
956 if (i != 0 && i != 6) env_panic(eakey); /* It's all or nothing */
957
958 /* Should update ethernet address in hardware */
959 if (i == 6)
960 {
961 port= rep->re_base_port;
962 rl_outb(port, RL_9346CR, RL_9346CR_EEM_CONFIG);
963 w= 0;
964 for (i= 0; i<4; i++)
965 w |= (rep->re_address.ea_addr[i] << (i*8));
966 rl_outl(port, RL_IDR, w);
967 w= 0;
968 for (i= 4; i<6; i++)
969 w |= (rep->re_address.ea_addr[i] << ((i-4)*8));
970 rl_outl(port, RL_IDR+4, w);
971 rl_outb(port, RL_9346CR, RL_9346CR_EEM_NORMAL);
972 }
973
974 /* Get ethernet address */
975 for (i= 0; i<6; i++)
976 rep->re_address.ea_addr[i]= rl_inb(port, RL_IDR+i);
977}
978
979/*===========================================================================*
980 * rl_rec_mode *
981 *===========================================================================*/
982static void rl_rec_mode(rep)
983re_t *rep;
984{
985 port_t port;
986 u32_t rcr;
987
988 port= rep->re_base_port;
989 rcr= rl_inl(port, RL_RCR);
990 rcr &= ~(RL_RCR_AB|RL_RCR_AM|RL_RCR_APM|RL_RCR_AAP);
991 if (rep->re_flags & REF_PROMISC)
992 rcr |= RL_RCR_AB | RL_RCR_AM | RL_RCR_AAP;
993 if (rep->re_flags & REF_BROAD)
994 rcr |= RL_RCR_AB;
995 if (rep->re_flags & REF_MULTI)
996 rcr |= RL_RCR_AM;
997 rcr |= RL_RCR_APM;
998
999 rl_outl(port, RL_RCR, rcr);
1000}
1001
1002/*===========================================================================*
1003 * rl_readv *
1004 *===========================================================================*/
1005static void rl_readv(mp, from_int, vectored)
1006message *mp;
1007int from_int;
1008int vectored;
1009{
1010 int i, j, n, o, s, s1, dl_port, re_client, count, size;
1011 port_t port;
1012 unsigned amount, totlen, packlen;
1013 phys_bytes src_phys, dst_phys, iov_src;
1014 u16_t d_start, d_end;
1015 u32_t l, rxstat = 0x12345678;
1016 re_t *rep;
1017 iovec_t *iovp;
1018 int cps;
1019
1020 dl_port = mp->DL_PORT;
1021 count = mp->DL_COUNT;
1022 if (dl_port < 0 || dl_port >= RE_PORT_NR)
1023 panic("rtl8139"," illegal port", dl_port);
1024 rep= &re_table[dl_port];
1025 re_client= mp->DL_PROC;
1026 rep->re_client= re_client;
1027
1028 if (rep->re_clear_rx)
1029 goto suspend; /* Buffer overflow */
1030
1031 assert(rep->re_mode == REM_ENABLED);
1032 assert(rep->re_flags & REF_ENABLED);
1033
1034 port= rep->re_base_port;
1035
1036 /* Assume that the RL_CR_BUFE check was been done by rl_checks_ints
1037 */
1038 if (!from_int && (rl_inb(port, RL_CR) & RL_CR_BUFE))
1039 {
1040 /* Receive buffer is empty, suspend */
1041 goto suspend;
1042 }
1043
1044 d_start= rl_inw(port, RL_CAPR) + RL_CAPR_DATA_OFF;
1045 d_end= rl_inw(port, RL_CBR) % RX_BUFSIZE;
1046
1047 if (d_start >= RX_BUFSIZE)
1048 {
1049 printf("rl_readv: strange value in RL_CAPR: 0x%x\n",
1050 rl_inw(port, RL_CAPR));
1051 d_start %= RX_BUFSIZE;
1052 }
1053
1054 if (d_end > d_start)
1055 amount= d_end-d_start;
1056 else
1057 amount= d_end+RX_BUFSIZE - d_start;
1058
1059 rxstat = *(u32_t *) (rep->v_re_rx_buf + d_start);
1060
1061#if DEAD_CODE
1062 src_phys= rep->re_rx_buf + d_start;
1063 cps = sys_physcopy(
1064 NONE, PHYS_SEG, src_phys,
1065 SELF, D, (vir_bytes) &rxstat, sizeof(rxstat));
1066 if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
1067#endif
1068
1069 if (rep->re_clear_rx)
1070 {
1071#if 0
1072 printf("rl_readv: late buffer overflow\n");
1073#endif
1074 goto suspend; /* Buffer overflow */
1075 }
1076
1077 /* Should convert from little endian to host byte order */
1078
1079 if (!(rxstat & RL_RXS_ROK))
1080 {
1081 printf("rxstat = 0x%08lx\n", rxstat);
1082 printf("d_start: 0x%x, d_end: 0x%x, rxstat: 0x%lx\n",
1083 d_start, d_end, rxstat);
1084 panic("rtl8139","received packet not OK", NO_NUM);
1085 }
1086 totlen= (rxstat >> RL_RXS_LEN_S);
1087 if (totlen < 8 || totlen > 2*ETH_MAX_PACK_SIZE)
1088 {
1089 /* Someting went wrong */
1090 printf(
1091 "rl_readv: bad length (%u) in status 0x%08lx at offset 0x%x\n",
1092 totlen, rxstat, d_start);
1093 printf(
1094 "d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%lx\n",
1095 d_start, d_end, totlen, rxstat);
1096 panic(NULL, NULL, NO_NUM);
1097 }
1098
1099#if 0
1100 printf("d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%x\n",
1101 d_start, d_end, totlen, rxstat);
1102#endif
1103
1104 if (totlen+4 > amount)
1105 {
1106 printf("rl_readv: packet not yet ready\n");
1107 goto suspend;
1108 }
1109
1110 /* Should subtract the CRC */
1111 packlen= totlen - ETH_CRC_SIZE;
1112
1113 if (vectored)
1114 {
1115 int iov_offset = 0;
1116#if 0
1117 if ((cps = sys_umap(re_client, D, (vir_bytes) mp->DL_ADDR,
1118 count * sizeof(rep->re_iovec[0]), &iov_src)) != OK)
1119 printf("sys_umap failed: %d\n", cps);
1120#endif
1121
1122 size= 0;
1123 o= d_start+4;
1124 src_phys= rep->re_rx_buf;
1125 for (i= 0; i<count; i += IOVEC_NR,
1126 iov_src += IOVEC_NR * sizeof(rep->re_iovec[0]),
1127 iov_offset += IOVEC_NR * sizeof(rep->re_iovec[0]))
1128 {
1129 n= IOVEC_NR;
1130 if (i+n > count)
1131 n= count-i;
1132#if 0
1133 cps = sys_physcopy(NONE, PHYS_SEG, iov_src, SELF, D, (vir_bytes) rep->re_iovec,
1134 n * sizeof(rep->re_iovec[0]));
1135 if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
1136#else
1137 cps = sys_vircopy(re_client, D, (vir_bytes) mp->DL_ADDR + iov_offset,
1138 SELF, D, (vir_bytes) rep->re_iovec, n * sizeof(rep->re_iovec[0]));
1139 if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d (%d)\n", cps, __LINE__);
1140#endif
1141
1142 for (j= 0, iovp= rep->re_iovec; j<n; j++, iovp++)
1143 {
1144 s= iovp->iov_size;
1145 if (size + s > packlen)
1146 {
1147 assert(packlen > size);
1148 s= packlen-size;
1149 }
1150
1151#if 0
1152 if (sys_umap(re_client, D, iovp->iov_addr, s, &dst_phys) != OK)
1153 panic("rtl8139","umap_local failed\n", NO_NUM);
1154#endif
1155
1156 if (o >= RX_BUFSIZE)
1157 {
1158 o -= RX_BUFSIZE;
1159 assert(o < RX_BUFSIZE);
1160 }
1161
1162 if (o+s > RX_BUFSIZE)
1163 {
1164 assert(o<RX_BUFSIZE);
1165 s1= RX_BUFSIZE-o;
1166
1167#if 0
1168 cps = sys_abscopy(src_phys+o, dst_phys, s1);
1169 if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
1170 cps = sys_abscopy(src_phys, dst_phys+s1, s-s1);
1171 if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
1172#else
1173 cps = sys_vircopy(SELF, D, (vir_bytes) rep->v_re_rx_buf+o,
1174 re_client, D, iovp->iov_addr, s1);
1175 if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d (%d)\n", cps, __LINE__);
1176 cps = sys_vircopy(SELF, D, (vir_bytes) rep->v_re_rx_buf,
1177 re_client, D, iovp->iov_addr+s1, s-s1);
1178 if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d (%d)\n", cps, __LINE__);
1179#endif
1180 }
1181 else
1182 {
1183#if 0
1184 cps = sys_abscopy(src_phys+o, dst_phys, s);
1185 if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
1186#else
1187 cps = sys_vircopy(SELF, D, (vir_bytes) rep->v_re_rx_buf+o,
1188 re_client, D, iovp->iov_addr, s);
1189 if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d (%d)\n", cps, __LINE__);
1190#endif
1191 }
1192
1193 size += s;
1194 if (size == packlen)
1195 break;
1196 o += s;
1197 }
1198 if (size == packlen)
1199 break;
1200 }
1201 if (size < packlen)
1202 {
1203 assert(0);
1204 }
1205 }
1206 else
1207 {
1208 assert(0);
1209#if 0
1210 size= mp->DL_COUNT;
1211 if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE_TAGGED)
1212 panic("rtl8139","invalid packet size", size);
1213 if (OK != sys_umap(re_client, D, (vir_bytes)mp->DL_ADDR, size, &phys_user))
1214 panic("rtl8139","umap_local failed", NO_NUM);
1215
1216 p= rep->re_tx[tx_head].ret_buf;
1217 cps = sys_abscopy(phys_user, p, size);
1218 if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
1219#endif
1220 }
1221
1222 if (rep->re_clear_rx)
1223 {
1224 /* For some reason the receiver FIFO is not stopped when
1225 * the buffer is full.
1226 */
1227 #if 0
1228 printf("rl_readv: later buffer overflow\n");
1229 #endif
1230 goto suspend; /* Buffer overflow */
1231 }
1232
1233 rep->re_stat.ets_packetR++;
1234 rep->re_read_s= packlen;
1235 rep->re_flags= (rep->re_flags & ~REF_READING) | REF_PACK_RECV;
1236
1237 /* Avoid overflow in 16-bit computations */
1238 l= d_start;
1239 l += totlen+4;
1240 l= (l+3) & ~3; /* align */
1241 if (l >= RX_BUFSIZE)
1242 {
1243 l -= RX_BUFSIZE;
1244 assert(l < RX_BUFSIZE);
1245 }
1246 rl_outw(port, RL_CAPR, l-RL_CAPR_DATA_OFF);
1247
1248 if (!from_int)
1249 reply(rep, OK, FALSE);
1250
1251 return;
1252
1253 suspend:
1254 if (from_int)
1255 {
1256 assert(rep->re_flags & REF_READING);
1257
1258 /* No need to store any state */
1259 return;
1260 }
1261
1262 rep->re_rx_mess= *mp;
1263 assert(!(rep->re_flags & REF_READING));
1264 rep->re_flags |= REF_READING;
1265
1266 reply(rep, OK, FALSE);
1267 }
1268
1269 /*===========================================================================*
1270 * rl_writev *
1271 *===========================================================================*/
1272 static void rl_writev(mp, from_int, vectored)
1273 message *mp;
1274 int from_int;
1275 int vectored;
1276 {
1277 phys_bytes p, iov_src, phys_user;
1278 int i, j, n, s, port, count, size;
1279 int tx_head, re_client;
1280 re_t *rep;
1281 iovec_t *iovp;
1282 char *ret;
1283 int cps;
1284
1285 port = mp->DL_PORT;
1286 count = mp->DL_COUNT;
1287 if (port < 0 || port >= RE_PORT_NR)
1288 panic("rtl8139","illegal port", port);
1289 rep= &re_table[port];
1290 re_client= mp->DL_PROC;
1291 rep->re_client= re_client;
1292
1293 assert(rep->re_mode == REM_ENABLED);
1294 assert(rep->re_flags & REF_ENABLED);
1295
1296 if (from_int)
1297 {
1298 assert(rep->re_flags & REF_SEND_AVAIL);
1299 rep->re_flags &= ~REF_SEND_AVAIL;
1300 rep->re_send_int= FALSE;
1301 rep->re_tx_alive= TRUE;
1302 }
1303
1304 tx_head= rep->re_tx_head;
1305 if (rep->re_tx[tx_head].ret_busy)
1306 {
1307 assert(!(rep->re_flags & REF_SEND_AVAIL));
1308 rep->re_flags |= REF_SEND_AVAIL;
1309 if (rep->re_tx[tx_head].ret_busy)
1310 goto suspend;
1311
1312 /* Race condition, the interrupt handler may clear re_busy
1313 * before we got a chance to set REF_SEND_AVAIL. Checking
1314 * ret_busy twice should be sufficient.
1315 */
1316 #if 0
1317 printf("rl_writev: race detected\n");
1318 #endif
1319 rep->re_flags &= ~REF_SEND_AVAIL;
1320 rep->re_send_int= FALSE;
1321 }
1322
1323 assert(!(rep->re_flags & REF_SEND_AVAIL));
1324 assert(!(rep->re_flags & REF_PACK_SENT));
1325
1326 if (vectored)
1327 {
1328 int iov_offset = 0;
1329
1330#if 0
1331 if (OK != sys_umap(re_client, D, (vir_bytes)mp->DL_ADDR,
1332 count * sizeof(rep->re_iovec[0]), &iov_src))
1333 panic("rtl8139","umap_local failed", NO_NUM);
1334#endif
1335
1336 size= 0;
1337#if 0
1338 p= rep->re_tx[tx_head].ret_buf;
1339#else
1340 ret = rep->re_tx[tx_head].v_ret_buf;
1341#endif
1342 for (i= 0; i<count; i += IOVEC_NR,
1343 iov_src += IOVEC_NR * sizeof(rep->re_iovec[0]),
1344 iov_offset += IOVEC_NR * sizeof(rep->re_iovec[0]))
1345 {
1346 n= IOVEC_NR;
1347 if (i+n > count)
1348 n= count-i;
1349#if 0
1350 cps = sys_physcopy(NONE, PHYS_SEG, iov_src, SELF, D, (vir_bytes) rep->re_iovec,
1351 n * sizeof(rep->re_iovec[0]));
1352 if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
1353#else
1354 cps = sys_vircopy(re_client, D, ((vir_bytes) mp->DL_ADDR) + iov_offset,
1355 SELF, D, (vir_bytes) rep->re_iovec,
1356 n * sizeof(rep->re_iovec[0]));
1357 if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d\n", cps);
1358#endif
1359
1360 for (j= 0, iovp= rep->re_iovec; j<n; j++, iovp++)
1361 {
1362 s= iovp->iov_size;
1363 if (size + s > ETH_MAX_PACK_SIZE_TAGGED)
1364 {
1365 panic("rtl8139","invalid packet size",
1366 NO_NUM);
1367 }
1368
1369 if (OK != sys_umap(re_client, D, iovp->iov_addr, s, &phys_user))
1370 panic("rtl8139","umap_local failed\n", NO_NUM);
1371
1372#if 0
1373 cps = sys_abscopy(phys_user, p, s);
1374 if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
1375#else
1376 cps = sys_vircopy(re_client, D, iovp->iov_addr,
1377 SELF, D, (vir_bytes) ret, s);
1378 if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d\n", cps);
1379#endif
1380 size += s;
1381#if 0
1382 p += s;
1383#endif
1384 ret += s;
1385 }
1386 }
1387 if (size < ETH_MIN_PACK_SIZE)
1388 panic("rtl8139","invalid packet size", size);
1389 }
1390 else
1391 {
1392 size= mp->DL_COUNT;
1393 if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE_TAGGED)
1394 panic("rtl8139","invalid packet size", size);
1395#if 0
1396 if (OK != sys_umap(re_client, D, (vir_bytes)mp->DL_ADDR, size, &phys_user))
1397 panic("rtl8139","umap_local failed\n", NO_NUM);
1398
1399 p= rep->re_tx[tx_head].ret_buf;
1400 cps = sys_abscopy(phys_user, p, size);
1401 if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
1402#else
1403 ret = rep->re_tx[tx_head].v_ret_buf;
1404 cps = sys_vircopy(re_client, D, (vir_bytes)mp->DL_ADDR,
1405 SELF, D, (vir_bytes) ret, size);
1406 if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
1407#endif
1408 }
1409
1410 rl_outl(rep->re_base_port, RL_TSD0+tx_head*4,
1411 rep->re_ertxth | size);
1412 rep->re_tx[tx_head].ret_busy= TRUE;
1413
1414 if (++tx_head == N_TX_BUF)
1415 tx_head= 0;
1416 assert(tx_head < RL_N_TX);
1417 rep->re_tx_head= tx_head;
1418
1419 rep->re_flags |= REF_PACK_SENT;
1420
1421 /* If the interrupt handler called, don't send a reply. The reply
1422 * will be sent after all interrupts are handled.
1423 */
1424 if (from_int)
1425 return;
1426 reply(rep, OK, FALSE);
1427 return;
1428
1429suspend:
1430#if 0
1431 printf("rl_writev: head %d, tail %d, busy: %d %d %d %d\n",
1432 tx_head, rep->re_tx_tail,
1433 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
1434 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
1435 printf("rl_writev: TSD: 0x%x, 0x%x, 0x%x, 0x%x\n",
1436 rl_inl(rep->re_base_port, RL_TSD0+0*4),
1437 rl_inl(rep->re_base_port, RL_TSD0+1*4),
1438 rl_inl(rep->re_base_port, RL_TSD0+2*4),
1439 rl_inl(rep->re_base_port, RL_TSD0+3*4));
1440#endif
1441
1442 if (from_int)
1443 panic("rtl8139","should not be sending\n", NO_NUM);
1444
1445 rep->re_tx_mess= *mp;
1446 reply(rep, OK, FALSE);
1447}
1448
1449/*===========================================================================*
1450 * rl_check_ints *
1451 *===========================================================================*/
1452static void rl_check_ints(rep)
1453re_t *rep;
1454{
1455#if 0
145610-1f R/W TSD[0-3] Transmit Status of Descriptor [0-3]
1457 31 R CRS Carrier Sense Lost
1458 30 R TABT Transmit Abort
1459 29 R OWC Out of Window Collision
1460 27-24 R NCC[3-0] Number of Collision Count
1461 23-22 reserved
1462 21-16 R/W ERTXH[5-0] Early Tx Threshold
1463 15 R TOK Transmit OK
1464 14 R TUN Transmit FIFO Underrun
1465 13 R/W OWN OWN
1466 12-0 R/W SIZE Descriptor Size
14673e-3f R/W ISR Interrupt Status Register
1468 6 R/W FOVW Fx FIFO Overflow Interrupt
1469 5 R/W PUN/LinkChg Packet Underrun / Link Change Interrupt
1470 3 R/W TER Transmit Error Interrupt
1471 2 R/W TOK Transmit OK Interrupt
14723e-3f R/W ISR Interrupt Status Register
1473 15 R/W SERR System Error Interrupt
1474 14 R/W TimeOut Time Out Interrupt
1475 13 R/W LenChg Cable Length Change Interrupt
14763e-3f R/W ISR Interrupt Status Register
1477 4 R/W RXOVW Rx Buffer Overflow Interrupt
1478 1 R/W RER Receive Error Interrupt
1479 0 R/W ROK Receive OK Interrupt
14804c-4f R/W MPC Missed Packet Counter
148160-61 R TSAD Transmit Status of All Descriptors
1482 15-12 R TOK[3-0] TOK bit of Descriptor [3-0]
1483 11-8 R TUN[3-0] TUN bit of Descriptor [3-0]
1484 7-4 R TABT[3-0] TABT bit of Descriptor [3-0]
1485 3-0 R OWN[3-0] OWN bit of Descriptor [3-0]
14866c-6d R DIS Disconnect Counter
1487 15-0 R DCNT Disconnect Counter
14886e-6f R FCSC False Carrier Sense Counter
1489 15-0 R FCSCNT False Carrier event counter
149072-73 R REC RX_ER Counter
1491 15-0 R RXERCNT Received packet counter
1492#endif
1493
1494 int re_flags;
1495
1496 re_flags= rep->re_flags;
1497
1498 if ((re_flags & REF_READING) &&
1499 !(rl_inb(rep->re_base_port, RL_CR) & RL_CR_BUFE))
1500 {
1501 if (rep->re_rx_mess.m_type == DL_READV)
1502 {
1503 rl_readv(&rep->re_rx_mess, TRUE /* from int */,
1504 TRUE /* vectored */);
1505 }
1506 else
1507 {
1508 assert(rep->re_rx_mess.m_type == DL_READ);
1509 rl_readv(&rep->re_rx_mess, TRUE /* from int */,
1510 FALSE /* !vectored */);
1511 }
1512 }
1513 if (rep->re_clear_rx)
1514 rl_clear_rx(rep);
1515
1516 if (rep->re_need_reset)
1517 rl_do_reset(rep);
1518
1519 if (rep->re_send_int)
1520 {
1521 if (rep->re_tx_mess.m_type == DL_WRITEV)
1522 {
1523 rl_writev(&rep->re_tx_mess, TRUE /* from int */,
1524 TRUE /* vectored */);
1525 }
1526 else
1527 {
1528 assert(rep->re_tx_mess.m_type == DL_WRITE);
1529 rl_writev(&rep->re_tx_mess, TRUE /* from int */,
1530 FALSE /* !vectored */);
1531 }
1532 }
1533
1534 if (rep->re_report_link)
1535 rl_report_link(rep);
1536
1537 if (rep->re_flags & (REF_PACK_SENT | REF_PACK_RECV))
1538 reply(rep, OK, TRUE);
1539}
1540
1541/*===========================================================================*
1542 * rl_report_link *
1543 *===========================================================================*/
1544static void rl_report_link(rep)
1545re_t *rep;
1546{
1547 port_t port;
1548 u16_t mii_ctrl, mii_status, mii_ana, mii_anlpa, mii_ane, mii_extstat;
1549 u8_t msr;
1550 int f, link_up;
1551
1552 rep->re_report_link= FALSE;
1553 port= rep->re_base_port;
1554 msr= rl_inb(port, RL_MSR);
1555 link_up= !(msr & RL_MSR_LINKB);
1556 rep->re_link_up= link_up;
1557 if (!link_up)
1558 {
1559 printf("%s: link down\n", rep->re_name);
1560 return;
1561 }
1562
1563 mii_ctrl= rl_inw(port, RL_BMCR);
1564 mii_status= rl_inw(port, RL_BMSR);
1565 mii_ana= rl_inw(port, RL_ANAR);
1566 mii_anlpa= rl_inw(port, RL_ANLPAR);
1567 mii_ane= rl_inw(port, RL_ANER);
1568 mii_extstat= 0;
1569
1570 if (mii_ctrl & (MII_CTRL_LB|MII_CTRL_PD|MII_CTRL_ISO))
1571 {
1572 printf("%s: PHY: ", rep->re_name);
1573 f= 1;
1574 if (mii_ctrl & MII_CTRL_LB)
1575 {
1576 printf("loopback mode");
1577 f= 0;
1578 }
1579 if (mii_ctrl & MII_CTRL_PD)
1580 {
1581 if (!f) printf(", ");
1582 f= 0;
1583 printf("powered down");
1584 }
1585 if (mii_ctrl & MII_CTRL_ISO)
1586 {
1587 if (!f) printf(", ");
1588 f= 0;
1589 printf("isolated");
1590 }
1591 printf("\n");
1592 return;
1593 }
1594 if (!(mii_ctrl & MII_CTRL_ANE))
1595 {
1596 printf("%s: manual config: ", rep->re_name);
1597 switch(mii_ctrl & (MII_CTRL_SP_LSB|MII_CTRL_SP_MSB))
1598 {
1599 case MII_CTRL_SP_10: printf("10 Mbps"); break;
1600 case MII_CTRL_SP_100: printf("100 Mbps"); break;
1601 case MII_CTRL_SP_1000: printf("1000 Mbps"); break;
1602 case MII_CTRL_SP_RES: printf("reserved speed"); break;
1603 }
1604 if (mii_ctrl & MII_CTRL_DM)
1605 printf(", full duplex");
1606 else
1607 printf(", half duplex");
1608 printf("\n");
1609 return;
1610 }
1611
1612 if (!debug) goto resspeed;
1613
1614 printf("%s: ", rep->re_name);
1615 mii_print_stat_speed(mii_status, mii_extstat);
1616 printf("\n");
1617
1618 if (!(mii_status & MII_STATUS_ANC))
1619 printf("%s: auto-negotiation not complete\n", rep->re_name);
1620 if (mii_status & MII_STATUS_RF)
1621 printf("%s: remote fault detected\n", rep->re_name);
1622 if (!(mii_status & MII_STATUS_ANA))
1623 {
1624 printf("%s: local PHY has no auto-negotiation ability\n",
1625 rep->re_name);
1626 }
1627 if (!(mii_status & MII_STATUS_LS))
1628 printf("%s: link down\n", rep->re_name);
1629 if (mii_status & MII_STATUS_JD)
1630 printf("%s: jabber condition detected\n", rep->re_name);
1631 if (!(mii_status & MII_STATUS_EC))
1632 {
1633 printf("%s: no extended register set\n", rep->re_name);
1634 goto resspeed;
1635 }
1636 if (!(mii_status & MII_STATUS_ANC))
1637 goto resspeed;
1638
1639 printf("%s: local cap.: ", rep->re_name);
1640 mii_print_techab(mii_ana);
1641 printf("\n");
1642
1643 if (mii_ane & MII_ANE_PDF)
1644 printf("%s: parallel detection fault\n", rep->re_name);
1645 if (!(mii_ane & MII_ANE_LPANA))
1646 {
1647 printf("%s: link-partner does not support auto-negotiation\n",
1648 rep->re_name);
1649 goto resspeed;
1650 }
1651
1652 printf("%s: remote cap.: ", rep->re_name);
1653 mii_print_techab(mii_anlpa);
1654 printf("\n");
1655
1656resspeed:
1657 printf("%s: ", rep->re_name);
1658 printf("link up at %d Mbps, ", (msr & RL_MSR_SPEED_10) ? 10 : 100);
1659 printf("%s duplex\n", ((mii_ctrl & MII_CTRL_DM) ? "full" : "half"));
1660
1661}
1662
1663static void mii_print_techab(techab)
1664u16_t techab;
1665{
1666 int fs, ft;
1667 if ((techab & MII_ANA_SEL_M) != MII_ANA_SEL_802_3)
1668 {
1669 printf("strange selector 0x%x, value 0x%x",
1670 techab & MII_ANA_SEL_M,
1671 (techab & MII_ANA_TAF_M) >> MII_ANA_TAF_S);
1672 return;
1673 }
1674 fs= 1;
1675 if (techab & (MII_ANA_100T4 | MII_ANA_100TXFD | MII_ANA_100TXHD))
1676 {
1677 printf("100 Mbps: ");
1678 fs= 0;
1679 ft= 1;
1680 if (techab & MII_ANA_100T4)
1681 {
1682 printf("T4");
1683 ft= 0;
1684 }
1685 if (techab & (MII_ANA_100TXFD | MII_ANA_100TXHD))
1686 {
1687 if (!ft)
1688 printf(", ");
1689 ft= 0;
1690 printf("TX-");
1691 switch(techab & (MII_ANA_100TXFD|MII_ANA_100TXHD))
1692 {
1693 case MII_ANA_100TXFD: printf("FD"); break;
1694 case MII_ANA_100TXHD: printf("HD"); break;
1695 default: printf("FD/HD"); break;
1696 }
1697 }
1698 }
1699 if (techab & (MII_ANA_10TFD | MII_ANA_10THD))
1700 {
1701 if (!fs)
1702 printf(", ");
1703 printf("10 Mbps: ");
1704 fs= 0;
1705 printf("T-");
1706 switch(techab & (MII_ANA_10TFD|MII_ANA_10THD))
1707 {
1708 case MII_ANA_10TFD: printf("FD"); break;
1709 case MII_ANA_10THD: printf("HD"); break;
1710 default: printf("FD/HD"); break;
1711 }
1712 }
1713 if (techab & MII_ANA_PAUSE_SYM)
1714 {
1715 if (!fs)
1716 printf(", ");
1717 fs= 0;
1718 printf("pause(SYM)");
1719 }
1720 if (techab & MII_ANA_PAUSE_ASYM)
1721 {
1722 if (!fs)
1723 printf(", ");
1724 fs= 0;
1725 printf("pause(ASYM)");
1726 }
1727 if (techab & MII_ANA_TAF_RES)
1728 {
1729 if (!fs)
1730 printf(", ");
1731 fs= 0;
1732 printf("0x%x", (techab & MII_ANA_TAF_RES) >> MII_ANA_TAF_S);
1733 }
1734}
1735
1736static void mii_print_stat_speed(stat, extstat)
1737u16_t stat;
1738u16_t extstat;
1739{
1740 int fs, ft;
1741 fs= 1;
1742 if (stat & MII_STATUS_EXT_STAT)
1743 {
1744 if (extstat & (MII_ESTAT_1000XFD | MII_ESTAT_1000XHD |
1745 MII_ESTAT_1000TFD | MII_ESTAT_1000THD))
1746 {
1747 printf("1000 Mbps: ");
1748 fs= 0;
1749 ft= 1;
1750 if (extstat & (MII_ESTAT_1000XFD | MII_ESTAT_1000XHD))
1751 {
1752 ft= 0;
1753 printf("X-");
1754 switch(extstat &
1755 (MII_ESTAT_1000XFD|MII_ESTAT_1000XHD))
1756 {
1757 case MII_ESTAT_1000XFD: printf("FD"); break;
1758 case MII_ESTAT_1000XHD: printf("HD"); break;
1759 default: printf("FD/HD"); break;
1760 }
1761 }
1762 if (extstat & (MII_ESTAT_1000TFD | MII_ESTAT_1000THD))
1763 {
1764 if (!ft)
1765 printf(", ");
1766 ft= 0;
1767 printf("T-");
1768 switch(extstat &
1769 (MII_ESTAT_1000TFD|MII_ESTAT_1000THD))
1770 {
1771 case MII_ESTAT_1000TFD: printf("FD"); break;
1772 case MII_ESTAT_1000THD: printf("HD"); break;
1773 default: printf("FD/HD"); break;
1774 }
1775 }
1776 }
1777 }
1778 if (stat & (MII_STATUS_100T4 |
1779 MII_STATUS_100XFD | MII_STATUS_100XHD |
1780 MII_STATUS_100T2FD | MII_STATUS_100T2HD))
1781 {
1782 if (!fs)
1783 printf(", ");
1784 fs= 0;
1785 printf("100 Mbps: ");
1786 ft= 1;
1787 if (stat & MII_STATUS_100T4)
1788 {
1789 printf("T4");
1790 ft= 0;
1791 }
1792 if (stat & (MII_STATUS_100XFD | MII_STATUS_100XHD))
1793 {
1794 if (!ft)
1795 printf(", ");
1796 ft= 0;
1797 printf("TX-");
1798 switch(stat & (MII_STATUS_100XFD|MII_STATUS_100XHD))
1799 {
1800 case MII_STATUS_100XFD: printf("FD"); break;
1801 case MII_STATUS_100XHD: printf("HD"); break;
1802 default: printf("FD/HD"); break;
1803 }
1804 }
1805 if (stat & (MII_STATUS_100T2FD | MII_STATUS_100T2HD))
1806 {
1807 if (!ft)
1808 printf(", ");
1809 ft= 0;
1810 printf("T2-");
1811 switch(stat & (MII_STATUS_100T2FD|MII_STATUS_100T2HD))
1812 {
1813 case MII_STATUS_100T2FD: printf("FD"); break;
1814 case MII_STATUS_100T2HD: printf("HD"); break;
1815 default: printf("FD/HD"); break;
1816 }
1817 }
1818 }
1819 if (stat & (MII_STATUS_10FD | MII_STATUS_10HD))
1820 {
1821 if (!fs)
1822 printf(", ");
1823 printf("10 Mbps: ");
1824 fs= 0;
1825 printf("T-");
1826 switch(stat & (MII_STATUS_10FD|MII_STATUS_10HD))
1827 {
1828 case MII_STATUS_10FD: printf("FD"); break;
1829 case MII_STATUS_10HD: printf("HD"); break;
1830 default: printf("FD/HD"); break;
1831 }
1832 }
1833}
1834
1835/*===========================================================================*
1836 * rl_clear_rx *
1837 *===========================================================================*/
1838static void rl_clear_rx(rep)
1839re_t *rep;
1840{
1841 port_t port;
1842 u8_t cr;
1843 int i;
1844 clock_t t0,t1;
1845
1846 rep->re_clear_rx= FALSE;
1847 port= rep->re_base_port;
1848
1849 /* Reset the receiver */
1850 cr= rl_inb(port, RL_CR);
1851 cr &= ~RL_CR_RE;
1852 rl_outb(port, RL_CR, cr);
1853 getuptime(&t0);
1854 do {
1855 if (!(rl_inb(port, RL_CR) & RL_CR_RE))
1856 break;
1857 } while (getuptime(&t1)==OK && (t1-t0) < HZ);
1858 if (rl_inb(port, RL_CR) & RL_CR_RE)
1859 panic("rtl8139","cannot disable receiver", NO_NUM);
1860
1861#if 0
1862 printf("RBSTART = 0x%08x\n", rl_inl(port, RL_RBSTART));
1863 printf("CAPR = 0x%04x\n", rl_inw(port, RL_CAPR));
1864 printf("CBR = 0x%04x\n", rl_inw(port, RL_CBR));
1865 printf("RCR = 0x%08x\n", rl_inl(port, RL_RCR));
1866#endif
1867
1868 rl_outb(port, RL_CR, cr | RL_CR_RE);
1869
1870 rl_outl(port, RL_RCR, RX_BUFBITS);
1871
1872 rl_rec_mode(rep);
1873
1874 rep->re_stat.ets_missedP++;
1875}
1876
1877/*===========================================================================*
1878 * rl_do_reset *
1879 *===========================================================================*/
1880static void rl_do_reset(rep)
1881re_t *rep;
1882{
1883 rep->re_need_reset= FALSE;
1884 rl_reset_hw(rep);
1885 rl_rec_mode(rep);
1886
1887 rep->re_tx_head= 0;
1888 if (rep->re_flags & REF_SEND_AVAIL)
1889 {
1890 rep->re_tx[rep->re_tx_head].ret_busy= FALSE;
1891 rep->re_send_int= TRUE;
1892 }
1893}
1894
1895/*===========================================================================*
1896 * rl_getstat *
1897 *===========================================================================*/
1898static void rl_getstat(mp)
1899message *mp;
1900{
1901 int port;
1902 eth_stat_t stats;
1903 re_t *rep;
1904
1905 port = mp->DL_PORT;
1906 if (port < 0 || port >= RE_PORT_NR)
1907 panic("rtl8139","illegal port", port);
1908 rep= &re_table[port];
1909 rep->re_client= mp->DL_PROC;
1910
1911 assert(rep->re_mode == REM_ENABLED);
1912 assert(rep->re_flags & REF_ENABLED);
1913
1914 stats= rep->re_stat;
1915
1916 put_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
1917 (vir_bytes) sizeof(stats), &stats);
1918 reply(rep, OK, FALSE);
1919}
1920
1921
1922/*===========================================================================*
1923 * rl_getname *
1924 *===========================================================================*/
1925static void rl_getname(mp)
1926message *mp;
1927{
1928 int r;
1929
1930 strncpy(mp->DL_NAME, progname, sizeof(mp->DL_NAME));
1931 mp->DL_NAME[sizeof(mp->DL_NAME)-1]= '\0';
1932 mp->m_type= DL_NAME_REPLY;
1933 r= send(mp->m_source, mp);
1934 if (r != OK)
1935 panic("RTL8139", "rl_getname: send failed: %d\n", r);
1936}
1937
1938
1939/*===========================================================================*
1940 * reply *
1941 *===========================================================================*/
1942static void reply(rep, err, may_block)
1943re_t *rep;
1944int err;
1945int may_block;
1946{
1947 message reply;
1948 int status;
1949 int r;
1950 clock_t now;
1951
1952 status = 0;
1953 if (rep->re_flags & REF_PACK_SENT)
1954 status |= DL_PACK_SEND;
1955 if (rep->re_flags & REF_PACK_RECV)
1956 status |= DL_PACK_RECV;
1957
1958 reply.m_type = DL_TASK_REPLY;
1959 reply.DL_PORT = rep - re_table;
1960 reply.DL_PROC = rep->re_client;
1961 reply.DL_STAT = status | ((u32_t) err << 16);
1962 reply.DL_COUNT = rep->re_read_s;
1963 if (OK != (r = getuptime(&now)))
1964 panic("rtl8139","getuptime() failed:", r);
1965 reply.DL_CLCK = now;
1966
1967 r= send(rep->re_client, &reply);
1968
1969 if (r == ELOCKED && may_block)
1970 {
1971#if 0
1972 printW(); printf("send locked\n");
1973#endif
1974 return;
1975 }
1976
1977 if (r < 0) {
1978 printf("RTL8139 tried sending to %d, type %d\n", rep->re_client, reply.m_type);
1979 panic("rtl8139","send failed:", r);
1980 }
1981
1982 rep->re_read_s = 0;
1983 rep->re_flags &= ~(REF_PACK_SENT | REF_PACK_RECV);
1984}
1985
1986/*===========================================================================*
1987 * mess_reply *
1988 *===========================================================================*/
1989static void mess_reply(req, reply_mess)
1990message *req;
1991message *reply_mess;
1992{
1993 if (send(req->m_source, reply_mess) != OK)
1994 panic("rtl8139","unable to mess_reply", NO_NUM);
1995}
1996
1997/*===========================================================================*
1998 * put_userdata *
1999 *===========================================================================*/
2000static void put_userdata(user_proc, user_addr, count, loc_addr)
2001int user_proc;
2002vir_bytes user_addr;
2003vir_bytes count;
2004void *loc_addr;
2005{
2006 int cps;
2007 cps = sys_datacopy(SELF, (vir_bytes) loc_addr, user_proc, user_addr, count);
2008 if (cps != OK) printf("RTL8139: warning, scopy failed: %d\n", cps);
2009}
2010
2011#if 0
2012static void dump_phy(rep)
2013re_t *rep;
2014{
2015 port_t port;
2016 u32_t t;
2017
2018 port= rep->re_base_port;
2019
2020 t= rl_inb(port, RL_MSR);
2021 printf("MSR: 0x%02lx\n", t);
2022 if (t & RL_MSR_SPEED_10)
2023 printf("\t10 Mbps\n");
2024 if (t & RL_MSR_LINKB)
2025 printf("\tLink failed\n");
2026
2027 t= rl_inb(port, RL_CONFIG1);
2028 printf("CONFIG1: 0x%02lx\n", t);
2029
2030 t= rl_inb(port, RL_CONFIG3);
2031 printf("CONFIG3: 0x%02lx\n", t);
2032
2033 t= rl_inb(port, RL_CONFIG4);
2034 printf("CONFIG4: 0x%02lx\n", t);
2035
2036 t= rl_inw(port, RL_BMCR);
2037 printf("BMCR (MII_CTRL): 0x%04lx\n", t);
2038
2039 t= rl_inw(port, RL_BMSR);
2040 printf("BMSR:");
2041 if (t & MII_STATUS_100T4)
2042 printf(" 100Base-T4");
2043 if (t & MII_STATUS_100XFD)
2044 printf(" 100Base-X-FD");
2045 if (t & MII_STATUS_100XHD)
2046 printf(" 100Base-X-HD");
2047 if (t & MII_STATUS_10FD)
2048 printf(" 10Mbps-FD");
2049 if (t & MII_STATUS_10HD)
2050 printf(" 10Mbps-HD");
2051 if (t & MII_STATUS_100T2FD)
2052 printf(" 100Base-T2-FD");
2053 if (t & MII_STATUS_100T2HD)
2054 printf(" 100Base-T2-HD");
2055 if (t & MII_STATUS_EXT_STAT)
2056 printf(" Ext-stat");
2057 if (t & MII_STATUS_RES)
2058 printf(" res-0x%lx", t & MII_STATUS_RES);
2059 if (t & MII_STATUS_MFPS)
2060 printf(" MFPS");
2061 if (t & MII_STATUS_ANC)
2062 printf(" ANC");
2063 if (t & MII_STATUS_RF)
2064 printf(" remote-fault");
2065 if (t & MII_STATUS_ANA)
2066 printf(" ANA");
2067 if (t & MII_STATUS_LS)
2068 printf(" Link");
2069 if (t & MII_STATUS_JD)
2070 printf(" Jabber");
2071 if (t & MII_STATUS_EC)
2072 printf(" Extended-capability");
2073 printf("\n");
2074
2075 t= rl_inw(port, RL_ANAR);
2076 printf("ANAR (MII_ANA): 0x%04lx\n", t);
2077
2078 t= rl_inw(port, RL_ANLPAR);
2079 printf("ANLPAR: 0x%04lx\n", t);
2080
2081 t= rl_inw(port, RL_ANER);
2082 printf("ANER (MII_ANE): ");
2083 if (t & MII_ANE_RES)
2084 printf(" res-0x%lx", t & MII_ANE_RES);
2085 if (t & MII_ANE_PDF)
2086 printf(" Par-Detect-Fault");
2087 if (t & MII_ANE_LPNPA)
2088 printf(" LP-Next-Page-Able");
2089 if (t & MII_ANE_NPA)
2090 printf(" Loc-Next-Page-Able");
2091 if (t & MII_ANE_PR)
2092 printf(" Page-Received");
2093 if (t & MII_ANE_LPANA)
2094 printf(" LP-Auto-Neg-Able");
2095 printf("\n");
2096
2097 t= rl_inw(port, RL_NWAYTR);
2098 printf("NWAYTR: 0x%04lx\n", t);
2099 t= rl_inw(port, RL_CSCR);
2100 printf("CSCR: 0x%04lx\n", t);
2101
2102 t= rl_inb(port, RL_CONFIG5);
2103 printf("CONFIG5: 0x%02lx\n", t);
2104}
2105#endif
2106
2107static int do_hard_int(void)
2108{
2109 int i,s;
2110
2111 for (i=0; i < RE_PORT_NR; i ++) {
2112
2113 /* Run interrupt handler at driver level. */
2114 rl_handler( &re_table[i]);
2115
2116 /* Reenable interrupts for this hook. */
2117 if ((s=sys_irqenable(&re_table[i].re_hook_id)) != OK)
2118 printf("RTL8139: error, couldn't enable interrupts: %d\n", s);
2119 }
2120}
2121
2122/*===========================================================================*
2123 * rl_handler *
2124 *===========================================================================*/
2125static int rl_handler(rep)
2126re_t *rep;
2127{
2128 int i, port, tx_head, tx_tail, link_up;
2129 u16_t isr, tsad;
2130 u32_t tsd, tcr, ertxth;
2131#if 0
2132 u8_t cr;
2133#endif
2134 clock_t t0,t1;
2135 int_event_check = FALSE; /* disable check by default */
2136
2137 port= rep->re_base_port;
2138
2139 /* Ack interrupt */
2140 isr= rl_inw(port, RL_ISR);
2141 rl_outw(port, RL_ISR, isr);
2142
2143 if (isr & RL_IMR_FOVW)
2144 {
2145 isr &= ~RL_IMR_FOVW;
2146 /* Should do anything? */
2147
2148 rep->re_stat.ets_fifoOver++;
2149 }
2150 if (isr & RL_IMR_PUN)
2151 {
2152 isr &= ~RL_IMR_PUN;
2153
2154 /* Either the link status changed or there was a TX fifo
2155 * underrun.
2156 */
2157 link_up= !(rl_inb(port, RL_MSR) & RL_MSR_LINKB);
2158 if (link_up != rep->re_link_up)
2159 {
2160 rep->re_report_link= TRUE;
2161 rep->re_got_int= TRUE;
2162 int_event_check = TRUE;
2163 }
2164 }
2165 if (isr & RL_IMR_RXOVW)
2166 {
2167 isr &= ~RL_IMR_RXOVW;
2168
2169 /* Clear the receive buffer */
2170 rep->re_clear_rx= TRUE;
2171 rep->re_got_int= TRUE;
2172 int_event_check = TRUE;
2173 }
2174
2175 if (isr & (RL_ISR_RER | RL_ISR_ROK))
2176 {
2177 isr &= ~(RL_ISR_RER | RL_ISR_ROK);
2178
2179 if (!rep->re_got_int && (rep->re_flags & REF_READING))
2180 {
2181 rep->re_got_int= TRUE;
2182 int_event_check = TRUE;
2183 }
2184 }
2185#if 0
2186 if ((isr & (RL_ISR_TER | RL_ISR_TOK)) &&
2187 (rep->re_flags & REF_SEND_AVAIL) &&
2188 (rep->re_tx[0].ret_busy || rep->re_tx[1].ret_busy ||
2189 rep->re_tx[2].ret_busy || rep->re_tx[3].ret_busy))
2190
2191 {
2192 printf(
2193 "rl_handler, SEND_AVAIL: tx_head %d, tx_tail %d, busy: %d %d %d %d\n",
2194 rep->re_tx_head, rep->re_tx_tail,
2195 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
2196 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
2197 printf(
2198 "rl_handler: TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
2199 rl_inw(port, RL_TSAD),
2200 rl_inl(port, RL_TSD0+0*4),
2201 rl_inl(port, RL_TSD0+1*4),
2202 rl_inl(port, RL_TSD0+2*4),
2203 rl_inl(port, RL_TSD0+3*4));
2204 }
2205#endif
2206 if ((isr & (RL_ISR_TER | RL_ISR_TOK)) || 1)
2207 {
2208 isr &= ~(RL_ISR_TER | RL_ISR_TOK);
2209
2210 tsad= rl_inw(port, RL_TSAD);
2211 if (tsad & (RL_TSAD_TABT0|RL_TSAD_TABT1|
2212 RL_TSAD_TABT2|RL_TSAD_TABT3))
2213 {
2214#if 0
2215 /* Do we need a watch dog? */
2216 /* Just reset the whole chip */
2217 rep->re_need_reset= TRUE;
2218 rep->re_got_int= TRUE;
2219 int_event_check = TRUE;
2220#elif 0
2221 /* Reset transmitter */
2222 rep->re_stat.ets_transAb++;
2223
2224 cr= rl_inb(port, RL_CR);
2225 cr &= ~RL_CR_TE;
2226 rl_outb(port, RL_CR, cr);
2227 getuptime(&t0);
2228 do {
2229 if (!(rl_inb(port, RL_CR) & RL_CR_TE))
2230 break;
2231 } while (getuptime(&t1)==OK && (t1-t0) < HZ);
2232 if (rl_inb(port, RL_CR) & RL_CR_TE)
2233 {
2234 panic("rtl8139","cannot disable transmitter",
2235 NO_NUM);
2236 }
2237 rl_outb(port, RL_CR, cr | RL_CR_TE);
2238
2239 tcr= rl_inl(port, RL_TCR);
2240 rl_outl(port, RL_TCR, tcr | RL_TCR_IFG_STD);
2241
2242 printf("rl_handler: reset after abort\n");
2243
2244 if (rep->re_flags & REF_SEND_AVAIL)
2245 {
2246 printf("rl_handler: REF_SEND_AVAIL\n");
2247 rep->re_send_int= TRUE;
2248 rep->re_got_int= TRUE;
2249 int_event_check = TRUE;
2250 }
2251 for (i= 0; i< N_TX_BUF; i++)
2252 rep->re_tx[i].ret_busy= FALSE;
2253 rep->re_tx_head= 0;
2254#else
2255 printf("rl_handler, TABT, tasd = 0x%04x\n",
2256 tsad);
2257
2258 /* Find the aborted transmit request */
2259 for (i= 0; i< N_TX_BUF; i++)
2260 {
2261 tsd= rl_inl(port, RL_TSD0+i*4);
2262 if (tsd & RL_TSD_TABT)
2263 break;
2264 }
2265 if (i >= N_TX_BUF)
2266 {
2267 printf(
2268 "rl_handler: can't find aborted TX req.\n");
2269 }
2270 else
2271 {
2272 printf("TSD%d = 0x%04lx\n", i, tsd);
2273
2274 /* Set head and tail to this buffer */
2275 rep->re_tx_head= rep->re_tx_tail= i;
2276 }
2277
2278 /* Aborted transmission, just kick the device
2279 * and be done with it.
2280 */
2281 rep->re_stat.ets_transAb++;
2282 tcr= rl_inl(port, RL_TCR);
2283 rl_outl(port, RL_TCR, tcr | RL_TCR_CLRABT);
2284#endif
2285 }
2286
2287 /* Transmit completed */
2288 tx_head= rep->re_tx_head;
2289 tx_tail= rep->re_tx_tail;
2290 for (i= 0; i< 2*N_TX_BUF; i++)
2291 {
2292 if (!rep->re_tx[tx_tail].ret_busy)
2293 {
2294 /* Strange, this buffer is not in-use.
2295 * Increment tx_tail until tx_head is
2296 * reached (or until we find a buffer that
2297 * is in-use.
2298 */
2299 if (tx_tail == tx_head)
2300 break;
2301 if (++tx_tail >= N_TX_BUF)
2302 tx_tail= 0;
2303 assert(tx_tail < RL_N_TX);
2304 rep->re_tx_tail= tx_tail;
2305 continue;
2306 }
2307 tsd= rl_inl(port, RL_TSD0+tx_tail*4);
2308 if (!(tsd & RL_TSD_OWN))
2309 {
2310 /* Buffer is not yet ready */
2311 break;
2312 }
2313
2314 /* Should collect statistics */
2315 if (tsd & RL_TSD_CRS)
2316 rep->re_stat.ets_carrSense++;
2317 if (tsd & RL_TSD_TABT)
2318 {
2319 printf("rl_handler, TABT, TSD%d = 0x%04lx\n",
2320 tx_tail, tsd);
2321 assert(0); /* CLRABT is not all that
2322 * effective, why not?
2323 */
2324 rep->re_stat.ets_transAb++;
2325 tcr= rl_inl(port, RL_TCR);
2326 rl_outl(port, RL_TCR, tcr | RL_TCR_CLRABT);
2327 }
2328 if (tsd & RL_TSD_OWC)
2329 rep->re_stat.ets_OWC++;
2330 if (tsd & RL_TSD_CDH)
2331 rep->re_stat.ets_CDheartbeat++;
2332
2333 /* What about collisions? */
2334 if (tsd & RL_TSD_TOK)
2335 rep->re_stat.ets_packetT++;
2336 else
2337 rep->re_stat.ets_sendErr++;
2338 if (tsd & RL_TSD_TUN)
2339 {
2340 rep->re_stat.ets_fifoUnder++;
2341
2342 /* Increase ERTXTH */
2343 ertxth= tsd + (1 << RL_TSD_ERTXTH_S);
2344 ertxth &= RL_TSD_ERTXTH_M;
2345 if (debug && ertxth > rep->re_ertxth)
2346 {
2347 printf("%s: new ertxth: %ld bytes\n",
2348 rep->re_name,
2349 (ertxth >> RL_TSD_ERTXTH_S) *
2350 32);
2351 rep->re_ertxth= ertxth;
2352 }
2353 }
2354 rep->re_tx[tx_tail].ret_busy= FALSE;
2355
2356#if 0
2357 if (rep->re_flags & REF_SEND_AVAIL)
2358 {
2359 printf("TSD%d: %08lx\n", tx_tail, tsd);
2360 printf(
2361 "rl_handler: head %d, tail %d, busy: %d %d %d %d\n",
2362 tx_head, tx_tail,
2363 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
2364 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
2365 }
2366#endif
2367
2368 if (++tx_tail >= N_TX_BUF)
2369 tx_tail= 0;
2370 assert(tx_tail < RL_N_TX);
2371 rep->re_tx_tail= tx_tail;
2372
2373 if (rep->re_flags & REF_SEND_AVAIL)
2374 {
2375#if 0
2376 printf("rl_handler: REF_SEND_AVAIL\n");
2377#endif
2378 rep->re_send_int= TRUE;
2379 if (!rep->re_got_int)
2380 {
2381 rep->re_got_int= TRUE;
2382 int_event_check = TRUE;
2383 }
2384 }
2385 }
2386 assert(i < 2*N_TX_BUF);
2387 }
2388 if (isr)
2389 {
2390 printf("rl_handler: unhandled interrupt: isr = 0x%04x\n",
2391 isr);
2392 }
2393
2394 return 1;
2395}
2396
2397/*===========================================================================*
2398 * rl_watchdog_f *
2399 *===========================================================================*/
2400static void rl_watchdog_f(tp)
2401timer_t *tp;
2402{
2403 int i;
2404 re_t *rep;
2405 /* Use a synchronous alarm instead of a watchdog timer. */
2406 sys_setalarm(HZ, 0);
2407
2408 for (i= 0, rep = &re_table[0]; i<RE_PORT_NR; i++, rep++)
2409 {
2410 if (rep->re_mode != REM_ENABLED)
2411 continue;
2412 if (!(rep->re_flags & REF_SEND_AVAIL))
2413 {
2414 /* Assume that an idle system is alive */
2415 rep->re_tx_alive= TRUE;
2416 continue;
2417 }
2418 if (rep->re_tx_alive)
2419 {
2420 rep->re_tx_alive= FALSE;
2421 continue;
2422 }
2423 printf("rl_watchdog_f: resetting port %d\n", i);
2424 printf(
2425 "TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
2426 rl_inw(rep->re_base_port, RL_TSAD),
2427 rl_inl(rep->re_base_port, RL_TSD0+0*4),
2428 rl_inl(rep->re_base_port, RL_TSD0+1*4),
2429 rl_inl(rep->re_base_port, RL_TSD0+2*4),
2430 rl_inl(rep->re_base_port, RL_TSD0+3*4));
2431 printf("tx_head %d, tx_tail %d, busy: %d %d %d %d\n",
2432 rep->re_tx_head, rep->re_tx_tail,
2433 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
2434 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
2435 rep->re_need_reset= TRUE;
2436 rep->re_got_int= TRUE;
2437
2438 check_int_events();
2439 }
2440}
2441
2442#if 0
2443
2444_PROTOTYPE( static void rtl_init, (struct dpeth *dep) );
2445_PROTOTYPE( static u16_t get_ee_word, (dpeth_t *dep, int a) );
2446_PROTOTYPE( static void ee_wen, (dpeth_t *dep) );
2447_PROTOTYPE( static void set_ee_word, (dpeth_t *dep, int a, U16_t w) );
2448_PROTOTYPE( static void ee_wds, (dpeth_t *dep) );
2449
2450static void rtl_init(dep)
2451dpeth_t *dep;
2452{
2453 u8_t reg_a, reg_b, cr, config0, config2, config3;
2454 int i;
2455 char val[128];
2456
2457 printf("rtl_init called\n");
2458 ne_init(dep);
2459
2460 /* ID */
2461 outb_reg0(dep, DP_CR, CR_PS_P0);
2462 reg_a = inb_reg0(dep, DP_DUM1);
2463 reg_b = inb_reg0(dep, DP_DUM2);
2464
2465 printf("rtl_init: '%c', '%c'\n", reg_a, reg_b);
2466
2467 outb_reg0(dep, DP_CR, CR_PS_P3);
2468 config0 = inb_reg3(dep, 3);
2469 config2 = inb_reg3(dep, 5);
2470 config3 = inb_reg3(dep, 6);
2471 outb_reg0(dep, DP_CR, CR_PS_P0);
2472
2473 printf("rtl_init: config 0/2/3 = %x/%x/%x\n",
2474 config0, config2, config3);
2475
2476 if (0 == sys_getkenv("RTL8029FD",9+1, val, sizeof(val)))
2477 {
2478 printf("rtl_init: setting full-duplex mode\n");
2479 outb_reg0(dep, DP_CR, CR_PS_P3);
2480
2481 cr= inb_reg3(dep, 1);
2482 outb_reg3(dep, 1, cr | 0xc0);
2483
2484 outb_reg3(dep, 6, config3 | 0x40);
2485 config3 = inb_reg3(dep, 6);
2486
2487 config2= inb_reg3(dep, 5);
2488 outb_reg3(dep, 5, config2 | 0x20);
2489 config2= inb_reg3(dep, 5);
2490
2491 outb_reg3(dep, 1, cr);
2492
2493 outb_reg0(dep, DP_CR, CR_PS_P0);
2494
2495 printf("rtl_init: config 2 = %x\n", config2);
2496 printf("rtl_init: config 3 = %x\n", config3);
2497 }
2498
2499 for (i= 0; i<64; i++)
2500 printf("%x ", get_ee_word(dep, i));
2501 printf("\n");
2502
2503 if (0 == sys_getkenv("RTL8029MN",9+1, val, sizeof(val)))
2504 {
2505 ee_wen(dep);
2506
2507 set_ee_word(dep, 0x78/2, 0x10ec);
2508 set_ee_word(dep, 0x7A/2, 0x8029);
2509 set_ee_word(dep, 0x7C/2, 0x10ec);
2510 set_ee_word(dep, 0x7E/2, 0x8029);
2511
2512 ee_wds(dep);
2513
2514 assert(get_ee_word(dep, 0x78/2) == 0x10ec);
2515 assert(get_ee_word(dep, 0x7A/2) == 0x8029);
2516 assert(get_ee_word(dep, 0x7C/2) == 0x10ec);
2517 assert(get_ee_word(dep, 0x7E/2) == 0x8029);
2518 }
2519
2520 if (0 == sys_getkenv("RTL8029XXX",10+1, val, sizeof(val)))
2521 {
2522 ee_wen(dep);
2523
2524 set_ee_word(dep, 0x76/2, 0x8029);
2525
2526 ee_wds(dep);
2527
2528 assert(get_ee_word(dep, 0x76/2) == 0x8029);
2529 }
2530}
2531
2532static u16_t get_ee_word(dep, a)
2533dpeth_t *dep;
2534int a;
2535{
2536 int b, i, cmd;
2537 u16_t w;
2538
2539 outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */
2540
2541 /* Switch to 9346 mode and enable CS */
2542 outb_reg3(dep, 1, 0x80 | 0x8);
2543
2544 cmd= 0x180 | (a & 0x3f); /* 1 1 0 a5 a4 a3 a2 a1 a0 */
2545 for (i= 8; i >= 0; i--)
2546 {
2547 b= (cmd & (1 << i));
2548 b= (b ? 2 : 0);
2549
2550 /* Cmd goes out on the rising edge of the clock */
2551 outb_reg3(dep, 1, 0x80 | 0x8 | b);
2552 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
2553 }
2554 outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */
2555
2556 w= 0;
2557 for (i= 0; i<16; i++)
2558 {
2559 w <<= 1;
2560
2561 /* Data is shifted out on the rising edge. Read at the
2562 * falling edge.
2563 */
2564 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4);
2565 outb_reg3(dep, 1, 0x80 | 0x8 | b);
2566 b= inb_reg3(dep, 1);
2567 w |= (b & 1);
2568 }
2569
2570 outb_reg3(dep, 1, 0x80); /* drop CS */
2571 outb_reg3(dep, 1, 0x00); /* back to normal */
2572 outb_reg0(dep, DP_CR, CR_PS_P0); /* back to bank 0 */
2573
2574 return w;
2575}
2576
2577static void ee_wen(dep)
2578dpeth_t *dep;
2579{
2580 int b, i, cmd;
2581 u16_t w;
2582
2583 outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */
2584
2585 /* Switch to 9346 mode and enable CS */
2586 outb_reg3(dep, 1, 0x80 | 0x8);
2587
2588 cmd= 0x130; /* 1 0 0 1 1 x x x x */
2589 for (i= 8; i >= 0; i--)
2590 {
2591 b= (cmd & (1 << i));
2592 b= (b ? 2 : 0);
2593
2594 /* Cmd goes out on the rising edge of the clock */
2595 outb_reg3(dep, 1, 0x80 | 0x8 | b);
2596 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
2597 }
2598 outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */
2599 outb_reg3(dep, 1, 0x80); /* Drop CS */
2600 /* micro_delay(1); */ /* Is this required? */
2601}
2602
2603static void set_ee_word(dep, a, w)
2604dpeth_t *dep;
2605int a;
2606u16_t w;
2607{
2608 int b, i, cmd;
2609 clock_t t0, t1;
2610
2611 outb_reg3(dep, 1, 0x80 | 0x8); /* Set CS */
2612
2613 cmd= 0x140 | (a & 0x3f); /* 1 0 1 a5 a4 a3 a2 a1 a0 */
2614 for (i= 8; i >= 0; i--)
2615 {
2616 b= (cmd & (1 << i));
2617 b= (b ? 2 : 0);
2618
2619 /* Cmd goes out on the rising edge of the clock */
2620 outb_reg3(dep, 1, 0x80 | 0x8 | b);
2621 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
2622 }
2623 for (i= 15; i >= 0; i--)
2624 {
2625 b= (w & (1 << i));
2626 b= (b ? 2 : 0);
2627
2628 /* Cmd goes out on the rising edge of the clock */
2629 outb_reg3(dep, 1, 0x80 | 0x8 | b);
2630 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
2631 }
2632 outb_reg3(dep, 1, 0x80 | 0x8); /* End of data */
2633 outb_reg3(dep, 1, 0x80); /* Drop CS */
2634 /* micro_delay(1); */ /* Is this required? */
2635 outb_reg3(dep, 1, 0x80 | 0x8); /* Set CS */
2636 getuptime(&t0);
2637 do {
2638 if (inb_reg3(dep, 1) & 1)
2639 break;
2640 } while (getuptime(&t1) == OK && (t1 == t0));
2641 if (!(inb_reg3(dep, 1) & 1))
2642 panic("set_ee_word","device remains busy", NO_NUM);
2643}
2644
2645static void ee_wds(dep)
2646dpeth_t *dep;
2647{
2648 int b, i, cmd;
2649 u16_t w;
2650
2651 outb_reg0(dep, DP_CR, CR_PS_P3); /* Bank 3 */
2652
2653 /* Switch to 9346 mode and enable CS */
2654 outb_reg3(dep, 1, 0x80 | 0x8);
2655
2656 cmd= 0x100; /* 1 0 0 0 0 x x x x */
2657 for (i= 8; i >= 0; i--)
2658 {
2659 b= (cmd & (1 << i));
2660 b= (b ? 2 : 0);
2661
2662 /* Cmd goes out on the rising edge of the clock */
2663 outb_reg3(dep, 1, 0x80 | 0x8 | b);
2664 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
2665 }
2666 outb_reg3(dep, 1, 0x80 | 0x8); /* End of cmd */
2667 outb_reg3(dep, 1, 0x80); /* Drop CS */
2668 outb_reg3(dep, 1, 0x00); /* back to normal */
2669 outb_reg0(dep, DP_CR, CR_PS_P0); /* back to bank 0 */
2670}
2671#endif
2672
2673/*
2674 * $PchId: rtl8139.c,v 1.3 2003/09/11 14:15:15 philip Exp $
2675 */
Note: See TracBrowser for help on using the repository browser.