Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers aps3_eth.c Source File

aps3_eth.c

Go to the documentation of this file.
00001 /**
00002  * @file aps3_eth.c
00003  * @brief Cortus APS3 Ethernet MAC controller
00004  *
00005  * @section License
00006  *
00007  * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
00008  *
00009  * This file is part of CycloneTCP Open.
00010  *
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License
00013  * as published by the Free Software Foundation; either version 2
00014  * of the License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software Foundation,
00023  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00024  *
00025  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00026  * @version 1.7.6
00027  **/
00028 
00029 //Switch to the appropriate trace level
00030 #define TRACE_LEVEL NIC_TRACE_LEVEL
00031 
00032 //Dependencies
00033 #include <machine/sfradr.h>
00034 #include <machine/sfradr_eth.h>
00035 #include <machine/ethernet.h>
00036 #include <machine/ic.h>
00037 #undef _ETHERNET_H
00038 #include "core/net.h"
00039 #include "drivers/aps3_eth.h"
00040 #include "debug.h"
00041 
00042 //Transmit buffer
00043 #define txBuffer ((uint8_t *) SFRADR_ETH_TX_MEM_BOTTOM_AD)
00044 //Receive buffer
00045 #define rxBuffer ((uint8_t *) SFRADR_ETH_RX_MEM_BOTTOM_AD)
00046 
00047 //Transmit DMA descriptors
00048 #define txDmaDesc ((Aps3TxDmaDesc *) (SFRADR_ETH_TX_MEM_BOTTOM_AD + \
00049    APS3_ETH_TX_BUFFER_COUNT * APS3_ETH_TX_BUFFER_SIZE))
00050 
00051 //Receive DMA descriptors
00052 #define rxDmaDesc ((Aps3RxDmaDesc *) (SFRADR_ETH_RX_MEM_BOTTOM_AD + \
00053    APS3_ETH_RX_BUFFER_COUNT * APS3_ETH_RX_BUFFER_SIZE))
00054 
00055 //Underlying network interface
00056 static NetInterface *nicDriverInterface;
00057 
00058 
00059 /**
00060  * @brief Cortus APS3 Ethernet MAC driver
00061  **/
00062 
00063 const NicDriver aps3EthDriver =
00064 {
00065    NIC_TYPE_ETHERNET,
00066    ETH_MTU,
00067    aps3EthInit,
00068    aps3EthTick,
00069    aps3EthEnableIrq,
00070    aps3EthDisableIrq,
00071    aps3EthEventHandler,
00072    aps3EthSendPacket,
00073    aps3EthSetMulticastFilter,
00074    aps3EthUpdateMacConfig,
00075    aps3EthWritePhyReg,
00076    aps3EthReadPhyReg,
00077    TRUE,
00078    TRUE,
00079    TRUE,
00080    FALSE
00081 };
00082 
00083 
00084 /**
00085  * @brief Cortus APS3 Ethernet MAC initialization
00086  * @param[in] interface Underlying network interface
00087  * @return Error code
00088  **/
00089 
00090 error_t aps3EthInit(NetInterface *interface)
00091 {
00092    error_t error;
00093 
00094    //Debug message
00095    TRACE_INFO("Initializing Cortus APS3 Ethernet MAC...\r\n");
00096 
00097    //Save underlying network interface
00098    nicDriverInterface = interface;
00099 
00100    //Adjust MDC clock range
00101    eth_miim->miim_clock_divider = 32;
00102 
00103    //PHY transceiver initialization
00104    error = interface->phyDriver->init(interface);
00105    //Failed to initialize PHY transceiver?
00106    if(error)
00107       return error;
00108 
00109    //Reset Ethernet MAC peripheral
00110    eth_mac->sw_reset = 1;
00111 
00112    //Set the MAC address
00113    eth_mac->addr_low = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
00114    eth_mac->addr_high = interface->macAddr.w[2];
00115 
00116    //Initialize hash table
00117    eth_mac->hash_filter_low = 0;
00118    eth_mac->hash_filter_high = 0;
00119 
00120    //Configure the receive filter
00121    eth_mac->unicast = 1;
00122    eth_mac->multicast = 0;
00123    eth_mac->broadcast = 1;
00124    eth_mac->hash = 1;
00125    eth_mac->exact_addr = 1;
00126 
00127    //Default duplex mode
00128    eth_mac->full_duplex = 0;
00129 
00130    //Automatic padding and CRC generation
00131    eth_mac->no_padding = 0;
00132    eth_mac->crc_disable = 0;
00133 
00134    //Set the maximum frame length
00135    eth_mac->max_frame_size = 1518;
00136 
00137    //Set transmit and receive thresholds
00138    eth_tx->tx_threshold = 0;
00139    eth_rx->rx_threshold = 0;
00140 
00141    //Disable indefinite deferral
00142    eth_mac->indefinite_deferral = 0;
00143    //Number of attempts to transmit a frame before aborting
00144    eth_mac->max_deferral = 15;
00145 
00146    //Use default collision window (112 half-octets)
00147    eth_mac->collision_window = 111;
00148    //Maximum Number of Collisions
00149    eth_mac->max_collision = 15;
00150 
00151    //Automatic backoff on collision
00152    eth_mac->no_backoff = 0;
00153 
00154    //Use the default interframe gap (24 half-octets or 96 bits)
00155    eth_mac->interframe_gap = 23;
00156 
00157    //Initialize DMA descriptor lists
00158    aps3EthInitDmaDesc(interface);
00159 
00160    //Configure TX interrupts
00161    eth_tx->tx_irq_mask = TX_IRQ_MASK_MEMORY_AVAILABLE;
00162    //Configure RX interrupts
00163    eth_rx->rx_irq_mask = RX_IRQ_MASK_FRAME_READY;
00164 
00165    //Configure TX interrupt priority
00166    irq[IRQ_ETH_TX].ipl = APS3_ETH_IRQ_PRIORITY;
00167    //Configure RX interrupt priority
00168    irq[IRQ_ETH_RX].ipl = APS3_ETH_IRQ_PRIORITY;
00169 
00170    //Enable transmission and reception
00171    eth_tx->tx_enable = 1;
00172    eth_rx->rx_enable = 1;
00173 
00174    //Accept any packets from the upper layer
00175    osSetEvent(&interface->nicTxEvent);
00176 
00177    //Successful initialization
00178    return NO_ERROR;
00179 }
00180 
00181 
00182 /**
00183  * @brief Initialize DMA descriptor lists
00184  * @param[in] interface Underlying network interface
00185  **/
00186 
00187 void aps3EthInitDmaDesc(NetInterface *interface)
00188 {
00189    uint_t i;
00190 
00191    //Initialize TX DMA descriptor list
00192    for(i = 0; i < APS3_ETH_TX_BUFFER_COUNT; i++)
00193    {
00194       //Transmit buffer address
00195       txDmaDesc[i].addr = (uint32_t) txBuffer + (APS3_ETH_TX_BUFFER_SIZE * i);
00196       //Transmit buffer size
00197       txDmaDesc[i].size = 0;
00198       //Transmit status
00199       txDmaDesc[i].status = 0;
00200    }
00201 
00202    //Initialize RX DMA descriptor list
00203    for(i = 0; i < APS3_ETH_RX_BUFFER_COUNT; i++)
00204    {
00205       //Receive buffer address
00206       rxDmaDesc[i].addr = (uint32_t) rxBuffer + (APS3_ETH_RX_BUFFER_SIZE * i);
00207       //Receive buffer size
00208       rxDmaDesc[i].size = 0;
00209       //Receive status
00210       rxDmaDesc[i].status = 0;
00211    }
00212 
00213    //Start location of the TX descriptor list
00214    eth_tx->tx_desc_base_addr = (uint32_t) txDmaDesc;
00215    //Number of TX descriptors
00216    eth_tx->tx_desc_number = APS3_ETH_TX_BUFFER_COUNT - 1;
00217 
00218    //Start location of the RX descriptor list
00219    eth_rx->rx_desc_base_addr = (uint32_t) rxDmaDesc;
00220    //Number of RX descriptors
00221    eth_rx->rx_desc_number = APS3_ETH_RX_BUFFER_COUNT - 1;
00222 }
00223 
00224 
00225 /**
00226  * @brief Cortus APS3 Ethernet MAC timer handler
00227  *
00228  * This routine is periodically called by the TCP/IP stack to
00229  * handle periodic operations such as polling the link state
00230  *
00231  * @param[in] interface Underlying network interface
00232  **/
00233 
00234 void aps3EthTick(NetInterface *interface)
00235 {
00236    //Handle periodic operations
00237    interface->phyDriver->tick(interface);
00238 }
00239 
00240 
00241 /**
00242  * @brief Enable interrupts
00243  * @param[in] interface Underlying network interface
00244  **/
00245 
00246 void aps3EthEnableIrq(NetInterface *interface)
00247 {
00248    //Enable Ethernet MAC interrupts
00249    irq[IRQ_ETH_TX].ien = 1;
00250    irq[IRQ_ETH_RX].ien = 1;
00251    //Enable Ethernet PHY interrupts
00252    interface->phyDriver->enableIrq(interface);
00253 }
00254 
00255 
00256 /**
00257  * @brief Disable interrupts
00258  * @param[in] interface Underlying network interface
00259  **/
00260 
00261 void aps3EthDisableIrq(NetInterface *interface)
00262 {
00263    //Disable Ethernet MAC interrupts
00264    irq[IRQ_ETH_TX].ien = 0;
00265    irq[IRQ_ETH_RX].ien = 0;
00266    //Disable Ethernet PHY interrupts
00267    interface->phyDriver->disableIrq(interface);
00268 }
00269 
00270 
00271 /**
00272  * @brief Ethernet MAC transmit interrupt service routine
00273  **/
00274 
00275 void aps3EthTxIrqHandler(void)
00276 {
00277    bool_t flag;
00278 
00279    //Enter interrupt service routine
00280    osEnterIsr();
00281 
00282    //This flag will be set if a higher priority task must be woken
00283    flag = FALSE;
00284 
00285    //Check interrupt flag
00286    if(eth_tx->tx_status & TX_IRQ_MASK_MEMORY_AVAILABLE)
00287    {
00288       //Disable TX interrupts
00289       eth_tx->tx_irq_mask = 0;
00290 
00291       //Check whether the TX buffer is available for writing
00292       if(!(eth_tx->tx_desc_status))
00293       {
00294          //Notify the TCP/IP stack that the transmitter is ready to send
00295          flag = osSetEventFromIsr(&nicDriverInterface->nicTxEvent);
00296       }
00297    }
00298 
00299    //Leave interrupt service routine
00300    osExitIsr(flag);
00301 }
00302 
00303 
00304 /**
00305  * @brief Ethernet MAC receive interrupt service routine
00306  **/
00307 
00308 void aps3EthRxIrqHandler(void)
00309 {
00310    bool_t flag;
00311 
00312    //Enter interrupt service routine
00313    osEnterIsr();
00314 
00315    //This flag will be set if a higher priority task must be woken
00316    flag = FALSE;
00317 
00318    //Disable RX interrupts
00319    eth_rx->rx_irq_mask = 0;
00320 
00321    //Set event flag
00322    nicDriverInterface->nicEvent = TRUE;
00323    //Notify the TCP/IP stack of the event
00324    flag = osSetEventFromIsr(&netEvent);
00325 
00326    //Leave interrupt service routine
00327    osExitIsr(flag);
00328 }
00329 
00330 
00331 /**
00332  * @brief Cortus APS3 Ethernet MAC event handler
00333  * @param[in] interface Underlying network interface
00334  **/
00335 
00336 void aps3EthEventHandler(NetInterface *interface)
00337 {
00338    error_t error;
00339 
00340    //A packet has been received?
00341    if(eth_rx->rx_status & RX_IRQ_MASK_FRAME_READY)
00342    {
00343       //Process all pending packets
00344       do
00345       {
00346          //Read incoming packet
00347          error = aps3EthReceivePacket(interface);
00348 
00349          //No more data in the receive buffer?
00350       } while(error != ERROR_BUFFER_EMPTY);
00351    }
00352 
00353    //Re-enable RX interrupts
00354    eth_rx->rx_irq_mask = RX_IRQ_MASK_FRAME_READY;
00355 }
00356 
00357 
00358 /**
00359  * @brief Send a packet
00360  * @param[in] interface Underlying network interface
00361  * @param[in] buffer Multi-part buffer containing the data to send
00362  * @param[in] offset Offset to the first data byte
00363  * @return Error code
00364  **/
00365 
00366 error_t aps3EthSendPacket(NetInterface *interface,
00367    const NetBuffer *buffer, size_t offset)
00368 {
00369    uint_t i;
00370    size_t length;
00371 
00372    //Retrieve the length of the packet
00373    length = netBufferGetLength(buffer) - offset;
00374 
00375    //Check the frame length
00376    if(length > APS3_ETH_TX_BUFFER_SIZE)
00377    {
00378       //The transmitter can accept another packet
00379       osSetEvent(&interface->nicTxEvent);
00380       //Report an error
00381       return ERROR_INVALID_LENGTH;
00382    }
00383 
00384    //Make sure the current buffer is available for writing
00385    if(eth_tx->tx_desc_status)
00386    {
00387       //Re-enable TX interrupts
00388       eth_tx->tx_irq_mask = TX_IRQ_MASK_MEMORY_AVAILABLE;
00389       //Report an error
00390       return ERROR_FAILURE;
00391    }
00392 
00393    //Get the index of the current descriptor
00394    i = eth_tx->tx_desc_produce;
00395 
00396    //Copy user data to the transmit buffer
00397    netBufferRead((uint8_t *) txDmaDesc[i].addr, buffer, offset, length);
00398    //Write the number of bytes to send
00399    txDmaDesc[i].size = length;
00400 
00401    //Start transmission
00402    eth_tx->tx_sw_done = 1;
00403 
00404    //Check whether the next buffer is available for writing
00405    if(!eth_tx->tx_desc_status)
00406    {
00407       //The transmitter can accept another packet
00408       osSetEvent(&interface->nicTxEvent);
00409    }
00410    else
00411    {
00412       //Re-enable TX interrupts
00413       eth_tx->tx_irq_mask = TX_IRQ_MASK_MEMORY_AVAILABLE;
00414    }
00415 
00416    //Data successfully written
00417    return NO_ERROR;
00418 }
00419 
00420 
00421 /**
00422  * @brief Receive a packet
00423  * @param[in] interface Underlying network interface
00424  * @return Error code
00425  **/
00426 
00427 error_t aps3EthReceivePacket(NetInterface *interface)
00428 {
00429    error_t error;
00430    uint_t i;
00431    size_t n;
00432 
00433    //The current buffer is available for reading?
00434    if(!(eth_rx->rx_desc_status))
00435    {
00436       //Point to the current descriptor
00437       i = eth_rx->rx_desc_consume;
00438 
00439       //Make sure no error occurred
00440       if(!(rxDmaDesc[i].status & RX_DESC_RECEIVE_ERROR))
00441       {
00442          //Retrieve the length of the frame
00443          n = rxDmaDesc[i].size;
00444          //Limit the number of data to read
00445          n = MIN(n, APS3_ETH_RX_BUFFER_SIZE);
00446 
00447          //Pass the packet to the upper layer
00448          nicProcessPacket(interface, (uint8_t *) rxDmaDesc[i].addr, n);
00449 
00450          //Valid packet received
00451          error = NO_ERROR;
00452       }
00453       else
00454       {
00455          //The received packet contains an error
00456          error = ERROR_INVALID_PACKET;
00457       }
00458 
00459       //The frame has been has been processed by the software
00460       //and is no longer needed
00461       eth_rx->rx_sw_done = 1;
00462    }
00463    else
00464    {
00465       //No more data in the receive buffer
00466       error = ERROR_BUFFER_EMPTY;
00467    }
00468 
00469    //Return status code
00470    return error;
00471 }
00472 
00473 
00474 /**
00475  * @brief Configure multicast MAC address filtering
00476  * @param[in] interface Underlying network interface
00477  * @return Error code
00478  **/
00479 
00480 error_t aps3EthSetMulticastFilter(NetInterface *interface)
00481 {
00482    uint_t i;
00483    uint_t k;
00484    uint32_t crc;
00485    uint32_t hashTable[2];
00486    MacFilterEntry *entry;
00487 
00488    //Debug message
00489    TRACE_DEBUG("Updating Cortus APS3 hash table...\r\n");
00490 
00491    //Clear hash table
00492    hashTable[0] = 0;
00493    hashTable[1] = 0;
00494 
00495    //The MAC filter table contains the multicast MAC addresses
00496    //to accept when receiving an Ethernet frame
00497    for(i = 0; i < MAC_MULTICAST_FILTER_SIZE; i++)
00498    {
00499       //Point to the current entry
00500       entry = &interface->macMulticastFilter[i];
00501 
00502       //Valid entry?
00503       if(entry->refCount > 0)
00504       {
00505          //Compute CRC over the current MAC address
00506          crc = aps3EthCalcCrc(&entry->addr, sizeof(MacAddr));
00507          //Calculate the corresponding index in the table
00508          k = (crc >> 23) & 0x3F;
00509          //Update hash table contents
00510          hashTable[k / 32] |= (1 << (k % 32));
00511       }
00512    }
00513 
00514    //Disable transmission and reception
00515    eth_tx->tx_enable = 0;
00516    eth_rx->rx_enable = 0;
00517 
00518    //Write the hash table
00519    eth_mac->hash_filter_low = hashTable[0];
00520    eth_mac->hash_filter_high = hashTable[1];
00521 
00522    //Debug message
00523    TRACE_DEBUG("  hash_filter_low = %08" PRIX32 "\r\n", hashTable[0]);
00524    TRACE_DEBUG("  hash_filter_high = %08" PRIX32 "\r\n", hashTable[1]);
00525 
00526    //Re-enable transmission and reception
00527    eth_tx->tx_enable = 1;
00528    eth_rx->rx_enable = 1;
00529 
00530    //Successful processing
00531    return NO_ERROR;
00532 }
00533 
00534 
00535 /**
00536  * @brief Adjust MAC configuration parameters for proper operation
00537  * @param[in] interface Underlying network interface
00538  * @return Error code
00539  **/
00540 
00541 error_t aps3EthUpdateMacConfig(NetInterface *interface)
00542 {
00543    //Disable transmission and reception
00544    eth_tx->tx_enable = 0;
00545    eth_rx->rx_enable = 0;
00546 
00547    //Half-duplex or full-duplex mode?
00548    if(interface->duplexMode == NIC_FULL_DUPLEX_MODE)
00549       eth_mac->full_duplex = 1;
00550    else
00551       eth_mac->full_duplex = 0;
00552 
00553    //Re-enable transmission and reception
00554    eth_tx->tx_enable = 1;
00555    eth_rx->rx_enable = 1;
00556 
00557    //Successful processing
00558    return NO_ERROR;
00559 }
00560 
00561 
00562 /**
00563  * @brief Write PHY register
00564  * @param[in] phyAddr PHY address
00565  * @param[in] regAddr Register address
00566  * @param[in] data Register value
00567  **/
00568 
00569 void aps3EthWritePhyReg(uint8_t phyAddr, uint8_t regAddr, uint16_t data)
00570 {
00571    //Wait for the MII management module to be ready
00572    while(!eth_miim->miim_status);
00573 
00574    //PHY address
00575    eth_miim->miim_phy_addr = phyAddr;
00576    //Register address
00577    eth_miim->miim_phy_register_addr = regAddr;
00578    //Data to be written in the PHY register
00579    eth_miim->miim_data = data;
00580 
00581    //Start a write operation
00582    eth_miim->miim_read_write = 0;
00583    //Wait for the write to complete
00584    while(!eth_miim->miim_status);
00585 }
00586 
00587 
00588 /**
00589  * @brief Read PHY register
00590  * @param[in] phyAddr PHY address
00591  * @param[in] regAddr Register address
00592  * @return Register value
00593  **/
00594 
00595 uint16_t aps3EthReadPhyReg(uint8_t phyAddr, uint8_t regAddr)
00596 {
00597    //Wait for the MII management module to be ready
00598    while(!eth_miim->miim_status);
00599 
00600    //PHY address
00601    eth_miim->miim_phy_addr = phyAddr;
00602    //Register address
00603    eth_miim->miim_phy_register_addr = regAddr;
00604 
00605    //Start a read operation
00606    eth_miim->miim_read_write = 1;
00607    //Wait for the read to complete
00608    while(!eth_miim->miim_status);
00609 
00610    //Return PHY register contents
00611    return eth_miim->miim_data;
00612 }
00613 
00614 
00615 /**
00616  * @brief CRC calculation
00617  * @param[in] data Pointer to the data over which to calculate the CRC
00618  * @param[in] length Number of bytes to process
00619  * @return Resulting CRC value
00620  **/
00621 
00622 uint32_t aps3EthCalcCrc(const void *data, size_t length)
00623 {
00624    uint_t i;
00625    uint_t j;
00626 
00627    //Point to the data over which to calculate the CRC
00628    const uint8_t *p = (uint8_t *) data;
00629    //CRC preset value
00630    uint32_t crc = 0xFFFFFFFF;
00631 
00632    //Loop through data
00633    for(i = 0; i < length; i++)
00634    {
00635       //Update CRC value
00636       crc ^= p[i];
00637 
00638       //The message is processed bit by bit
00639       for(j = 0; j < 8; j++)
00640       {
00641          //Update CRC value
00642          if(crc & 0x00000001)
00643             crc = (crc >> 1) ^ 0xEDB88320;
00644          else
00645             crc = crc >> 1;
00646       }
00647    }
00648 
00649    //Return CRC value
00650    return ~crc;
00651 }
00652