ksz8864_driver.c
Go to the documentation of this file.
1 /**
2  * @file ksz8864_driver.c
3  * @brief KSZ8864 4-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.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 KSZ8864 Ethernet switch driver
43  **/
44 
46 {
70 };
71 
72 
73 /**
74  * @brief Tail tag rules (host to KSZ8864)
75  **/
76 
77 const uint8_t ksz8864IngressTailTag[4] =
78 {
83 };
84 
85 
86 /**
87  * @brief KSZ8864 Ethernet switch initialization
88  * @param[in] interface Underlying network interface
89  * @return Error code
90  **/
91 
93 {
94  uint_t port;
95  uint8_t temp;
96 
97  //Debug message
98  TRACE_INFO("Initializing KSZ8864...\r\n");
99 
100  //SPI slave mode?
101  if(interface->spiDriver != NULL)
102  {
103  //Initialize SPI interface
104  interface->spiDriver->init();
105  }
106  else if(interface->smiDriver != NULL)
107  {
108  //Initialize serial management interface
109  interface->smiDriver->init();
110  }
111  else
112  {
113  //Just for sanity
114  }
115 
116  //Wait for the serial interface to be ready
117  do
118  {
119  //Read CHIP_ID0 register
120  temp = ksz8864ReadSwitchReg(interface, KSZ8864_CHIP_ID0);
121 
122  //The returned data is invalid until the serial interface is ready
123  } while(temp != KSZ8864_CHIP_ID0_FAMILY_ID_DEFAULT);
124 
125 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
126  //Enable tail tag feature
127  temp = ksz8864ReadSwitchReg(interface, KSZ8864_GLOBAL_CTRL10);
130 #else
131  //Disable tail tag feature
132  temp = ksz8864ReadSwitchReg(interface, KSZ8864_GLOBAL_CTRL10);
135 #endif
136 
137  //Loop through the ports
139  {
140 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
141  //Port separation mode?
142  if(interface->port != 0)
143  {
144  //Disable packet transmission and address learning
146  }
147  else
148 #endif
149  {
150  //Enable transmission, reception and address learning
152  }
153  }
154 
155  //Start switch operation
158 
159  //Dump switch registers for debugging purpose
160  ksz8864DumpSwitchReg(interface);
161 
162  //SMI interface mode?
163  if(interface->spiDriver == NULL)
164  {
165  //Loop through the ports
167  {
168  //Debug message
169  TRACE_DEBUG("Port %u:\r\n", port);
170  //Dump PHY registers for debugging purpose
171  ksz8864DumpPhyReg(interface, port);
172  }
173  }
174 
175  //Perform custom configuration
176  ksz8864InitHook(interface);
177 
178  //Force the TCP/IP stack to poll the link state at startup
179  interface->phyEvent = TRUE;
180  //Notify the TCP/IP stack of the event
182 
183  //Successful initialization
184  return NO_ERROR;
185 }
186 
187 
188 /**
189  * @brief KSZ8864 custom configuration
190  * @param[in] interface Underlying network interface
191  **/
192 
193 __weak_func void ksz8864InitHook(NetInterface *interface)
194 {
195 }
196 
197 
198 /**
199  * @brief KSZ8864 timer handler
200  * @param[in] interface Underlying network interface
201  **/
202 
203 void ksz8864Tick(NetInterface *interface)
204 {
205  uint_t port;
206  bool_t linkState;
207 
208 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
209  //Port separation mode?
210  if(interface->port != 0)
211  {
212  uint_t i;
213  NetInterface *virtualInterface;
214 
215  //Loop through network interfaces
216  for(i = 0; i < NET_INTERFACE_COUNT; i++)
217  {
218  //Point to the current interface
219  virtualInterface = &netInterface[i];
220 
221  //Check whether the current virtual interface is attached to the
222  //physical interface
223  if(virtualInterface == interface ||
224  virtualInterface->parent == interface)
225  {
226  //Retrieve current link state
227  linkState = ksz8864GetLinkState(interface, virtualInterface->port);
228 
229  //Link up or link down event?
230  if(linkState != virtualInterface->linkState)
231  {
232  //Set event flag
233  interface->phyEvent = TRUE;
234  //Notify the TCP/IP stack of the event
236  }
237  }
238  }
239  }
240  else
241 #endif
242  {
243  //Initialize link state
244  linkState = FALSE;
245 
246  //Loop through the ports
248  {
249  //Retrieve current link state
250  if(ksz8864GetLinkState(interface, port))
251  {
252  linkState = TRUE;
253  }
254  }
255 
256  //Link up or link down event?
257  if(linkState != interface->linkState)
258  {
259  //Set event flag
260  interface->phyEvent = TRUE;
261  //Notify the TCP/IP stack of the event
263  }
264  }
265 }
266 
267 
268 /**
269  * @brief Enable interrupts
270  * @param[in] interface Underlying network interface
271  **/
272 
274 {
275 }
276 
277 
278 /**
279  * @brief Disable interrupts
280  * @param[in] interface Underlying network interface
281  **/
282 
284 {
285 }
286 
287 
288 /**
289  * @brief KSZ8864 event handler
290  * @param[in] interface Underlying network interface
291  **/
292 
294 {
295  uint_t port;
296  bool_t linkState;
297 
298 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
299  //Port separation mode?
300  if(interface->port != 0)
301  {
302  uint_t i;
303  NetInterface *virtualInterface;
304 
305  //Loop through network interfaces
306  for(i = 0; i < NET_INTERFACE_COUNT; i++)
307  {
308  //Point to the current interface
309  virtualInterface = &netInterface[i];
310 
311  //Check whether the current virtual interface is attached to the
312  //physical interface
313  if(virtualInterface == interface ||
314  virtualInterface->parent == interface)
315  {
316  //Get the port number associated with the current interface
317  port = virtualInterface->port;
318 
319  //Check port number
320  if(port >= KSZ8864_PORT1 && port <= KSZ8864_PORT3)
321  {
322  //Retrieve current link state
323  linkState = ksz8864GetLinkState(interface, port);
324 
325  //Link up event?
326  if(linkState && !virtualInterface->linkState)
327  {
328  //Retrieve host interface speed
329  interface->linkSpeed = ksz8864GetLinkSpeed(interface,
330  KSZ8864_PORT4);
331 
332  //Retrieve host interface duplex mode
333  interface->duplexMode = ksz8864GetDuplexMode(interface,
334  KSZ8864_PORT4);
335 
336  //Adjust MAC configuration parameters for proper operation
337  interface->nicDriver->updateMacConfig(interface);
338 
339  //Check current speed
340  virtualInterface->linkSpeed = ksz8864GetLinkSpeed(interface,
341  port);
342 
343  //Check current duplex mode
344  virtualInterface->duplexMode = ksz8864GetDuplexMode(interface,
345  port);
346 
347  //Update link state
348  virtualInterface->linkState = TRUE;
349 
350  //Process link state change event
351  nicNotifyLinkChange(virtualInterface);
352  }
353  //Link down event
354  else if(!linkState && virtualInterface->linkState)
355  {
356  //Update link state
357  virtualInterface->linkState = FALSE;
358 
359  //Process link state change event
360  nicNotifyLinkChange(virtualInterface);
361  }
362  }
363  else
364  {
365  //The specified port number is not valid
366  }
367  }
368  }
369  }
370  else
371 #endif
372  {
373  //Initialize link state
374  linkState = FALSE;
375 
376  //Loop through the ports
378  {
379  //Retrieve current link state
380  if(ksz8864GetLinkState(interface, port))
381  {
382  linkState = TRUE;
383  }
384  }
385 
386  //Link up event?
387  if(linkState)
388  {
389  //Retrieve host interface speed
390  interface->linkSpeed = ksz8864GetLinkSpeed(interface, KSZ8864_PORT4);
391  //Retrieve host interface duplex mode
392  interface->duplexMode = ksz8864GetDuplexMode(interface, KSZ8864_PORT4);
393 
394  //Adjust MAC configuration parameters for proper operation
395  interface->nicDriver->updateMacConfig(interface);
396 
397  //Update link state
398  interface->linkState = TRUE;
399  }
400  else
401  {
402  //Update link state
403  interface->linkState = FALSE;
404  }
405 
406  //Process link state change event
407  nicNotifyLinkChange(interface);
408  }
409 }
410 
411 
412 /**
413  * @brief Add tail tag to Ethernet frame
414  * @param[in] interface Underlying network interface
415  * @param[in] buffer Multi-part buffer containing the payload
416  * @param[in,out] offset Offset to the first payload byte
417  * @param[in] ancillary Additional options passed to the stack along with
418  * the packet
419  * @return Error code
420  **/
421 
423  size_t *offset, NetTxAncillary *ancillary)
424 {
425  error_t error;
426 
427  //Initialize status code
428  error = NO_ERROR;
429 
430 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
431  //Valid port?
432  if(ancillary->port <= KSZ8864_PORT3)
433  {
434  size_t length;
435  const uint8_t *tailTag;
436 
437  //The one byte tail tagging is used to indicate the destination port
438  tailTag = &ksz8864IngressTailTag[ancillary->port];
439 
440  //Retrieve the length of the Ethernet frame
441  length = netBufferGetLength(buffer) - *offset;
442 
443  //The host controller should manually add padding to the packet before
444  //inserting the tail tag
445  error = ethPadFrame(buffer, &length);
446 
447  //Check status code
448  if(!error)
449  {
450  //The tail tag is inserted at the end of the packet, just before
451  //the CRC
452  error = netBufferAppend(buffer, tailTag, sizeof(uint8_t));
453  }
454  }
455  else
456  {
457  //The port number is not valid
458  error = ERROR_INVALID_PORT;
459  }
460 #endif
461 
462  //Return status code
463  return error;
464 }
465 
466 
467 /**
468  * @brief Decode tail tag from incoming Ethernet frame
469  * @param[in] interface Underlying network interface
470  * @param[in,out] frame Pointer to the received Ethernet frame
471  * @param[in,out] length Length of the frame, in bytes
472  * @param[in,out] ancillary Additional options passed to the stack along with
473  * the packet
474  * @return Error code
475  **/
476 
477 error_t ksz8864UntagFrame(NetInterface *interface, uint8_t **frame,
478  size_t *length, NetRxAncillary *ancillary)
479 {
480  error_t error;
481 
482  //Initialize status code
483  error = NO_ERROR;
484 
485 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
486  //Valid Ethernet frame received?
487  if(*length >= (sizeof(EthHeader) + sizeof(uint8_t)))
488  {
489  uint8_t *tailTag;
490 
491  //The tail tag is inserted at the end of the packet, just before
492  //the CRC
493  tailTag = *frame + *length - sizeof(uint8_t);
494 
495  //The one byte tail tagging is used to indicate the source port
496  ancillary->port = *tailTag & KSZ8864_TAIL_TAG_SRC_PORT;
497 
498  //Strip tail tag from Ethernet frame
499  *length -= sizeof(uint8_t);
500  }
501  else
502  {
503  //Drop the received frame
504  error = ERROR_INVALID_LENGTH;
505  }
506 #endif
507 
508  //Return status code
509  return error;
510 }
511 
512 
513 /**
514  * @brief Get link state
515  * @param[in] interface Underlying network interface
516  * @param[in] port Port number
517  * @return Link state
518  **/
519 
521 {
522  uint16_t status;
523  bool_t linkState;
524 
525  //Check port number
526  if(port == KSZ8864_PORT1 || port == KSZ8864_PORT2)
527  {
528  //Read port status 1 register
529  status = ksz8864ReadSwitchReg(interface, KSZ8864_PORTn_STAT1(port));
530 
531  //Retrieve current link state
532  linkState = (status & KSZ8864_PORTn_STAT1_LINK_GOOD) ? TRUE : FALSE;
533  }
534  else if(port == KSZ8864_PORT3)
535  {
536  //Port 3 is always up
537  linkState = TRUE;
538  }
539  else
540  {
541  //The specified port number is not valid
542  linkState = FALSE;
543  }
544 
545  //Return link status
546  return linkState;
547 }
548 
549 
550 /**
551  * @brief Get link speed
552  * @param[in] interface Underlying network interface
553  * @param[in] port Port number
554  * @return Link speed
555  **/
556 
557 uint32_t ksz8864GetLinkSpeed(NetInterface *interface, uint8_t port)
558 {
559  uint16_t status;
560  uint32_t linkSpeed;
561 
562  //Check port number
563  if(port == KSZ8864_PORT1 || port == KSZ8864_PORT2)
564  {
565  //Read port status 0 register
566  status = ksz8864ReadSwitchReg(interface, KSZ8864_PORTn_STAT0(port));
567 
568  //Retrieve current link speed
569  if((status & KSZ8864_PORTn_STAT0_OP_SPEED) != 0)
570  {
571  linkSpeed = NIC_LINK_SPEED_100MBPS;
572  }
573  else
574  {
575  linkSpeed = NIC_LINK_SPEED_10MBPS;
576  }
577  }
578  else if(port == KSZ8864_PORT3)
579  {
580  //Port 3 link speed
581  linkSpeed = NIC_LINK_SPEED_100MBPS;
582  }
583  else if(port == KSZ8864_PORT4)
584  {
585  //Read global control 4 register
586  status = ksz8864ReadSwitchReg(interface, KSZ8864_GLOBAL_CTRL4);
587 
588  //Retrieve host interface speed
589  if((status & KSZ8864_GLOBAL_CTRL4_SW4_SPEED) != 0)
590  {
591  linkSpeed = NIC_LINK_SPEED_10MBPS;
592  }
593  else
594  {
595  linkSpeed = NIC_LINK_SPEED_100MBPS;
596  }
597  }
598  else
599  {
600  //The specified port number is not valid
601  linkSpeed = NIC_LINK_SPEED_UNKNOWN;
602  }
603 
604  //Return link status
605  return linkSpeed;
606 }
607 
608 
609 /**
610  * @brief Get duplex mode
611  * @param[in] interface Underlying network interface
612  * @param[in] port Port number
613  * @return Duplex mode
614  **/
615 
617 {
618  uint16_t status;
619  NicDuplexMode duplexMode;
620 
621  //Check port number
622  if(port == KSZ8864_PORT1 || port == KSZ8864_PORT2)
623  {
624  //Read port status 0 register
625  status = ksz8864ReadSwitchReg(interface, KSZ8864_PORTn_STAT0(port));
626 
627  //Retrieve current duplex mode
628  if((status & KSZ8864_PORTn_STAT0_OP_DUPLEX) != 0)
629  {
630  duplexMode = NIC_FULL_DUPLEX_MODE;
631  }
632  else
633  {
634  duplexMode = NIC_HALF_DUPLEX_MODE;
635  }
636  }
637  else if(port == KSZ8864_PORT3)
638  {
639  //Port 3 duplex mode
640  duplexMode = NIC_FULL_DUPLEX_MODE;
641  }
642  else if(port == KSZ8864_PORT4)
643  {
644  //Read global control 4 register
645  status = ksz8864ReadSwitchReg(interface, KSZ8864_GLOBAL_CTRL4);
646 
647  //Retrieve host interface duplex mode
649  {
650  duplexMode = NIC_HALF_DUPLEX_MODE;
651  }
652  else
653  {
654  duplexMode = NIC_FULL_DUPLEX_MODE;
655  }
656  }
657  else
658  {
659  //The specified port number is not valid
660  duplexMode = NIC_UNKNOWN_DUPLEX_MODE;
661  }
662 
663  //Return duplex mode
664  return duplexMode;
665 }
666 
667 
668 /**
669  * @brief Set port state
670  * @param[in] interface Underlying network interface
671  * @param[in] port Port number
672  * @param[in] state Port state
673  **/
674 
675 void ksz8864SetPortState(NetInterface *interface, uint8_t port,
676  SwitchPortState state)
677 {
678  uint8_t temp;
679 
680  //Check port number
681  if(port >= KSZ8864_PORT1 && port <= KSZ8864_PORT3)
682  {
683  //Read port control 2 register
684  temp = ksz8864ReadSwitchReg(interface, KSZ8864_PORTn_CTRL2(port));
685 
686  //Update port state
687  switch(state)
688  {
689  //Listening state
694  break;
695 
696  //Learning state
701  break;
702 
703  //Forwarding state
708  break;
709 
710  //Disabled state
711  default:
715  break;
716  }
717 
718  //Write the value back to port control 2 register
720  }
721 }
722 
723 
724 /**
725  * @brief Get port state
726  * @param[in] interface Underlying network interface
727  * @param[in] port Port number
728  * @return Port state
729  **/
730 
732 {
733  uint8_t temp;
734  SwitchPortState state;
735 
736  //Check port number
737  if(port >= KSZ8864_PORT1 && port <= KSZ8864_PORT3)
738  {
739  //Read port control 2 register
740  temp = ksz8864ReadSwitchReg(interface, KSZ8864_PORTn_CTRL2(port));
741 
742  //Check port state
743  if((temp & KSZ8864_PORTn_CTRL2_TRANSMIT_EN) == 0 &&
744  (temp & KSZ8864_PORTn_CTRL2_RECEIVE_EN) == 0 &&
745  (temp & KSZ8864_PORTn_CTRL2_LEARNING_DIS) != 0)
746  {
747  //Disabled state
749  }
750  else if((temp & KSZ8864_PORTn_CTRL2_TRANSMIT_EN) == 0 &&
751  (temp & KSZ8864_PORTn_CTRL2_RECEIVE_EN) != 0 &&
752  (temp & KSZ8864_PORTn_CTRL2_LEARNING_DIS) != 0)
753  {
754  //Listening state
756  }
757  else if((temp & KSZ8864_PORTn_CTRL2_TRANSMIT_EN) == 0 &&
758  (temp & KSZ8864_PORTn_CTRL2_RECEIVE_EN) == 0 &&
759  (temp & KSZ8864_PORTn_CTRL2_LEARNING_DIS) == 0)
760  {
761  //Learning state
763  }
764  else if((temp & KSZ8864_PORTn_CTRL2_TRANSMIT_EN) != 0 &&
765  (temp & KSZ8864_PORTn_CTRL2_RECEIVE_EN) != 0 &&
766  (temp & KSZ8864_PORTn_CTRL2_LEARNING_DIS) == 0)
767  {
768  //Forwarding state
770  }
771  else
772  {
773  //Unknown state
775  }
776  }
777  else
778  {
779  //The specified port number is not valid
781  }
782 
783  //Return port state
784  return state;
785 }
786 
787 
788 /**
789  * @brief Set aging time for dynamic filtering entries
790  * @param[in] interface Underlying network interface
791  * @param[in] agingTime Aging time, in seconds
792  **/
793 
794 void ksz8864SetAgingTime(NetInterface *interface, uint32_t agingTime)
795 {
796  //The aging period is fixed to 300 seconds
797 }
798 
799 
800 /**
801  * @brief Enable IGMP snooping
802  * @param[in] interface Underlying network interface
803  * @param[in] enable Enable or disable IGMP snooping
804  **/
805 
807 {
808  uint8_t temp;
809 
810  //Read global control 3 register
811  temp = ksz8864ReadSwitchReg(interface, KSZ8864_GLOBAL_CTRL3);
812 
813  //Enable or disable IGMP snooping
814  if(enable)
815  {
817  }
818  else
819  {
821  }
822 
823  //Write the value back to global control 3 register
825 }
826 
827 
828 /**
829  * @brief Enable MLD snooping
830  * @param[in] interface Underlying network interface
831  * @param[in] enable Enable or disable MLD snooping
832  **/
833 
835 {
836  //Not implemented
837 }
838 
839 
840 /**
841  * @brief Enable reserved multicast table
842  * @param[in] interface Underlying network interface
843  * @param[in] enable Enable or disable reserved group addresses
844  **/
845 
847 {
848  uint_t i;
849  SwitchFdbEntry entry;
850 
851  //The reserved group addresses are in the range of 01-80-C2-00-00-00 to
852  //01-80-C2-00-00-0F
853  for(i = 0; i <= 15; i++)
854  {
855  //Specify the reserved group address to be added or removed
856  entry.macAddr.b[0] = 0x01;
857  entry.macAddr.b[1] = 0x80;
858  entry.macAddr.b[2] = 0xC2;
859  entry.macAddr.b[3] = 0x00;
860  entry.macAddr.b[4] = 0x00;
861  entry.macAddr.b[5] = i;
862 
863  //Format forwarding database entry
864  entry.srcPort = 0;
866  entry.override = TRUE;
867 
868  //Update the static MAC table
869  if(enable)
870  {
871  ksz8864AddStaticFdbEntry(interface, &entry);
872  }
873  else
874  {
875  ksz8864DeleteStaticFdbEntry(interface, &entry);
876  }
877  }
878 }
879 
880 
881 /**
882  * @brief Add a new entry to the static MAC table
883  * @param[in] interface Underlying network interface
884  * @param[in] entry Pointer to the forwarding database entry
885  * @return Error code
886  **/
887 
889  const SwitchFdbEntry *entry)
890 {
891  error_t error;
892  uint_t i;
893  uint_t j;
894  uint8_t *p;
895  SwitchFdbEntry currentEntry;
896  Ksz8864StaticMacEntryW newEntry;
897 
898  //Keep track of the first free entry
900 
901  //Loop through the static MAC table
902  for(i = 0; i < KSZ8864_STATIC_MAC_TABLE_SIZE; i++)
903  {
904  //Read current entry
905  error = ksz8864GetStaticFdbEntry(interface, i, &currentEntry);
906 
907  //Valid entry?
908  if(!error)
909  {
910  //Check whether the table already contains the specified MAC address
911  if(macCompAddr(&currentEntry.macAddr, &entry->macAddr))
912  {
913  j = i;
914  break;
915  }
916  }
917  else
918  {
919  //Keep track of the first free entry
921  {
922  j = i;
923  }
924  }
925  }
926 
927  //Any entry available?
929  {
930  //Format MAC entry
931  newEntry.fid = 0;
932  newEntry.useFid = 0;
933  newEntry.override = entry->override;
934  newEntry.valid = TRUE;
935  newEntry.reserved = 0;
936  newEntry.macAddr = entry->macAddr;
937 
938  //Set the relevant forward ports
939  if(entry->destPorts == SWITCH_CPU_PORT_MASK)
940  {
941  newEntry.forwardPorts = KSZ8864_PORT4_MASK;
942  }
943  else
944  {
945  newEntry.forwardPorts = entry->destPorts & KSZ8864_PORT_MASK;
946  }
947 
948  //Select the static MAC address table
952 
953  //Point to the MAC entry
954  p = (uint8_t *) &newEntry;
955 
956  //Write indirect data registers
957  for(i = 0; i < sizeof(Ksz8864StaticMacEntryW); i++)
958  {
959  ksz8864WriteSwitchReg(interface, KSZ8864_INDIRECT_DATA7 + i, p[i]);
960  }
961 
962  //Setup a write operation
966 
967  //Trigger the write operation
969 
970  //Successful processing
971  error = NO_ERROR;
972  }
973  else
974  {
975  //The static MAC table is full
976  error = ERROR_TABLE_FULL;
977  }
978 
979  //Return status code
980  return error;
981 }
982 
983 
984 /**
985  * @brief Remove an entry from the static MAC table
986  * @param[in] interface Underlying network interface
987  * @param[in] entry Forwarding database entry to remove from the table
988  * @return Error code
989  **/
990 
992  const SwitchFdbEntry *entry)
993 {
994  error_t error;
995  uint_t i;
996  uint_t j;
997  SwitchFdbEntry currentEntry;
998 
999  //Loop through the static MAC table
1000  for(j = 0; j < KSZ8864_STATIC_MAC_TABLE_SIZE; j++)
1001  {
1002  //Read current entry
1003  error = ksz8864GetStaticFdbEntry(interface, j, &currentEntry);
1004 
1005  //Valid entry?
1006  if(!error)
1007  {
1008  //Check whether the table contains the specified MAC address
1009  if(macCompAddr(&currentEntry.macAddr, &entry->macAddr))
1010  {
1011  break;
1012  }
1013  }
1014  }
1015 
1016  //Any matching entry?
1018  {
1019  //Select the static MAC address table
1023 
1024  //Clear indirect data registers
1025  for(i = 0; i < sizeof(Ksz8864StaticMacEntryW); i++)
1026  {
1027  ksz8864WriteSwitchReg(interface, KSZ8864_INDIRECT_DATA7 + i, 0);
1028  }
1029 
1030  //Setup a write operation
1034 
1035  //Trigger the write operation
1037 
1038  //Successful processing
1039  error = NO_ERROR;
1040  }
1041  else
1042  {
1043  //The static MAC table does not contain the specified address
1044  error = ERROR_NOT_FOUND;
1045  }
1046 
1047  //Return status code
1048  return error;
1049 }
1050 
1051 
1052 /**
1053  * @brief Read an entry from the static MAC table
1054  * @param[in] interface Underlying network interface
1055  * @param[in] index Zero-based index of the entry to read
1056  * @param[out] entry Pointer to the forwarding database entry
1057  * @return Error code
1058  **/
1059 
1061  SwitchFdbEntry *entry)
1062 {
1063  error_t error;
1064  uint_t i;
1065  uint8_t *p;
1066  Ksz8864StaticMacEntryR currentEntry;
1067 
1068  //Check index parameter
1069  if(index < KSZ8864_STATIC_MAC_TABLE_SIZE)
1070  {
1071  //Select the static MAC address table
1075 
1076  //Trigger the read operation
1077  ksz8864WriteSwitchReg(interface, KSZ8864_INDIRECT_CTRL1, index);
1078 
1079  //Point to the MAC entry
1080  p = (uint8_t *) &currentEntry;
1081 
1082  //Read indirect data registers
1083  for(i = 0; i < sizeof(Ksz8864StaticMacEntryR); i++)
1084  {
1085  p[i] = ksz8864ReadSwitchReg(interface, KSZ8864_INDIRECT_DATA7 + i);
1086  }
1087 
1088  //Valid entry?
1089  if(currentEntry.valid)
1090  {
1091  //Copy MAC entry
1092  entry->macAddr = currentEntry.macAddr;
1093  entry->srcPort = 0;
1094  entry->destPorts = currentEntry.forwardPorts & KSZ8864_PORT_MASK;
1095  entry->override = currentEntry.override;
1096 
1097  //Successful processing
1098  error = NO_ERROR;
1099  }
1100  else
1101  {
1102  //The entry is not valid
1103  error = ERROR_INVALID_ENTRY;
1104  }
1105  }
1106  else
1107  {
1108  //The end of the table has been reached
1109  error = ERROR_END_OF_TABLE;
1110  }
1111 
1112  //Return status code
1113  return error;
1114 }
1115 
1116 
1117 /**
1118  * @brief Flush static MAC table
1119  * @param[in] interface Underlying network interface
1120  **/
1121 
1123 {
1124  uint_t i;
1125  uint_t temp;
1126  uint8_t state[4];
1127 
1128  //Loop through the ports
1129  for(i = KSZ8864_PORT1; i <= KSZ8864_PORT4; i++)
1130  {
1131  //Save the current state of the port
1132  state[i - 1] = ksz8864ReadSwitchReg(interface, KSZ8864_PORTn_CTRL2(i));
1133 
1134  //Turn off learning capability
1136  state[i - 1] | KSZ8864_PORTn_CTRL2_LEARNING_DIS);
1137  }
1138 
1139  //All the entries associated with a port that has its learning capability
1140  //being turned off will be flushed
1141  temp = ksz8864ReadSwitchReg(interface, KSZ8864_GLOBAL_CTRL0);
1143  ksz8864WriteSwitchReg(interface, KSZ8864_GLOBAL_CTRL0, temp);
1144 
1145  //Loop through the ports
1146  for(i = KSZ8864_PORT1; i <= KSZ8864_PORT4; i++)
1147  {
1148  //Restore the original state of the port
1149  ksz8864WriteSwitchReg(interface, KSZ8864_PORTn_CTRL2(i), state[i - 1]);
1150  }
1151 }
1152 
1153 
1154 /**
1155  * @brief Read an entry from the dynamic MAC table
1156  * @param[in] interface Underlying network interface
1157  * @param[in] index Zero-based index of the entry to read
1158  * @param[out] entry Pointer to the forwarding database entry
1159  * @return Error code
1160  **/
1161 
1163  SwitchFdbEntry *entry)
1164 {
1165  error_t error;
1166  uint_t i;
1167  uint_t n;
1168  uint8_t *p;
1169  Ksz8864DynamicMacEntry currentEntry;
1170 
1171  //Check index parameter
1172  if(index < KSZ8864_DYNAMIC_MAC_TABLE_SIZE)
1173  {
1174  //Read the MAC entry at the specified index
1175  do
1176  {
1177  //Select the dynamic MAC address table
1181  (MSB(index) & KSZ8864_INDIRECT_CTRL0_ADDR_H));
1182 
1183  //Trigger the read operation
1184  ksz8864WriteSwitchReg(interface, KSZ8864_INDIRECT_CTRL1, LSB(index));
1185 
1186  //Point to the MAC entry
1187  p = (uint8_t *) &currentEntry;
1188 
1189  //Read indirect data registers
1190  for(i = 0; i < sizeof(Ksz8864DynamicMacEntry); i++)
1191  {
1192  p[i] = ksz8864ReadSwitchReg(interface, KSZ8864_INDIRECT_DATA8 + i);
1193  }
1194 
1195  //Retry until the entry is ready
1196  } while(currentEntry.dataNotReady);
1197 
1198  //Check whether there are valid entries in the table
1199  if(!currentEntry.macEmpty)
1200  {
1201  //Retrieve the number of valid entries
1202  n = ((currentEntry.numValidEntriesH << 3) |
1203  currentEntry.numValidEntriesL) + 1;
1204  }
1205  else
1206  {
1207  //The table is empty
1208  n = 0;
1209  }
1210 
1211  //Valid entry?
1212  if(index < n)
1213  {
1214  //Copy MAC entry
1215  entry->macAddr = currentEntry.macAddr;
1216  entry->srcPort = currentEntry.sourcePort;
1217  entry->destPorts = 0;
1218  entry->override = FALSE;
1219 
1220  //Successful processing
1221  error = NO_ERROR;
1222  }
1223  else
1224  {
1225  //The end of the table has been reached
1226  error = ERROR_END_OF_TABLE;
1227  }
1228  }
1229  else
1230  {
1231  //The end of the table has been reached
1232  error = ERROR_END_OF_TABLE;
1233  }
1234 
1235  //Return status code
1236  return error;
1237 }
1238 
1239 
1240 /**
1241  * @brief Flush dynamic MAC table
1242  * @param[in] interface Underlying network interface
1243  * @param[in] port Port number
1244  **/
1245 
1247 {
1248  uint_t i;
1249  uint_t temp;
1250  uint8_t state[4];
1251 
1252  //Loop through the ports
1253  for(i = KSZ8864_PORT1; i <= KSZ8864_PORT4; i++)
1254  {
1255  //Matching port number?
1256  if(i == port || port == 0)
1257  {
1258  //Save the current state of the port
1259  state[i - 1] = ksz8864ReadSwitchReg(interface, KSZ8864_PORTn_CTRL2(i));
1260 
1261  //Turn off learning capability
1263  state[i - 1] | KSZ8864_PORTn_CTRL2_LEARNING_DIS);
1264  }
1265  }
1266 
1267  //All the entries associated with a port that has its learning capability
1268  //being turned off will be flushed
1269  temp = ksz8864ReadSwitchReg(interface, KSZ8864_GLOBAL_CTRL0);
1271  ksz8864WriteSwitchReg(interface, KSZ8864_GLOBAL_CTRL0, temp);
1272 
1273  //Loop through the ports
1274  for(i = KSZ8864_PORT1; i <= KSZ8864_PORT4; i++)
1275  {
1276  //Matching port number?
1277  if(i == port || port == 0)
1278  {
1279  //Restore the original state of the port
1280  ksz8864WriteSwitchReg(interface, KSZ8864_PORTn_CTRL2(i), state[i - 1]);
1281  }
1282  }
1283 }
1284 
1285 
1286 /**
1287  * @brief Set forward ports for unknown multicast packets
1288  * @param[in] interface Underlying network interface
1289  * @param[in] enable Enable or disable forwarding of unknown multicast packets
1290  * @param[in] forwardPorts Port map
1291  **/
1292 
1294  bool_t enable, uint32_t forwardPorts)
1295 {
1296  uint8_t temp;
1297 
1298  //Read global control 16 register
1299  temp = ksz8864ReadSwitchReg(interface, KSZ8864_GLOBAL_CTRL16);
1300 
1301  //Clear port map
1303 
1304  //Enable or disable forwarding of unknown multicast packets
1305  if(enable)
1306  {
1307  //Enable forwarding
1309 
1310  //Check whether unknown multicast packets should be forwarded to the CPU port
1311  if((forwardPorts & SWITCH_CPU_PORT_MASK) != 0)
1312  {
1314  }
1315 
1316  //Select the desired forward ports
1317  temp |= forwardPorts & KSZ8864_GLOBAL_CTRL16_UNKNOWN_MCAST_FWD_MAP_ALL;
1318  }
1319  else
1320  {
1321  //Disable forwarding
1323  }
1324 
1325  //Write the value back to global control 16 register
1326  ksz8864WriteSwitchReg(interface, KSZ8864_GLOBAL_CTRL16, temp);
1327 }
1328 
1329 
1330 /**
1331  * @brief Write PHY register
1332  * @param[in] interface Underlying network interface
1333  * @param[in] port Port number
1334  * @param[in] address PHY register address
1335  * @param[in] data Register value
1336  **/
1337 
1338 void ksz8864WritePhyReg(NetInterface *interface, uint8_t port,
1339  uint8_t address, uint16_t data)
1340 {
1341  //Write the specified PHY register
1342  if(interface->smiDriver != NULL)
1343  {
1344  interface->smiDriver->writePhyReg(SMI_OPCODE_WRITE, port, address, data);
1345  }
1346  else
1347  {
1348  interface->nicDriver->writePhyReg(SMI_OPCODE_WRITE, port, address, data);
1349  }
1350 }
1351 
1352 
1353 /**
1354  * @brief Read PHY register
1355  * @param[in] interface Underlying network interface
1356  * @param[in] port Port number
1357  * @param[in] address PHY register address
1358  * @return Register value
1359  **/
1360 
1361 uint16_t ksz8864ReadPhyReg(NetInterface *interface, uint8_t port,
1362  uint8_t address)
1363 {
1364  uint16_t data;
1365 
1366  //Read the specified PHY register
1367  if(interface->smiDriver != NULL)
1368  {
1369  data = interface->smiDriver->readPhyReg(SMI_OPCODE_READ, port, address);
1370  }
1371  else
1372  {
1373  data = interface->nicDriver->readPhyReg(SMI_OPCODE_READ, port, address);
1374  }
1375 
1376  //Return the value of the PHY register
1377  return data;
1378 }
1379 
1380 
1381 /**
1382  * @brief Dump PHY registers for debugging purpose
1383  * @param[in] interface Underlying network interface
1384  * @param[in] port Port number
1385  **/
1386 
1387 void ksz8864DumpPhyReg(NetInterface *interface, uint8_t port)
1388 {
1389  uint8_t i;
1390 
1391  //Loop through PHY registers
1392  for(i = 0; i < 32; i++)
1393  {
1394  //Display current PHY register
1395  TRACE_DEBUG("%02" PRIu8 ": 0x%04" PRIX16 "\r\n", i,
1396  ksz8864ReadPhyReg(interface, port, i));
1397  }
1398 
1399  //Terminate with a line feed
1400  TRACE_DEBUG("\r\n");
1401 }
1402 
1403 
1404 /**
1405  * @brief Write switch register
1406  * @param[in] interface Underlying network interface
1407  * @param[in] address Switch register address
1408  * @param[in] data Register value
1409  **/
1410 
1411 void ksz8864WriteSwitchReg(NetInterface *interface, uint8_t address,
1412  uint8_t data)
1413 {
1414  uint8_t phyAddr;
1415  uint8_t regAddr;
1416 
1417  //SPI slave mode?
1418  if(interface->spiDriver != NULL)
1419  {
1420  //Pull the CS pin low
1421  interface->spiDriver->assertCs();
1422 
1423  //Set up a write operation
1424  interface->spiDriver->transfer(KSZ8864_SPI_CMD_WRITE);
1425  //Write register address
1426  interface->spiDriver->transfer(address);
1427 
1428  //Write data
1429  interface->spiDriver->transfer(data);
1430 
1431  //Terminate the operation by raising the CS pin
1432  interface->spiDriver->deassertCs();
1433  }
1434  else
1435  {
1436  //SMI register write access is selected when opcode is set to 10 and
1437  //bits 2:1 of the PHY address are set to 11
1438  phyAddr = 0x06 | ((address >> 3) & 0x18) | ((address >> 5) & 0x01);
1439 
1440  //Register address field forms register address bits 4:0
1441  regAddr = address & 0x1F;
1442 
1443  //Registers are 8 data bits wide. For write operation, data bits 15:8
1444  //are not defined, and hence can be set to either zeroes or ones
1445  if(interface->smiDriver != NULL)
1446  {
1447  interface->smiDriver->writePhyReg(SMI_OPCODE_WRITE, phyAddr, regAddr,
1448  data);
1449  }
1450  else
1451  {
1452  interface->nicDriver->writePhyReg(SMI_OPCODE_WRITE, phyAddr, regAddr,
1453  data);
1454  }
1455  }
1456 }
1457 
1458 
1459 /**
1460  * @brief Read switch register
1461  * @param[in] interface Underlying network interface
1462  * @param[in] address Switch register address
1463  * @return Register value
1464  **/
1465 
1466 uint8_t ksz8864ReadSwitchReg(NetInterface *interface, uint8_t address)
1467 {
1468  uint8_t phyAddr;
1469  uint8_t regAddr;
1470  uint8_t data;
1471 
1472  //SPI slave mode?
1473  if(interface->spiDriver != NULL)
1474  {
1475  //Pull the CS pin low
1476  interface->spiDriver->assertCs();
1477 
1478  //Set up a read operation
1479  interface->spiDriver->transfer(KSZ8864_SPI_CMD_READ);
1480  //Write register address
1481  interface->spiDriver->transfer(address);
1482 
1483  //Read data
1484  data = interface->spiDriver->transfer(0xFF);
1485 
1486  //Terminate the operation by raising the CS pin
1487  interface->spiDriver->deassertCs();
1488  }
1489  else
1490  {
1491  //SMI register read access is selected when opcode is set to 10 and
1492  //bits 2:1 of the PHY address are set to 11
1493  phyAddr = 0x06 | ((address >> 3) & 0x18) | ((address >> 5) & 0x01);
1494 
1495  //Register address field forms register address bits 4:0
1496  regAddr = address & 0x1F;
1497 
1498  //Registers are 8 data bits wide. For read operation, data bits 15:8
1499  //are read back as zeroes
1500  if(interface->smiDriver != NULL)
1501  {
1502  data = interface->smiDriver->readPhyReg(SMI_OPCODE_READ, phyAddr,
1503  regAddr) & 0xFF;
1504  }
1505  else
1506  {
1507  data = interface->nicDriver->readPhyReg(SMI_OPCODE_READ, phyAddr,
1508  regAddr) & 0xFF;
1509  }
1510  }
1511 
1512  //Return register value
1513  return data;
1514 }
1515 
1516 
1517 /**
1518  * @brief Dump switch registers for debugging purpose
1519  * @param[in] interface Underlying network interface
1520  **/
1521 
1523 {
1524  uint16_t i;
1525 
1526  //Loop through switch registers
1527  for(i = 0; i < 256; i++)
1528  {
1529  //Display current switch register
1530  TRACE_DEBUG("0x%02" PRIX16 " (%02" PRIu16 ") : 0x%02" PRIX8 "\r\n",
1531  i, i, ksz8864ReadSwitchReg(interface, i));
1532  }
1533 
1534  //Terminate with a line feed
1535  TRACE_DEBUG("\r\n");
1536 }
unsigned int uint_t
Definition: compiler_port.h:50
int bool_t
Definition: compiler_port.h:53
Debugging facilities.
#define TRACE_DEBUG(...)
Definition: debug.h:107
#define TRACE_INFO(...)
Definition: debug.h:95
uint8_t n
uint16_t port
Definition: dns_common.h:267
error_t
Error codes.
Definition: error.h:43
@ ERROR_INVALID_PORT
Definition: error.h:104
@ ERROR_NOT_FOUND
Definition: error.h:147
@ ERROR_END_OF_TABLE
Definition: error.h:290
@ ERROR_INVALID_ENTRY
Definition: error.h:288
@ ERROR_TABLE_FULL
Definition: error.h:289
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_INVALID_LENGTH
Definition: error.h:111
uint8_t data[]
Definition: ethernet.h:222
#define macCompAddr(macAddr1, macAddr2)
Definition: ethernet.h:130
EthHeader
Definition: ethernet.h:223
error_t ethPadFrame(NetBuffer *buffer, size_t *length)
Ethernet frame padding.
Helper functions for Ethernet.
Ipv6Addr address[]
Definition: ipv6.h:316
void ksz8864WritePhyReg(NetInterface *interface, uint8_t port, uint8_t address, uint16_t data)
Write PHY register.
bool_t ksz8864GetLinkState(NetInterface *interface, uint8_t port)
Get link state.
void ksz8864EventHandler(NetInterface *interface)
KSZ8864 event handler.
void ksz8864WriteSwitchReg(NetInterface *interface, uint8_t address, uint8_t data)
Write switch register.
void ksz8864DumpSwitchReg(NetInterface *interface)
Dump switch registers for debugging purpose.
void ksz8864SetAgingTime(NetInterface *interface, uint32_t agingTime)
Set aging time for dynamic filtering entries.
void ksz8864EnableRsvdMcastTable(NetInterface *interface, bool_t enable)
Enable reserved multicast table.
void ksz8864FlushStaticFdbTable(NetInterface *interface)
Flush static MAC table.
void ksz8864DisableIrq(NetInterface *interface)
Disable interrupts.
void ksz8864SetPortState(NetInterface *interface, uint8_t port, SwitchPortState state)
Set port state.
error_t ksz8864DeleteStaticFdbEntry(NetInterface *interface, const SwitchFdbEntry *entry)
Remove an entry from the static MAC table.
uint32_t ksz8864GetLinkSpeed(NetInterface *interface, uint8_t port)
Get link speed.
void ksz8864EnableMldSnooping(NetInterface *interface, bool_t enable)
Enable MLD snooping.
error_t ksz8864GetStaticFdbEntry(NetInterface *interface, uint_t index, SwitchFdbEntry *entry)
Read an entry from the static MAC table.
void ksz8864FlushDynamicFdbTable(NetInterface *interface, uint8_t port)
Flush dynamic MAC table.
uint8_t ksz8864ReadSwitchReg(NetInterface *interface, uint8_t address)
Read switch register.
void ksz8864EnableIrq(NetInterface *interface)
Enable interrupts.
uint16_t ksz8864ReadPhyReg(NetInterface *interface, uint8_t port, uint8_t address)
Read PHY register.
error_t ksz8864GetDynamicFdbEntry(NetInterface *interface, uint_t index, SwitchFdbEntry *entry)
Read an entry from the dynamic MAC table.
void ksz8864DumpPhyReg(NetInterface *interface, uint8_t port)
Dump PHY registers for debugging purpose.
error_t ksz8864TagFrame(NetInterface *interface, NetBuffer *buffer, size_t *offset, NetTxAncillary *ancillary)
Add tail tag to Ethernet frame.
__weak_func void ksz8864InitHook(NetInterface *interface)
KSZ8864 custom configuration.
void ksz8864SetUnknownMcastFwdPorts(NetInterface *interface, bool_t enable, uint32_t forwardPorts)
Set forward ports for unknown multicast packets.
const uint8_t ksz8864IngressTailTag[4]
Tail tag rules (host to KSZ8864)
const SwitchDriver ksz8864SwitchDriver
KSZ8864 Ethernet switch driver.
error_t ksz8864AddStaticFdbEntry(NetInterface *interface, const SwitchFdbEntry *entry)
Add a new entry to the static MAC table.
void ksz8864EnableIgmpSnooping(NetInterface *interface, bool_t enable)
Enable IGMP snooping.
error_t ksz8864Init(NetInterface *interface)
KSZ8864 Ethernet switch initialization.
void ksz8864Tick(NetInterface *interface)
KSZ8864 timer handler.
error_t ksz8864UntagFrame(NetInterface *interface, uint8_t **frame, size_t *length, NetRxAncillary *ancillary)
Decode tail tag from incoming Ethernet frame.
NicDuplexMode ksz8864GetDuplexMode(NetInterface *interface, uint8_t port)
Get duplex mode.
SwitchPortState ksz8864GetPortState(NetInterface *interface, uint8_t port)
Get port state.
KSZ8864 4-port Ethernet switch driver.
#define KSZ8864_PORT_MASK
#define KSZ8864_PORTn_STAT0_OP_SPEED
#define KSZ8864_PORTn_CTRL2_LEARNING_DIS
#define KSZ8864_GLOBAL_CTRL10_TAIL_TAG_EN
#define KSZ8864_INDIRECT_CTRL1
#define KSZ8864_INDIRECT_CTRL0_READ
#define KSZ8864_INDIRECT_CTRL0_TABLE_SEL_DYNAMIC_MAC
#define KSZ8864_GLOBAL_CTRL4_SW4_SPEED
#define KSZ8864_PORT4
#define KSZ8864_GLOBAL_CTRL16_UNKNOWN_MCAST_FWD_MAP_ALL
#define KSZ8864_INDIRECT_CTRL0_ADDR_H
#define KSZ8864_SPI_CMD_READ
#define KSZ8864_TAIL_TAG_DEST_PORT1
#define KSZ8864_GLOBAL_CTRL3
#define KSZ8864_PORTn_STAT1(port)
#define KSZ8864_INDIRECT_CTRL0_WRITE
#define KSZ8864_GLOBAL_CTRL16_UNKNOWN_MCAST_FWD
#define KSZ8864_GLOBAL_CTRL16
#define KSZ8864_TAIL_TAG_SRC_PORT
#define KSZ8864_CHIP_ID0
#define KSZ8864_PORTn_STAT0_OP_DUPLEX
#define KSZ8864_INDIRECT_DATA7
#define KSZ8864_INDIRECT_DATA8
#define KSZ8864_TAIL_TAG_DEST_PORT3
#define KSZ8864_GLOBAL_CTRL0_FLUSH_STATIC_MAC_TABLE
#define KSZ8864_TAIL_TAG_NORMAL_ADDR_LOOKUP
#define KSZ8864_GLOBAL_CTRL16_UNKNOWN_MCAST_FWD_MAP
#define KSZ8864_PORT2
#define KSZ8864_PORT1
#define KSZ8864_STATIC_MAC_TABLE_SIZE
#define KSZ8864_CHIP_ID1
#define KSZ8864_PORTn_STAT1_LINK_GOOD
#define KSZ8864_SPI_CMD_WRITE
#define KSZ8864_GLOBAL_CTRL4
#define KSZ8864_PORT3
#define KSZ8864_PORTn_CTRL2(port)
#define KSZ8864_TAIL_TAG_DEST_PORT2
#define KSZ8864_GLOBAL_CTRL0_FLUSH_DYNAMIC_MAC_TABLE
#define KSZ8864_TAIL_TAG_PORT_SEL
#define KSZ8864_PORTn_STAT0(port)
#define KSZ8864_GLOBAL_CTRL4_SW4_HALF_DUPLEX_MODE
#define KSZ8864_PORT4_MASK
#define KSZ8864_PORTn_CTRL2_TRANSMIT_EN
#define KSZ8864_INDIRECT_CTRL0
#define KSZ8864_GLOBAL_CTRL10
#define KSZ8864_CHIP_ID0_FAMILY_ID_DEFAULT
#define KSZ8864_INDIRECT_CTRL0_TABLE_SEL_STATIC_MAC
#define KSZ8864_PORTn_CTRL2_RECEIVE_EN
#define KSZ8864_GLOBAL_CTRL16_UNKNOWN_MCAST_FWD_MAP_PORT4
#define KSZ8864_GLOBAL_CTRL0
#define KSZ8864_GLOBAL_CTRL3_SW4_IGMP_SNOOP_EN
#define KSZ8864_DYNAMIC_MAC_TABLE_SIZE
#define KSZ8864_CHIP_ID1_START_SWITCH
uint16_t regAddr
uint8_t p
Definition: ndp.h:300
TCP/IP stack core.
#define NET_INTERFACE_COUNT
Definition: net.h:113
#define NetInterface
Definition: net.h:36
#define netInterface
Definition: net_legacy.h:199
#define netEvent
Definition: net_legacy.h:196
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
error_t netBufferAppend(NetBuffer *dest, const void *src, size_t length)
Append data a multi-part buffer.
Definition: net_mem.c:588
#define NetRxAncillary
Definition: net_misc.h:40
#define NetTxAncillary
Definition: net_misc.h:36
void nicNotifyLinkChange(NetInterface *interface)
Process link state change notification.
Definition: nic.c:548
#define SMI_OPCODE_WRITE
Definition: nic.h:66
#define SMI_OPCODE_READ
Definition: nic.h:67
NicDuplexMode
Duplex mode.
Definition: nic.h:122
@ NIC_FULL_DUPLEX_MODE
Definition: nic.h:125
@ NIC_HALF_DUPLEX_MODE
Definition: nic.h:124
@ NIC_UNKNOWN_DUPLEX_MODE
Definition: nic.h:123
#define SWITCH_CPU_PORT_MASK
Definition: nic.h:60
SwitchPortState
Switch port state.
Definition: nic.h:134
@ SWITCH_PORT_STATE_UNKNOWN
Definition: nic.h:135
@ SWITCH_PORT_STATE_FORWARDING
Definition: nic.h:140
@ SWITCH_PORT_STATE_LISTENING
Definition: nic.h:138
@ SWITCH_PORT_STATE_DISABLED
Definition: nic.h:136
@ SWITCH_PORT_STATE_LEARNING
Definition: nic.h:139
@ NIC_LINK_SPEED_100MBPS
Definition: nic.h:112
@ NIC_LINK_SPEED_10MBPS
Definition: nic.h:111
@ NIC_LINK_SPEED_UNKNOWN
Definition: nic.h:110
#define LSB(x)
Definition: os_port.h:55
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
#define MSB(x)
Definition: os_port.h:59
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
Dynamic MAC table entry.
uint8_t numValidEntriesH
uint8_t sourcePort
MacAddr macAddr
uint8_t macEmpty
uint8_t numValidEntriesL
uint8_t dataNotReady
Static MAC table entry (read operation)
uint8_t forwardPorts
MacAddr macAddr
uint8_t valid
uint8_t override
Static MAC table entry (write operation)
uint8_t forwardPorts
MacAddr macAddr
uint8_t valid
uint8_t useFid
uint8_t override
uint8_t fid
uint8_t reserved
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
Ethernet switch driver.
Definition: nic.h:322
Forwarding database entry.
Definition: nic.h:149
MacAddr macAddr
Definition: nic.h:150
uint32_t destPorts
Definition: nic.h:152
bool_t override
Definition: nic.h:153
uint8_t srcPort
Definition: nic.h:151
uint8_t length
Definition: tcp.h:368