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