ksz8567_driver.c
Go to the documentation of this file.
1 /**
2  * @file ksz8567_driver.c
3  * @brief KSZ8567 7-port Ethernet switch driver
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2010-2024 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneTCP Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.4.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL NIC_TRACE_LEVEL
33 
34 //Dependencies
35 #include "core/net.h"
36 #include "core/ethernet_misc.h"
38 #include "debug.h"
39 
40 
41 /**
42  * @brief KSZ8567 Ethernet switch driver
43  **/
44 
46 {
70 };
71 
72 
73 /**
74  * @brief Tail tag rules (host to KSZ8567)
75  **/
76 
77 const uint16_t ksz8567IngressTailTag[6] =
78 {
85 };
86 
87 
88 /**
89  * @brief KSZ8567 Ethernet switch initialization
90  * @param[in] interface Underlying network interface
91  * @return Error code
92  **/
93 
95 {
96  uint_t port;
97  uint8_t temp;
98 
99  //Debug message
100  TRACE_INFO("Initializing KSZ8567...\r\n");
101 
102  //SPI slave mode?
103  if(interface->spiDriver != NULL)
104  {
105  //Initialize SPI interface
106  interface->spiDriver->init();
107 
108  //Wait for the serial interface to be ready
109  do
110  {
111  //Read CHIP_ID1 register
112  temp = ksz8567ReadSwitchReg8(interface, KSZ8567_CHIP_ID1);
113 
114  //The returned data is invalid until the serial interface is ready
115  } while(temp != KSZ8567_CHIP_ID1_DEFAULT);
116 
117 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
118  //Enable tail tag feature
122 
123  //Disable frame length check (silicon errata workaround 12)
127 #else
128  //Disable tail tag feature
132 
133  //Enable frame length check
137 #endif
138 
139  //Loop through the ports
141  {
142 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
143  //Port separation mode?
144  if(interface->port != 0)
145  {
146  //Disable packet transmission and address learning
148  }
149  else
150 #endif
151  {
152  //Enable transmission, reception and address learning
154  }
155  }
156 
157  //Restore default age count
161 
162  //Restore default age period
165 
166  //Add internal delay to ingress and egress RGMII clocks
171 
172  //Start switch operation
175  }
176  else if(interface->smiDriver != NULL)
177  {
178  //Initialize serial management interface
179  interface->smiDriver->init();
180  }
181  else
182  {
183  //Just for sanity
184  }
185 
186  //Loop through the ports
188  {
189  //Improve PHY receive performance (silicon errata workaround 1)
190  ksz8567WriteMmdReg(interface, port, 0x01, 0x6F, 0xDD0B);
191  ksz8567WriteMmdReg(interface, port, 0x01, 0x8F, 0x6032);
192  ksz8567WriteMmdReg(interface, port, 0x01, 0x9D, 0x248C);
193  ksz8567WriteMmdReg(interface, port, 0x01, 0x75, 0x0060);
194  ksz8567WriteMmdReg(interface, port, 0x01, 0xD3, 0x7777);
195  ksz8567WriteMmdReg(interface, port, 0x1C, 0x06, 0x3008);
196  ksz8567WriteMmdReg(interface, port, 0x1C, 0x08, 0x2001);
197 
198  //Improve transmit waveform amplitude (silicon errata workaround 2)
199  ksz8567WriteMmdReg(interface, port, 0x1C, 0x04, 0x00D0);
200 
201  //EEE must be manually disabled (silicon errata workaround 4)
203 
204  //Adjust power supply settings (silicon errata workaround 7)
205  ksz8567WriteMmdReg(interface, port, 0x1C, 0x13, 0x6EFF);
206  ksz8567WriteMmdReg(interface, port, 0x1C, 0x14, 0xE6FF);
207  ksz8567WriteMmdReg(interface, port, 0x1C, 0x15, 0x6EFF);
208  ksz8567WriteMmdReg(interface, port, 0x1C, 0x16, 0xE6FF);
209  ksz8567WriteMmdReg(interface, port, 0x1C, 0x17, 0x00FF);
210  ksz8567WriteMmdReg(interface, port, 0x1C, 0x18, 0x43FF);
211  ksz8567WriteMmdReg(interface, port, 0x1C, 0x19, 0xC3FF);
212  ksz8567WriteMmdReg(interface, port, 0x1C, 0x1A, 0x6FFF);
213  ksz8567WriteMmdReg(interface, port, 0x1C, 0x1B, 0x07FF);
214  ksz8567WriteMmdReg(interface, port, 0x1C, 0x1C, 0x0FFF);
215  ksz8567WriteMmdReg(interface, port, 0x1C, 0x1D, 0xE7FF);
216  ksz8567WriteMmdReg(interface, port, 0x1C, 0x1E, 0xEFFF);
217  ksz8567WriteMmdReg(interface, port, 0x1C, 0x20, 0xEEEE);
218 
219  //Select single-LED mode
223 
224  //Implement workaround for single-LED mode
225  ksz8567WritePhyReg(interface, port, 0x1E, 0xFA00);
226 
227  //Debug message
228  TRACE_DEBUG("Port %u:\r\n", port);
229  //Dump PHY registers for debugging purpose
230  ksz8567DumpPhyReg(interface, port);
231  }
232 
233  //Perform custom configuration
234  ksz8567InitHook(interface);
235 
236  //Force the TCP/IP stack to poll the link state at startup
237  interface->phyEvent = TRUE;
238  //Notify the TCP/IP stack of the event
240 
241  //Successful initialization
242  return NO_ERROR;
243 }
244 
245 
246 /**
247  * @brief KSZ8567 custom configuration
248  * @param[in] interface Underlying network interface
249  **/
250 
251 __weak_func void ksz8567InitHook(NetInterface *interface)
252 {
253 }
254 
255 
256 /**
257  * @brief KSZ8567 timer handler
258  * @param[in] interface Underlying network interface
259  **/
260 
261 void ksz8567Tick(NetInterface *interface)
262 {
263  uint_t port;
264  bool_t linkState;
265 
266 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
267  //Port separation mode?
268  if(interface->port != 0)
269  {
270  uint_t i;
271  NetInterface *virtualInterface;
272 
273  //Loop through network interfaces
274  for(i = 0; i < NET_INTERFACE_COUNT; i++)
275  {
276  //Point to the current interface
277  virtualInterface = &netInterface[i];
278 
279  //Check whether the current virtual interface is attached to the
280  //physical interface
281  if(virtualInterface == interface ||
282  virtualInterface->parent == interface)
283  {
284  //Retrieve current link state
285  linkState = ksz8567GetLinkState(interface, virtualInterface->port);
286 
287  //Link up or link down event?
288  if(linkState != virtualInterface->linkState)
289  {
290  //Set event flag
291  interface->phyEvent = TRUE;
292  //Notify the TCP/IP stack of the event
294  }
295  }
296  }
297  }
298  else
299 #endif
300  {
301  //Initialize link state
302  linkState = FALSE;
303 
304  //Loop through the ports
306  {
307  //Retrieve current link state
308  if(ksz8567GetLinkState(interface, port))
309  {
310  linkState = TRUE;
311  }
312  }
313 
314  //Link up or link down event?
315  if(linkState != interface->linkState)
316  {
317  //Set event flag
318  interface->phyEvent = TRUE;
319  //Notify the TCP/IP stack of the event
321  }
322  }
323 }
324 
325 
326 /**
327  * @brief Enable interrupts
328  * @param[in] interface Underlying network interface
329  **/
330 
332 {
333 }
334 
335 
336 /**
337  * @brief Disable interrupts
338  * @param[in] interface Underlying network interface
339  **/
340 
342 {
343 }
344 
345 
346 /**
347  * @brief KSZ8567 event handler
348  * @param[in] interface Underlying network interface
349  **/
350 
352 {
353  uint_t port;
354  bool_t linkState;
355 
356 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
357  //Port separation mode?
358  if(interface->port != 0)
359  {
360  uint_t i;
361  NetInterface *virtualInterface;
362 
363  //Loop through network interfaces
364  for(i = 0; i < NET_INTERFACE_COUNT; i++)
365  {
366  //Point to the current interface
367  virtualInterface = &netInterface[i];
368 
369  //Check whether the current virtual interface is attached to the
370  //physical interface
371  if(virtualInterface == interface ||
372  virtualInterface->parent == interface)
373  {
374  //Get the port number associated with the current interface
375  port = virtualInterface->port;
376 
377  //Valid port?
378  if(port >= KSZ8567_PORT1 && port <= KSZ8567_PORT5)
379  {
380  //Retrieve current link state
381  linkState = ksz8567GetLinkState(interface, port);
382 
383  //Link up event?
384  if(linkState && !virtualInterface->linkState)
385  {
386  //Retrieve host interface speed
387  interface->linkSpeed = ksz8567GetLinkSpeed(interface,
388  KSZ8567_PORT6);
389 
390  //Retrieve host interface duplex mode
391  interface->duplexMode = ksz8567GetDuplexMode(interface,
392  KSZ8567_PORT6);
393 
394  //Adjust MAC configuration parameters for proper operation
395  interface->nicDriver->updateMacConfig(interface);
396 
397  //Check current speed
398  virtualInterface->linkSpeed = ksz8567GetLinkSpeed(interface,
399  port);
400 
401  //Check current duplex mode
402  virtualInterface->duplexMode = ksz8567GetDuplexMode(interface,
403  port);
404 
405  //Update link state
406  virtualInterface->linkState = TRUE;
407 
408  //Process link state change event
409  nicNotifyLinkChange(virtualInterface);
410  }
411  //Link down event
412  else if(!linkState && virtualInterface->linkState)
413  {
414  //Update link state
415  virtualInterface->linkState = FALSE;
416 
417  //Process link state change event
418  nicNotifyLinkChange(virtualInterface);
419  }
420  }
421  }
422  }
423  }
424  else
425 #endif
426  {
427  //Initialize link state
428  linkState = FALSE;
429 
430  //Loop through the ports
432  {
433  //Retrieve current link state
434  if(ksz8567GetLinkState(interface, port))
435  {
436  linkState = TRUE;
437  }
438  }
439 
440  //Link up event?
441  if(linkState)
442  {
443  //Retrieve host interface speed
444  interface->linkSpeed = ksz8567GetLinkSpeed(interface, KSZ8567_PORT6);
445  //Retrieve host interface duplex mode
446  interface->duplexMode = ksz8567GetDuplexMode(interface, KSZ8567_PORT6);
447 
448  //Adjust MAC configuration parameters for proper operation
449  interface->nicDriver->updateMacConfig(interface);
450 
451  //Update link state
452  interface->linkState = TRUE;
453  }
454  else
455  {
456  //Update link state
457  interface->linkState = FALSE;
458  }
459 
460  //Process link state change event
461  nicNotifyLinkChange(interface);
462  }
463 }
464 
465 
466 /**
467  * @brief Add tail tag to Ethernet frame
468  * @param[in] interface Underlying network interface
469  * @param[in] buffer Multi-part buffer containing the payload
470  * @param[in,out] offset Offset to the first payload byte
471  * @param[in] ancillary Additional options passed to the stack along with
472  * the packet
473  * @return Error code
474  **/
475 
477  size_t *offset, NetTxAncillary *ancillary)
478 {
479  error_t error;
480 
481  //Initialize status code
482  error = NO_ERROR;
483 
484 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
485  //SPI slave mode?
486  if(interface->spiDriver != NULL)
487  {
488  //Valid port?
489  if(ancillary->port <= KSZ8567_PORT5)
490  {
491  size_t length;
492  const uint16_t *tailTag;
493 
494  //The two-byte tail tagging is used to indicate the destination port
495  tailTag = &ksz8567IngressTailTag[ancillary->port];
496 
497  //Retrieve the length of the Ethernet frame
498  length = netBufferGetLength(buffer) - *offset;
499 
500  //The host controller should manually add padding to the packet before
501  //inserting the tail tag
502  error = ethPadFrame(buffer, &length);
503 
504  //Check status code
505  if(!error)
506  {
507  //The tail tag is inserted at the end of the packet, just before
508  //the CRC
509  error = netBufferAppend(buffer, tailTag, sizeof(uint16_t));
510  }
511  }
512  else
513  {
514  //The port number is not valid
515  error = ERROR_INVALID_PORT;
516  }
517  }
518 #endif
519 
520  //Return status code
521  return error;
522 }
523 
524 
525 /**
526  * @brief Decode tail tag from incoming Ethernet frame
527  * @param[in] interface Underlying network interface
528  * @param[in,out] frame Pointer to the received Ethernet frame
529  * @param[in,out] length Length of the frame, in bytes
530  * @param[in,out] ancillary Additional options passed to the stack along with
531  * the packet
532  * @return Error code
533  **/
534 
535 error_t ksz8567UntagFrame(NetInterface *interface, uint8_t **frame,
536  size_t *length, NetRxAncillary *ancillary)
537 {
538  error_t error;
539 
540  //Initialize status code
541  error = NO_ERROR;
542 
543 #if (ETH_PORT_TAGGING_SUPPORT == ENABLED)
544  //SPI slave mode?
545  if(interface->spiDriver != NULL)
546  {
547  //Valid Ethernet frame received?
548  if(*length >= (sizeof(EthHeader) + sizeof(uint8_t)))
549  {
550  uint8_t *tailTag;
551 
552  //The tail tag is inserted at the end of the packet, just before
553  //the CRC
554  tailTag = *frame + *length - sizeof(uint8_t);
555 
556  //The one byte tail tagging is used to indicate the source port
557  ancillary->port = (*tailTag & KSZ8567_TAIL_TAG_SRC_PORT) + 1;
558 
559  //Strip tail tag from Ethernet frame
560  *length -= sizeof(uint8_t);
561  }
562  else
563  {
564  //Drop the received frame
565  error = ERROR_INVALID_LENGTH;
566  }
567  }
568  else
569  {
570  //Tail tagging mode cannot be enabled through MDC/MDIO interface
571  ancillary->port = 0;
572  }
573 #endif
574 
575  //Return status code
576  return error;
577 }
578 
579 
580 /**
581  * @brief Get link state
582  * @param[in] interface Underlying network interface
583  * @param[in] port Port number
584  * @return Link state
585  **/
586 
588 {
589  uint16_t value;
590  bool_t linkState;
591 
592  //Check port number
593  if(port >= KSZ8567_PORT1 && port <= KSZ8567_PORT5)
594  {
595  //Any link failure condition is latched in the BMSR register. Reading
596  //the register twice will always return the actual link status
597  value = ksz8567ReadPhyReg(interface, port, KSZ8567_BMSR);
598  value = ksz8567ReadPhyReg(interface, port, KSZ8567_BMSR);
599 
600  //Retrieve current link state
601  linkState = (value & KSZ8567_BMSR_LINK_STATUS) ? TRUE : FALSE;
602  }
603  else
604  {
605  //The specified port number is not valid
606  linkState = FALSE;
607  }
608 
609  //Return link status
610  return linkState;
611 }
612 
613 
614 /**
615  * @brief Get link speed
616  * @param[in] interface Underlying network interface
617  * @param[in] port Port number
618  * @return Link speed
619  **/
620 
621 uint32_t ksz8567GetLinkSpeed(NetInterface *interface, uint8_t port)
622 {
623  uint8_t type;
624  uint16_t value;
625  uint32_t linkSpeed;
626 
627  //Check port number
628  if(port >= KSZ8567_PORT1 && port <= KSZ8567_PORT5)
629  {
630  //Read PHY control register
632 
633  //Retrieve current link speed
635  {
636  //100BASE-TX
637  linkSpeed = NIC_LINK_SPEED_100MBPS;
638  }
639  else if((value & KSZ8567_PHYCON_SPEED_10BT) != 0)
640  {
641  //10BASE-T
642  linkSpeed = NIC_LINK_SPEED_10MBPS;
643  }
644  else
645  {
646  //The link speed is not valid
647  linkSpeed = NIC_LINK_SPEED_UNKNOWN;
648  }
649  }
650  else if(port == KSZ8567_PORT6)
651  {
652  //SPI slave mode?
653  if(interface->spiDriver != NULL)
654  {
655  //Read port 6 XMII control 1 register
657 
658  //Retrieve host interface type
660 
661  //Gigabit interface?
664  {
665  //1000 Mb/s mode
666  linkSpeed = NIC_LINK_SPEED_1GBPS;
667  }
668  else
669  {
670  //Read port 6 XMII control 0 register
672 
673  //Retrieve host interface speed
675  {
676  //100 Mb/s mode
677  linkSpeed = NIC_LINK_SPEED_100MBPS;
678  }
679  else
680  {
681  //10 Mb/s mode
682  linkSpeed = NIC_LINK_SPEED_10MBPS;
683  }
684  }
685  }
686  else
687  {
688  //The MDC/MDIO interface does not have access to all the configuration
689  //registers. It can only access the standard MIIM registers
690  linkSpeed = NIC_LINK_SPEED_100MBPS;
691  }
692  }
693  else
694  {
695  //The specified port number is not valid
696  linkSpeed = NIC_LINK_SPEED_UNKNOWN;
697  }
698 
699  //Return link status
700  return linkSpeed;
701 }
702 
703 
704 /**
705  * @brief Get duplex mode
706  * @param[in] interface Underlying network interface
707  * @param[in] port Port number
708  * @return Duplex mode
709  **/
710 
712 {
713  uint16_t value;
714  NicDuplexMode duplexMode;
715 
716  //Check port number
717  if(port >= KSZ8567_PORT1 && port <= KSZ8567_PORT5)
718  {
719  //Read PHY control register
721 
722  //Retrieve current duplex mode
724  {
725  duplexMode = NIC_FULL_DUPLEX_MODE;
726  }
727  else
728  {
729  duplexMode = NIC_HALF_DUPLEX_MODE;
730  }
731  }
732  else if(port == KSZ8567_PORT6)
733  {
734  //SPI slave mode?
735  if(interface->spiDriver != NULL)
736  {
737  //Read port 6 XMII control 0 register
739 
740  //Retrieve host interface duplex mode
742  {
743  duplexMode = NIC_FULL_DUPLEX_MODE;
744  }
745  else
746  {
747  duplexMode = NIC_HALF_DUPLEX_MODE;
748  }
749  }
750  else
751  {
752  //The MDC/MDIO interface does not have access to all the configuration
753  //registers. It can only access the standard MIIM registers
754  duplexMode = NIC_FULL_DUPLEX_MODE;
755  }
756  }
757  else
758  {
759  //The specified port number is not valid
760  duplexMode = NIC_UNKNOWN_DUPLEX_MODE;
761  }
762 
763  //Return duplex mode
764  return duplexMode;
765 }
766 
767 
768 /**
769  * @brief Set port state
770  * @param[in] interface Underlying network interface
771  * @param[in] port Port number
772  * @param[in] state Port state
773  **/
774 
775 void ksz8567SetPortState(NetInterface *interface, uint8_t port,
776  SwitchPortState state)
777 {
778  uint8_t temp;
779 
780  //Check port number
781  if(port >= KSZ8567_PORT1 && port <= KSZ8567_PORT5)
782  {
783  //Read MSTP state register
785 
786  //Update port state
787  switch(state)
788  {
789  //Listening state
794  break;
795 
796  //Learning state
801  break;
802 
803  //Forwarding state
808  break;
809 
810  //Disabled state
811  default:
815  break;
816  }
817 
818  //Write the value back to MSTP state register
820  }
821 }
822 
823 
824 /**
825  * @brief Get port state
826  * @param[in] interface Underlying network interface
827  * @param[in] port Port number
828  * @return Port state
829  **/
830 
832 {
833  uint8_t temp;
834  SwitchPortState state;
835 
836  //Check port number
837  if(port >= KSZ8567_PORT1 && port <= KSZ8567_PORT5)
838  {
839  //Read MSTP state register
841 
842  //Check port state
843  if((temp & KSZ8567_PORTn_MSTP_STATE_TRANSMIT_EN) == 0 &&
844  (temp & KSZ8567_PORTn_MSTP_STATE_RECEIVE_EN) == 0 &&
846  {
847  //Disabled state
849  }
850  else if((temp & KSZ8567_PORTn_MSTP_STATE_TRANSMIT_EN) == 0 &&
851  (temp & KSZ8567_PORTn_MSTP_STATE_RECEIVE_EN) != 0 &&
853  {
854  //Listening state
856  }
857  else if((temp & KSZ8567_PORTn_MSTP_STATE_TRANSMIT_EN) == 0 &&
858  (temp & KSZ8567_PORTn_MSTP_STATE_RECEIVE_EN) == 0 &&
860  {
861  //Learning state
863  }
864  else if((temp & KSZ8567_PORTn_MSTP_STATE_TRANSMIT_EN) != 0 &&
865  (temp & KSZ8567_PORTn_MSTP_STATE_RECEIVE_EN) != 0 &&
867  {
868  //Forwarding state
870  }
871  else
872  {
873  //Unknown state
875  }
876  }
877  else
878  {
879  //The specified port number is not valid
881  }
882 
883  //Return port state
884  return state;
885 }
886 
887 
888 /**
889  * @brief Set aging time for dynamic filtering entries
890  * @param[in] interface Underlying network interface
891  * @param[in] agingTime Aging time, in seconds
892  **/
893 
894 void ksz8567SetAgingTime(NetInterface *interface, uint32_t agingTime)
895 {
896  //The Age Period in combination with the Age Count field determines the
897  //aging time of dynamic entries in the address lookup table
898  agingTime = (agingTime + 3) / 4;
899 
900  //Limit the range of the parameter
901  agingTime = MIN(agingTime, 255);
902 
903  //Write the value to Switch Lookup Engine Control 3 register
905  (uint8_t) agingTime);
906 }
907 
908 
909 /**
910  * @brief Enable IGMP snooping
911  * @param[in] interface Underlying network interface
912  * @param[in] enable Enable or disable IGMP snooping
913  **/
914 
916 {
917  uint8_t temp;
918 
919  //Read the Global Port Mirroring and Snooping Control register
920  temp = ksz8567ReadSwitchReg8(interface,
922 
923  //Enable or disable IGMP snooping
924  if(enable)
925  {
927  }
928  else
929  {
931  }
932 
933  //Write the value back to Global Port Mirroring and Snooping Control register
935  temp);
936 }
937 
938 
939 /**
940  * @brief Enable MLD snooping
941  * @param[in] interface Underlying network interface
942  * @param[in] enable Enable or disable MLD snooping
943  **/
944 
946 {
947  uint8_t temp;
948 
949  //Read the Global Port Mirroring and Snooping Control register
950  temp = ksz8567ReadSwitchReg8(interface,
952 
953  //Enable or disable MLD snooping
954  if(enable)
955  {
957  }
958  else
959  {
961  }
962 
963  //Write the value back to Global Port Mirroring and Snooping Control register
965  temp);
966 }
967 
968 
969 /**
970  * @brief Enable reserved multicast table
971  * @param[in] interface Underlying network interface
972  * @param[in] enable Enable or disable reserved group addresses
973  **/
974 
976 {
977  uint8_t temp;
978 
979  //Read the Switch Lookup Engine Control 0 register
981 
982  //Enable or disable the reserved multicast table
983  if(enable)
984  {
986  }
987  else
988  {
990  }
991 
992  //Write the value back to Switch Lookup Engine Control 0 register
994 }
995 
996 
997 /**
998  * @brief Add a new entry to the static MAC table
999  * @param[in] interface Underlying network interface
1000  * @param[in] entry Pointer to the forwarding database entry
1001  * @return Error code
1002  **/
1003 
1005  const SwitchFdbEntry *entry)
1006 {
1007  error_t error;
1008  uint_t i;
1009  uint_t j;
1010  uint32_t value;
1011  SwitchFdbEntry currentEntry;
1012 
1013  //Keep track of the first free entry
1015 
1016  //Loop through the static MAC table
1017  for(i = 0; i < KSZ8567_STATIC_MAC_TABLE_SIZE; i++)
1018  {
1019  //Read current entry
1020  error = ksz8567GetStaticFdbEntry(interface, i, &currentEntry);
1021 
1022  //Valid entry?
1023  if(!error)
1024  {
1025  //Check whether the table already contains the specified MAC address
1026  if(macCompAddr(&currentEntry.macAddr, &entry->macAddr))
1027  {
1028  j = i;
1029  break;
1030  }
1031  }
1032  else
1033  {
1034  //Keep track of the first free entry
1036  {
1037  j = i;
1038  }
1039  }
1040  }
1041 
1042  //Any entry available?
1044  {
1045  //Write the Static Address Table Entry 1 register
1048 
1049  //Set the relevant forward ports
1050  if(entry->destPorts == SWITCH_CPU_PORT_MASK)
1051  {
1053  }
1054  else
1055  {
1056  value = entry->destPorts & KSZ8567_PORT_MASK;
1057  }
1058 
1059  //Enable overriding of port state
1060  if(entry->override)
1061  {
1063  }
1064 
1065  //Write the Static Address Table Entry 2 register
1067 
1068  //Copy MAC address (first 16 bits)
1069  value = (entry->macAddr.b[0] << 8) | entry->macAddr.b[1];
1070 
1071  //Write the Static Address Table Entry 3 register
1073 
1074  //Copy MAC address (last 32 bits)
1075  value = (entry->macAddr.b[2] << 24) | (entry->macAddr.b[3] << 16) |
1076  (entry->macAddr.b[4] << 8) | entry->macAddr.b[5];
1077 
1078  //Write the Static Address Table Entry 4 register
1080 
1081  //Write the TABLE_INDEX field with the 4-bit index value
1083  //Set the TABLE_SELECT bit to 0 to select the static address table
1085  //Set the ACTION bit to 0 to indicate a write operation
1087  //Set the START_FINISH bit to 1 to initiate the operation
1089 
1090  //Start the write operation
1092  value);
1093 
1094  //When the operation is complete, the START_FINISH bit will be cleared
1095  //automatically
1096  do
1097  {
1098  //Read the Static Address and Reserved Multicast Table Control register
1099  value = ksz8567ReadSwitchReg32(interface,
1101 
1102  //Poll the START_FINISH bit
1104 
1105  //Successful processing
1106  error = NO_ERROR;
1107  }
1108  else
1109  {
1110  //The static MAC table is full
1111  error = ERROR_TABLE_FULL;
1112  }
1113 
1114  //Return status code
1115  return error;
1116 }
1117 
1118 
1119 /**
1120  * @brief Remove an entry from the static MAC table
1121  * @param[in] interface Underlying network interface
1122  * @param[in] entry Forwarding database entry to remove from the table
1123  * @return Error code
1124  **/
1125 
1127  const SwitchFdbEntry *entry)
1128 {
1129  error_t error;
1130  uint_t j;
1131  uint32_t value;
1132  SwitchFdbEntry currentEntry;
1133 
1134  //Loop through the static MAC table
1135  for(j = 0; j < KSZ8567_STATIC_MAC_TABLE_SIZE; j++)
1136  {
1137  //Read current entry
1138  error = ksz8567GetStaticFdbEntry(interface, j, &currentEntry);
1139 
1140  //Valid entry?
1141  if(!error)
1142  {
1143  //Check whether the table contains the specified MAC address
1144  if(macCompAddr(&currentEntry.macAddr, &entry->macAddr))
1145  {
1146  break;
1147  }
1148  }
1149  }
1150 
1151  //Any matching entry?
1153  {
1154  //Clear Static Address Table Entry registers
1159 
1160  //Write the TABLE_INDEX field with the 4-bit index value
1162  //Set the TABLE_SELECT bit to 0 to select the static address table
1164  //Set the ACTION bit to 0 to indicate a write operation
1166  //Set the START_FINISH bit to 1 to initiate the operation
1168 
1169  //Start the write operation
1171  value);
1172 
1173  //When the operation is complete, the START_FINISH bit will be cleared
1174  //automatically
1175  do
1176  {
1177  //Read the Static Address and Reserved Multicast Table Control register
1178  value = ksz8567ReadSwitchReg32(interface,
1180 
1181  //Poll the START_FINISH bit
1183 
1184  //Successful processing
1185  error = NO_ERROR;
1186  }
1187  else
1188  {
1189  //The static MAC table does not contain the specified address
1190  error = ERROR_NOT_FOUND;
1191  }
1192 
1193  //Return status code
1194  return error;
1195 }
1196 
1197 
1198 /**
1199  * @brief Read an entry from the static MAC table
1200  * @param[in] interface Underlying network interface
1201  * @param[in] index Zero-based index of the entry to read
1202  * @param[out] entry Pointer to the forwarding database entry
1203  * @return Error code
1204  **/
1205 
1207  SwitchFdbEntry *entry)
1208 {
1209  error_t error;
1210  uint32_t value;
1211 
1212  //Check index parameter
1213  if(index < KSZ8567_STATIC_MAC_TABLE_SIZE)
1214  {
1215  //Write the TABLE_INDEX field with the 4-bit index value
1217  //Set the TABLE_SELECT bit to 0 to select the static address table
1219  //Set the ACTION bit to 1 to indicate a read operation
1221  //Set the START_FINISH bit to 1 to initiate the operation
1223 
1224  //Start the read operation
1226  value);
1227 
1228  //When the operation is complete, the START_FINISH bit will be cleared
1229  //automatically
1230  do
1231  {
1232  //Read the Static Address and Reserved Multicast Table Control register
1233  value = ksz8567ReadSwitchReg32(interface,
1235 
1236  //Poll the START_FINISH bit
1238 
1239  //Read the Static Address Table Entry 1 register
1241 
1242  //Valid entry?
1244  {
1245  //Read the Static Address Table Entry 2 register
1247 
1248  //Retrieve the ports associated with this MAC address
1249  entry->srcPort = 0;
1251 
1252  //Check the value of the OVERRIDE bit
1254  {
1255  entry->override = TRUE;
1256  }
1257  else
1258  {
1259  entry->override = FALSE;
1260  }
1261 
1262  //Read the Static Address Table Entry 3 register
1264 
1265  //Copy MAC address (first 16 bits)
1266  entry->macAddr.b[0] = (value >> 8) & 0xFF;
1267  entry->macAddr.b[1] = value & 0xFF;
1268 
1269  //Read the Static Address Table Entry 4 register
1271 
1272  //Copy MAC address (last 32 bits)
1273  entry->macAddr.b[2] = (value >> 24) & 0xFF;
1274  entry->macAddr.b[3] = (value >> 16) & 0xFF;
1275  entry->macAddr.b[4] = (value >> 8) & 0xFF;
1276  entry->macAddr.b[5] = value & 0xFF;
1277 
1278  //Successful processing
1279  error = NO_ERROR;
1280  }
1281  else
1282  {
1283  //The entry is not valid
1284  error = ERROR_INVALID_ENTRY;
1285  }
1286  }
1287  else
1288  {
1289  //The end of the table has been reached
1290  error = ERROR_END_OF_TABLE;
1291  }
1292 
1293  //Return status code
1294  return error;
1295 }
1296 
1297 
1298 /**
1299  * @brief Flush static MAC table
1300  * @param[in] interface Underlying network interface
1301  **/
1302 
1304 {
1305  uint_t i;
1306  uint32_t value;
1307 
1308  //Loop through the static MAC table
1309  for(i = 0; i < KSZ8567_STATIC_MAC_TABLE_SIZE; i++)
1310  {
1311  //Clear Static Address Table Entry registers
1316 
1317  //Write the TABLE_INDEX field with the 4-bit index value
1319  //Set the TABLE_SELECT bit to 0 to select the static address table
1321  //Set the ACTION bit to 0 to indicate a write operation
1323  //Set the START_FINISH bit to 1 to initiate the operation
1325 
1326  //Start the write operation
1328  value);
1329 
1330  //When the operation is complete, the START_FINISH bit will be cleared
1331  //automatically
1332  do
1333  {
1334  //Read the Static Address and Reserved Multicast Table Control register
1335  value = ksz8567ReadSwitchReg32(interface,
1337 
1338  //Poll the START_FINISH bit
1340  }
1341 }
1342 
1343 
1344 /**
1345  * @brief Read an entry from the dynamic MAC table
1346  * @param[in] interface Underlying network interface
1347  * @param[in] index Zero-based index of the entry to read
1348  * @param[out] entry Pointer to the forwarding database entry
1349  * @return Error code
1350  **/
1351 
1353  SwitchFdbEntry *entry)
1354 {
1355  error_t error;
1356  uint32_t value;
1357 
1358  //First entry?
1359  if(index == 0)
1360  {
1361  //Clear the ALU Table Access Control register to stop any operation
1363 
1364  //Start the search operation
1368  }
1369 
1370  //Poll the VALID_ENTRY_OR_SEARCH_END bit until it is set
1371  do
1372  {
1373  //Read the ALU Table Access Control register
1375 
1376  //This bit goes high to indicate either a new valid entry is returned or
1377  //the search is complete
1379 
1380  //Check whether the next valid entry is ready
1381  if((value & KSZ8567_ALU_TABLE_CTRL_VALID) != 0)
1382  {
1383  //Store the data from the ALU table entry
1384  entry->destPorts = 0;
1385  entry->override = FALSE;
1386 
1387  //Read the ALU Table Entry 1 and 2 registers
1390 
1391  //Retrieve the port associated with this MAC address
1393  {
1395  entry->srcPort = KSZ8567_PORT1;
1396  break;
1398  entry->srcPort = KSZ8567_PORT2;
1399  break;
1401  entry->srcPort = KSZ8567_PORT3;
1402  break;
1404  entry->srcPort = KSZ8567_PORT4;
1405  break;
1407  entry->srcPort = KSZ8567_PORT5;
1408  break;
1410  entry->srcPort = KSZ8567_PORT6;
1411  break;
1413  entry->srcPort = KSZ8567_PORT7;
1414  break;
1415  default:
1416  entry->srcPort = 0;
1417  break;
1418  }
1419 
1420  //Read the ALU Table Entry 3 register
1422 
1423  //Copy MAC address (first 16 bits)
1424  entry->macAddr.b[0] = (value >> 8) & 0xFF;
1425  entry->macAddr.b[1] = value & 0xFF;
1426 
1427  //Read the ALU Table Entry 4 register
1429 
1430  //Copy MAC address (last 32 bits)
1431  entry->macAddr.b[2] = (value >> 24) & 0xFF;
1432  entry->macAddr.b[3] = (value >> 16) & 0xFF;
1433  entry->macAddr.b[4] = (value >> 8) & 0xFF;
1434  entry->macAddr.b[5] = value & 0xFF;
1435 
1436  //Successful processing
1437  error = NO_ERROR;
1438  }
1439  else
1440  {
1441  //The search can be stopped any time by setting the START_FINISH bit to 0
1443 
1444  //The end of the table has been reached
1445  error = ERROR_END_OF_TABLE;
1446  }
1447 
1448  //Return status code
1449  return error;
1450 }
1451 
1452 
1453 /**
1454  * @brief Flush dynamic MAC table
1455  * @param[in] interface Underlying network interface
1456  * @param[in] port Port number
1457  **/
1458 
1460 {
1461  uint_t temp;
1462  uint8_t state;
1463 
1464  //Flush only dynamic table entries
1469 
1470  //Valid port number?
1471  if(port >= KSZ8567_PORT1 && port <= KSZ8567_PORT7)
1472  {
1473  //Save the current state of the port
1475 
1476  //Turn off learning capability
1479 
1480  //All the entries associated with a port that has its learning capability
1481  //being turned off will be flushed
1485 
1486  //Restore the original state of the port
1488  }
1489  else
1490  {
1491  //Trigger a flush of the entire address lookup table
1495  }
1496 }
1497 
1498 
1499 /**
1500  * @brief Set forward ports for unknown multicast packets
1501  * @param[in] interface Underlying network interface
1502  * @param[in] enable Enable or disable forwarding of unknown multicast packets
1503  * @param[in] forwardPorts Port map
1504  **/
1505 
1507  bool_t enable, uint32_t forwardPorts)
1508 {
1509  uint32_t temp;
1510 
1511  //Read Unknown Multicast Control register
1513 
1514  //Clear port map
1516 
1517  //Enable or disable forwarding of unknown multicast packets
1518  if(enable)
1519  {
1520  //Enable forwarding
1522 
1523  //Check whether unknown multicast packets should be forwarded to the CPU port
1524  if((forwardPorts & SWITCH_CPU_PORT_MASK) != 0)
1525  {
1527  }
1528 
1529  //Select the desired forward ports
1530  temp |= forwardPorts & KSZ8567_UNKONWN_MULTICAST_CTRL_FWD_MAP_ALL;
1531  }
1532  else
1533  {
1534  //Disable forwarding
1536  }
1537 
1538  //Write the value back to Unknown Multicast Control register
1540 }
1541 
1542 
1543 /**
1544  * @brief Write PHY register
1545  * @param[in] interface Underlying network interface
1546  * @param[in] port Port number
1547  * @param[in] address PHY register address
1548  * @param[in] data Register value
1549  **/
1550 
1551 void ksz8567WritePhyReg(NetInterface *interface, uint8_t port,
1552  uint8_t address, uint16_t data)
1553 {
1554  uint16_t n;
1555 
1556  //SPI slave mode?
1557  if(interface->spiDriver != NULL)
1558  {
1559  //The SPI interface provides access to all PHY registers
1561  //Write the 16-bit value
1562  ksz8567WriteSwitchReg16(interface, n, data);
1563  }
1564  else if(interface->smiDriver != NULL)
1565  {
1566  //Write the specified PHY register
1567  interface->smiDriver->writePhyReg(SMI_OPCODE_WRITE, port, address, data);
1568  }
1569  else
1570  {
1571  //Write the specified PHY register
1572  interface->nicDriver->writePhyReg(SMI_OPCODE_WRITE, port, address, data);
1573  }
1574 }
1575 
1576 
1577 /**
1578  * @brief Read PHY register
1579  * @param[in] interface Underlying network interface
1580  * @param[in] port Port number
1581  * @param[in] address PHY register address
1582  * @return Register value
1583  **/
1584 
1585 uint16_t ksz8567ReadPhyReg(NetInterface *interface, uint8_t port,
1586  uint8_t address)
1587 {
1588  uint16_t n;
1589  uint16_t data;
1590 
1591  //SPI slave mode?
1592  if(interface->spiDriver != NULL)
1593  {
1594  //The SPI interface provides access to all PHY registers
1596  //Read the 16-bit value
1597  data = ksz8567ReadSwitchReg16(interface, n);
1598  }
1599  else if(interface->smiDriver != NULL)
1600  {
1601  //Read the specified PHY register
1602  data = interface->smiDriver->readPhyReg(SMI_OPCODE_READ, port, address);
1603  }
1604  else
1605  {
1606  //Read the specified PHY register
1607  data = interface->nicDriver->readPhyReg(SMI_OPCODE_READ, port, address);
1608  }
1609 
1610  //Return register value
1611  return data;
1612 }
1613 
1614 
1615 /**
1616  * @brief Dump PHY registers for debugging purpose
1617  * @param[in] interface Underlying network interface
1618  * @param[in] port Port number
1619  **/
1620 
1621 void ksz8567DumpPhyReg(NetInterface *interface, uint8_t port)
1622 {
1623  uint8_t i;
1624 
1625  //Loop through PHY registers
1626  for(i = 0; i < 32; i++)
1627  {
1628  //Display current PHY register
1629  TRACE_DEBUG("%02" PRIu8 ": 0x%04" PRIX16 "\r\n", i,
1630  ksz8567ReadPhyReg(interface, port, i));
1631  }
1632 
1633  //Terminate with a line feed
1634  TRACE_DEBUG("\r\n");
1635 }
1636 
1637 
1638 /**
1639  * @brief Write MMD register
1640  * @param[in] interface Underlying network interface
1641  * @param[in] port Port number
1642  * @param[in] devAddr Device address
1643  * @param[in] regAddr Register address
1644  * @param[in] data Register value
1645  **/
1646 
1647 void ksz8567WriteMmdReg(NetInterface *interface, uint8_t port,
1648  uint8_t devAddr, uint16_t regAddr, uint16_t data)
1649 {
1650  //Select register operation
1653 
1654  //Write MMD register address
1656 
1657  //Select data operation
1660 
1661  //Write the content of the MMD register
1663 }
1664 
1665 
1666 /**
1667  * @brief Read MMD register
1668  * @param[in] interface Underlying network interface
1669  * @param[in] port Port number
1670  * @param[in] devAddr Device address
1671  * @param[in] regAddr Register address
1672  * @return Register value
1673  **/
1674 
1675 uint16_t ksz8567ReadMmdReg(NetInterface *interface, uint8_t port,
1676  uint8_t devAddr, uint16_t regAddr)
1677 {
1678  //Select register operation
1681 
1682  //Write MMD register address
1684 
1685  //Select data operation
1688 
1689  //Read the content of the MMD register
1690  return ksz8567ReadPhyReg(interface, port, KSZ8567_MMDAADR);
1691 }
1692 
1693 
1694 /**
1695  * @brief Write switch register (8 bits)
1696  * @param[in] interface Underlying network interface
1697  * @param[in] address Switch register address
1698  * @param[in] data Register value
1699  **/
1700 
1701 void ksz8567WriteSwitchReg8(NetInterface *interface, uint16_t address,
1702  uint8_t data)
1703 {
1704  uint32_t command;
1705 
1706  //SPI slave mode?
1707  if(interface->spiDriver != NULL)
1708  {
1709  //Set up a write operation
1710  command = KSZ8567_SPI_CMD_WRITE;
1711  //Set register address
1712  command |= (address << 5) & KSZ8567_SPI_CMD_ADDR;
1713 
1714  //Pull the CS pin low
1715  interface->spiDriver->assertCs();
1716 
1717  //Write 32-bit command
1718  interface->spiDriver->transfer((command >> 24) & 0xFF);
1719  interface->spiDriver->transfer((command >> 16) & 0xFF);
1720  interface->spiDriver->transfer((command >> 8) & 0xFF);
1721  interface->spiDriver->transfer(command & 0xFF);
1722 
1723  //Write 8-bit data
1724  interface->spiDriver->transfer(data);
1725 
1726  //Terminate the operation by raising the CS pin
1727  interface->spiDriver->deassertCs();
1728  }
1729  else
1730  {
1731  //The MDC/MDIO interface does not have access to all the configuration
1732  //registers. It can only access the standard MIIM registers
1733  }
1734 }
1735 
1736 
1737 /**
1738  * @brief Read switch register (8 bits)
1739  * @param[in] interface Underlying network interface
1740  * @param[in] address Switch register address
1741  * @return Register value
1742  **/
1743 
1744 uint8_t ksz8567ReadSwitchReg8(NetInterface *interface, uint16_t address)
1745 {
1746  uint8_t data;
1747  uint32_t command;
1748 
1749  //SPI slave mode?
1750  if(interface->spiDriver != NULL)
1751  {
1752  //Set up a read operation
1753  command = KSZ8567_SPI_CMD_READ;
1754  //Set register address
1755  command |= (address << 5) & KSZ8567_SPI_CMD_ADDR;
1756 
1757  //Pull the CS pin low
1758  interface->spiDriver->assertCs();
1759 
1760  //Write 32-bit command
1761  interface->spiDriver->transfer((command >> 24) & 0xFF);
1762  interface->spiDriver->transfer((command >> 16) & 0xFF);
1763  interface->spiDriver->transfer((command >> 8) & 0xFF);
1764  interface->spiDriver->transfer(command & 0xFF);
1765 
1766  //Read 8-bit data
1767  data = interface->spiDriver->transfer(0xFF);
1768 
1769  //Terminate the operation by raising the CS pin
1770  interface->spiDriver->deassertCs();
1771  }
1772  else
1773  {
1774  //The MDC/MDIO interface does not have access to all the configuration
1775  //registers. It can only access the standard MIIM registers
1776  data = 0;
1777  }
1778 
1779  //Return register value
1780  return data;
1781 }
1782 
1783 
1784 /**
1785  * @brief Write switch register (16 bits)
1786  * @param[in] interface Underlying network interface
1787  * @param[in] address Switch register address
1788  * @param[in] data Register value
1789  **/
1790 
1792  uint16_t data)
1793 {
1794  uint32_t command;
1795 
1796  //SPI slave mode?
1797  if(interface->spiDriver != NULL)
1798  {
1799  //Set up a write operation
1800  command = KSZ8567_SPI_CMD_WRITE;
1801  //Set register address
1802  command |= (address << 5) & KSZ8567_SPI_CMD_ADDR;
1803 
1804  //Pull the CS pin low
1805  interface->spiDriver->assertCs();
1806 
1807  //Write 32-bit command
1808  interface->spiDriver->transfer((command >> 24) & 0xFF);
1809  interface->spiDriver->transfer((command >> 16) & 0xFF);
1810  interface->spiDriver->transfer((command >> 8) & 0xFF);
1811  interface->spiDriver->transfer(command & 0xFF);
1812 
1813  //Write 16-bit data
1814  interface->spiDriver->transfer((data >> 8) & 0xFF);
1815  interface->spiDriver->transfer(data & 0xFF);
1816 
1817  //Terminate the operation by raising the CS pin
1818  interface->spiDriver->deassertCs();
1819  }
1820  else
1821  {
1822  //The MDC/MDIO interface does not have access to all the configuration
1823  //registers. It can only access the standard MIIM registers
1824  }
1825 }
1826 
1827 
1828 /**
1829  * @brief Read switch register (16 bits)
1830  * @param[in] interface Underlying network interface
1831  * @param[in] address Switch register address
1832  * @return Register value
1833  **/
1834 
1835 uint16_t ksz8567ReadSwitchReg16(NetInterface *interface, uint16_t address)
1836 {
1837  uint16_t data;
1838  uint32_t command;
1839 
1840  //SPI slave mode?
1841  if(interface->spiDriver != NULL)
1842  {
1843  //Set up a read operation
1844  command = KSZ8567_SPI_CMD_READ;
1845  //Set register address
1846  command |= (address << 5) & KSZ8567_SPI_CMD_ADDR;
1847 
1848  //Pull the CS pin low
1849  interface->spiDriver->assertCs();
1850 
1851  //Write 32-bit command
1852  interface->spiDriver->transfer((command >> 24) & 0xFF);
1853  interface->spiDriver->transfer((command >> 16) & 0xFF);
1854  interface->spiDriver->transfer((command >> 8) & 0xFF);
1855  interface->spiDriver->transfer(command & 0xFF);
1856 
1857  //Read 16-bit data
1858  data = interface->spiDriver->transfer(0xFF) << 8;
1859  data |= interface->spiDriver->transfer(0xFF);
1860 
1861  //Terminate the operation by raising the CS pin
1862  interface->spiDriver->deassertCs();
1863  }
1864  else
1865  {
1866  //The MDC/MDIO interface does not have access to all the configuration
1867  //registers. It can only access the standard MIIM registers
1868  data = 0;
1869  }
1870 
1871  //Return register value
1872  return data;
1873 }
1874 
1875 
1876 /**
1877  * @brief Write switch register (32 bits)
1878  * @param[in] interface Underlying network interface
1879  * @param[in] address Switch register address
1880  * @param[in] data Register value
1881  **/
1882 
1884  uint32_t data)
1885 {
1886  uint32_t command;
1887 
1888  //SPI slave mode?
1889  if(interface->spiDriver != NULL)
1890  {
1891  //Set up a write operation
1892  command = KSZ8567_SPI_CMD_WRITE;
1893  //Set register address
1894  command |= (address << 5) & KSZ8567_SPI_CMD_ADDR;
1895 
1896  //Pull the CS pin low
1897  interface->spiDriver->assertCs();
1898 
1899  //Write 32-bit command
1900  interface->spiDriver->transfer((command >> 24) & 0xFF);
1901  interface->spiDriver->transfer((command >> 16) & 0xFF);
1902  interface->spiDriver->transfer((command >> 8) & 0xFF);
1903  interface->spiDriver->transfer(command & 0xFF);
1904 
1905  //Write 32-bit data
1906  interface->spiDriver->transfer((data >> 24) & 0xFF);
1907  interface->spiDriver->transfer((data >> 16) & 0xFF);
1908  interface->spiDriver->transfer((data >> 8) & 0xFF);
1909  interface->spiDriver->transfer(data & 0xFF);
1910 
1911  //Terminate the operation by raising the CS pin
1912  interface->spiDriver->deassertCs();
1913  }
1914  else
1915  {
1916  //The MDC/MDIO interface does not have access to all the configuration
1917  //registers. It can only access the standard MIIM registers
1918  }
1919 }
1920 
1921 
1922 /**
1923  * @brief Read switch register (32 bits)
1924  * @param[in] interface Underlying network interface
1925  * @param[in] address Switch register address
1926  * @return Register value
1927  **/
1928 
1929 uint32_t ksz8567ReadSwitchReg32(NetInterface *interface, uint16_t address)
1930 {
1931  uint32_t data;
1932  uint32_t command;
1933 
1934  //SPI slave mode?
1935  if(interface->spiDriver != NULL)
1936  {
1937  //Set up a read operation
1938  command = KSZ8567_SPI_CMD_READ;
1939  //Set register address
1940  command |= (address << 5) & KSZ8567_SPI_CMD_ADDR;
1941 
1942  //Pull the CS pin low
1943  interface->spiDriver->assertCs();
1944 
1945  //Write 32-bit command
1946  interface->spiDriver->transfer((command >> 24) & 0xFF);
1947  interface->spiDriver->transfer((command >> 16) & 0xFF);
1948  interface->spiDriver->transfer((command >> 8) & 0xFF);
1949  interface->spiDriver->transfer(command & 0xFF);
1950 
1951  //Read 32-bit data
1952  data = interface->spiDriver->transfer(0xFF) << 24;
1953  data |= interface->spiDriver->transfer(0xFF) << 16;
1954  data |= interface->spiDriver->transfer(0xFF) << 8;
1955  data |= interface->spiDriver->transfer(0xFF);
1956 
1957  //Terminate the operation by raising the CS pin
1958  interface->spiDriver->deassertCs();
1959  }
1960  else
1961  {
1962  //The MDC/MDIO interface does not have access to all the configuration
1963  //registers. It can only access the standard MIIM registers
1964  data = 0;
1965  }
1966 
1967  //Return register value
1968  return data;
1969 }
uint8_t type
Definition: coap_common.h:176
unsigned int uint_t
Definition: compiler_port.h:50
int bool_t
Definition: compiler_port.h:53
#define HTONS(value)
Definition: cpu_endian.h:410
Debugging facilities.
#define TRACE_DEBUG(...)
Definition: debug.h:107
#define TRACE_INFO(...)
Definition: debug.h:95
uint8_t n
uint16_t port
Definition: dns_common.h:267
error_t
Error codes.
Definition: error.h:43
@ ERROR_INVALID_PORT
Definition: error.h:104
@ ERROR_NOT_FOUND
Definition: error.h:147
@ ERROR_END_OF_TABLE
Definition: error.h:290
@ ERROR_INVALID_ENTRY
Definition: error.h:288
@ ERROR_TABLE_FULL
Definition: error.h:289
@ NO_ERROR
Success.
Definition: error.h:44
@ ERROR_INVALID_LENGTH
Definition: error.h:111
uint8_t data[]
Definition: ethernet.h:222
#define macCompAddr(macAddr1, macAddr2)
Definition: ethernet.h:130
EthHeader
Definition: ethernet.h:223
error_t ethPadFrame(NetBuffer *buffer, size_t *length)
Ethernet frame padding.
Helper functions for Ethernet.
Ipv6Addr address[]
Definition: ipv6.h:316
error_t ksz8567GetDynamicFdbEntry(NetInterface *interface, uint_t index, SwitchFdbEntry *entry)
Read an entry from the dynamic MAC table.
const SwitchDriver ksz8567SwitchDriver
KSZ8567 Ethernet switch driver.
void ksz8567WriteMmdReg(NetInterface *interface, uint8_t port, uint8_t devAddr, uint16_t regAddr, uint16_t data)
Write MMD register.
void ksz8567SetPortState(NetInterface *interface, uint8_t port, SwitchPortState state)
Set port state.
uint8_t ksz8567ReadSwitchReg8(NetInterface *interface, uint16_t address)
Read switch register (8 bits)
uint16_t ksz8567ReadSwitchReg16(NetInterface *interface, uint16_t address)
Read switch register (16 bits)
void ksz8567WriteSwitchReg16(NetInterface *interface, uint16_t address, uint16_t data)
Write switch register (16 bits)
void ksz8567DumpPhyReg(NetInterface *interface, uint8_t port)
Dump PHY registers for debugging purpose.
void ksz8567EnableIgmpSnooping(NetInterface *interface, bool_t enable)
Enable IGMP snooping.
error_t ksz8567DeleteStaticFdbEntry(NetInterface *interface, const SwitchFdbEntry *entry)
Remove an entry from the static MAC table.
void ksz8567SetAgingTime(NetInterface *interface, uint32_t agingTime)
Set aging time for dynamic filtering entries.
SwitchPortState ksz8567GetPortState(NetInterface *interface, uint8_t port)
Get port state.
error_t ksz8567UntagFrame(NetInterface *interface, uint8_t **frame, size_t *length, NetRxAncillary *ancillary)
Decode tail tag from incoming Ethernet frame.
bool_t ksz8567GetLinkState(NetInterface *interface, uint8_t port)
Get link state.
uint16_t ksz8567ReadPhyReg(NetInterface *interface, uint8_t port, uint8_t address)
Read PHY register.
void ksz8567EnableIrq(NetInterface *interface)
Enable interrupts.
void ksz8567Tick(NetInterface *interface)
KSZ8567 timer handler.
error_t ksz8567AddStaticFdbEntry(NetInterface *interface, const SwitchFdbEntry *entry)
Add a new entry to the static MAC table.
void ksz8567EnableRsvdMcastTable(NetInterface *interface, bool_t enable)
Enable reserved multicast table.
uint16_t ksz8567ReadMmdReg(NetInterface *interface, uint8_t port, uint8_t devAddr, uint16_t regAddr)
Read MMD register.
void ksz8567FlushDynamicFdbTable(NetInterface *interface, uint8_t port)
Flush dynamic MAC table.
error_t ksz8567TagFrame(NetInterface *interface, NetBuffer *buffer, size_t *offset, NetTxAncillary *ancillary)
Add tail tag to Ethernet frame.
void ksz8567DisableIrq(NetInterface *interface)
Disable interrupts.
void ksz8567EventHandler(NetInterface *interface)
KSZ8567 event handler.
NicDuplexMode ksz8567GetDuplexMode(NetInterface *interface, uint8_t port)
Get duplex mode.
uint32_t ksz8567ReadSwitchReg32(NetInterface *interface, uint16_t address)
Read switch register (32 bits)
error_t ksz8567Init(NetInterface *interface)
KSZ8567 Ethernet switch initialization.
uint32_t ksz8567GetLinkSpeed(NetInterface *interface, uint8_t port)
Get link speed.
void ksz8567EnableMldSnooping(NetInterface *interface, bool_t enable)
Enable MLD snooping.
__weak_func void ksz8567InitHook(NetInterface *interface)
KSZ8567 custom configuration.
void ksz8567FlushStaticFdbTable(NetInterface *interface)
Flush static MAC table.
void ksz8567WriteSwitchReg8(NetInterface *interface, uint16_t address, uint8_t data)
Write switch register (8 bits)
void ksz8567SetUnknownMcastFwdPorts(NetInterface *interface, bool_t enable, uint32_t forwardPorts)
Set forward ports for unknown multicast packets.
const uint16_t ksz8567IngressTailTag[6]
Tail tag rules (host to KSZ8567)
void ksz8567WritePhyReg(NetInterface *interface, uint8_t port, uint8_t address, uint16_t data)
Write PHY register.
void ksz8567WriteSwitchReg32(NetInterface *interface, uint16_t address, uint32_t data)
Write switch register (32 bits)
error_t ksz8567GetStaticFdbEntry(NetInterface *interface, uint_t index, SwitchFdbEntry *entry)
Read an entry from the static MAC table.
KSZ8567 7-port Ethernet switch driver.
#define KSZ8567_SWITCH_LUE_CTRL1_FLUSH_MSTP_ENTRIES
#define KSZ8567_GLOBAL_PORT_MIRROR_SNOOP_CTRL_MLD_SNOOP_EN
#define KSZ8567_SWITCH_LUE_CTRL0_RESERVED_MCAST_LOOKUP_EN
#define KSZ8567_STATIC_TABLE_ENTRY1
#define KSZ8567_SWITCH_LUE_CTRL3_AGE_PERIOD_DEFAULT
#define KSZ8567_TAIL_TAG_DEST_PORT3
#define KSZ8567_PHYCON
#define KSZ8567_MMD_LED_MODE
#define KSZ8567_ALU_TABLE_ENTRY2_PORT7_FORWARD
#define KSZ8567_STATIC_MCAST_TABLE_CTRL
#define KSZ8567_SWITCH_OP_START_SWITCH
#define KSZ8567_PHYCON_DUPLEX_STATUS
#define KSZ8567_STATIC_MCAST_TABLE_CTRL_TABLE_INDEX
#define KSZ8567_PORT2
#define KSZ8567_PORTn_XMII_CTRL0_DUPLEX
#define KSZ8567_MMD_LED_MODE_LED_MODE_SINGLE
#define KSZ8567_SWITCH_LUE_CTRL3
#define KSZ8567_UNKONWN_MULTICAST_CTRL_FWD_MAP
#define KSZ8567_TAIL_TAG_DEST_PORT4
#define KSZ8567_STATIC_TABLE_ENTRY2_PORT_FORWARD
#define KSZ8567_PORTn_XMII_CTRL1_IF_TYPE
#define KSZ8567_ALU_TABLE_CTRL_VALID
#define KSZ8567_PORT_MASK
#define KSZ8567_STATIC_MCAST_TABLE_CTRL_TABLE_SELECT
#define KSZ8567_ALU_TABLE_ENTRY2_PORT3_FORWARD
#define KSZ8567_PORTn_XMII_CTRL1_RGMII_ID_IG
#define KSZ8567_PORT6_OP_CTRL0
#define KSZ8567_PORT7
#define KSZ8567_UNKONWN_MULTICAST_CTRL_FWD
#define KSZ8567_ALU_TABLE_CTRL_START_FINISH
#define KSZ8567_TAIL_TAG_SRC_PORT
#define KSZ8567_STATIC_TABLE_ENTRY3
#define KSZ8567_ALU_TABLE_CTRL_VALID_ENTRY_OR_SEARCH_END
#define KSZ8567_MMDACR_FUNC_ADDR
#define KSZ8567_PORT6_XMII_CTRL1
#define KSZ8567_STATIC_MCAST_TABLE_CTRL_ACTION
#define KSZ8567_SPI_CMD_READ
#define KSZ8567_BMSR_LINK_STATUS
#define KSZ8567_ALU_TABLE_ENTRY2_PORT4_FORWARD
#define KSZ8567_TAIL_TAG_DEST_PORT2
#define KSZ8567_ALU_TABLE_ENTRY2_PORT5_FORWARD
#define KSZ8567_PHYCON_SPEED_100BTX
#define KSZ8567_SWITCH_LUE_CTRL2_FLUSH_OPTION
#define KSZ8567_ALU_TABLE_CTRL
#define KSZ8567_ALU_TABLE_ENTRY2_PORT_FORWARD
#define KSZ8567_PORTn_XMII_CTRL1_RGMII_ID_EG
#define KSZ8567_UNKONWN_MULTICAST_CTRL_FWD_MAP_PORT6
#define KSZ8567_PORTn_MSTP_STATE_LEARNING_DIS
#define KSZ8567_STATIC_TABLE_ENTRY1_VALID
#define KSZ8567_SWITCH_MAC_CTRL0
#define KSZ8567_MMD_EEE_ADV
#define KSZ8567_STATIC_TABLE_ENTRY2_OVERRIDE
#define KSZ8567_GLOBAL_PORT_MIRROR_SNOOP_CTRL
#define KSZ8567_SWITCH_LUE_CTRL1
#define KSZ8567_ALU_TABLE_ENTRY2
#define KSZ8567_GLOBAL_PORT_MIRROR_SNOOP_CTRL_IGMP_SNOOP_EN
#define KSZ8567_ALU_TABLE_ENTRY4
#define KSZ8567_SWITCH_LUE_CTRL2
#define KSZ8567_PORTn_MSTP_STATE(port)
#define KSZ8567_TAIL_TAG_NORMAL_ADDR_LOOKUP
#define KSZ8567_PORTn_ETH_PHY_REG(port, addr)
#define KSZ8567_UNKONWN_MULTICAST_CTRL
#define KSZ8567_PORTn_XMII_CTRL0_SPEED_10_100
#define KSZ8567_MMDACR_DEVAD
#define KSZ8567_PORTn_MSTP_STATE_TRANSMIT_EN
#define KSZ8567_STATIC_TABLE_ENTRY4
#define KSZ8567_CHIP_ID1_DEFAULT
#define KSZ8567_SPI_CMD_ADDR
#define KSZ8567_STATIC_TABLE_ENTRY2
#define KSZ8567_SWITCH_OP
#define KSZ8567_PORT6
#define KSZ8567_TAIL_TAG_PORT_BLOCKING_OVERRIDE
#define KSZ8567_TAIL_TAG_DEST_PORT1
#define KSZ8567_SWITCH_LUE_CTRL0_HASH_OPTION_CRC
#define KSZ8567_SWITCH_LUE_CTRL2_FLUSH_OPTION_DYNAMIC
#define KSZ8567_SPI_CMD_WRITE
#define KSZ8567_PORTn_XMII_CTRL1_IF_TYPE_RGMII
#define KSZ8567_STATIC_MAC_TABLE_SIZE
#define KSZ8567_ALU_TABLE_ENTRY2_PORT6_FORWARD
#define KSZ8567_ALU_TABLE_ENTRY2_PORT1_FORWARD
#define KSZ8567_SWITCH_LUE_CTRL0_AGE_COUNT_DEFAULT
#define KSZ8567_PHYCON_SPEED_10BT
#define KSZ8567_MMD_LED_MODE_RESERVED_DEFAULT
#define KSZ8567_CHIP_ID1
#define KSZ8567_SWITCH_MAC_CTRL0_FRAME_LEN_CHECK_EN
#define KSZ8567_STATIC_MCAST_TABLE_CTRL_START_FINISH
#define KSZ8567_PORTn_MSTP_STATE_RECEIVE_EN
#define KSZ8567_MMDACR
#define KSZ8567_PORT6_MASK
#define KSZ8567_SWITCH_LUE_CTRL1_FLUSH_ALU_TABLE
#define KSZ8567_ALU_TABLE_ENTRY1
#define KSZ8567_PORTn_XMII_CTRL1_SPEED_1000
#define KSZ8567_BMSR
#define KSZ8567_MMDACR_FUNC_DATA_NO_POST_INC
#define KSZ8567_PORT1
#define KSZ8567_MMDAADR
#define KSZ8567_ALU_TABLE_ENTRY3
#define KSZ8567_SWITCH_LUE_CTRL0
#define KSZ8567_ALU_TABLE_ENTRY2_PORT2_FORWARD
#define KSZ8567_UNKONWN_MULTICAST_CTRL_FWD_MAP_ALL
#define KSZ8567_PORT4
#define KSZ8567_ALU_TABLE_CTRL_ACTION_SEARCH
#define KSZ8567_PORTn_OP_CTRL0_TAIL_TAG_EN
#define KSZ8567_PORT3
#define KSZ8567_TAIL_TAG_DEST_PORT5
#define KSZ8567_PORT5
#define KSZ8567_PORT6_XMII_CTRL0
uint16_t regAddr
TCP/IP stack core.
#define NET_INTERFACE_COUNT
Definition: net.h:113
#define NetInterface
Definition: net.h:36
#define netInterface
Definition: net_legacy.h:199
#define netEvent
Definition: net_legacy.h:196
size_t netBufferGetLength(const NetBuffer *buffer)
Get the actual length of a multi-part buffer.
Definition: net_mem.c:297
error_t netBufferAppend(NetBuffer *dest, const void *src, size_t length)
Append data a multi-part buffer.
Definition: net_mem.c:588
#define NetRxAncillary
Definition: net_misc.h:40
#define NetTxAncillary
Definition: net_misc.h:36
void nicNotifyLinkChange(NetInterface *interface)
Process link state change notification.
Definition: nic.c:548
#define SMI_OPCODE_WRITE
Definition: nic.h:66
#define SMI_OPCODE_READ
Definition: nic.h:67
NicDuplexMode
Duplex mode.
Definition: nic.h:122
@ NIC_FULL_DUPLEX_MODE
Definition: nic.h:125
@ NIC_HALF_DUPLEX_MODE
Definition: nic.h:124
@ NIC_UNKNOWN_DUPLEX_MODE
Definition: nic.h:123
#define SWITCH_CPU_PORT_MASK
Definition: nic.h:60
SwitchPortState
Switch port state.
Definition: nic.h:134
@ SWITCH_PORT_STATE_UNKNOWN
Definition: nic.h:135
@ SWITCH_PORT_STATE_FORWARDING
Definition: nic.h:140
@ SWITCH_PORT_STATE_LISTENING
Definition: nic.h:138
@ SWITCH_PORT_STATE_DISABLED
Definition: nic.h:136
@ SWITCH_PORT_STATE_LEARNING
Definition: nic.h:139
@ NIC_LINK_SPEED_100MBPS
Definition: nic.h:112
@ NIC_LINK_SPEED_10MBPS
Definition: nic.h:111
@ NIC_LINK_SPEED_UNKNOWN
Definition: nic.h:110
@ NIC_LINK_SPEED_1GBPS
Definition: nic.h:113
#define MIN(a, b)
Definition: os_port.h:63
#define TRUE
Definition: os_port.h:50
#define FALSE
Definition: os_port.h:46
void osSetEvent(OsEvent *event)
Set the specified event object to the signaled state.
Structure describing a buffer that spans multiple chunks.
Definition: net_mem.h:89
Ethernet switch driver.
Definition: nic.h:322
Forwarding database entry.
Definition: nic.h:149
MacAddr macAddr
Definition: nic.h:150
uint32_t destPorts
Definition: nic.h:152
bool_t override
Definition: nic.h:153
uint8_t srcPort
Definition: nic.h:151
uint8_t length
Definition: tcp.h:368
uint8_t value[]
Definition: tcp.h:369