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