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-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 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
182  osSetEvent(&interface->netContext->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 __weak_func 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  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 = ksz8895GetLinkState(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(ksz8895GetLinkState(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 KSZ8895 event handler
295  * @param[in] interface Underlying network interface
296  **/
297 
298 __weak_func void ksz8895EventHandler(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 >= KSZ8895_PORT1 && port <= KSZ8895_PORT4)
330  {
331  //Retrieve current link state
332  linkState = ksz8895GetLinkState(interface, port);
333 
334  //Link up event?
335  if(linkState && !virtualInterface->linkState)
336  {
337  //Retrieve host interface speed
338  interface->linkSpeed = ksz8895GetLinkSpeed(interface,
339  KSZ8895_PORT5);
340 
341  //Retrieve host interface duplex mode
342  interface->duplexMode = ksz8895GetDuplexMode(interface,
343  KSZ8895_PORT5);
344 
345  //Adjust MAC configuration parameters for proper operation
346  interface->nicDriver->updateMacConfig(interface);
347 
348  //Check current speed
349  virtualInterface->linkSpeed = ksz8895GetLinkSpeed(interface,
350  port);
351 
352  //Check current duplex mode
353  virtualInterface->duplexMode = ksz8895GetDuplexMode(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(ksz8895GetLinkState(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 = ksz8895GetLinkSpeed(interface, KSZ8895_PORT5);
396  //Retrieve host interface duplex mode
397  interface->duplexMode = ksz8895GetDuplexMode(interface, KSZ8895_PORT5);
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 <= KSZ8895_PORT4)
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 = &ksz8895IngressTailTag[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 ksz8895UntagFrame(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 & KSZ8895_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 >= KSZ8895_PORT1 && port <= KSZ8895_PORT4)
532  {
533  //Read port status 1 register
534  status = ksz8895ReadSwitchReg(interface, KSZ8895_PORTn_STAT1(port));
535 
536  //Retrieve current link state
537  linkState = (status & KSZ8895_PORTn_STAT1_LINK_GOOD) ? TRUE : FALSE;
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 ksz8895GetLinkSpeed(NetInterface *interface, uint8_t port)
558 {
559  uint16_t status;
560  uint32_t linkSpeed;
561 
562  //Check port number
563  if(port >= KSZ8895_PORT1 && port <= KSZ8895_PORT4)
564  {
565  //Read port status 0 register
566  status = ksz8895ReadSwitchReg(interface, KSZ8895_PORTn_STAT0(port));
567 
568  //Retrieve current link speed
569  if((status & KSZ8895_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 == KSZ8895_PORT5)
579  {
580  //Read global control 4 register
581  status = ksz8895ReadSwitchReg(interface, KSZ8895_GLOBAL_CTRL4);
582 
583  //Retrieve host interface speed
584  if((status & KSZ8895_GLOBAL_CTRL4_SW5_SPEED) != 0)
585  {
586  linkSpeed = NIC_LINK_SPEED_10MBPS;
587  }
588  else
589  {
590  linkSpeed = NIC_LINK_SPEED_100MBPS;
591  }
592  }
593  else
594  {
595  //The specified port number is not valid
596  linkSpeed = NIC_LINK_SPEED_UNKNOWN;
597  }
598 
599  //Return link speed
600  return linkSpeed;
601 }
602 
603 
604 /**
605  * @brief Get duplex mode
606  * @param[in] interface Underlying network interface
607  * @param[in] port Port number
608  * @return Duplex mode
609  **/
610 
612 {
613  uint16_t status;
614  NicDuplexMode duplexMode;
615 
616  //Check port number
617  if(port >= KSZ8895_PORT1 && port <= KSZ8895_PORT4)
618  {
619  //Read port status 0 register
620  status = ksz8895ReadSwitchReg(interface, KSZ8895_PORTn_STAT0(port));
621 
622  //Retrieve current duplex mode
623  if((status & KSZ8895_PORTn_STAT0_OP_DUPLEX) != 0)
624  {
625  duplexMode = NIC_FULL_DUPLEX_MODE;
626  }
627  else
628  {
629  duplexMode = NIC_HALF_DUPLEX_MODE;
630  }
631  }
632  else if(port == KSZ8895_PORT5)
633  {
634  //Read global control 4 register
635  status = ksz8895ReadSwitchReg(interface, KSZ8895_GLOBAL_CTRL4);
636 
637  //Retrieve host interface duplex mode
639  {
640  duplexMode = NIC_HALF_DUPLEX_MODE;
641  }
642  else
643  {
644  duplexMode = NIC_FULL_DUPLEX_MODE;
645  }
646  }
647  else
648  {
649  //The specified port number is not valid
650  duplexMode = NIC_UNKNOWN_DUPLEX_MODE;
651  }
652 
653  //Return duplex mode
654  return duplexMode;
655 }
656 
657 
658 /**
659  * @brief Set port state
660  * @param[in] interface Underlying network interface
661  * @param[in] port Port number
662  * @param[in] state Port state
663  **/
664 
665 void ksz8895SetPortState(NetInterface *interface, uint8_t port,
666  SwitchPortState state)
667 {
668  uint8_t temp;
669 
670  //Check port number
671  if(port >= KSZ8895_PORT1 && port <= KSZ8895_PORT4)
672  {
673  //Read port control 2 register
674  temp = ksz8895ReadSwitchReg(interface, KSZ8895_PORTn_CTRL2(port));
675 
676  //Update port state
677  switch(state)
678  {
679  //Listening state
684  break;
685 
686  //Learning state
691  break;
692 
693  //Forwarding state
698  break;
699 
700  //Disabled state
701  default:
705  break;
706  }
707 
708  //Write the value back to port control 2 register
710  }
711 }
712 
713 
714 /**
715  * @brief Get port state
716  * @param[in] interface Underlying network interface
717  * @param[in] port Port number
718  * @return Port state
719  **/
720 
722 {
723  uint8_t temp;
724  SwitchPortState state;
725 
726  //Check port number
727  if(port >= KSZ8895_PORT1 && port <= KSZ8895_PORT4)
728  {
729  //Read port control 2 register
730  temp = ksz8895ReadSwitchReg(interface, KSZ8895_PORTn_CTRL2(port));
731 
732  //Check port state
733  if((temp & KSZ8895_PORTn_CTRL2_TRANSMIT_EN) == 0 &&
734  (temp & KSZ8895_PORTn_CTRL2_RECEIVE_EN) == 0 &&
735  (temp & KSZ8895_PORTn_CTRL2_LEARNING_DIS) != 0)
736  {
737  //Disabled state
739  }
740  else if((temp & KSZ8895_PORTn_CTRL2_TRANSMIT_EN) == 0 &&
741  (temp & KSZ8895_PORTn_CTRL2_RECEIVE_EN) != 0 &&
742  (temp & KSZ8895_PORTn_CTRL2_LEARNING_DIS) != 0)
743  {
744  //Listening state
746  }
747  else if((temp & KSZ8895_PORTn_CTRL2_TRANSMIT_EN) == 0 &&
748  (temp & KSZ8895_PORTn_CTRL2_RECEIVE_EN) == 0 &&
749  (temp & KSZ8895_PORTn_CTRL2_LEARNING_DIS) == 0)
750  {
751  //Learning state
753  }
754  else if((temp & KSZ8895_PORTn_CTRL2_TRANSMIT_EN) != 0 &&
755  (temp & KSZ8895_PORTn_CTRL2_RECEIVE_EN) != 0 &&
756  (temp & KSZ8895_PORTn_CTRL2_LEARNING_DIS) == 0)
757  {
758  //Forwarding state
760  }
761  else
762  {
763  //Unknown state
765  }
766  }
767  else
768  {
769  //The specified port number is not valid
771  }
772 
773  //Return port state
774  return state;
775 }
776 
777 
778 /**
779  * @brief Set aging time for dynamic filtering entries
780  * @param[in] interface Underlying network interface
781  * @param[in] agingTime Aging time, in seconds
782  **/
783 
784 void ksz8895SetAgingTime(NetInterface *interface, uint32_t agingTime)
785 {
786  //The aging period is fixed to 300 seconds
787 }
788 
789 
790 /**
791  * @brief Enable IGMP snooping
792  * @param[in] interface Underlying network interface
793  * @param[in] enable Enable or disable IGMP snooping
794  **/
795 
797 {
798  uint8_t temp;
799 
800  //Read global control 3 register
801  temp = ksz8895ReadSwitchReg(interface, KSZ8895_GLOBAL_CTRL3);
802 
803  //Enable or disable IGMP snooping
804  if(enable)
805  {
807  }
808  else
809  {
811  }
812 
813  //Write the value back to global control 3 register
815 }
816 
817 
818 /**
819  * @brief Enable MLD snooping
820  * @param[in] interface Underlying network interface
821  * @param[in] enable Enable or disable MLD snooping
822  **/
823 
825 {
826  //Not implemented
827 }
828 
829 
830 /**
831  * @brief Enable reserved multicast table
832  * @param[in] interface Underlying network interface
833  * @param[in] enable Enable or disable reserved group addresses
834  **/
835 
837 {
838  uint_t i;
839  SwitchFdbEntry entry;
840 
841  //The reserved group addresses are in the range of 01-80-C2-00-00-00 to
842  //01-80-C2-00-00-0F
843  for(i = 0; i <= 15; i++)
844  {
845  //Specify the reserved group address to be added or removed
846  entry.macAddr.b[0] = 0x01;
847  entry.macAddr.b[1] = 0x80;
848  entry.macAddr.b[2] = 0xC2;
849  entry.macAddr.b[3] = 0x00;
850  entry.macAddr.b[4] = 0x00;
851  entry.macAddr.b[5] = i;
852 
853  //Format forwarding database entry
854  entry.srcPort = 0;
856  entry.override = TRUE;
857 
858  //Update the static MAC table
859  if(enable)
860  {
861  ksz8895AddStaticFdbEntry(interface, &entry);
862  }
863  else
864  {
865  ksz8895DeleteStaticFdbEntry(interface, &entry);
866  }
867  }
868 }
869 
870 
871 /**
872  * @brief Add a new entry to the static MAC table
873  * @param[in] interface Underlying network interface
874  * @param[in] entry Pointer to the forwarding database entry
875  * @return Error code
876  **/
877 
879  const SwitchFdbEntry *entry)
880 {
881  error_t error;
882  uint_t i;
883  uint_t j;
884  uint8_t *p;
885  SwitchFdbEntry currentEntry;
886  Ksz8895StaticMacEntryW newEntry;
887 
888  //Keep track of the first free entry
890 
891  //Loop through the static MAC table
892  for(i = 0; i < KSZ8895_STATIC_MAC_TABLE_SIZE; i++)
893  {
894  //Read current entry
895  error = ksz8895GetStaticFdbEntry(interface, i, &currentEntry);
896 
897  //Valid entry?
898  if(!error)
899  {
900  //Check whether the table already contains the specified MAC address
901  if(macCompAddr(&currentEntry.macAddr, &entry->macAddr))
902  {
903  j = i;
904  break;
905  }
906  }
907  else
908  {
909  //Keep track of the first free entry
911  {
912  j = i;
913  }
914  }
915  }
916 
917  //Any entry available?
919  {
920  //Format MAC entry
921  newEntry.fid = 0;
922  newEntry.useFid = 0;
923  newEntry.override = entry->override;
924  newEntry.valid = TRUE;
925  newEntry.macAddr = entry->macAddr;
926 
927  //Set the relevant forward ports
928  if(entry->destPorts == SWITCH_CPU_PORT_MASK)
929  {
930  newEntry.forwardPorts = KSZ8895_PORT5_MASK;
931  }
932  else
933  {
934  newEntry.forwardPorts = entry->destPorts & KSZ8895_PORT_MASK;
935  }
936 
937  //Select the static MAC address table
941 
942  //Point to the MAC entry
943  p = (uint8_t *) &newEntry;
944 
945  //Write indirect data registers
946  for(i = 0; i < sizeof(Ksz8895StaticMacEntryW); i++)
947  {
948  ksz8895WriteSwitchReg(interface, KSZ8895_INDIRECT_DATA7 + i, p[i]);
949  }
950 
951  //Setup a write operation
955 
956  //Trigger the write operation
958 
959  //Successful processing
960  error = NO_ERROR;
961  }
962  else
963  {
964  //The static MAC table is full
965  error = ERROR_TABLE_FULL;
966  }
967 
968  //Return status code
969  return error;
970 }
971 
972 
973 /**
974  * @brief Remove an entry from the static MAC table
975  * @param[in] interface Underlying network interface
976  * @param[in] entry Forwarding database entry to remove from the table
977  * @return Error code
978  **/
979 
981  const SwitchFdbEntry *entry)
982 {
983  error_t error;
984  uint_t i;
985  uint_t j;
986  SwitchFdbEntry currentEntry;
987 
988  //Loop through the static MAC table
989  for(j = 0; j < KSZ8895_STATIC_MAC_TABLE_SIZE; j++)
990  {
991  //Read current entry
992  error = ksz8895GetStaticFdbEntry(interface, j, &currentEntry);
993 
994  //Valid entry?
995  if(!error)
996  {
997  //Check whether the table contains the specified MAC address
998  if(macCompAddr(&currentEntry.macAddr, &entry->macAddr))
999  {
1000  break;
1001  }
1002  }
1003  }
1004 
1005  //Any matching entry?
1007  {
1008  //Select the static MAC address table
1012 
1013  //Clear indirect data registers
1014  for(i = 0; i < sizeof(Ksz8895StaticMacEntryW); i++)
1015  {
1016  ksz8895WriteSwitchReg(interface, KSZ8895_INDIRECT_DATA7 + i, 0);
1017  }
1018 
1019  //Setup a write operation
1023 
1024  //Trigger the write operation
1026 
1027  //Successful processing
1028  error = NO_ERROR;
1029  }
1030  else
1031  {
1032  //The static MAC table does not contain the specified address
1033  error = ERROR_NOT_FOUND;
1034  }
1035 
1036  //Return status code
1037  return error;
1038 }
1039 
1040 
1041 /**
1042  * @brief Read an entry from the static MAC table
1043  * @param[in] interface Underlying network interface
1044  * @param[in] index Zero-based index of the entry to read
1045  * @param[out] entry Pointer to the forwarding database entry
1046  * @return Error code
1047  **/
1048 
1050  SwitchFdbEntry *entry)
1051 {
1052  error_t error;
1053  uint_t i;
1054  uint8_t *p;
1055  Ksz8895StaticMacEntryR currentEntry;
1056 
1057  //Check index parameter
1058  if(index < KSZ8895_STATIC_MAC_TABLE_SIZE)
1059  {
1060  //Select the static MAC address table
1064 
1065  //Trigger the read operation
1066  ksz8895WriteSwitchReg(interface, KSZ8895_INDIRECT_CTRL1, index);
1067 
1068  //Point to the MAC entry
1069  p = (uint8_t *) &currentEntry;
1070 
1071  //Read indirect data registers
1072  for(i = 0; i < sizeof(Ksz8895StaticMacEntryR); i++)
1073  {
1074  p[i] = ksz8895ReadSwitchReg(interface, KSZ8895_INDIRECT_DATA7 + i);
1075  }
1076 
1077  //Valid entry?
1078  if(currentEntry.valid)
1079  {
1080  //Copy MAC entry
1081  entry->macAddr = currentEntry.macAddr;
1082  entry->srcPort = 0;
1083  entry->destPorts = currentEntry.forwardPorts & KSZ8895_PORT_MASK;
1084  entry->override = currentEntry.override;
1085 
1086  //Successful processing
1087  error = NO_ERROR;
1088  }
1089  else
1090  {
1091  //The entry is not valid
1092  error = ERROR_INVALID_ENTRY;
1093  }
1094  }
1095  else
1096  {
1097  //The end of the table has been reached
1098  error = ERROR_END_OF_TABLE;
1099  }
1100 
1101  //Return status code
1102  return error;
1103 }
1104 
1105 
1106 /**
1107  * @brief Flush static MAC table
1108  * @param[in] interface Underlying network interface
1109  **/
1110 
1112 {
1113  uint_t i;
1114  uint_t temp;
1115  uint8_t state[5];
1116 
1117  //Loop through the ports
1118  for(i = KSZ8895_PORT1; i <= KSZ8895_PORT5; i++)
1119  {
1120  //Save the current state of the port
1121  state[i - 1] = ksz8895ReadSwitchReg(interface, KSZ8895_PORTn_CTRL2(i));
1122 
1123  //Turn off learning capability
1125  state[i - 1] | KSZ8895_PORTn_CTRL2_LEARNING_DIS);
1126  }
1127 
1128  //All the entries associated with a port that has its learning capability
1129  //being turned off will be flushed
1130  temp = ksz8895ReadSwitchReg(interface, KSZ8895_GLOBAL_CTRL0);
1132  ksz8895WriteSwitchReg(interface, KSZ8895_GLOBAL_CTRL0, temp);
1133 
1134  //Loop through the ports
1135  for(i = KSZ8895_PORT1; i <= KSZ8895_PORT5; i++)
1136  {
1137  //Restore the original state of the port
1138  ksz8895WriteSwitchReg(interface, KSZ8895_PORTn_CTRL2(i), state[i - 1]);
1139  }
1140 }
1141 
1142 
1143 /**
1144  * @brief Set forward ports for unknown multicast packets
1145  * @param[in] interface Underlying network interface
1146  * @param[in] enable Enable or disable forwarding of unknown multicast packets
1147  * @param[in] forwardPorts Port map
1148  **/
1149 
1151  bool_t enable, uint32_t forwardPorts)
1152 {
1153  uint8_t temp;
1154 
1155  //Read global control 16 register
1156  temp = ksz8895ReadSwitchReg(interface, KSZ8895_GLOBAL_CTRL16);
1157 
1158  //Clear port map
1160 
1161  //Enable or disable forwarding of unknown multicast packets
1162  if(enable)
1163  {
1164  //Enable forwarding
1166 
1167  //Check whether unknown multicast packets should be forwarded to the CPU port
1168  if((forwardPorts & SWITCH_CPU_PORT_MASK) != 0)
1169  {
1171  }
1172 
1173  //Select the desired forward ports
1174  temp |= forwardPorts & KSZ8895_GLOBAL_CTRL16_UNKNOWN_MCAST_FWD_MAP_ALL;
1175  }
1176  else
1177  {
1178  //Disable forwarding
1180  }
1181 
1182  //Write the value back to global control 16 register
1183  ksz8895WriteSwitchReg(interface, KSZ8895_GLOBAL_CTRL16, temp);
1184 }
1185 
1186 
1187 /**
1188  * @brief Read an entry from the dynamic MAC table
1189  * @param[in] interface Underlying network interface
1190  * @param[in] index Zero-based index of the entry to read
1191  * @param[out] entry Pointer to the forwarding database entry
1192  * @return Error code
1193  **/
1194 
1196  SwitchFdbEntry *entry)
1197 {
1198  error_t error;
1199  uint_t i;
1200  uint_t n;
1201  uint8_t *p;
1202  Ksz8895DynamicMacEntry currentEntry;
1203 
1204  //Check index parameter
1205  if(index < KSZ8895_DYNAMIC_MAC_TABLE_SIZE)
1206  {
1207  //Read the MAC entry at the specified index
1208  do
1209  {
1210  //Select the dynamic MAC address table
1214  (MSB(index) & KSZ8895_INDIRECT_CTRL0_ADDR_H));
1215 
1216  //Trigger the read operation
1217  ksz8895WriteSwitchReg(interface, KSZ8895_INDIRECT_CTRL1, LSB(index));
1218 
1219  //Point to the MAC entry
1220  p = (uint8_t *) &currentEntry;
1221 
1222  //Read indirect data registers
1223  for(i = 0; i < sizeof(Ksz8895DynamicMacEntry); i++)
1224  {
1225  p[i] = ksz8895ReadSwitchReg(interface, KSZ8895_INDIRECT_DATA8 + i);
1226  }
1227 
1228  //Retry until the entry is ready
1229  } while(currentEntry.dataNotReady);
1230 
1231  //Check whether there are valid entries in the table
1232  if(!currentEntry.macEmpty)
1233  {
1234  //Retrieve the number of valid entries
1235  n = ((currentEntry.numValidEntriesH << 3) |
1236  currentEntry.numValidEntriesL) + 1;
1237  }
1238  else
1239  {
1240  //The table is empty
1241  n = 0;
1242  }
1243 
1244  //Valid entry?
1245  if(index < n)
1246  {
1247  //Copy MAC entry
1248  entry->macAddr = currentEntry.macAddr;
1249  entry->srcPort = currentEntry.sourcePort + 1;
1250  entry->destPorts = 0;
1251  entry->override = FALSE;
1252 
1253  //Successful processing
1254  error = NO_ERROR;
1255  }
1256  else
1257  {
1258  //The end of the table has been reached
1259  error = ERROR_END_OF_TABLE;
1260  }
1261  }
1262  else
1263  {
1264  //The end of the table has been reached
1265  error = ERROR_END_OF_TABLE;
1266  }
1267 
1268  //Return status code
1269  return error;
1270 }
1271 
1272 
1273 /**
1274  * @brief Flush dynamic MAC table
1275  * @param[in] interface Underlying network interface
1276  * @param[in] port Port number
1277  **/
1278 
1280 {
1281  uint_t i;
1282  uint_t temp;
1283  uint8_t state[5];
1284 
1285  //Loop through the ports
1286  for(i = KSZ8895_PORT1; i <= KSZ8895_PORT5; i++)
1287  {
1288  //Matching port number?
1289  if(i == port || port == 0)
1290  {
1291  //Save the current state of the port
1292  state[i - 1] = ksz8895ReadSwitchReg(interface, KSZ8895_PORTn_CTRL2(i));
1293 
1294  //Turn off learning capability
1296  state[i - 1] | KSZ8895_PORTn_CTRL2_LEARNING_DIS);
1297  }
1298  }
1299 
1300  //All the entries associated with a port that has its learning capability
1301  //being turned off will be flushed
1302  temp = ksz8895ReadSwitchReg(interface, KSZ8895_GLOBAL_CTRL0);
1304  ksz8895WriteSwitchReg(interface, KSZ8895_GLOBAL_CTRL0, temp);
1305 
1306  //Loop through the ports
1307  for(i = KSZ8895_PORT1; i <= KSZ8895_PORT5; i++)
1308  {
1309  //Matching port number?
1310  if(i == port || port == 0)
1311  {
1312  //Restore the original state of the port
1313  ksz8895WriteSwitchReg(interface, KSZ8895_PORTn_CTRL2(i), state[i - 1]);
1314  }
1315  }
1316 }
1317 
1318 
1319 /**
1320  * @brief Write VLAN entry
1321  * @param[in] interface Underlying network interface
1322  * @param[in] entry VLAN entry
1323  * @return Error code
1324  **/
1325 
1327  const SwitchVlanEntry *entry)
1328 {
1329  error_t error;
1330  uint_t i;
1331  uint8_t *p;
1332  Ksz8895VlanEntrySet vlanSet;
1333 
1334  //The VLAN table supports up to 4096 VLAN entries
1335  if(entry->vlanId < KSZ8895_VLAN_TABLE_SIZE)
1336  {
1337  //Select the VLAN table for reading
1341 
1342  //Trigger the read operation
1344  entry->vlanId / 4);
1345 
1346  //Point to the VLAN set
1347  p = (uint8_t *) &vlanSet;
1348 
1349  //Read indirect data registers
1350  for(i = 0; i < sizeof(Ksz8895VlanEntrySet); i++)
1351  {
1352  p[i] = ksz8895ReadSwitchReg(interface, KSZ8895_INDIRECT_DATA6 + i);
1353  }
1354 
1355  //Each VLAN set consists of 4 VLAN entries
1356  switch(entry->vlanId % 4)
1357  {
1358  case 0:
1359  //Modify the first VLAN entry of the VLAN set
1360  vlanSet.entry0Valid = entry->valid;
1361  vlanSet.entry0MembershipL = entry->ports & 0x01;
1362  vlanSet.entry0MembershipH = (entry->ports >> 1) & 0x0F;
1363  vlanSet.entry0Fid = entry->fid & 0x7F;
1364  break;
1365 
1366  case 1:
1367  //Modify the second VLAN entry of the VLAN set
1368  vlanSet.entry1Valid = entry->valid;
1369  vlanSet.entry1MembershipL = entry->ports & 0x0F;
1370  vlanSet.entry1MembershipH = (entry->ports >> 4) & 0x01;
1371  vlanSet.entry1FidL = entry->fid & 0x07;
1372  vlanSet.entry1FidH = (entry->fid >> 3) & 0x0F;
1373  break;
1374 
1375  case 2:
1376  //Modify the third VLAN entry of the VLAN set
1377  vlanSet.entry2Valid = entry->valid;
1378  vlanSet.entry2Membership = entry->ports & 0x01F;
1379  vlanSet.entry2FidL = entry->fid & 0x03F;
1380  vlanSet.entry2FidH = (entry->fid >> 6) & 0x01;
1381  break;
1382 
1383  default:
1384  //Modify the fourth VLAN entry of the VLAN set
1385  vlanSet.entry3Valid = entry->valid;
1386  vlanSet.entry3MembershipL = entry->ports & 0x03;
1387  vlanSet.entry3MembershipH = (entry->ports >> 2) & 0x07;
1388  vlanSet.entry3FidL = entry->fid & 0x01;
1389  vlanSet.entry3FidH = (entry->fid >> 1) & 0x3F;
1390  break;
1391  }
1392 
1393  //Write indirect data registers
1394  for(i = 0; i < sizeof(Ksz8895VlanEntrySet); i++)
1395  {
1396  ksz8895WriteSwitchReg(interface, KSZ8895_INDIRECT_DATA6 + i, p[i]);
1397  }
1398 
1399  //Select the VLAN table for writing
1403 
1404  //Trigger the write operation
1406  entry->vlanId / 4);
1407 
1408  //Successful processing
1409  error = NO_ERROR;
1410  }
1411  else
1412  {
1413  //The VLAN identifier is invalid
1414  error = ERROR_INVALID_PARAMETER;
1415  }
1416 
1417  //Return status code
1418  return error;
1419 }
1420 
1421 
1422 /**
1423  * @brief Write PHY register
1424  * @param[in] interface Underlying network interface
1425  * @param[in] port Port number
1426  * @param[in] address PHY register address
1427  * @param[in] data Register value
1428  **/
1429 
1430 void ksz8895WritePhyReg(NetInterface *interface, uint8_t port,
1431  uint8_t address, uint16_t data)
1432 {
1433  //Write the specified PHY register
1434  if(interface->smiDriver != NULL)
1435  {
1436  interface->smiDriver->writePhyReg(SMI_OPCODE_WRITE, port, address, data);
1437  }
1438  else
1439  {
1440  interface->nicDriver->writePhyReg(SMI_OPCODE_WRITE, port, address, data);
1441  }
1442 }
1443 
1444 
1445 /**
1446  * @brief Read PHY register
1447  * @param[in] interface Underlying network interface
1448  * @param[in] port Port number
1449  * @param[in] address PHY register address
1450  * @return Register value
1451  **/
1452 
1453 uint16_t ksz8895ReadPhyReg(NetInterface *interface, uint8_t port,
1454  uint8_t address)
1455 {
1456  uint16_t data;
1457 
1458  //Read the specified PHY register
1459  if(interface->smiDriver != NULL)
1460  {
1461  data = interface->smiDriver->readPhyReg(SMI_OPCODE_READ, port, address);
1462  }
1463  else
1464  {
1465  data = interface->nicDriver->readPhyReg(SMI_OPCODE_READ, port, address);
1466  }
1467 
1468  //Return the value of the PHY register
1469  return data;
1470 }
1471 
1472 
1473 /**
1474  * @brief Dump PHY registers for debugging purpose
1475  * @param[in] interface Underlying network interface
1476  * @param[in] port Port number
1477  **/
1478 
1479 void ksz8895DumpPhyReg(NetInterface *interface, uint8_t port)
1480 {
1481  uint8_t i;
1482 
1483  //Loop through PHY registers
1484  for(i = 0; i < 32; i++)
1485  {
1486  //Display current PHY register
1487  TRACE_DEBUG("%02" PRIu8 ": 0x%04" PRIX16 "\r\n", i,
1488  ksz8895ReadPhyReg(interface, port, i));
1489  }
1490 
1491  //Terminate with a line feed
1492  TRACE_DEBUG("\r\n");
1493 }
1494 
1495 
1496 /**
1497  * @brief Write switch register
1498  * @param[in] interface Underlying network interface
1499  * @param[in] address Switch register address
1500  * @param[in] data Register value
1501  **/
1502 
1503 void ksz8895WriteSwitchReg(NetInterface *interface, uint8_t address,
1504  uint8_t data)
1505 {
1506  uint8_t phyAddr;
1507  uint8_t regAddr;
1508 
1509  //SPI slave mode?
1510  if(interface->spiDriver != NULL)
1511  {
1512  //Pull the CS pin low
1513  interface->spiDriver->assertCs();
1514 
1515  //Set up a write operation
1516  interface->spiDriver->transfer(KSZ8895_SPI_CMD_WRITE);
1517  //Write register address
1518  interface->spiDriver->transfer(address);
1519 
1520  //Write data
1521  interface->spiDriver->transfer(data);
1522 
1523  //Terminate the operation by raising the CS pin
1524  interface->spiDriver->deassertCs();
1525  }
1526  else
1527  {
1528  //SMI register write access is selected when opcode is set to 10 and
1529  //bits 2:1 of the PHY address are set to 11
1530  phyAddr = 0x06 | ((address >> 3) & 0x18) | ((address >> 5) & 0x01);
1531 
1532  //Register address field forms register address bits 4:0
1533  regAddr = address & 0x1F;
1534 
1535  //Registers are 8 data bits wide. For write operation, data bits 15:8
1536  //are not defined, and hence can be set to either zeroes or ones
1537  if(interface->smiDriver != NULL)
1538  {
1539  interface->smiDriver->writePhyReg(SMI_OPCODE_WRITE, phyAddr, regAddr,
1540  data);
1541  }
1542  else
1543  {
1544  interface->nicDriver->writePhyReg(SMI_OPCODE_WRITE, phyAddr, regAddr,
1545  data);
1546  }
1547  }
1548 }
1549 
1550 
1551 /**
1552  * @brief Read switch register
1553  * @param[in] interface Underlying network interface
1554  * @param[in] address Switch register address
1555  * @return Register value
1556  **/
1557 
1558 uint8_t ksz8895ReadSwitchReg(NetInterface *interface, uint8_t address)
1559 {
1560  uint8_t phyAddr;
1561  uint8_t regAddr;
1562  uint8_t data;
1563 
1564  //SPI slave mode?
1565  if(interface->spiDriver != NULL)
1566  {
1567  //Pull the CS pin low
1568  interface->spiDriver->assertCs();
1569 
1570  //Set up a read operation
1571  interface->spiDriver->transfer(KSZ8895_SPI_CMD_READ);
1572  //Write register address
1573  interface->spiDriver->transfer(address);
1574 
1575  //Read data
1576  data = interface->spiDriver->transfer(0xFF);
1577 
1578  //Terminate the operation by raising the CS pin
1579  interface->spiDriver->deassertCs();
1580  }
1581  else
1582  {
1583  //SMI register read access is selected when opcode is set to 10 and
1584  //bits 2:1 of the PHY address are set to 11
1585  phyAddr = 0x06 | ((address >> 3) & 0x18) | ((address >> 5) & 0x01);
1586 
1587  //Register address field forms register address bits 4:0
1588  regAddr = address & 0x1F;
1589 
1590  //Registers are 8 data bits wide. For read operation, data bits 15:8
1591  //are read back as zeroes
1592  if(interface->smiDriver != NULL)
1593  {
1594  data = interface->smiDriver->readPhyReg(SMI_OPCODE_READ, phyAddr,
1595  regAddr) & 0xFF;
1596  }
1597  else
1598  {
1599  data = interface->nicDriver->readPhyReg(SMI_OPCODE_READ, phyAddr,
1600  regAddr) & 0xFF;
1601  }
1602  }
1603 
1604  //Return register value
1605  return data;
1606 }
1607 
1608 
1609 /**
1610  * @brief Dump switch registers for debugging purpose
1611  * @param[in] interface Underlying network interface
1612  **/
1613 
1615 {
1616  uint16_t i;
1617 
1618  //Loop through switch registers
1619  for(i = 0; i < 256; i++)
1620  {
1621  //Display current switch register
1622  TRACE_DEBUG("0x%02" PRIX16 " (%02" PRIu16 ") : 0x%02" PRIX8 "\r\n",
1623  i, i, ksz8895ReadSwitchReg(interface, i));
1624  }
1625 
1626  //Terminate with a line feed
1627  TRACE_DEBUG("\r\n");
1628 }
void nicNotifyLinkChange(NetInterface *interface)
Process link state change notification.
Definition: nic.c:601
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 NetContext
Definition: net.h:36
#define KSZ8895_PORTn_CTRL2(port)
int bool_t
Definition: compiler_port.h:63
@ ERROR_NOT_FOUND
Definition: error.h:148
@ NIC_LINK_SPEED_UNKNOWN
Definition: nic.h:110
uint32_t destPorts
Definition: nic.h:152
uint8_t entry3FidH
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
uint8_t entry3FidL
#define KSZ8895_INDIRECT_CTRL0_READ
@ NIC_FULL_DUPLEX_MODE
Definition: nic.h:125
uint8_t entry2Membership
@ SWITCH_PORT_STATE_LISTENING
Definition: nic.h:138
__weak_func void ksz8895Tick(NetInterface *interface)
KSZ8895 timer handler.
#define KSZ8895_DYNAMIC_MAC_TABLE_SIZE
#define KSZ8895_CHIP_ID1_START_SWITCH
@ 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
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:224
error_t ksz8895TagFrame(NetInterface *interface, NetBuffer *buffer, size_t *offset, NetTxAncillary *ancillary)
Add tail tag to Ethernet frame.
NicDuplexMode ksz8895GetDuplexMode(NetInterface *interface, uint8_t port)
Get duplex mode.
bool_t valid
Definition: nic.h:164
@ 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
__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:291
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:225
#define KSZ8895_SPI_CMD_WRITE
uint8_t entry1MembershipH
#define SMI_OPCODE_WRITE
Definition: nic.h:66
uint8_t entry3Valid
uint8_t override
uint8_t entry2FidL
#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
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
SwitchPortState ksz8895GetPortState(NetInterface *interface, uint8_t port)
Get port state.
uint8_t numValidEntriesH
VLAN entry.
Definition: nic.h:162
error_t
Error codes.
Definition: error.h:43
#define KSZ8895_GLOBAL_CTRL16_UNKNOWN_MCAST_FWD_MAP_PORT5
#define KSZ8895_PORT4
uint8_t entry2FidH
uint8_t entry0Fid
uint8_t entry1MembershipL
#define KSZ8895_TAIL_TAG_SRC_PORT
uint8_t entry0MembershipL
#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:40
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
Set of VLAN entries.
#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
uint8_t entry0MembershipH
#define KSZ8895_INDIRECT_DATA6
#define TRACE_INFO(...)
Definition: debug.h:105
#define KSZ8895_TAIL_TAG_DEST_PORT2
uint8_t length
Definition: tcp.h:375
#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
uint8_t entry1Valid
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
uint8_t entry0Valid
#define KSZ8895_PORTn_CTRL2_RECEIVE_EN
uint8_t entry3MembershipL
@ SWITCH_PORT_STATE_FORWARDING
Definition: nic.h:140
uint16_t port
Definition: dns_common.h:270
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:119
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
uint16_t fid
Definition: nic.h:165
Static MAC table entry (read operation)
uint8_t dataNotReady
uint8_t entry2Valid
uint16_t regAddr
uint8_t valid
#define KSZ8895_VLAN_TABLE_SIZE
#define KSZ8895_PORT5
Ethernet switch driver.
Definition: nic.h:325
#define KSZ8895_CHIP_ID0
#define KSZ8895_TAIL_TAG_DEST_PORT1
uint16_t vlanId
Definition: nic.h:163
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:290
error_t netBufferAppend(NetBuffer *dest, const void *src, size_t length)
Append data a multi-part buffer.
Definition: net_mem.c:604
Ipv6Addr address[]
Definition: ipv6.h:345
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
__weak_func void ksz8895EventHandler(NetInterface *interface)
KSZ8895 event handler.
#define KSZ8895_INDIRECT_CTRL0_TABLE_SEL_VLAN
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
uint8_t entry1FidL
@ NIC_UNKNOWN_DUPLEX_MODE
Definition: nic.h:123
#define KSZ8895_GLOBAL_CTRL16_UNKNOWN_MCAST_FWD
uint8_t macEmpty
error_t ksz8895WriteVlanEntry(NetInterface *interface, const SwitchVlanEntry *entry)
Write VLAN entry.
uint32_t ports
Definition: nic.h:166
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
uint8_t entry3MembershipH
unsigned int uint_t
Definition: compiler_port.h:57
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 entry1FidH
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