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

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