Nut/OS  4.10.3
API Reference
ax88796.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  * Initially taken from Marek Hummel's port of the Realtek driver.
00034  *
00035  * Revision 1.0  2004/07/20 17:29:08  MarekH
00036  */
00037 
00038 /*
00039  * $Log$
00040  * Revision 1.9  2009/01/17 11:26:37  haraldkipp
00041  * Getting rid of two remaining BSD types in favor of stdint.
00042  * Replaced 'u_int' by 'unsinged int' and 'uptr_t' by 'uintptr_t'.
00043  *
00044  * Revision 1.8  2008/08/28 11:12:15  haraldkipp
00045  * Added interface flags, which will be required to implement Ethernet ioctl
00046  * functions.
00047  *
00048  * Revision 1.7  2008/08/11 06:59:07  haraldkipp
00049  * BSD types replaced by stdint types (feature request #1282721).
00050  *
00051  * Revision 1.6  2007/05/02 11:22:51  haraldkipp
00052  * Added multicast table entry.
00053  *
00054  * Revision 1.5  2006/06/28 17:10:15  haraldkipp
00055  * Include more general header file for ARM.
00056  *
00057  * Revision 1.4  2006/03/02 19:48:19  haraldkipp
00058  * Replaced inline assembly nops with their portable counterparts.
00059  *
00060  * Revision 1.3  2006/01/23 17:27:47  haraldkipp
00061  * Previous hack to fix missing network configuration routines disabled
00062  * non-volatile memory access for ARM.
00063  *
00064  * Revision 1.2  2005/10/22 08:55:47  haraldkipp
00065  * CPU specific headers moved to subdirectories for the CPU family.
00066  *
00067  * Revision 1.1  2005/07/26 18:02:26  haraldkipp
00068  * Moved from dev.
00069  *
00070  * Revision 1.1  2005/04/05 17:47:48  haraldkipp
00071  * Initial check in. For ARM only.
00072  *
00073  */
00074 
00075 #include <arch/arm.h>
00076 
00077 #include <string.h>
00078 //#include <stdio.h>
00079 
00080 #include <sys/atom.h>
00081 #include <sys/heap.h>
00082 #include <sys/thread.h>
00083 #include <sys/event.h>
00084 #include <sys/timer.h>
00085 #include <sys/confnet.h>
00086 
00087 #include <dev/irqreg.h>
00088 #include <dev/ax88796.h>
00089 #include "reg_ax88796.h"
00090 
00091 #define ASIX_RESET_PIN 10
00092 
00093 static NICINFO dcb_eth0;
00094 
00099 
00100 
00106 static IFNET ifn_eth0 = {
00107     IFT_ETHER,                  
00108     0,                          
00109     {0, 0, 0, 0, 0, 0},         
00110     0,                          
00111     0,                          
00112     0,                          
00113     ETHERMTU,                   
00114     0,                          
00115     0,                          
00116     0,                          
00117     NutEtherInput,              
00118     AsixOutput,                 
00119     NutEtherOutput              
00120 };
00121 
00131 NUTDEVICE devAx88796 = {
00132     0,                          /* Pointer to next device. */
00133     {'e', 't', 'h', '0', 0, 0, 0, 0, 0},        /* Unique device name. */
00134     IFTYP_NET,                  /* Type of device. */
00135     0,                          /* Base address. */
00136     0,                          /* First interrupt number. */
00137     &ifn_eth0,                  /* Interface control block. */
00138     &dcb_eth0,                  /* Driver control block. */
00139     AsixInit,                   /* Driver initialization routine. */
00140     0,                          /* Driver specific control function. */
00141     0,                          /* Read from device. */
00142     0,                          /* Write to device. */
00143     0,                          /* Open a device or file. */
00144     0,                          /* Close a device or file. */
00145     0                           /* Request file size. */
00146 };
00147 
00151 struct nic_pkt_header {
00152     uint8_t ph_status;           
00153     uint8_t ph_nextpg;           
00154     uint16_t ph_size;            
00155 };
00156 
00157 /*
00158  * This delay has been added by Bengt Florin and is used to minimize 
00159  * the effect of the IORDY line during reads. Bengt contributed a
00160  * more versatile loop, which unfortunately wasn't portable to the
00161  * ImageCraft compiler.
00162  *
00163  * Both versions depend on the CPU clock and had been tested with
00164  * 14.7456 MHz.
00165  */
00166 void Delay16Cycles(void)
00167 {
00168     _NOP();
00169     _NOP();
00170     _NOP();
00171     _NOP();
00172     _NOP();
00173     _NOP();
00174     _NOP();
00175     _NOP();
00176     _NOP();
00177     _NOP();
00178     _NOP();
00179     _NOP();
00180     _NOP();
00181     _NOP();
00182     _NOP();
00183     _NOP();
00184 }
00185 
00186 //==============================================================================
00192 static uint16_t MIIPutGet(uint16_t data, uint8_t bitCount)
00193 {
00194     uint16_t rc = 0;
00195     uint16_t mask;
00196     uint8_t i;
00197 
00198     mask = 1 << (bitCount - 1);
00199 
00200     for (i = 0; i < bitCount; i++) {
00201 
00202         /* send data to MII */
00203         if (data & mask) {
00204             Asix_Write(MII_EEP, (Asix_Read(MII_EEP) | MII_EEP_MDO));
00205         } else {
00206             Asix_Write(MII_EEP, (Asix_Read(MII_EEP) & ~(MII_EEP_MDO)));
00207         }
00208         /* clock and data recieve from MII */
00209         Asix_Write(MII_EEP, (Asix_Read(MII_EEP) | MII_EEP_MDC));        //clock up
00210         Delay16Cycles();
00211 
00212         data <<= 1;
00213         rc <<= 1;
00214         rc |= (Asix_Read(MII_EEP) & MII_EEP_MDI) != 0;  //read MII
00215         Asix_Write(MII_EEP, (Asix_Read(MII_EEP) & ~(MII_EEP_MDC)));     //clock down
00216     }
00217     return rc;
00218 }
00219 
00220 //==============================================================================
00227 uint16_t NicPhyRead(uint8_t reg)
00228 {
00229     uint16_t rc = 0;
00230 
00231     /* Select Bank 0. */
00232     Asix_Write(CR, (Asix_Read(CR) & ~(CR_PS0)));
00233 
00234     /* Preamble. Send idle pattern, 32 '1's to synchronize MII. */
00235     MIIPutGet(0xFFFF, 16);
00236     MIIPutGet(0xFFFF, 16);
00237 
00238     /* Start(01), Read(10), PhyAdr(10000) */
00239     MIIPutGet(0xD0, 9);
00240 
00241     /* Reg address<5:0> */
00242     MIIPutGet(reg, 5);
00243 
00244     /* TA(Z0), no support high-Z */
00245     MIIPutGet(0x0, 1);
00246 
00247     /* Read data from internel PHY */
00248     rc = MIIPutGet(0, 16);
00249 
00250     return rc;
00251 }
00252 
00253 //==============================================================================
00262 void NicPhyWrite(uint8_t reg, uint16_t val)
00263 {
00264 
00265     /* Select Bank 0. */
00266     Asix_Write(CR, (Asix_Read(CR) & ~(CR_PS0)));
00267 
00268     /* Preamble. Send idle pattern, 32 '1's to synchronize MII. */
00269     MIIPutGet(0xFFFF, 16);
00270     MIIPutGet(0xFFFF, 16);
00271 
00272     /* Start(01), Write(01), PhyAdr(10000) */
00273     MIIPutGet(0xB0, 9);
00274 
00275     /* Reg address<5:0> */
00276     MIIPutGet(reg, 5);
00277 
00278     /* TA(01) */
00279     MIIPutGet(0x02, 2);
00280 
00281     /* Write data to internel PHY */
00282     MIIPutGet(val, 16);
00283 }
00284 
00285 //==============================================================================
00286 
00290 static void NicCompleteDma(void)
00291 {
00292     uint8_t i;
00293 
00294     /* Check that we have a DMA complete flag. */
00295     do {
00296         i = Asix_Read(PG0_ISR);
00297     } while ((i & ISR_RDC) == 0);
00298 
00299     /* Complete remote dma. */
00300     Asix_Write(CR, CR_START | CR_RD2);
00301 
00302     /* Reset remote dma complete flag. */
00303     Asix_Write(PG0_ISR, ISR_RDC);
00304 
00305     /* Wait for intterupt flag. */
00306     Delay16Cycles();
00307 }
00308 
00309 //==============================================================================
00315 static int NicReset(void)
00316 {
00317     int tmp;
00318     //uint16_t test;
00319 
00320     //printf("NicReset()\n");
00321     outr(PIO_PER, _BV(ASIX_RESET_PIN));  /* Set PIO Enable Register */
00322     outr(PIO_OER, _BV(ASIX_RESET_PIN));  /* Set PIO Status Register */
00323     outr(PIO_SODR, _BV(ASIX_RESET_PIN)); /* ASIX_RESET_PIN = 1 */
00324     NutDelay(100);
00325     outr(PIO_CODR, _BV(ASIX_RESET_PIN)); /* ASIX_RESET_PIN = 0 */
00326 
00327     /* wait for PHY to come out of reset. */
00328     tmp = 10;
00329     while (1) {
00330         NutDelay(255);
00331         if (!(Asix_Read(TR) & TR_RST_B))
00332             break;
00333         if (tmp-- == 0)
00334             return -1;
00335     }
00336 
00337     //test = NicPhyRead(PHY_MR2);
00338     //printf("PHY_MR2 = 0x%.04x\n\r", test);
00339     //test = NicPhyRead(PHY_MR3);
00340     //printf("PHY_MR3 = 0x%.04x\n\r", test);
00341 
00342 
00343 /* Following actions will fix the problem of long auto negotiation. */
00344 //      NicPhyWrite(0x00,0x0800);
00345 //      NutSleep(2500);
00346 //      NicPhyWrite(0x00,0x1200); /* set speed to auto */
00347     return 0;
00348 }
00349 
00350 //==============================================================================
00351 /*
00352  * Fires up the network interface. NIC interrupts
00353  * should have been disabled when calling this
00354  * function.
00355  *
00356  * \param mac Six byte unique MAC address.
00357  */
00358 static int NicStart(CONST uint8_t * mac)
00359 {
00360     uint8_t i;
00361 
00362     //printf("NicStart()\n");
00363     if (NicReset())
00364         return -1;
00365 
00366     /* Stop the NIC, abort DMA, page 0. */
00367     Asix_Write(CR, (CR_RD2 | CR_STOP));
00368 
00369     /* Selects word-wide DMA transfers. */
00370     Asix_Write(PG0_DCR, DCR_WTS);
00371 
00372     /* Load data byte count for remote DMA. */
00373     Asix_Write(PG0_RBCR0, 0x00);
00374     Asix_Write(PG0_RBCR1, 0x00);
00375 
00376     /* Temporarily set receiver to monitor mode. */
00377     Asix_Write(PG0_RCR, RCR_MON);
00378 
00379     /* Transmitter set to internal loopback mode. */
00380     Asix_Write(PG0_TCR, TCR_LB0);
00381 
00382     /* Initialize Recieve Buffer Ring. */
00383     Asix_Write(PG0_BNRY, RXSTART_INIT);
00384     Asix_Write(PG0_PSTART, RXSTART_INIT);
00385     Asix_Write(PG0_PSTOP, RXSTOP_INIT);
00386 
00387     /* Clear interrupt status. */
00388     Asix_Write(PG0_ISR, 0xFF);
00389 
00390     /* Initialize interrupt mask. */
00391     Asix_Write(PG0_IMR, IMR_PRXE | IMR_PTXE | IMR_RXEE | IMR_TXEE | IMR_OVWE);
00392 
00393     /* Stop the NIC, abort DMA, page 1. */
00394     Asix_Write(CR, (CR_PS0 | CR_RD2 | CR_STOP));
00395     Delay16Cycles();
00396 
00397     /* Set Physical address - MAC. */
00398     for (i = 0; i < 6; i++) {
00399         Asix_Write(PG1_PAR0 + i, mac[i]);
00400     }
00401 
00402     /* Set Multicast address. */
00403     for (i = 0; i < 8; i++) {
00404         Asix_Write(PG1_MAR0 + i, 0x00);
00405     }
00406 
00407     /* Set Current pointer point. */
00408     Asix_Write(PG1_CPR, RXSTART_INIT + 1);
00409 
00410     /* Start the NIC, Abort DMA, page 0. */
00411     Asix_Write(CR, (CR_RD2 | CR_START));        // stop the NIC, abort DMA, page 0   
00412     Delay16Cycles();
00413 
00414     /* Select media interfac. */
00415     Asix_Write(GPOC, 0x10);
00416 
00417     /* Check PHY speed setting 100base = full duplex, 10base > half duplex. */
00418     if (Asix_Read(GPI) & 0x04) {
00419         //printf("Full duplex\n");
00420         Asix_Write(PG0_TCR, TCR_FDU);
00421     }
00422     else {
00423         //printf("Half duplex\n");
00424         Asix_Write(PG0_TCR, 0);
00425     }
00426 
00427     /* Enable receiver and set accept broadcast. */
00428     //Asix_Write(PG0_RCR, (RCR_INTT | RCR_AB));
00429     Asix_Write(PG0_RCR, RCR_AB);
00430 
00431     return 0;
00432 }
00433 
00434 //==============================================================================
00435 /*
00436  * Write data block to the NIC.
00437  */
00438 static void NicWrite(uint8_t * buf, uint16_t len)
00439 {
00440     register uint16_t *wp = (uint16_t *) buf;
00441 
00442     if (len & 1)
00443         len++;
00444     len >>= 1;
00445     //printf("Write(%u): ", len);
00446     while (len--) {
00447         //printf("%04X ", *wp);
00448         Asix_WriteWord(DATAPORT, *wp);
00449         wp++;
00450     }
00451     //putchar('\n');
00452 }
00453 
00454 //==============================================================================
00455 /*
00456  * Read data block from the NIC.
00457  */
00458 static void NicRead(uint8_t * buf, uint16_t len)
00459 {
00460     register uint16_t *wp = (uint16_t *) buf;
00461 
00462     if (len & 1)
00463         len++;
00464     len >>= 1;
00465     //printf("Read(%u): ", len);
00466     while (len--) {
00467         *wp = Asix_ReadWord(DATAPORT);
00468         //printf("%04X ", *wp);
00469         wp++;
00470     }
00471     //putchar('\n');
00472 }
00473 
00474 //==============================================================================
00485 static NETBUF *NicGetPacket(void)
00486 {
00487     NETBUF *nb = 0;
00488     struct nic_pkt_header hdr;
00489     uint16_t count;
00490     uint8_t nextpg;
00491     uint8_t bnry;
00492     uint8_t curr;
00493     uint8_t drop = 0;
00494 
00495     /* we don't want to be interrupted by NIC owerflow */
00496     NutEnterCritical();
00497 
00498     /*
00499      * Get the current page pointer. It points to the page where the NIC 
00500      * will start saving the next incoming packet.
00501      */
00502     curr = Asix_Read(PG0_CPR);
00503     //printf("curr=%02X\n", curr);
00504 
00505     /*
00506      * Get the pointer to the last page we read from. The following page
00507      * is the one where we start reading. If it's equal to the current
00508      * page pointer, then there's nothing to read. In this case we return
00509      * a null pointer.
00510      */
00511     if ((bnry = Asix_Read(PG0_BNRY) + 1) >= RXSTOP_INIT) {
00512         //printf("bnry=%02X?\n", bnry);
00513         bnry = RXSTART_INIT;
00514     }
00515     if (bnry == curr) {
00516         //printf("bnry=%02X\n", bnry);
00517         NutJumpOutCritical();
00518         return 0;
00519     }
00520     /*
00521      * Read the NIC specific packet header (4 bytes).
00522      */
00523     Asix_Write(PG0_RBCR0, sizeof(struct nic_pkt_header));
00524     Asix_Write(PG0_RBCR1, 0);
00525     Asix_Write(PG0_RSAR0, 0);
00526     Asix_Write(PG0_RSAR1, bnry);
00527     Asix_Write(CR, CR_START | CR_RD0);
00528     Delay16Cycles();
00529 
00530     NicRead((uint8_t *) & hdr, sizeof(struct nic_pkt_header));
00531     NicCompleteDma();
00532     //printf("[S=%02X N=%02X L=%u]", hdr.ph_status, hdr.ph_nextpg, hdr.ph_size);
00533 
00534     /*
00535      *  Check packet length. Silently discard packets of illegal size.
00536      */
00537     if (hdr.ph_size < 60 + sizeof(struct nic_pkt_header) || hdr.ph_size > 1514 + sizeof(struct nic_pkt_header)) {
00538         //printf("Drop\n");
00539         drop = 1;
00540     }
00541 
00542     /*
00543      * Calculate the page of the next packet. If it differs from the
00544      * pointer in the packet header, we discard the whole buffer
00545      * and return a null pointer.
00546      */
00547 
00548 
00549 //      nextpg = hdr.ph_nextpg;
00550 //  bnry = hdr.ph_nextpg - 1;
00551 //      if(bnry < RXSTART_INIT) bnry = RXSTOP_INIT - 1; 
00552 
00553 //  printf("hdr.ph_size = %02u\n\r",hdr.ph_size);
00554 //  printf("hdr.ph_nextpg = %02x\n\r",hdr.ph_nextpg);
00555 
00556     nextpg = bnry + (hdr.ph_size >> 8) + ((hdr.ph_size & 0xFF) != 0);
00557     //printf("[nextpg = %02x ->", nextpg);
00558 
00559     if (nextpg >= RXSTOP_INIT) {
00560         nextpg -= RXSTOP_INIT;
00561         nextpg += RXSTART_INIT;
00562     }
00563     if (nextpg != hdr.ph_nextpg) {
00564         uint8_t nextpg1 = nextpg + 1;
00565         if (nextpg1 >= RXSTOP_INIT) {
00566             nextpg1 -= RXSTOP_INIT;
00567             nextpg1 += RXSTART_INIT;
00568         }
00569         //HK if (nextpg1 != hdr.ph_nextpg) {
00570         //HK    return (NETBUF *) 0xFFFF;
00571         //HK }
00572         nextpg = nextpg1;
00573     }
00574     //printf("%02x]", nextpg);
00575 
00576 
00577     /*
00578      * Check packet status. It should have set bit 0, but
00579      * even without this bit packets seem to be OK.
00580      */
00581     //printf("Drop=%u Status=%02X\n", drop, hdr.ph_status & 0x0E);
00582     if (!drop && ((hdr.ph_status & 0x0E) == 0)) {
00583 
00584         /* Allocate a NETBUF. */
00585         count = hdr.ph_size - sizeof(struct nic_pkt_header);
00586         //printf("Count=%u\n", count);
00587         if ((nb = NutNetBufAlloc(0, NBAF_DATALINK, count))) {
00588             /*
00589              * Set remote dma byte count and
00590              * start address. Don't read the
00591              * header again.
00592              */
00593             Asix_Write(PG0_RBCR0, count);
00594             Asix_Write(PG0_RBCR1, count >> 8);
00595             Asix_Write(PG0_RSAR0, sizeof(struct nic_pkt_header));
00596             Asix_Write(PG0_RSAR1, bnry);
00597 
00598             /*
00599              * Perform the read.
00600              */
00601             Asix_Write(CR, CR_START | CR_RD0);
00602             Delay16Cycles();
00603             NicRead(nb->nb_dl.vp, count);
00604             NicCompleteDma();
00605         }
00606     }
00607 
00608     /*
00609      * Set boundary register to the last page we read.
00610      * This also drops packets with errors
00611      */
00612     if (--nextpg < RXSTART_INIT)
00613         nextpg = RXSTOP_INIT - 1;
00614     Asix_Write(PG0_BNRY, nextpg);
00615     NutExitCritical();
00616     return nb;
00617 
00618 }
00619 
00620 //==============================================================================
00621 /*
00622  * \brief Handle NIC overflows.
00623  *
00624  * When a receiver buffer overflow occurs, the NIC will defer any subsequent 
00625  * action until properly restarted.
00626  *
00627  * This routine is called within interrupt context, which introduces a big
00628  * problem. It waits for the last transmission to finish, which may take
00629  * several milliseconds. Since Nut/OS 3.5, we do not support nested interrupts
00630  * on AVR systems anymore. So this routine may now increase interrupt
00631  * latency in an unacceptable way. The solution might be to handle overflows
00632  * in the receiver thread.
00633  *
00634  * In any case, this routines needs a major redesign. But it has been
00635  * tested in its current form to gracefully withstand ping floods. Thanks
00636  * to Bengt Florin for contributing his code, which provides much more
00637  * stability than its predecessor.
00638  */
00639 static uint8_t NicOverflow(volatile uint8_t * base)
00640 {
00641     unsigned int cr;
00642     unsigned int resend = 0;
00643     unsigned int curr;
00644 
00645     /*
00646      * Wait for any transmission in progress. Save the command register, 
00647      * so we can later determine, if NIC transmitter has been interrupted. 
00648      * or reception in progress.
00649      */
00650     while (Asix_Read(CR) & CR_TXP);
00651     cr = Asix_Read(CR);
00652 
00653     /*
00654      * Get the current page pointer. It points to the page where the NIC 
00655      * will start saving the next incoming packet.
00656      */
00657     Asix_Write(CR, CR_STOP | CR_RD2 | CR_PS0);
00658     curr = Asix_Read(PG1_CPR);
00659     Asix_Write(CR, CR_STOP | CR_RD2);
00660 
00661     /* Clear remote byte count register. */
00662     Asix_Write(PG0_RBCR0, 0);
00663     Asix_Write(PG0_RBCR1, 0);
00664 
00665     /* Check for any incomplete transmission. */
00666     if ((cr & CR_TXP) && ((Asix_Read(PG0_ISR) & (ISR_PTX | ISR_TXE)) == 0)) {
00667         resend = 1;
00668     }
00669 
00670     /* Enter loopback mode and restart the NIC. */
00671     Asix_Write(PG0_TCR, TCR_LB0);
00672     Asix_Write(CR, CR_START | CR_RD2);
00673 
00674     /* 
00675      * Discard all packets from the receiver buffer. Set boundary 
00676      * register to the last page we read. 
00677      */
00678     if (--curr < TXSTART_INIT) {
00679         curr = RXSTOP_INIT - 1;
00680     }
00681     Asix_Write(PG0_BNRY, curr);
00682 
00683     /* Switch from loopback to normal mode mode. */
00684     Asix_Write(PG0_TCR, 0);
00685 
00686     /* Re-invoke any interrupted transmission. */
00687     if (resend) {
00688         Asix_Write(CR, CR_START | CR_TXP | CR_RD2);
00689     }
00690 
00691     /* Finally clear the overflow flag */
00692     Asix_Write(PG0_ISR, ISR_OVW);
00693     return resend;
00694 }
00695 
00696 //==============================================================================
00697 static int NicPutPacket(NETBUF * nb)
00698 {
00699     uint16_t sz;                 // packed size
00700     uint16_t send_sz;            // send packed size, min 60
00701     static uint8_t first_put = 0;
00702     int tmp;
00703 
00704 
00705     /*
00706      * Fix problem after power on.
00707      */
00708     if (first_put != 1) {
00709         Asix_Write(CR, 0x21);
00710         NutDelay(1);
00711         Asix_Write(CR, 0x22);
00712         first_put = 1;
00713     }
00714 
00715     /*
00716      * Calculate the number of bytes to be send. Do not
00717      * send packets larger than 1518 bytes.
00718      */
00719     sz = nb->nb_dl.sz + nb->nb_nw.sz + nb->nb_tp.sz + nb->nb_ap.sz;
00720     if (sz > 1518)
00721         return -1;
00722     //printf("Asix Send %u\n", sz);
00723 
00724     /*
00725      * Calculate the number of min bytes. Pad will be
00726      * added when packet lenght less than 60. Enable in TCR reg. PD = 0. 
00727      */
00728     send_sz = sz;
00729     if (sz <= 60)
00730         send_sz = 60;
00731 
00732     /* Disable Asix interrupts. */
00733     NutEnterCritical();
00734     /* start the NIC */
00735     Asix_Write(CR, (CR_RD2 | CR_START));
00736 
00737     /*
00738      * Bengt Florin introduces polling mode for the transmitter. Be
00739      * aware, that this may introduce other problems. If a high
00740      * priority thread is waiting for the transmitter, it may hold
00741      * the CPU for more than 1.2 milliseconds in worst cases.
00742      */
00743     tmp = 120;
00744     while ((Asix_Read(CR) & CR_TXP) && tmp--)
00745         NutDelay(1);
00746 
00747 
00748     /* set start address for remote DMA operation */
00749     Asix_Write(PG0_RSAR0, 0x00);
00750     Asix_Write(PG0_RSAR1, TXSTART_INIT);
00751 
00752     /* load data byte count for remote DMA */
00753     Asix_Write(PG0_RBCR0, (unsigned char) (sz));
00754     Asix_Write(PG0_RBCR1, (unsigned char) (sz >> 8));
00755 
00756     /* do remote write operation */
00757     Asix_Write(CR, (CR_RD1 | CR_START));
00758 
00759     /* Transfer the Ethernet frame. */
00760     NicWrite(nb->nb_dl.vp, nb->nb_dl.sz);
00761     NicWrite(nb->nb_nw.vp, nb->nb_nw.sz);
00762     NicWrite(nb->nb_tp.vp, nb->nb_tp.sz);
00763     NicWrite(nb->nb_ap.vp, nb->nb_ap.sz);
00764 
00765     /* Complete remote dma. */
00766     NicCompleteDma();
00767 
00768     /* Clear interrupt flags. */
00769     Asix_Write(PG0_ISR, (ISR_PTX | ISR_TXE));
00770     Delay16Cycles();
00771 
00772     /* Set size and pointer to data. */
00773     Asix_Write(CR, CR_START | CR_RD2);
00774     //printf("Asix Start Send\n");
00775     Asix_Write(PG0_TBCR0, (unsigned char) (send_sz));
00776     Asix_Write(PG0_TBCR1, (unsigned char) ((send_sz) >> 8));
00777     Asix_Write(PG0_TPSR, TXSTART_INIT);
00778 
00779     /* Start transmission. */
00780     Asix_Write(CR, CR_START | CR_TXP | CR_RD2);
00781 
00782     /* Enable Asix interrupts. */
00783     NutExitCritical();
00784     return 0;
00785 }
00786 
00787 //==============================================================================
00792 THREAD(NicRxAsix, arg)
00793 {
00794 
00795     NUTDEVICE *dev;
00796     IFNET *ifn;
00797     NICINFO *ni;
00798     NETBUF *nb;
00799 
00800     /* Hack! Unfortunately no parameter passing with ARM */
00801     dev = &devAx88796;
00802 
00803     ifn = (IFNET *) dev->dev_icb;
00804     ni = (NICINFO *) dev->dev_dcb;
00805 
00806     /*
00807      * This is a temporary hack. Due to a change in initialization,
00808      * we may not have got a MAC address yet. Wait until a valid one
00809      * has been set.
00810      */
00811     while (!ETHER_IS_UNICAST(ifn->if_mac)) {
00812         NutSleep(10);
00813     }
00814 
00815     NutEnterCritical();
00816     NicStart(ifn->if_mac);
00817     NutExitCritical();
00818 
00819     /* Run at high priority. */
00820     //printf("Increase prio\n");
00821     NutThreadSetPriority(9);
00822 
00823     while (1) {
00824         //printf("-------- Wait rx\n");
00825         NutEventWait(&ni->ni_rx_rdy, 0);
00826         //printf("-------- Got rx\n");
00827         /*
00828          * Fetch all packets from the NIC's internal
00829          * buffer and pass them to the registered handler.
00830          */
00831         do {
00832             nb = NicGetPacket();
00833             /* The sanity check may fail because the controller is too busy.
00834                restart the NIC. */
00835             if (0) {            //HK if ((u_short)nb == 0xFFFF) {
00836                 NicStart(ifn->if_mac);
00837 //                ni->ni_rx_size_errors++;
00838             } else if (nb) {
00839                 ni->ni_rx_packets++;
00840                 (*ifn->if_recv) (dev, nb);
00841             }
00842         } while (nb);
00843     }
00844 }
00845 
00846 //==============================================================================
00847 /*
00848  * NIC interrupt entry.
00849  */
00850 static void NicInterrupt(void *arg)
00851 {
00852     uint8_t isr;
00853     volatile uint8_t *base = (uint8_t *) (((NUTDEVICE *) arg)->dev_base);
00854     NICINFO *ni = (NICINFO *) ((NUTDEVICE *) arg)->dev_dcb;
00855 
00856     ni->ni_interrupts++;
00857 
00858     isr = Asix_Read(PG0_ISR);
00859     Delay16Cycles();
00860     Asix_Write(PG0_ISR, isr);
00861 
00862     //if(isr)
00863     //    printf("%02X\n", isr);
00864     //else
00865     //    return;
00866 
00867     /*
00868      * Recover from receive buffer overflow. This may take some
00869      * time, so we enable global interrupts but keep NIC
00870      * interrupts disabled.
00871      */
00872     if (isr & ISR_OVW) {
00873         ni->ni_rx_pending++;
00874         if (NicOverflow(base))
00875             ni->ni_tx_bsy++;
00876         else {
00877             NutEventPostAsync(&ni->ni_tx_rdy);
00878         }
00879         ni->ni_overruns++;
00880     } else {
00881 
00882         /*
00883          * If this is a transmit interrupt, then a packet has been sent. 
00884          * So we can clear the transmitter busy flag and wake up the 
00885          * transmitter thread.
00886          */
00887         if (isr & (ISR_PTX | ISR_TXE)) {
00888             ni->ni_tx_bsy = 0;
00889         }
00890 
00891         /*
00892          * If this is a receive interrupt, then wake up the receiver 
00893          * thread.
00894          */
00895         if (isr & ISR_PRX) {
00896             ni->ni_rx_pending++;
00897             //printf("Post %lX\n", (uint32_t) ni->ni_rx_rdy);
00898             NutEventPostFromIrq(&ni->ni_rx_rdy);
00899         }
00900 
00901         /* Rx error. */
00902         if (isr & ISR_RXE) {
00903             if (Asix_Read(PG0_RSR) & RSR_FAE)
00904                 ni->ni_rx_frame_errors++;
00905             if (Asix_Read(PG0_RSR) & RSR_CR)
00906                 ni->ni_rx_crc_errors++;
00907             if (Asix_Read(PG0_RSR) & RSR_MPA)
00908                 ni->ni_rx_missed_errors++;
00909         }
00910     }
00911 }
00912 
00913 void NicInterruptEntry(void) __attribute__ ((naked));
00914 void NicInterruptEntry(void)
00915 {
00916     IRQ_ENTRY();
00917     //putchar('i');
00918     NicInterrupt(&devAx88796);
00919     IRQ_EXIT();
00920 }
00921 
00922 //==============================================================================
00933 int AsixOutput(NUTDEVICE * dev, NETBUF * nb)
00934 {
00935     int rc = -1;
00936     NICINFO *ni = (NICINFO *) dev->dev_dcb;
00937 
00938     if (NicPutPacket(nb) == 0) {
00939         ni->ni_tx_packets++;
00940         rc = 0;
00941     }
00942     return rc;
00943 }
00944 
00945 //==============================================================================
00963 int AsixInit(NUTDEVICE * dev)
00964 {
00965     //printf("Set confnet\n");
00966     confnet.cd_size = sizeof(CONFNET);
00967     strcpy(confnet.cd_name, "eth0");
00968     memset(confnet.cdn_mac, 0xFF, 6);
00969 
00970     /* Disable NIC interrupt and clear NICINFO structure. */
00971     //printf("Clear nicinfo\n");
00972     memset(dev->dev_dcb, 0, sizeof(NICINFO));
00973 
00974     /*
00975      * Start the receiver thread.
00976      */
00977     //printf("Create rxi5(%lX)\n", (u_long) dev);
00978     NutThreadCreate("rxi5", NicRxAsix, dev, 1024);
00979 
00980     outr(PIO_PDR, _BV(9));
00981     /* Register interrupt handler and enable interrupts. */
00982     /* Disable timer 0 interrupts. */
00983     outr(AIC_IDCR, _BV(IRQ0_ID));
00984     /* Set the TC0 IRQ handler address */
00985     outr(AIC_SVR(IRQ0_ID), (unsigned int) NicInterruptEntry);
00986     /* Set the trigg and priority for timer 0 interrupt */
00987     /* Level 7 is highest, level 0 lowest. */
00988     outr(AIC_SMR(IRQ0_ID), (AIC_SRCTYPE_EXT_NEGATIVE_EDGE | 5));
00989     /* Clear timer 0 interrupt */
00990     outr(AIC_ICCR, _BV(IRQ0_ID));
00991     /* Enable timer 0 interrupts */
00992     outr(AIC_IECR, _BV(IRQ0_ID));
00993 
00994     //printf("======== AsixcInit done ========\n");
00995     return 0;
00996 }
00997