Webserver+3d print
Embed:
(wiki syntax)
Show/hide line numbers
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
Generated on Tue Jul 12 2022 17:10:12 by
