dm9000e.c

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

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