rtl8139.c

Go to the documentation of this file.
00001 /*
00002  * rtl8139.c
00003  *
00004  * This file contains a ethernet device driver for Realtek rtl8139 based
00005  * ethernet cards.
00006  *
00007  * The valid messages and their parameters are:
00008  *
00009  *   m_type       DL_PORT    DL_PROC   DL_COUNT   DL_MODE   DL_ADDR
00010  * |------------+----------+---------+----------+---------+---------|
00011  * | HARD_INT   |          |         |          |         |         |
00012  * |------------|----------|---------|----------|---------|---------|
00013  * | DL_WRITE   | port nr  | proc nr | count    | mode    | address |
00014  * |------------|----------|---------|----------|---------|---------|
00015  * | DL_WRITEV  | port nr  | proc nr | count    | mode    | address |
00016  * |------------|----------|---------|----------|---------|---------|
00017  * | DL_READ    | port nr  | proc nr | count    |         | address |
00018  * |------------|----------|---------|----------|---------|---------|
00019  * | DL_READV   | port nr  | proc nr | count    |         | address |
00020  * |------------|----------|---------|----------|---------|---------|
00021  * | DL_INIT    | port nr  | proc nr | mode     |         | address |
00022  * |------------|----------|---------|----------|---------|---------|
00023  * | DL_GETSTAT | port nr  | proc nr |          |         | address |
00024  * |------------|----------|---------|----------|---------|---------|
00025  * | DL_GETNAME |          |         |          |         |         |
00026  * |------------|----------|---------|----------|---------|---------|
00027  * | DL_STOP    | port_nr  |         |          |         |         |
00028  * |------------|----------|---------|----------|---------|---------|
00029  *
00030  * The messages sent are:
00031  *
00032  *   m-type       DL_POR T   DL_PROC   DL_COUNT   DL_STAT   DL_CLCK
00033  * |------------|----------|---------|----------|---------|---------|
00034  * |DL_TASK_REPL| port nr  | proc nr | rd-count | err|stat| clock   |
00035  * |------------|----------|---------|----------|---------|---------|
00036  *
00037  *   m_type       m3_i1     m3_i2       m3_ca1
00038  * |------------+---------+-----------+---------------|
00039  * |DL_INIT_REPL| port nr | last port | ethernet addr |
00040  * |------------|---------|-----------|---------------|
00041  *
00042  * Created:     Aug 2003 by Philip Homburg <philip@cs.vu.nl>
00043  * Changes:
00044  *   Aug 15, 2004   sync alarms replace watchdogs timers  (Jorrit N. Herder)
00045  *   May 02, 2004   flag alarms replace micro_elapsed()  (Jorrit N. Herder)
00046  *
00047  */
00048 
00049 #include "../drivers.h"
00050 
00051 #include <stdlib.h>
00052 #include <stdio.h>
00053 #include <string.h>
00054 #include <stddef.h>
00055 #include <minix/com.h>
00056 #include <minix/keymap.h>
00057 #include <minix/syslib.h>
00058 #include <minix/type.h>
00059 #include <minix/sysutil.h>
00060 #include <timers.h>
00061 #include <ibm/portio.h>
00062 #include <net/hton.h>
00063 #include <net/gen/ether.h>
00064 #include <net/gen/eth_io.h>
00065 #include <ibm/pci.h>
00066 
00067 #include <sys/types.h>
00068 #include <fcntl.h>
00069 #include <assert.h>
00070 #include <unistd.h>
00071 #include <sys/ioc_memory.h>
00072 #include "../../kernel/const.h"
00073 #include "../../kernel/config.h"
00074 #include "../../kernel/type.h"
00075 
00076 #define tmra_ut                 timer_t
00077 #define tmra_inittimer(tp)      tmr_inittimer(tp)
00078 #define Proc_number(p)          proc_number(p)
00079 #define debug                   0
00080 #define printW()                ((void)0)
00081 #define vm_1phys2bus(p)         (p)
00082 
00083 #define VERBOSE         1       /* display message during init */
00084 
00085 #include "rtl8139.h"
00086 
00087 #define RX_BUFSIZE      RL_RCR_RBLEN_64K_SIZE
00088 #define RX_BUFBITS      RL_RCR_RBLEN_64K
00089 #define N_TX_BUF        RL_N_TX
00090 
00091 #define RE_PORT_NR      1               /* Minix */
00092 
00093 /* I/O vectors are handled IOVEC_NR entries at a time. */
00094 #define IOVEC_NR        16
00095 
00096 /* Configuration */
00097 #define RL_ENVVAR       "RTLETH"
00098 
00099 PRIVATE struct pcitab
00100 {
00101         u16_t vid;
00102         u16_t did;
00103         int checkclass;
00104 } pcitab[]=
00105 {
00106         { 0x10ec, 0x8139, 0 },          /* Realtek RTL8139 */
00107         { 0x1186, 0x1300, 0 },          /* D-Link RTL8139 */
00108 
00109         { 0x0000, 0x0000, 0 }
00110 };
00111 
00112 typedef struct re
00113 {
00114         port_t re_base_port;
00115         int re_irq;
00116         int re_mode;
00117         int re_flags;
00118         int re_client;
00119         int re_link_up;
00120         int re_got_int;
00121         int re_send_int;
00122         int re_report_link;
00123         int re_clear_rx;
00124         int re_need_reset;
00125         int re_tx_alive;
00126         char *re_model;
00127 
00128         /* Rx */
00129         phys_bytes re_rx_buf;
00130         char  *v_re_rx_buf;
00131         vir_bytes re_read_s;
00132 
00133         /* Tx */
00134         int re_tx_head;
00135         int re_tx_tail;
00136         struct
00137         {
00138                 int ret_busy;
00139                 phys_bytes ret_buf;
00140                 char * v_ret_buf;
00141         } re_tx[N_TX_BUF];
00142         u32_t re_ertxth;        /* Early Tx Threshold */
00143 
00144         /* PCI related */
00145         int re_seen;                    /* TRUE iff device available */
00146         u8_t re_pcibus; 
00147         u8_t re_pcidev; 
00148         u8_t re_pcifunc;        
00149 
00150         /* 'large' items */
00151         int re_hook_id;                 /* IRQ hook id at kernel */
00152         eth_stat_t re_stat;
00153         ether_addr_t re_address;
00154         message re_rx_mess;
00155         message re_tx_mess;
00156         char re_name[sizeof("rtl8139#n")];
00157         iovec_t re_iovec[IOVEC_NR];
00158 }
00159 re_t;
00160 
00161 #define REM_DISABLED    0x0
00162 #define REM_ENABLED     0x1
00163 
00164 #define REF_PACK_SENT   0x001
00165 #define REF_PACK_RECV   0x002
00166 #define REF_SEND_AVAIL  0x004
00167 #define REF_READING     0x010
00168 #define REF_EMPTY       0x000
00169 #define REF_PROMISC     0x040
00170 #define REF_MULTI       0x080
00171 #define REF_BROAD       0x100
00172 #define REF_ENABLED     0x200
00173 
00174 static re_t re_table[RE_PORT_NR];
00175 
00176 static u16_t eth_ign_proto;
00177 static tmra_ut rl_watchdog;
00178 
00179 FORWARD _PROTOTYPE( unsigned my_inb, (U16_t port) );
00180 FORWARD _PROTOTYPE( unsigned my_inw, (U16_t port) );
00181 FORWARD _PROTOTYPE( unsigned my_inl, (U16_t port) );
00182 static unsigned my_inb(U16_t port) {
00183         u32_t value;
00184         int s;
00185         if ((s=sys_inb(port, &value)) !=OK)
00186                 printf("RTL8139: warning, sys_inb failed: %d\n", s);
00187         return value;
00188 }
00189 static unsigned my_inw(U16_t port) {
00190         u32_t value;
00191         int s;
00192         if ((s=sys_inw(port, &value)) !=OK)
00193                 printf("RTL8139: warning, sys_inw failed: %d\n", s);
00194         return value;
00195 }
00196 static unsigned my_inl(U16_t port) {
00197         U32_t value;
00198         int s;
00199         if ((s=sys_inl(port, &value)) !=OK)
00200                 printf("RTL8139: warning, sys_inl failed: %d\n", s);
00201         return value;
00202 }
00203 #define rl_inb(port, offset)    (my_inb((port) + (offset)))
00204 #define rl_inw(port, offset)    (my_inw((port) + (offset)))
00205 #define rl_inl(port, offset)    (my_inl((port) + (offset)))
00206 
00207 FORWARD _PROTOTYPE( void my_outb, (U16_t port, U8_t value) );
00208 FORWARD _PROTOTYPE( void my_outw, (U16_t port, U16_t value) );
00209 FORWARD _PROTOTYPE( void my_outl, (U16_t port, U32_t value) );
00210 static void my_outb(U16_t port, U8_t value) {
00211         int s;
00212         if ((s=sys_outb(port, value)) !=OK)
00213                 printf("RTL8139: warning, sys_outb failed: %d\n", s);
00214 }
00215 static void my_outw(U16_t port, U16_t value) {
00216         int s;
00217         if ((s=sys_outw(port, value)) !=OK)
00218                 printf("RTL8139: warning, sys_outw failed: %d\n", s);
00219 }
00220 static void my_outl(U16_t port, U32_t value) {
00221         int s;
00222         if ((s=sys_outl(port, value)) !=OK)
00223                 printf("RTL8139: warning, sys_outl failed: %d\n", s);
00224 }
00225 #define rl_outb(port, offset, value)    (my_outb((port) + (offset), (value)))
00226 #define rl_outw(port, offset, value)    (my_outw((port) + (offset), (value)))
00227 #define rl_outl(port, offset, value)    (my_outl((port) + (offset), (value)))
00228 
00229 _PROTOTYPE( static void sig_handler, (void)                             );
00230 _PROTOTYPE( static void rl_init, (message *mp)                          );
00231 _PROTOTYPE( static void rl_pci_conf, (void)                             );
00232 _PROTOTYPE( static int rl_probe, (re_t *rep)                            );
00233 _PROTOTYPE( static void rl_conf_hw, (re_t *rep)                         );
00234 _PROTOTYPE( static void rl_init_buf, (re_t *rep)                                );
00235 _PROTOTYPE( static void rl_init_hw, (re_t *rep)                         );
00236 _PROTOTYPE( static void rl_reset_hw, (re_t *rep)                        );
00237 _PROTOTYPE( static void rl_confaddr, (re_t *rep)                        );
00238 _PROTOTYPE( static void rl_rec_mode, (re_t *rep)                        );
00239 _PROTOTYPE( static void rl_readv, (message *mp, int from_int, 
00240                                                         int vectored)   );
00241 _PROTOTYPE( static void rl_writev, (message *mp, int from_int,
00242                                                         int vectored)   );
00243 _PROTOTYPE( static void rl_check_ints, (re_t *rep)                      );
00244 _PROTOTYPE( static void rl_report_link, (re_t *rep)                     );
00245 _PROTOTYPE( static void mii_print_techab, (U16_t techab)                );
00246 _PROTOTYPE( static void mii_print_stat_speed, (U16_t stat,
00247                                                         U16_t extstat)  );
00248 _PROTOTYPE( static void rl_clear_rx, (re_t *rep)                        );
00249 _PROTOTYPE( static void rl_do_reset, (re_t *rep)                        );
00250 _PROTOTYPE( static void rl_getstat, (message *mp)                       );
00251 _PROTOTYPE( static void rl_getname, (message *mp)                       );
00252 _PROTOTYPE( static void reply, (re_t *rep, int err, int may_block)      );
00253 _PROTOTYPE( static void mess_reply, (message *req, message *reply)      );
00254 _PROTOTYPE( static void put_userdata, (int user_proc,
00255                 vir_bytes user_addr, vir_bytes count, void *loc_addr)   );
00256 _PROTOTYPE( static void rtl8139_stop, (void)                            );
00257 _PROTOTYPE( static void check_int_events, (void)                                );
00258 _PROTOTYPE( static int do_hard_int, (void)                              );
00259 _PROTOTYPE( static void rtl8139_dump, (message *m)                              );
00260 #if 0
00261 _PROTOTYPE( static void dump_phy, (re_t *rep)                           );
00262 #endif
00263 _PROTOTYPE( static int rl_handler, (re_t *rep)                  );
00264 _PROTOTYPE( static void rl_watchdog_f, (timer_t *tp)                    );
00265 
00266 /* The message used in the main loop is made global, so that rl_watchdog_f()
00267  * can change its message type to fake a HARD_INT message.
00268  */
00269 PRIVATE message m;
00270 PRIVATE int int_event_check;            /* set to TRUE if events arrived */
00271 
00272 static char *progname;
00273 extern int errno;
00274 
00275 /*===========================================================================*
00276  *                              main                                 *
00277  *===========================================================================*/
00278 int main(int argc, char *argv[])
00279 {
00280         int fkeys, sfkeys;
00281         int inet_proc_nr;
00282         int i, r;
00283         re_t *rep;
00284         long v;
00285 
00286         env_setargs(argc, argv);
00287 
00288         v= 0;
00289         (void) env_parse("ETH_IGN_PROTO", "x", 0, &v, 0x0000L, 0xFFFFL);
00290         eth_ign_proto= htons((u16_t) v);
00291 
00292         /* Observe some function key for debug dumps. */
00293         fkeys = sfkeys = 0; bit_set(sfkeys, 9);
00294         if ((r=fkey_map(&fkeys, &sfkeys)) != OK) 
00295             printf("Warning: RTL8139 couldn't observe Shift+F9 key: %d\n",r);
00296 
00297         /* Claim buffer memory now under Minix, before MM takes it all. */
00298         for (rep= &re_table[0]; rep < re_table+RE_PORT_NR; rep++)
00299                 rl_init_buf(rep);
00300 
00301         /* Try to notify INET that we are present (again). If INET cannot
00302          * be found, assume this is the first time we started and INET is
00303          * not yet alive.
00304          */
00305         (progname=strrchr(argv[0],'/')) ? progname++ : (progname=argv[0]);
00306         r = _pm_findproc("inet", &inet_proc_nr);
00307         if (r == OK) notify(inet_proc_nr);
00308 
00309 
00310         while (TRUE)
00311         {
00312                 if ((r= receive(ANY, &m)) != OK)
00313                         panic("rtl8139","receive failed", r);
00314 
00315                 switch (m.m_type)
00316                 {
00317                 case DEV_PING: notify(m.m_source);              continue;
00318                 case DL_WRITEV: rl_writev(&m, FALSE, TRUE);     break;
00319                 case DL_WRITE:  rl_writev(&m, FALSE, FALSE);    break;
00320 #if 0
00321                 case DL_READ:   do_vread(&m, FALSE);            break;
00322 #endif
00323                 case DL_READV:  rl_readv(&m, FALSE, TRUE);      break;
00324                 case DL_INIT:   rl_init(&m);                    break;
00325                 case DL_GETSTAT: rl_getstat(&m);                break;
00326                 case DL_GETNAME: rl_getname(&m);                break;
00327 #if 0
00328                 case DL_STOP:   do_stop(&m);                    break;
00329 #endif
00330                 case SYN_ALARM:
00331                         /* Under MINIX, synchronous alarms are used instead of
00332                          * watchdog functions. The approach is very different:
00333                          * MINIX VMD timeouts are handled within the kernel 
00334                          * (the watchdog is executed by CLOCK), and notify()
00335                          * the driver in some cases.
00336                          * MINIX timeouts result in a SYN_ALARM message to the
00337                          * driver and thus are handled where they should be
00338                          * handled. Locally, watchdog functions are used again. 
00339                          */
00340                         rl_watchdog_f(NULL);     
00341                         break;           
00342                 case HARD_INT:
00343                         do_hard_int();
00344                         if (int_event_check)
00345                                 check_int_events();
00346                         break ;
00347                 case FKEY_PRESSED: rtl8139_dump(&m);            break;
00348                 case PROC_EVENT:
00349                         sig_handler();
00350                         break;
00351                 default:
00352                         panic("rtl8139","illegal message", m.m_type);
00353                 }
00354         }
00355 }
00356 
00357 /*===========================================================================*
00358  *                              sig_handler                                  *
00359  *===========================================================================*/
00360 PRIVATE void sig_handler()
00361 {
00362   sigset_t sigset;
00363   int sig;
00364 
00365   /* Try to obtain signal set from PM. */
00366   if (getsigset(&sigset) != 0) return;
00367 
00368   /* Check for known signals. */
00369   if (sigismember(&sigset, SIGTERM)) {
00370       rtl8139_stop();
00371   }
00372 }
00373 
00374 /*===========================================================================*
00375  *                              check_int_events                             *
00376  *===========================================================================*/
00377 static void check_int_events(void) 
00378 {
00379   int i;
00380   re_t *rep;
00381                         for (i= 0, rep= &re_table[0]; i<RE_PORT_NR; i++, rep++)
00382                         {
00383                                 if (rep->re_mode != REM_ENABLED)
00384                                         continue;
00385                                 if (!rep->re_got_int)
00386                                         continue;
00387                                 rep->re_got_int= 0;
00388                                 assert(rep->re_flags & REF_ENABLED);
00389                                 rl_check_ints(rep);
00390                         }
00391 }
00392 
00393 /*===========================================================================*
00394  *                              rtl8139_stop                                 *
00395  *===========================================================================*/
00396 static void rtl8139_stop()
00397 {
00398         int i;
00399         re_t *rep;
00400 
00401         for (i= 0, rep= &re_table[0]; i<RE_PORT_NR; i++, rep++)
00402         {
00403                 if (rep->re_mode != REM_ENABLED)
00404                         continue;
00405                 rl_outb(rep->re_base_port, RL_CR, 0);
00406         }
00407         sys_exit(0);
00408 }
00409 
00410 /*===========================================================================*
00411  *                              rtl8139_dump                                 *
00412  *===========================================================================*/
00413 static void rtl8139_dump(m)
00414 message *m;                     /* pointer to request message */
00415 {
00416         re_t *rep;
00417         int i;
00418 
00419         printf("\n");
00420         for (i= 0, rep = &re_table[0]; i<RE_PORT_NR; i++, rep++)
00421         {
00422                 if (rep->re_mode == REM_DISABLED)
00423                         printf("Realtek RTL 8139 port %d is disabled\n", i);
00424 
00425                 if (rep->re_mode != REM_ENABLED)
00426                         continue;
00427 
00428                 printf("Realtek RTL 8139 statistics of port %d:\n", i);
00429 
00430                 printf("recvErr    :%8ld\t", rep->re_stat.ets_recvErr);
00431                 printf("sendErr    :%8ld\t", rep->re_stat.ets_sendErr);
00432                 printf("OVW        :%8ld\n", rep->re_stat.ets_OVW);
00433 
00434                 printf("CRCerr     :%8ld\t", rep->re_stat.ets_CRCerr);
00435                 printf("frameAll   :%8ld\t", rep->re_stat.ets_frameAll);
00436                 printf("missedP    :%8ld\n", rep->re_stat.ets_missedP);
00437 
00438                 printf("packetR    :%8ld\t", rep->re_stat.ets_packetR);
00439                 printf("packetT    :%8ld\t", rep->re_stat.ets_packetT);
00440                 printf("transDef   :%8ld\n", rep->re_stat.ets_transDef);
00441 
00442                 printf("collision  :%8ld\t", rep->re_stat.ets_collision);
00443                 printf("transAb    :%8ld\t", rep->re_stat.ets_transAb);
00444                 printf("carrSense  :%8ld\n", rep->re_stat.ets_carrSense);
00445 
00446                 printf("fifoUnder  :%8ld\t", rep->re_stat.ets_fifoUnder);
00447                 printf("fifoOver   :%8ld\t", rep->re_stat.ets_fifoOver);
00448                 printf("CDheartbeat:%8ld\n", rep->re_stat.ets_CDheartbeat);
00449 
00450                 printf("OWC        :%8ld\t", rep->re_stat.ets_OWC);
00451 
00452                 printf("re_flags = 0x%x\n", rep->re_flags);
00453 
00454                 printf(
00455         "TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
00456                         rl_inw(rep->re_base_port, RL_TSAD),
00457                         rl_inl(rep->re_base_port, RL_TSD0+0*4),
00458                         rl_inl(rep->re_base_port, RL_TSD0+1*4),
00459                         rl_inl(rep->re_base_port, RL_TSD0+2*4),
00460                         rl_inl(rep->re_base_port, RL_TSD0+3*4));
00461                 printf("tx_head %d, tx_tail %d, busy: %d %d %d %d\n",
00462                         rep->re_tx_head, rep->re_tx_tail,
00463                         rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
00464                         rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
00465         }
00466 }
00467 
00468 /*===========================================================================*
00469  *                              do_init                                      *
00470  *===========================================================================*/
00471 static void rl_init(mp)
00472 message *mp;
00473 {
00474         static int first_time= 1;
00475 
00476         int port;
00477         re_t *rep;
00478         message reply_mess;
00479 
00480         if (first_time)
00481         {
00482                 first_time= 0;
00483                 rl_pci_conf(); /* Configure PCI devices. */
00484 
00485                 tmra_inittimer(&rl_watchdog);
00486                 /* Use a synchronous alarm instead of a watchdog timer. */
00487                 sys_setalarm(HZ, 0);
00488         }
00489 
00490         port = mp->DL_PORT;
00491         if (port < 0 || port >= RE_PORT_NR)
00492         {
00493                 reply_mess.m_type= DL_INIT_REPLY;
00494                 reply_mess.m3_i1= ENXIO;
00495                 mess_reply(mp, &reply_mess);
00496                 return;
00497         }
00498         rep= &re_table[port];
00499         if (rep->re_mode == REM_DISABLED)
00500         {
00501                 /* This is the default, try to (re)locate the device. */
00502                 rl_conf_hw(rep);
00503                 if (rep->re_mode == REM_DISABLED)
00504                 {
00505                         /* Probe failed, or the device is configured off. */
00506                         reply_mess.m_type= DL_INIT_REPLY;
00507                         reply_mess.m3_i1= ENXIO;
00508                         mess_reply(mp, &reply_mess);
00509                         return;
00510                 }
00511                 if (rep->re_mode == REM_ENABLED)
00512                         rl_init_hw(rep);
00513 #if VERBOSE     /* load silently ... can always check status later */
00514                 rl_report_link(rep);
00515 #endif
00516         }
00517 
00518         assert(rep->re_mode == REM_ENABLED);
00519         assert(rep->re_flags & REF_ENABLED);
00520 
00521         rep->re_flags &= ~(REF_PROMISC | REF_MULTI | REF_BROAD);
00522 
00523         if (mp->DL_MODE & DL_PROMISC_REQ)
00524                 rep->re_flags |= REF_PROMISC;
00525         if (mp->DL_MODE & DL_MULTI_REQ)
00526                 rep->re_flags |= REF_MULTI;
00527         if (mp->DL_MODE & DL_BROAD_REQ)
00528                 rep->re_flags |= REF_BROAD;
00529 
00530         rep->re_client = mp->m_source;
00531         rl_rec_mode(rep);
00532 
00533         reply_mess.m_type = DL_INIT_REPLY;
00534         reply_mess.m3_i1 = mp->DL_PORT;
00535         reply_mess.m3_i2 = RE_PORT_NR;
00536         *(ether_addr_t *) reply_mess.m3_ca1 = rep->re_address;
00537 
00538         mess_reply(mp, &reply_mess);
00539 }
00540 
00541 /*===========================================================================*
00542  *                              rl_pci_conf                                  *
00543  *===========================================================================*/
00544 static void rl_pci_conf()
00545 {
00546         int i, h;
00547         re_t *rep;
00548         static char envvar[] = RL_ENVVAR "#";
00549         static char envfmt[] = "*:d.d.d";
00550         static char val[128];
00551         long v;
00552 
00553         for (i= 0, rep= re_table; i<RE_PORT_NR; i++, rep++)
00554         {
00555                 strcpy(rep->re_name, "rtl8139#0");
00556                 rep->re_name[8] += i;
00557                 rep->re_seen= FALSE;
00558                 envvar[sizeof(RL_ENVVAR)-1]= '0'+i;
00559                 if (0 == env_get_param(envvar, val, sizeof(val)) && 
00560                                 ! env_prefix(envvar, "pci")) {
00561                         env_panic(envvar);
00562                 }
00563                 v= 0;
00564                 (void) env_parse(envvar, envfmt, 1, &v, 0, 255);
00565                 rep->re_pcibus= v;
00566                 v= 0;
00567                 (void) env_parse(envvar, envfmt, 2, &v, 0, 255);
00568                 rep->re_pcidev= v;
00569                 v= 0;
00570                 (void) env_parse(envvar, envfmt, 3, &v, 0, 255);
00571                 rep->re_pcifunc= v;
00572         }
00573 
00574         pci_init();
00575 
00576         for (h= 1; h >= 0; h--) {
00577                 for (i= 0, rep= re_table; i<RE_PORT_NR; i++, rep++)
00578                 {
00579                         if (((rep->re_pcibus | rep->re_pcidev |
00580                                 rep->re_pcifunc) != 0) != h)
00581                         {
00582                                 continue;
00583                         }
00584                         if (rl_probe(rep))
00585                                 rep->re_seen= TRUE;
00586                 }
00587         }
00588 }
00589 
00590 /*===========================================================================*
00591  *                              rl_probe                                     *
00592  *===========================================================================*/
00593 static int rl_probe(rep)
00594 re_t *rep;
00595 {
00596         int i, r, devind, just_one;
00597         u16_t vid, did;
00598         u32_t bar;
00599         u8_t ilr;
00600         char *dname;
00601 
00602         if ((rep->re_pcibus | rep->re_pcidev | rep->re_pcifunc) != 0)
00603         {
00604                 /* Look for specific PCI device */
00605                 r= pci_find_dev(rep->re_pcibus, rep->re_pcidev,
00606                         rep->re_pcifunc, &devind);
00607                 if (r == 0)
00608                 {
00609                         printf("%s: no PCI found at %d.%d.%d\n",
00610                                 rep->re_name, rep->re_pcibus,
00611                                 rep->re_pcidev, rep->re_pcifunc);
00612                         return 0;
00613                 }
00614                 pci_ids(devind, &vid, &did);
00615                 just_one= TRUE;
00616         }
00617         else
00618         {
00619                 r= pci_first_dev(&devind, &vid, &did);
00620                 if (r == 0)
00621                         return 0;
00622                 just_one= FALSE;
00623         }
00624 
00625         for(;;)
00626         {
00627                 for (i= 0; pcitab[i].vid != 0; i++)
00628                 {
00629                         if (pcitab[i].vid != vid)
00630                                 continue;
00631                         if (pcitab[i].did != did)
00632                                 continue;
00633                         if (pcitab[i].checkclass)
00634                         {
00635                           panic("rtl_probe",
00636                             "class check not implemented", NO_NUM);
00637                         }
00638                         break;
00639                 }
00640                 if (pcitab[i].vid != 0)
00641                         break;
00642 
00643                 if (just_one)
00644                 {
00645                         printf(
00646                 "%s: wrong PCI device (%04x/%04x) found at %d.%d.%d\n",
00647                                 rep->re_name, vid, did,
00648                                 rep->re_pcibus,
00649                                 rep->re_pcidev, rep->re_pcifunc);
00650                         return 0;
00651                 }
00652 
00653                 r= pci_next_dev(&devind, &vid, &did);
00654                 if (!r)
00655                         return 0;
00656         }
00657 
00658 #if VERBOSE     /* stay silent at startup, can always get status later */
00659         dname= pci_dev_name(vid, did);
00660         if (!dname)
00661                 dname= "unknown device";
00662         printf("%s: ", rep->re_name);
00663         printf("%s (%x/%x) at %s\n", dname, vid, did, pci_slot_name(devind));
00664 #endif
00665         pci_reserve(devind);
00666         /* printf("cr = 0x%x\n", pci_attr_r16(devind, PCI_CR)); */
00667         bar= pci_attr_r32(devind, PCI_BAR) & 0xffffffe0;
00668         if (bar < 0x400)
00669         {
00670                 panic("rtl_probe",
00671                         "base address is not properly configured", NO_NUM);
00672         }
00673         rep->re_base_port= bar;
00674 
00675         ilr= pci_attr_r8(devind, PCI_ILR);
00676         rep->re_irq= ilr;
00677         if (debug)
00678         {
00679                 printf("%s: using I/O address 0x%lx, IRQ %d\n",
00680                         rep->re_name, (unsigned long)bar, ilr);
00681         }
00682 
00683         return TRUE;
00684 }
00685 
00686 /*===========================================================================*
00687  *                              rl_conf_hw                                   *
00688  *===========================================================================*/
00689 static void rl_conf_hw(rep)
00690 re_t *rep;
00691 {
00692         static eth_stat_t empty_stat = {0, 0, 0, 0, 0, 0        /* ,... */ };
00693 
00694         rep->re_mode= REM_DISABLED;     /* Superfluous */
00695 
00696         if (rep->re_seen)
00697         {
00698                 /* PCI device is present */
00699                 rep->re_mode= REM_ENABLED;
00700         }
00701         if (rep->re_mode != REM_ENABLED)
00702                 return;
00703 
00704         rep->re_flags= REF_EMPTY;
00705         rep->re_link_up= -1;    /* Unknown */
00706         rep->re_got_int= 0;
00707         rep->re_send_int= 0;
00708         rep->re_report_link= 0;
00709         rep->re_clear_rx= 0;
00710         rep->re_need_reset= 0;
00711         rep->re_tx_alive= 0;
00712         rep->re_read_s= 0;
00713         rep->re_tx_head= 0;
00714         rep->re_tx_tail= 0;
00715         rep->re_ertxth= RL_TSD_ERTXTH_8;
00716         rep->re_stat= empty_stat;
00717 }
00718 
00719 /*===========================================================================*
00720  *                              rl_init_buf                                  *
00721  *===========================================================================*/
00722 static void rl_init_buf(rep)
00723 re_t *rep;
00724 {
00725         size_t rx_bufsize, tx_bufsize, tot_bufsize;
00726         phys_bytes buf;
00727         char *mallocbuf;
00728         static struct memory chunk;
00729         int fd, s, i, off;
00730 
00731         /* Allocate receive and transmit buffers */
00732         tx_bufsize= ETH_MAX_PACK_SIZE_TAGGED;
00733         if (tx_bufsize % 4)
00734                 tx_bufsize += 4-(tx_bufsize % 4);       /* Align */
00735         rx_bufsize= RX_BUFSIZE;
00736         tot_bufsize= N_TX_BUF*tx_bufsize + rx_bufsize;
00737 
00738         /* Now try to allocate a kernel memory buffer. */
00739         chunk.size = tot_bufsize;
00740 
00741 #define BUF_ALIGNMENT (64*1024)
00742 
00743         if(!(mallocbuf = malloc(BUF_ALIGNMENT + tot_bufsize))) {
00744             panic("RTL8139","Couldn't allocate kernel buffer",i);
00745         }
00746 
00747         if(OK != (i = sys_umap(SELF, D, (vir_bytes) mallocbuf, tot_bufsize, &buf))) {
00748             panic("RTL8139","Couldn't re-map malloced buffer",i);
00749         }
00750 
00751         /* click-align mallocced buffer. this is what we used to get
00752          * from kmalloc() too.
00753          */
00754         if((off = buf % BUF_ALIGNMENT)) {
00755                 mallocbuf += BUF_ALIGNMENT - off;
00756                 buf += BUF_ALIGNMENT - off;
00757         }
00758 
00759         for (i= 0; i<N_TX_BUF; i++)
00760         {
00761                 rep->re_tx[i].ret_buf= buf;
00762                 rep->re_tx[i].v_ret_buf= mallocbuf;
00763                 buf += tx_bufsize;
00764                 mallocbuf += tx_bufsize;
00765         }
00766         rep->re_rx_buf= buf;
00767         rep->v_re_rx_buf= mallocbuf;
00768 }
00769 
00770 /*===========================================================================*
00771  *                              rl_init_hw                                   *
00772  *===========================================================================*/
00773 static void rl_init_hw(rep)
00774 re_t *rep;
00775 {
00776         int s, i;
00777 
00778         rep->re_flags = REF_EMPTY;
00779         rep->re_flags |= REF_ENABLED;
00780 
00781         /* Set the interrupt handler. The policy is to only send HARD_INT 
00782          * notifications. Don't reenable interrupts automatically. The id
00783          * that is passed back is the interrupt line number.
00784          */
00785         rep->re_hook_id = rep->re_irq;  
00786         if ((s=sys_irqsetpolicy(rep->re_irq, 0, &rep->re_hook_id)) != OK)
00787                 printf("RTL8139: error, couldn't set IRQ policy: %d\n", s);
00788 
00789         rl_reset_hw(rep);
00790 
00791         if ((s=sys_irqenable(&rep->re_hook_id)) != OK)
00792                 printf("RTL8139: error, couldn't enable interrupts: %d\n", s);
00793 
00794 #if VERBOSE     /* stay silent during startup, can always get status later */
00795         if (rep->re_model) {
00796                 printf("%s: model %s\n", rep->re_name, rep->re_model);
00797         } else
00798         {
00799                 printf("%s: unknown model 0x%08x\n",
00800                         rep->re_name,
00801                         rl_inl(rep->re_base_port, RL_TCR) &
00802                         (RL_TCR_HWVER_AM | RL_TCR_HWVER_BM));
00803         }
00804 #endif
00805 
00806         rl_confaddr(rep);
00807         if (debug)
00808         {
00809                 printf("%s: Ethernet address ", rep->re_name);
00810                 for (i= 0; i < 6; i++)
00811                 {
00812                         printf("%x%c", rep->re_address.ea_addr[i],
00813                                 i < 5 ? ':' : '\n');
00814                 }
00815         }
00816 }
00817 
00818 /*===========================================================================*
00819  *                              rl_reset_hw                                  *
00820  *===========================================================================*/
00821 static void rl_reset_hw(rep)
00822 re_t *rep;
00823 {
00824         port_t port;
00825         u32_t t;
00826         phys_bytes bus_buf;
00827         int i;
00828         clock_t t0,t1;
00829 
00830         port= rep->re_base_port;
00831 
00832 #if 0
00833         /* Reset the PHY */
00834         rl_outb(port, RL_BMCR, MII_CTRL_RST);
00835         getuptime(&t0);
00836         do {
00837                 if (!(rl_inb(port, RL_BMCR) & MII_CTRL_RST))
00838                         break;
00839         } while (getuptime(&t1)==OK && (t1-t0) < HZ);
00840         if (rl_inb(port, RL_BMCR) & MII_CTRL_RST)
00841                 panic("rtl8139","reset PHY failed to complete", NO_NUM);
00842 #endif
00843 
00844         /* Reset the device */
00845         printf("rl_reset_hw: (before reset) port = 0x%x, RL_CR = 0x%x\n",
00846                 port, rl_inb(port, RL_CR));
00847         rl_outb(port, RL_CR, RL_CR_RST);
00848         getuptime(&t0);
00849         do {
00850                 if (!(rl_inb(port, RL_CR) & RL_CR_RST))
00851                         break;
00852         } while (getuptime(&t1)==OK && (t1-t0) < HZ);
00853         printf("rl_reset_hw: (after reset) port = 0x%x, RL_CR = 0x%x\n",
00854                 port, rl_inb(port, RL_CR));
00855         if (rl_inb(port, RL_CR) & RL_CR_RST)
00856                 printf("rtl8139: reset failed to complete");
00857 
00858         t= rl_inl(port, RL_TCR);
00859         switch(t & (RL_TCR_HWVER_AM | RL_TCR_HWVER_BM))
00860         {
00861         case RL_TCR_HWVER_RTL8139: rep->re_model= "RTL8139"; break;
00862         case RL_TCR_HWVER_RTL8139A: rep->re_model= "RTL8139A"; break;
00863         case RL_TCR_HWVER_RTL8139AG:
00864                 rep->re_model= "RTL8139A-G / RTL8139C";
00865                 break;
00866         case RL_TCR_HWVER_RTL8139B:
00867                 rep->re_model= "RTL8139B / RTL8130";
00868                 break;
00869         case RL_TCR_HWVER_RTL8100: rep->re_model= "RTL8100"; break;
00870         case RL_TCR_HWVER_RTL8100B:
00871                 rep->re_model= "RTL8100B/RTL8139D";
00872                 break;
00873         case RL_TCR_HWVER_RTL8139CP: rep->re_model= "RTL8139C+"; break;
00874         case RL_TCR_HWVER_RTL8101: rep->re_model= "RTL8101"; break;
00875         default:
00876                 rep->re_model= NULL;
00877                 break;
00878         }
00879 
00880 #if 0
00881         printf("REVID: 0x%02x\n", rl_inb(port, RL_REVID));
00882 #endif
00883 
00884         /* Intialize Rx */
00885 
00886         /* Should init multicast mask */
00887 #if 0
00888 08-0f   R/W     MAR[0-7]        multicast
00889 #endif
00890         bus_buf= vm_1phys2bus(rep->re_rx_buf);
00891         rl_outl(port, RL_RBSTART, bus_buf);
00892 
00893         /* Initialize Tx */ 
00894         for (i= 0; i<N_TX_BUF; i++)
00895         {
00896                 rep->re_tx[i].ret_busy= FALSE;
00897                 bus_buf= vm_1phys2bus(rep->re_tx[i].ret_buf);
00898                 rl_outl(port, RL_TSAD0+i*4, bus_buf);
00899                 t= rl_inl(port, RL_TSD0+i*4);
00900                 assert(t & RL_TSD_OWN);
00901         }
00902 
00903 #if 0
00904         dump_phy(rep);
00905 #endif
00906 
00907         t= rl_inw(port, RL_IMR);
00908         rl_outw(port, RL_IMR, t | (RL_IMR_SERR | RL_IMR_TIMEOUT |
00909                 RL_IMR_LENCHG));
00910 
00911         t= rl_inw(port, RL_IMR);
00912         rl_outw(port, RL_IMR, t | (RL_IMR_FOVW | RL_IMR_PUN |
00913                 RL_IMR_RXOVW | RL_IMR_RER | RL_IMR_ROK));
00914 
00915         t= rl_inw(port, RL_IMR);
00916         rl_outw(port, RL_IMR, t | (RL_IMR_TER | RL_IMR_TOK));
00917 
00918         t= rl_inb(port, RL_CR);
00919         rl_outb(port, RL_CR, t | RL_CR_RE);
00920 
00921         t= rl_inb(port, RL_CR);
00922         rl_outb(port, RL_CR, t | RL_CR_TE);
00923 
00924         rl_outl(port, RL_RCR, RX_BUFBITS);
00925 
00926         t= rl_inl(port, RL_TCR);
00927         rl_outl(port, RL_TCR, t | RL_TCR_IFG_STD);
00928 }
00929 
00930 /*===========================================================================*
00931  *                              rl_confaddr                                  *
00932  *===========================================================================*/
00933 static void rl_confaddr(rep)
00934 re_t *rep;
00935 {
00936         static char eakey[]= RL_ENVVAR "#_EA";
00937         static char eafmt[]= "x:x:x:x:x:x";
00938 
00939         int i;
00940         port_t port;
00941         u32_t w;
00942         long v;
00943 
00944         /* User defined ethernet address? */
00945         eakey[sizeof(RL_ENVVAR)-1]= '0' + (rep-re_table);
00946 
00947         port= rep->re_base_port;
00948 
00949         for (i= 0; i < 6; i++)
00950         {
00951                 if (env_parse(eakey, eafmt, i, &v, 0x00L, 0xFFL) != EP_SET)
00952                         break;
00953                 rep->re_address.ea_addr[i]= v;
00954         }
00955 
00956         if (i != 0 && i != 6) env_panic(eakey); /* It's all or nothing */
00957 
00958         /* Should update ethernet address in hardware */
00959         if (i == 6)
00960         {
00961                 port= rep->re_base_port;
00962                 rl_outb(port, RL_9346CR, RL_9346CR_EEM_CONFIG);
00963                 w= 0;
00964                 for (i= 0; i<4; i++)
00965                         w |= (rep->re_address.ea_addr[i] << (i*8));
00966                 rl_outl(port, RL_IDR, w);
00967                 w= 0;
00968                 for (i= 4; i<6; i++)
00969                         w |= (rep->re_address.ea_addr[i] << ((i-4)*8));
00970                 rl_outl(port, RL_IDR+4, w);
00971                 rl_outb(port, RL_9346CR, RL_9346CR_EEM_NORMAL);
00972         }
00973 
00974         /* Get ethernet address */
00975         for (i= 0; i<6; i++)
00976                 rep->re_address.ea_addr[i]= rl_inb(port, RL_IDR+i);
00977 }
00978 
00979 /*===========================================================================*
00980  *                              rl_rec_mode                                  *
00981  *===========================================================================*/
00982 static void rl_rec_mode(rep)
00983 re_t *rep;
00984 {
00985         port_t port;
00986         u32_t rcr;
00987 
00988         port= rep->re_base_port;
00989         rcr= rl_inl(port, RL_RCR);
00990         rcr &= ~(RL_RCR_AB|RL_RCR_AM|RL_RCR_APM|RL_RCR_AAP);
00991         if (rep->re_flags & REF_PROMISC)
00992                 rcr |= RL_RCR_AB | RL_RCR_AM | RL_RCR_AAP;
00993         if (rep->re_flags & REF_BROAD)
00994                 rcr |= RL_RCR_AB;
00995         if (rep->re_flags & REF_MULTI)
00996                 rcr |= RL_RCR_AM;
00997         rcr |= RL_RCR_APM;
00998 
00999         rl_outl(port, RL_RCR, rcr);
01000 }
01001 
01002 /*===========================================================================*
01003  *                              rl_readv                                     *
01004  *===========================================================================*/
01005 static void rl_readv(mp, from_int, vectored)
01006 message *mp;
01007 int from_int;
01008 int vectored;
01009 {
01010         int i, j, n, o, s, s1, dl_port, re_client, count, size;
01011         port_t port;
01012         unsigned amount, totlen, packlen;
01013         phys_bytes src_phys, dst_phys, iov_src;
01014         u16_t d_start, d_end;
01015         u32_t l, rxstat = 0x12345678;
01016         re_t *rep;
01017         iovec_t *iovp;
01018         int cps;
01019 
01020         dl_port = mp->DL_PORT;
01021         count = mp->DL_COUNT;
01022         if (dl_port < 0 || dl_port >= RE_PORT_NR)
01023                 panic("rtl8139"," illegal port", dl_port);
01024         rep= &re_table[dl_port];
01025         re_client= mp->DL_PROC;
01026         rep->re_client= re_client;
01027 
01028         if (rep->re_clear_rx)
01029                 goto suspend;   /* Buffer overflow */
01030 
01031         assert(rep->re_mode == REM_ENABLED);
01032         assert(rep->re_flags & REF_ENABLED);
01033 
01034         port= rep->re_base_port;
01035 
01036         /* Assume that the RL_CR_BUFE check was been done by rl_checks_ints
01037          */
01038         if (!from_int && (rl_inb(port, RL_CR) & RL_CR_BUFE))
01039         {
01040                 /* Receive buffer is empty, suspend */
01041                 goto suspend;
01042         }
01043 
01044         d_start= rl_inw(port, RL_CAPR) + RL_CAPR_DATA_OFF;
01045         d_end= rl_inw(port, RL_CBR) % RX_BUFSIZE;
01046 
01047         if (d_start >= RX_BUFSIZE)
01048         {
01049                 printf("rl_readv: strange value in RL_CAPR: 0x%x\n",
01050                         rl_inw(port, RL_CAPR));
01051                 d_start %= RX_BUFSIZE;
01052         }
01053 
01054         if (d_end > d_start)
01055                 amount= d_end-d_start;
01056         else
01057                 amount= d_end+RX_BUFSIZE - d_start;
01058 
01059         rxstat = *(u32_t *) (rep->v_re_rx_buf + d_start);
01060 
01061 #if DEAD_CODE
01062         src_phys= rep->re_rx_buf + d_start;
01063         cps = sys_physcopy(
01064                 NONE, PHYS_SEG, src_phys,
01065                 SELF, D, (vir_bytes) &rxstat, sizeof(rxstat));
01066         if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
01067 #endif
01068 
01069         if (rep->re_clear_rx)
01070         {
01071 #if 0
01072                 printf("rl_readv: late buffer overflow\n");
01073 #endif
01074                 goto suspend;   /* Buffer overflow */
01075         }
01076 
01077         /* Should convert from little endian to host byte order */
01078 
01079         if (!(rxstat & RL_RXS_ROK))
01080         {
01081                 printf("rxstat = 0x%08lx\n", rxstat);
01082                 printf("d_start: 0x%x, d_end: 0x%x, rxstat: 0x%lx\n",
01083                         d_start, d_end, rxstat);
01084                 panic("rtl8139","received packet not OK", NO_NUM);
01085         }
01086         totlen= (rxstat >> RL_RXS_LEN_S);
01087         if (totlen < 8 || totlen > 2*ETH_MAX_PACK_SIZE)
01088         {
01089                 /* Someting went wrong */
01090                 printf(
01091                 "rl_readv: bad length (%u) in status 0x%08lx at offset 0x%x\n",
01092                         totlen, rxstat, d_start);
01093                 printf(
01094                 "d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%lx\n",
01095                         d_start, d_end, totlen, rxstat);
01096                 panic(NULL, NULL, NO_NUM);
01097         }
01098 
01099 #if 0
01100         printf("d_start: 0x%x, d_end: 0x%x, totlen: %d, rxstat: 0x%x\n",
01101                 d_start, d_end, totlen, rxstat);
01102 #endif
01103 
01104         if (totlen+4 > amount)
01105         {
01106                 printf("rl_readv: packet not yet ready\n");
01107                 goto suspend;
01108         }
01109 
01110         /* Should subtract the CRC */
01111         packlen= totlen - ETH_CRC_SIZE;
01112 
01113         if (vectored)
01114         {
01115                 int iov_offset = 0;
01116 #if 0
01117                 if ((cps = sys_umap(re_client, D, (vir_bytes) mp->DL_ADDR,
01118                         count * sizeof(rep->re_iovec[0]), &iov_src)) != OK)
01119                         printf("sys_umap failed: %d\n", cps);
01120 #endif
01121 
01122                 size= 0;
01123                 o= d_start+4;
01124                 src_phys= rep->re_rx_buf;
01125                 for (i= 0; i<count; i += IOVEC_NR,
01126                         iov_src += IOVEC_NR * sizeof(rep->re_iovec[0]),
01127                         iov_offset += IOVEC_NR * sizeof(rep->re_iovec[0]))
01128                 {
01129                         n= IOVEC_NR;
01130                         if (i+n > count)
01131                                 n= count-i;
01132 #if 0
01133                         cps = sys_physcopy(NONE, PHYS_SEG, iov_src, SELF, D, (vir_bytes) rep->re_iovec, 
01134                                 n * sizeof(rep->re_iovec[0]));
01135         if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
01136 #else
01137                         cps = sys_vircopy(re_client, D, (vir_bytes) mp->DL_ADDR + iov_offset,
01138                                 SELF, D, (vir_bytes) rep->re_iovec, n * sizeof(rep->re_iovec[0]));
01139         if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d (%d)\n", cps, __LINE__);
01140 #endif
01141 
01142                         for (j= 0, iovp= rep->re_iovec; j<n; j++, iovp++)
01143                         {
01144                                 s= iovp->iov_size;
01145                                 if (size + s > packlen)
01146                                 {
01147                                         assert(packlen > size);
01148                                         s= packlen-size;
01149                                 }
01150 
01151 #if 0
01152                                 if (sys_umap(re_client, D, iovp->iov_addr, s, &dst_phys) != OK)
01153                                   panic("rtl8139","umap_local failed\n", NO_NUM);
01154 #endif
01155 
01156                                 if (o >= RX_BUFSIZE)
01157                                 {
01158                                         o -= RX_BUFSIZE;
01159                                         assert(o < RX_BUFSIZE);
01160                                 }
01161 
01162                                 if (o+s > RX_BUFSIZE)
01163                                 {
01164                                         assert(o<RX_BUFSIZE);
01165                                         s1= RX_BUFSIZE-o;
01166 
01167 #if 0
01168                                         cps = sys_abscopy(src_phys+o, dst_phys, s1);
01169         if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
01170                                         cps = sys_abscopy(src_phys, dst_phys+s1, s-s1);
01171         if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
01172 #else
01173                                         cps = sys_vircopy(SELF, D, (vir_bytes) rep->v_re_rx_buf+o,
01174                                         re_client, D, iovp->iov_addr, s1);
01175         if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d (%d)\n", cps, __LINE__);
01176                                         cps = sys_vircopy(SELF, D, (vir_bytes) rep->v_re_rx_buf,
01177                                         re_client, D, iovp->iov_addr+s1, s-s1);
01178         if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d (%d)\n", cps, __LINE__);
01179 #endif
01180                                 }
01181                                 else
01182                                 {
01183 #if 0
01184                                         cps = sys_abscopy(src_phys+o, dst_phys, s);
01185         if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
01186 #else
01187                                         cps = sys_vircopy(SELF, D, (vir_bytes) rep->v_re_rx_buf+o,
01188                                         re_client, D, iovp->iov_addr, s);
01189         if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d (%d)\n", cps, __LINE__);
01190 #endif
01191                                 }
01192 
01193                                 size += s;
01194                                 if (size == packlen)
01195                                         break;
01196                                 o += s;
01197                         }
01198                         if (size == packlen)
01199                                 break;
01200                 }
01201                 if (size < packlen)
01202                 {
01203                         assert(0);
01204                 }
01205         }
01206         else
01207         {  
01208                 assert(0);
01209 #if 0
01210                 size= mp->DL_COUNT;
01211                 if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE_TAGGED)
01212                         panic("rtl8139","invalid packet size", size);
01213                 if (OK != sys_umap(re_client, D, (vir_bytes)mp->DL_ADDR, size, &phys_user))
01214                         panic("rtl8139","umap_local failed", NO_NUM);
01215 
01216                 p= rep->re_tx[tx_head].ret_buf;
01217                 cps = sys_abscopy(phys_user, p, size);
01218                 if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
01219 #endif
01220                 }
01221 
01222                 if (rep->re_clear_rx)
01223                 {
01224                         /* For some reason the receiver FIFO is not stopped when
01225                          * the buffer is full.
01226                          */
01227         #if 0
01228                         printf("rl_readv: later buffer overflow\n");
01229         #endif
01230                         goto suspend;   /* Buffer overflow */
01231                 }
01232 
01233                 rep->re_stat.ets_packetR++;
01234                 rep->re_read_s= packlen;
01235                 rep->re_flags= (rep->re_flags & ~REF_READING) | REF_PACK_RECV;
01236 
01237                 /* Avoid overflow in 16-bit computations */
01238                 l= d_start;
01239                 l += totlen+4;
01240                 l= (l+3) & ~3;  /* align */
01241                 if (l >= RX_BUFSIZE)
01242                 {
01243                         l -= RX_BUFSIZE;
01244                         assert(l < RX_BUFSIZE);
01245                 }
01246                 rl_outw(port, RL_CAPR, l-RL_CAPR_DATA_OFF);
01247 
01248                 if (!from_int)
01249                         reply(rep, OK, FALSE);
01250 
01251                 return;
01252 
01253         suspend:
01254                 if (from_int)
01255                 {
01256                         assert(rep->re_flags & REF_READING);
01257 
01258                         /* No need to store any state */
01259                         return;
01260                 }
01261 
01262                 rep->re_rx_mess= *mp;
01263                 assert(!(rep->re_flags & REF_READING));
01264                 rep->re_flags |= REF_READING;
01265 
01266                 reply(rep, OK, FALSE);
01267         }
01268 
01269         /*===========================================================================*
01270          *                              rl_writev                                    *
01271          *===========================================================================*/
01272         static void rl_writev(mp, from_int, vectored)
01273         message *mp;
01274         int from_int;
01275         int vectored;
01276         {
01277                 phys_bytes p, iov_src, phys_user;
01278                 int i, j, n, s, port, count, size;
01279                 int tx_head, re_client;
01280                 re_t *rep;
01281                 iovec_t *iovp;
01282                 char *ret;
01283                 int cps;
01284 
01285                 port = mp->DL_PORT;
01286                 count = mp->DL_COUNT;
01287                 if (port < 0 || port >= RE_PORT_NR)
01288                         panic("rtl8139","illegal port", port);
01289                 rep= &re_table[port];
01290                 re_client= mp->DL_PROC;
01291                 rep->re_client= re_client;
01292 
01293                 assert(rep->re_mode == REM_ENABLED);
01294                 assert(rep->re_flags & REF_ENABLED);
01295 
01296                 if (from_int)
01297                 {
01298                         assert(rep->re_flags & REF_SEND_AVAIL);
01299                         rep->re_flags &= ~REF_SEND_AVAIL;
01300                         rep->re_send_int= FALSE;
01301                         rep->re_tx_alive= TRUE;
01302                 }
01303 
01304                 tx_head= rep->re_tx_head;
01305                 if (rep->re_tx[tx_head].ret_busy)
01306                 {
01307                         assert(!(rep->re_flags & REF_SEND_AVAIL));
01308                         rep->re_flags |= REF_SEND_AVAIL;
01309                         if (rep->re_tx[tx_head].ret_busy)
01310                                 goto suspend;
01311 
01312                         /* Race condition, the interrupt handler may clear re_busy
01313                          * before we got a chance to set REF_SEND_AVAIL. Checking
01314                          * ret_busy twice should be sufficient.
01315                          */
01316         #if 0
01317                         printf("rl_writev: race detected\n");
01318         #endif
01319                         rep->re_flags &= ~REF_SEND_AVAIL;
01320                         rep->re_send_int= FALSE;
01321                 }
01322 
01323                 assert(!(rep->re_flags & REF_SEND_AVAIL));
01324                 assert(!(rep->re_flags & REF_PACK_SENT));
01325 
01326                 if (vectored)
01327                 {
01328                         int iov_offset = 0;
01329 
01330 #if 0
01331                         if (OK != sys_umap(re_client, D, (vir_bytes)mp->DL_ADDR,
01332                                 count * sizeof(rep->re_iovec[0]), &iov_src))
01333                                 panic("rtl8139","umap_local failed", NO_NUM);
01334 #endif
01335 
01336                         size= 0;
01337 #if 0
01338                         p= rep->re_tx[tx_head].ret_buf;
01339 #else
01340                         ret = rep->re_tx[tx_head].v_ret_buf;
01341 #endif
01342                         for (i= 0; i<count; i += IOVEC_NR,
01343                                 iov_src += IOVEC_NR * sizeof(rep->re_iovec[0]),
01344                                 iov_offset += IOVEC_NR * sizeof(rep->re_iovec[0]))
01345                         {
01346                                 n= IOVEC_NR;
01347                                 if (i+n > count)
01348                                         n= count-i;
01349 #if 0
01350                                 cps = sys_physcopy(NONE, PHYS_SEG, iov_src, SELF, D, (vir_bytes) rep->re_iovec, 
01351                                         n * sizeof(rep->re_iovec[0]));
01352                 if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
01353 #else
01354                                 cps = sys_vircopy(re_client, D, ((vir_bytes) mp->DL_ADDR) + iov_offset,
01355                                         SELF, D, (vir_bytes) rep->re_iovec, 
01356                                         n * sizeof(rep->re_iovec[0]));
01357         if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d\n", cps);
01358 #endif
01359 
01360                         for (j= 0, iovp= rep->re_iovec; j<n; j++, iovp++)
01361                         {
01362                                 s= iovp->iov_size;
01363                                 if (size + s > ETH_MAX_PACK_SIZE_TAGGED)
01364                                 {
01365                                   panic("rtl8139","invalid packet size",
01366                                     NO_NUM);
01367                                 }
01368 
01369                                 if (OK != sys_umap(re_client, D, iovp->iov_addr, s, &phys_user))
01370                                   panic("rtl8139","umap_local failed\n", NO_NUM);
01371 
01372 #if 0
01373                                 cps = sys_abscopy(phys_user, p, s);
01374         if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
01375 #else
01376                                 cps = sys_vircopy(re_client, D, iovp->iov_addr,
01377                                         SELF, D, (vir_bytes) ret, s);
01378                 if (cps != OK) printf("RTL8139: warning, sys_vircopy failed: %d\n", cps);
01379 #endif
01380                                 size += s;
01381 #if 0
01382                                 p += s;
01383 #endif
01384                                 ret += s;
01385                         }
01386                 }
01387                 if (size < ETH_MIN_PACK_SIZE)
01388                         panic("rtl8139","invalid packet size", size);
01389         }
01390         else
01391         {  
01392                 size= mp->DL_COUNT;
01393                 if (size < ETH_MIN_PACK_SIZE || size > ETH_MAX_PACK_SIZE_TAGGED)
01394                         panic("rtl8139","invalid packet size", size);
01395 #if 0
01396                 if (OK != sys_umap(re_client, D, (vir_bytes)mp->DL_ADDR, size, &phys_user))
01397                         panic("rtl8139","umap_local failed\n", NO_NUM);
01398 
01399                 p= rep->re_tx[tx_head].ret_buf;
01400                 cps = sys_abscopy(phys_user, p, size);
01401         if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
01402 #else
01403                 ret = rep->re_tx[tx_head].v_ret_buf;
01404                 cps = sys_vircopy(re_client, D, (vir_bytes)mp->DL_ADDR, 
01405                         SELF, D, (vir_bytes) ret, size);
01406         if (cps != OK) printf("RTL8139: warning, sys_abscopy failed: %d\n", cps);
01407 #endif
01408         }
01409 
01410         rl_outl(rep->re_base_port, RL_TSD0+tx_head*4, 
01411                 rep->re_ertxth | size);
01412         rep->re_tx[tx_head].ret_busy= TRUE;
01413 
01414         if (++tx_head == N_TX_BUF)
01415                 tx_head= 0;
01416         assert(tx_head < RL_N_TX);
01417         rep->re_tx_head= tx_head;
01418 
01419         rep->re_flags |= REF_PACK_SENT;
01420 
01421         /* If the interrupt handler called, don't send a reply. The reply
01422          * will be sent after all interrupts are handled. 
01423          */
01424         if (from_int)
01425                 return;
01426         reply(rep, OK, FALSE);
01427         return;
01428 
01429 suspend:
01430 #if 0
01431                 printf("rl_writev: head %d, tail %d, busy: %d %d %d %d\n",
01432                         tx_head, rep->re_tx_tail,
01433                         rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
01434                         rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
01435                 printf("rl_writev: TSD: 0x%x, 0x%x, 0x%x, 0x%x\n",
01436                         rl_inl(rep->re_base_port, RL_TSD0+0*4),
01437                         rl_inl(rep->re_base_port, RL_TSD0+1*4),
01438                         rl_inl(rep->re_base_port, RL_TSD0+2*4),
01439                         rl_inl(rep->re_base_port, RL_TSD0+3*4));
01440 #endif
01441 
01442         if (from_int)
01443                 panic("rtl8139","should not be sending\n", NO_NUM);
01444 
01445         rep->re_tx_mess= *mp;
01446         reply(rep, OK, FALSE);
01447 }
01448 
01449 /*===========================================================================*
01450  *                              rl_check_ints                                *
01451  *===========================================================================*/
01452 static void rl_check_ints(rep)
01453 re_t *rep;
01454 {
01455 #if 0
01456 10-1f   R/W     TSD[0-3]        Transmit Status of Descriptor [0-3]
01457         31      R       CRS     Carrier Sense Lost
01458         30      R       TABT    Transmit Abort
01459         29      R       OWC     Out of Window Collision
01460         27-24   R       NCC[3-0] Number of Collision Count
01461         23-22                   reserved
01462         21-16   R/W     ERTXH[5-0] Early Tx Threshold
01463         15      R       TOK     Transmit OK
01464         14      R       TUN     Transmit FIFO Underrun
01465         13      R/W     OWN     OWN
01466         12-0    R/W     SIZE    Descriptor Size
01467 3e-3f   R/W     ISR             Interrupt Status Register
01468         6       R/W     FOVW    Fx FIFO Overflow Interrupt
01469         5       R/W     PUN/LinkChg Packet Underrun / Link Change Interrupt
01470         3       R/W     TER     Transmit Error Interrupt
01471         2       R/W     TOK     Transmit OK Interrupt
01472 3e-3f   R/W     ISR             Interrupt Status Register
01473         15      R/W     SERR    System Error Interrupt
01474         14      R/W     TimeOut Time Out Interrupt
01475         13      R/W     LenChg  Cable Length Change Interrupt
01476 3e-3f   R/W     ISR             Interrupt Status Register
01477         4       R/W     RXOVW   Rx Buffer Overflow Interrupt
01478         1       R/W     RER     Receive Error Interrupt
01479         0       R/W     ROK     Receive OK Interrupt
01480 4c-4f   R/W     MPC             Missed Packet Counter
01481 60-61   R       TSAD            Transmit Status of All Descriptors
01482         15-12   R       TOK[3-0] TOK bit of Descriptor [3-0]
01483         11-8    R       TUN[3-0] TUN bit of Descriptor [3-0]
01484         7-4     R       TABT[3-0] TABT bit of Descriptor [3-0]
01485         3-0     R       OWN[3-0] OWN bit of Descriptor [3-0]
01486 6c-6d   R       DIS             Disconnect Counter
01487         15-0    R       DCNT    Disconnect Counter
01488 6e-6f   R       FCSC            False Carrier Sense Counter
01489         15-0    R       FCSCNT  False Carrier event counter
01490 72-73   R       REC             RX_ER Counter
01491         15-0    R       RXERCNT Received packet counter
01492 #endif
01493 
01494         int re_flags;
01495 
01496         re_flags= rep->re_flags;
01497 
01498         if ((re_flags & REF_READING) &&
01499                 !(rl_inb(rep->re_base_port, RL_CR) & RL_CR_BUFE))
01500         {
01501                 if (rep->re_rx_mess.m_type == DL_READV)
01502                 {
01503                         rl_readv(&rep->re_rx_mess, TRUE /* from int */,
01504                                 TRUE /* vectored */);
01505                 }
01506                 else
01507                 {
01508                         assert(rep->re_rx_mess.m_type == DL_READ);
01509                         rl_readv(&rep->re_rx_mess, TRUE /* from int */,
01510                                 FALSE /* !vectored */);
01511                 }
01512         }
01513         if (rep->re_clear_rx)
01514                 rl_clear_rx(rep);
01515 
01516         if (rep->re_need_reset)
01517                 rl_do_reset(rep);
01518 
01519         if (rep->re_send_int)
01520         {
01521                 if (rep->re_tx_mess.m_type == DL_WRITEV)
01522                 {
01523                         rl_writev(&rep->re_tx_mess, TRUE /* from int */,
01524                                 TRUE /* vectored */);
01525                 }
01526                 else
01527                 {
01528                         assert(rep->re_tx_mess.m_type == DL_WRITE);
01529                         rl_writev(&rep->re_tx_mess, TRUE /* from int */,
01530                                 FALSE /* !vectored */);
01531                 }
01532         }
01533 
01534         if (rep->re_report_link)
01535                 rl_report_link(rep);
01536 
01537         if (rep->re_flags & (REF_PACK_SENT | REF_PACK_RECV))
01538                 reply(rep, OK, TRUE);
01539 }
01540 
01541 /*===========================================================================*
01542  *                              rl_report_link                               *
01543  *===========================================================================*/
01544 static void rl_report_link(rep)
01545 re_t *rep;
01546 {
01547         port_t port;
01548         u16_t mii_ctrl, mii_status, mii_ana, mii_anlpa, mii_ane, mii_extstat;
01549         u8_t msr;
01550         int f, link_up;
01551 
01552         rep->re_report_link= FALSE;
01553         port= rep->re_base_port;
01554         msr= rl_inb(port, RL_MSR);
01555         link_up= !(msr & RL_MSR_LINKB);
01556         rep->re_link_up= link_up;
01557         if (!link_up)
01558         {
01559                 printf("%s: link down\n", rep->re_name);
01560                 return;
01561         }
01562 
01563         mii_ctrl= rl_inw(port, RL_BMCR);
01564         mii_status= rl_inw(port, RL_BMSR);
01565         mii_ana= rl_inw(port, RL_ANAR);
01566         mii_anlpa= rl_inw(port, RL_ANLPAR);
01567         mii_ane= rl_inw(port, RL_ANER);
01568         mii_extstat= 0;
01569 
01570         if (mii_ctrl & (MII_CTRL_LB|MII_CTRL_PD|MII_CTRL_ISO))
01571         {
01572                 printf("%s: PHY: ", rep->re_name);
01573                 f= 1;
01574                 if (mii_ctrl & MII_CTRL_LB)
01575                 {
01576                         printf("loopback mode");
01577                         f= 0;
01578                 }
01579                 if (mii_ctrl & MII_CTRL_PD)
01580                 {
01581                         if (!f) printf(", ");
01582                         f= 0;
01583                         printf("powered down");
01584                 }
01585                 if (mii_ctrl & MII_CTRL_ISO)
01586                 {
01587                         if (!f) printf(", ");
01588                         f= 0;
01589                         printf("isolated");
01590                 }
01591                 printf("\n");
01592                 return;
01593         }
01594         if (!(mii_ctrl & MII_CTRL_ANE))
01595         {
01596                 printf("%s: manual config: ", rep->re_name);
01597                 switch(mii_ctrl & (MII_CTRL_SP_LSB|MII_CTRL_SP_MSB))
01598                 {
01599                 case MII_CTRL_SP_10:    printf("10 Mbps"); break;
01600                 case MII_CTRL_SP_100:   printf("100 Mbps"); break;
01601                 case MII_CTRL_SP_1000:  printf("1000 Mbps"); break;
01602                 case MII_CTRL_SP_RES:   printf("reserved speed"); break;
01603                 }
01604                 if (mii_ctrl & MII_CTRL_DM)
01605                         printf(", full duplex");
01606                 else
01607                         printf(", half duplex");
01608                 printf("\n");
01609                 return;
01610         }
01611 
01612         if (!debug) goto resspeed;
01613 
01614         printf("%s: ", rep->re_name);
01615         mii_print_stat_speed(mii_status, mii_extstat);
01616         printf("\n");
01617 
01618         if (!(mii_status & MII_STATUS_ANC))
01619                 printf("%s: auto-negotiation not complete\n", rep->re_name);
01620         if (mii_status & MII_STATUS_RF)
01621                 printf("%s: remote fault detected\n", rep->re_name);
01622         if (!(mii_status & MII_STATUS_ANA))
01623         {
01624                 printf("%s: local PHY has no auto-negotiation ability\n",
01625                         rep->re_name);
01626         }
01627         if (!(mii_status & MII_STATUS_LS))
01628                 printf("%s: link down\n", rep->re_name);
01629         if (mii_status & MII_STATUS_JD)
01630                 printf("%s: jabber condition detected\n", rep->re_name);
01631         if (!(mii_status & MII_STATUS_EC))
01632         {
01633                 printf("%s: no extended register set\n", rep->re_name);
01634                 goto resspeed;
01635         }
01636         if (!(mii_status & MII_STATUS_ANC))
01637                 goto resspeed;
01638 
01639         printf("%s: local cap.: ", rep->re_name);
01640         mii_print_techab(mii_ana);
01641         printf("\n");
01642 
01643         if (mii_ane & MII_ANE_PDF)
01644                 printf("%s: parallel detection fault\n", rep->re_name);
01645         if (!(mii_ane & MII_ANE_LPANA))
01646         {
01647                 printf("%s: link-partner does not support auto-negotiation\n",
01648                         rep->re_name);
01649                 goto resspeed;
01650         }
01651 
01652         printf("%s: remote cap.: ", rep->re_name);
01653         mii_print_techab(mii_anlpa);
01654         printf("\n");
01655 
01656 resspeed:
01657         printf("%s: ", rep->re_name);
01658         printf("link up at %d Mbps, ", (msr & RL_MSR_SPEED_10) ? 10 : 100);
01659         printf("%s duplex\n", ((mii_ctrl & MII_CTRL_DM) ? "full" : "half"));
01660 
01661 }
01662 
01663 static void mii_print_techab(techab)
01664 u16_t techab;
01665 {
01666         int fs, ft;
01667         if ((techab & MII_ANA_SEL_M) != MII_ANA_SEL_802_3)
01668         {
01669                 printf("strange selector 0x%x, value 0x%x",
01670                         techab & MII_ANA_SEL_M,
01671                         (techab & MII_ANA_TAF_M) >> MII_ANA_TAF_S);
01672                 return;
01673         }
01674         fs= 1;
01675         if (techab & (MII_ANA_100T4 | MII_ANA_100TXFD | MII_ANA_100TXHD))
01676         {
01677                 printf("100 Mbps: ");
01678                 fs= 0;
01679                 ft= 1;
01680                 if (techab & MII_ANA_100T4)
01681                 {
01682                         printf("T4");
01683                         ft= 0;
01684                 }
01685                 if (techab & (MII_ANA_100TXFD | MII_ANA_100TXHD))
01686                 {
01687                         if (!ft)
01688                                 printf(", ");
01689                         ft= 0;
01690                         printf("TX-");
01691                         switch(techab & (MII_ANA_100TXFD|MII_ANA_100TXHD))
01692                         {
01693                         case MII_ANA_100TXFD:   printf("FD"); break;
01694                         case MII_ANA_100TXHD:   printf("HD"); break;
01695                         default:                printf("FD/HD"); break;
01696                         }
01697                 }
01698         }
01699         if (techab & (MII_ANA_10TFD | MII_ANA_10THD))
01700         {
01701                 if (!fs)
01702                         printf(", ");
01703                 printf("10 Mbps: ");
01704                 fs= 0;
01705                 printf("T-");
01706                 switch(techab & (MII_ANA_10TFD|MII_ANA_10THD))
01707                 {
01708                 case MII_ANA_10TFD:     printf("FD"); break;
01709                 case MII_ANA_10THD:     printf("HD"); break;
01710                 default:                printf("FD/HD"); break;
01711                 }
01712         }
01713         if (techab & MII_ANA_PAUSE_SYM)
01714         {
01715                 if (!fs)
01716                         printf(", ");
01717                 fs= 0;
01718                 printf("pause(SYM)");
01719         }
01720         if (techab & MII_ANA_PAUSE_ASYM)
01721         {
01722                 if (!fs)
01723                         printf(", ");
01724                 fs= 0;
01725                 printf("pause(ASYM)");
01726         }
01727         if (techab & MII_ANA_TAF_RES)
01728         {
01729                 if (!fs)
01730                         printf(", ");
01731                 fs= 0;
01732                 printf("0x%x", (techab & MII_ANA_TAF_RES) >> MII_ANA_TAF_S);
01733         }
01734 }
01735 
01736 static void mii_print_stat_speed(stat, extstat)
01737 u16_t stat;
01738 u16_t extstat;
01739 {
01740         int fs, ft;
01741         fs= 1;
01742         if (stat & MII_STATUS_EXT_STAT)
01743         {
01744                 if (extstat & (MII_ESTAT_1000XFD | MII_ESTAT_1000XHD |
01745                         MII_ESTAT_1000TFD | MII_ESTAT_1000THD))
01746                 {
01747                         printf("1000 Mbps: ");
01748                         fs= 0;
01749                         ft= 1;
01750                         if (extstat & (MII_ESTAT_1000XFD | MII_ESTAT_1000XHD))
01751                         {
01752                                 ft= 0;
01753                                 printf("X-");
01754                                 switch(extstat &
01755                                         (MII_ESTAT_1000XFD|MII_ESTAT_1000XHD))
01756                                 {
01757                                 case MII_ESTAT_1000XFD: printf("FD"); break;
01758                                 case MII_ESTAT_1000XHD: printf("HD"); break;
01759                                 default:                printf("FD/HD"); break;
01760                                 }
01761                         }
01762                         if (extstat & (MII_ESTAT_1000TFD | MII_ESTAT_1000THD))
01763                         {
01764                                 if (!ft)
01765                                         printf(", ");
01766                                 ft= 0;
01767                                 printf("T-");
01768                                 switch(extstat &
01769                                         (MII_ESTAT_1000TFD|MII_ESTAT_1000THD))
01770                                 {
01771                                 case MII_ESTAT_1000TFD: printf("FD"); break;
01772                                 case MII_ESTAT_1000THD: printf("HD"); break;
01773                                 default:                printf("FD/HD"); break;
01774                                 }
01775                         }
01776                 }
01777         }
01778         if (stat & (MII_STATUS_100T4 |
01779                 MII_STATUS_100XFD | MII_STATUS_100XHD |
01780                 MII_STATUS_100T2FD | MII_STATUS_100T2HD))
01781         {
01782                 if (!fs)
01783                         printf(", ");
01784                 fs= 0;
01785                 printf("100 Mbps: ");
01786                 ft= 1;
01787                 if (stat & MII_STATUS_100T4)
01788                 {
01789                         printf("T4");
01790                         ft= 0;
01791                 }
01792                 if (stat & (MII_STATUS_100XFD | MII_STATUS_100XHD))
01793                 {
01794                         if (!ft)
01795                                 printf(", ");
01796                         ft= 0;
01797                         printf("TX-");
01798                         switch(stat & (MII_STATUS_100XFD|MII_STATUS_100XHD))
01799                         {
01800                         case MII_STATUS_100XFD: printf("FD"); break;
01801                         case MII_STATUS_100XHD: printf("HD"); break;
01802                         default:                printf("FD/HD"); break;
01803                         }
01804                 }
01805                 if (stat & (MII_STATUS_100T2FD | MII_STATUS_100T2HD))
01806                 {
01807                         if (!ft)
01808                                 printf(", ");
01809                         ft= 0;
01810                         printf("T2-");
01811                         switch(stat & (MII_STATUS_100T2FD|MII_STATUS_100T2HD))
01812                         {
01813                         case MII_STATUS_100T2FD:        printf("FD"); break;
01814                         case MII_STATUS_100T2HD:        printf("HD"); break;
01815                         default:                printf("FD/HD"); break;
01816                         }
01817                 }
01818         }
01819         if (stat & (MII_STATUS_10FD | MII_STATUS_10HD))
01820         {
01821                 if (!fs)
01822                         printf(", ");
01823                 printf("10 Mbps: ");
01824                 fs= 0;
01825                 printf("T-");
01826                 switch(stat & (MII_STATUS_10FD|MII_STATUS_10HD))
01827                 {
01828                 case MII_STATUS_10FD:   printf("FD"); break;
01829                 case MII_STATUS_10HD:   printf("HD"); break;
01830                 default:                printf("FD/HD"); break;
01831                 }
01832         }
01833 }
01834 
01835 /*===========================================================================*
01836  *                              rl_clear_rx                                  *
01837  *===========================================================================*/
01838 static void rl_clear_rx(rep)
01839 re_t *rep;
01840 {
01841         port_t port;
01842         u8_t cr;
01843         int i;
01844         clock_t t0,t1;
01845 
01846         rep->re_clear_rx= FALSE;
01847         port= rep->re_base_port;
01848 
01849         /* Reset the receiver */
01850         cr= rl_inb(port, RL_CR);
01851         cr &= ~RL_CR_RE;
01852         rl_outb(port, RL_CR, cr);
01853         getuptime(&t0);
01854         do {
01855                 if (!(rl_inb(port, RL_CR) & RL_CR_RE))
01856                         break;
01857         } while (getuptime(&t1)==OK && (t1-t0) < HZ);
01858         if (rl_inb(port, RL_CR) & RL_CR_RE)
01859                 panic("rtl8139","cannot disable receiver", NO_NUM);
01860 
01861 #if 0
01862         printf("RBSTART = 0x%08x\n", rl_inl(port, RL_RBSTART));
01863         printf("CAPR = 0x%04x\n", rl_inw(port, RL_CAPR));
01864         printf("CBR = 0x%04x\n", rl_inw(port, RL_CBR));
01865         printf("RCR = 0x%08x\n", rl_inl(port, RL_RCR));
01866 #endif
01867 
01868         rl_outb(port, RL_CR, cr | RL_CR_RE);
01869 
01870         rl_outl(port, RL_RCR, RX_BUFBITS);
01871 
01872         rl_rec_mode(rep);
01873 
01874         rep->re_stat.ets_missedP++;
01875 }
01876 
01877 /*===========================================================================*
01878  *                              rl_do_reset                                  *
01879  *===========================================================================*/
01880 static void rl_do_reset(rep)
01881 re_t *rep;
01882 {
01883         rep->re_need_reset= FALSE;
01884         rl_reset_hw(rep);
01885         rl_rec_mode(rep);
01886 
01887         rep->re_tx_head= 0;
01888         if (rep->re_flags & REF_SEND_AVAIL)
01889         {
01890                 rep->re_tx[rep->re_tx_head].ret_busy= FALSE;
01891                 rep->re_send_int= TRUE;
01892         }
01893 }
01894 
01895 /*===========================================================================*
01896  *                              rl_getstat                                   *
01897  *===========================================================================*/
01898 static void rl_getstat(mp)
01899 message *mp;
01900 {
01901         int port;
01902         eth_stat_t stats;
01903         re_t *rep;
01904 
01905         port = mp->DL_PORT;
01906         if (port < 0 || port >= RE_PORT_NR)
01907                 panic("rtl8139","illegal port", port);
01908         rep= &re_table[port];
01909         rep->re_client= mp->DL_PROC;
01910 
01911         assert(rep->re_mode == REM_ENABLED);
01912         assert(rep->re_flags & REF_ENABLED);
01913 
01914         stats= rep->re_stat;
01915 
01916         put_userdata(mp->DL_PROC, (vir_bytes) mp->DL_ADDR,
01917                 (vir_bytes) sizeof(stats), &stats);
01918         reply(rep, OK, FALSE);
01919 }
01920 
01921 
01922 /*===========================================================================*
01923  *                              rl_getname                                   *
01924  *===========================================================================*/
01925 static void rl_getname(mp)
01926 message *mp;
01927 {
01928         int r;
01929 
01930         strncpy(mp->DL_NAME, progname, sizeof(mp->DL_NAME));
01931         mp->DL_NAME[sizeof(mp->DL_NAME)-1]= '\0';
01932         mp->m_type= DL_NAME_REPLY;
01933         r= send(mp->m_source, mp);
01934         if (r != OK)
01935                 panic("RTL8139", "rl_getname: send failed: %d\n", r);
01936 }
01937 
01938 
01939 /*===========================================================================*
01940  *                              reply                                        *
01941  *===========================================================================*/
01942 static void reply(rep, err, may_block)
01943 re_t *rep;
01944 int err;
01945 int may_block;
01946 {
01947         message reply;
01948         int status;
01949         int r;
01950         clock_t now;
01951 
01952         status = 0;
01953         if (rep->re_flags & REF_PACK_SENT)
01954                 status |= DL_PACK_SEND;
01955         if (rep->re_flags & REF_PACK_RECV)
01956                 status |= DL_PACK_RECV;
01957 
01958         reply.m_type = DL_TASK_REPLY;
01959         reply.DL_PORT = rep - re_table;
01960         reply.DL_PROC = rep->re_client;
01961         reply.DL_STAT = status | ((u32_t) err << 16);
01962         reply.DL_COUNT = rep->re_read_s;
01963         if (OK != (r = getuptime(&now)))
01964                 panic("rtl8139","getuptime() failed:", r);
01965         reply.DL_CLCK = now;
01966 
01967         r= send(rep->re_client, &reply);
01968 
01969         if (r == ELOCKED && may_block)
01970         {
01971 #if 0
01972                 printW(); printf("send locked\n");
01973 #endif
01974                 return;
01975         }
01976 
01977         if (r < 0) {
01978                 printf("RTL8139 tried sending to %d, type %d\n", rep->re_client, reply.m_type);
01979                 panic("rtl8139","send failed:", r);
01980         }
01981         
01982         rep->re_read_s = 0;
01983         rep->re_flags &= ~(REF_PACK_SENT | REF_PACK_RECV);
01984 }
01985 
01986 /*===========================================================================*
01987  *                              mess_reply                                   *
01988  *===========================================================================*/
01989 static void mess_reply(req, reply_mess)
01990 message *req;
01991 message *reply_mess;
01992 {
01993         if (send(req->m_source, reply_mess) != OK)
01994                 panic("rtl8139","unable to mess_reply", NO_NUM);
01995 }
01996 
01997 /*===========================================================================*
01998  *                              put_userdata                                 *
01999  *===========================================================================*/
02000 static void put_userdata(user_proc, user_addr, count, loc_addr)
02001 int user_proc;
02002 vir_bytes user_addr;
02003 vir_bytes count;
02004 void *loc_addr;
02005 {
02006         int cps;
02007         cps = sys_datacopy(SELF, (vir_bytes) loc_addr, user_proc, user_addr, count);
02008         if (cps != OK) printf("RTL8139: warning, scopy failed: %d\n", cps);
02009 }
02010 
02011 #if 0
02012 static void dump_phy(rep)
02013 re_t *rep;
02014 {
02015         port_t port;
02016         u32_t t;
02017 
02018         port= rep->re_base_port;
02019 
02020         t= rl_inb(port, RL_MSR);
02021         printf("MSR: 0x%02lx\n", t);
02022         if (t & RL_MSR_SPEED_10)
02023                 printf("\t10 Mbps\n");
02024         if (t & RL_MSR_LINKB)
02025                 printf("\tLink failed\n");
02026 
02027         t= rl_inb(port, RL_CONFIG1);
02028         printf("CONFIG1: 0x%02lx\n", t);
02029 
02030         t= rl_inb(port, RL_CONFIG3);
02031         printf("CONFIG3: 0x%02lx\n", t);
02032 
02033         t= rl_inb(port, RL_CONFIG4);
02034         printf("CONFIG4: 0x%02lx\n", t);
02035 
02036         t= rl_inw(port, RL_BMCR);
02037         printf("BMCR (MII_CTRL): 0x%04lx\n", t);
02038 
02039         t= rl_inw(port, RL_BMSR);
02040         printf("BMSR:");
02041         if (t & MII_STATUS_100T4)
02042                 printf(" 100Base-T4");
02043         if (t & MII_STATUS_100XFD)
02044                 printf(" 100Base-X-FD");
02045         if (t & MII_STATUS_100XHD)
02046                 printf(" 100Base-X-HD");
02047         if (t & MII_STATUS_10FD)
02048                 printf(" 10Mbps-FD");
02049         if (t & MII_STATUS_10HD)
02050                 printf(" 10Mbps-HD");
02051         if (t & MII_STATUS_100T2FD)
02052                 printf(" 100Base-T2-FD");
02053         if (t & MII_STATUS_100T2HD)
02054                 printf(" 100Base-T2-HD");
02055         if (t & MII_STATUS_EXT_STAT)
02056                 printf(" Ext-stat");
02057         if (t & MII_STATUS_RES)
02058                 printf(" res-0x%lx", t & MII_STATUS_RES);
02059         if (t & MII_STATUS_MFPS)
02060                 printf(" MFPS");
02061         if (t & MII_STATUS_ANC)
02062                 printf(" ANC");
02063         if (t & MII_STATUS_RF)
02064                 printf(" remote-fault");
02065         if (t & MII_STATUS_ANA)
02066                 printf(" ANA");
02067         if (t & MII_STATUS_LS)
02068                 printf(" Link");
02069         if (t & MII_STATUS_JD)
02070                 printf(" Jabber");
02071         if (t & MII_STATUS_EC)
02072                 printf(" Extended-capability");
02073         printf("\n");
02074 
02075         t= rl_inw(port, RL_ANAR);
02076         printf("ANAR (MII_ANA): 0x%04lx\n", t);
02077 
02078         t= rl_inw(port, RL_ANLPAR);
02079         printf("ANLPAR: 0x%04lx\n", t);
02080 
02081         t= rl_inw(port, RL_ANER);
02082         printf("ANER (MII_ANE): ");
02083         if (t & MII_ANE_RES)
02084                 printf(" res-0x%lx", t & MII_ANE_RES);
02085         if (t & MII_ANE_PDF)
02086                 printf(" Par-Detect-Fault");
02087         if (t & MII_ANE_LPNPA)
02088                 printf(" LP-Next-Page-Able");
02089         if (t & MII_ANE_NPA)
02090                 printf(" Loc-Next-Page-Able");
02091         if (t & MII_ANE_PR)
02092                 printf(" Page-Received");
02093         if (t & MII_ANE_LPANA)
02094                 printf(" LP-Auto-Neg-Able");
02095         printf("\n");
02096 
02097         t= rl_inw(port, RL_NWAYTR);
02098         printf("NWAYTR: 0x%04lx\n", t);
02099         t= rl_inw(port, RL_CSCR);
02100         printf("CSCR: 0x%04lx\n", t);
02101 
02102         t= rl_inb(port, RL_CONFIG5);
02103         printf("CONFIG5: 0x%02lx\n", t);
02104 }
02105 #endif
02106 
02107 static int do_hard_int(void)
02108 {
02109         int i,s;
02110 
02111         for (i=0; i < RE_PORT_NR; i ++) {
02112 
02113                 /* Run interrupt handler at driver level. */
02114                 rl_handler( &re_table[i]);
02115 
02116                 /* Reenable interrupts for this hook. */
02117         if ((s=sys_irqenable(&re_table[i].re_hook_id)) != OK)
02118                 printf("RTL8139: error, couldn't enable interrupts: %d\n", s);
02119         }
02120 }
02121 
02122 /*===========================================================================*
02123  *                              rl_handler                                   *
02124  *===========================================================================*/
02125 static int rl_handler(rep)
02126 re_t *rep;
02127 {
02128         int i, port, tx_head, tx_tail, link_up;
02129         u16_t isr, tsad;
02130         u32_t tsd, tcr, ertxth;
02131 #if 0
02132         u8_t cr;
02133 #endif
02134         clock_t t0,t1;
02135         int_event_check = FALSE;        /* disable check by default */
02136 
02137         port= rep->re_base_port;
02138 
02139         /* Ack interrupt */
02140         isr= rl_inw(port, RL_ISR);
02141         rl_outw(port, RL_ISR, isr);
02142 
02143         if (isr & RL_IMR_FOVW)
02144         {
02145                 isr &= ~RL_IMR_FOVW;
02146                 /* Should do anything? */
02147 
02148                 rep->re_stat.ets_fifoOver++;
02149         }
02150         if (isr & RL_IMR_PUN)
02151         {
02152                 isr &= ~RL_IMR_PUN;
02153 
02154                 /* Either the link status changed or there was a TX fifo
02155                  * underrun.
02156                  */
02157                 link_up= !(rl_inb(port, RL_MSR) & RL_MSR_LINKB);
02158                 if (link_up != rep->re_link_up)
02159                 {
02160                         rep->re_report_link= TRUE;
02161                         rep->re_got_int= TRUE;
02162                         int_event_check = TRUE;
02163                 }
02164         }
02165         if (isr & RL_IMR_RXOVW)
02166         {
02167                 isr &= ~RL_IMR_RXOVW;
02168 
02169                 /* Clear the receive buffer */
02170                 rep->re_clear_rx= TRUE;
02171                 rep->re_got_int= TRUE;
02172                 int_event_check = TRUE;
02173         }
02174 
02175         if (isr & (RL_ISR_RER | RL_ISR_ROK))
02176         {
02177                 isr &= ~(RL_ISR_RER | RL_ISR_ROK);
02178 
02179                 if (!rep->re_got_int && (rep->re_flags & REF_READING))
02180                 {
02181                         rep->re_got_int= TRUE;
02182                         int_event_check = TRUE;
02183                 }
02184         }
02185 #if 0
02186         if ((isr & (RL_ISR_TER | RL_ISR_TOK)) &&
02187                 (rep->re_flags & REF_SEND_AVAIL) &&
02188                 (rep->re_tx[0].ret_busy || rep->re_tx[1].ret_busy ||
02189                 rep->re_tx[2].ret_busy || rep->re_tx[3].ret_busy))
02190                 
02191         {
02192                 printf(
02193         "rl_handler, SEND_AVAIL: tx_head %d, tx_tail %d, busy: %d %d %d %d\n",
02194                         rep->re_tx_head, rep->re_tx_tail,
02195                         rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
02196                         rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
02197                 printf(
02198         "rl_handler: TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
02199                         rl_inw(port, RL_TSAD),
02200                         rl_inl(port, RL_TSD0+0*4),
02201                         rl_inl(port, RL_TSD0+1*4),
02202                         rl_inl(port, RL_TSD0+2*4),
02203                         rl_inl(port, RL_TSD0+3*4));
02204         }
02205 #endif
02206         if ((isr & (RL_ISR_TER | RL_ISR_TOK)) || 1)
02207         {
02208                 isr &= ~(RL_ISR_TER | RL_ISR_TOK);
02209 
02210                 tsad= rl_inw(port, RL_TSAD);
02211                 if (tsad & (RL_TSAD_TABT0|RL_TSAD_TABT1|
02212                         RL_TSAD_TABT2|RL_TSAD_TABT3))
02213                 {
02214 #if 0
02215                         /* Do we need a watch dog? */
02216                         /* Just reset the whole chip */
02217                         rep->re_need_reset= TRUE;
02218                         rep->re_got_int= TRUE;
02219                         int_event_check = TRUE;
02220 #elif 0
02221                         /* Reset transmitter */
02222                         rep->re_stat.ets_transAb++;
02223 
02224                         cr= rl_inb(port, RL_CR);
02225                         cr &= ~RL_CR_TE;
02226                         rl_outb(port, RL_CR, cr);
02227                         getuptime(&t0);
02228                         do {
02229                                 if (!(rl_inb(port, RL_CR) & RL_CR_TE))
02230                                         break;
02231                         } while (getuptime(&t1)==OK && (t1-t0) < HZ);
02232                         if (rl_inb(port, RL_CR) & RL_CR_TE)
02233                         {
02234                           panic("rtl8139","cannot disable transmitter",
02235                                         NO_NUM);
02236                         }
02237                         rl_outb(port, RL_CR, cr | RL_CR_TE);
02238 
02239                         tcr= rl_inl(port, RL_TCR);
02240                         rl_outl(port, RL_TCR, tcr | RL_TCR_IFG_STD);
02241 
02242                         printf("rl_handler: reset after abort\n");
02243 
02244                         if (rep->re_flags & REF_SEND_AVAIL)
02245                         {
02246                                 printf("rl_handler: REF_SEND_AVAIL\n");
02247                                 rep->re_send_int= TRUE;
02248                                 rep->re_got_int= TRUE;
02249                                 int_event_check = TRUE;
02250                         }
02251                         for (i= 0; i< N_TX_BUF; i++)
02252                                 rep->re_tx[i].ret_busy= FALSE;
02253                         rep->re_tx_head= 0;
02254 #else
02255                         printf("rl_handler, TABT, tasd = 0x%04x\n",
02256                                 tsad);
02257 
02258                         /* Find the aborted transmit request */
02259                         for (i= 0; i< N_TX_BUF; i++)
02260                         {
02261                                 tsd= rl_inl(port, RL_TSD0+i*4);
02262                                 if (tsd & RL_TSD_TABT)
02263                                         break;
02264                         }
02265                         if (i >= N_TX_BUF)
02266                         {
02267                                 printf(
02268                                 "rl_handler: can't find aborted TX req.\n");
02269                         }
02270                         else
02271                         {
02272                                 printf("TSD%d = 0x%04lx\n", i, tsd);
02273 
02274                                 /* Set head and tail to this buffer */
02275                                 rep->re_tx_head= rep->re_tx_tail= i;
02276                         }
02277 
02278                         /* Aborted transmission, just kick the device
02279                          * and be done with it.
02280                          */
02281                         rep->re_stat.ets_transAb++;
02282                         tcr= rl_inl(port, RL_TCR);
02283                         rl_outl(port, RL_TCR, tcr | RL_TCR_CLRABT);
02284 #endif
02285                 }
02286 
02287                 /* Transmit completed */
02288                 tx_head= rep->re_tx_head;
02289                 tx_tail= rep->re_tx_tail;
02290                 for (i= 0; i< 2*N_TX_BUF; i++)
02291                 {
02292                         if (!rep->re_tx[tx_tail].ret_busy)
02293                         {
02294                                 /* Strange, this buffer is not in-use.
02295                                  * Increment tx_tail until tx_head is
02296                                  * reached (or until we find a buffer that
02297                                  * is in-use.
02298                                  */
02299                                 if (tx_tail == tx_head)
02300                                         break;
02301                                 if (++tx_tail >= N_TX_BUF)
02302                                         tx_tail= 0;
02303                                 assert(tx_tail < RL_N_TX);
02304                                 rep->re_tx_tail= tx_tail;
02305                                 continue;
02306                         }
02307                         tsd= rl_inl(port, RL_TSD0+tx_tail*4);
02308                         if (!(tsd & RL_TSD_OWN))
02309                         {
02310                                 /* Buffer is not yet ready */
02311                                 break;
02312                         }
02313 
02314                         /* Should collect statistics */
02315                         if (tsd & RL_TSD_CRS)
02316                                 rep->re_stat.ets_carrSense++;
02317                         if (tsd & RL_TSD_TABT)
02318                         {
02319                                 printf("rl_handler, TABT, TSD%d = 0x%04lx\n",
02320                                         tx_tail, tsd);
02321                                 assert(0);      /* CLRABT is not all that
02322                                                  * effective, why not?
02323                                                  */
02324                                 rep->re_stat.ets_transAb++;
02325                                 tcr= rl_inl(port, RL_TCR);
02326                                 rl_outl(port, RL_TCR, tcr | RL_TCR_CLRABT);
02327                         }
02328                         if (tsd & RL_TSD_OWC)
02329                                 rep->re_stat.ets_OWC++;
02330                         if (tsd & RL_TSD_CDH)
02331                                 rep->re_stat.ets_CDheartbeat++;
02332 
02333                         /* What about collisions? */
02334                         if (tsd & RL_TSD_TOK)
02335                                 rep->re_stat.ets_packetT++;
02336                         else
02337                                 rep->re_stat.ets_sendErr++;
02338                         if (tsd & RL_TSD_TUN)
02339                         {
02340                                 rep->re_stat.ets_fifoUnder++;
02341 
02342                                 /* Increase ERTXTH */
02343                                 ertxth= tsd + (1 << RL_TSD_ERTXTH_S);
02344                                 ertxth &= RL_TSD_ERTXTH_M;
02345                                 if (debug && ertxth > rep->re_ertxth)
02346                                 {
02347                                         printf("%s: new ertxth: %ld bytes\n",
02348                                                 rep->re_name,
02349                                                 (ertxth >> RL_TSD_ERTXTH_S) *
02350                                                 32);
02351                                         rep->re_ertxth= ertxth;
02352                                 }
02353                         }
02354                         rep->re_tx[tx_tail].ret_busy= FALSE;
02355 
02356 #if 0
02357                         if (rep->re_flags & REF_SEND_AVAIL)
02358                         {
02359                         printf("TSD%d: %08lx\n", tx_tail, tsd);
02360                         printf(
02361                         "rl_handler: head %d, tail %d, busy: %d %d %d %d\n", 
02362                                 tx_head, tx_tail,
02363                                 rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy, 
02364                                 rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
02365                         }
02366 #endif
02367 
02368                         if (++tx_tail >= N_TX_BUF)
02369                                 tx_tail= 0;
02370                         assert(tx_tail < RL_N_TX);
02371                         rep->re_tx_tail= tx_tail;
02372 
02373                         if (rep->re_flags & REF_SEND_AVAIL)
02374                         {
02375 #if 0
02376                                 printf("rl_handler: REF_SEND_AVAIL\n");
02377 #endif
02378                                 rep->re_send_int= TRUE;
02379                                 if (!rep->re_got_int)
02380                                 {
02381                                         rep->re_got_int= TRUE;
02382                                         int_event_check = TRUE;
02383                                 }
02384                         }
02385                 }
02386                 assert(i < 2*N_TX_BUF);
02387         }
02388         if (isr)
02389         {
02390                 printf("rl_handler: unhandled interrupt: isr = 0x%04x\n",
02391                         isr);
02392         }
02393 
02394         return 1;
02395 }
02396 
02397 /*===========================================================================*
02398  *                              rl_watchdog_f                                *
02399  *===========================================================================*/
02400 static void rl_watchdog_f(tp)
02401 timer_t *tp;
02402 {
02403         int i;
02404         re_t *rep;
02405         /* Use a synchronous alarm instead of a watchdog timer. */
02406         sys_setalarm(HZ, 0);
02407 
02408         for (i= 0, rep = &re_table[0]; i<RE_PORT_NR; i++, rep++)
02409         {
02410                 if (rep->re_mode != REM_ENABLED)
02411                         continue;
02412                 if (!(rep->re_flags & REF_SEND_AVAIL))
02413                 {
02414                         /* Assume that an idle system is alive */
02415                         rep->re_tx_alive= TRUE;
02416                         continue;
02417                 }
02418                 if (rep->re_tx_alive)
02419                 {
02420                         rep->re_tx_alive= FALSE;
02421                         continue;
02422                 }
02423                 printf("rl_watchdog_f: resetting port %d\n", i);
02424                 printf(
02425         "TSAD: 0x%04x, TSD: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
02426                         rl_inw(rep->re_base_port, RL_TSAD),
02427                         rl_inl(rep->re_base_port, RL_TSD0+0*4),
02428                         rl_inl(rep->re_base_port, RL_TSD0+1*4),
02429                         rl_inl(rep->re_base_port, RL_TSD0+2*4),
02430                         rl_inl(rep->re_base_port, RL_TSD0+3*4));
02431                 printf("tx_head %d, tx_tail %d, busy: %d %d %d %d\n",
02432                         rep->re_tx_head, rep->re_tx_tail,
02433                         rep->re_tx[0].ret_busy, rep->re_tx[1].ret_busy,
02434                         rep->re_tx[2].ret_busy, rep->re_tx[3].ret_busy);
02435                 rep->re_need_reset= TRUE;
02436                 rep->re_got_int= TRUE;
02437                         
02438                 check_int_events();
02439         }
02440 }
02441 
02442 #if 0
02443 
02444 _PROTOTYPE( static void rtl_init, (struct dpeth *dep)                   );
02445 _PROTOTYPE( static u16_t get_ee_word, (dpeth_t *dep, int a)             );
02446 _PROTOTYPE( static void ee_wen, (dpeth_t *dep)                          );
02447 _PROTOTYPE( static void set_ee_word, (dpeth_t *dep, int a, U16_t w)     );
02448 _PROTOTYPE( static void ee_wds, (dpeth_t *dep)                          );
02449 
02450 static void rtl_init(dep)
02451 dpeth_t *dep;
02452 {
02453         u8_t reg_a, reg_b, cr, config0, config2, config3;
02454         int i;
02455         char val[128];
02456 
02457         printf("rtl_init called\n");
02458         ne_init(dep);
02459 
02460         /* ID */
02461         outb_reg0(dep, DP_CR, CR_PS_P0);
02462         reg_a = inb_reg0(dep, DP_DUM1);
02463         reg_b = inb_reg0(dep, DP_DUM2);
02464 
02465         printf("rtl_init: '%c', '%c'\n", reg_a, reg_b);
02466 
02467         outb_reg0(dep, DP_CR, CR_PS_P3);
02468         config0 = inb_reg3(dep, 3);
02469         config2 = inb_reg3(dep, 5);
02470         config3 = inb_reg3(dep, 6);
02471         outb_reg0(dep, DP_CR, CR_PS_P0);
02472 
02473         printf("rtl_init: config 0/2/3 = %x/%x/%x\n",
02474                 config0, config2, config3);
02475 
02476         if (0 == sys_getkenv("RTL8029FD",9+1, val, sizeof(val)))
02477         {
02478                 printf("rtl_init: setting full-duplex mode\n");
02479                 outb_reg0(dep, DP_CR, CR_PS_P3);
02480 
02481                 cr= inb_reg3(dep, 1);
02482                 outb_reg3(dep, 1, cr | 0xc0);
02483 
02484                 outb_reg3(dep, 6, config3 | 0x40);
02485                 config3 = inb_reg3(dep, 6);
02486 
02487                 config2= inb_reg3(dep, 5);
02488                 outb_reg3(dep, 5, config2 | 0x20);
02489                 config2= inb_reg3(dep, 5);
02490 
02491                 outb_reg3(dep, 1, cr);
02492 
02493                 outb_reg0(dep, DP_CR, CR_PS_P0);
02494 
02495                 printf("rtl_init: config 2 = %x\n", config2);
02496                 printf("rtl_init: config 3 = %x\n", config3);
02497         }
02498 
02499         for (i= 0; i<64; i++)
02500                 printf("%x ", get_ee_word(dep, i));
02501         printf("\n");
02502 
02503         if (0 == sys_getkenv("RTL8029MN",9+1, val, sizeof(val)))
02504         {
02505                 ee_wen(dep);
02506 
02507                 set_ee_word(dep, 0x78/2, 0x10ec);
02508                 set_ee_word(dep, 0x7A/2, 0x8029);
02509                 set_ee_word(dep, 0x7C/2, 0x10ec);
02510                 set_ee_word(dep, 0x7E/2, 0x8029);
02511 
02512                 ee_wds(dep);
02513 
02514                 assert(get_ee_word(dep, 0x78/2) == 0x10ec);
02515                 assert(get_ee_word(dep, 0x7A/2) == 0x8029);
02516                 assert(get_ee_word(dep, 0x7C/2) == 0x10ec);
02517                 assert(get_ee_word(dep, 0x7E/2) == 0x8029);
02518         }
02519 
02520         if (0 == sys_getkenv("RTL8029XXX",10+1, val, sizeof(val)))
02521         {
02522                 ee_wen(dep);
02523 
02524                 set_ee_word(dep, 0x76/2, 0x8029);
02525 
02526                 ee_wds(dep);
02527 
02528                 assert(get_ee_word(dep, 0x76/2) == 0x8029);
02529         }
02530 }
02531 
02532 static u16_t get_ee_word(dep, a)
02533 dpeth_t *dep;
02534 int a;
02535 {
02536         int b, i, cmd;
02537         u16_t w;
02538 
02539         outb_reg0(dep, DP_CR, CR_PS_P3);        /* Bank 3 */
02540 
02541         /* Switch to 9346 mode and enable CS */
02542         outb_reg3(dep, 1, 0x80 | 0x8);
02543 
02544         cmd= 0x180 | (a & 0x3f);        /* 1 1 0 a5 a4 a3 a2 a1 a0 */
02545         for (i= 8; i >= 0; i--)
02546         {
02547                 b= (cmd & (1 << i));
02548                 b= (b ? 2 : 0);
02549 
02550                 /* Cmd goes out on the rising edge of the clock */
02551                 outb_reg3(dep, 1, 0x80 | 0x8 | b);
02552                 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
02553         }
02554         outb_reg3(dep, 1, 0x80 | 0x8);  /* End of cmd */
02555 
02556         w= 0;
02557         for (i= 0; i<16; i++)
02558         {
02559                 w <<= 1;
02560 
02561                 /* Data is shifted out on the rising edge. Read at the
02562                  * falling edge.
02563                  */
02564                 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4);
02565                 outb_reg3(dep, 1, 0x80 | 0x8 | b);
02566                 b= inb_reg3(dep, 1);
02567                 w |= (b & 1);
02568         }
02569 
02570         outb_reg3(dep, 1, 0x80);                /* drop CS */
02571         outb_reg3(dep, 1, 0x00);                /* back to normal */
02572         outb_reg0(dep, DP_CR, CR_PS_P0);        /* back to bank 0 */
02573 
02574         return w;
02575 }
02576 
02577 static void ee_wen(dep)
02578 dpeth_t *dep;
02579 {
02580         int b, i, cmd;
02581         u16_t w;
02582 
02583         outb_reg0(dep, DP_CR, CR_PS_P3);        /* Bank 3 */
02584 
02585         /* Switch to 9346 mode and enable CS */
02586         outb_reg3(dep, 1, 0x80 | 0x8);
02587 
02588         cmd= 0x130;             /* 1 0 0 1 1 x x x x */
02589         for (i= 8; i >= 0; i--)
02590         {
02591                 b= (cmd & (1 << i));
02592                 b= (b ? 2 : 0);
02593 
02594                 /* Cmd goes out on the rising edge of the clock */
02595                 outb_reg3(dep, 1, 0x80 | 0x8 | b);
02596                 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
02597         }
02598         outb_reg3(dep, 1, 0x80 | 0x8);  /* End of cmd */
02599         outb_reg3(dep, 1, 0x80);        /* Drop CS */
02600         /* micro_delay(1); */                   /* Is this required? */
02601 }
02602 
02603 static void set_ee_word(dep, a, w)
02604 dpeth_t *dep;
02605 int a;
02606 u16_t w;
02607 {
02608         int b, i, cmd;
02609         clock_t t0, t1;
02610 
02611         outb_reg3(dep, 1, 0x80 | 0x8);          /* Set CS */
02612 
02613         cmd= 0x140 | (a & 0x3f);                /* 1 0 1 a5 a4 a3 a2 a1 a0 */
02614         for (i= 8; i >= 0; i--)
02615         {
02616                 b= (cmd & (1 << i));
02617                 b= (b ? 2 : 0);
02618 
02619                 /* Cmd goes out on the rising edge of the clock */
02620                 outb_reg3(dep, 1, 0x80 | 0x8 | b);
02621                 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
02622         }
02623         for (i= 15; i >= 0; i--)
02624         {
02625                 b= (w & (1 << i));
02626                 b= (b ? 2 : 0);
02627 
02628                 /* Cmd goes out on the rising edge of the clock */
02629                 outb_reg3(dep, 1, 0x80 | 0x8 | b);
02630                 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
02631         }
02632         outb_reg3(dep, 1, 0x80 | 0x8);  /* End of data */
02633         outb_reg3(dep, 1, 0x80);        /* Drop CS */
02634         /* micro_delay(1); */                   /* Is this required? */
02635         outb_reg3(dep, 1, 0x80 | 0x8);          /* Set CS */
02636         getuptime(&t0);
02637         do {
02638                 if (inb_reg3(dep, 1) & 1)
02639                         break;
02640         } while (getuptime(&t1) == OK && (t1 == t0));
02641         if (!(inb_reg3(dep, 1) & 1))
02642                 panic("set_ee_word","device remains busy", NO_NUM);
02643 }
02644 
02645 static void ee_wds(dep)
02646 dpeth_t *dep;
02647 {
02648         int b, i, cmd;
02649         u16_t w;
02650 
02651         outb_reg0(dep, DP_CR, CR_PS_P3);        /* Bank 3 */
02652 
02653         /* Switch to 9346 mode and enable CS */
02654         outb_reg3(dep, 1, 0x80 | 0x8);
02655 
02656         cmd= 0x100;             /* 1 0 0 0 0 x x x x */
02657         for (i= 8; i >= 0; i--)
02658         {
02659                 b= (cmd & (1 << i));
02660                 b= (b ? 2 : 0);
02661 
02662                 /* Cmd goes out on the rising edge of the clock */
02663                 outb_reg3(dep, 1, 0x80 | 0x8 | b);
02664                 outb_reg3(dep, 1, 0x80 | 0x8 | 0x4 | b);
02665         }
02666         outb_reg3(dep, 1, 0x80 | 0x8);  /* End of cmd */
02667         outb_reg3(dep, 1, 0x80);        /* Drop CS */
02668         outb_reg3(dep, 1, 0x00);                /* back to normal */
02669         outb_reg0(dep, DP_CR, CR_PS_P0);        /* back to bank 0 */
02670 }
02671 #endif
02672 
02673 /*
02674  * $PchId: rtl8139.c,v 1.3 2003/09/11 14:15:15 philip Exp $
02675  */

Generated on Fri Apr 14 22:57:18 2006 for minix by  doxygen 1.4.6