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

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