lan9646_driver.c
Go to the documentation of this file.
1 /**
2  * @file lan9646_driver.c
3  * @brief LAN9646 6-port Gigabit Ethernet switch driver
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2026 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.6.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL NIC_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
36 #include "core/ethernet_misc.h"
38 #include "debug.h"
39 
40 
41 /**
42  * @brief LAN9646 Ethernet switch driver
43  **/
44 
46 {
70 };
71 
72 
73 /**
74  * @brief Tail tag rules (host to LAN9646)
75  **/
76 
77 const uint16_t lan9646IngressTailTag[8] =
78 {
84  HTONS(0),
85  HTONS(0),
87 };
88 
89 
90 /**
91  * @brief LAN9646 Ethernet switch initialization
92  * @param[in] interface Underlying network interface
93  * @return Error code
94  **/
95 
97 {
98  uint_t port;
99  uint8_t temp;
100 
101  //Debug message
102  TRACE_INFO("Initializing LAN9646...\r\n");
103 
104  //SPI slave mode?
105  if(interface->spiDriver != NULL)
106  {
107  //Initialize SPI interface
108  interface->spiDriver->init();
109 
110  //Wait for the serial interface to be ready
111  do
112  {
113  //Read CHIP_ID1 register
114  temp = lan9646ReadSwitchReg8(interface, LAN9646_CHIP_ID1);
115 
116  //The returned data is invalid until the serial interface is ready
117  } while(temp != LAN9646_CHIP_ID1_DEFAULT);
118 
119 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
120  //Enable tail tag feature
124 
125  //Disable frame length check (silicon errata workaround 13)
129 #else
130  //Disable tail tag feature
134 
135  //Enable frame length check
139 #endif
140 
141  //Loop through the ports
143  {
144  //Skip unused ports
145  if(port != LAN9646_PORT5 && port != LAN9646_PORT6)
146  {
147 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
148  //Port separation mode?
149  if(interface->port != 0)
150  {
151  //Disable packet transmission and address learning
152  lan9646SetPortState(interface, port,
154  }
155  else
156 #endif
157  {
158  //Enable transmission, reception and address learning
159  lan9646SetPortState(interface, port,
161  }
162  }
163  }
164 
165  //Restore default age count
169 
170  //Restore default age period
173 
174  //Add internal delay to ingress and egress RGMII clocks
179 
180  //Reset SGMII registers (silicon errata workaround 15)
184 
185  //Start switch operation
188  }
189  else if(interface->smiDriver != NULL)
190  {
191  //Initialize serial management interface
192  interface->smiDriver->init();
193  }
194  else
195  {
196  //Just for sanity
197  }
198 
199  //Loop through the ports
201  {
202  //Improve PHY receive performance (silicon errata workaround 1)
203  lan9646WriteMmdReg(interface, port, 0x01, 0x6F, 0xDD0B);
204  lan9646WriteMmdReg(interface, port, 0x01, 0x8F, 0x6032);
205  lan9646WriteMmdReg(interface, port, 0x01, 0x9D, 0x248C);
206  lan9646WriteMmdReg(interface, port, 0x01, 0x75, 0x0060);
207  lan9646WriteMmdReg(interface, port, 0x01, 0xD3, 0x7777);
208  lan9646WriteMmdReg(interface, port, 0x1C, 0x06, 0x3008);
209  lan9646WriteMmdReg(interface, port, 0x1C, 0x08, 0x2001);
210 
211  //Improve transmit waveform amplitude (silicon errata workaround 2)
212  lan9646WriteMmdReg(interface, port, 0x1C, 0x04, 0x00D0);
213 
214  //EEE must be manually disabled (silicon errata workaround 4)
216 
217  //Adjust power supply settings (silicon errata workaround 7)
218  lan9646WriteMmdReg(interface, port, 0x1C, 0x13, 0x6EFF);
219  lan9646WriteMmdReg(interface, port, 0x1C, 0x14, 0xE6FF);
220  lan9646WriteMmdReg(interface, port, 0x1C, 0x15, 0x6EFF);
221  lan9646WriteMmdReg(interface, port, 0x1C, 0x16, 0xE6FF);
222  lan9646WriteMmdReg(interface, port, 0x1C, 0x17, 0x00FF);
223  lan9646WriteMmdReg(interface, port, 0x1C, 0x18, 0x43FF);
224  lan9646WriteMmdReg(interface, port, 0x1C, 0x19, 0xC3FF);
225  lan9646WriteMmdReg(interface, port, 0x1C, 0x1A, 0x6FFF);
226  lan9646WriteMmdReg(interface, port, 0x1C, 0x1B, 0x07FF);
227  lan9646WriteMmdReg(interface, port, 0x1C, 0x1C, 0x0FFF);
228  lan9646WriteMmdReg(interface, port, 0x1C, 0x1D, 0xE7FF);
229  lan9646WriteMmdReg(interface, port, 0x1C, 0x1E, 0xEFFF);
230  lan9646WriteMmdReg(interface, port, 0x1C, 0x20, 0xEEEE);
231 
232  //Select tri-color dual-LED mode (silicon errata workaround 15)
236 
237  //Debug message
238  TRACE_DEBUG("Port %u:\r\n", port);
239  //Dump PHY registers for debugging purpose
240  lan9646DumpPhyReg(interface, port);
241  }
242 
243  //Perform custom configuration
244  lan9646InitHook(interface);
245 
246  //Force the TCP/IP stack to poll the link state at startup
247  interface->phyEvent = TRUE;
248  //Notify the TCP/IP stack of the event
249  osSetEvent(&interface->netContext->event);
250 
251  //Successful initialization
252  return NO_ERROR;
253 }
254 
255 
256 /**
257  * @brief LAN9646 custom configuration
258  * @param[in] interface Underlying network interface
259  **/
260 
261 __weak_func void lan9646InitHook(NetInterface *interface)
262 {
263 }
264 
265 
266 /**
267  * @brief LAN9646 timer handler
268  * @param[in] interface Underlying network interface
269  **/
270 
271 __weak_func void lan9646Tick(NetInterface *interface)
272 {
273  uint_t port;
274  bool_t linkState;
275 
276 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
277  //Port separation mode?
278  if(interface->port != 0)
279  {
280  uint_t i;
281  NetContext *context;
282  NetInterface *virtualInterface;
283 
284  //Point to the TCP/IP stack context
285  context = interface->netContext;
286 
287  //Loop through network interfaces
288  for(i = 0; i < context->numInterfaces; i++)
289  {
290  //Point to the current interface
291  virtualInterface = &context->interfaces[i];
292 
293  //Check whether the current virtual interface is attached to the
294  //physical interface
295  if(virtualInterface == interface ||
296  virtualInterface->parent == interface)
297  {
298  //Retrieve current link state
299  linkState = lan9646GetLinkState(interface, virtualInterface->port);
300 
301  //Link up or link down event?
302  if(linkState != virtualInterface->linkState)
303  {
304  //Set event flag
305  interface->phyEvent = TRUE;
306  //Notify the TCP/IP stack of the event
307  osSetEvent(&interface->netContext->event);
308  }
309  }
310  }
311  }
312  else
313 #endif
314  {
315  //Initialize link state
316  linkState = FALSE;
317 
318  //Loop through the ports
320  {
321  //Skip unused ports
322  if(port != LAN9646_PORT5 && port != LAN9646_PORT6)
323  {
324  //Retrieve current link state
325  if(lan9646GetLinkState(interface, port))
326  {
327  linkState = TRUE;
328  }
329  }
330  }
331 
332  //Link up or link down event?
333  if(linkState != interface->linkState)
334  {
335  //Set event flag
336  interface->phyEvent = TRUE;
337  //Notify the TCP/IP stack of the event
338  osSetEvent(&interface->netContext->event);
339  }
340  }
341 }
342 
343 
344 /**
345  * @brief Enable interrupts
346  * @param[in] interface Underlying network interface
347  **/
348 
350 {
351 }
352 
353 
354 /**
355  * @brief Disable interrupts
356  * @param[in] interface Underlying network interface
357  **/
358 
360 {
361 }
362 
363 
364 /**
365  * @brief LAN9646 event handler
366  * @param[in] interface Underlying network interface
367  **/
368 
369 __weak_func void lan9646EventHandler(NetInterface *interface)
370 {
371  uint_t port;
372  bool_t linkState;
373 
374 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
375  //Port separation mode?
376  if(interface->port != 0)
377  {
378  uint_t i;
379  NetContext *context;
380  NetInterface *virtualInterface;
381 
382  //Point to the TCP/IP stack context
383  context = interface->netContext;
384 
385  //Loop through network interfaces
386  for(i = 0; i < context->numInterfaces; i++)
387  {
388  //Point to the current interface
389  virtualInterface = &context->interfaces[i];
390 
391  //Check whether the current virtual interface is attached to the
392  //physical interface
393  if(virtualInterface == interface ||
394  virtualInterface->parent == interface)
395  {
396  //Get the port number associated with the current interface
397  port = virtualInterface->port;
398 
399  //Valid port?
400  if((port >= LAN9646_PORT1 && port <= LAN9646_PORT4) ||
401  port == LAN9646_PORT7)
402  {
403  //Retrieve current link state
404  linkState = lan9646GetLinkState(interface, port);
405 
406  //Link up event?
407  if(linkState && !virtualInterface->linkState)
408  {
409  //Retrieve host interface speed
410  interface->linkSpeed = lan9646GetLinkSpeed(interface,
411  LAN9646_PORT6);
412 
413  //Retrieve host interface duplex mode
414  interface->duplexMode = lan9646GetDuplexMode(interface,
415  LAN9646_PORT6);
416 
417  //Adjust MAC configuration parameters for proper operation
418  interface->nicDriver->updateMacConfig(interface);
419 
420  //Check current speed
421  virtualInterface->linkSpeed = lan9646GetLinkSpeed(interface,
422  port);
423 
424  //Check current duplex mode
425  virtualInterface->duplexMode = lan9646GetDuplexMode(interface,
426  port);
427 
428  //Update link state
429  virtualInterface->linkState = TRUE;
430 
431  //Process link state change event
432  nicNotifyLinkChange(virtualInterface);
433  }
434  //Link down event
435  else if(!linkState && virtualInterface->linkState)
436  {
437  //Update link state
438  virtualInterface->linkState = FALSE;
439 
440  //Process link state change event
441  nicNotifyLinkChange(virtualInterface);
442  }
443  }
444  }
445  }
446  }
447  else
448 #endif
449  {
450  //Initialize link state
451  linkState = FALSE;
452 
453  //Loop through the ports
455  {
456  //Skip unused ports
457  if(port != LAN9646_PORT5 && port != LAN9646_PORT6)
458  {
459  //Retrieve current link state
460  if(lan9646GetLinkState(interface, port))
461  {
462  linkState = TRUE;
463  }
464  }
465  }
466 
467  //Link up event?
468  if(linkState)
469  {
470  //Retrieve host interface speed
471  interface->linkSpeed = lan9646GetLinkSpeed(interface, LAN9646_PORT6);
472  //Retrieve host interface duplex mode
473  interface->duplexMode = lan9646GetDuplexMode(interface, LAN9646_PORT6);
474 
475  //Adjust MAC configuration parameters for proper operation
476  interface->nicDriver->updateMacConfig(interface);
477 
478  //Update link state
479  interface->linkState = TRUE;
480  }
481  else
482  {
483  //Update link state
484  interface->linkState = FALSE;
485  }
486 
487  //Process link state change event
488  nicNotifyLinkChange(interface);
489  }
490 }
491 
492 
493 /**
494  * @brief Add tail tag to Ethernet frame
495  * @param[in] interface Underlying network interface
496  * @param[in] buffer Multi-part buffer containing the payload
497  * @param[in,out] offset Offset to the first payload byte
498  * @param[in] ancillary Additional options passed to the stack along with
499  * the packet
500  * @return Error code
501  **/
502 
504  size_t *offset, NetTxAncillary *ancillary)
505 {
506  error_t error;
507 
508  //Initialize status code
509  error = NO_ERROR;
510 
511 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
512  //SPI slave mode?
513  if(interface->spiDriver != NULL)
514  {
515  //Valid port?
516  if(ancillary->port <= LAN9646_PORT7)
517  {
518  size_t length;
519  const uint16_t *tailTag;
520 
521  //The two-byte tail tagging is used to indicate the destination port
522  tailTag = &lan9646IngressTailTag[ancillary->port];
523 
524  //Retrieve the length of the Ethernet frame
525  length = netBufferGetLength(buffer) - *offset;
526 
527  //The host controller should manually add padding to the packet before
528  //inserting the tail tag
529  error = ethPadFrame(buffer, &length);
530 
531  //Check status code
532  if(!error)
533  {
534  //The tail tag is inserted at the end of the packet, just before
535  //the CRC
536  error = netBufferAppend(buffer, tailTag, sizeof(uint16_t));
537  }
538  }
539  else
540  {
541  //The port number is not valid
542  error = ERROR_INVALID_PORT;
543  }
544  }
545 #endif
546 
547  //Return status code
548  return error;
549 }
550 
551 
552 /**
553  * @brief Decode tail tag from incoming Ethernet frame
554  * @param[in] interface Underlying network interface
555  * @param[in,out] frame Pointer to the received Ethernet frame
556  * @param[in,out] length Length of the frame, in bytes
557  * @param[in,out] ancillary Additional options passed to the stack along with
558  * the packet
559  * @return Error code
560  **/
561 
562 error_t lan9646UntagFrame(NetInterface *interface, uint8_t **frame,
563  size_t *length, NetRxAncillary *ancillary)
564 {
565  error_t error;
566 
567  //Initialize status code
568  error = NO_ERROR;
569 
570 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
571  //SPI slave mode?
572  if(interface->spiDriver != NULL)
573  {
574  //Valid Ethernet frame received?
575  if(*length >= (sizeof(EthHeader) + sizeof(uint8_t)))
576  {
577  uint8_t *tailTag;
578 
579  //The tail tag is inserted at the end of the packet, just before
580  //the CRC
581  tailTag = *frame + *length - sizeof(uint8_t);
582 
583  //The one byte tail tagging is used to indicate the source port
584  ancillary->port = (*tailTag & LAN9646_TAIL_TAG_SRC_PORT) + 1;
585 
586  //Strip tail tag from Ethernet frame
587  *length -= sizeof(uint8_t);
588  }
589  else
590  {
591  //Drop the received frame
592  error = ERROR_INVALID_LENGTH;
593  }
594  }
595  else
596  {
597  //Tail tagging mode cannot be enabled through MDC/MDIO interface
598  ancillary->port = 0;
599  }
600 #endif
601 
602  //Return status code
603  return error;
604 }
605 
606 
607 /**
608  * @brief Get link state
609  * @param[in] interface Underlying network interface
610  * @param[in] port Port number
611  * @return Link state
612  **/
613 
615 {
616  uint16_t value;
617  bool_t linkState;
618 
619  //Check port number
620  if(port >= LAN9646_PORT1 && port <= LAN9646_PORT4)
621  {
622  //Any link failure condition is latched in the BMSR register. Reading
623  //the register twice will always return the actual link status
624  value = lan9646ReadPhyReg(interface, port, LAN9646_BMSR);
625  value = lan9646ReadPhyReg(interface, port, LAN9646_BMSR);
626 
627  //Retrieve current link state
628  linkState = (value & LAN9646_BMSR_LINK_STATUS) ? TRUE : FALSE;
629  }
630  else if(port == LAN9646_PORT7)
631  {
632  //An external PHY can optionally be connected to port 7
633  linkState = lan9646GetPort7LinkState(interface);
634  }
635  else
636  {
637  //The specified port number is not valid
638  linkState = FALSE;
639  }
640 
641  //Return link status
642  return linkState;
643 }
644 
645 
646 /**
647  * @brief Get link speed
648  * @param[in] interface Underlying network interface
649  * @param[in] port Port number
650  * @return Link speed
651  **/
652 
653 uint32_t lan9646GetLinkSpeed(NetInterface *interface, uint8_t port)
654 {
655  uint8_t type;
656  uint16_t value;
657  uint32_t linkSpeed;
658 
659  //Check port number
660  if(port >= LAN9646_PORT1 && port <= LAN9646_PORT4)
661  {
662  //Read PHY control register
664 
665  //Retrieve current link speed
667  {
668  //1000BASE-T
669  linkSpeed = NIC_LINK_SPEED_1GBPS;
670  }
671  else if((value & LAN9646_PHYCON_SPEED_100BTX) != 0)
672  {
673  //100BASE-TX
674  linkSpeed = NIC_LINK_SPEED_100MBPS;
675  }
676  else if((value & LAN9646_PHYCON_SPEED_10BT) != 0)
677  {
678  //10BASE-T
679  linkSpeed = NIC_LINK_SPEED_10MBPS;
680  }
681  else
682  {
683  //The link speed is not valid
684  linkSpeed = NIC_LINK_SPEED_UNKNOWN;
685  }
686  }
687  else if(port == LAN9646_PORT6)
688  {
689  //SPI slave mode?
690  if(interface->spiDriver != NULL)
691  {
692  //Read port 6 XMII control 1 register
694 
695  //Retrieve host interface type
697 
698  //Gigabit interface?
701  {
702  //1000 Mb/s mode
703  linkSpeed = NIC_LINK_SPEED_1GBPS;
704  }
705  else
706  {
707  //Read port 6 XMII control 0 register
709 
710  //Retrieve host interface speed
712  {
713  //100 Mb/s mode
714  linkSpeed = NIC_LINK_SPEED_100MBPS;
715  }
716  else
717  {
718  //10 Mb/s mode
719  linkSpeed = NIC_LINK_SPEED_10MBPS;
720  }
721  }
722  }
723  else
724  {
725  //The MDC/MDIO interface does not have access to all the configuration
726  //registers. It can only access the standard MIIM registers
727  linkSpeed = NIC_LINK_SPEED_100MBPS;
728  }
729  }
730  else if(port == LAN9646_PORT7)
731  {
732  //An external PHY can optionally be connected to port 7
733  linkSpeed = lan9646GetPort7LinkSpeed(interface);
734  }
735  else
736  {
737  //The specified port number is not valid
738  linkSpeed = NIC_LINK_SPEED_UNKNOWN;
739  }
740 
741  //Return link speed
742  return linkSpeed;
743 }
744 
745 
746 /**
747  * @brief Get duplex mode
748  * @param[in] interface Underlying network interface
749  * @param[in] port Port number
750  * @return Duplex mode
751  **/
752 
754 {
755  uint16_t value;
756  NicDuplexMode duplexMode;
757 
758  //Check port number
759  if(port >= LAN9646_PORT1 && port <= LAN9646_PORT4)
760  {
761  //Read PHY control register
763 
764  //Retrieve current duplex mode
766  {
767  duplexMode = NIC_FULL_DUPLEX_MODE;
768  }
769  else
770  {
771  duplexMode = NIC_HALF_DUPLEX_MODE;
772  }
773  }
774  else if(port == LAN9646_PORT6)
775  {
776  //SPI slave mode?
777  if(interface->spiDriver != NULL)
778  {
779  //Read port 6 XMII control 0 register
781 
782  //Retrieve host interface duplex mode
784  {
785  duplexMode = NIC_FULL_DUPLEX_MODE;
786  }
787  else
788  {
789  duplexMode = NIC_HALF_DUPLEX_MODE;
790  }
791  }
792  else
793  {
794  //The MDC/MDIO interface does not have access to all the configuration
795  //registers. It can only access the standard MIIM registers
796  duplexMode = NIC_FULL_DUPLEX_MODE;
797  }
798  }
799  else if(port == LAN9646_PORT7)
800  {
801  //An external PHY can optionally be connected to port 7
802  duplexMode = lan9646GetPort7DuplexMode(interface);
803  }
804  else
805  {
806  //The specified port number is not valid
807  duplexMode = NIC_UNKNOWN_DUPLEX_MODE;
808  }
809 
810  //Return duplex mode
811  return duplexMode;
812 }
813 
814 
815 /**
816  * @brief Get port 7 link state
817  * @param[in] interface Underlying network interface
818  * @return Link state
819  **/
820 
822 {
823  uint16_t value;
824  bool_t linkState;
825 
826  //Read SGMII Status register
828 
829  //Check whether the SGMII link is up
831  {
832  //Read SGMII Auto-Negotiation Status register
834 
835  //Check the link status reported by the PHY-side device
837  {
838  //The link is up
839  linkState = TRUE;
840  }
841  else
842  {
843  //The link is down
844  linkState = FALSE;
845  }
846  }
847  else
848  {
849  //The SGMII link is down
850  linkState = FALSE;
851  }
852 
853  //Return current link status
854  return linkState;
855 }
856 
857 
858 /**
859  * @brief Get port 7 link speed
860  * @param[in] interface Underlying network interface
861  * @return Link speed
862  **/
863 
864 __weak_func uint32_t lan9646GetPort7LinkSpeed(NetInterface *interface)
865 {
866  uint16_t value;
867  uint32_t linkSpeed;
868 
869  //Read SGMII Auto-Negotiation Status register
871 
872  //Retrieve current link speed
874  {
875  //10 Mbps?
877  linkSpeed = NIC_LINK_SPEED_10MBPS;
878  break;
879 
880  //100 Mbps?
882  linkSpeed = NIC_LINK_SPEED_100MBPS;
883  break;
884 
885  //1000 Mbps?
887  linkSpeed = NIC_LINK_SPEED_1GBPS;
888  break;
889 
890  //Unknown speed?
891  default:
892  linkSpeed = NIC_LINK_SPEED_UNKNOWN;
893  break;
894  }
895 
896  //Read SGMII Control register
898 
899  //If the SGMII speed is variable or less than 1000 Mbps, software must
900  //update GMAC parameters when there is a change to the link speed (silicon
901  //errata workaround 8)
902  if(linkSpeed == NIC_LINK_SPEED_10MBPS)
903  {
906  }
907  else if(linkSpeed == NIC_LINK_SPEED_100MBPS)
908  {
911  }
912  else if(linkSpeed == NIC_LINK_SPEED_1GBPS)
913  {
916  }
917  else
918  {
919  }
920 
921  //Write the modified value to the SGMII Control register
923 
924  //Return current link speed
925  return linkSpeed;
926 }
927 
928 
929 /**
930  * @brief Get port 7 duplex mode
931  * @param[in] interface Underlying network interface
932  * @return Duplex mode
933  **/
934 
936 {
937  uint16_t value;
938  NicDuplexMode duplexMode;
939 
940  //Read SGMII Auto-Negotiation Status register
942 
943  //Retrieve current duplex mode
945  {
946  duplexMode = NIC_FULL_DUPLEX_MODE;
947  }
948  else
949  {
950  duplexMode = NIC_HALF_DUPLEX_MODE;
951  }
952 
953  //Read SGMII Control register
955 
956  //Update GMAC duplex mode (silicon errata workaround 8)
957  if(duplexMode == NIC_FULL_DUPLEX_MODE)
958  {
960  }
961  else
962  {
964  }
965 
966  //Write the modified value to the SGMII Control register
968 
969  //Return current duplex mode
970  return duplexMode;
971 }
972 
973 
974 /**
975  * @brief Set port state
976  * @param[in] interface Underlying network interface
977  * @param[in] port Port number
978  * @param[in] state Port state
979  **/
980 
981 void lan9646SetPortState(NetInterface *interface, uint8_t port,
982  SwitchPortState state)
983 {
984  uint8_t temp;
985 
986  //Check port number
987  if((port >= LAN9646_PORT1 && port <= LAN9646_PORT4) ||
988  port == LAN9646_PORT7)
989  {
990  //Read MSTP state register
992 
993  //Update port state
994  switch(state)
995  {
996  //Listening state
1001  break;
1002 
1003  //Learning state
1008  break;
1009 
1010  //Forwarding state
1015  break;
1016 
1017  //Disabled state
1018  default:
1022  break;
1023  }
1024 
1025  //Write the value back to MSTP state register
1027  }
1028 }
1029 
1030 
1031 /**
1032  * @brief Get port state
1033  * @param[in] interface Underlying network interface
1034  * @param[in] port Port number
1035  * @return Port state
1036  **/
1037 
1039 {
1040  uint8_t temp;
1041  SwitchPortState state;
1042 
1043  //Check port number
1044  if((port >= LAN9646_PORT1 && port <= LAN9646_PORT4) ||
1045  port == LAN9646_PORT7)
1046  {
1047  //Read MSTP state register
1049 
1050  //Check port state
1051  if((temp & LAN9646_PORTn_MSTP_STATE_TRANSMIT_EN) == 0 &&
1052  (temp & LAN9646_PORTn_MSTP_STATE_RECEIVE_EN) == 0 &&
1054  {
1055  //Disabled state
1057  }
1058  else if((temp & LAN9646_PORTn_MSTP_STATE_TRANSMIT_EN) == 0 &&
1059  (temp & LAN9646_PORTn_MSTP_STATE_RECEIVE_EN) != 0 &&
1061  {
1062  //Listening state
1064  }
1065  else if((temp & LAN9646_PORTn_MSTP_STATE_TRANSMIT_EN) == 0 &&
1066  (temp & LAN9646_PORTn_MSTP_STATE_RECEIVE_EN) == 0 &&
1068  {
1069  //Learning state
1071  }
1072  else if((temp & LAN9646_PORTn_MSTP_STATE_TRANSMIT_EN) != 0 &&
1073  (temp & LAN9646_PORTn_MSTP_STATE_RECEIVE_EN) != 0 &&
1075  {
1076  //Forwarding state
1078  }
1079  else
1080  {
1081  //Unknown state
1082  state = SWITCH_PORT_STATE_UNKNOWN;
1083  }
1084  }
1085  else
1086  {
1087  //The specified port number is not valid
1089  }
1090 
1091  //Return port state
1092  return state;
1093 }
1094 
1095 
1096 /**
1097  * @brief Set aging time for dynamic filtering entries
1098  * @param[in] interface Underlying network interface
1099  * @param[in] agingTime Aging time, in seconds
1100  **/
1101 
1102 void lan9646SetAgingTime(NetInterface *interface, uint32_t agingTime)
1103 {
1104  //The Age Period in combination with the Age Count field determines the
1105  //aging time of dynamic entries in the address lookup table
1106  agingTime = (agingTime + 3) / 4;
1107 
1108  //Limit the range of the parameter
1109  agingTime = MIN(agingTime, 255);
1110 
1111  //Write the value to Switch Lookup Engine Control 3 register
1113  (uint8_t) agingTime);
1114 }
1115 
1116 
1117 /**
1118  * @brief Enable IGMP snooping
1119  * @param[in] interface Underlying network interface
1120  * @param[in] enable Enable or disable IGMP snooping
1121  **/
1122 
1124 {
1125  uint8_t temp;
1126 
1127  //Read the Global Port Mirroring and Snooping Control register
1128  temp = lan9646ReadSwitchReg8(interface,
1130 
1131  //Enable or disable IGMP snooping
1132  if(enable)
1133  {
1135  }
1136  else
1137  {
1139  }
1140 
1141  //Write the value back to Global Port Mirroring and Snooping Control register
1143  temp);
1144 }
1145 
1146 
1147 /**
1148  * @brief Enable MLD snooping
1149  * @param[in] interface Underlying network interface
1150  * @param[in] enable Enable or disable MLD snooping
1151  **/
1152 
1154 {
1155  uint8_t temp;
1156 
1157  //Read the Global Port Mirroring and Snooping Control register
1158  temp = lan9646ReadSwitchReg8(interface,
1160 
1161  //Enable or disable MLD snooping
1162  if(enable)
1163  {
1165  }
1166  else
1167  {
1169  }
1170 
1171  //Write the value back to Global Port Mirroring and Snooping Control register
1173  temp);
1174 }
1175 
1176 
1177 /**
1178  * @brief Enable reserved multicast table
1179  * @param[in] interface Underlying network interface
1180  * @param[in] enable Enable or disable reserved group addresses
1181  **/
1182 
1184 {
1185  uint8_t temp;
1186 
1187  //Read the Switch Lookup Engine Control 0 register
1189 
1190  //Enable or disable the reserved multicast table
1191  if(enable)
1192  {
1194  }
1195  else
1196  {
1198  }
1199 
1200  //Write the value back to Switch Lookup Engine Control 0 register
1202 }
1203 
1204 
1205 /**
1206  * @brief Add a new entry to the static MAC table
1207  * @param[in] interface Underlying network interface
1208  * @param[in] entry Pointer to the forwarding database entry
1209  * @return Error code
1210  **/
1211 
1213  const SwitchFdbEntry *entry)
1214 {
1215  error_t error;
1216  uint_t i;
1217  uint_t j;
1218  uint32_t value;
1219  SwitchFdbEntry currentEntry;
1220 
1221  //Keep track of the first free entry
1223 
1224  //Loop through the static MAC table
1225  for(i = 0; i < LAN9646_STATIC_MAC_TABLE_SIZE; i++)
1226  {
1227  //Read current entry
1228  error = lan9646GetStaticFdbEntry(interface, i, &currentEntry);
1229 
1230  //Valid entry?
1231  if(!error)
1232  {
1233  //Check whether the table already contains the specified MAC address
1234  if(macCompAddr(&currentEntry.macAddr, &entry->macAddr))
1235  {
1236  j = i;
1237  break;
1238  }
1239  }
1240  else
1241  {
1242  //Keep track of the first free entry
1244  {
1245  j = i;
1246  }
1247  }
1248  }
1249 
1250  //Any entry available?
1252  {
1253  //Write the Static Address Table Entry 1 register
1256 
1257  //Set the relevant forward ports
1258  if(entry->destPorts == SWITCH_CPU_PORT_MASK)
1259  {
1261  }
1262  else
1263  {
1264  value = entry->destPorts & LAN9646_PORT_MASK;
1265  }
1266 
1267  //Enable overriding of port state
1268  if(entry->override)
1269  {
1271  }
1272 
1273  //Write the Static Address Table Entry 2 register
1275 
1276  //Copy MAC address (first 16 bits)
1277  value = (entry->macAddr.b[0] << 8) | entry->macAddr.b[1];
1278 
1279  //Write the Static Address Table Entry 3 register
1281 
1282  //Copy MAC address (last 32 bits)
1283  value = (entry->macAddr.b[2] << 24) | (entry->macAddr.b[3] << 16) |
1284  (entry->macAddr.b[4] << 8) | entry->macAddr.b[5];
1285 
1286  //Write the Static Address Table Entry 4 register
1288 
1289  //Write the TABLE_INDEX field with the 4-bit index value
1291  //Set the TABLE_SELECT bit to 0 to select the static address table
1293  //Set the ACTION bit to 0 to indicate a write operation
1295  //Set the START_FINISH bit to 1 to initiate the operation
1297 
1298  //Start the write operation
1300  value);
1301 
1302  //When the operation is complete, the START_FINISH bit will be cleared
1303  //automatically
1304  do
1305  {
1306  //Read the Static Address and Reserved Multicast Table Control register
1307  value = lan9646ReadSwitchReg32(interface,
1309 
1310  //Poll the START_FINISH bit
1312 
1313  //Successful processing
1314  error = NO_ERROR;
1315  }
1316  else
1317  {
1318  //The static MAC table is full
1319  error = ERROR_TABLE_FULL;
1320  }
1321 
1322  //Return status code
1323  return error;
1324 }
1325 
1326 
1327 /**
1328  * @brief Remove an entry from the static MAC table
1329  * @param[in] interface Underlying network interface
1330  * @param[in] entry Forwarding database entry to remove from the table
1331  * @return Error code
1332  **/
1333 
1335  const SwitchFdbEntry *entry)
1336 {
1337  error_t error;
1338  uint_t j;
1339  uint32_t value;
1340  SwitchFdbEntry currentEntry;
1341 
1342  //Loop through the static MAC table
1343  for(j = 0; j < LAN9646_STATIC_MAC_TABLE_SIZE; j++)
1344  {
1345  //Read current entry
1346  error = lan9646GetStaticFdbEntry(interface, j, &currentEntry);
1347 
1348  //Valid entry?
1349  if(!error)
1350  {
1351  //Check whether the table contains the specified MAC address
1352  if(macCompAddr(&currentEntry.macAddr, &entry->macAddr))
1353  {
1354  break;
1355  }
1356  }
1357  }
1358 
1359  //Any matching entry?
1361  {
1362  //Clear Static Address Table Entry registers
1367 
1368  //Write the TABLE_INDEX field with the 4-bit index value
1370  //Set the TABLE_SELECT bit to 0 to select the static address table
1372  //Set the ACTION bit to 0 to indicate a write operation
1374  //Set the START_FINISH bit to 1 to initiate the operation
1376 
1377  //Start the write operation
1379  value);
1380 
1381  //When the operation is complete, the START_FINISH bit will be cleared
1382  //automatically
1383  do
1384  {
1385  //Read the Static Address and Reserved Multicast Table Control register
1386  value = lan9646ReadSwitchReg32(interface,
1388 
1389  //Poll the START_FINISH bit
1391 
1392  //Successful processing
1393  error = NO_ERROR;
1394  }
1395  else
1396  {
1397  //The static MAC table does not contain the specified address
1398  error = ERROR_NOT_FOUND;
1399  }
1400 
1401  //Return status code
1402  return error;
1403 }
1404 
1405 
1406 /**
1407  * @brief Read an entry from the static MAC table
1408  * @param[in] interface Underlying network interface
1409  * @param[in] index Zero-based index of the entry to read
1410  * @param[out] entry Pointer to the forwarding database entry
1411  * @return Error code
1412  **/
1413 
1415  SwitchFdbEntry *entry)
1416 {
1417  error_t error;
1418  uint32_t value;
1419 
1420  //Check index parameter
1421  if(index < LAN9646_STATIC_MAC_TABLE_SIZE)
1422  {
1423  //Write the TABLE_INDEX field with the 4-bit index value
1425  //Set the TABLE_SELECT bit to 0 to select the static address table
1427  //Set the ACTION bit to 1 to indicate a read operation
1429  //Set the START_FINISH bit to 1 to initiate the operation
1431 
1432  //Start the read operation
1434  value);
1435 
1436  //When the operation is complete, the START_FINISH bit will be cleared
1437  //automatically
1438  do
1439  {
1440  //Read the Static Address and Reserved Multicast Table Control register
1441  value = lan9646ReadSwitchReg32(interface,
1443 
1444  //Poll the START_FINISH bit
1446 
1447  //Read the Static Address Table Entry 1 register
1449 
1450  //Valid entry?
1452  {
1453  //Read the Static Address Table Entry 2 register
1455 
1456  //Retrieve the ports associated with this MAC address
1457  entry->srcPort = 0;
1459 
1460  //Check the value of the OVERRIDE bit
1462  {
1463  entry->override = TRUE;
1464  }
1465  else
1466  {
1467  entry->override = FALSE;
1468  }
1469 
1470  //Read the Static Address Table Entry 3 register
1472 
1473  //Copy MAC address (first 16 bits)
1474  entry->macAddr.b[0] = (value >> 8) & 0xFF;
1475  entry->macAddr.b[1] = value & 0xFF;
1476 
1477  //Read the Static Address Table Entry 4 register
1479 
1480  //Copy MAC address (last 32 bits)
1481  entry->macAddr.b[2] = (value >> 24) & 0xFF;
1482  entry->macAddr.b[3] = (value >> 16) & 0xFF;
1483  entry->macAddr.b[4] = (value >> 8) & 0xFF;
1484  entry->macAddr.b[5] = value & 0xFF;
1485 
1486  //Successful processing
1487  error = NO_ERROR;
1488  }
1489  else
1490  {
1491  //The entry is not valid
1492  error = ERROR_INVALID_ENTRY;
1493  }
1494  }
1495  else
1496  {
1497  //The end of the table has been reached
1498  error = ERROR_END_OF_TABLE;
1499  }
1500 
1501  //Return status code
1502  return error;
1503 }
1504 
1505 
1506 /**
1507  * @brief Flush static MAC table
1508  * @param[in] interface Underlying network interface
1509  **/
1510 
1512 {
1513  uint_t i;
1514  uint32_t value;
1515 
1516  //Loop through the static MAC table
1517  for(i = 0; i < LAN9646_STATIC_MAC_TABLE_SIZE; i++)
1518  {
1519  //Clear Static Address Table Entry registers
1524 
1525  //Write the TABLE_INDEX field with the 4-bit index value
1527  //Set the TABLE_SELECT bit to 0 to select the static address table
1529  //Set the ACTION bit to 0 to indicate a write operation
1531  //Set the START_FINISH bit to 1 to initiate the operation
1533 
1534  //Start the write operation
1536  value);
1537 
1538  //When the operation is complete, the START_FINISH bit will be cleared
1539  //automatically
1540  do
1541  {
1542  //Read the Static Address and Reserved Multicast Table Control register
1543  value = lan9646ReadSwitchReg32(interface,
1545 
1546  //Poll the START_FINISH bit
1548  }
1549 }
1550 
1551 
1552 /**
1553  * @brief Read an entry from the dynamic MAC table
1554  * @param[in] interface Underlying network interface
1555  * @param[in] index Zero-based index of the entry to read
1556  * @param[out] entry Pointer to the forwarding database entry
1557  * @return Error code
1558  **/
1559 
1561  SwitchFdbEntry *entry)
1562 {
1563  error_t error;
1564  uint32_t value;
1565 
1566  //First entry?
1567  if(index == 0)
1568  {
1569  //Clear the ALU Table Access Control register to stop any operation
1571 
1572  //Start the search operation
1576  }
1577 
1578  //Poll the VALID_ENTRY_OR_SEARCH_END bit until it is set
1579  do
1580  {
1581  //Read the ALU Table Access Control register
1583 
1584  //This bit goes high to indicate either a new valid entry is returned or
1585  //the search is complete
1587 
1588  //Check whether the next valid entry is ready
1589  if((value & LAN9646_ALU_TABLE_CTRL_VALID) != 0)
1590  {
1591  //Store the data from the ALU table entry
1592  entry->destPorts = 0;
1593  entry->override = FALSE;
1594 
1595  //Read the ALU Table Entry 1 and 2 registers
1598 
1599  //Retrieve the port associated with this MAC address
1601  {
1603  entry->srcPort = LAN9646_PORT1;
1604  break;
1606  entry->srcPort = LAN9646_PORT2;
1607  break;
1609  entry->srcPort = LAN9646_PORT3;
1610  break;
1612  entry->srcPort = LAN9646_PORT4;
1613  break;
1615  entry->srcPort = LAN9646_PORT6;
1616  break;
1618  entry->srcPort = LAN9646_PORT7;
1619  break;
1620  default:
1621  entry->srcPort = 0;
1622  break;
1623  }
1624 
1625  //Read the ALU Table Entry 3 register
1627 
1628  //Copy MAC address (first 16 bits)
1629  entry->macAddr.b[0] = (value >> 8) & 0xFF;
1630  entry->macAddr.b[1] = value & 0xFF;
1631 
1632  //Read the ALU Table Entry 4 register
1634 
1635  //Copy MAC address (last 32 bits)
1636  entry->macAddr.b[2] = (value >> 24) & 0xFF;
1637  entry->macAddr.b[3] = (value >> 16) & 0xFF;
1638  entry->macAddr.b[4] = (value >> 8) & 0xFF;
1639  entry->macAddr.b[5] = value & 0xFF;
1640 
1641  //Successful processing
1642  error = NO_ERROR;
1643  }
1644  else
1645  {
1646  //The search can be stopped any time by setting the START_FINISH bit to 0
1648 
1649  //The end of the table has been reached
1650  error = ERROR_END_OF_TABLE;
1651  }
1652 
1653  //Return status code
1654  return error;
1655 }
1656 
1657 
1658 /**
1659  * @brief Flush dynamic MAC table
1660  * @param[in] interface Underlying network interface
1661  * @param[in] port Port number
1662  **/
1663 
1665 {
1666  uint_t temp;
1667  uint8_t state;
1668 
1669  //Flush only dynamic table entries
1674 
1675  //Valid port number?
1676  if(port >= LAN9646_PORT1 && port <= LAN9646_PORT7)
1677  {
1678  //Save the current state of the port
1680 
1681  //Turn off learning capability
1684 
1685  //All the entries associated with a port that has its learning capability
1686  //being turned off will be flushed
1690 
1691  //Restore the original state of the port
1693  }
1694  else
1695  {
1696  //Trigger a flush of the entire address lookup table
1700  }
1701 }
1702 
1703 
1704 /**
1705  * @brief Set forward ports for unknown multicast packets
1706  * @param[in] interface Underlying network interface
1707  * @param[in] enable Enable or disable forwarding of unknown multicast packets
1708  * @param[in] forwardPorts Port map
1709  **/
1710 
1712  bool_t enable, uint32_t forwardPorts)
1713 {
1714  uint32_t temp;
1715 
1716  //Read Unknown Multicast Control register
1718 
1719  //Clear port map
1721 
1722  //Enable or disable forwarding of unknown multicast packets
1723  if(enable)
1724  {
1725  //Enable forwarding
1727 
1728  //Check whether unknown multicast packets should be forwarded to the CPU port
1729  if((forwardPorts & SWITCH_CPU_PORT_MASK) != 0)
1730  {
1732  }
1733 
1734  //Select the desired forward ports
1735  temp |= forwardPorts & LAN9646_UNKONWN_MULTICAST_CTRL_FWD_MAP_ALL;
1736  }
1737  else
1738  {
1739  //Disable forwarding
1741  }
1742 
1743  //Write the value back to Unknown Multicast Control register
1745 }
1746 
1747 
1748 /**
1749  * @brief Write PHY register
1750  * @param[in] interface Underlying network interface
1751  * @param[in] port Port number
1752  * @param[in] address PHY register address
1753  * @param[in] data Register value
1754  **/
1755 
1756 void lan9646WritePhyReg(NetInterface *interface, uint8_t port,
1757  uint8_t address, uint16_t data)
1758 {
1759  uint16_t n;
1760 
1761  //SPI slave mode?
1762  if(interface->spiDriver != NULL)
1763  {
1764  //The SPI interface provides access to all PHY registers
1766  //Write the 16-bit value
1767  lan9646WriteSwitchReg16(interface, n, data);
1768  }
1769  else if(interface->smiDriver != NULL)
1770  {
1771  //Write the specified PHY register
1772  interface->smiDriver->writePhyReg(SMI_OPCODE_WRITE, port, address, data);
1773  }
1774  else
1775  {
1776  //Write the specified PHY register
1777  interface->nicDriver->writePhyReg(SMI_OPCODE_WRITE, port, address, data);
1778  }
1779 }
1780 
1781 
1782 /**
1783  * @brief Read PHY register
1784  * @param[in] interface Underlying network interface
1785  * @param[in] port Port number
1786  * @param[in] address PHY register address
1787  * @return Register value
1788  **/
1789 
1790 uint16_t lan9646ReadPhyReg(NetInterface *interface, uint8_t port,
1791  uint8_t address)
1792 {
1793  uint16_t n;
1794  uint16_t data;
1795 
1796  //SPI slave mode?
1797  if(interface->spiDriver != NULL)
1798  {
1799  //The SPI interface provides access to all PHY registers
1801  //Read the 16-bit value
1802  data = lan9646ReadSwitchReg16(interface, n);
1803  }
1804  else if(interface->smiDriver != NULL)
1805  {
1806  //Read the specified PHY register
1807  data = interface->smiDriver->readPhyReg(SMI_OPCODE_READ, port, address);
1808  }
1809  else
1810  {
1811  //Read the specified PHY register
1812  data = interface->nicDriver->readPhyReg(SMI_OPCODE_READ, port, address);
1813  }
1814 
1815  //Return register value
1816  return data;
1817 }
1818 
1819 
1820 /**
1821  * @brief Dump PHY registers for debugging purpose
1822  * @param[in] interface Underlying network interface
1823  * @param[in] port Port number
1824  **/
1825 
1826 void lan9646DumpPhyReg(NetInterface *interface, uint8_t port)
1827 {
1828  uint8_t i;
1829 
1830  //Loop through PHY registers
1831  for(i = 0; i < 32; i++)
1832  {
1833  //Display current PHY register
1834  TRACE_DEBUG("%02" PRIu8 ": 0x%04" PRIX16 "\r\n", i,
1835  lan9646ReadPhyReg(interface, port, i));
1836  }
1837 
1838  //Terminate with a line feed
1839  TRACE_DEBUG("\r\n");
1840 }
1841 
1842 
1843 /**
1844  * @brief Write MMD register
1845  * @param[in] interface Underlying network interface
1846  * @param[in] port Port number
1847  * @param[in] devAddr Device address
1848  * @param[in] regAddr Register address
1849  * @param[in] data Register value
1850  **/
1851 
1852 void lan9646WriteMmdReg(NetInterface *interface, uint8_t port,
1853  uint8_t devAddr, uint16_t regAddr, uint16_t data)
1854 {
1855  //Select register operation
1858 
1859  //Write MMD register address
1861 
1862  //Select data operation
1865 
1866  //Write the content of the MMD register
1868 }
1869 
1870 
1871 /**
1872  * @brief Read MMD register
1873  * @param[in] interface Underlying network interface
1874  * @param[in] port Port number
1875  * @param[in] devAddr Device address
1876  * @param[in] regAddr Register address
1877  * @return Register value
1878  **/
1879 
1880 uint16_t lan9646ReadMmdReg(NetInterface *interface, uint8_t port,
1881  uint8_t devAddr, uint16_t regAddr)
1882 {
1883  //Select register operation
1886 
1887  //Write MMD register address
1889 
1890  //Select data operation
1893 
1894  //Read the content of the MMD register
1895  return lan9646ReadPhyReg(interface, port, LAN9646_MMDAADR);
1896 }
1897 
1898 
1899 /**
1900  * @brief Write SGMII register
1901  * @param[in] interface Underlying network interface
1902  * @param[in] address SGMII register address
1903  * @param[in] data Register value
1904  **/
1905 
1906 void lan9646WriteSgmiiReg(NetInterface *interface, uint32_t address,
1907  uint16_t data)
1908 {
1909  //Write the SGMII register address to the Port SGMII Address register
1911 
1912  //Write the SGMII register data to the Port SGMII Data register
1914 }
1915 
1916 
1917 /**
1918  * @brief Read SGMII register
1919  * @param[in] interface Underlying network interface
1920  * @param[in] address SGMII register address
1921  * @return Register value
1922  **/
1923 
1924 uint16_t lan9646ReadSgmiiReg(NetInterface *interface, uint32_t address)
1925 {
1926  //Write the SGMII register address to the Port SGMII Address register
1928 
1929  //Read the SGMII register data from the Port SGMII Data register
1931 }
1932 
1933 
1934 /**
1935  * @brief Write switch register (8 bits)
1936  * @param[in] interface Underlying network interface
1937  * @param[in] address Switch register address
1938  * @param[in] data Register value
1939  **/
1940 
1941 void lan9646WriteSwitchReg8(NetInterface *interface, uint16_t address,
1942  uint8_t data)
1943 {
1944  uint32_t command;
1945 
1946  //SPI slave mode?
1947  if(interface->spiDriver != NULL)
1948  {
1949  //Set up a write operation
1950  command = LAN9646_SPI_CMD_WRITE;
1951  //Set register address
1952  command |= (address << 5) & LAN9646_SPI_CMD_ADDR;
1953 
1954  //Pull the CS pin low
1955  interface->spiDriver->assertCs();
1956 
1957  //Write 32-bit command
1958  interface->spiDriver->transfer((command >> 24) & 0xFF);
1959  interface->spiDriver->transfer((command >> 16) & 0xFF);
1960  interface->spiDriver->transfer((command >> 8) & 0xFF);
1961  interface->spiDriver->transfer(command & 0xFF);
1962 
1963  //Write 8-bit data
1964  interface->spiDriver->transfer(data);
1965 
1966  //Terminate the operation by raising the CS pin
1967  interface->spiDriver->deassertCs();
1968  }
1969  else
1970  {
1971  //The MDC/MDIO interface does not have access to all the configuration
1972  //registers. It can only access the standard MIIM registers
1973  }
1974 }
1975 
1976 
1977 /**
1978  * @brief Read switch register (8 bits)
1979  * @param[in] interface Underlying network interface
1980  * @param[in] address Switch register address
1981  * @return Register value
1982  **/
1983 
1984 uint8_t lan9646ReadSwitchReg8(NetInterface *interface, uint16_t address)
1985 {
1986  uint8_t data;
1987  uint32_t command;
1988 
1989  //SPI slave mode?
1990  if(interface->spiDriver != NULL)
1991  {
1992  //Set up a read operation
1993  command = LAN9646_SPI_CMD_READ;
1994  //Set register address
1995  command |= (address << 5) & LAN9646_SPI_CMD_ADDR;
1996 
1997  //Pull the CS pin low
1998  interface->spiDriver->assertCs();
1999 
2000  //Write 32-bit command
2001  interface->spiDriver->transfer((command >> 24) & 0xFF);
2002  interface->spiDriver->transfer((command >> 16) & 0xFF);
2003  interface->spiDriver->transfer((command >> 8) & 0xFF);
2004  interface->spiDriver->transfer(command & 0xFF);
2005 
2006  //Read 8-bit data
2007  data = interface->spiDriver->transfer(0xFF);
2008 
2009  //Terminate the operation by raising the CS pin
2010  interface->spiDriver->deassertCs();
2011  }
2012  else
2013  {
2014  //The MDC/MDIO interface does not have access to all the configuration
2015  //registers. It can only access the standard MIIM registers
2016  data = 0;
2017  }
2018 
2019  //Return register value
2020  return data;
2021 }
2022 
2023 
2024 /**
2025  * @brief Write switch register (16 bits)
2026  * @param[in] interface Underlying network interface
2027  * @param[in] address Switch register address
2028  * @param[in] data Register value
2029  **/
2030 
2032  uint16_t data)
2033 {
2034  uint32_t command;
2035 
2036  //SPI slave mode?
2037  if(interface->spiDriver != NULL)
2038  {
2039  //Set up a write operation
2040  command = LAN9646_SPI_CMD_WRITE;
2041  //Set register address
2042  command |= (address << 5) & LAN9646_SPI_CMD_ADDR;
2043 
2044  //Pull the CS pin low
2045  interface->spiDriver->assertCs();
2046 
2047  //Write 32-bit command
2048  interface->spiDriver->transfer((command >> 24) & 0xFF);
2049  interface->spiDriver->transfer((command >> 16) & 0xFF);
2050  interface->spiDriver->transfer((command >> 8) & 0xFF);
2051  interface->spiDriver->transfer(command & 0xFF);
2052 
2053  //Write 16-bit data
2054  interface->spiDriver->transfer((data >> 8) & 0xFF);
2055  interface->spiDriver->transfer(data & 0xFF);
2056 
2057  //Terminate the operation by raising the CS pin
2058  interface->spiDriver->deassertCs();
2059  }
2060  else
2061  {
2062  //The MDC/MDIO interface does not have access to all the configuration
2063  //registers. It can only access the standard MIIM registers
2064  }
2065 }
2066 
2067 
2068 /**
2069  * @brief Read switch register (16 bits)
2070  * @param[in] interface Underlying network interface
2071  * @param[in] address Switch register address
2072  * @return Register value
2073  **/
2074 
2075 uint16_t lan9646ReadSwitchReg16(NetInterface *interface, uint16_t address)
2076 {
2077  uint16_t data;
2078  uint32_t command;
2079 
2080  //SPI slave mode?
2081  if(interface->spiDriver != NULL)
2082  {
2083  //Set up a read operation
2084  command = LAN9646_SPI_CMD_READ;
2085  //Set register address
2086  command |= (address << 5) & LAN9646_SPI_CMD_ADDR;
2087 
2088  //Pull the CS pin low
2089  interface->spiDriver->assertCs();
2090 
2091  //Write 32-bit command
2092  interface->spiDriver->transfer((command >> 24) & 0xFF);
2093  interface->spiDriver->transfer((command >> 16) & 0xFF);
2094  interface->spiDriver->transfer((command >> 8) & 0xFF);
2095  interface->spiDriver->transfer(command & 0xFF);
2096 
2097  //Read 16-bit data
2098  data = interface->spiDriver->transfer(0xFF) << 8;
2099  data |= interface->spiDriver->transfer(0xFF);
2100 
2101  //Terminate the operation by raising the CS pin
2102  interface->spiDriver->deassertCs();
2103  }
2104  else
2105  {
2106  //The MDC/MDIO interface does not have access to all the configuration
2107  //registers. It can only access the standard MIIM registers
2108  data = 0;
2109  }
2110 
2111  //Return register value
2112  return data;
2113 }
2114 
2115 
2116 /**
2117  * @brief Write switch register (32 bits)
2118  * @param[in] interface Underlying network interface
2119  * @param[in] address Switch register address
2120  * @param[in] data Register value
2121  **/
2122 
2124  uint32_t data)
2125 {
2126  uint32_t command;
2127 
2128  //SPI slave mode?
2129  if(interface->spiDriver != NULL)
2130  {
2131  //Set up a write operation
2132  command = LAN9646_SPI_CMD_WRITE;
2133  //Set register address
2134  command |= (address << 5) & LAN9646_SPI_CMD_ADDR;
2135 
2136  //Pull the CS pin low
2137  interface->spiDriver->assertCs();
2138 
2139  //Write 32-bit command
2140  interface->spiDriver->transfer((command >> 24) & 0xFF);
2141  interface->spiDriver->transfer((command >> 16) & 0xFF);
2142  interface->spiDriver->transfer((command >> 8) & 0xFF);
2143  interface->spiDriver->transfer(command & 0xFF);
2144 
2145  //Write 32-bit data
2146  interface->spiDriver->transfer((data >> 24) & 0xFF);
2147  interface->spiDriver->transfer((data >> 16) & 0xFF);
2148  interface->spiDriver->transfer((data >> 8) & 0xFF);
2149  interface->spiDriver->transfer(data & 0xFF);
2150 
2151  //Terminate the operation by raising the CS pin
2152  interface->spiDriver->deassertCs();
2153  }
2154  else
2155  {
2156  //The MDC/MDIO interface does not have access to all the configuration
2157  //registers. It can only access the standard MIIM registers
2158  }
2159 }
2160 
2161 
2162 /**
2163  * @brief Read switch register (32 bits)
2164  * @param[in] interface Underlying network interface
2165  * @param[in] address Switch register address
2166  * @return Register value
2167  **/
2168 
2169 uint32_t lan9646ReadSwitchReg32(NetInterface *interface, uint16_t address)
2170 {
2171  uint32_t data;
2172  uint32_t command;
2173 
2174  //SPI slave mode?
2175  if(interface->spiDriver != NULL)
2176  {
2177  //Set up a read operation
2178  command = LAN9646_SPI_CMD_READ;
2179  //Set register address
2180  command |= (address << 5) & LAN9646_SPI_CMD_ADDR;
2181 
2182  //Pull the CS pin low
2183  interface->spiDriver->assertCs();
2184 
2185  //Write 32-bit command
2186  interface->spiDriver->transfer((command >> 24) & 0xFF);
2187  interface->spiDriver->transfer((command >> 16) & 0xFF);
2188  interface->spiDriver->transfer((command >> 8) & 0xFF);
2189  interface->spiDriver->transfer(command & 0xFF);
2190 
2191  //Read 32-bit data
2192  data = interface->spiDriver->transfer(0xFF) << 24;
2193  data |= interface->spiDriver->transfer(0xFF) << 16;
2194  data |= interface->spiDriver->transfer(0xFF) << 8;
2195  data |= interface->spiDriver->transfer(0xFF);
2196 
2197  //Terminate the operation by raising the CS pin
2198  interface->spiDriver->deassertCs();
2199  }
2200  else
2201  {
2202  //The MDC/MDIO interface does not have access to all the configuration
2203  //registers. It can only access the standard MIIM registers
2204  data = 0;
2205  }
2206 
2207  //Return register value
2208  return data;
2209 }
void nicNotifyLinkChange(NetInterface *interface)
Process link state change notification.
Definition: nic.c:601
void lan9646WriteSwitchReg16(NetInterface *interface, uint16_t address, uint16_t data)
Write switch register (16 bits)
__weak_func void lan9646InitHook(NetInterface *interface)
LAN9646 custom configuration.
uint16_t lan9646ReadSwitchReg16(NetInterface *interface, uint16_t address)
Read switch register (16 bits)
#define LAN9646_PORTn_XMII_CTRL1_SPEED_1000
#define LAN9646_SGMII_CTRL_SPEED_SEL_LSB
@ NIC_LINK_SPEED_1GBPS
Definition: nic.h:113
SwitchPortState lan9646GetPortState(NetInterface *interface, uint8_t port)
Get port state.
#define LAN9646_PORT6_XMII_CTRL0
#define NetContext
Definition: net.h:36
#define LAN9646_SGMII_AN_STATUS_LINK_SPEED_1000MBPS
#define LAN9646_PORT7_SGMII_DATA
int bool_t
Definition: compiler_port.h:63
@ ERROR_NOT_FOUND
Definition: error.h:148
#define LAN9646_ALU_TABLE_ENTRY2_PORT3_FORWARD
void lan9646WriteSgmiiReg(NetInterface *interface, uint32_t address, uint16_t data)
Write SGMII register.
@ NIC_LINK_SPEED_UNKNOWN
Definition: nic.h:110
uint32_t destPorts
Definition: nic.h:152
#define LAN9646_CHIP_ID1
#define LAN9646_PORTn_XMII_CTRL1_RGMII_ID_EG
void lan9646DisableIrq(NetInterface *interface)
Disable interrupts.
#define LAN9646_UNKONWN_MULTICAST_CTRL_FWD_MAP
@ NIC_FULL_DUPLEX_MODE
Definition: nic.h:125
#define LAN9646_SPI_CMD_ADDR
void lan9646WriteSwitchReg8(NetInterface *interface, uint16_t address, uint8_t data)
Write switch register (8 bits)
#define LAN9646_PHYCON_SPEED_10BT
#define LAN9646_ALU_TABLE_ENTRY2_PORT1_FORWARD
@ SWITCH_PORT_STATE_LISTENING
Definition: nic.h:138
void lan9646FlushDynamicFdbTable(NetInterface *interface, uint8_t port)
Flush dynamic MAC table.
#define LAN9646_STATIC_TABLE_ENTRY2_OVERRIDE
void lan9646FlushStaticFdbTable(NetInterface *interface)
Flush static MAC table.
@ ERROR_END_OF_TABLE
Definition: error.h:292
@ SWITCH_PORT_STATE_DISABLED
Definition: nic.h:136
#define LAN9646_SWITCH_LUE_CTRL0_RESERVED_MCAST_LOOKUP_EN
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
#define LAN9646_STATIC_MCAST_TABLE_CTRL_TABLE_INDEX
#define LAN9646_BMSR_LINK_STATUS
#define LAN9646_SWITCH_MAC_CTRL0
#define TRUE
Definition: os_port.h:50
#define LAN9646_MMDACR_DEVAD
uint8_t data[]
Definition: ethernet.h:224
#define LAN9646_ALU_TABLE_ENTRY2_PORT_FORWARD
#define LAN9646_TAIL_TAG_NORMAL_ADDR_LOOKUP
const uint16_t lan9646IngressTailTag[8]
Tail tag rules (host to LAN9646)
@ SWITCH_PORT_STATE_LEARNING
Definition: nic.h:139
error_t lan9646DeleteStaticFdbEntry(NetInterface *interface, const SwitchFdbEntry *entry)
Remove an entry from the static MAC table.
#define LAN9646_SWITCH_LUE_CTRL2_FLUSH_OPTION
uint8_t type
Definition: coap_common.h:176
#define LAN9646_ALU_TABLE_CTRL_ACTION_SEARCH
#define LAN9646_ALU_TABLE_ENTRY2_PORT6_FORWARD
void lan9646EnableIrq(NetInterface *interface)
Enable interrupts.
#define LAN9646_SGMII_AN_STATUS_LINK_SPEED_100MBPS
#define LAN9646_SGMII_CTRL_AN_EN
@ ERROR_INVALID_PORT
Definition: error.h:104
#define LAN9646_STATIC_MCAST_TABLE_CTRL_START_FINISH
#define LAN9646_MMDAADR
void lan9646SetUnknownMcastFwdPorts(NetInterface *interface, bool_t enable, uint32_t forwardPorts)
Set forward ports for unknown multicast packets.
@ ERROR_TABLE_FULL
Definition: error.h:291
#define LAN9646_SWITCH_OP
#define LAN9646_TAIL_TAG_SRC_PORT
error_t lan9646AddStaticFdbEntry(NetInterface *interface, const SwitchFdbEntry *entry)
Add a new entry to the static MAC table.
#define LAN9646_TAIL_TAG_DEST_PORT1
error_t lan9646GetDynamicFdbEntry(NetInterface *interface, uint_t index, SwitchFdbEntry *entry)
Read an entry from the dynamic MAC table.
EthHeader
Definition: ethernet.h:225
#define LAN9646_PORTn_MSTP_STATE_RECEIVE_EN
uint16_t lan9646ReadSgmiiReg(NetInterface *interface, uint32_t address)
Read SGMII register.
#define LAN9646_PHYCON_SPEED_100BTX
__weak_func NicDuplexMode lan9646GetPort7DuplexMode(NetInterface *interface)
Get port 7 duplex mode.
#define LAN9646_SGMII_STATUS
#define LAN9646_UNKONWN_MULTICAST_CTRL_FWD_MAP_ALL
#define LAN9646_UNKONWN_MULTICAST_CTRL_FWD
#define SMI_OPCODE_WRITE
Definition: nic.h:66
uint32_t lan9646GetLinkSpeed(NetInterface *interface, uint8_t port)
Get link speed.
#define LAN9646_PORT2
#define LAN9646_GLOBAL_PORT_MIRROR_SNOOP_CTRL_IGMP_SNOOP_EN
#define LAN9646_ALU_TABLE_ENTRY3
#define LAN9646_SGMII_AN_STATUS_LINK_STATUS
#define LAN9646_PORTn_XMII_CTRL0_DUPLEX
#define LAN9646_PORTn_XMII_CTRL0_SPEED_10_100
uint16_t lan9646ReadPhyReg(NetInterface *interface, uint8_t port, uint8_t address)
Read PHY register.
@ SWITCH_PORT_STATE_UNKNOWN
Definition: nic.h:135
#define FALSE
Definition: os_port.h:46
#define LAN9646_PORT4
void lan9646EnableIgmpSnooping(NetInterface *interface, bool_t enable)
Enable IGMP snooping.
__weak_func void lan9646EventHandler(NetInterface *interface)
LAN9646 event handler.
#define LAN9646_MMD_LED_MODE
#define LAN9646_MMDACR
error_t
Error codes.
Definition: error.h:43
#define LAN9646_PORT1
#define LAN9646_SWITCH_LUE_CTRL0_HASH_OPTION_CRC
#define LAN9646_STATIC_TABLE_ENTRY2
#define LAN9646_TAIL_TAG_DEST_PORT3
#define LAN9646_PORT6_OP_CTRL0
#define LAN9646_SGMII_STATUS_LINK_STATUS
#define LAN9646_SGMII_CTRL_DUPLEX_MODE
#define LAN9646_SWITCH_LUE_CTRL3_AGE_PERIOD_DEFAULT
LAN9646 6-port Gigabit Ethernet switch driver.
NicDuplexMode lan9646GetDuplexMode(NetInterface *interface, uint8_t port)
Get duplex mode.
#define LAN9646_ALU_TABLE_CTRL_START_FINISH
#define LAN9646_MMD_EEE_ADV
#define LAN9646_SGMII_AN_STATUS_FULL_DUPLEX
#define LAN9646_MMDACR_FUNC_DATA_NO_POST_INC
#define LAN9646_STATIC_TABLE_ENTRY2_PORT_FORWARD
#define LAN9646_PORTn_MSTP_STATE_TRANSMIT_EN
#define LAN9646_MMD_LED_MODE_RESERVED_DEFAULT
void lan9646SetAgingTime(NetInterface *interface, uint32_t agingTime)
Set aging time for dynamic filtering entries.
void lan9646DumpPhyReg(NetInterface *interface, uint8_t port)
Dump PHY registers for debugging purpose.
#define NetRxAncillary
Definition: net_misc.h:40
void lan9646WriteSwitchReg32(NetInterface *interface, uint16_t address, uint32_t data)
Write switch register (32 bits)
#define NetInterface
Definition: net.h:40
@ NIC_LINK_SPEED_10MBPS
Definition: nic.h:111
@ ERROR_INVALID_LENGTH
Definition: error.h:111
void lan9646WriteMmdReg(NetInterface *interface, uint8_t port, uint8_t devAddr, uint16_t regAddr, uint16_t data)
Write MMD register.
uint32_t lan9646ReadSwitchReg32(NetInterface *interface, uint16_t address)
Read switch register (32 bits)
#define LAN9646_ALU_TABLE_ENTRY1
#define LAN9646_ALU_TABLE_CTRL
error_t ethPadFrame(NetBuffer *buffer, size_t *length)
Ethernet frame padding.
#define LAN9646_SPI_CMD_READ
void lan9646WritePhyReg(NetInterface *interface, uint8_t port, uint8_t address, uint16_t data)
Write PHY register.
#define LAN9646_SPI_CMD_WRITE
#define LAN9646_GLOBAL_PORT_MIRROR_SNOOP_CTRL
#define NetTxAncillary
Definition: net_misc.h:36
#define LAN9646_BMSR
#define SMI_OPCODE_READ
Definition: nic.h:67
SwitchPortState
Switch port state.
Definition: nic.h:134
uint8_t lan9646ReadSwitchReg8(NetInterface *interface, uint16_t address)
Read switch register (8 bits)
#define LAN9646_SWITCH_LUE_CTRL2
#define TRACE_INFO(...)
Definition: debug.h:105
#define LAN9646_PORT6
#define LAN9646_ALU_TABLE_ENTRY2_PORT2_FORWARD
uint8_t length
Definition: tcp.h:375
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
#define LAN9646_PORTn_ETH_PHY_REG(port, addr)
#define LAN9646_STATIC_MCAST_TABLE_CTRL_TABLE_SELECT
#define MIN(a, b)
Definition: os_port.h:63
void lan9646EnableMldSnooping(NetInterface *interface, bool_t enable)
Enable MLD snooping.
error_t lan9646UntagFrame(NetInterface *interface, uint8_t **frame, size_t *length, NetRxAncillary *ancillary)
Decode tail tag from incoming Ethernet frame.
#define LAN9646_STATIC_TABLE_ENTRY1_VALID
#define LAN9646_TAIL_TAG_DEST_PORT2
#define LAN9646_PORT3
@ SWITCH_PORT_STATE_FORWARDING
Definition: nic.h:140
#define LAN9646_TAIL_TAG_PORT_BLOCKING_OVERRIDE
__weak_func uint32_t lan9646GetPort7LinkSpeed(NetInterface *interface)
Get port 7 link speed.
#define LAN9646_TAIL_TAG_DEST_PORT7
uint16_t port
Definition: dns_common.h:270
#define LAN9646_PHYCON_SPEED_1000BT
const SwitchDriver lan9646SwitchDriver
LAN9646 Ethernet switch driver.
#define LAN9646_SGMII_AN_STATUS
#define TRACE_DEBUG(...)
Definition: debug.h:119
#define LAN9646_PHYCON_DUPLEX_STATUS
#define LAN9646_STATIC_MCAST_TABLE_CTRL_ACTION
#define LAN9646_TAIL_TAG_DEST_PORT4
#define LAN9646_STATIC_MAC_TABLE_SIZE
#define LAN9646_STATIC_TABLE_ENTRY1
uint16_t regAddr
Ethernet switch driver.
Definition: nic.h:325
#define LAN9646_STATIC_TABLE_ENTRY4
#define LAN9646_PORT7
error_t lan9646TagFrame(NetInterface *interface, NetBuffer *buffer, size_t *offset, NetTxAncillary *ancillary)
Add tail tag to Ethernet frame.
#define HTONS(value)
Definition: cpu_endian.h:410
uint8_t n
#define LAN9646_ALU_TABLE_ENTRY4
#define LAN9646_GLOBAL_PORT_MIRROR_SNOOP_CTRL_MLD_SNOOP_EN
#define LAN9646_PORT5
#define LAN9646_PORT_MASK
@ ERROR_INVALID_ENTRY
Definition: error.h:290
error_t netBufferAppend(NetBuffer *dest, const void *src, size_t length)
Append data a multi-part buffer.
Definition: net_mem.c:604
Ipv6Addr address[]
Definition: ipv6.h:345
#define LAN9646_PORT7_SGMII_ADDR
#define LAN9646_SWITCH_LUE_CTRL2_FLUSH_OPTION_DYNAMIC
#define LAN9646_ALU_TABLE_ENTRY2_PORT7_FORWARD
NicDuplexMode
Duplex mode.
Definition: nic.h:122
#define LAN9646_ALU_TABLE_CTRL_VALID_ENTRY_OR_SEARCH_END
MacAddr macAddr
Definition: nic.h:150
#define LAN9646_SWITCH_LUE_CTRL1_FLUSH_ALU_TABLE
uint8_t srcPort
Definition: nic.h:151
@ NIC_HALF_DUPLEX_MODE
Definition: nic.h:124
uint8_t value[]
Definition: tcp.h:376
#define LAN9646_CHIP_ID1_DEFAULT
__weak_func bool_t lan9646GetPort7LinkState(NetInterface *interface)
Get port 7 link state.
#define macCompAddr(macAddr1, macAddr2)
Definition: ethernet.h:130
error_t lan9646GetStaticFdbEntry(NetInterface *interface, uint_t index, SwitchFdbEntry *entry)
Read an entry from the static MAC table.
#define LAN9646_STATIC_TABLE_ENTRY3
#define LAN9646_PORTn_XMII_CTRL1_IF_TYPE_RGMII
#define LAN9646_PORTn_MSTP_STATE(port)
#define LAN9646_UNKONWN_MULTICAST_CTRL
@ NIC_UNKNOWN_DUPLEX_MODE
Definition: nic.h:123
#define LAN9646_PHYCON
#define LAN9646_SGMII_CTRL_SOFT_RESET
#define LAN9646_SWITCH_LUE_CTRL1_FLUSH_MSTP_ENTRIES
#define LAN9646_PORT6_MASK
#define LAN9646_SGMII_AN_STATUS_LINK_SPEED_10MBPS
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
#define LAN9646_STATIC_MCAST_TABLE_CTRL
#define LAN9646_SWITCH_LUE_CTRL1
#define LAN9646_ALU_TABLE_CTRL_VALID
__weak_func void lan9646Tick(NetInterface *interface)
LAN9646 timer handler.
#define LAN9646_UNKONWN_MULTICAST_CTRL_FWD_MAP_PORT6
#define LAN9646_ALU_TABLE_ENTRY2
#define LAN9646_PORTn_XMII_CTRL1_RGMII_ID_IG
#define SWITCH_CPU_PORT_MASK
Definition: nic.h:60
@ NIC_LINK_SPEED_100MBPS
Definition: nic.h:112
#define LAN9646_MMDACR_FUNC_ADDR
#define LAN9646_SWITCH_LUE_CTRL0
unsigned int uint_t
Definition: compiler_port.h:57
#define LAN9646_SGMII_AN_STATUS_LINK_SPEED
TCP/IP stack core.
#define LAN9646_PORT6_XMII_CTRL1
#define LAN9646_SWITCH_MAC_CTRL0_FRAME_LEN_CHECK_EN
#define LAN9646_MMD_LED_MODE_LED_MODE_TRI_COLOR_DUAL
error_t lan9646Init(NetInterface *interface)
LAN9646 Ethernet switch initialization.
#define LAN9646_PORTn_OP_CTRL0_TAIL_TAG_EN
#define LAN9646_SGMII_CTRL
#define LAN9646_PORTn_XMII_CTRL1_IF_TYPE
void lan9646EnableRsvdMcastTable(NetInterface *interface, bool_t enable)
Enable reserved multicast table.
void lan9646SetPortState(NetInterface *interface, uint8_t port, SwitchPortState state)
Set port state.
uint16_t lan9646ReadMmdReg(NetInterface *interface, uint8_t port, uint8_t devAddr, uint16_t regAddr)
Read MMD register.
#define LAN9646_SWITCH_LUE_CTRL0_AGE_COUNT_DEFAULT
Helper functions for Ethernet.
#define LAN9646_SWITCH_OP_START_SWITCH
bool_t lan9646GetLinkState(NetInterface *interface, uint8_t port)
Get link state.
#define LAN9646_ALU_TABLE_ENTRY2_PORT4_FORWARD
@ NO_ERROR
Success.
Definition: error.h:44
bool_t override
Definition: nic.h:153
Debugging facilities.
Forwarding database entry.
Definition: nic.h:149
#define LAN9646_PORTn_MSTP_STATE_LEARNING_DIS
#define LAN9646_SGMII_CTRL_SPEED_SEL_MSB
#define LAN9646_SWITCH_LUE_CTRL3