ksz8863_driver.c
Go to the documentation of this file.
1 /**
2  * @file ksz8863_driver.c
3  * @brief KSZ8863 3-port Ethernet switch driver
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 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.4.4
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 KSZ8863 Ethernet switch driver
43  **/
44 
46 {
70 };
71 
72 
73 /**
74  * @brief Tail tag rules (host to KSZ8863)
75  **/
76 
77 const uint8_t ksz8863IngressTailTag[3] =
78 {
82 };
83 
84 
85 /**
86  * @brief KSZ8863 Ethernet switch initialization
87  * @param[in] interface Underlying network interface
88  * @return Error code
89  **/
90 
92 {
93  uint_t port;
94 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
95  uint8_t temp;
96 #endif
97 
98  //Debug message
99  TRACE_INFO("Initializing KSZ8863...\r\n");
100 
101  //SPI slave mode?
102  if(interface->spiDriver != NULL)
103  {
104  //Initialize SPI interface
105  interface->spiDriver->init();
106  }
107  else if(interface->smiDriver != NULL)
108  {
109  //Initialize serial management interface
110  interface->smiDriver->init();
111  }
112  else
113  {
114  //Just for sanity
115  }
116 
117 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
118  //Wait for the serial interface to be ready
119  do
120  {
121  //Read CHIP_ID0 register
122  temp = ksz8863ReadSwitchReg(interface, KSZ8863_CHIP_ID0);
123 
124  //The returned data is invalid until the serial interface is ready
125  } while(temp != KSZ8863_CHIP_ID0_FAMILY_ID_DEFAULT);
126 
127  //Enable tail tag feature
128  temp = ksz8863ReadSwitchReg(interface, KSZ8863_GLOBAL_CTRL1);
131 
132  //Loop through the ports
134  {
135  //Port separation mode?
136  if(interface->port != 0)
137  {
138  //Disable packet transmission and address learning
140  }
141  else
142  {
143  //Enable transmission, reception and address learning
145  }
146  }
147 
148  //Dump switch registers for debugging purpose
149  ksz8863DumpSwitchReg(interface);
150 #endif
151 
152  //SMI interface mode?
153  if(interface->spiDriver == NULL)
154  {
155  //Loop through the ports
157  {
158  //Debug message
159  TRACE_DEBUG("Port %u:\r\n", port);
160  //Dump PHY registers for debugging purpose
161  ksz8863DumpPhyReg(interface, port);
162  }
163  }
164 
165  //Perform custom configuration
166  ksz8863InitHook(interface);
167 
168  //Force the TCP/IP stack to poll the link state at startup
169  interface->phyEvent = TRUE;
170  //Notify the TCP/IP stack of the event
172 
173  //Successful initialization
174  return NO_ERROR;
175 }
176 
177 
178 /**
179  * @brief KSZ8863 custom configuration
180  * @param[in] interface Underlying network interface
181  **/
182 
183 __weak_func void ksz8863InitHook(NetInterface *interface)
184 {
185 }
186 
187 
188 /**
189  * @brief KSZ8863 timer handler
190  * @param[in] interface Underlying network interface
191  **/
192 
193 void ksz8863Tick(NetInterface *interface)
194 {
195  uint_t port;
196  bool_t linkState;
197 
198 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
199  //Port separation mode?
200  if(interface->port != 0)
201  {
202  uint_t i;
203  NetInterface *virtualInterface;
204 
205  //Loop through network interfaces
206  for(i = 0; i < NET_INTERFACE_COUNT; i++)
207  {
208  //Point to the current interface
209  virtualInterface = &netInterface[i];
210 
211  //Check whether the current virtual interface is attached to the
212  //physical interface
213  if(virtualInterface == interface ||
214  virtualInterface->parent == interface)
215  {
216  //Retrieve current link state
217  linkState = ksz8863GetLinkState(interface, virtualInterface->port);
218 
219  //Link up or link down event?
220  if(linkState != virtualInterface->linkState)
221  {
222  //Set event flag
223  interface->phyEvent = TRUE;
224  //Notify the TCP/IP stack of the event
226  }
227  }
228  }
229  }
230  else
231 #endif
232  {
233  //Initialize link state
234  linkState = FALSE;
235 
236  //Loop through the ports
238  {
239  //Retrieve current link state
240  if(ksz8863GetLinkState(interface, port))
241  {
242  linkState = TRUE;
243  }
244  }
245 
246  //Link up or link down event?
247  if(linkState != interface->linkState)
248  {
249  //Set event flag
250  interface->phyEvent = TRUE;
251  //Notify the TCP/IP stack of the event
253  }
254  }
255 }
256 
257 
258 /**
259  * @brief Enable interrupts
260  * @param[in] interface Underlying network interface
261  **/
262 
264 {
265 }
266 
267 
268 /**
269  * @brief Disable interrupts
270  * @param[in] interface Underlying network interface
271  **/
272 
274 {
275 }
276 
277 
278 /**
279  * @brief KSZ8863 event handler
280  * @param[in] interface Underlying network interface
281  **/
282 
284 {
285  uint_t port;
286  bool_t linkState;
287 
288 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
289  //Port separation mode?
290  if(interface->port != 0)
291  {
292  uint_t i;
293  NetInterface *virtualInterface;
294 
295  //Loop through network interfaces
296  for(i = 0; i < NET_INTERFACE_COUNT; i++)
297  {
298  //Point to the current interface
299  virtualInterface = &netInterface[i];
300 
301  //Check whether the current virtual interface is attached to the
302  //physical interface
303  if(virtualInterface == interface ||
304  virtualInterface->parent == interface)
305  {
306  //Get the port number associated with the current interface
307  port = virtualInterface->port;
308 
309  //Valid port?
310  if(port >= KSZ8863_PORT1 && port <= KSZ8863_PORT2)
311  {
312  //Retrieve current link state
313  linkState = ksz8863GetLinkState(interface, port);
314 
315  //Link up event?
316  if(linkState && !virtualInterface->linkState)
317  {
318  //Retrieve host interface speed
319  interface->linkSpeed = ksz8863GetLinkSpeed(interface,
320  KSZ8863_PORT3);
321 
322  //Retrieve host interface duplex mode
323  interface->duplexMode = ksz8863GetDuplexMode(interface,
324  KSZ8863_PORT3);
325 
326  //Adjust MAC configuration parameters for proper operation
327  interface->nicDriver->updateMacConfig(interface);
328 
329  //Check current speed
330  virtualInterface->linkSpeed = ksz8863GetLinkSpeed(interface,
331  port);
332 
333  //Check current duplex mode
334  virtualInterface->duplexMode = ksz8863GetDuplexMode(interface,
335  port);
336 
337  //Update link state
338  virtualInterface->linkState = TRUE;
339 
340  //Process link state change event
341  nicNotifyLinkChange(virtualInterface);
342  }
343  //Link down event
344  else if(!linkState && virtualInterface->linkState)
345  {
346  //Update link state
347  virtualInterface->linkState = FALSE;
348 
349  //Process link state change event
350  nicNotifyLinkChange(virtualInterface);
351  }
352  }
353  }
354  }
355  }
356  else
357 #endif
358  {
359  //Initialize link state
360  linkState = FALSE;
361 
362  //Loop through the ports
364  {
365  //Retrieve current link state
366  if(ksz8863GetLinkState(interface, port))
367  {
368  linkState = TRUE;
369  }
370  }
371 
372  //Link up event?
373  if(linkState)
374  {
375  //Retrieve host interface speed
376  interface->linkSpeed = ksz8863GetLinkSpeed(interface, KSZ8863_PORT3);
377  //Retrieve host interface duplex mode
378  interface->duplexMode = ksz8863GetDuplexMode(interface, KSZ8863_PORT3);
379 
380  //Adjust MAC configuration parameters for proper operation
381  interface->nicDriver->updateMacConfig(interface);
382 
383  //Update link state
384  interface->linkState = TRUE;
385  }
386  else
387  {
388  //Update link state
389  interface->linkState = FALSE;
390  }
391 
392  //Process link state change event
393  nicNotifyLinkChange(interface);
394  }
395 }
396 
397 
398 /**
399  * @brief Add tail tag to Ethernet frame
400  * @param[in] interface Underlying network interface
401  * @param[in] buffer Multi-part buffer containing the payload
402  * @param[in,out] offset Offset to the first payload byte
403  * @param[in] ancillary Additional options passed to the stack along with
404  * the packet
405  * @return Error code
406  **/
407 
409  size_t *offset, NetTxAncillary *ancillary)
410 {
411  error_t error;
412 
413  //Initialize status code
414  error = NO_ERROR;
415 
416 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
417  //Valid port?
418  if(ancillary->port <= KSZ8863_PORT2)
419  {
420  size_t length;
421  const uint8_t *tailTag;
422 
423  //The one byte tail tagging is used to indicate the destination port
424  tailTag = &ksz8863IngressTailTag[ancillary->port];
425 
426  //Retrieve the length of the Ethernet frame
427  length = netBufferGetLength(buffer) - *offset;
428 
429  //The host controller should manually add padding to the packet before
430  //inserting the tail tag
431  error = ethPadFrame(buffer, &length);
432 
433  //Check status code
434  if(!error)
435  {
436  //The tail tag is inserted at the end of the packet, just before
437  //the CRC
438  error = netBufferAppend(buffer, tailTag, sizeof(uint8_t));
439  }
440  }
441  else
442  {
443  //The port number is not valid
444  error = ERROR_INVALID_PORT;
445  }
446 #endif
447 
448  //Return status code
449  return error;
450 }
451 
452 
453 /**
454  * @brief Decode tail tag from incoming Ethernet frame
455  * @param[in] interface Underlying network interface
456  * @param[in,out] frame Pointer to the received Ethernet frame
457  * @param[in,out] length Length of the frame, in bytes
458  * @param[in,out] ancillary Additional options passed to the stack along with
459  * the packet
460  * @return Error code
461  **/
462 
463 error_t ksz8863UntagFrame(NetInterface *interface, uint8_t **frame,
464  size_t *length, NetRxAncillary *ancillary)
465 {
466  error_t error;
467 
468  //Initialize status code
469  error = NO_ERROR;
470 
471 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
472  //Valid Ethernet frame received?
473  if(*length >= (sizeof(EthHeader) + sizeof(uint8_t)))
474  {
475  uint8_t *tailTag;
476 
477  //The tail tag is inserted at the end of the packet, just before
478  //the CRC
479  tailTag = *frame + *length - sizeof(uint8_t);
480 
481  //The one byte tail tagging is used to indicate the source port
482  ancillary->port = (*tailTag & KSZ8863_TAIL_TAG_SRC_PORT) + 1;
483 
484  //Strip tail tag from Ethernet frame
485  *length -= sizeof(uint8_t);
486  }
487  else
488  {
489  //Drop the received frame
490  error = ERROR_INVALID_LENGTH;
491  }
492 #endif
493 
494  //Return status code
495  return error;
496 }
497 
498 
499 /**
500  * @brief Get link state
501  * @param[in] interface Underlying network interface
502  * @param[in] port Port number
503  * @return Link state
504  **/
505 
507 {
508  uint16_t status;
509  bool_t linkState;
510 
511  //Check port number
512  if(port >= KSZ8863_PORT1 && port <= KSZ8863_PORT2)
513  {
514  //SPI slave mode?
515  if(interface->spiDriver != NULL)
516  {
517  //Read port status 0 register
518  status = ksz8863ReadSwitchReg(interface, KSZ8863_PORTn_STAT0(port));
519 
520  //Retrieve current link state
521  linkState = (status & KSZ8863_PORTn_STAT0_LINK_GOOD) ? TRUE : FALSE;
522  }
523  else
524  {
525  //Read status register
526  status = ksz8863ReadPhyReg(interface, port, KSZ8863_BMSR);
527 
528  //Retrieve current link state
529  linkState = (status & KSZ8863_BMSR_LINK_STATUS) ? TRUE : FALSE;
530  }
531  }
532  else
533  {
534  //The specified port number is not valid
535  linkState = FALSE;
536  }
537 
538  //Return link status
539  return linkState;
540 }
541 
542 
543 /**
544  * @brief Get link speed
545  * @param[in] interface Underlying network interface
546  * @param[in] port Port number
547  * @return Link speed
548  **/
549 
550 uint32_t ksz8863GetLinkSpeed(NetInterface *interface, uint8_t port)
551 {
552  uint16_t status;
553  uint32_t linkSpeed;
554 
555  //Check port number
556  if(port >= KSZ8863_PORT1 && port <= KSZ8863_PORT2)
557  {
558  //Read port status 1 register
559  status = ksz8863ReadSwitchReg(interface, KSZ8863_PORTn_STAT1(port));
560 
561  //Retrieve current link speed
562  if((status & KSZ8863_PORTn_STAT1_OP_SPEED) != 0)
563  {
564  linkSpeed = NIC_LINK_SPEED_100MBPS;
565  }
566  else
567  {
568  linkSpeed = NIC_LINK_SPEED_10MBPS;
569  }
570  }
571  else if(port == KSZ8863_PORT3)
572  {
573  //Read global control 4 register
574  status = ksz8863ReadSwitchReg(interface, KSZ8863_GLOBAL_CTRL4);
575 
576  //Retrieve host interface speed
577  if((status & KSZ8863_GLOBAL_CTRL4_SW_MII_10BT) != 0)
578  {
579  linkSpeed = NIC_LINK_SPEED_10MBPS;
580  }
581  else
582  {
583  linkSpeed = NIC_LINK_SPEED_100MBPS;
584  }
585  }
586  else
587  {
588  //The specified port number is not valid
589  linkSpeed = NIC_LINK_SPEED_UNKNOWN;
590  }
591 
592  //Return link status
593  return linkSpeed;
594 }
595 
596 
597 /**
598  * @brief Get duplex mode
599  * @param[in] interface Underlying network interface
600  * @param[in] port Port number
601  * @return Duplex mode
602  **/
603 
605 {
606  uint16_t status;
607  NicDuplexMode duplexMode;
608 
609  //Check port number
610  if(port >= KSZ8863_PORT1 && port <= KSZ8863_PORT2)
611  {
612  //Read port status 1 register
613  status = ksz8863ReadSwitchReg(interface, KSZ8863_PORTn_STAT1(port));
614 
615  //Retrieve current duplex mode
616  if((status & KSZ8863_PORTn_STAT1_OP_DUPLEX) != 0)
617  {
618  duplexMode = NIC_FULL_DUPLEX_MODE;
619  }
620  else
621  {
622  duplexMode = NIC_HALF_DUPLEX_MODE;
623  }
624  }
625  else if(port == KSZ8863_PORT3)
626  {
627  //Read global control 4 register
628  status = ksz8863ReadSwitchReg(interface, KSZ8863_GLOBAL_CTRL4);
629 
630  //Retrieve host interface duplex mode
632  {
633  duplexMode = NIC_HALF_DUPLEX_MODE;
634  }
635  else
636  {
637  duplexMode = NIC_FULL_DUPLEX_MODE;
638  }
639  }
640  else
641  {
642  //The specified port number is not valid
643  duplexMode = NIC_UNKNOWN_DUPLEX_MODE;
644  }
645 
646  //Return duplex mode
647  return duplexMode;
648 }
649 
650 
651 /**
652  * @brief Set port state
653  * @param[in] interface Underlying network interface
654  * @param[in] port Port number
655  * @param[in] state Port state
656  **/
657 
658 void ksz8863SetPortState(NetInterface *interface, uint8_t port,
659  SwitchPortState state)
660 {
661  uint8_t temp;
662 
663  //Check port number
664  if(port >= KSZ8863_PORT1 && port <= KSZ8863_PORT2)
665  {
666  //Read port control 2 register
667  temp = ksz8863ReadSwitchReg(interface, KSZ8863_PORTn_CTRL2(port));
668 
669  //Update port state
670  switch(state)
671  {
672  //Listening state
677  break;
678 
679  //Learning state
684  break;
685 
686  //Forwarding state
691  break;
692 
693  //Disabled state
694  default:
698  break;
699  }
700 
701  //Write the value back to port control 2 register
703  }
704 }
705 
706 
707 /**
708  * @brief Get port state
709  * @param[in] interface Underlying network interface
710  * @param[in] port Port number
711  * @return Port state
712  **/
713 
715 {
716  uint8_t temp;
717  SwitchPortState state;
718 
719  //Check port number
720  if(port >= KSZ8863_PORT1 && port <= KSZ8863_PORT2)
721  {
722  //Read port control 2 register
723  temp = ksz8863ReadSwitchReg(interface, KSZ8863_PORTn_CTRL2(port));
724 
725  //Check port state
726  if((temp & KSZ8863_PORTn_CTRL2_TRANSMIT_EN) == 0 &&
727  (temp & KSZ8863_PORTn_CTRL2_RECEIVE_EN) == 0 &&
728  (temp & KSZ8863_PORTn_CTRL2_LEARNING_DIS) != 0)
729  {
730  //Disabled state
732  }
733  else if((temp & KSZ8863_PORTn_CTRL2_TRANSMIT_EN) == 0 &&
734  (temp & KSZ8863_PORTn_CTRL2_RECEIVE_EN) != 0 &&
735  (temp & KSZ8863_PORTn_CTRL2_LEARNING_DIS) != 0)
736  {
737  //Listening state
739  }
740  else if((temp & KSZ8863_PORTn_CTRL2_TRANSMIT_EN) == 0 &&
741  (temp & KSZ8863_PORTn_CTRL2_RECEIVE_EN) == 0 &&
742  (temp & KSZ8863_PORTn_CTRL2_LEARNING_DIS) == 0)
743  {
744  //Learning state
746  }
747  else if((temp & KSZ8863_PORTn_CTRL2_TRANSMIT_EN) != 0 &&
748  (temp & KSZ8863_PORTn_CTRL2_RECEIVE_EN) != 0 &&
749  (temp & KSZ8863_PORTn_CTRL2_LEARNING_DIS) == 0)
750  {
751  //Forwarding state
753  }
754  else
755  {
756  //Unknown state
758  }
759  }
760  else
761  {
762  //The specified port number is not valid
764  }
765 
766  //Return port state
767  return state;
768 }
769 
770 
771 /**
772  * @brief Set aging time for dynamic filtering entries
773  * @param[in] interface Underlying network interface
774  * @param[in] agingTime Aging time, in seconds
775  **/
776 
777 void ksz8863SetAgingTime(NetInterface *interface, uint32_t agingTime)
778 {
779  //The aging period is fixed to 200 seconds
780 }
781 
782 
783 /**
784  * @brief Enable IGMP snooping
785  * @param[in] interface Underlying network interface
786  * @param[in] enable Enable or disable IGMP snooping
787  **/
788 
790 {
791  uint8_t temp;
792 
793  //Read global control 3 register
794  temp = ksz8863ReadSwitchReg(interface, KSZ8863_GLOBAL_CTRL3);
795 
796  //Enable or disable IGMP snooping
797  if(enable)
798  {
800  }
801  else
802  {
804  }
805 
806  //Write the value back to global control 3 register
808 }
809 
810 
811 /**
812  * @brief Enable MLD snooping
813  * @param[in] interface Underlying network interface
814  * @param[in] enable Enable or disable MLD snooping
815  **/
816 
818 {
819  //Not implemented
820 }
821 
822 
823 /**
824  * @brief Enable reserved multicast table
825  * @param[in] interface Underlying network interface
826  * @param[in] enable Enable or disable reserved group addresses
827  **/
828 
830 {
831  //Not implemented
832 }
833 
834 
835 /**
836  * @brief Add a new entry to the static MAC table
837  * @param[in] interface Underlying network interface
838  * @param[in] entry Pointer to the forwarding database entry
839  * @return Error code
840  **/
841 
843  const SwitchFdbEntry *entry)
844 {
845  error_t error;
846  uint_t i;
847  uint_t j;
848  uint8_t *p;
849  SwitchFdbEntry currentEntry;
850  Ksz8863StaticMacEntry newEntry;
851 
852  //Keep track of the first free entry
854 
855  //Loop through the static MAC table
856  for(i = 0; i < KSZ8863_STATIC_MAC_TABLE_SIZE; i++)
857  {
858  //Read current entry
859  error = ksz8863GetStaticFdbEntry(interface, i, &currentEntry);
860 
861  //Valid entry?
862  if(!error)
863  {
864  //Check whether the table already contains the specified MAC address
865  if(macCompAddr(&currentEntry.macAddr, &entry->macAddr))
866  {
867  j = i;
868  break;
869  }
870  }
871  else
872  {
873  //Keep track of the first free entry
875  {
876  j = i;
877  }
878  }
879  }
880 
881  //Any entry available?
883  {
884  //Format MAC entry
885  newEntry.reserved = 0;
886  newEntry.fidH = 0;
887  newEntry.fidL = 0;
888  newEntry.useFid = 0;
889  newEntry.override = entry->override;
890  newEntry.valid = TRUE;
891  newEntry.macAddr = entry->macAddr;
892 
893  //Set the relevant forward ports
894  if(entry->destPorts == SWITCH_CPU_PORT_MASK)
895  {
896  newEntry.forwardPorts = KSZ8863_PORT3_MASK;
897  }
898  else
899  {
900  newEntry.forwardPorts = entry->destPorts & KSZ8863_PORT_MASK;
901  }
902 
903  //Point to the MAC entry
904  p = (uint8_t *) &newEntry;
905 
906  //Write indirect data registers
907  for(i = 0; i < sizeof(Ksz8863StaticMacEntry); i++)
908  {
909  ksz8863WriteSwitchReg(interface, KSZ8863_INDIRECT_DATA7 + i, p[i]);
910  }
911 
912  //Select the static MAC address table
916 
917  //Trigger the write operation
919 
920  //Successful processing
921  error = NO_ERROR;
922  }
923  else
924  {
925  //The static MAC table is full
926  error = ERROR_TABLE_FULL;
927  }
928 
929  //Return status code
930  return error;
931 }
932 
933 
934 /**
935  * @brief Remove an entry from the static MAC table
936  * @param[in] interface Underlying network interface
937  * @param[in] entry Forwarding database entry to remove from the table
938  * @return Error code
939  **/
940 
942  const SwitchFdbEntry *entry)
943 {
944  error_t error;
945  uint_t i;
946  uint_t j;
947  SwitchFdbEntry currentEntry;
948 
949  //Loop through the static MAC table
950  for(j = 0; j < KSZ8863_STATIC_MAC_TABLE_SIZE; j++)
951  {
952  //Read current entry
953  error = ksz8863GetStaticFdbEntry(interface, j, &currentEntry);
954 
955  //Valid entry?
956  if(!error)
957  {
958  //Check whether the table contains the specified MAC address
959  if(macCompAddr(&currentEntry.macAddr, &entry->macAddr))
960  {
961  break;
962  }
963  }
964  }
965 
966  //Any matching entry?
968  {
969  //Clear indirect data registers
970  for(i = 0; i < sizeof(Ksz8863StaticMacEntry); i++)
971  {
973  }
974 
975  //Select the static MAC address table
979 
980  //Trigger the write operation
982 
983  //Successful processing
984  error = NO_ERROR;
985  }
986  else
987  {
988  //The static MAC table does not contain the specified address
989  error = ERROR_NOT_FOUND;
990  }
991 
992  //Return status code
993  return error;
994 }
995 
996 
997 /**
998  * @brief Read an entry from the static MAC table
999  * @param[in] interface Underlying network interface
1000  * @param[in] index Zero-based index of the entry to read
1001  * @param[out] entry Pointer to the forwarding database entry
1002  * @return Error code
1003  **/
1004 
1006  SwitchFdbEntry *entry)
1007 {
1008  error_t error;
1009  uint_t i;
1010  uint8_t *p;
1011  Ksz8863StaticMacEntry currentEntry;
1012 
1013  //Check index parameter
1014  if(index < KSZ8863_STATIC_MAC_TABLE_SIZE)
1015  {
1016  //Select the static MAC address table
1020 
1021  //Trigger the read operation
1022  ksz8863WriteSwitchReg(interface, KSZ8863_INDIRECT_CTRL1, index);
1023 
1024  //Point to the MAC entry
1025  p = (uint8_t *) &currentEntry;
1026 
1027  //Read indirect data registers
1028  for(i = 0; i < sizeof(Ksz8863StaticMacEntry); i++)
1029  {
1030  p[i] = ksz8863ReadSwitchReg(interface, KSZ8863_INDIRECT_DATA7 + i);
1031  }
1032 
1033  //Valid entry?
1034  if(currentEntry.valid)
1035  {
1036  //Copy MAC entry
1037  entry->macAddr = currentEntry.macAddr;
1038  entry->srcPort = 0;
1039  entry->destPorts = currentEntry.forwardPorts & KSZ8863_PORT_MASK;
1040  entry->override = currentEntry.override;
1041 
1042  //Successful processing
1043  error = NO_ERROR;
1044  }
1045  else
1046  {
1047  //The entry is not valid
1048  error = ERROR_INVALID_ENTRY;
1049  }
1050  }
1051  else
1052  {
1053  //The end of the table has been reached
1054  error = ERROR_END_OF_TABLE;
1055  }
1056 
1057  //Return status code
1058  return error;
1059 }
1060 
1061 
1062 /**
1063  * @brief Flush static MAC table
1064  * @param[in] interface Underlying network interface
1065  **/
1066 
1068 {
1069  uint_t i;
1070  uint_t temp;
1071  uint8_t state[3];
1072 
1073  //Loop through the ports
1074  for(i = KSZ8863_PORT1; i <= KSZ8863_PORT3; i++)
1075  {
1076  //Save the current state of the port
1077  state[i - 1] = ksz8863ReadSwitchReg(interface, KSZ8863_PORTn_CTRL2(i));
1078 
1079  //Turn off learning capability
1081  state[i - 1] | KSZ8863_PORTn_CTRL2_LEARNING_DIS);
1082  }
1083 
1084  //All the entries associated with a port that has its learning capability
1085  //being turned off will be flushed
1086  temp = ksz8863ReadSwitchReg(interface, KSZ8863_GLOBAL_CTRL0);
1088  ksz8863WriteSwitchReg(interface, KSZ8863_GLOBAL_CTRL0, temp);
1089 
1090  //Loop through the ports
1091  for(i = KSZ8863_PORT1; i <= KSZ8863_PORT3; i++)
1092  {
1093  //Restore the original state of the port
1094  ksz8863WriteSwitchReg(interface, KSZ8863_PORTn_CTRL2(i), state[i - 1]);
1095  }
1096 }
1097 
1098 
1099 /**
1100  * @brief Read an entry from the dynamic MAC table
1101  * @param[in] interface Underlying network interface
1102  * @param[in] index Zero-based index of the entry to read
1103  * @param[out] entry Pointer to the forwarding database entry
1104  * @return Error code
1105  **/
1106 
1108  SwitchFdbEntry *entry)
1109 {
1110  error_t error;
1111  uint_t i;
1112  uint_t n;
1113  uint8_t *p;
1114  Ksz8863DynamicMacEntry currentEntry;
1115 
1116  //Check index parameter
1117  if(index < KSZ8863_DYNAMIC_MAC_TABLE_SIZE)
1118  {
1119  //Read the MAC entry at the specified index
1120  do
1121  {
1122  //Select the dynamic MAC address table
1126  (MSB(index) & KSZ8863_INDIRECT_CTRL0_ADDR_H));
1127 
1128  //Trigger the read operation
1129  ksz8863WriteSwitchReg(interface, KSZ8863_INDIRECT_CTRL1, LSB(index));
1130 
1131  //Point to the MAC entry
1132  p = (uint8_t *) &currentEntry;
1133 
1134  //Read indirect data registers
1135  for(i = 0; i < sizeof(Ksz8863DynamicMacEntry); i++)
1136  {
1137  p[i] = ksz8863ReadSwitchReg(interface, KSZ8863_INDIRECT_DATA8 + i);
1138  }
1139 
1140  //Retry until the entry is ready
1141  } while(currentEntry.dataNotReady);
1142 
1143  //Check whether there are valid entries in the table
1144  if(!currentEntry.macEmpty)
1145  {
1146  //Retrieve the number of valid entries
1147  n = ((currentEntry.numValidEntriesH << 8) |
1148  currentEntry.numValidEntriesL) + 1;
1149  }
1150  else
1151  {
1152  //The table is empty
1153  n = 0;
1154  }
1155 
1156  //Valid entry?
1157  if(index < n)
1158  {
1159  //Copy MAC entry
1160  entry->macAddr = currentEntry.macAddr;
1161  entry->srcPort = currentEntry.sourcePort + 1;
1162  entry->destPorts = 0;
1163  entry->override = FALSE;
1164 
1165  //Successful processing
1166  error = NO_ERROR;
1167  }
1168  else
1169  {
1170  //The end of the table has been reached
1171  error = ERROR_END_OF_TABLE;
1172  }
1173  }
1174  else
1175  {
1176  //The end of the table has been reached
1177  error = ERROR_END_OF_TABLE;
1178  }
1179 
1180  //Return status code
1181  return error;
1182 }
1183 
1184 
1185 /**
1186  * @brief Flush dynamic MAC table
1187  * @param[in] interface Underlying network interface
1188  * @param[in] port Port number
1189  **/
1190 
1192 {
1193  uint_t i;
1194  uint_t temp;
1195  uint8_t state[3];
1196 
1197  //Loop through the ports
1198  for(i = KSZ8863_PORT1; i <= KSZ8863_PORT3; i++)
1199  {
1200  //Matching port number?
1201  if(i == port || port == 0)
1202  {
1203  //Save the current state of the port
1204  state[i - 1] = ksz8863ReadSwitchReg(interface, KSZ8863_PORTn_CTRL2(i));
1205 
1206  //Turn off learning capability
1208  state[i - 1] | KSZ8863_PORTn_CTRL2_LEARNING_DIS);
1209  }
1210  }
1211 
1212  //All the entries associated with a port that has its learning capability
1213  //being turned off will be flushed
1214  temp = ksz8863ReadSwitchReg(interface, KSZ8863_GLOBAL_CTRL0);
1216  ksz8863WriteSwitchReg(interface, KSZ8863_GLOBAL_CTRL0, temp);
1217 
1218  //Loop through the ports
1219  for(i = KSZ8863_PORT1; i <= KSZ8863_PORT3; i++)
1220  {
1221  //Matching port number?
1222  if(i == port || port == 0)
1223  {
1224  //Restore the original state of the port
1225  ksz8863WriteSwitchReg(interface, KSZ8863_PORTn_CTRL2(i), state[i - 1]);
1226  }
1227  }
1228 }
1229 
1230 
1231 /**
1232  * @brief Set forward ports for unknown multicast packets
1233  * @param[in] interface Underlying network interface
1234  * @param[in] enable Enable or disable forwarding of unknown multicast packets
1235  * @param[in] forwardPorts Port map
1236  **/
1237 
1239  bool_t enable, uint32_t forwardPorts)
1240 {
1241  //Not implemented
1242 }
1243 
1244 
1245 /**
1246  * @brief Write PHY register
1247  * @param[in] interface Underlying network interface
1248  * @param[in] port Port number
1249  * @param[in] address PHY register address
1250  * @param[in] data Register value
1251  **/
1252 
1253 void ksz8863WritePhyReg(NetInterface *interface, uint8_t port,
1254  uint8_t address, uint16_t data)
1255 {
1256  //Write the specified PHY register
1257  if(interface->smiDriver != NULL)
1258  {
1259  interface->smiDriver->writePhyReg(SMI_OPCODE_WRITE, port, address, data);
1260  }
1261  else
1262  {
1263  interface->nicDriver->writePhyReg(SMI_OPCODE_WRITE, port, address, data);
1264  }
1265 }
1266 
1267 
1268 /**
1269  * @brief Read PHY register
1270  * @param[in] interface Underlying network interface
1271  * @param[in] port Port number
1272  * @param[in] address PHY register address
1273  * @return Register value
1274  **/
1275 
1276 uint16_t ksz8863ReadPhyReg(NetInterface *interface, uint8_t port,
1277  uint8_t address)
1278 {
1279  uint16_t data;
1280 
1281  //Read the specified PHY register
1282  if(interface->smiDriver != NULL)
1283  {
1284  data = interface->smiDriver->readPhyReg(SMI_OPCODE_READ, port, address);
1285  }
1286  else
1287  {
1288  data = interface->nicDriver->readPhyReg(SMI_OPCODE_READ, port, address);
1289  }
1290 
1291  //Return the value of the PHY register
1292  return data;
1293 }
1294 
1295 
1296 /**
1297  * @brief Dump PHY registers for debugging purpose
1298  * @param[in] interface Underlying network interface
1299  * @param[in] port Port number
1300  **/
1301 
1302 void ksz8863DumpPhyReg(NetInterface *interface, uint8_t port)
1303 {
1304  uint8_t i;
1305 
1306  //Loop through PHY registers
1307  for(i = 0; i < 32; i++)
1308  {
1309  //Display current PHY register
1310  TRACE_DEBUG("%02" PRIu8 ": 0x%04" PRIX16 "\r\n", i,
1311  ksz8863ReadPhyReg(interface, port, i));
1312  }
1313 
1314  //Terminate with a line feed
1315  TRACE_DEBUG("\r\n");
1316 }
1317 
1318 
1319 /**
1320  * @brief Write switch register
1321  * @param[in] interface Underlying network interface
1322  * @param[in] address Switch register address
1323  * @param[in] data Register value
1324  **/
1325 
1326 void ksz8863WriteSwitchReg(NetInterface *interface, uint8_t address,
1327  uint8_t data)
1328 {
1329  uint8_t phyAddr;
1330  uint8_t regAddr;
1331 
1332  //SPI slave mode?
1333  if(interface->spiDriver != NULL)
1334  {
1335  //Pull the CS pin low
1336  interface->spiDriver->assertCs();
1337 
1338  //Set up a write operation
1339  interface->spiDriver->transfer(KSZ8863_SPI_CMD_WRITE);
1340  //Write register address
1341  interface->spiDriver->transfer(address);
1342 
1343  //Write data
1344  interface->spiDriver->transfer(data);
1345 
1346  //Terminate the operation by raising the CS pin
1347  interface->spiDriver->deassertCs();
1348  }
1349  else
1350  {
1351  //SMI register read access is selected when opcode is set to 0 and
1352  //bit 4 of the PHY address is set to 0
1353  phyAddr = (address >> 5) & 0x07;
1354 
1355  //Register address field forms register address bits 4:0
1356  regAddr = address & 0x1F;
1357 
1358  //Registers are 8 data bits wide. For write operation, data bits 15:8
1359  //are not defined, and hence can be set to either zeroes or ones
1360  if(interface->smiDriver != NULL)
1361  {
1362  interface->smiDriver->writePhyReg(SMI_OPCODE_0, phyAddr, regAddr,
1363  data);
1364  }
1365  else
1366  {
1367  interface->nicDriver->writePhyReg(SMI_OPCODE_0, phyAddr, regAddr,
1368  data);
1369  }
1370  }
1371 }
1372 
1373 
1374 /**
1375  * @brief Read switch register
1376  * @param[in] interface Underlying network interface
1377  * @param[in] address Switch register address
1378  * @return Register value
1379  **/
1380 
1381 uint8_t ksz8863ReadSwitchReg(NetInterface *interface, uint8_t address)
1382 {
1383  uint8_t phyAddr;
1384  uint8_t regAddr;
1385  uint8_t data;
1386 
1387  //SPI slave mode?
1388  if(interface->spiDriver != NULL)
1389  {
1390  //Pull the CS pin low
1391  interface->spiDriver->assertCs();
1392 
1393  //Set up a read operation
1394  interface->spiDriver->transfer(KSZ8863_SPI_CMD_READ);
1395  //Write register address
1396  interface->spiDriver->transfer(address);
1397 
1398  //Read data
1399  data = interface->spiDriver->transfer(0xFF);
1400 
1401  //Terminate the operation by raising the CS pin
1402  interface->spiDriver->deassertCs();
1403  }
1404  else
1405  {
1406  //SMI register read access is selected when opcode is set to 0 and
1407  //bit 4 of the PHY address is set to 1
1408  phyAddr = 0x10 | ((address >> 5) & 0x07);
1409 
1410  //Register address field forms register address bits 4:0
1411  regAddr = address & 0x1F;
1412 
1413  //Registers are 8 data bits wide. For read operation, data bits 15:8
1414  //are read back as zeroes
1415  if(interface->smiDriver != NULL)
1416  {
1417  data = interface->smiDriver->readPhyReg(SMI_OPCODE_0, phyAddr,
1418  regAddr) & 0xFF;
1419  }
1420  else
1421  {
1422  data = interface->nicDriver->readPhyReg(SMI_OPCODE_0, phyAddr,
1423  regAddr) & 0xFF;
1424  }
1425  }
1426 
1427  //Return register value
1428  return data;
1429 }
1430 
1431 
1432 /**
1433  * @brief Dump switch registers for debugging purpose
1434  * @param[in] interface Underlying network interface
1435  **/
1436 
1438 {
1439  uint16_t i;
1440 
1441  //Loop through switch registers
1442  for(i = 0; i < 256; i++)
1443  {
1444  //Display current switch register
1445  TRACE_DEBUG("0x%02" PRIX16 " (%02" PRIu16 ") : 0x%02" PRIX8 "\r\n",
1446  i, i, ksz8863ReadSwitchReg(interface, i));
1447  }
1448 
1449  //Terminate with a line feed
1450  TRACE_DEBUG("\r\n");
1451 }
#define KSZ8863_CHIP_ID0
void nicNotifyLinkChange(NetInterface *interface)
Process link state change notification.
Definition: nic.c:559
error_t ksz8863DeleteStaticFdbEntry(NetInterface *interface, const SwitchFdbEntry *entry)
Remove an entry from the static MAC table.
Static MAC table entry.
#define KSZ8863_INDIRECT_CTRL0_TABLE_SEL_DYNAMIC_MAC
void ksz8863EnableIrq(NetInterface *interface)
Enable interrupts.
int bool_t
Definition: compiler_port.h:53
@ ERROR_NOT_FOUND
Definition: error.h:147
void ksz8863DumpPhyReg(NetInterface *interface, uint8_t port)
Dump PHY registers for debugging purpose.
error_t ksz8863GetDynamicFdbEntry(NetInterface *interface, uint_t index, SwitchFdbEntry *entry)
Read an entry from the dynamic MAC table.
@ NIC_LINK_SPEED_UNKNOWN
Definition: nic.h:110
uint32_t destPorts
Definition: nic.h:152
#define netEvent
Definition: net_legacy.h:196
#define KSZ8863_GLOBAL_CTRL4
#define KSZ8863_PORTn_STAT0(port)
uint8_t numValidEntriesL
@ NIC_FULL_DUPLEX_MODE
Definition: nic.h:125
@ SWITCH_PORT_STATE_LISTENING
Definition: nic.h:138
#define KSZ8863_GLOBAL_CTRL0
uint8_t forwardPorts
error_t ksz8863AddStaticFdbEntry(NetInterface *interface, const SwitchFdbEntry *entry)
Add a new entry to the static MAC table.
uint8_t numValidEntriesH
void ksz8863Tick(NetInterface *interface)
KSZ8863 timer handler.
@ ERROR_END_OF_TABLE
Definition: error.h:291
uint8_t p
Definition: ndp.h:300
@ SWITCH_PORT_STATE_DISABLED
Definition: nic.h:136
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
#define KSZ8863_GLOBAL_CTRL1
#define TRUE
Definition: os_port.h:50
#define KSZ8863_BMSR
#define KSZ8863_INDIRECT_CTRL0_ADDR_H
uint8_t data[]
Definition: ethernet.h:222
void ksz8863DumpSwitchReg(NetInterface *interface)
Dump switch registers for debugging purpose.
@ SWITCH_PORT_STATE_LEARNING
Definition: nic.h:139
uint8_t sourcePort
void ksz8863FlushDynamicFdbTable(NetInterface *interface, uint8_t port)
Flush dynamic MAC table.
#define KSZ8863_GLOBAL_CTRL1_TAIL_TAG_EN
#define NET_INTERFACE_COUNT
Definition: net.h:114
error_t ksz8863Init(NetInterface *interface)
KSZ8863 Ethernet switch initialization.
#define KSZ8863_PORTn_CTRL2(port)
@ ERROR_INVALID_PORT
Definition: error.h:104
uint8_t fidH
@ ERROR_TABLE_FULL
Definition: error.h:290
EthHeader
Definition: ethernet.h:223
void ksz8863EnableRsvdMcastTable(NetInterface *interface, bool_t enable)
Enable reserved multicast table.
#define KSZ8863_PORTn_STAT1_OP_SPEED
#define KSZ8863_PORT1
#define SMI_OPCODE_WRITE
Definition: nic.h:66
void ksz8863WritePhyReg(NetInterface *interface, uint8_t port, uint8_t address, uint16_t data)
Write PHY register.
#define KSZ8863_TAIL_TAG_NORMAL_ADDR_LOOKUP
void ksz8863EnableMldSnooping(NetInterface *interface, bool_t enable)
Enable MLD snooping.
#define KSZ8863_PORTn_CTRL2_RECEIVE_EN
#define KSZ8863_PORT3_MASK
@ SWITCH_PORT_STATE_UNKNOWN
Definition: nic.h:135
#define FALSE
Definition: os_port.h:46
#define KSZ8863_DYNAMIC_MAC_TABLE_SIZE
#define KSZ8863_TAIL_TAG_DEST_PORT2
error_t
Error codes.
Definition: error.h:43
#define netInterface
Definition: net_legacy.h:199
#define KSZ8863_GLOBAL_CTRL3
void ksz8863WriteSwitchReg(NetInterface *interface, uint8_t address, uint8_t data)
Write switch register.
#define KSZ8863_STATIC_MAC_TABLE_SIZE
#define KSZ8863_INDIRECT_CTRL0
#define KSZ8863_GLOBAL_CTRL4_SW_MII_HALF_DUPLEX_MODE
#define NetRxAncillary
Definition: net_misc.h:40
bool_t ksz8863GetLinkState(NetInterface *interface, uint8_t port)
Get link state.
KSZ8863 3-port Ethernet switch driver.
#define NetInterface
Definition: net.h:36
@ NIC_LINK_SPEED_10MBPS
Definition: nic.h:111
@ ERROR_INVALID_LENGTH
Definition: error.h:111
void ksz8863SetUnknownMcastFwdPorts(NetInterface *interface, bool_t enable, uint32_t forwardPorts)
Set forward ports for unknown multicast packets.
error_t ethPadFrame(NetBuffer *buffer, size_t *length)
Ethernet frame padding.
#define KSZ8863_GLOBAL_CTRL3_IGMP_SNOOP_EN
#define NetTxAncillary
Definition: net_misc.h:36
SwitchPortState ksz8863GetPortState(NetInterface *interface, uint8_t port)
Get port state.
error_t ksz8863TagFrame(NetInterface *interface, NetBuffer *buffer, size_t *offset, NetTxAncillary *ancillary)
Add tail tag to Ethernet frame.
#define SMI_OPCODE_0
Definition: nic.h:65
#define MSB(x)
Definition: os_port.h:59
#define KSZ8863_PORTn_STAT0_LINK_GOOD
#define KSZ8863_PORTn_CTRL2_LEARNING_DIS
#define SMI_OPCODE_READ
Definition: nic.h:67
SwitchPortState
Switch port state.
Definition: nic.h:134
#define KSZ8863_TAIL_TAG_SRC_PORT
#define TRACE_INFO(...)
Definition: debug.h:95
uint8_t length
Definition: tcp.h:368
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
#define KSZ8863_CHIP_ID0_FAMILY_ID_DEFAULT
#define LSB(x)
Definition: os_port.h:55
uint8_t dataNotReady
#define KSZ8863_PORTn_STAT1(port)
#define KSZ8863_TAIL_TAG_DEST_PORT1
#define KSZ8863_INDIRECT_DATA8
void ksz8863FlushStaticFdbTable(NetInterface *interface)
Flush static MAC table.
@ SWITCH_PORT_STATE_FORWARDING
Definition: nic.h:140
uint16_t port
Definition: dns_common.h:267
error_t ksz8863GetStaticFdbEntry(NetInterface *interface, uint_t index, SwitchFdbEntry *entry)
Read an entry from the static MAC table.
#define TRACE_DEBUG(...)
Definition: debug.h:107
#define KSZ8863_INDIRECT_CTRL1
error_t ksz8863UntagFrame(NetInterface *interface, uint8_t **frame, size_t *length, NetRxAncillary *ancillary)
Decode tail tag from incoming Ethernet frame.
uint16_t regAddr
#define KSZ8863_BMSR_LINK_STATUS
Ethernet switch driver.
Definition: nic.h:325
void ksz8863DisableIrq(NetInterface *interface)
Disable interrupts.
uint8_t n
#define KSZ8863_PORT3
#define KSZ8863_PORT_MASK
@ ERROR_INVALID_ENTRY
Definition: error.h:289
error_t netBufferAppend(NetBuffer *dest, const void *src, size_t length)
Append data a multi-part buffer.
Definition: net_mem.c:604
#define KSZ8863_INDIRECT_CTRL0_WRITE
Ipv6Addr address[]
Definition: ipv6.h:325
NicDuplexMode
Duplex mode.
Definition: nic.h:122
MacAddr macAddr
Definition: nic.h:150
#define KSZ8863_GLOBAL_CTRL4_SW_MII_10BT
#define KSZ8863_PORT2
#define KSZ8863_INDIRECT_CTRL0_TABLE_SEL_STATIC_MAC
uint8_t srcPort
Definition: nic.h:151
@ NIC_HALF_DUPLEX_MODE
Definition: nic.h:124
#define KSZ8863_GLOBAL_CTRL0_FLUSH_DYNAMIC_MAC_TABLE
#define KSZ8863_GLOBAL_CTRL0_FLUSH_STATIC_MAC_TABLE
uint8_t ksz8863ReadSwitchReg(NetInterface *interface, uint8_t address)
Read switch register.
void ksz8863SetAgingTime(NetInterface *interface, uint32_t agingTime)
Set aging time for dynamic filtering entries.
uint8_t valid
#define macCompAddr(macAddr1, macAddr2)
Definition: ethernet.h:130
#define KSZ8863_SPI_CMD_WRITE
@ NIC_UNKNOWN_DUPLEX_MODE
Definition: nic.h:123
void ksz8863EventHandler(NetInterface *interface)
KSZ8863 event handler.
__weak_func void ksz8863InitHook(NetInterface *interface)
KSZ8863 custom configuration.
NicDuplexMode ksz8863GetDuplexMode(NetInterface *interface, uint8_t port)
Get duplex mode.
uint8_t reserved
const SwitchDriver ksz8863SwitchDriver
KSZ8863 Ethernet switch driver.
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
uint8_t fidL
#define KSZ8863_SPI_CMD_READ
#define SWITCH_CPU_PORT_MASK
Definition: nic.h:60
@ NIC_LINK_SPEED_100MBPS
Definition: nic.h:112
void ksz8863SetPortState(NetInterface *interface, uint8_t port, SwitchPortState state)
Set port state.
MacAddr macAddr
#define KSZ8863_PORTn_STAT1_OP_DUPLEX
MacAddr macAddr
uint32_t ksz8863GetLinkSpeed(NetInterface *interface, uint8_t port)
Get link speed.
unsigned int uint_t
Definition: compiler_port.h:50
TCP/IP stack core.
#define KSZ8863_INDIRECT_DATA7
#define KSZ8863_INDIRECT_CTRL0_READ
Dynamic MAC table entry.
uint8_t macEmpty
Helper functions for Ethernet.
@ NO_ERROR
Success.
Definition: error.h:44
bool_t override
Definition: nic.h:153
Debugging facilities.
uint8_t override
uint16_t ksz8863ReadPhyReg(NetInterface *interface, uint8_t port, uint8_t address)
Read PHY register.
Forwarding database entry.
Definition: nic.h:149
#define KSZ8863_PORTn_CTRL2_TRANSMIT_EN
const uint8_t ksz8863IngressTailTag[3]
Tail tag rules (host to KSZ8863)
void ksz8863EnableIgmpSnooping(NetInterface *interface, bool_t enable)
Enable IGMP snooping.
uint8_t useFid