aps3_eth_driver.c
Go to the documentation of this file.
1 /**
2  * @file aps3_eth_driver.c
3  * @brief Cortus APS3 Ethernet MAC controller
4  *
5  * @section License
6  *
7  * Copyright (C) 2010-2018 Oryx Embedded SARL. All rights reserved.
8  *
9  * This file is part of CycloneTCP Open.
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24  *
25  * @author Oryx Embedded SARL (www.oryx-embedded.com)
26  * @version 1.9.0
27  **/
28 
29 //Switch to the appropriate trace level
30 #define TRACE_LEVEL NIC_TRACE_LEVEL
31 
32 //Dependencies
33 #include <machine/sfradr.h>
34 #include <machine/sfradr_eth.h>
35 #include <machine/ethernet.h>
36 #include <machine/ic.h>
37 #undef _ETHERNET_H
38 #include "core/net.h"
40 #include "debug.h"
41 
42 //Transmit buffer
43 #define txBuffer ((uint8_t *) SFRADR_ETH_TX_MEM_BOTTOM_AD)
44 //Receive buffer
45 #define rxBuffer ((uint8_t *) SFRADR_ETH_RX_MEM_BOTTOM_AD)
46 
47 //Transmit DMA descriptors
48 #define txDmaDesc ((Aps3TxDmaDesc *) (SFRADR_ETH_TX_MEM_BOTTOM_AD + \
49  APS3_ETH_TX_BUFFER_COUNT * APS3_ETH_TX_BUFFER_SIZE))
50 
51 //Receive DMA descriptors
52 #define rxDmaDesc ((Aps3RxDmaDesc *) (SFRADR_ETH_RX_MEM_BOTTOM_AD + \
53  APS3_ETH_RX_BUFFER_COUNT * APS3_ETH_RX_BUFFER_SIZE))
54 
55 //Underlying network interface
56 static NetInterface *nicDriverInterface;
57 
58 
59 /**
60  * @brief Cortus APS3 Ethernet MAC driver
61  **/
62 
64 {
66  ETH_MTU,
77  TRUE,
78  TRUE,
79  TRUE,
80  FALSE
81 };
82 
83 
84 /**
85  * @brief Cortus APS3 Ethernet MAC initialization
86  * @param[in] interface Underlying network interface
87  * @return Error code
88  **/
89 
91 {
92  error_t error;
93 
94  //Debug message
95  TRACE_INFO("Initializing Cortus APS3 Ethernet MAC...\r\n");
96 
97  //Save underlying network interface
98  nicDriverInterface = interface;
99 
100  //Adjust MDC clock range
101  eth_miim->miim_clock_divider = 32;
102 
103  //PHY transceiver initialization
104  error = interface->phyDriver->init(interface);
105  //Failed to initialize PHY transceiver?
106  if(error)
107  return error;
108 
109  //Reset Ethernet MAC peripheral
110  eth_mac->sw_reset = 1;
111 
112  //Set the MAC address
113  eth_mac->addr_low = interface->macAddr.w[0] | (interface->macAddr.w[1] << 16);
114  eth_mac->addr_high = interface->macAddr.w[2];
115 
116  //Initialize hash table
117  eth_mac->hash_filter_low = 0;
118  eth_mac->hash_filter_high = 0;
119 
120  //Configure the receive filter
121  eth_mac->unicast = 1;
122  eth_mac->multicast = 0;
123  eth_mac->broadcast = 1;
124  eth_mac->hash = 1;
125  eth_mac->exact_addr = 1;
126 
127  //Default duplex mode
128  eth_mac->full_duplex = 0;
129 
130  //Automatic padding and CRC generation
131  eth_mac->no_padding = 0;
132  eth_mac->crc_disable = 0;
133 
134  //Set the maximum frame length
135  eth_mac->max_frame_size = 1518;
136 
137  //Set transmit and receive thresholds
138  eth_tx->tx_threshold = 0;
139  eth_rx->rx_threshold = 0;
140 
141  //Disable indefinite deferral
142  eth_mac->indefinite_deferral = 0;
143  //Number of attempts to transmit a frame before aborting
144  eth_mac->max_deferral = 15;
145 
146  //Use default collision window (112 half-octets)
147  eth_mac->collision_window = 111;
148  //Maximum Number of Collisions
149  eth_mac->max_collision = 15;
150 
151  //Automatic backoff on collision
152  eth_mac->no_backoff = 0;
153 
154  //Use the default interframe gap (24 half-octets or 96 bits)
155  eth_mac->interframe_gap = 23;
156 
157  //Initialize DMA descriptor lists
158  aps3EthInitDmaDesc(interface);
159 
160  //Configure TX interrupts
161  eth_tx->tx_irq_mask = TX_IRQ_MASK_MEMORY_AVAILABLE;
162  //Configure RX interrupts
163  eth_rx->rx_irq_mask = RX_IRQ_MASK_FRAME_READY;
164 
165  //Configure TX interrupt priority
166  irq[IRQ_ETH_TX].ipl = APS3_ETH_IRQ_PRIORITY;
167  //Configure RX interrupt priority
168  irq[IRQ_ETH_RX].ipl = APS3_ETH_IRQ_PRIORITY;
169 
170  //Enable transmission and reception
171  eth_tx->tx_enable = 1;
172  eth_rx->rx_enable = 1;
173 
174  //Accept any packets from the upper layer
175  osSetEvent(&interface->nicTxEvent);
176 
177  //Successful initialization
178  return NO_ERROR;
179 }
180 
181 
182 /**
183  * @brief Initialize DMA descriptor lists
184  * @param[in] interface Underlying network interface
185  **/
186 
188 {
189  uint_t i;
190 
191  //Initialize TX DMA descriptor list
192  for(i = 0; i < APS3_ETH_TX_BUFFER_COUNT; i++)
193  {
194  //Transmit buffer address
195  txDmaDesc[i].addr = (uint32_t) txBuffer + (APS3_ETH_TX_BUFFER_SIZE * i);
196  //Transmit buffer size
197  txDmaDesc[i].size = 0;
198  //Transmit status
199  txDmaDesc[i].status = 0;
200  }
201 
202  //Initialize RX DMA descriptor list
203  for(i = 0; i < APS3_ETH_RX_BUFFER_COUNT; i++)
204  {
205  //Receive buffer address
206  rxDmaDesc[i].addr = (uint32_t) rxBuffer + (APS3_ETH_RX_BUFFER_SIZE * i);
207  //Receive buffer size
208  rxDmaDesc[i].size = 0;
209  //Receive status
210  rxDmaDesc[i].status = 0;
211  }
212 
213  //Start location of the TX descriptor list
214  eth_tx->tx_desc_base_addr = (uint32_t) txDmaDesc;
215  //Number of TX descriptors
216  eth_tx->tx_desc_number = APS3_ETH_TX_BUFFER_COUNT - 1;
217 
218  //Start location of the RX descriptor list
219  eth_rx->rx_desc_base_addr = (uint32_t) rxDmaDesc;
220  //Number of RX descriptors
221  eth_rx->rx_desc_number = APS3_ETH_RX_BUFFER_COUNT - 1;
222 }
223 
224 
225 /**
226  * @brief Cortus APS3 Ethernet MAC timer handler
227  *
228  * This routine is periodically called by the TCP/IP stack to
229  * handle periodic operations such as polling the link state
230  *
231  * @param[in] interface Underlying network interface
232  **/
233 
234 void aps3EthTick(NetInterface *interface)
235 {
236  //Handle periodic operations
237  interface->phyDriver->tick(interface);
238 }
239 
240 
241 /**
242  * @brief Enable interrupts
243  * @param[in] interface Underlying network interface
244  **/
245 
247 {
248  //Enable Ethernet MAC interrupts
249  irq[IRQ_ETH_TX].ien = 1;
250  irq[IRQ_ETH_RX].ien = 1;
251 
252  //Enable Ethernet PHY interrupts
253  interface->phyDriver->enableIrq(interface);
254 }
255 
256 
257 /**
258  * @brief Disable interrupts
259  * @param[in] interface Underlying network interface
260  **/
261 
263 {
264  //Disable Ethernet MAC interrupts
265  irq[IRQ_ETH_TX].ien = 0;
266  irq[IRQ_ETH_RX].ien = 0;
267 
268  //Disable Ethernet PHY interrupts
269  interface->phyDriver->disableIrq(interface);
270 }
271 
272 
273 /**
274  * @brief Ethernet MAC transmit interrupt service routine
275  **/
276 
278 {
279  bool_t flag;
280 
281  //Enter interrupt service routine
282  osEnterIsr();
283 
284  //This flag will be set if a higher priority task must be woken
285  flag = FALSE;
286 
287  //Check interrupt flag
288  if(eth_tx->tx_status & TX_IRQ_MASK_MEMORY_AVAILABLE)
289  {
290  //Disable TX interrupts
291  eth_tx->tx_irq_mask = 0;
292 
293  //Check whether the TX buffer is available for writing
294  if(!(eth_tx->tx_desc_status))
295  {
296  //Notify the TCP/IP stack that the transmitter is ready to send
297  flag = osSetEventFromIsr(&nicDriverInterface->nicTxEvent);
298  }
299  }
300 
301  //Leave interrupt service routine
302  osExitIsr(flag);
303 }
304 
305 
306 /**
307  * @brief Ethernet MAC receive interrupt service routine
308  **/
309 
311 {
312  bool_t flag;
313 
314  //Enter interrupt service routine
315  osEnterIsr();
316 
317  //This flag will be set if a higher priority task must be woken
318  flag = FALSE;
319 
320  //Disable RX interrupts
321  eth_rx->rx_irq_mask = 0;
322 
323  //Set event flag
324  nicDriverInterface->nicEvent = TRUE;
325  //Notify the TCP/IP stack of the event
326  flag = osSetEventFromIsr(&netEvent);
327 
328  //Leave interrupt service routine
329  osExitIsr(flag);
330 }
331 
332 
333 /**
334  * @brief Cortus APS3 Ethernet MAC event handler
335  * @param[in] interface Underlying network interface
336  **/
337 
339 {
340  error_t error;
341 
342  //A packet has been received?
343  if(eth_rx->rx_status & RX_IRQ_MASK_FRAME_READY)
344  {
345  //Process all pending packets
346  do
347  {
348  //Read incoming packet
349  error = aps3EthReceivePacket(interface);
350 
351  //No more data in the receive buffer?
352  } while(error != ERROR_BUFFER_EMPTY);
353  }
354 
355  //Re-enable RX interrupts
356  eth_rx->rx_irq_mask = RX_IRQ_MASK_FRAME_READY;
357 }
358 
359 
360 /**
361  * @brief Send a packet
362  * @param[in] interface Underlying network interface
363  * @param[in] buffer Multi-part buffer containing the data to send
364  * @param[in] offset Offset to the first data byte
365  * @return Error code
366  **/
367 
369  const NetBuffer *buffer, size_t offset)
370 {
371  uint_t i;
372  size_t length;
373 
374  //Retrieve the length of the packet
375  length = netBufferGetLength(buffer) - offset;
376 
377  //Check the frame length
379  {
380  //The transmitter can accept another packet
381  osSetEvent(&interface->nicTxEvent);
382  //Report an error
383  return ERROR_INVALID_LENGTH;
384  }
385 
386  //Make sure the current buffer is available for writing
387  if(eth_tx->tx_desc_status)
388  {
389  //Re-enable TX interrupts
390  eth_tx->tx_irq_mask = TX_IRQ_MASK_MEMORY_AVAILABLE;
391  //Report an error
392  return ERROR_FAILURE;
393  }
394 
395  //Get the index of the current descriptor
396  i = eth_tx->tx_desc_produce;
397 
398  //Copy user data to the transmit buffer
399  netBufferRead((uint8_t *) txDmaDesc[i].addr, buffer, offset, length);
400  //Write the number of bytes to send
401  txDmaDesc[i].size = length;
402 
403  //Start transmission
404  eth_tx->tx_sw_done = 1;
405 
406  //Check whether the next buffer is available for writing
407  if(!eth_tx->tx_desc_status)
408  {
409  //The transmitter can accept another packet
410  osSetEvent(&interface->nicTxEvent);
411  }
412  else
413  {
414  //Re-enable TX interrupts
415  eth_tx->tx_irq_mask = TX_IRQ_MASK_MEMORY_AVAILABLE;
416  }
417 
418  //Data successfully written
419  return NO_ERROR;
420 }
421 
422 
423 /**
424  * @brief Receive a packet
425  * @param[in] interface Underlying network interface
426  * @return Error code
427  **/
428 
430 {
431  error_t error;
432  uint_t i;
433  size_t n;
434 
435  //The current buffer is available for reading?
436  if(!(eth_rx->rx_desc_status))
437  {
438  //Point to the current descriptor
439  i = eth_rx->rx_desc_consume;
440 
441  //Make sure no error occurred
442  if(!(rxDmaDesc[i].status & RX_DESC_RECEIVE_ERROR))
443  {
444  //Retrieve the length of the frame
445  n = rxDmaDesc[i].size;
446  //Limit the number of data to read
448 
449  //Pass the packet to the upper layer
450  nicProcessPacket(interface, (uint8_t *) rxDmaDesc[i].addr, n);
451 
452  //Valid packet received
453  error = NO_ERROR;
454  }
455  else
456  {
457  //The received packet contains an error
458  error = ERROR_INVALID_PACKET;
459  }
460 
461  //The frame has been has been processed by the software
462  //and is no longer needed
463  eth_rx->rx_sw_done = 1;
464  }
465  else
466  {
467  //No more data in the receive buffer
468  error = ERROR_BUFFER_EMPTY;
469  }
470 
471  //Return status code
472  return error;
473 }
474 
475 
476 /**
477  * @brief Configure MAC address filtering
478  * @param[in] interface Underlying network interface
479  * @return Error code
480  **/
481 
483 {
484  uint_t i;
485  uint_t k;
486  uint32_t crc;
487  uint32_t hashTable[2];
488  MacFilterEntry *entry;
489 
490  //Debug message
491  TRACE_DEBUG("Updating Cortus APS3 hash table...\r\n");
492 
493  //Clear hash table
494  hashTable[0] = 0;
495  hashTable[1] = 0;
496 
497  //The MAC address filter contains the list of MAC addresses to accept
498  //when receiving an Ethernet frame
499  for(i = 0; i < MAC_ADDR_FILTER_SIZE; i++)
500  {
501  //Point to the current entry
502  entry = &interface->macAddrFilter[i];
503 
504  //Valid entry?
505  if(entry->refCount > 0)
506  {
507  //Compute CRC over the current MAC address
508  crc = aps3EthCalcCrc(&entry->addr, sizeof(MacAddr));
509  //Calculate the corresponding index in the table
510  k = (crc >> 23) & 0x3F;
511  //Update hash table contents
512  hashTable[k / 32] |= (1 << (k % 32));
513  }
514  }
515 
516  //Disable transmission and reception
517  eth_tx->tx_enable = 0;
518  eth_rx->rx_enable = 0;
519 
520  //Write the hash table
521  eth_mac->hash_filter_low = hashTable[0];
522  eth_mac->hash_filter_high = hashTable[1];
523 
524  //Debug message
525  TRACE_DEBUG(" hash_filter_low = %08" PRIX32 "\r\n", hashTable[0]);
526  TRACE_DEBUG(" hash_filter_high = %08" PRIX32 "\r\n", hashTable[1]);
527 
528  //Re-enable transmission and reception
529  eth_tx->tx_enable = 1;
530  eth_rx->rx_enable = 1;
531 
532  //Successful processing
533  return NO_ERROR;
534 }
535 
536 
537 /**
538  * @brief Adjust MAC configuration parameters for proper operation
539  * @param[in] interface Underlying network interface
540  * @return Error code
541  **/
542 
544 {
545  //Disable transmission and reception
546  eth_tx->tx_enable = 0;
547  eth_rx->rx_enable = 0;
548 
549  //Half-duplex or full-duplex mode?
550  if(interface->duplexMode == NIC_FULL_DUPLEX_MODE)
551  eth_mac->full_duplex = 1;
552  else
553  eth_mac->full_duplex = 0;
554 
555  //Re-enable transmission and reception
556  eth_tx->tx_enable = 1;
557  eth_rx->rx_enable = 1;
558 
559  //Successful processing
560  return NO_ERROR;
561 }
562 
563 
564 /**
565  * @brief Write PHY register
566  * @param[in] phyAddr PHY address
567  * @param[in] regAddr Register address
568  * @param[in] data Register value
569  **/
570 
571 void aps3EthWritePhyReg(uint8_t phyAddr, uint8_t regAddr, uint16_t data)
572 {
573  //Wait for the MII management module to be ready
574  while(!eth_miim->miim_status);
575 
576  //PHY address
577  eth_miim->miim_phy_addr = phyAddr;
578  //Register address
579  eth_miim->miim_phy_register_addr = regAddr;
580  //Data to be written in the PHY register
581  eth_miim->miim_data = data;
582 
583  //Start a write operation
584  eth_miim->miim_read_write = 0;
585  //Wait for the write to complete
586  while(!eth_miim->miim_status);
587 }
588 
589 
590 /**
591  * @brief Read PHY register
592  * @param[in] phyAddr PHY address
593  * @param[in] regAddr Register address
594  * @return Register value
595  **/
596 
597 uint16_t aps3EthReadPhyReg(uint8_t phyAddr, uint8_t regAddr)
598 {
599  //Wait for the MII management module to be ready
600  while(!eth_miim->miim_status);
601 
602  //PHY address
603  eth_miim->miim_phy_addr = phyAddr;
604  //Register address
605  eth_miim->miim_phy_register_addr = regAddr;
606 
607  //Start a read operation
608  eth_miim->miim_read_write = 1;
609  //Wait for the read to complete
610  while(!eth_miim->miim_status);
611 
612  //Return PHY register contents
613  return eth_miim->miim_data;
614 }
615 
616 
617 /**
618  * @brief CRC calculation
619  * @param[in] data Pointer to the data over which to calculate the CRC
620  * @param[in] length Number of bytes to process
621  * @return Resulting CRC value
622  **/
623 
624 uint32_t aps3EthCalcCrc(const void *data, size_t length)
625 {
626  uint_t i;
627  uint_t j;
628 
629  //Point to the data over which to calculate the CRC
630  const uint8_t *p = (uint8_t *) data;
631  //CRC preset value
632  uint32_t crc = 0xFFFFFFFF;
633 
634  //Loop through data
635  for(i = 0; i < length; i++)
636  {
637  //Update CRC value
638  crc ^= p[i];
639 
640  //The message is processed bit by bit
641  for(j = 0; j < 8; j++)
642  {
643  //Update CRC value
644  if(crc & 0x00000001)
645  crc = (crc >> 1) ^ 0xEDB88320;
646  else
647  crc = crc >> 1;
648  }
649  }
650 
651  //Return CRC value
652  return ~crc;
653 }
#define RX_IRQ_MASK_FRAME_READY
#define txDmaDesc
MacAddr addr
MAC address.
Definition: ethernet.h:210
error_t aps3EthReceivePacket(NetInterface *interface)
Receive a packet.
void aps3EthTick(NetInterface *interface)
Cortus APS3 Ethernet MAC timer handler.
TCP/IP stack core.
Debugging facilities.
uint8_t p
Definition: ndp.h:295
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:295
uint32_t aps3EthCalcCrc(const void *data, size_t length)
CRC calculation.
Generic error code.
Definition: error.h:43
#define rxDmaDesc
#define APS3_ETH_TX_BUFFER_SIZE
void aps3EthTxIrqHandler(void)
Ethernet MAC transmit interrupt service routine.
#define txBuffer
error_t aps3EthUpdateMacAddrFilter(NetInterface *interface)
Configure MAC address filtering.
#define APS3_ETH_RX_BUFFER_COUNT
#define TRUE
Definition: os_port.h:48
#define MAC_ADDR_FILTER_SIZE
Definition: ethernet.h:65
void aps3EthDisableIrq(NetInterface *interface)
Disable interrupts.
#define APS3_ETH_TX_BUFFER_COUNT
#define APS3_ETH_IRQ_PRIORITY
void aps3EthRxIrqHandler(void)
Ethernet MAC receive interrupt service routine.
size_t netBufferRead(void *dest, const NetBuffer *src, size_t srcOffset, size_t length)
Read data from a multi-part buffer.
Definition: net_mem.c:670
void aps3EthEventHandler(NetInterface *interface)
Cortus APS3 Ethernet MAC event handler.
NIC driver.
Definition: nic.h:161
const NicDriver aps3EthDriver
Cortus APS3 Ethernet MAC driver.
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:86
#define MIN(a, b)
Definition: os_port.h:60
bool_t osSetEventFromIsr(OsEvent *event)
Set an event object to the signaled state from an interrupt service routine.
Cortus APS3 Ethernet MAC controller.
error_t aps3EthInit(NetInterface *interface)
Cortus APS3 Ethernet MAC initialization.
#define TRACE_INFO(...)
Definition: debug.h:86
uint16_t regAddr
void aps3EthInitDmaDesc(NetInterface *interface)
Initialize DMA descriptor lists.
#define ETH_MTU
Definition: ethernet.h:82
Ethernet interface.
Definition: nic.h:69
Success.
Definition: error.h:42
#define rxBuffer
void aps3EthWritePhyReg(uint8_t phyAddr, uint8_t regAddr, uint16_t data)
Write PHY register.
OsEvent netEvent
Definition: net.c:72
void nicProcessPacket(NetInterface *interface, void *packet, size_t length)
Handle a packet received by the network controller.
Definition: nic.c:239
uint_t refCount
Reference count for the current entry.
Definition: ethernet.h:211
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
error_t
Error codes.
Definition: error.h:40
unsigned int uint_t
Definition: compiler_port.h:43
__start_packed struct @112 MacAddr
MAC address.
void aps3EthEnableIrq(NetInterface *interface)
Enable interrupts.
uint8_t data[]
Definition: dtls_misc.h:167
#define NetInterface
Definition: net.h:34
uint16_t aps3EthReadPhyReg(uint8_t phyAddr, uint8_t regAddr)
Read PHY register.
#define osExitIsr(flag)
#define osEnterIsr()
error_t aps3EthSendPacket(NetInterface *interface, const NetBuffer *buffer, size_t offset)
Send a packet.
#define TX_IRQ_MASK_MEMORY_AVAILABLE
uint8_t length
Definition: dtls_misc.h:140
uint8_t n
#define FALSE
Definition: os_port.h:44
error_t aps3EthUpdateMacConfig(NetInterface *interface)
Adjust MAC configuration parameters for proper operation.
#define RX_DESC_RECEIVE_ERROR
int bool_t
Definition: compiler_port.h:47
#define APS3_ETH_RX_BUFFER_SIZE
Ipv4Addr addr
Definition: nbns_common.h:119
MAC filter table entry.
Definition: ethernet.h:208
#define TRACE_DEBUG(...)
Definition: debug.h:98