ksz8794_driver.c
Go to the documentation of this file.
1 /**
2  * @file ksz8794_driver.c
3  * @brief KSZ8794 4-port Ethernet switch driver
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2020 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 1.9.8
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 KSZ8794 Ethernet switch driver
43  **/
44 
46 {
67 };
68 
69 
70 /**
71  * @brief Tail tag rules (host to KSZ8794)
72  **/
73 
74 const uint8_t ksz8794IngressTailTag[4] =
75 {
80 };
81 
82 
83 /**
84  * @brief KSZ8794 Ethernet switch initialization
85  * @param[in] interface Underlying network interface
86  * @return Error code
87  **/
88 
90 {
91  uint_t port;
92  uint8_t temp;
93 
94  //Debug message
95  TRACE_INFO("Initializing KSZ8794...\r\n");
96 
97  //SPI slave mode?
98  if(interface->spiDriver != NULL)
99  {
100  //Initialize SPI interface
101  interface->spiDriver->init();
102 
103  //Wait for the serial interface to be ready
104  do
105  {
106  //Read CHIP_ID0 register
107  temp = ksz8794ReadSwitchReg(interface, KSZ8794_CHIP_ID0);
108 
109  //The returned data is invalid until the serial interface is ready
110  } while(temp != KSZ8794_CHIP_ID0_FAMILY_ID_DEFAULT);
111 
112 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
113  //Enable tail tag feature
114  temp = ksz8794ReadSwitchReg(interface, KSZ8794_GLOBAL_CTRL10);
117 #else
118  //Disable tail tag feature
119  temp = ksz8794ReadSwitchReg(interface, KSZ8794_GLOBAL_CTRL10);
122 #endif
123 
124  //Loop through the ports
126  {
127 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
128  //Port separation mode?
129  if(interface->port != 0)
130  {
131  //Disable packet transmission and address learning
133  }
134  else
135 #endif
136  {
137  //Enable transmission, reception and address learning
139  }
140  }
141 
142  //Silicon errata workaround #2
146 
147  //Silicon errata workaround #3
151 
152  //Silicon errata workaround #4
156 
157  //Dump switch registers for debugging purpose
158  ksz8794DumpSwitchReg(interface);
159  }
160  else
161  {
162  //Initialize serial management interface
163  if(interface->smiDriver != NULL)
164  {
165  interface->smiDriver->init();
166  }
167 
168  //Loop through the ports
170  {
171  //Debug message
172  TRACE_DEBUG("Port %u:\r\n", port);
173  //Dump PHY registers for debugging purpose
174  ksz8794DumpPhyReg(interface, port);
175  }
176  }
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 KSZ8794 timer handler
190  * @param[in] interface Underlying network interface
191  **/
192 
193 void ksz8794Tick(NetInterface *interface)
194 {
195  uint_t port;
196  bool_t linkState;
197 
198 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
199  //Port separation mode?
200  if(interface->port != 0)
201  {
202  uint_t i;
203  NetInterface *virtualInterface;
204 
205  //Loop through network interfaces
206  for(i = 0; i < NET_INTERFACE_COUNT; i++)
207  {
208  //Point to the current interface
209  virtualInterface = &netInterface[i];
210 
211  //Check whether the current virtual interface is attached to the
212  //physical interface
213  if(virtualInterface == interface ||
214  virtualInterface->parent == interface)
215  {
216  //Retrieve current link state
217  linkState = ksz8794GetLinkState(interface, virtualInterface->port);
218 
219  //Link up or link down event?
220  if(linkState != virtualInterface->linkState)
221  {
222  //Set event flag
223  interface->phyEvent = TRUE;
224  //Notify the TCP/IP stack of the event
226  }
227  }
228  }
229  }
230  else
231 #endif
232  {
233  //Initialize link state
234  linkState = FALSE;
235 
236  //Loop through the ports
238  {
239  //Retrieve current link state
240  if(ksz8794GetLinkState(interface, port))
241  {
242  linkState = TRUE;
243  }
244  }
245 
246  //Link up or link down event?
247  if(linkState != interface->linkState)
248  {
249  //Set event flag
250  interface->phyEvent = TRUE;
251  //Notify the TCP/IP stack of the event
253  }
254  }
255 }
256 
257 
258 /**
259  * @brief Enable interrupts
260  * @param[in] interface Underlying network interface
261  **/
262 
264 {
265 }
266 
267 
268 /**
269  * @brief Disable interrupts
270  * @param[in] interface Underlying network interface
271  **/
272 
274 {
275 }
276 
277 
278 /**
279  * @brief KSZ8794 event handler
280  * @param[in] interface Underlying network interface
281  **/
282 
284 {
285  uint_t port;
286  bool_t linkState;
287 
288 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
289  //Port separation mode?
290  if(interface->port != 0)
291  {
292  uint_t i;
293  NetInterface *virtualInterface;
294 
295  //Loop through network interfaces
296  for(i = 0; i < NET_INTERFACE_COUNT; i++)
297  {
298  //Point to the current interface
299  virtualInterface = &netInterface[i];
300 
301  //Check whether the current virtual interface is attached to the
302  //physical interface
303  if(virtualInterface == interface ||
304  virtualInterface->parent == interface)
305  {
306  //Get the port number associated with the current interface
307  port = virtualInterface->port;
308 
309  //Valid port?
310  if(port >= KSZ8794_PORT1 && port <= KSZ8794_PORT3)
311  {
312  //Retrieve current link state
313  linkState = ksz8794GetLinkState(interface, port);
314 
315  //Link up event?
316  if(linkState && !virtualInterface->linkState)
317  {
318  //Retrieve host interface speed
319  interface->linkSpeed = ksz8794GetLinkSpeed(interface,
320  KSZ8794_PORT4);
321 
322  //Retrieve host interface duplex mode
323  interface->duplexMode = ksz8794GetDuplexMode(interface,
324  KSZ8794_PORT4);
325 
326  //Adjust MAC configuration parameters for proper operation
327  interface->nicDriver->updateMacConfig(interface);
328 
329  //Check current speed
330  virtualInterface->linkSpeed = ksz8794GetLinkSpeed(interface,
331  port);
332 
333  //Check current duplex mode
334  virtualInterface->duplexMode = ksz8794GetDuplexMode(interface,
335  port);
336 
337  //Update link state
338  virtualInterface->linkState = TRUE;
339 
340  //Process link state change event
341  nicNotifyLinkChange(virtualInterface);
342  }
343  //Link down event
344  else if(!linkState && virtualInterface->linkState)
345  {
346  //Update link state
347  virtualInterface->linkState = FALSE;
348 
349  //Process link state change event
350  nicNotifyLinkChange(virtualInterface);
351  }
352  }
353  }
354  }
355  }
356  else
357 #endif
358  {
359  //Initialize link state
360  linkState = FALSE;
361 
362  //Loop through the ports
364  {
365  //Retrieve current link state
366  if(ksz8794GetLinkState(interface, port))
367  {
368  linkState = TRUE;
369  }
370  }
371 
372  //Link up event?
373  if(linkState)
374  {
375  //Retrieve host interface speed
376  interface->linkSpeed = ksz8794GetLinkSpeed(interface, KSZ8794_PORT4);
377  //Retrieve host interface duplex mode
378  interface->duplexMode = ksz8794GetDuplexMode(interface, KSZ8794_PORT4);
379 
380  //Adjust MAC configuration parameters for proper operation
381  interface->nicDriver->updateMacConfig(interface);
382 
383  //Update link state
384  interface->linkState = TRUE;
385  }
386  else
387  {
388  //Update link state
389  interface->linkState = FALSE;
390  }
391 
392  //Process link state change event
393  nicNotifyLinkChange(interface);
394  }
395 }
396 
397 
398 /**
399  * @brief Add tail tag to Ethernet frame
400  * @param[in] interface Underlying network interface
401  * @param[in] buffer Multi-part buffer containing the payload
402  * @param[in,out] offset Offset to the first payload byte
403  * @param[in] ancillary Additional options passed to the stack along with
404  * the packet
405  * @return Error code
406  **/
407 
409  size_t *offset, NetTxAncillary *ancillary)
410 {
411  error_t error;
412 
413  //Initialize status code
414  error = NO_ERROR;
415 
416 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
417  //SPI slave mode?
418  if(interface->spiDriver != NULL)
419  {
420  //Valid port?
421  if(ancillary->port <= KSZ8794_PORT3)
422  {
423  size_t length;
424  const uint8_t *tailTag;
425 
426  //The one byte tail tagging is used to indicate the destination port
427  tailTag = &ksz8794IngressTailTag[ancillary->port];
428 
429  //Retrieve the length of the Ethernet frame
430  length = netBufferGetLength(buffer) - *offset;
431 
432  //The host controller should manually add padding to the packet before
433  //inserting the tail tag
434  error = ethPadFrame(buffer, &length);
435 
436  //Check status code
437  if(!error)
438  {
439  //The tail tag is inserted at the end of the packet, just before
440  //the CRC
441  error = netBufferAppend(buffer, tailTag, sizeof(uint8_t));
442  }
443  }
444  else
445  {
446  //The port number is not valid
447  error = ERROR_INVALID_PORT;
448  }
449  }
450 #endif
451 
452  //Return status code
453  return error;
454 }
455 
456 
457 /**
458  * @brief Decode tail tag from incoming Ethernet frame
459  * @param[in] interface Underlying network interface
460  * @param[in,out] frame Pointer to the received Ethernet frame
461  * @param[in,out] length Length of the frame, in bytes
462  * @param[in,out] ancillary Additional options passed to the stack along with
463  * the packet
464  * @return Error code
465  **/
466 
467 error_t ksz8794UntagFrame(NetInterface *interface, uint8_t **frame,
468  size_t *length, NetRxAncillary *ancillary)
469 {
470  error_t error;
471 
472  //Initialize status code
473  error = NO_ERROR;
474 
475 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
476  //SPI slave mode?
477  if(interface->spiDriver != NULL)
478  {
479  //Valid Ethernet frame received?
480  if(*length >= (sizeof(EthHeader) + sizeof(uint8_t)))
481  {
482  uint8_t *tailTag;
483 
484  //The tail tag is inserted at the end of the packet, just before
485  //the CRC
486  tailTag = *frame + *length - sizeof(uint8_t);
487 
488  //The one byte tail tagging is used to indicate the source port
489  ancillary->port = (*tailTag & KSZ8794_TAIL_TAG_SRC_PORT) + 1;
490 
491  //Strip tail tag from Ethernet frame
492  *length -= sizeof(uint8_t);
493  }
494  else
495  {
496  //Drop the received frame
497  error = ERROR_INVALID_LENGTH;
498  }
499  }
500  else
501  {
502  //Tail tagging mode cannot be enabled through MDC/MDIO interface
503  ancillary->port = 0;
504  }
505 #endif
506 
507  //Return status code
508  return error;
509 }
510 
511 
512 /**
513  * @brief Get link state
514  * @param[in] interface Underlying network interface
515  * @param[in] port Port number
516  * @return Link state
517  **/
518 
520 {
521  uint16_t status;
522  bool_t linkState;
523 
524  //Check port number
525  if(port >= KSZ8794_PORT1 && port <= KSZ8794_PORT3)
526  {
527  //SPI slave mode?
528  if(interface->spiDriver != NULL)
529  {
530  //Read port status 2 register
531  status = ksz8794ReadSwitchReg(interface, KSZ8794_PORTn_STAT2(port));
532 
533  //Retrieve current link state
534  linkState = (status & KSZ8794_PORTn_STAT2_LINK_GOOD) ? TRUE : FALSE;
535  }
536  else
537  {
538  //Read status register
539  status = ksz8794ReadPhyReg(interface, port, KSZ8794_BMSR);
540 
541  //Retrieve current link state
542  linkState = (status & KSZ8794_BMSR_LINK_STATUS) ? TRUE : FALSE;
543  }
544  }
545  else
546  {
547  //The specified port number is not valid
548  linkState = FALSE;
549  }
550 
551  //Return link status
552  return linkState;
553 }
554 
555 
556 /**
557  * @brief Get link speed
558  * @param[in] interface Underlying network interface
559  * @param[in] port Port number
560  * @return Link speed
561  **/
562 
563 uint32_t ksz8794GetLinkSpeed(NetInterface *interface, uint8_t port)
564 {
565  uint8_t type;
566  uint8_t value;
567  uint32_t linkSpeed;
568 
569  //SPI slave mode?
570  if(interface->spiDriver != NULL)
571  {
572  //Check port number
573  if(port >= KSZ8794_PORT1 && port <= KSZ8794_PORT3)
574  {
575  //Read port status 1 register
577 
578  //Retrieve current link speed
580  {
581  linkSpeed = NIC_LINK_SPEED_100MBPS;
582  }
583  else
584  {
585  linkSpeed = NIC_LINK_SPEED_10MBPS;
586  }
587  }
588  else if(port == KSZ8794_PORT4)
589  {
590  //Read port 4 interface control 6 register
592 
593  //Retrieve host interface type
595 
596  //Gigabit interface?
599  {
600  //1000 Mb/s mode
601  linkSpeed = NIC_LINK_SPEED_1GBPS;
602  }
603  else
604  {
605  //Read global control 4 register
607 
608  //Retrieve host interface speed
610  {
611  //10 Mb/s mode
612  linkSpeed = NIC_LINK_SPEED_10MBPS;
613  }
614  else
615  {
616  //100 Mb/s mode
617  linkSpeed = NIC_LINK_SPEED_100MBPS;
618  }
619  }
620  }
621  else
622  {
623  //The specified port number is not valid
624  linkSpeed = NIC_LINK_SPEED_UNKNOWN;
625  }
626  }
627  else
628  {
629  //The MDC/MDIO interface does not have access to all the configuration
630  //registers. It can only access the standard MIIM registers
631  linkSpeed = NIC_LINK_SPEED_100MBPS;
632  }
633 
634  //Return link status
635  return linkSpeed;
636 }
637 
638 
639 /**
640  * @brief Get duplex mode
641  * @param[in] interface Underlying network interface
642  * @param[in] port Port number
643  * @return Duplex mode
644  **/
645 
647 {
648  uint8_t value;
649  NicDuplexMode duplexMode;
650 
651  //SPI slave mode?
652  if(interface->spiDriver != NULL)
653  {
654  //Check port number
655  if(port >= KSZ8794_PORT1 && port <= KSZ8794_PORT3)
656  {
657  //Read port status 1 register
659 
660  //Retrieve current duplex mode
662  {
663  duplexMode = NIC_FULL_DUPLEX_MODE;
664  }
665  else
666  {
667  duplexMode = NIC_HALF_DUPLEX_MODE;
668  }
669  }
670  else if(port == KSZ8794_PORT4)
671  {
672  //Read global control 4 register
674 
675  //Retrieve host interface duplex mode
677  {
678  duplexMode = NIC_HALF_DUPLEX_MODE;
679  }
680  else
681  {
682  duplexMode = NIC_FULL_DUPLEX_MODE;
683  }
684  }
685  else
686  {
687  //The specified port number is not valid
688  duplexMode = NIC_UNKNOWN_DUPLEX_MODE;
689  }
690  }
691  else
692  {
693  //The MDC/MDIO interface does not have access to all the configuration
694  //registers. It can only access the standard MIIM registers
695  duplexMode = NIC_FULL_DUPLEX_MODE;
696  }
697 
698  //Return duplex mode
699  return duplexMode;
700 }
701 
702 
703 /**
704  * @brief Set port state
705  * @param[in] interface Underlying network interface
706  * @param[in] port Port number
707  * @param[in] state Port state
708  * @return Duplex mode
709  **/
710 
711 void ksz8794SetPortState(NetInterface *interface, uint8_t port,
712  SwitchPortState state)
713 {
714  uint16_t temp;
715 
716  //Check port number
717  if(port >= KSZ8794_PORT1 && port <= KSZ8794_PORT3)
718  {
719  //Read port control 2 register
720  temp = ksz8794ReadSwitchReg(interface, KSZ8794_PORTn_CTRL2(port));
721 
722  //Update port state
723  switch(state)
724  {
725  //Listening state
730  break;
731 
732  //Learning state
737  break;
738 
739  //Forwarding state
744  break;
745 
746  //Disabled state
747  default:
751  break;
752  }
753 
754  //Write the value back to port control 2 register
756  }
757 }
758 
759 
760 /**
761  * @brief Get port state
762  * @param[in] interface Underlying network interface
763  * @param[in] port Port number
764  * @return Port state
765  **/
766 
768 {
769  uint16_t temp;
770  SwitchPortState state;
771 
772  //Check port number
773  if(port >= KSZ8794_PORT1 && port <= KSZ8794_PORT3)
774  {
775  //Read port control 2 register
776  temp = ksz8794ReadSwitchReg(interface, KSZ8794_PORTn_CTRL2(port));
777 
778  //Check port state
779  if((temp & KSZ8794_PORTn_CTRL2_TRANSMIT_EN) == 0 &&
780  (temp & KSZ8794_PORTn_CTRL2_RECEIVE_EN) == 0 &&
781  (temp & KSZ8794_PORTn_CTRL2_LEARNING_DIS) != 0)
782  {
783  //Disabled state
785  }
786  else if((temp & KSZ8794_PORTn_CTRL2_TRANSMIT_EN) == 0 &&
787  (temp & KSZ8794_PORTn_CTRL2_RECEIVE_EN) != 0 &&
788  (temp & KSZ8794_PORTn_CTRL2_LEARNING_DIS) != 0)
789  {
790  //Listening state
792  }
793  else if((temp & KSZ8794_PORTn_CTRL2_TRANSMIT_EN) == 0 &&
794  (temp & KSZ8794_PORTn_CTRL2_RECEIVE_EN) == 0 &&
795  (temp & KSZ8794_PORTn_CTRL2_LEARNING_DIS) == 0)
796  {
797  //Learning state
799  }
800  else if((temp & KSZ8794_PORTn_CTRL2_TRANSMIT_EN) != 0 &&
801  (temp & KSZ8794_PORTn_CTRL2_RECEIVE_EN) != 0 &&
802  (temp & KSZ8794_PORTn_CTRL2_LEARNING_DIS) == 0)
803  {
804  //Forwarding state
806  }
807  else
808  {
809  //Unknown state
811  }
812  }
813  else
814  {
815  //The specified port number is not valid
817  }
818 
819  //Return port state
820  return state;
821 }
822 
823 
824 /**
825  * @brief Set aging time for dynamic filtering entries
826  * @param[in] interface Underlying network interface
827  * @param[in] agingTime Aging time, in seconds
828  **/
829 
830 void ksz8794SetAgingTime(NetInterface *interface, uint32_t agingTime)
831 {
832  //The aging period is fixed to 300 seconds
833 }
834 
835 
836 /**
837  * @brief Enable reserved multicast table
838  * @param[in] interface Underlying network interface
839  * @param[in] enable Enable or disable reserved group addresses
840  **/
841 
843 {
844  uint_t i;
845  SwitchFdbEntry entry;
846 
847  //The reserved group addresses are in the range of 01-80-C2-00-00-00 to
848  //01-80-C2-00-00-0F
849  for(i = 0; i <= 15; i++)
850  {
851  //Specify the reserved group address to be added or removed
852  entry.macAddr.b[0] = 0x01;
853  entry.macAddr.b[1] = 0x80;
854  entry.macAddr.b[2] = 0xC2;
855  entry.macAddr.b[3] = 0x00;
856  entry.macAddr.b[4] = 0x00;
857  entry.macAddr.b[5] = i;
858 
859  //Format forwarding database entry
860  entry.srcPort = 0;
862  entry.override = TRUE;
863 
864  //Update the static MAC table
865  if(enable)
866  {
867  ksz8794AddStaticFdbEntry(interface, &entry);
868  }
869  else
870  {
871  ksz8794DeleteStaticFdbEntry(interface, &entry);
872  }
873  }
874 }
875 
876 
877 /**
878  * @brief Add a new entry to the static MAC table
879  * @param[in] interface Underlying network interface
880  * @param[in] entry Pointer to the forwarding database entry
881  * @return Error code
882  **/
883 
885  const SwitchFdbEntry *entry)
886 {
887  error_t error;
888  uint_t i;
889  uint_t j;
890  uint8_t *p;
891  SwitchFdbEntry currentEntry;
892  Ksz8794StaticMacEntryW newEntry;
893 
894  //Keep track of the first free entry
896 
897  //Loop through the static MAC table
898  for(i = 0; i < KSZ8794_STATIC_MAC_TABLE_SIZE; i++)
899  {
900  //Read current entry
901  error = ksz8794GetStaticFdbEntry(interface, i, &currentEntry);
902 
903  //Valid entry?
904  if(!error)
905  {
906  //Check whether the table already contains the specified MAC address
907  if(macCompAddr(&currentEntry.macAddr, &entry->macAddr))
908  {
909  j = i;
910  break;
911  }
912  }
913  else
914  {
915  //Keep track of the first free entry
917  {
918  j = i;
919  }
920  }
921  }
922 
923  //Any entry available?
925  {
926  //Format MAC entry
927  newEntry.fid = 0;
928  newEntry.useFid = 0;
929  newEntry.override = entry->override;
930  newEntry.valid = TRUE;
931  newEntry.macAddr = entry->macAddr;
932 
933  //Set the relevant forward ports
934  if(entry->destPorts == SWITCH_CPU_PORT_MASK)
935  {
936  newEntry.forwardPorts = KSZ8794_PORT4_MASK;
937  }
938  else
939  {
940  newEntry.forwardPorts = entry->destPorts & KSZ8794_PORT_MASK;
941  }
942 
943  //Select the static MAC address table
947 
948  //Point to the MAC entry
949  p = (uint8_t *) &newEntry;
950 
951  //Write indirect data registers
952  for(i = 0; i < sizeof(Ksz8794StaticMacEntryW); i++)
953  {
954  ksz8794WriteSwitchReg(interface, KSZ8794_INDIRECT_DATA7 + i, p[i]);
955  }
956 
957  //Setup a write operation
961 
962  //Trigger the write operation
964 
965  //Successful processing
966  error = NO_ERROR;
967  }
968  else
969  {
970  //The static MAC table is full
971  error = ERROR_TABLE_FULL;
972  }
973 
974  //Return status code
975  return error;
976 }
977 
978 
979 /**
980  * @brief Remove an entry from the static MAC table
981  * @param[in] interface Underlying network interface
982  * @param[in] entry Forwarding database entry to remove from the table
983  * @return Error code
984  **/
985 
987  const SwitchFdbEntry *entry)
988 {
989  error_t error;
990  uint_t i;
991  uint_t j;
992  SwitchFdbEntry currentEntry;
993 
994  //Loop through the static MAC table
995  for(j = 0; j < KSZ8794_STATIC_MAC_TABLE_SIZE; j++)
996  {
997  //Read current entry
998  error = ksz8794GetStaticFdbEntry(interface, j, &currentEntry);
999 
1000  //Valid entry?
1001  if(!error)
1002  {
1003  //Check whether the table contains the specified MAC address
1004  if(macCompAddr(&currentEntry.macAddr, &entry->macAddr))
1005  {
1006  break;
1007  }
1008  }
1009  }
1010 
1011  //Any matching entry?
1013  {
1014  //Select the static MAC address table
1018 
1019  //Clear indirect data registers
1020  for(i = 0; i < sizeof(Ksz8794StaticMacEntryW); i++)
1021  {
1022  ksz8794WriteSwitchReg(interface, KSZ8794_INDIRECT_DATA7 + i, 0);
1023  }
1024 
1025  //Setup a write operation
1029 
1030  //Trigger the write operation
1032 
1033  //Successful processing
1034  error = NO_ERROR;
1035  }
1036  else
1037  {
1038  //The static MAC table does not contain the specified address
1039  error = ERROR_NOT_FOUND;
1040  }
1041 
1042  //Return status code
1043  return error;
1044 }
1045 
1046 
1047 /**
1048  * @brief Read an entry from the static MAC table
1049  * @param[in] interface Underlying network interface
1050  * @param[in] index Zero-based index of the entry to read
1051  * @param[out] entry Pointer to the forwarding database entry
1052  * @return Error code
1053  **/
1054 
1056  SwitchFdbEntry *entry)
1057 {
1058  error_t error;
1059  uint_t i;
1060  uint8_t *p;
1061  Ksz8794StaticMacEntryR currentEntry;
1062 
1063  //Check index parameter
1064  if(index < KSZ8794_STATIC_MAC_TABLE_SIZE)
1065  {
1066  //Select the static MAC address table
1070 
1071  //Trigger the read operation
1072  ksz8794WriteSwitchReg(interface, KSZ8794_INDIRECT_CTRL1, index);
1073 
1074  //Point to the MAC entry
1075  p = (uint8_t *) &currentEntry;
1076 
1077  //Read indirect data registers
1078  for(i = 0; i < sizeof(Ksz8794StaticMacEntryR); i++)
1079  {
1080  p[i] = ksz8794ReadSwitchReg(interface, KSZ8794_INDIRECT_DATA7 + i);
1081  }
1082 
1083  //Valid entry?
1084  if(currentEntry.valid)
1085  {
1086  //Copy MAC entry
1087  entry->macAddr = currentEntry.macAddr;
1088  entry->srcPort = 0;
1089  entry->destPorts = currentEntry.forwardPorts & KSZ8794_PORT_MASK;
1090  entry->override = currentEntry.override;
1091 
1092  //Successful processing
1093  error = NO_ERROR;
1094  }
1095  else
1096  {
1097  //The entry is not valid
1098  error = ERROR_INVALID_ENTRY;
1099  }
1100  }
1101  else
1102  {
1103  //The end of the table has been reached
1104  error = ERROR_END_OF_TABLE;
1105  }
1106 
1107  //Return status code
1108  return error;
1109 }
1110 
1111 
1112 /**
1113  * @brief Flush static MAC table
1114  * @param[in] interface Underlying network interface
1115  **/
1116 
1118 {
1119  uint_t i;
1120  uint_t temp;
1121  uint8_t state[5];
1122 
1123  //Loop through the ports
1124  for(i = KSZ8794_PORT1; i <= KSZ8794_PORT4; i++)
1125  {
1126  //Valid port?
1127  if(i != KSZ8794_PORT_RESERVED)
1128  {
1129  //Save the current state of the port
1130  state[i - 1] = ksz8794ReadSwitchReg(interface, KSZ8794_PORTn_CTRL2(i));
1131 
1132  //Turn off learning capability
1134  state[i - 1] | KSZ8794_PORTn_CTRL2_LEARNING_DIS);
1135  }
1136  }
1137 
1138  //All the entries associated with a port that has its learning capability
1139  //being turned off will be flushed
1140  temp = ksz8794ReadSwitchReg(interface, KSZ8794_GLOBAL_CTRL0);
1142  ksz8794WriteSwitchReg(interface, KSZ8794_GLOBAL_CTRL0, temp);
1143 
1144  //Loop through the ports
1145  for(i = KSZ8794_PORT1; i <= KSZ8794_PORT4; i++)
1146  {
1147  //Valid port?
1148  if(i != KSZ8794_PORT_RESERVED)
1149  {
1150  //Restore the original state of the port
1151  ksz8794WriteSwitchReg(interface, KSZ8794_PORTn_CTRL2(i), state[i - 1]);
1152  }
1153  }
1154 }
1155 
1156 
1157 /**
1158  * @brief Read an entry from the dynamic MAC table
1159  * @param[in] interface Underlying network interface
1160  * @param[in] index Zero-based index of the entry to read
1161  * @param[out] entry Pointer to the forwarding database entry
1162  * @return Error code
1163  **/
1164 
1166  SwitchFdbEntry *entry)
1167 {
1168  error_t error;
1169  uint_t i;
1170  uint_t n;
1171  uint8_t *p;
1172  Ksz8794DynamicMacEntry currentEntry;
1173 
1174  //Check index parameter
1175  if(index < KSZ8794_DYNAMIC_MAC_TABLE_SIZE)
1176  {
1177  //Read the MAC entry at the specified index
1178  do
1179  {
1180  //Select the dynamic MAC address table
1185 
1186  //Trigger the read operation
1187  ksz8794WriteSwitchReg(interface, KSZ8794_INDIRECT_CTRL1, LSB(index));
1188 
1189  //Point to the MAC entry
1190  p = (uint8_t *) &currentEntry;
1191 
1192  //Read indirect data registers
1193  for(i = 0; i < sizeof(Ksz8794DynamicMacEntry); i++)
1194  {
1195  p[i] = ksz8794ReadSwitchReg(interface, KSZ8794_INDIRECT_DATA8 + i);
1196  }
1197 
1198  //Retry until the entry is ready
1199  } while(currentEntry.dataNotReady);
1200 
1201  //Check whether there are valid entries in the table
1202  if(!currentEntry.macEmpty)
1203  {
1204  //Retrieve the number of valid entries
1205  n = ((currentEntry.numValidEntriesH << 3) |
1206  currentEntry.numValidEntriesL) + 1;
1207  }
1208  else
1209  {
1210  //The table is empty
1211  n = 0;
1212  }
1213 
1214  //Valid entry?
1215  if(index < n)
1216  {
1217  //Copy MAC entry
1218  entry->macAddr = currentEntry.macAddr;
1219  entry->srcPort = currentEntry.sourcePort + 1;
1220  entry->destPorts = 0;
1221  entry->override = FALSE;
1222 
1223  //Successful processing
1224  error = NO_ERROR;
1225  }
1226  else
1227  {
1228  //The end of the table has been reached
1229  error = ERROR_END_OF_TABLE;
1230  }
1231  }
1232  else
1233  {
1234  //The end of the table has been reached
1235  error = ERROR_END_OF_TABLE;
1236  }
1237 
1238  //Return status code
1239  return error;
1240 }
1241 
1242 
1243 /**
1244  * @brief Flush dynamic MAC table
1245  * @param[in] interface Underlying network interface
1246  * @param[in] port Port number
1247  **/
1248 
1250 {
1251  uint_t i;
1252  uint_t temp;
1253  uint8_t state[5];
1254 
1255  //Loop through the ports
1256  for(i = KSZ8794_PORT1; i <= KSZ8794_PORT4; i++)
1257  {
1258  //Valid port?
1259  if(i != KSZ8794_PORT_RESERVED)
1260  {
1261  //Matching port number?
1262  if(i == port || port == 0)
1263  {
1264  //Save the current state of the port
1265  state[i - 1] = ksz8794ReadSwitchReg(interface,
1266  KSZ8794_PORTn_CTRL2(i));
1267 
1268  //Turn off learning capability
1270  state[i - 1] | KSZ8794_PORTn_CTRL2_LEARNING_DIS);
1271  }
1272  }
1273  }
1274 
1275  //All the entries associated with a port that has its learning capability
1276  //being turned off will be flushed
1277  temp = ksz8794ReadSwitchReg(interface, KSZ8794_GLOBAL_CTRL0);
1279  ksz8794WriteSwitchReg(interface, KSZ8794_GLOBAL_CTRL0, temp);
1280 
1281  //Loop through the ports
1282  for(i = KSZ8794_PORT1; i <= KSZ8794_PORT4; i++)
1283  {
1284  //Valid port?
1285  if(i != KSZ8794_PORT_RESERVED)
1286  {
1287  //Matching port number?
1288  if(i == port || port == 0)
1289  {
1290  //Restore the original state of the port
1292  state[i - 1]);
1293  }
1294  }
1295  }
1296 }
1297 
1298 
1299 /**
1300  * @brief Write PHY register
1301  * @param[in] interface Underlying network interface
1302  * @param[in] port Port number
1303  * @param[in] address PHY register address
1304  * @param[in] data Register value
1305  **/
1306 
1307 void ksz8794WritePhyReg(NetInterface *interface, uint8_t port,
1308  uint8_t address, uint16_t data)
1309 {
1310  //Write the specified PHY register
1311  if(interface->smiDriver != NULL)
1312  {
1313  interface->smiDriver->writePhyReg(SMI_OPCODE_WRITE, port, address, data);
1314  }
1315  else
1316  {
1317  interface->nicDriver->writePhyReg(SMI_OPCODE_WRITE, port, address, data);
1318  }
1319 }
1320 
1321 
1322 /**
1323  * @brief Read PHY register
1324  * @param[in] interface Underlying network interface
1325  * @param[in] port Port number
1326  * @param[in] address PHY register address
1327  * @return Register value
1328  **/
1329 
1330 uint16_t ksz8794ReadPhyReg(NetInterface *interface, uint8_t port,
1331  uint8_t address)
1332 {
1333  uint16_t data;
1334 
1335  //Read the specified PHY register
1336  if(interface->smiDriver != NULL)
1337  {
1338  data = interface->smiDriver->readPhyReg(SMI_OPCODE_READ, port, address);
1339  }
1340  else
1341  {
1342  data = interface->nicDriver->readPhyReg(SMI_OPCODE_READ, port, address);
1343  }
1344 
1345  //Return the value of the PHY register
1346  return data;
1347 }
1348 
1349 
1350 /**
1351  * @brief Dump PHY registers for debugging purpose
1352  * @param[in] interface Underlying network interface
1353  * @param[in] port Port number
1354  **/
1355 
1356 void ksz8794DumpPhyReg(NetInterface *interface, uint8_t port)
1357 {
1358  uint8_t i;
1359 
1360  //Loop through PHY registers
1361  for(i = 0; i < 32; i++)
1362  {
1363  //Display current PHY register
1364  TRACE_DEBUG("%02" PRIu8 ": 0x%04" PRIX16 "\r\n", i,
1365  ksz8794ReadPhyReg(interface, port, i));
1366  }
1367 
1368  //Terminate with a line feed
1369  TRACE_DEBUG("\r\n");
1370 }
1371 
1372 
1373 /**
1374  * @brief Write switch register
1375  * @param[in] interface Underlying network interface
1376  * @param[in] address Switch register address
1377  * @param[in] data Register value
1378  **/
1379 
1380 void ksz8794WriteSwitchReg(NetInterface *interface, uint16_t address,
1381  uint8_t data)
1382 {
1383  uint16_t command;
1384 
1385  //SPI slave mode?
1386  if(interface->spiDriver != NULL)
1387  {
1388  //Set up a write operation
1389  command = KSZ8794_SPI_CMD_WRITE;
1390  //Set register address
1391  command |= (address << 1) & KSZ8794_SPI_CMD_ADDR;
1392 
1393  //Pull the CS pin low
1394  interface->spiDriver->assertCs();
1395 
1396  //Write 16-bit command
1397  interface->spiDriver->transfer(MSB(command));
1398  interface->spiDriver->transfer(LSB(command));
1399 
1400  //Write data
1401  interface->spiDriver->transfer(data);
1402 
1403  //Terminate the operation by raising the CS pin
1404  interface->spiDriver->deassertCs();
1405  }
1406  else
1407  {
1408  //The MDC/MDIO interface does not have access to all the configuration
1409  //registers. It can only access the standard MIIM registers
1410  }
1411 }
1412 
1413 
1414 /**
1415  * @brief Read switch register
1416  * @param[in] interface Underlying network interface
1417  * @param[in] address Switch register address
1418  * @return Register value
1419  **/
1420 
1421 uint8_t ksz8794ReadSwitchReg(NetInterface *interface, uint16_t address)
1422 {
1423  uint8_t data;
1424  uint16_t command;
1425 
1426  //SPI slave mode?
1427  if(interface->spiDriver != NULL)
1428  {
1429  //Set up a read operation
1430  command = KSZ8794_SPI_CMD_READ;
1431  //Set register address
1432  command |= (address << 1) & KSZ8794_SPI_CMD_ADDR;
1433 
1434  //Pull the CS pin low
1435  interface->spiDriver->assertCs();
1436 
1437  //Write 16-bit command
1438  interface->spiDriver->transfer(MSB(command));
1439  interface->spiDriver->transfer(LSB(command));
1440 
1441  //Read data
1442  data = interface->spiDriver->transfer(0xFF);
1443 
1444  //Terminate the operation by raising the CS pin
1445  interface->spiDriver->deassertCs();
1446  }
1447  else
1448  {
1449  //The MDC/MDIO interface does not have access to all the configuration
1450  //registers. It can only access the standard MIIM registers
1451  data = 0;
1452  }
1453 
1454  //Return register value
1455  return data;
1456 }
1457 
1458 
1459 /**
1460  * @brief Dump switch registers for debugging purpose
1461  * @param[in] interface Underlying network interface
1462  **/
1463 
1465 {
1466  uint16_t i;
1467 
1468  //Loop through switch registers
1469  for(i = 0; i < 256; i++)
1470  {
1471  //Display current switch register
1472  TRACE_DEBUG("0x%02" PRIX16 " (%02" PRIu16 ") : 0x%02" PRIX8 "\r\n",
1473  i, i, ksz8794ReadSwitchReg(interface, i));
1474  }
1475 
1476  //Terminate with a line feed
1477  TRACE_DEBUG("\r\n");
1478 }
void nicNotifyLinkChange(NetInterface *interface)
Process link state change notification.
Definition: nic.c:532
uint8_t length
Definition: coap_common.h:190
#define KSZ8794_GLOBAL_CTRL4_SW4_HALF_DUPLEX_MODE
uint8_t useFid
int bool_t
Definition: compiler_port.h:49
#define KSZ8794_STATIC_MAC_TABLE_SIZE
uint32_t destPorts
Definition: nic.h:149
#define netEvent
Definition: net_legacy.h:267
error_t ksz8794TagFrame(NetInterface *interface, NetBuffer *buffer, size_t *offset, NetTxAncillary *ancillary)
Add tail tag to Ethernet frame.
#define KSZ8794_PORT4_IF_CTRL6_IF_MODE_SEL
uint8_t data[]
Definition: ethernet.h:209
uint32_t ksz8794GetLinkSpeed(NetInterface *interface, uint8_t port)
Get link speed.
error_t ksz8794Init(NetInterface *interface)
KSZ8794 Ethernet switch initialization.
error_t ksz8794UntagFrame(NetInterface *interface, uint8_t **frame, size_t *length, NetRxAncillary *ancillary)
Decode tail tag from incoming Ethernet frame.
#define KSZ8794_SPI_CMD_READ
uint8_t p
Definition: ndp.h:298
#define KSZ8794_GLOBAL_CTRL0_FLUSH_DYNAMIC_MAC_TABLE
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:88
#define TRUE
Definition: os_port.h:50
#define KSZ8794_PORTn_STAT2_LINK_GOOD
#define KSZ8794_PORTn_STAT1_OP_SPEED
#define KSZ8794_TAIL_TAG_PORT_SEL
#define NET_INTERFACE_COUNT
Definition: net.h:110
#define KSZ8794_PORT_RESERVED
uint8_t fid
#define KSZ8794_PORT4_MASK
Dynamic MAC table entry.
#define KSZ8794_PORTn_CTRL2_LEARNING_DIS
uint16_t ksz8794ReadPhyReg(NetInterface *interface, uint8_t port, uint8_t address)
Read PHY register.
MacAddr macAddr
error_t ksz8794DeleteStaticFdbEntry(NetInterface *interface, const SwitchFdbEntry *entry)
Remove an entry from the static MAC table.
#define KSZ8794_CHIP_ID0
#define KSZ8794_INDIRECT_CTRL0_ADDR_9_8
#define SMI_OPCODE_WRITE
Definition: nic.h:65
#define KSZ8794_INDIRECT_CTRL1
#define KSZ8794_TAIL_TAG_SRC_PORT
#define KSZ8794_INDIRECT_CTRL0_WRITE
uint8_t override
uint8_t sourcePort
MacAddr macAddr
#define FALSE
Definition: os_port.h:46
char_t type
#define KSZ8794_GLOBAL_CTRL0_FLUSH_STATIC_MAC_TABLE
error_t
Error codes.
Definition: error.h:42
#define KSZ8794_PORT4_IF_CTRL6_IF_MODE_SEL_RGMII
#define netInterface
Definition: net_legacy.h:273
KSZ8794 4-port Ethernet switch driver.
#define KSZ8794_TAIL_TAG_DEST_PORT2
#define KSZ8794_INDIRECT_CTRL0
#define KSZ8794_GLOBAL_CTRL4
#define KSZ8794_PORTn_CTRL2_RECEIVE_EN
#define KSZ8794_PORT4
#define KSZ8794_CHIP_ID0_FAMILY_ID_DEFAULT
uint8_t value[]
Definition: tcp.h:332
void ksz8794DumpPhyReg(NetInterface *interface, uint8_t port)
Dump PHY registers for debugging purpose.
Static MAC table entry (read operation)
#define KSZ8794_PORT_MASK
uint8_t forwardPorts
#define KSZ8794_PORT3
void ksz8794EventHandler(NetInterface *interface)
KSZ8794 event handler.
#define KSZ8794_BMSR
uint8_t numValidEntriesH
#define KSZ8794_GLOBAL_CTRL10
#define NetRxAncillary
Definition: net_misc.h:40
MacAddr macAddr
#define NetInterface
Definition: net.h:36
#define KSZ8794_TAIL_TAG_NORMAL_ADDR_LOOKUP
Static MAC table entry (write operation)
const uint8_t ksz8794IngressTailTag[4]
Tail tag rules (host to KSZ8794)
#define KSZ8794_INDIRECT_CTRL0_READ
error_t ethPadFrame(NetBuffer *buffer, size_t *length)
Ethernet frame padding.
#define KSZ8794_GLOBAL_CTRL0
SwitchPortState ksz8794GetPortState(NetInterface *interface, uint8_t port)
Get port state.
#define NetTxAncillary
Definition: net_misc.h:36
#define MSB(x)
Definition: os_port.h:58
#define SMI_OPCODE_READ
Definition: nic.h:66
SwitchPortState
Switch port state.
Definition: nic.h:130
void ksz8794FlushStaticFdbTable(NetInterface *interface)
Flush static MAC table.
#define TRACE_INFO(...)
Definition: debug.h:95
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:54
#define KSZ8794_SPI_CMD_WRITE
#define KSZ8794_INDIRECT_BYTE
void ksz8794SetPortState(NetInterface *interface, uint8_t port, SwitchPortState state)
Set port state.
uint8_t dataNotReady
uint8_t valid
#define KSZ8794_INDIRECT_DATA7
NicDuplexMode ksz8794GetDuplexMode(NetInterface *interface, uint8_t port)
Get duplex mode.
#define KSZ8794_TAIL_TAG_DEST_PORT1
void ksz8794DisableIrq(NetInterface *interface)
Disable interrupts.
uint16_t port
Definition: dns_common.h:223
#define TRACE_DEBUG(...)
Definition: debug.h:107
uint8_t numValidEntriesL
error_t ksz8794GetStaticFdbEntry(NetInterface *interface, uint_t index, SwitchFdbEntry *entry)
Read an entry from the static MAC table.
__start_packed struct @7 EthHeader
Ethernet frame header.
error_t ksz8794GetDynamicFdbEntry(NetInterface *interface, uint_t index, SwitchFdbEntry *entry)
Read an entry from the dynamic MAC table.
#define KSZ8794_GLOBAL_CTRL4_SW4_SPEED
Ethernet switch driver.
Definition: nic.h:306
error_t ksz8794AddStaticFdbEntry(NetInterface *interface, const SwitchFdbEntry *entry)
Add a new entry to the static MAC table.
uint8_t n
void ksz8794FlushDynamicFdbTable(NetInterface *interface, uint8_t port)
Flush dynamic MAC table.
error_t netBufferAppend(NetBuffer *dest, const void *src, size_t length)
Append data a multi-part buffer.
Definition: net_mem.c:586
#define KSZ8794_PORTn_STAT1_OP_DUPLEX
#define KSZ8794_BMSR_LINK_STATUS
NicDuplexMode
Duplex mode.
Definition: nic.h:118
MacAddr macAddr
Definition: nic.h:147
void ksz8794WritePhyReg(NetInterface *interface, uint8_t port, uint8_t address, uint16_t data)
Write PHY register.
uint8_t forwardPorts
uint8_t srcPort
Definition: nic.h:148
#define KSZ8794_PORT4_IF_CTRL6
#define KSZ8794_PORTn_STAT1(port)
#define KSZ8794_PORTn_STAT2(port)
void ksz8794WriteSwitchReg(NetInterface *interface, uint16_t address, uint8_t data)
Write switch register.
uint8_t macEmpty
#define macCompAddr(macAddr1, macAddr2)
Definition: ethernet.h:121
#define KSZ8794_GLOBAL_CTRL10_TAIL_TAG_EN
#define KSZ8794_INDIRECT_CTRL0_TABLE_SEL_DYNAMIC_MAC
#define KSZ8794_PORT1
bool_t ksz8794GetLinkState(NetInterface *interface, uint8_t port)
Get link state.
Ipv6Addr address
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
void ksz8794DumpSwitchReg(NetInterface *interface)
Dump switch registers for debugging purpose.
#define KSZ8794_PORTn_CTRL2_TRANSMIT_EN
#define KSZ8794_INDIRECT_DATA8
#define SWITCH_CPU_PORT_MASK
Definition: nic.h:59
#define KSZ8794_PORTn_CTRL2(port)
void ksz8794EnableRsvdMcastTable(NetInterface *interface, bool_t enable)
Enable reserved multicast table.
void ksz8794Tick(NetInterface *interface)
KSZ8794 timer handler.
void ksz8794EnableIrq(NetInterface *interface)
Enable interrupts.
unsigned int uint_t
Definition: compiler_port.h:45
#define KSZ8794_DYNAMIC_MAC_TABLE_SIZE
TCP/IP stack core.
#define KSZ8794_SPI_CMD_ADDR
uint8_t valid
#define KSZ8794_PORT4_IF_CTRL6_IS_1GBPS
void ksz8794SetAgingTime(NetInterface *interface, uint32_t agingTime)
Set aging time for dynamic filtering entries.
const SwitchDriver ksz8794SwitchDriver
KSZ8794 Ethernet switch driver.
Helper functions for Ethernet.
uint8_t ksz8794ReadSwitchReg(NetInterface *interface, uint16_t address)
Read switch register.
Success.
Definition: error.h:44
bool_t override
Definition: nic.h:150
Debugging facilities.
#define KSZ8794_INDIRECT_CTRL0_TABLE_SEL_STATIC_MAC
Forwarding database entry.
Definition: nic.h:145
uint8_t override
#define KSZ8794_TAIL_TAG_DEST_PORT3