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$
00037  * Revision 1.12  2009/02/06 15:37:39  haraldkipp
00038  * Added stack space multiplier and addend. Adjusted stack space.
00039  *
00040  * Revision 1.11  2008/08/28 11:12:15  haraldkipp
00041  * Added interface flags, which will be required to implement Ethernet ioctl
00042  * functions.
00043  *
00044  * Revision 1.10  2008/08/11 06:59:07  haraldkipp
00045  * BSD types replaced by stdint types (feature request #1282721).
00046  *
00047  * Revision 1.9  2008/02/15 17:09:44  haraldkipp
00048  * Added support for the Elektor Internet Radio.
00049  *
00050  * Revision 1.8  2007/08/17 11:43:46  haraldkipp
00051  * Enable multicast.
00052  *
00053  * Revision 1.7  2007/05/24 07:26:44  haraldkipp
00054  * Added some delay befor reading the status of the received packet. Fixes
00055  * bug #1672527, thanks to Andreas Helmcke.
00056  *
00057  * Revision 1.6  2007/05/02 11:22:51  haraldkipp
00058  * Added multicast table entry.
00059  *
00060  * Revision 1.5  2006/06/28 17:10:15  haraldkipp
00061  * Include more general header file for ARM.
00062  *
00063  * Revision 1.4  2006/03/16 19:04:48  haraldkipp
00064  * Adding a short delay before reading the status word makes it work with
00065  * compiler optimization. On receiver overflow interrupts the chip is
00066  * declared insane. The output routine will no more enter NutEventWait()
00067  * on insane chips.
00068  *
00069  * Revision 1.3  2006/03/02 19:51:16  haraldkipp
00070  * Replaced GCC specific inline specifications with their portable
00071  * counterparts.
00072  *
00073  * Revision 1.2  2006/01/23 17:33:14  haraldkipp
00074  * Possible memory alignment problem may start network interface too early.
00075  *
00076  * Revision 1.1  2005/10/24 08:49:05  haraldkipp
00077  * Initial check in.
00078  *
00079  */
00080 
00081 #include <cfg/os.h>
00082 #include <arch/arm.h>
00083 
00084 #include <string.h>
00085 
00086 #include <sys/atom.h>
00087 #include <sys/heap.h>
00088 #include <sys/thread.h>
00089 #include <sys/event.h>
00090 #include <sys/timer.h>
00091 #include <sys/confnet.h>
00092 
00093 #include <netinet/if_ether.h>
00094 #include <net/ether.h>
00095 #include <net/if_var.h>
00096 
00097 #include <dev/irqreg.h>
00098 #include <dev/dm9000e.h>
00099 
00100 /* WARNING: Variadic macros are C99 and may fail with C89 compilers. */
00101 #ifdef NUTDEBUG
00102 #include <stdio.h>
00103 #define DMPRINTF(args,...) printf(args,##__VA_ARGS__)
00104 #else
00105 #define DMPRINTF(args,...)
00106 #endif
00107 
00108 #ifndef NUT_THREAD_NICRXSTACK
00109 /* arm-elf-gcc size optimized code used 160 bytes. */
00110 #define NUT_THREAD_NICRXSTACK   384
00111 #endif
00112 
00113 /*
00114  * Determine ports, which had not been explicitely configured.
00115  */
00116 #if defined(ETHERNUT3)
00117 
00118 #ifndef NIC_BASE_ADDR
00119 #define NIC_BASE_ADDR   0x20000000
00120 #endif
00121 
00122 #ifndef NIC_SIGNAL_IRQ
00123 #define NIC_SIGNAL_IRQ  INT1
00124 #endif
00125 
00126 #ifndef NIC_SIGNAL_PDR
00127 #define NIC_SIGNAL_PDR  PIO_PDR
00128 #endif
00129 
00130 #ifndef NIC_SIGNAL_BIT
00131 #define NIC_SIGNAL_BIT  10
00132 #endif
00133 
00134 #elif defined(ELEKTOR_IR1)
00135 
00136 #ifndef NIC_BASE_ADDR
00137 #define NIC_BASE_ADDR   0x30000000
00138 #endif
00139 
00140 #ifndef NIC_SIGNAL_IRQ
00141 #define NIC_SIGNAL_IRQ  INT0
00142 #endif
00143 
00144 #ifndef NIC_SIGNAL_PDR
00145 #define NIC_SIGNAL_PDR  PIOB_PDR
00146 #endif
00147 
00148 #ifndef NIC_SIGNAL_XSR
00149 #define NIC_SIGNAL_XSR  PIOB_ASR
00150 #endif
00151 
00152 #ifndef NIC_SIGNAL_BIT
00153 #define NIC_SIGNAL_BIT  PB20_IRQ0_A
00154 #endif
00155 
00156 #endif
00157 
00158 #ifdef NIC_BASE_ADDR
00159 
00160 #ifndef NIC_DATA_ADDR
00161 #define NIC_DATA_ADDR   (NIC_BASE_ADDR + 4)
00162 #endif
00163 
00164 #define INT0    0
00165 #define INT1    1
00166 #define INT2    2
00167 #define INT3    3
00168 #define INT4    4
00169 #define INT5    5
00170 #define INT6    6
00171 #define INT7    7
00172 
00173 #ifdef NIC_RESET_BIT
00174 
00175 #if (NIC_RESET_AVRPORT == AVRPORTB)
00176 #define NIC_RESET_PORT   PORTB
00177 #define NIC_RESET_DDR    DDRB
00178 
00179 #elif (NIC_RESET_AVRPORT == AVRPORTD)
00180 #define NIC_RESET_PORT   PORTD
00181 #define NIC_RESET_DDR    DDRD
00182 
00183 #elif (NIC_RESET_AVRPORT == AVRPORTE)
00184 #define NIC_RESET_PORT   PORTE
00185 #define NIC_RESET_DDR    DDRE
00186 
00187 #elif (NIC_RESET_AVRPORT == AVRPORTF)
00188 #define NIC_RESET_PORT   PORTF
00189 #define NIC_RESET_DDR    DDRF
00190 
00191 #endif                          /* NIC_RESET_AVRPORT */
00192 
00193 #endif                          /* NIC_RESET_BIT */
00194 
00195 /*
00196  * Determine interrupt settings.
00197  * DOES NOT WORK
00198  */
00199 #if (NIC_SIGNAL_IRQ == INT0)
00200 #define NIC_SIGNAL          sig_INTERRUPT0
00201 
00202 #elif (NIC_SIGNAL_IRQ == INT2)
00203 #define NIC_SIGNAL          sig_INTERRUPT2
00204 
00205 #elif (NIC_SIGNAL_IRQ == INT3)
00206 #define NIC_SIGNAL          sig_INTERRUPT3
00207 
00208 #elif (NIC_SIGNAL_IRQ == INT4)
00209 #define NIC_SIGNAL          sig_INTERRUPT4
00210 
00211 #elif (NIC_SIGNAL_IRQ == INT5)
00212 #define NIC_SIGNAL          sig_INTERRUPT5
00213 
00214 #elif (NIC_SIGNAL_IRQ == INT6)
00215 #define NIC_SIGNAL          sig_INTERRUPT6
00216 
00217 #elif (NIC_SIGNAL_IRQ == INT7)
00218 #define NIC_SIGNAL          sig_INTERRUPT7
00219 
00220 #else
00221 #define NIC_SIGNAL          sig_INTERRUPT1
00222 
00223 #endif
00224 
00229 
00230 #define NIC_NCR     0x00        /* Network control register (0x00). */
00231 #define NIC_NCR_LBM     0x06    /* Loopback mode. */
00232 #define NIC_NCR_LBNORM  0x00    /* Normal mode. */
00233 #define NIC_NCR_LBMAC   0x02    /* MAC loopback. */
00234 #define NIC_NCR_LBPHY   0x04    /* PHY loopback. */
00235 #define NIC_NCR_RST     0x01    /* Software reset, auto clear. */
00236 
00237 #define NIC_NSR     0x01        /* Network status register (0x00). */
00238 #define NIC_NSR_SPEED   0x80
00239 #define NIC_NSR_LINKST  0x40
00240 #define NIC_NSR_WAKEST  0x20
00241 #define NIC_NSR_TX2END  0x08
00242 #define NIC_NSR_TX1END  0x04
00243 #define NIC_NSR_RXOV    0x02
00244 
00245 #define NIC_TCR     0x02        /* TX control register (0x00). */
00246 #define NIC_TCR_TXREQ    0x01   /* TX request */
00247 
00248 #define NIC_TSR1    0x03        /* TX status register I (0x00). */
00249 
00250 #define NIC_TSR2    0x04        /* TX status register II (0x00). */
00251 
00252 #define NIC_RCR     0x05        /* RX control register (0x00). */
00253 #define NIC_RCR_DIS_LONG 0x20   /* Discard long packets. */
00254 #define NIC_RCR_DIS_CRC 0x10    /* Discard CRC error packets. */
00255 #define NIC_RCR_ALL     0x08    /* Pass all multicast */
00256 #define NIC_RCR_PRMSC   0x02    /* Enable promiscuous mode. */
00257 #define NIC_RCR_RXEN    0x01    /* Enable receiver. */
00258 
00259 #define NIC_RSR     0x06        /* RX status register (0x00). */
00260 #define NIC_RSR_ERRORS  0xBF    /* Error bit mask. */
00261 #define NIC_RSR_RF      0x80    /* Runt frame. */
00262 #define NIC_RSR_MF      0x40    /* Multicast frame. */
00263 #define NIC_RSR_LCS     0x20    /* Late collision. */
00264 #define NIC_RSR_RWTO    0x10    /* Receiver watchdog time out. */
00265 #define NIC_RSR_PLE     0x08    /* Physical layer error. */
00266 #define NIC_RSR_AE      0x04    /* Alignment error. */
00267 #define NIC_RSR_CE      0x02    /* CRC error. */
00268 #define NIC_RSR_FOE     0x01    /* FIFO overflow error. */
00269 
00270 #define NIC_ROCR    0x07        /* Receive overflow counter register (0x00). */
00271 
00272 #define NIC_BPTR    0x08        /* Back pressure threshold register (0x37). */
00273 
00274 #define NIC_FCTR    0x09        /* Flow control threshold register (0x38). */
00275 
00276 #define NIC_FCR     0x0A        /* RX flow control register (0x00). */
00277 
00278 #define NIC_EPCR    0x0B        /* EEPROM and PHY control register. */
00279 
00280 #define NIC_EPAR    0x0C        /* EEPROM and PHY address register. */
00281 
00282 #define NIC_EPDRL   0x0D        /* EEPROM and PHY low byte data register. */
00283 
00284 #define NIC_EPDRH   0x0E        /* EEPROM and PHY high byte data register. */
00285 
00286 #define NIC_WCR     0x0F        /* Wake up control register (0x00). */
00287 
00288 #define NIC_PAR     0x10        /* 6 byte physical address register. */
00289 
00290 #define NIC_MAR     0x16        /* 8 byte multicast address register. */
00291 
00292 #define NIC_GPCR    0x1E        /* General purpose control register (?). */
00293 
00294 #define NIC_GPR     0x1F        /* General purpose register (?). */
00295 
00296 #define NIC_TRPA    0x22        /* 2 byte TX SRAM read pointer address, low/high (0x0000). */
00297 
00298 #define NIC_RWPA    0x24        /* 2 byte RX SRAM write pointer address, low/high (0x0000). */
00299 
00300 #define NIC_VID     0x28        /* 2 byte vendor ID (0x0A46). */
00301 
00302 #define NIC_PID     0x2A        /* 2 byte product ID (0x0900). */
00303 
00304 #define NIC_CHIPR   0x2C        /* Chip revision (0x00). */
00305 
00306 #define NIC_SMCR    0x2F        /* Special mode register (0x00). */
00307 
00308 #define NIC_MRCMDX  0xF0        /* Memory data read command w/o increment (?). */
00309 
00310 #define NIC_MRCMD   0xF2        /* Memory data read command with increment (?). */
00311 
00312 #define NIC_MRR     0xF4        /* 2 byte memory data read register, low/high (?). */
00313 
00314 #define NIC_MWCMDX  0xF6        /* Memory data write command register w/o increment (?). */
00315 
00316 #define NIC_MWCMD   0xF8        /* Memory data write command register with increment (?). */
00317 
00318 #define NIC_MWR     0xFA        /* Memory data write command register with increment (?). */
00319 
00320 #define NIC_TXPL    0xFC        /* 2 byte TX packet length register. (?). */
00321 
00322 #define NIC_ISR     0xFE        /* Interrupt status register (0x00). */
00323 #define NIC_ISR_IOM     0xC0    /* I/O mode mask */
00324 #define NIC_ISR_M16     0x00    /* 16-bit I/O mode */
00325 #define NIC_ISR_M32     0x40    /* 32-bit I/O mode */
00326 #define NIC_ISR_M8      0x80    /* 8-bit I/O mode */
00327 #define NIC_ISR_ROOS    0x08    /* Receiver overflow counter interrupt. */
00328 #define NIC_ISR_ROS     0x04    /* Receiver overflow interrupt. */
00329 #define NIC_ISR_PTS     0x02    /* Transmitter interrupt. */
00330 #define NIC_ISR_PRS     0x01    /* Receiver interrupt. */
00331 
00332 #define NIC_IMR     0xFF        /* Interrupt mask register (0x00). */
00333 #define NIC_IMR_PAR     0x80    /* Enable read/write pointer wrap around. */
00334 #define NIC_IMR_ROOM    0x08    /* Enable receiver overflow counter interrupts. */
00335 #define NIC_IMR_ROM     0x04    /* Enable receiver overflow interrupts. */
00336 #define NIC_IMR_PTM     0x02    /* Enable transmitter interrupts. */
00337 #define NIC_IMR_PRM     0x01    /* Enable receiver interrupts. */
00338 
00339 #define NIC_PHY_BMCR    0x00    /* Basic mode control register. */
00340 
00341 #define NIC_PHY_BMSR    0x01    /* Basic mode status register. */
00342 #define NIC_PHY_BMSR_ANCOMPL    0x0020  /* Auto negotiation complete. */
00343 #define NIC_PHY_BMSR_LINKSTAT   0x0004  /* Link status. */
00344 
00345 #define NIC_PHY_ID1     0x02    /* PHY identifier register 1. */
00346 
00347 #define NIC_PHY_ID2     0x03    /* PHY identifier register 2. */
00348 
00349 #define NIC_PHY_ANAR    0x04    /* Auto negotiation advertisement register. */
00350 
00351 #define NIC_PHY_ANLPAR  0x05    /* Auto negotiation link partner availability register. */
00352 
00353 #define NIC_PHY_ANER    0x06    /* Auto negotiation expansion register. */
00354 
00355 #define NIC_PHY_DSCR    0x10    /* Davicom specified configuration register. */
00356 
00357 #define NIC_PHY_DSCSR   0x11    /* Davicom specified configuration and status register. */
00358 
00359 #define NIC_PHY_10BTCSR 0x12    /* 10BASE-T configuration and status register. */
00360 
00364 struct _NICINFO {
00365 #ifdef NUT_PERFMON
00366     uint32_t ni_rx_packets;       
00367     uint32_t ni_tx_packets;       
00368     uint32_t ni_overruns;         
00369     uint32_t ni_rx_frame_errors;  
00370     uint32_t ni_rx_crc_errors;    
00371     uint32_t ni_rx_missed_errors; 
00372 #endif
00373     HANDLE volatile ni_rx_rdy;  
00374     HANDLE volatile ni_tx_rdy;  
00375     HANDLE ni_mutex;            
00376     volatile int ni_tx_queued;  
00377     volatile int ni_tx_quelen;  
00378     volatile int ni_insane;     
00379     int ni_iomode;              
00380 };
00381 
00385 typedef struct _NICINFO NICINFO;
00386 
00393 
00394 
00395 static INLINE void nic_outb(uint8_t reg, uint8_t val)
00396 {
00397     outb(NIC_BASE_ADDR, reg);
00398     outb(NIC_DATA_ADDR, val);
00399 }
00400 
00401 static INLINE uint8_t nic_inb(uint16_t reg)
00402 {
00403     outb(NIC_BASE_ADDR, reg);
00404     return inb(NIC_DATA_ADDR);
00405 }
00406 
00414 static uint16_t phy_inw(uint8_t reg)
00415 {
00416     /* Select PHY register */
00417     nic_outb(NIC_EPAR, 0x40 | reg);
00418 
00419     /* PHY read command. */
00420     nic_outb(NIC_EPCR, 0x0C);
00421     NutDelay(1);
00422     nic_outb(NIC_EPCR, 0x00);
00423 
00424     /* Get data from PHY data register. */
00425     return ((uint16_t) nic_inb(NIC_EPDRH) << 8) | (uint16_t) nic_inb(NIC_EPDRL);
00426 }
00427 
00436 static void phy_outw(uint8_t reg, uint16_t val)
00437 {
00438     /* Select PHY register */
00439     nic_outb(NIC_EPAR, 0x40 | reg);
00440 
00441     /* Store value in PHY data register. */
00442     nic_outb(NIC_EPDRL, (uint8_t) val);
00443     nic_outb(NIC_EPDRH, (uint8_t) (val >> 8));
00444 
00445     /* PHY write command. */
00446     nic_outb(NIC_EPCR, 0x0A);
00447     NutDelay(1);
00448     nic_outb(NIC_EPCR, 0x00);
00449 }
00450 
00451 static int NicPhyInit(void)
00452 {
00453     /* Restart auto negotiation. */
00454     phy_outw(NIC_PHY_ANAR, 0x01E1);
00455     phy_outw(NIC_PHY_BMCR, 0x1200);
00456 
00457     nic_outb(NIC_GPCR, 1);
00458     nic_outb(NIC_GPR, 0);
00459 
00460     return 0;
00461 }
00462 
00468 static int NicReset(void)
00469 {
00470     /* Hardware reset. */
00471 #ifdef undef_NIC_RESET_BIT
00472     sbi(NIC_RESET_DDR, NIC_RESET_BIT);
00473     sbi(NIC_RESET_PORT, NIC_RESET_BIT);
00474     NutDelay(WAIT100);
00475     cbi(NIC_RESET_PORT, NIC_RESET_BIT);
00476     NutDelay(WAIT250);
00477     NutDelay(WAIT250);
00478 #else
00479     /* Software reset. */
00480     nic_outb(NIC_NCR, NIC_NCR_RST | NIC_NCR_LBMAC);
00481     NutDelay(1);
00482     /* FIXME: Delay required. */
00483 #endif
00484     DMPRINTF("\n*DMRES*\n");
00485     return NicPhyInit();
00486 }
00487 
00488 /*
00489  * NIC interrupt entry.
00490  */
00491 static void NicInterrupt(void *arg)
00492 {
00493     uint_fast8_t isr;
00494     NICINFO *ni = (NICINFO *) ((NUTDEVICE *) arg)->dev_dcb;
00495 
00496     /* Read interrupt status and disable interrupts. */
00497     isr = nic_inb(NIC_ISR);
00498     DMPRINTF("*DMIRQ %02x:", isr);
00499 
00500     /* Receiver interrupt. */
00501     if (isr & NIC_ISR_PRS) {
00502         DMPRINTF("RX*");
00503         nic_outb(NIC_ISR, NIC_ISR_PRS);
00504         NutEventPostFromIrq(&ni->ni_rx_rdy);
00505     }
00506 
00507     /* Transmitter interrupt. */
00508     if (isr & NIC_ISR_PTS) {
00509         DMPRINTF("TX*");
00510         if (ni->ni_tx_queued) {
00511             if (ni->ni_tx_quelen) {
00512                 /* Initiate transfer of a queued packet. */
00513                 nic_outb(NIC_TXPL, (uint8_t) ni->ni_tx_quelen);
00514                 nic_outb(NIC_TXPL + 1, (uint8_t) (ni->ni_tx_quelen >> 8));
00515                 ni->ni_tx_quelen = 0;
00516                 nic_outb(NIC_TCR, NIC_TCR_TXREQ);
00517             }
00518             ni->ni_tx_queued--;
00519         }
00520         nic_outb(NIC_ISR, NIC_ISR_PTS);
00521         NutEventPostFromIrq(&ni->ni_tx_rdy);
00522     }
00523 
00524     /* Receiver overflow interrupt. */
00525     if (isr & NIC_ISR_ROS) {
00526         DMPRINTF("OVI*");
00527         nic_outb(NIC_ISR, NIC_ISR_ROS);
00528         ni->ni_insane = 1;
00529         NutEventPostFromIrq(&ni->ni_rx_rdy);
00530     }
00531 
00532     /* Receiver overflow counter interrupt. */
00533     if (isr & NIC_ISR_ROOS) {
00534         DMPRINTF("OVC*");
00535         nic_outb(NIC_ISR, NIC_ISR_ROOS);
00536         NutEventPostFromIrq(&ni->ni_rx_rdy);
00537     }
00538 
00539     if( ni->ni_insane)
00540         DMPRINTF("INS\n");
00541     else
00542         DMPRINTF("\n");
00543 }
00544 
00550 static void NicWrite8(uint8_t * buf, uint16_t len)
00551 {
00552     while (len--) {
00553         outb(NIC_DATA_ADDR, *buf);
00554         buf++;
00555     }
00556 }
00557 
00563 static void NicWrite16(uint8_t * buf, uint16_t len)
00564 {
00565     uint16_t *wp = (uint16_t *) buf;
00566 
00567     len = (len + 1) / 2;
00568     while (len--) {
00569         outw(NIC_DATA_ADDR, *wp);
00570         wp++;
00571     }
00572 }
00573 
00579 static void NicRead8(uint8_t * buf, uint16_t len)
00580 {
00581     while (len--) {
00582         *buf++ = inb(NIC_DATA_ADDR);
00583     }
00584 }
00585 
00591 static void NicRead16(uint8_t * buf, uint16_t len)
00592 {
00593     uint16_t *wp = (uint16_t *) buf;
00594 
00595     len = (len + 1) / 2;
00596     while (len--) {
00597         *wp++ = inw(NIC_DATA_ADDR);
00598     }
00599 }
00600 
00609 static int NicGetPacket(NICINFO * ni, NETBUF ** nbp)
00610 {
00611     int rc = -1;
00612     uint16_t fsw;
00613     uint16_t fbc;
00614 
00615     *nbp = NULL;
00616 
00617     /* Disable NIC interrupts. */
00618     NutIrqDisable(&NIC_SIGNAL);
00619 
00620     /*
00621      * Read the status word w/o auto increment. If zero, no packet is
00622      * available. Otherwise it should be set to one. Any other value
00623      * indicates a weird chip crying for reset.
00624      */
00625     nic_inb(NIC_MRCMDX);
00626     /* Add some delay befor reading the status of the received packet. */
00627     _NOP(); _NOP(); _NOP(); _NOP();
00628     fsw = inb(NIC_DATA_ADDR);
00629     if (fsw > 1) {
00630         ni->ni_insane = 1;
00631     } else if (fsw) {
00632         /* Now read status word and byte count with auto increment. */
00633         outb(NIC_BASE_ADDR, NIC_MRCMD);
00634         if (ni->ni_iomode == NIC_ISR_M16) {
00635             fsw = inw(NIC_DATA_ADDR);
00636             _NOP(); _NOP(); _NOP(); _NOP();
00637             fbc = inw(NIC_DATA_ADDR);
00638         } else {
00639             fsw = inb(NIC_DATA_ADDR) + ((uint16_t) inb(NIC_DATA_ADDR) << 8);
00640             _NOP(); _NOP(); _NOP(); _NOP();
00641             fbc = inb(NIC_DATA_ADDR) + ((uint16_t) inb(NIC_DATA_ADDR) << 8);
00642         }
00643 
00644         /*
00645          * Receiving long packets is unexpected, because we disabled
00646          * this during initialization. Let's declare the chip insane.
00647          * Short packets will be handled by the caller.
00648          */
00649         if (fbc > 1536) {
00650             ni->ni_insane = 1;
00651         } else {
00652             /*
00653              * The high byte of the status word contains a copy of the
00654              * receiver status register.
00655              */
00656             fsw >>= 8;
00657             fsw &= NIC_RSR_ERRORS;
00658 #ifdef NUT_PERMON
00659             /* Update statistics. */
00660             if (fsw) {
00661                 if (RxStatus & NIC_RSR_CE) {
00662                     ni->ni_crc_errors++;
00663                 } else if (RxStatus & NIC_RSR_FOE) {
00664                     ni->ni_overruns++;
00665                 } else {
00666                     ni->ni_rx_missed_errors++;
00667                 }
00668             } else {
00669                 ni->ni_rx_packets++;
00670             }
00671 #endif
00672             /*
00673              * If we got an error packet or failed to allocated the
00674              * buffer, then silently discard the packet.
00675              */
00676             if (fsw || (*nbp = NutNetBufAlloc(0, NBAF_DATALINK, fbc - 4)) == NULL) {
00677                 if (ni->ni_iomode == NIC_ISR_M16) {
00678                     fbc = (fbc + 1) / 2;
00679                     while (fbc--) {
00680                         fsw = inw(NIC_DATA_ADDR);
00681                     }
00682                 } else {
00683                     while (fbc--) {
00684                         fsw = inb(NIC_DATA_ADDR);
00685                     }
00686                 }
00687             } else {
00688                 if (ni->ni_iomode == NIC_ISR_M16) {
00689                     /* Read packet data from 16 bit bus. */
00690                     NicRead16((*nbp)->nb_dl.vp, (*nbp)->nb_dl.sz);
00691                     /* Read packet CRC. */
00692                     fsw = inw(NIC_DATA_ADDR);
00693                     fsw = inw(NIC_DATA_ADDR);
00694                 } else {
00695                     /* Read packet data from 8 bit bus. */
00696                     NicRead8((*nbp)->nb_dl.vp, (*nbp)->nb_dl.sz);
00697                     /* Read packet CRC. */
00698                     fsw = inb(NIC_DATA_ADDR);
00699                     fsw = inb(NIC_DATA_ADDR);
00700                     fsw = inb(NIC_DATA_ADDR);
00701                     fsw = inb(NIC_DATA_ADDR);
00702                 }
00703                 /* Return success. */
00704                 rc = 0;
00705             }
00706         }
00707     }
00708 
00709     /* Enable NIC interrupts if the chip is sane. */
00710     if (ni->ni_insane == 0) {
00711         NutIrqEnable(&NIC_SIGNAL);
00712     }
00713     return rc;
00714 }
00715 
00728 static int NicPutPacket(NICINFO * ni, NETBUF * nb)
00729 {
00730     int rc = -1;
00731     uint16_t sz;
00732 
00733     /*
00734      * Calculate the number of bytes to be send. Do not send packets
00735      * larger than the Ethernet maximum transfer unit. The MTU
00736      * consist of 1500 data bytes plus the 14 byte Ethernet header
00737      * plus 4 bytes CRC. We check the data bytes only.
00738      */
00739     if ((sz = nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz) > ETHERMTU) {
00740         return -1;
00741     }
00742     sz += nb->nb_dl.sz;
00743     if (sz & 1) {
00744         sz++;
00745     }
00746 
00747     /* Disable interrupts. */
00748     NutIrqDisable(&NIC_SIGNAL);
00749 
00750     /* TODO: Check for link. */
00751     if (ni->ni_insane == 0) {
00752         /* Enable data write. */
00753         outb(NIC_BASE_ADDR, NIC_MWCMD);
00754 
00755         /* Transfer the Ethernet frame. */
00756         if (ni->ni_iomode == NIC_ISR_M16) {
00757             NicWrite16(nb->nb_dl.vp, nb->nb_dl.sz);
00758             NicWrite16(nb->nb_nw.vp, nb->nb_nw.sz);
00759             NicWrite16(nb->nb_tp.vp, nb->nb_tp.sz);
00760             NicWrite16(nb->nb_ap.vp, nb->nb_ap.sz);
00761         } else {
00762             NicWrite8(nb->nb_dl.vp, nb->nb_dl.sz);
00763             NicWrite8(nb->nb_nw.vp, nb->nb_nw.sz);
00764             NicWrite8(nb->nb_tp.vp, nb->nb_tp.sz);
00765             NicWrite8(nb->nb_ap.vp, nb->nb_ap.sz);
00766         }
00767 
00768         /* If no packet is queued, start the transmission. */
00769         if (ni->ni_tx_queued == 0) {
00770             nic_outb(NIC_TXPL, (uint8_t) sz);
00771             nic_outb(NIC_TXPL + 1, (uint8_t) (sz >> 8));
00772             nic_outb(NIC_TCR, NIC_TCR_TXREQ);
00773         }
00774         /* ...otherwise mark this packet queued. */
00775         else {
00776             ni->ni_tx_quelen = sz;
00777         }
00778         ni->ni_tx_queued++;
00779         rc = 0;
00780 #ifdef NUT_PERFMON
00781         ni->ni_tx_packets++;
00782 #endif
00783     }
00784 
00785     /* Enable interrupts. */
00786     NutIrqEnable(&NIC_SIGNAL);
00787 
00788     /* If the controller buffer is filled with two packets, then
00789        wait for the first being sent out. */
00790     if (rc == 0 && ni->ni_tx_queued > 1) {
00791         NutEventWait(&ni->ni_tx_rdy, 500);
00792     }
00793     return rc;
00794 }
00795 
00803 static int NicStart(CONST uint8_t * mac)
00804 {
00805     int i;
00806     int link_wait = 20;
00807 
00808     /* Power up the PHY. */
00809     nic_outb(NIC_GPR, 0);
00810     NutDelay(5);
00811 
00812     /* Software reset with MAC loopback. */
00813     nic_outb(NIC_NCR, NIC_NCR_RST | NIC_NCR_LBMAC);
00814     NutDelay(5);
00815     nic_outb(NIC_NCR, NIC_NCR_RST | NIC_NCR_LBMAC);
00816     NutDelay(5);
00817 
00818     /*
00819      * PHY power down followed by PHY power up. This should activate
00820      * the auto sense link.
00821      */
00822     nic_outb(NIC_GPR, 1);
00823     nic_outb(NIC_GPR, 0);
00824 
00825     /* Set MAC address. */
00826     for (i = 0; i < 6; i++) {
00827         nic_outb(NIC_PAR + i, mac[i]);
00828     }
00829 
00830     /* Enable broadcast receive. */
00831     for (i = 0; i < 7; i++) {
00832         nic_outb(NIC_MAR + i, 0);
00833     }
00834     nic_outb(NIC_MAR + 7, 0x80);
00835 
00836     /* Clear interrupts. */
00837     nic_outb(NIC_ISR, NIC_ISR_ROOS | NIC_ISR_ROS | NIC_ISR_PTS | NIC_ISR_PRS);
00838 
00839     /* Enable late collision retries on the DM9000A. */
00840     if (nic_inb(NIC_CHIPR) == 0x19) {
00841         nic_outb(0x2D, 0x40);
00842     }
00843 
00844     /* Enable receiver. */
00845     nic_outb(NIC_RCR, NIC_RCR_DIS_LONG | NIC_RCR_DIS_CRC | NIC_RCR_RXEN | NIC_RCR_ALL);
00846 
00847     /* Wait for link. */
00848     for (link_wait = 20;; link_wait--) {
00849         if (phy_inw(NIC_PHY_BMSR) & NIC_PHY_BMSR_ANCOMPL) {
00850             break;
00851         }
00852         if (link_wait == 0) {
00853             return -1;
00854         }
00855         NutSleep(200);
00856     }
00857 
00858     /* Enable interrupts. */
00859     nic_outb(NIC_IMR, NIC_IMR_PAR | NIC_IMR_PTM | NIC_IMR_PRM);
00860 
00861     return 0;
00862 }
00863 
00868 THREAD(NicRxLanc, arg)
00869 {
00870     NUTDEVICE *dev;
00871     IFNET *ifn;
00872     NICINFO *ni;
00873     NETBUF *nb;
00874 
00875     dev = arg;
00876     ifn = (IFNET *) dev->dev_icb;
00877     ni = (NICINFO *) dev->dev_dcb;
00878 
00879     /*
00880      * This is a temporary hack. Due to a change in initialization,
00881      * we may not have got a MAC address yet. Wait until a valid one
00882      * has been set.
00883      */
00884     while (!ETHER_IS_UNICAST(ifn->if_mac)) {
00885         NutSleep(10);
00886     }
00887 
00888     /*
00889      * Do not continue unless we managed to start the NIC. We are
00890      * trapped here if the Ethernet link cannot be established.
00891      * This happens, for example, if no Ethernet cable is plugged
00892      * in.
00893      */
00894     while (NicStart(ifn->if_mac)) {
00895         NutSleep(1000);
00896     }
00897 
00898     /* Initialize the access mutex. */
00899     NutEventPost(&ni->ni_mutex);
00900 
00901     /* Run at high priority. */
00902     NutThreadSetPriority(9);
00903 
00904     /* Enable interrupts. */
00905 #ifdef NIC_SIGNAL_XSR
00906     outr(NIC_SIGNAL_XSR, _BV(NIC_SIGNAL_BIT));
00907 #if defined(ELEKTOR_IR1)
00908     /* Ugly code alarm: Should be configurable. */
00909     outr(PMC_PCER, _BV(IRQ0_ID));
00910 #endif
00911 #endif
00912     outr(NIC_SIGNAL_PDR, _BV(NIC_SIGNAL_BIT));
00913     NutIrqEnable(&NIC_SIGNAL);
00914 #if defined(ELEKTOR_IR1)
00915     /* Ugly code alarm: Should be configurable. */
00916     NutIrqSetMode(&NIC_SIGNAL, NUT_IRQMODE_HIGHLEVEL);
00917 #endif
00918 
00919     for (;;) {
00920         /*
00921          * Wait for the arrival of new packets or poll the receiver
00922          * every two seconds.
00923          */
00924         NutEventWait(&ni->ni_rx_rdy, 2000);
00925 
00926         /*
00927          * Fetch all packets from the NIC's internal buffer and pass
00928          * them to the registered handler.
00929          */
00930         while (NicGetPacket(ni, &nb) == 0) {
00931 
00932             /* Discard short packets. */
00933             if (nb->nb_dl.sz < 60) {
00934                 NutNetBufFree(nb);
00935             } else {
00936                 (*ifn->if_recv) (dev, nb);
00937             }
00938         }
00939 
00940         /* We got a weird chip, try to restart it. */
00941         while (ni->ni_insane) {
00942             if (NicStart(ifn->if_mac) == 0) {
00943                 ni->ni_insane = 0;
00944                 ni->ni_tx_queued = 0;
00945                 ni->ni_tx_quelen = 0;
00946                 NutIrqEnable(&NIC_SIGNAL);
00947             } else {
00948                 NutSleep(1000);
00949             }
00950         }
00951     }
00952 }
00953 
00964 int DmOutput(NUTDEVICE * dev, NETBUF * nb)
00965 {
00966     static uint32_t mx_wait = 5000;
00967     int rc = -1;
00968     NICINFO *ni = (NICINFO *) dev->dev_dcb;
00969 
00970     /*
00971      * After initialization we are waiting for a long time to give
00972      * the PHY a chance to establish an Ethernet link.
00973      */
00974     while (rc) {
00975         if (ni->ni_insane) {
00976             break;
00977         }
00978         if (NutEventWait(&ni->ni_mutex, mx_wait)) {
00979             break;
00980         }
00981 
00982         /* Check for packet queue space. */
00983         if (ni->ni_tx_queued > 1) {
00984             if (NutEventWait(&ni->ni_tx_rdy, 500)) {
00985                 /* No queue space. Release the lock and give up. */
00986                 NutEventPost(&ni->ni_mutex);
00987                 break;
00988             }
00989         } else if (NicPutPacket(ni, nb) == 0) {
00990             /* Ethernet works. Set a long waiting time in case we
00991                temporarly lose the link next time. */
00992             rc = 0;
00993             mx_wait = 5000;
00994         }
00995         NutEventPost(&ni->ni_mutex);
00996     }
00997     /*
00998      * Probably no Ethernet link. Significantly reduce the waiting
00999      * time, so following transmission will soon return an error.
01000      */
01001     if (rc) {
01002         mx_wait = 500;
01003     }
01004     return rc;
01005 }
01006 
01024 int DmInit(NUTDEVICE * dev)
01025 {
01026     uint32_t id;
01027     NICINFO *ni = (NICINFO *) dev->dev_dcb;
01028 
01029 #if defined(ELEKTOR_IR1)
01030     outr(PIOA_BSR, _BV(PA20_NCS2_B));
01031     outr(PIOA_PDR, _BV(PA20_NCS2_B));
01032     outr(PIOC_BSR, _BV(PC16_NWAIT_B) | _BV(PC21_NWR0_B) | _BV(PC22_NRD_B));
01033     outr(PIOC_PDR, _BV(PC16_NWAIT_B) | _BV(PC21_NWR0_B) | _BV(PC22_NRD_B));
01034 
01035     outr(SMC_CSR(2)
01036         , (1 << SMC_NWS_LSB)
01037         | SMC_WSEN
01038         | (2 << SMC_TDF_LSB)
01039         | SMC_BAT
01040         | SMC_DBW_16
01041         | (1 << SMC_RWSETUP_LSB)
01042         | (1 << SMC_RWHOLD_LSB)
01043         );
01044 #endif
01045 
01046     /* Probe chip by verifying the identifier registers. */
01047     id = (uint32_t) nic_inb(NIC_VID);
01048     id |= (uint32_t) nic_inb(NIC_VID + 1) << 8;
01049     id |= (uint32_t) nic_inb(NIC_PID) << 16;
01050     id |= (uint32_t) nic_inb(NIC_PID + 1) << 24;
01051     if (id != 0x90000A46) {
01052         return -1;
01053     }
01054 
01055     /* Reset chip. */
01056     if (NicReset()) {
01057         return -1;
01058     }
01059 
01060     /* Clear NICINFO structure. */
01061     memset(ni, 0, sizeof(NICINFO));
01062 
01063     /* Determine bus mode. We do not support 32 bit access. */
01064     ni->ni_iomode = nic_inb(NIC_ISR) & NIC_ISR_IOM;
01065     if (ni->ni_iomode == NIC_ISR_M32) {
01066         return -1;
01067     }
01068 
01069     /* Register interrupt handler. */
01070     if (NutRegisterIrqHandler(&NIC_SIGNAL, NicInterrupt, dev)) {
01071         return -1;
01072     }
01073 
01074     /* Start the receiver thread. */
01075     if (NutThreadCreate("rxi1", NicRxLanc, dev,
01076         (NUT_THREAD_NICRXSTACK * NUT_THREAD_STACK_MULT) + NUT_THREAD_STACK_ADD) == NULL) {
01077         return -1;
01078     }
01079     return 0;
01080 }
01081 
01082 static NICINFO dcb_eth0;
01083 
01089 static IFNET ifn_eth0 = {
01090     IFT_ETHER,                  
01091     0,                          
01092     {0, 0, 0, 0, 0, 0},         
01093     0,                          
01094     0,                          
01095     0,                          
01096     ETHERMTU,                   
01097     0,                          
01098     0,                          
01099     0,                          
01100     NutEtherInput,              
01101     DmOutput,                   
01102     NutEtherOutput              
01103 };
01104 
01114 NUTDEVICE devDM9000E = {
01115     0,                          
01116     {'e', 't', 'h', '0', 0, 0, 0, 0, 0},        
01117     IFTYP_NET,                  
01118     0,                          
01119     0,                          
01120     &ifn_eth0,                  
01121     &dcb_eth0,                  
01122     DmInit,                     
01123     0,                          
01124     0,                          
01125     0,                          
01126 #ifdef __HARVARD_ARCH__
01127     0,                          
01128 #endif
01129     0,                          
01130     0,                          
01131     0                           
01132 };
01133 
01134 #endif /* NIC_BASE_ADDR */
01135 

© 2000-2010 by contributors - visit http://www.ethernut.de/