Main Page   Modules   Alphabetical List   Data Structures   File List   Data Fields   Globals   Related Pages  

rtl8139.c

Go to the documentation of this file.
00001 /*!     \file drivers/rtl8139/rtl8139.c
00002  *      \brief RTL8139C(L) single chip fast ethernet controller driver.
00003  *      \author Andrea Righi <drizzt@inwind.it>
00004  *      \date Last update: 2003-11-09
00005  *      \note Copyright (&copy;) 2003 Andrea Righi
00006  *
00007  *      \n
00008  *      Based on drivers/net/8139too.c from Linux.
00009  *      -Andrea Righi.
00010  */
00011 
00012 #include <const.h>
00013 #include <errno.h>
00014 #include <stdlib.h>
00015 #include <string.h>
00016 
00017 #include <arch/i386.h>
00018 #include <arch/interrupt.h>
00019 #include <arch/mem.h>
00020 #include <arch/paging.h>
00021 
00022 #include <kernel/clock.h>
00023 #include <kernel/dma.h>
00024 #include <kernel/kmalloc.h>
00025 #include <kernel/pci.h>
00026 #include <kernel/semaphore.h>
00027 #include <kernel/video.h>
00028 
00029 #include <net/arp.h>
00030 #include <net/eth.h>
00031 #include <net/ip.h>
00032 #include <net/network.h>
00033 #include <net/rtl8139.h>
00034 
00035 //! Symbolic RTL8139 offsets to registers.
00036 enum RTL8139_registers
00037 {
00038         MAC0=0,                 //!< Ethernet hardware address.
00039         MAR0=8,                 //!< Multicast filter.
00040         TxStatus0=0x10,         //!< Transmit status: 4 32bit registers.
00041         TxAddr0=0x20,           //!< Tx descriptors (also 4 32bit).
00042 
00043         RxBuf=0x30,
00044         RxEarlyCnt=0x34,
00045         RxEarlyStatus=0x36,
00046 
00047         ChipCmd=0x37,
00048         RxBufPtr=0x38,
00049         RxBufAddr=0x3A,
00050 
00051         IntrMask=0x3C,
00052         IntrStatus=0x3E,
00053         TxConfig=0x40,
00054         RxConfig=0x44,
00055 
00056         Timer=0x48,             //!< General-purpose counter.
00057         RxMissed=0x4C,          //!< 24 bits valid, write clears.
00058 
00059         Cfg9346=0x50,
00060         Config0=0x51,
00061         Config1=0x52,
00062 
00063         TimerIntrReg=0x54, //!< INTR if gp counter reaches this value.
00064         MediaStatus=0x58,
00065         Config3=0x59,
00066         HltClk=0x5B,
00067         MultiIntr=0x5C,
00068         RevisionID=0x5E,        //!< Revision of the RTL8139 chip.
00069         TxSummary=0x60,
00070 
00071         MII_BMCR=0x62,
00072         MII_BMSR=0x64,
00073 
00074         NWayAdvert=0x66,
00075         NWayLPAR=0x68,
00076         NWayExpansion=0x6A,
00077 
00078         DisconnectCnt=0x6C,
00079         FalseCarrierCnt=0x6E,
00080         NWayTestReg=0x70,
00081 
00082         RxCnt=0x72,             //!< Packet received counter.
00083         CSCR=0x74,      //!< Chip status and configuration register.
00084 
00085         PhyParm1=0x78,          //!< Undocumented.
00086         TwisterParm=0x7c,       //!< Undocumented.
00087         PhyParm2=0x80,          //!< Undocumented.
00088 
00089         // From 0x84 onwards are a number of power management/wakeup    //
00090         // frame definitions we will probably never need to know about. //
00091 };
00092 
00093 enum ChipCmdBits
00094 {
00095         CmdReset=0x10,
00096         CmdRxEnb=0x08,
00097         CmdTxEnb=0x04,
00098         RxBufEmpty=0x01,
00099 };
00100 
00101 //! Interrupt Status Register bits.
00102 enum IntrStatusBits
00103 {
00104         PCIErr=0x8000,
00105         PCSTimeout=0x4000,
00106         CableLenChange= 0x2000,
00107         RxFIFOOver=0x40,
00108         RxUnderrun=0x20,
00109         RxOverflow=0x10,
00110         TxErr=0x08,
00111         TxOK=0x04,
00112         RxErr=0x02,
00113         RxOK=0x01,
00114         IntrDefault = RxOK | TxOK,
00115 };
00116 
00117 //! Transmit Status Register bits.
00118 enum TxStatusBits
00119 {
00120         TxHostOwns=0x2000,
00121         TxUnderrun=0x4000,
00122         TxStatOK=0x8000,
00123         TxOutOfWindow=0x20000000,
00124         TxAborted=0x40000000,
00125         TxCarrierLost=0x80000000,
00126 };
00127 
00128 //! Receive Status Register bits.
00129 enum RxStatusBits
00130 {
00131         RxMulticast=0x8000,
00132         RxPhysical=0x4000,
00133         RxBroadcast=0x2000,
00134         RxBadSymbol=0x0020,
00135         RxRunt=0x0010,
00136         RxTooLong=0x0008,
00137         RxCRCErr=0x0004,
00138         RxBadAlign=0x0002,
00139         RxStatusOK=0x0001,
00140 };
00141 
00142 //! Media Status Register bits.
00143 enum MediaStatusBits
00144 {
00145         MSRTxFlowEnable=0x80,
00146         MSRRxFlowEnable=0x40,
00147         MSRSpeed10=0x08,
00148         MSRLinkFail=0x04,
00149         MSRRxPauseFlag=0x02,
00150         MSRTxPauseFlag=0x01,
00151 };
00152 
00153 enum MIIBMCRBits
00154 {
00155         BMCRReset=0x8000,
00156         BMCRSpeed100=0x2000,
00157         BMCRNWayEnable=0x1000,
00158         BMCRRestartNWay=0x0200,
00159         BMCRDuplex=0x0100,
00160 };
00161 
00162 enum CSCRBits
00163 {
00164         CSCR_LinkOKBit=0x0400,
00165         CSCR_LinkChangeBit=0x0800,
00166         CSCR_LinkStatusBits=0x0f000,
00167         CSCR_LinkDownOffCmd=0x003c0,
00168         CSCR_LinkDownCmd=0x0f3c0,
00169 };
00170 
00171 //! Bits in Receive Configuration Register.
00172 enum rx_mode_bits
00173 {
00174         RxCfgWrap=0x80,
00175         AcceptErr=0x20,
00176         AcceptRunt=0x10,
00177         AcceptBroadcast=0x08,
00178         AcceptMulticast=0x04,
00179         AcceptMyPhys=0x02,
00180         AcceptAllPhys=0x01,
00181 };
00182 
00183 //! Pointer to the RTL8139 structure.
00184 rtl8139_t *rtl=NULL;
00185 
00186 //! \brief Halt the RTL8139 card and free the logical device.
00187 //! \param rtl
00188 //!     An indirect pointer to the RTL8139 structure. Must be
00189 //!     passed as an indirect pointer because it will be modified
00190 //!     inside this routine!!!
00191 void rtl8139_close(rtl8139_t **rtl)
00192 {
00193         // Disable interrupts by clearing the interrupt mask            //
00194         out16((*rtl)->iobase + IntrMask, 0);
00195         // Stop the chip's Tx and Rx DMA processes                      //
00196         out((*rtl)->iobase + ChipCmd, 0);
00197 
00198         // Put the chip in low-power mode                               //
00199         out((*rtl)->iobase + Cfg9346, 0xC0);
00200         out((*rtl)->iobase + Config1, 0x03);
00201         // 'R' would leave the clock running                            //
00202         out((*rtl)->iobase + HltClk, 'H');
00203 
00204         if ( (*rtl) != NULL )
00205         {
00206                 // Disable the IRQ line                                 //
00207                 disable_IRQ((*rtl)->irq);
00208 
00209                 // Deallocate the ring buffers                          //
00210                 dma_phys_free((*rtl)->rx_phys, RX_BUF_LEN);
00211                 dma_phys_free((*rtl)->tx_phys, TX_BUF_SIZE*NUM_TX_DESC);
00212 
00213                 // Deallocate the logical structure                     //
00214                 kfree((*rtl));
00215                 *rtl = NULL;
00216         }
00217 }
00218 
00219 //! \brief Read RTL8139 informations from the EEPROM.
00220 //! \param rtl The RTL8139 structure.
00221 //! \param location The location in the EEPROM to read.
00222 //! \return The value read from the EEPROM.
00223 static unsigned rtl8139_read_eeprom(rtl8139_t *rtl, unsigned location)
00224 {
00225         int i;
00226         unsigned int retval = 0;
00227         long ee_addr = rtl->iobase + Cfg9346;
00228         int read_cmd = location | EE_READ_CMD;
00229 
00230         out(ee_addr, EE_ENB & ~EE_CS);
00231         out(ee_addr, EE_ENB);
00232 
00233         // Shift the read command bits out                              //
00234         for (i = 10; i >= 0; i--)
00235         {
00236                 int dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
00237                 out(ee_addr, EE_ENB | dataval);
00238                 eeprom_delay();
00239                 out(ee_addr, EE_ENB | dataval | EE_SHIFT_CLK);
00240                 eeprom_delay();
00241         }
00242 
00243         out(ee_addr, EE_ENB);
00244         eeprom_delay();
00245 
00246         for (i = 16; i > 0; i--)
00247         {
00248                 out(ee_addr, EE_ENB | EE_SHIFT_CLK);
00249                 eeprom_delay();
00250                 retval = (retval << 1) | ((in(ee_addr) & EE_DATA_READ) ? 1 : 0);
00251                 out(ee_addr, EE_ENB);
00252                 eeprom_delay();
00253         }
00254 
00255         // Terminate the EEPROM access                                  //
00256         out(ee_addr, ~EE_CS);
00257         return(retval);
00258 }
00259 
00260 //! \brief Enable/disable the promiscuous mode for the RTL8139 card.
00261 //! \param rtl The RTL8139 structure.
00262 //! \param on
00263 //!     \li #TRUE enable the promiscuous mode;
00264 //!     \li #FALSE disable the promiscuous mode.
00265 void rtl8139_promisc(rtl8139_t *rtl, bool on)
00266 {
00267         uint8_t rxc;
00268         dword IF = GET_IF();
00269 
00270         disable();
00271         rxc = in(rtl->iobase + RxConfig);
00272         if ( on )
00273                 out(rtl->iobase + RxConfig, rxc | AcceptAllPhys);
00274         else
00275                 out(rtl->iobase + RxConfig, rxc & (~AcceptAllPhys));
00276         rtl->promisc = on;
00277         SET_IF(IF);
00278 }
00279 
00280 //! \brief Reset the RTL8139 ethernet card.
00281 //! \param rtl The RTL8139 structure.
00282 void rtl8139_reset(rtl8139_t *rtl)
00283 {
00284         unsigned i;
00285         timeout_t elapsed;
00286         dword IF = GET_IF();
00287 
00288         // Send the software-reset command                              //
00289         out(rtl->iobase + ChipCmd, CmdReset);
00290 
00291         // Reset the Rx and Tx rings                                    //
00292         rtl->cur_rx = 0;
00293         rtl->cur_tx = 0;
00294 
00295         // Give the chip 10ms to finish the reset                       //
00296         enable();
00297         set_timeout(&elapsed, 10);
00298         while ( (in(rtl->iobase + ChipCmd) & CmdReset) != 0 )
00299                 if ( is_timeout(&elapsed) ) break;
00300         SET_IF(IF);
00301 
00302         // Set-up the card MAC address register                         //
00303         for (i=0; i<_countof(rtl->station_address); i++)
00304                 out(rtl->iobase + MAC0 + i, rtl->station_address[i]);
00305 
00306         // Must enable Tx/Rx before setting transfer thresholds!        //
00307         out(rtl->iobase + ChipCmd, CmdRxEnb | CmdTxEnb);
00308          // Accept no frames yet!                                       //
00309         out32(rtl->iobase + RxConfig,
00310                 (RX_FIFO_THRESH<<13) | (RX_BUF_LEN_IDX<<11) | (RX_DMA_BURST<<8));
00311         out32(rtl->iobase + TxConfig, (TX_DMA_BURST<<8) | 0x03000000);
00312 
00313         // Configure the RX buffer                                      //
00314         out32(rtl->iobase + RxBuf, rtl->rx_phys);
00315 
00316         // Init Tx buffer DMA addresses                                 //
00317         for (i = 0; i < NUM_TX_DESC; i++)
00318                 out32(rtl->iobase + TxAddr0 + (i * 4), rtl->tx_phys + (TX_BUF_SIZE*i));
00319 
00320         // Reset the missed packets counter                             //
00321         out32(rtl->iobase + RxMissed, 0);
00322 
00323         // Set RX mode                                                  //
00324         if ( rtl->promisc )
00325                 out(rtl->iobase + RxConfig, AcceptBroadcast | AcceptMyPhys | AcceptAllPhys);
00326         else
00327                 out(rtl->iobase + RxConfig, AcceptBroadcast | AcceptMyPhys);
00328 
00329         // If we add multicast support, the MAR0 register would have to //
00330         // be initialized to 0xFFFFFFFF.FFFFFFFF (two 32 bit accesses). //
00331         // Etherboot only needs broadcast (for ARP/RARP/BOOTP/DHCP) and //
00332         // unicast.                                                     //
00333 
00334         // Start the chip's Tx and Rx process                           //
00335         out(rtl->iobase + ChipCmd, CmdRxEnb | CmdTxEnb);
00336 
00337         // Disable all known interrupts by setting the interrupt mask   //
00338         // out16(rtl->iobase + IntrMask, 0x0000);
00339 
00340         // Enable all known interrupts                                  //
00341         // out16(rtl->iobase + IntrMask, PCIErr | PCSTimeout | RxUnderrun |
00342         //      RxOverflow | RxFIFOOver |
00343         //      TxErr | TxOK | RxErr | RxOK);
00344 
00345         // Enable default interrupt mask (RxOK | TxOK)                  //
00346         out16(rtl->iobase + IntrMask, IntrDefault);
00347 }
00348 
00349 //! \brief Initialize the RTL8139 driver.
00350 //! \param promisc
00351 //!     \li #TRUE initialize the card and put it in promiscuous mode;
00352 //!     \li #FALSE initialize the card and don't put it in promiscuous
00353 //!     mode.
00354 //! \return
00355 //!     \li 0 if we can successfully enable the RTL8139 ethernet card;
00356 //!     \li -#ENXIO if the device if not present on PCI bus;
00357 //!     \li -#EIO if we cannot read ethernet card informations;
00358 int rtl8139_init(bool promisc)
00359 {
00360         pci_cfg_t cfg;
00361         unsigned i;
00362         dword IF = GET_IF();
00363 
00364         // Search an ethernet device on PCI and enable it!              //
00365         cfg.base_class = 0x02;  // Ethernet class                       //
00366         cfg.sub_class  = 0x00;  // Ethernet sub_class                   //
00367         cfg.interface  = 0x00;  // Ethernet interface                   //
00368 
00369         if ( !pci_find_cfg(&cfg, TRUE) )
00370         {
00371                 return(-ENXIO);
00372         }
00373 
00374         // Close a previous RTL8139 structure if present                //
00375         if ( rtl != NULL )
00376         {
00377                 rtl8139_close(&rtl);
00378         }
00379 
00380         // Allocate the RTL8139 structure                               //
00381         rtl = kmalloc(sizeof(rtl8139_t));
00382         if ( !rtl )
00383                 return(-ENOMEM);
00384 
00385         memset(rtl, 0, sizeof(rtl8139_t));
00386 
00387         // Setup the I/O base register                                  //
00388         for (i=0; i<6; i++)
00389                 if ( (rtl->iobase=cfg.base[i]) != 0 ) break;
00390 
00391         // Check if the device I/O base address is valid                //
00392         if ( rtl->iobase == 0 )
00393         {
00394                 kfree(rtl);
00395                 return(-EIO);
00396         }
00397 
00398         // Setup the IRQ line                                           //
00399         disable();
00400         rtl->irq = cfg.irq;
00401         install_irq_handler( rtl->irq, (void *)&rtl8139_handler );
00402 
00403         // Bring the chip out of low-power mode                         //
00404         out(rtl->iobase + Config1, 0x00);
00405 
00406         // Read the MAC address                                         //
00407         if (rtl8139_read_eeprom(rtl, 0) != 0xFFFF)
00408         {
00409                 // Read from EEPROM                                     //
00410                 unsigned short *ap = (unsigned short*)rtl->station_address;
00411                 for (i = 0; i < 3; i++)
00412                 *ap++ = rtl8139_read_eeprom(rtl, i + 7);
00413         }
00414         else
00415         {
00416                 // Read from MAC0 register                              //
00417                 unsigned char *ap = (unsigned char*)rtl->station_address;
00418                 for (i = 0; i < 6; i++)
00419                         *ap++ = in(rtl->iobase + MAC0 + i);
00420         }
00421 
00422         // Read the media informations                                  //
00423         rtl->speed10 = (in(rtl->iobase + MediaStatus) & MSRSpeed10) != 0;
00424         rtl->fullduplex = (in16(rtl->iobase + MII_BMCR) & BMCRDuplex) != 0;
00425 
00426         // Setup the promiscuous mode                                   //
00427         rtl->promisc = promisc;
00428 
00429         // Initialize the Rx and Tx rings buffer                        //
00430         if ( !(rtl->rx_ring) )
00431         {
00432                 rtl->rx_phys = (addr_t)dma_phys_alloc(RX_BUF_LEN);
00433                 rtl->rx_ring = PHYSICAL( (uint8_t *)(rtl->rx_phys) );
00434         }
00435         if ( !(rtl->tx_ring) )
00436         {
00437                 rtl->tx_phys = (addr_t)dma_phys_alloc(TX_BUF_SIZE*NUM_TX_DESC);
00438                 rtl->tx_ring = PHYSICAL( (uint8_t *)(rtl->tx_phys) );
00439         }
00440 
00441         // Initialize the RTL8139 mutex semaphore                       //
00442         INIT_MUTEX(&rtl->mutex);
00443 
00444         // Hardware reset of the RTL8139                                //
00445         rtl8139_reset(rtl);
00446 
00447         // Well done!                                                   //
00448         SET_IF(IF);
00449         return(0);
00450 }
00451 
00452 //! \brief Get the MAC hardware address of the RTL8139 ethernet card.
00453 //! \return A pointer to the MAC address value.
00454 //! \exception NULL if a RTL8139 card has not been initialized.
00455 uint8_t *get_eth_mac_addr()
00456 {
00457         if (rtl)
00458                 return(rtl->station_address);
00459         else
00460                 return(NULL);
00461 }
00462 
00463 //! \brief Get the pointer of the RTL8139 device structure.
00464 //! \return
00465 //!     \li a pointer of the RTL8139 structure if it has been
00466 //!     initialized;
00467 //!     \li 0 if the RTL8139 card has not been initialized.
00468 rtl8139_t *get_rtl8139_device()
00469 {
00470         return( rtl );
00471 }
00472 
00473 //! \brief Send an ethernet packet to the physiscal layer.
00474 //! \param rtl The RTL8139 structure.
00475 //! \param data The data to be sent.
00476 //! \param len The size of the data to be sent in bytes.
00477 //! \return The number of bytes sent, or -1 if an error occurred.
00478 /**
00479  *      \todo Set up a timeout for the transmitted packets.
00480  */
00481 int send_rtl8139_packet(rtl8139_t *rtl, const void *data, size_t len)
00482 {
00483         // Check if the RTL8139 card has been configured                //
00484         if ( !rtl ) return(-1);
00485 
00486         // Adapt the packet length to the Tx buffer size                //
00487         // This should be done by the ethernet layer...                 //
00488         len = MIN(len, TX_BUF_SIZE);
00489 
00490         // Enter critical region                                        //
00491         DOWN(&rtl->mutex);
00492 
00493         // kprintf("\n\rlooking for buffer %u", desc);
00494         if ( in32(rtl->iobase + TxStatus0 + (rtl->cur_tx * 4)) & TxHostOwns )
00495         {
00496                 // Found a free buffer!                         //
00497 
00498                 // Copy the raw data to the Tx ring             //
00499                 memcpy(rtl->tx_ring + (TX_BUF_SIZE*rtl->cur_tx), data, len);
00500 
00501                 // NOTE: RTL8139 doesn't auto-pad! Be sure that //
00502                 // the ethernet layer has done it correctly     //
00503                 while (len < ETH_MIN_LEN)
00504                         (rtl->tx_ring + (TX_BUF_SIZE*rtl->cur_tx))[len++] = '\0';
00505 
00506                 // Move the data from the Tx buffer to the      //
00507                 // internal transmit FIFO in PCI bus master     //
00508                 // mode                                         //
00509                 out32(rtl->iobase + TxAddr0 + rtl->cur_tx * 4,
00510                         rtl->tx_phys + (TX_BUF_SIZE * rtl->cur_tx));
00511                 out32(rtl->iobase + TxStatus0 + rtl->cur_tx * 4,
00512                         ((TX_FIFO_THRESH<<11) & 0x003F0000) | len);
00513 
00514                 // Select new descriptor for transmition        //
00515                 rtl->cur_tx = (rtl->cur_tx + 1) % NUM_TX_DESC;
00516 
00517                 // End of critical region                       //
00518                 UP(&rtl->mutex);
00519 
00520                 // Return the byte transmitted                          //
00521                 return(len);
00522         }
00523         // End of critical region                                       //
00524         UP(&rtl->mutex);
00525 
00526         // Buffer not available!                                        //
00527         return(-1);
00528 }
00529 
00530 //! \brief Handle a transmitted packet event.
00531 //! \param rtl The RTL8139 structure.
00532 void rtl8139_handle_tx(rtl8139_t *rtl)
00533 {
00534         unsigned int i, status;
00535 
00536         for(i=0; i<NUM_TX_DESC; i++)
00537         {
00538                 // We must read the status of every descriptor when     //
00539                 // a Tx interrupt occurs                                //
00540                 status = in32(rtl->iobase + TxStatus0 + (i * 4));
00541                 #ifdef DEBUG
00542                 kprintf("\n\rbuffer %u status %#010x", i, status);
00543                 #endif
00544         }
00545 }
00546 
00547 //! \brief Handle a received packet event.
00548 //! \param rtl The RTL8139 structure.
00549 void rtl8139_handle_rx(rtl8139_t *rtl)
00550 {
00551         uint32_t ring_offs, rx_size, rx_status;
00552         rxpacket_t *packet;
00553 
00554         while ((in(rtl->iobase + ChipCmd) & RxBufEmpty) == 0)
00555         {
00556                 ring_offs = rtl->cur_rx % RX_BUF_LEN;
00557 
00558                 // Read status+size of the next frame from DMA          //
00559                 // ring buffer                                          //
00560                 rx_status = *(uint32_t *)(rtl->rx_ring + ring_offs);
00561                 rx_size = rx_status >> 16;
00562                 rx_status &= 0xFFFF;
00563 
00564                 if (
00565                         (rx_status & (RxBadSymbol | RxRunt | RxTooLong | RxCRCErr | RxBadAlign)) ||
00566                         (rx_size < ETH_MIN_LEN) ||
00567                         (rx_size > ETH_FRAME_LEN + 4)
00568                 )
00569                 {
00570                         #ifdef DEBUG
00571                         kprintf("\n\rRX error! status=%#010x rx_size=%#010x\n\r", rx_status, rx_size);
00572                         #endif
00573                         rtl8139_reset(rtl);
00574                         return;
00575                 }
00576 
00577                 // Allocate a buffer to store the packet                //
00578                 packet = kmalloc(sizeof(rxpacket_t) - 1 + rx_size - 4);
00579                 if (packet == NULL)
00580                         return;
00581 
00582                 // No one cares about the FCS                           //
00583                 packet->length = rx_size - 4;
00584 
00585                 // Received a good packet                               //
00586                 if (ring_offs + 4 + rx_size - 4 > RX_BUF_LEN)
00587                 {
00588                         int semi_count = RX_BUF_LEN - ring_offs - 4;
00589 
00590                         memcpy(packet->data, rtl->rx_ring + ring_offs + 4, semi_count);
00591                         memcpy(packet->data + semi_count, rtl->rx_ring, rx_size - 4 - semi_count);
00592                         #ifdef DEBUG
00593                         kprintf("\n\rRX packet (%u+%u bytes)", semi_count, rx_size - 4 - semi_count);
00594                         #endif
00595                 }
00596                 else
00597                 {
00598                         memcpy(packet->data, rtl->rx_ring + ring_offs + 4, packet->length);
00599                         #ifdef DEBUG
00600                         kprintf("\n\rRX packet (%u bytes)", rx_size-4);
00601                         #endif
00602                 }
00603                 #if 0
00604                 // Dump the received packet content                     //
00605                 kprintf("\n\r");
00606                 for (i=0; i<packet->length; i++)
00607                         kprintf("%02X ", packet->data[i]);
00608                 #endif
00609                 rtl->cur_rx = (rtl->cur_rx + rx_size + 4 + 3) & ~3;
00610                 out16(rtl->iobase + RxBufPtr, rtl->cur_rx - 16);
00611 
00612                 // Send the packet to the upper layer                   //
00613                 to_eth_layer((ethernet_t *)packet->data, packet->length);
00614 
00615                 // Free the packet sturcture                            //
00616                 kfree(packet);
00617         }
00618         return;
00619 }
00620 
00621 /** \ingroup Handlers */
00622 //! \brief
00623 //!     The RTL8139 interrupt handler routine. It is invoked every
00624 //!     time that an ethernet packet is received or when a packet
00625 //!     has been transmitted.
00626 void rtl8139_handler()
00627 {
00628         uint16_t status;
00629 
00630         out16(rtl->iobase + IntrMask, 0);
00631 
00632         status = in16(rtl->iobase + IntrStatus);
00633         // Acknowledge all known interrupts                             //
00634         out16(rtl->iobase + IntrStatus, status & ~(RxFIFOOver | RxOverflow | RxOK));
00635 
00636         if (status & (RxOK | RxErr))
00637                 rtl8139_handle_rx(rtl);
00638         else
00639                 if (status & (TxOK | TxErr))
00640                         rtl8139_handle_tx(rtl);
00641                 // #ifdef DEBUG
00642                 else
00643                         kprintf("\n\rRTL8139: unknown interrupt: isr = %#010x\n", status);
00644                 // #endif
00645 
00646         // Re-enable interrupts from the RTL8139 card                   //
00647         out16(rtl->iobase + IntrStatus, status & (RxFIFOOver | RxOverflow | RxOK));
00648         out16(rtl->iobase + IntrMask, IntrDefault);
00649 }
00650 
00651 //! \brief
00652 //!     Print the current RTL8139 card configuration on the console.
00653 //! \param rtl The RTL8139 structure.
00654 void rtl8139_dump_info(rtl8139_t *rtl)
00655 {
00656         in_addr_t ip, netmask, ip_bcast;
00657 
00658         if ( !rtl )
00659         {
00660                 // The card is not configured                           //
00661                 kprintf("\n\rUsage: ifconfig [up|down]");
00662                 kprintf("\n\rRTL8139: ethernet card not configured!\n\r");
00663                 return;
00664         }
00665 
00666         // Dump the device informations                                 //
00667         kprintf("\n\rRTL8139: card configured @ I/O base=%04X IRQ=%u", rtl->iobase, rtl->irq);
00668         // Dump the MAC address                                         //
00669         kprintf("\n\rRTL8139: MAC address %02x:%02x:%02x:%02x:%02x:%02x",
00670                 rtl->station_address[0], rtl->station_address[1], rtl->station_address[2],
00671                 rtl->station_address[3], rtl->station_address[4], rtl->station_address[5]
00672         );
00673         // Dump the media informations                                  //
00674         kprintf("\n\rRTL8139: %sMbps %s-duplex",
00675                 rtl->speed10 ? "10" : "100",
00676                 rtl->fullduplex ? "full" : "half"
00677         );
00678         // Print the promiscuous mode flag                              //
00679         kprintf("\n\rRTL8139: promiscuous mode %s", (rtl->promisc) ? "ENABLED" : "DISABLED");
00680         // Print virtual memory rings pointers                          //
00681         kprintf("\n\rRTL8139: rx_ring=%p<->%p, tx_ring=%p<->%p",
00682                 rtl->rx_ring, rtl->rx_ring + RX_BUF_LEN,
00683                 rtl->tx_ring, rtl->tx_ring + PAGE_ALIGN_UP(TX_BUF_SIZE*NUM_TX_DESC)
00684         );
00685         // Well done!                                                   //
00686         kprintf("\n\rRTL8139: OK, ethernet card is ready!");
00687 
00688         ip = ntohl( get_host_ip() );
00689         netmask = ntohl( get_host_netmask() );
00690         ip_bcast = (~netmask) | (ip & netmask);
00691         kprintf("\n\n\rhost ip=%u.%u.%u.%u netmask=%u.%u.%u.%u broadcast=%u.%u.%u.%u\n\r",
00692                 IP_A(ip), IP_B(ip), IP_C(ip), IP_D(ip),
00693                 IP_A(netmask), IP_B(netmask), IP_C(netmask), IP_D(netmask),
00694                 IP_A(ip_bcast), IP_B(ip_bcast), IP_C(ip_bcast), IP_D(ip_bcast)
00695         );
00696 }

Generated on Fri Feb 20 15:32:16 2004 for Minirighi by doxygen1.2.18