dm9000e.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2003-2005 by egnite Software GmbH. All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY EGNITE SOFTWARE GMBH AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL EGNITE
00021  * SOFTWARE GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  *
00032  */
00033 
00034 /*
00035  * $Log: dm9000e.c,v $
00036  * Revision 1.8  2007/08/17 11:43:46  haraldkipp
00037  * Enable multicast.
00038  *
00039  * Revision 1.7  2007/05/24 07:26:44  haraldkipp
00040  * Added some delay befor reading the status of the received packet. Fixes
00041  * bug #1672527, thanks to Andreas Helmcke.
00042  *
00043  * Revision 1.6  2007/05/02 11:22:51  haraldkipp
00044  * Added multicast table entry.
00045  *
00046  * Revision 1.5  2006/06/28 17:10:15  haraldkipp
00047  * Include more general header file for ARM.
00048  *
00049  * Revision 1.4  2006/03/16 19:04:48  haraldkipp
00050  * Adding a short delay before reading the status word makes it work with
00051  * compiler optimization. On receiver overflow interrupts the chip is
00052  * declared insane. The output routine will no more enter NutEventWait()
00053  * on insane chips.
00054  *
00055  * Revision 1.3  2006/03/02 19:51:16  haraldkipp
00056  * Replaced GCC specific inline specifications with their portable
00057  * counterparts.
00058  *
00059  * Revision 1.2  2006/01/23 17:33:14  haraldkipp
00060  * Possible memory alignment problem may start network interface too early.
00061  *
00062  * Revision 1.1  2005/10/24 08:49:05  haraldkipp
00063  * Initial check in.
00064  *
00065  */
00066 
00067 #include <cfg/os.h>
00068 #include <arch/arm.h>
00069 
00070 #include <string.h>
00071 
00072 #include <sys/atom.h>
00073 #include <sys/heap.h>
00074 #include <sys/thread.h>
00075 #include <sys/event.h>
00076 #include <sys/timer.h>
00077 #include <sys/confnet.h>
00078 
00079 #include <netinet/if_ether.h>
00080 #include <net/ether.h>
00081 #include <net/if_var.h>
00082 
00083 #include <dev/irqreg.h>
00084 #include <dev/dm9000e.h>
00085 
00086 #ifdef NUTDEBUG
00087 #include <stdio.h>
00088 #endif
00089 
00090 #ifndef NUT_THREAD_NICRXSTACK
00091 #define NUT_THREAD_NICRXSTACK   768
00092 #endif
00093 
00094 /*
00095  * Determine ports, which had not been explicitely configured.
00096  */
00097 #ifndef NIC_BASE_ADDR
00098 #define NIC_BASE_ADDR   0x20000000
00099 #endif
00100 
00101 #ifndef NIC_DATA_ADDR
00102 #define NIC_DATA_ADDR   (NIC_BASE_ADDR + 4)
00103 #endif
00104 
00105 #define INT0    0
00106 #define INT1    1
00107 #define INT2    2
00108 #define INT3    3
00109 #define INT4    4
00110 #define INT5    5
00111 #define INT6    6
00112 #define INT7    7
00113 
00114 #ifndef NIC_SIGNAL_IRQ
00115 #define NIC_SIGNAL_IRQ  INT1
00116 #endif
00117 
00118 #ifdef NIC_RESET_BIT
00119 
00120 #if (NIC_RESET_AVRPORT == AVRPORTB)
00121 #define NIC_RESET_PORT   PORTB
00122 #define NIC_RESET_DDR    DDRB
00123 
00124 #elif (NIC_RESET_AVRPORT == AVRPORTD)
00125 #define NIC_RESET_PORT   PORTD
00126 #define NIC_RESET_DDR    DDRD
00127 
00128 #elif (NIC_RESET_AVRPORT == AVRPORTE)
00129 #define NIC_RESET_PORT   PORTE
00130 #define NIC_RESET_DDR    DDRE
00131 
00132 #elif (NIC_RESET_AVRPORT == AVRPORTF)
00133 #define NIC_RESET_PORT   PORTF
00134 #define NIC_RESET_DDR    DDRF
00135 
00136 #endif                          /* NIC_RESET_AVRPORT */
00137 
00138 #endif                          /* NIC_RESET_BIT */
00139 
00140 /*
00141  * Determine interrupt settings.
00142  * DOES NOT WORK
00143  */
00144 #if (NIC_SIGNAL_IRQ == INT0)
00145 #define NIC_SIGNAL          sig_INTERRUPT0
00146 
00147 #elif (NIC_SIGNAL_IRQ == INT2)
00148 #define NIC_SIGNAL          sig_INTERRUPT2
00149 
00150 #elif (NIC_SIGNAL_IRQ == INT3)
00151 #define NIC_SIGNAL          sig_INTERRUPT3
00152 
00153 #elif (NIC_SIGNAL_IRQ == INT4)
00154 #define NIC_SIGNAL          sig_INTERRUPT4
00155 
00156 #elif (NIC_SIGNAL_IRQ == INT5)
00157 #define NIC_SIGNAL          sig_INTERRUPT5
00158 
00159 #elif (NIC_SIGNAL_IRQ == INT6)
00160 #define NIC_SIGNAL          sig_INTERRUPT6
00161 
00162 #elif (NIC_SIGNAL_IRQ == INT7)
00163 #define NIC_SIGNAL          sig_INTERRUPT7
00164 
00165 #else
00166 #define NIC_SIGNAL          sig_INTERRUPT1
00167 
00168 #endif
00169 
00174 
00175 #define NIC_NCR     0x00        /* Network control register (0x00). */
00176 #define NIC_NCR_LBM     0x06    /* Loopback mode. */
00177 #define NIC_NCR_LBNORM  0x00    /* Normal mode. */
00178 #define NIC_NCR_LBMAC   0x02    /* MAC loopback. */
00179 #define NIC_NCR_LBPHY   0x04    /* PHY loopback. */
00180 #define NIC_NCR_RST     0x01    /* Software reset, auto clear. */
00181 
00182 #define NIC_NSR     0x01        /* Network status register (0x00). */
00183 #define NIC_NSR_SPEED   0x80
00184 #define NIC_NSR_LINKST  0x40
00185 #define NIC_NSR_WAKEST  0x20
00186 #define NIC_NSR_TX2END  0x08
00187 #define NIC_NSR_TX1END  0x04
00188 #define NIC_NSR_RXOV    0x02
00189 
00190 #define NIC_TCR     0x02        /* TX control register (0x00). */
00191 #define NIC_TCR_TXREQ    0x01   /* TX request */
00192 
00193 #define NIC_TSR1    0x03        /* TX status register I (0x00). */
00194 
00195 #define NIC_TSR2    0x04        /* TX status register II (0x00). */
00196 
00197 #define NIC_RCR     0x05        /* RX control register (0x00). */
00198 #define NIC_RCR_DIS_LONG 0x20   /* Discard long packets. */
00199 #define NIC_RCR_DIS_CRC 0x10    /* Discard CRC error packets. */
00200 #define NIC_RCR_ALL     0x08    /* Pass all multicast */
00201 #define NIC_RCR_PRMSC   0x02    /* Enable promiscuous mode. */
00202 #define NIC_RCR_RXEN    0x01    /* Enable receiver. */
00203 
00204 #define NIC_RSR     0x06        /* RX status register (0x00). */
00205 #define NIC_RSR_ERRORS  0xBF    /* Error bit mask. */
00206 #define NIC_RSR_RF      0x80    /* Runt frame. */
00207 #define NIC_RSR_MF      0x40    /* Multicast frame. */
00208 #define NIC_RSR_LCS     0x20    /* Late collision. */
00209 #define NIC_RSR_RWTO    0x10    /* Receiver watchdog time out. */
00210 #define NIC_RSR_PLE     0x08    /* Physical layer error. */
00211 #define NIC_RSR_AE      0x04    /* Alignment error. */
00212 #define NIC_RSR_CE      0x02    /* CRC error. */
00213 #define NIC_RSR_FOE     0x01    /* FIFO overflow error. */
00214 
00215 #define NIC_ROCR    0x07        /* Receive overflow counter register (0x00). */
00216 
00217 #define NIC_BPTR    0x08        /* Back pressure threshold register (0x37). */
00218 
00219 #define NIC_FCTR    0x09        /* Flow control threshold register (0x38). */
00220 
00221 #define NIC_FCR     0x0A        /* RX flow control register (0x00). */
00222 
00223 #define NIC_EPCR    0x0B        /* EEPROM and PHY control register. */
00224 
00225 #define NIC_EPAR    0x0C        /* EEPROM and PHY address register. */
00226 
00227 #define NIC_EPDRL   0x0D        /* EEPROM and PHY low byte data register. */
00228 
00229 #define NIC_EPDRH   0x0E        /* EEPROM and PHY high byte data register. */
00230 
00231 #define NIC_WCR     0x0F        /* Wake up control register (0x00). */
00232 
00233 #define NIC_PAR     0x10        /* 6 byte physical address register. */
00234 
00235 #define NIC_MAR     0x16        /* 8 byte multicast address register. */
00236 
00237 #define NIC_GPCR    0x1E        /* General purpose control register (?). */
00238 
00239 #define NIC_GPR     0x1F        /* General purpose register (?). */
00240 
00241 #define NIC_TRPA    0x22        /* 2 byte TX SRAM read pointer address, low/high (0x0000). */
00242 
00243 #define NIC_RWPA    0x24        /* 2 byte RX SRAM write pointer address, low/high (0x0000). */
00244 
00245 #define NIC_VID     0x28        /* 2 byte vendor ID (0x0A46). */
00246 
00247 #define NIC_PID     0x2A        /* 2 byte product ID (0x0900). */
00248 
00249 #define NIC_CHIPR   0x2C        /* Chip revision (0x00). */
00250 
00251 #define NIC_SMCR    0x2F        /* Special mode register (0x00). */
00252 
00253 #define NIC_MRCMDX  0xF0        /* Memory data read command w/o increment (?). */
00254 
00255 #define NIC_MRCMD   0xF2        /* Memory data read command with increment (?). */
00256 
00257 #define NIC_MRR     0xF4        /* 2 byte memory data read register, low/high (?). */
00258 
00259 #define NIC_MWCMDX  0xF6        /* Memory data write command register w/o increment (?). */
00260 
00261 #define NIC_MWCMD   0xF8        /* Memory data write command register with increment (?). */
00262 
00263 #define NIC_MWR     0xFA        /* Memory data write command register with increment (?). */
00264 
00265 #define NIC_TXPL    0xFC        /* 2 byte TX packet length register. (?). */
00266 
00267 #define NIC_ISR     0xFE        /* Interrupt status register (0x00). */
00268 #define NIC_ISR_IOM     0xC0    /* I/O mode mask */
00269 #define NIC_ISR_M16     0x00    /* 16-bit I/O mode */
00270 #define NIC_ISR_M32     0x40    /* 32-bit I/O mode */
00271 #define NIC_ISR_M8      0x80    /* 8-bit I/O mode */
00272 #define NIC_ISR_ROOS    0x08    /* Receiver overflow counter interrupt. */
00273 #define NIC_ISR_ROS     0x04    /* Receiver overflow interrupt. */
00274 #define NIC_ISR_PTS     0x02    /* Transmitter interrupt. */
00275 #define NIC_ISR_PRS     0x01    /* Receiver interrupt. */
00276 
00277 #define NIC_IMR     0xFF        /* Interrupt mask register (0x00). */
00278 #define NIC_IMR_PAR     0x80    /* Enable read/write pointer wrap around. */
00279 #define NIC_IMR_ROOM    0x08    /* Enable receiver overflow counter interrupts. */
00280 #define NIC_IMR_ROM     0x04    /* Enable receiver overflow interrupts. */
00281 #define NIC_IMR_PTM     0x02    /* Enable transmitter interrupts. */
00282 #define NIC_IMR_PRM     0x01    /* Enable receiver interrupts. */
00283 
00284 #define NIC_PHY_BMCR    0x00    /* Basic mode control register. */
00285 
00286 #define NIC_PHY_BMSR    0x01    /* Basic mode status register. */
00287 #define NIC_PHY_BMSR_ANCOMPL    0x0020  /* Auto negotiation complete. */
00288 #define NIC_PHY_BMSR_LINKSTAT   0x0004  /* Link status. */
00289 
00290 #define NIC_PHY_ID1     0x02    /* PHY identifier register 1. */
00291 
00292 #define NIC_PHY_ID2     0x03    /* PHY identifier register 2. */
00293 
00294 #define NIC_PHY_ANAR    0x04    /* Auto negotiation advertisement register. */
00295 
00296 #define NIC_PHY_ANLPAR  0x05    /* Auto negotiation link partner availability register. */
00297 
00298 #define NIC_PHY_ANER    0x06    /* Auto negotiation expansion register. */
00299 
00300 #define NIC_PHY_DSCR    0x10    /* Davicom specified configuration register. */
00301 
00302 #define NIC_PHY_DSCSR   0x11    /* Davicom specified configuration and status register. */
00303 
00304 #define NIC_PHY_10BTCSR 0x12    /* 10BASE-T configuration and status register. */
00305 
00309 struct _NICINFO {
00310 #ifdef NUT_PERFMON
00311     u_long ni_rx_packets;       
00312     u_long ni_tx_packets;       
00313     u_long ni_overruns;         
00314     u_long ni_rx_frame_errors;  
00315     u_long ni_rx_crc_errors;    
00316     u_long ni_rx_missed_errors; 
00317 #endif
00318     HANDLE volatile ni_rx_rdy;  
00319     HANDLE volatile ni_tx_rdy;  
00320     HANDLE ni_mutex;            
00321     volatile int ni_tx_queued;  
00322     volatile int ni_tx_quelen;  
00323     volatile int ni_insane;     
00324     int ni_iomode;              
00325 };
00326 
00330 typedef struct _NICINFO NICINFO;
00331 
00338 
00339 
00340 static INLINE void nic_outb(u_char reg, u_char val)
00341 {
00342     outb(NIC_BASE_ADDR, reg);
00343     outb(NIC_DATA_ADDR, val);
00344 }
00345 
00346 static INLINE u_char nic_inb(u_short reg)
00347 {
00348     outb(NIC_BASE_ADDR, reg);
00349     return inb(NIC_DATA_ADDR);
00350 }
00351 
00359 static u_short phy_inw(u_char reg)
00360 {
00361     /* Select PHY register */
00362     nic_outb(NIC_EPAR, 0x40 | reg);
00363 
00364     /* PHY read command. */
00365     nic_outb(NIC_EPCR, 0x0C);
00366     NutDelay(1);
00367     nic_outb(NIC_EPCR, 0x00);
00368 
00369     /* Get data from PHY data register. */
00370     return ((u_short) nic_inb(NIC_EPDRH) << 8) | (u_short) nic_inb(NIC_EPDRL);
00371 }
00372 
00381 static void phy_outw(u_char reg, u_short val)
00382 {
00383     /* Select PHY register */
00384     nic_outb(NIC_EPAR, 0x40 | reg);
00385 
00386     /* Store value in PHY data register. */
00387     nic_outb(NIC_EPDRL, (u_char) val);
00388     nic_outb(NIC_EPDRH, (u_char) (val >> 8));
00389 
00390     /* PHY write command. */
00391     nic_outb(NIC_EPCR, 0x0A);
00392     NutDelay(1);
00393     nic_outb(NIC_EPCR, 0x00);
00394 }
00395 
00396 static int NicPhyInit(void)
00397 {
00398     /* Restart auto negotiation. */
00399     phy_outw(NIC_PHY_ANAR, 0x01E1);
00400     phy_outw(NIC_PHY_BMCR, 0x1200);
00401 
00402     nic_outb(NIC_GPCR, 1);
00403     nic_outb(NIC_GPR, 0);
00404 
00405     return 0;
00406 }
00407 
00413 static int NicReset(void)
00414 {
00415     /* Hardware reset. */
00416 #ifdef undef_NIC_RESET_BIT
00417     sbi(NIC_RESET_DDR, NIC_RESET_BIT);
00418     sbi(NIC_RESET_PORT, NIC_RESET_BIT);
00419     NutDelay(WAIT100);
00420     cbi(NIC_RESET_PORT, NIC_RESET_BIT);
00421     NutDelay(WAIT250);
00422     NutDelay(WAIT250);
00423 #else
00424     /* Software reset. */
00425     nic_outb(NIC_NCR, NIC_NCR_RST | NIC_NCR_LBMAC);
00426     NutDelay(1);
00427     /* FIXME: Delay required. */
00428 #endif
00429 
00430     return NicPhyInit();
00431 }
00432 
00433 /*
00434  * NIC interrupt entry.
00435  */
00436 static void NicInterrupt(void *arg)
00437 {
00438     u_char isr;
00439     NICINFO *ni = (NICINFO *) ((NUTDEVICE *) arg)->dev_dcb;
00440 
00441     /* Read interrupt status and disable interrupts. */
00442     isr = nic_inb(NIC_ISR);
00443 
00444     /* Receiver interrupt. */
00445     if (isr & NIC_ISR_PRS) {
00446         nic_outb(NIC_ISR, NIC_ISR_PRS);
00447         NutEventPostFromIrq(&ni->ni_rx_rdy);
00448     }
00449 
00450     /* Transmitter interrupt. */
00451     if (isr & NIC_ISR_PTS) {
00452         if (ni->ni_tx_queued) {
00453             if (ni->ni_tx_quelen) {
00454                 /* Initiate transfer of a queued packet. */
00455                 nic_outb(NIC_TXPL, (u_char) ni->ni_tx_quelen);
00456                 nic_outb(NIC_TXPL + 1, (u_char) (ni->ni_tx_quelen >> 8));
00457                 ni->ni_tx_quelen = 0;
00458                 nic_outb(NIC_TCR, NIC_TCR_TXREQ);
00459             }
00460             ni->ni_tx_queued--;
00461         }
00462         nic_outb(NIC_ISR, NIC_ISR_PTS);
00463         NutEventPostFromIrq(&ni->ni_tx_rdy);
00464     }
00465 
00466     /* Receiver overflow interrupt. */
00467     if (isr & NIC_ISR_ROS) {
00468         nic_outb(NIC_ISR, NIC_ISR_ROS);
00469         ni->ni_insane = 1;
00470         NutEventPostFromIrq(&ni->ni_rx_rdy);
00471     }
00472 
00473     /* Receiver overflow counter interrupt. */
00474     if (isr & NIC_ISR_ROOS) {
00475         nic_outb(NIC_ISR, NIC_ISR_ROOS);
00476         NutEventPostFromIrq(&ni->ni_rx_rdy);
00477     }
00478 }
00479 
00485 static void NicWrite8(u_char * buf, u_short len)
00486 {
00487     while (len--) {
00488         outb(NIC_DATA_ADDR, *buf);
00489         buf++;
00490     }
00491 }
00492 
00498 static void NicWrite16(u_char * buf, u_short len)
00499 {
00500     u_short *wp = (u_short *) buf;
00501 
00502     len = (len + 1) / 2;
00503     while (len--) {
00504         outw(NIC_DATA_ADDR, *wp);
00505         wp++;
00506     }
00507 }
00508 
00514 static void NicRead8(u_char * buf, u_short len)
00515 {
00516     while (len--) {
00517         *buf++ = inb(NIC_DATA_ADDR);
00518     }
00519 }
00520 
00526 static void NicRead16(u_char * buf, u_short len)
00527 {
00528     u_short *wp = (u_short *) buf;
00529 
00530     len = (len + 1) / 2;
00531     while (len--) {
00532         *wp++ = inw(NIC_DATA_ADDR);
00533     }
00534 }
00535 
00544 static int NicGetPacket(NICINFO * ni, NETBUF ** nbp)
00545 {
00546     int rc = -1;
00547     u_short fsw;
00548     u_short fbc;
00549 
00550     *nbp = NULL;
00551 
00552     /* Disable NIC interrupts. */
00553     NutIrqDisable(&NIC_SIGNAL);
00554 
00555     /* 
00556      * Read the status word w/o auto increment. If zero, no packet is 
00557      * available. Otherwise it should be set to one. Any other value 
00558      * indicates a weird chip crying for reset.
00559      */
00560     nic_inb(NIC_MRCMDX);
00561     /* Add some delay befor reading the status of the received packet. */
00562     _NOP(); _NOP(); _NOP(); _NOP();
00563     fsw = inb(NIC_DATA_ADDR);
00564     if (fsw > 1) {
00565         ni->ni_insane = 1;
00566     } else if (fsw) {
00567         /* Now read status word and byte count with auto increment. */
00568         outb(NIC_BASE_ADDR, NIC_MRCMD);
00569         if (ni->ni_iomode == NIC_ISR_M16) {
00570             fsw = inw(NIC_DATA_ADDR);
00571             _NOP(); _NOP(); _NOP(); _NOP();
00572             fbc = inw(NIC_DATA_ADDR);
00573         } else {
00574             fsw = inb(NIC_DATA_ADDR) + ((u_short) inb(NIC_DATA_ADDR) << 8);
00575             _NOP(); _NOP(); _NOP(); _NOP();
00576             fbc = inb(NIC_DATA_ADDR) + ((u_short) inb(NIC_DATA_ADDR) << 8);
00577         }
00578 
00579         /*
00580          * Receiving long packets is unexpected, because we disabled 
00581          * this during initialization. Let's declare the chip insane.
00582          * Short packets will be handled by the caller.
00583          */
00584         if (fbc > 1536) {
00585             ni->ni_insane = 1;
00586         } else {
00587             /*
00588              * The high byte of the status word contains a copy of the 
00589              * receiver status register.
00590              */
00591             fsw >>= 8;
00592             fsw &= NIC_RSR_ERRORS;
00593 #ifdef NUT_PERMON
00594             /* Update statistics. */
00595             if (fsw) {
00596                 if (RxStatus & NIC_RSR_CE) {
00597                     ni->ni_crc_errors++;
00598                 } else if (RxStatus & NIC_RSR_FOE) {
00599                     ni->ni_overruns++;
00600                 } else {
00601                     ni->ni_rx_missed_errors++;
00602                 }
00603             } else {
00604                 ni->ni_rx_packets++;
00605             }
00606 #endif
00607             /* 
00608              * If we got an error packet or failed to allocated the
00609              * buffer, then silently discard the packet.
00610              */
00611             if (fsw || (*nbp = NutNetBufAlloc(0, NBAF_DATALINK, fbc - 4)) == NULL) {
00612                 if (ni->ni_iomode == NIC_ISR_M16) {
00613                     fbc = (fbc + 1) / 2;
00614                     while (fbc--) {
00615                         fsw = inw(NIC_DATA_ADDR);
00616                     }
00617                 } else {
00618                     while (fbc--) {
00619                         fsw = inb(NIC_DATA_ADDR);
00620                     }
00621                 }
00622             } else {
00623                 if (ni->ni_iomode == NIC_ISR_M16) {
00624                     /* Read packet data from 16 bit bus. */
00625                     NicRead16((*nbp)->nb_dl.vp, (*nbp)->nb_dl.sz);
00626                     /* Read packet CRC. */
00627                     fsw = inw(NIC_DATA_ADDR);
00628                     fsw = inw(NIC_DATA_ADDR);
00629                 } else {
00630                     /* Read packet data from 8 bit bus. */
00631                     NicRead8((*nbp)->nb_dl.vp, (*nbp)->nb_dl.sz);
00632                     /* Read packet CRC. */
00633                     fsw = inb(NIC_DATA_ADDR);
00634                     fsw = inb(NIC_DATA_ADDR);
00635                     fsw = inb(NIC_DATA_ADDR);
00636                     fsw = inb(NIC_DATA_ADDR);
00637                 }
00638                 /* Return success. */
00639                 rc = 0;
00640             }
00641         }
00642     }
00643 
00644     /* Enable NIC interrupts if the chip is sane. */
00645     if (ni->ni_insane == 0) {
00646         NutIrqEnable(&NIC_SIGNAL);
00647     }
00648     return rc;
00649 }
00650 
00663 static int NicPutPacket(NICINFO * ni, NETBUF * nb)
00664 {
00665     int rc = -1;
00666     u_short sz;
00667 
00668     /*
00669      * Calculate the number of bytes to be send. Do not send packets 
00670      * larger than the Ethernet maximum transfer unit. The MTU
00671      * consist of 1500 data bytes plus the 14 byte Ethernet header
00672      * plus 4 bytes CRC. We check the data bytes only.
00673      */
00674     if ((sz = nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz) > ETHERMTU) {
00675         return -1;
00676     }
00677     sz += nb->nb_dl.sz;
00678     if (sz & 1) {
00679         sz++;
00680     }
00681 
00682     /* Disable interrupts. */
00683     NutIrqDisable(&NIC_SIGNAL);
00684 
00685     /* TODO: Check for link. */
00686     if (ni->ni_insane == 0) {
00687         /* Enable data write. */
00688         outb(NIC_BASE_ADDR, NIC_MWCMD);
00689 
00690         /* Transfer the Ethernet frame. */
00691         if (ni->ni_iomode == NIC_ISR_M16) {
00692             NicWrite16(nb->nb_dl.vp, nb->nb_dl.sz);
00693             NicWrite16(nb->nb_nw.vp, nb->nb_nw.sz);
00694             NicWrite16(nb->nb_tp.vp, nb->nb_tp.sz);
00695             NicWrite16(nb->nb_ap.vp, nb->nb_ap.sz);
00696         } else {
00697             NicWrite8(nb->nb_dl.vp, nb->nb_dl.sz);
00698             NicWrite8(nb->nb_nw.vp, nb->nb_nw.sz);
00699             NicWrite8(nb->nb_tp.vp, nb->nb_tp.sz);
00700             NicWrite8(nb->nb_ap.vp, nb->nb_ap.sz);
00701         }
00702 
00703         /* If no packet is queued, start the transmission. */
00704         if (ni->ni_tx_queued == 0) {
00705             nic_outb(NIC_TXPL, (u_char) sz);
00706             nic_outb(NIC_TXPL + 1, (u_char) (sz >> 8));
00707             nic_outb(NIC_TCR, NIC_TCR_TXREQ);
00708         }
00709         /* ...otherwise mark this packet queued. */
00710         else {
00711             ni->ni_tx_quelen = sz;
00712         }
00713         ni->ni_tx_queued++;
00714         rc = 0;
00715 #ifdef NUT_PERFMON
00716         ni->ni_tx_packets++;
00717 #endif
00718     }
00719 
00720     /* Enable interrupts. */
00721     NutIrqEnable(&NIC_SIGNAL);
00722 
00723     /* If the controller buffer is filled with two packets, then
00724        wait for the first being sent out. */
00725     if (rc == 0 && ni->ni_tx_queued > 1) {
00726         NutEventWait(&ni->ni_tx_rdy, 500);
00727     }
00728     return rc;
00729 }
00730 
00738 static int NicStart(CONST u_char * mac)
00739 {
00740     int i;
00741     int link_wait = 20;
00742 
00743     /* Power up the PHY. */
00744     nic_outb(NIC_GPR, 0);
00745     NutDelay(5);
00746 
00747     /* Software reset with MAC loopback. */
00748     nic_outb(NIC_NCR, NIC_NCR_RST | NIC_NCR_LBMAC);
00749     NutDelay(5);
00750     nic_outb(NIC_NCR, NIC_NCR_RST | NIC_NCR_LBMAC);
00751     NutDelay(5);
00752 
00753     /* 
00754      * PHY power down followed by PHY power up. This should activate 
00755      * the auto sense link.
00756      */
00757     nic_outb(NIC_GPR, 1);
00758     nic_outb(NIC_GPR, 0);
00759 
00760     /* Set MAC address. */
00761     for (i = 0; i < 6; i++) {
00762         nic_outb(NIC_PAR + i, mac[i]);
00763     }
00764 
00765     /* Enable broadcast receive. */
00766     for (i = 0; i < 7; i++) {
00767         nic_outb(NIC_MAR + i, 0);
00768     }
00769     nic_outb(NIC_MAR + 7, 0x80);
00770 
00771     /* Clear interrupts. */
00772     nic_outb(NIC_ISR, NIC_ISR_ROOS | NIC_ISR_ROS | NIC_ISR_PTS | NIC_ISR_PRS);
00773 
00774     /* Enable receiver. */
00775     nic_outb(NIC_RCR, NIC_RCR_DIS_LONG | NIC_RCR_DIS_CRC | NIC_RCR_RXEN | NIC_RCR_ALL);
00776 
00777     /* Wait for link. */
00778     for (link_wait = 20;; link_wait--) {
00779         if (phy_inw(NIC_PHY_BMSR) & NIC_PHY_BMSR_ANCOMPL) {
00780             break;
00781         }
00782         if (link_wait == 0) {
00783             return -1;
00784         }
00785         NutSleep(200);
00786     }
00787 
00788     /* Enable interrupts. */
00789     nic_outb(NIC_IMR, NIC_IMR_PAR | NIC_IMR_PTM | NIC_IMR_PRM);
00790 
00791     return 0;
00792 }
00793 
00798 THREAD(NicRxLanc, arg)
00799 {
00800     NUTDEVICE *dev;
00801     IFNET *ifn;
00802     NICINFO *ni;
00803     NETBUF *nb;
00804 
00805     dev = arg;
00806     ifn = (IFNET *) dev->dev_icb;
00807     ni = (NICINFO *) dev->dev_dcb;
00808 
00809     /*
00810      * This is a temporary hack. Due to a change in initialization,
00811      * we may not have got a MAC address yet. Wait until one has been
00812      * set.
00813      */
00814     for (;;) {
00815         int i;
00816 
00817         for (i = 0; i < sizeof(ifn->if_mac); i++) {
00818             if (ifn->if_mac[i] && ifn->if_mac[i] != 0xFF) {
00819                 break;
00820             }
00821         }
00822         if (i < sizeof(ifn->if_mac)) {
00823             break;
00824         }
00825         NutSleep(63);
00826     }
00827 
00828     /*
00829      * Do not continue unless we managed to start the NIC. We are
00830      * trapped here if the Ethernet link cannot be established.
00831      * This happens, for example, if no Ethernet cable is plugged
00832      * in.
00833      */
00834     while (NicStart(ifn->if_mac)) {
00835         NutSleep(1000);
00836     }
00837 
00838     /* Initialize the access mutex. */
00839     NutEventPost(&ni->ni_mutex);
00840 
00841     /* Run at high priority. */
00842     NutThreadSetPriority(9);
00843 
00844     /* Enable interrupts for P10. */
00845     outr(PIO_PDR, _BV(10));
00846     NutIrqEnable(&NIC_SIGNAL);
00847 
00848     for (;;) {
00849         /*
00850          * Wait for the arrival of new packets or poll the receiver 
00851          * every two seconds.
00852          */
00853         NutEventWait(&ni->ni_rx_rdy, 2000);
00854 
00855         /*
00856          * Fetch all packets from the NIC's internal buffer and pass 
00857          * them to the registered handler.
00858          */
00859         while (NicGetPacket(ni, &nb) == 0) {
00860 
00861             /* Discard short packets. */
00862             if (nb->nb_dl.sz < 60) {
00863                 NutNetBufFree(nb);
00864             } else {
00865                 (*ifn->if_recv) (dev, nb);
00866             }
00867         }
00868 
00869         /* We got a weird chip, try to restart it. */
00870         while (ni->ni_insane) {
00871             if (NicStart(ifn->if_mac) == 0) {
00872                 ni->ni_insane = 0;
00873                 ni->ni_tx_queued = 0;
00874                 ni->ni_tx_quelen = 0;
00875                 NutIrqEnable(&NIC_SIGNAL);
00876             } else {
00877                 NutSleep(1000);
00878             }
00879         }
00880     }
00881 }
00882 
00893 int DmOutput(NUTDEVICE * dev, NETBUF * nb)
00894 {
00895     static u_long mx_wait = 5000;
00896     int rc = -1;
00897     NICINFO *ni = (NICINFO *) dev->dev_dcb;
00898 
00899     /*
00900      * After initialization we are waiting for a long time to give
00901      * the PHY a chance to establish an Ethernet link.
00902      */
00903     while (rc) {
00904         if (ni->ni_insane) {
00905             break;
00906         }
00907         if (NutEventWait(&ni->ni_mutex, mx_wait)) {
00908             break;
00909         }
00910 
00911         /* Check for packet queue space. */
00912         if (ni->ni_tx_queued > 1) {
00913             if (NutEventWait(&ni->ni_tx_rdy, 500)) {
00914                 /* No queue space. Release the lock and give up. */
00915                 NutEventPost(&ni->ni_mutex);
00916                 break;
00917             }
00918         } else if (NicPutPacket(ni, nb) == 0) {
00919             /* Ethernet works. Set a long waiting time in case we
00920                temporarly lose the link next time. */
00921             rc = 0;
00922             mx_wait = 5000;
00923         }
00924         NutEventPost(&ni->ni_mutex);
00925     }
00926     /*
00927      * Probably no Ethernet link. Significantly reduce the waiting
00928      * time, so following transmission will soon return an error.
00929      */
00930     if (rc) {
00931         mx_wait = 500;
00932     }
00933     return rc;
00934 }
00935 
00953 int DmInit(NUTDEVICE * dev)
00954 {
00955     u_long id;
00956     NICINFO *ni = (NICINFO *) dev->dev_dcb;
00957 
00958     /* Probe chip by verifying the identifier registers. */
00959     id = (u_long) nic_inb(NIC_VID);
00960     id |= (u_long) nic_inb(NIC_VID + 1) << 8;
00961     id |= (u_long) nic_inb(NIC_PID) << 16;
00962     id |= (u_long) nic_inb(NIC_PID + 1) << 24;
00963     if (id != 0x90000A46) {
00964         return -1;
00965     }
00966 
00967     /* Reset chip. */
00968     if (NicReset()) {
00969         return -1;
00970     }
00971 
00972     /* Clear NICINFO structure. */
00973     memset(ni, 0, sizeof(NICINFO));
00974 
00975     /* Determine bus mode. We do not support 32 bit access. */
00976     ni->ni_iomode = nic_inb(NIC_ISR) & NIC_ISR_IOM;
00977     if (ni->ni_iomode == NIC_ISR_M32) {
00978         return -1;
00979     }
00980 
00981     /* Register interrupt handler. */
00982     if (NutRegisterIrqHandler(&NIC_SIGNAL, NicInterrupt, dev)) {
00983         return -1;
00984     }
00985 
00986     /* Start the receiver thread. */
00987     if (NutThreadCreate("rxi1", NicRxLanc, dev, NUT_THREAD_NICRXSTACK) == NULL) {
00988         return -1;
00989     }
00990     return 0;
00991 }
00992 
00993 static NICINFO dcb_eth0;
00994 
01000 static IFNET ifn_eth0 = {
01001     IFT_ETHER,                  
01002     {0, 0, 0, 0, 0, 0},         
01003     0,                          
01004     0,                          
01005     0,                          
01006     ETHERMTU,                   
01007     0,                          
01008     0,                          
01009     0,                          
01010     NutEtherInput,              
01011     DmOutput,                   
01012     NutEtherOutput              
01013 };
01014 
01024 NUTDEVICE devDM9000E = {
01025     0,                          
01026     {'e', 't', 'h', '0', 0, 0, 0, 0, 0},        
01027     IFTYP_NET,                  
01028     0,                          
01029     0,                          
01030     &ifn_eth0,                  
01031     &dcb_eth0,                  
01032     DmInit,                     
01033     0,                          
01034     0,                          
01035     0,                          
01036 #ifdef __HARVARD_ARCH__
01037     0,                          
01038 #endif
01039     0,                          
01040     0,                          
01041     0                           
01042 };
01043 

© 2000-2007 by egnite Software GmbH - visit http://www.ethernut.de/