1717#include <linux/kernel.h>
1818#include <linux/module.h>
1919#include <linux/device.h>
20+ #include <linux/iopoll.h>
2021#include <linux/of.h>
2122#include <linux/of_mdio.h>
2223#include <linux/bitops.h>
268269#define IS_7398 (a ) ((a)->chipid == VSC73XX_CHIPID_ID_7398)
269270#define IS_739X (a ) (IS_7395(a) || IS_7398(a))
270271
272+ #define VSC73XX_POLL_SLEEP_US 1000
273+ #define VSC73XX_POLL_TIMEOUT_US 10000
274+
271275struct vsc73xx_counter {
272276 u8 counter ;
273277 const char * name ;
@@ -713,51 +717,44 @@ static void vsc73xx_init_port(struct vsc73xx *vsc, int port)
713717 port , VSC73XX_C_RX0 , 0 );
714718}
715719
716- static void vsc73xx_adjust_enable_port (struct vsc73xx * vsc ,
717- int port , struct phy_device * phydev ,
718- u32 initval )
720+ static void vsc73xx_reset_port (struct vsc73xx * vsc , int port , u32 initval )
719721{
720- u32 val = initval ;
721- u8 seed ;
722-
723- /* Reset this port FIXME: break out subroutine */
724- val |= VSC73XX_MAC_CFG_RESET ;
725- vsc73xx_write (vsc , VSC73XX_BLOCK_MAC , port , VSC73XX_MAC_CFG , val );
726-
727- /* Seed the port randomness with randomness */
728- get_random_bytes (& seed , 1 );
729- val |= seed << VSC73XX_MAC_CFG_SEED_OFFSET ;
730- val |= VSC73XX_MAC_CFG_SEED_LOAD ;
731- val |= VSC73XX_MAC_CFG_WEXC_DIS ;
732- vsc73xx_write (vsc , VSC73XX_BLOCK_MAC , port , VSC73XX_MAC_CFG , val );
722+ int ret , err ;
723+ u32 val ;
733724
734- /* Flow control for the PHY facing ports:
735- * Use a zero delay pause frame when pause condition is left
736- * Obey pause control frames
737- * When generating pause frames, use 0xff as pause value
738- */
739- vsc73xx_write (vsc , VSC73XX_BLOCK_MAC , port , VSC73XX_FCCONF ,
740- VSC73XX_FCCONF_ZERO_PAUSE_EN |
741- VSC73XX_FCCONF_FLOW_CTRL_OBEY |
742- 0xff );
725+ /* Disable RX on this port */
726+ vsc73xx_update_bits (vsc , VSC73XX_BLOCK_MAC , port ,
727+ VSC73XX_MAC_CFG ,
728+ VSC73XX_MAC_CFG_RX_EN , 0 );
743729
744- /* Disallow backward dropping of frames from this port */
730+ /* Discard packets */
745731 vsc73xx_update_bits (vsc , VSC73XX_BLOCK_ARBITER , 0 ,
746- VSC73XX_SBACKWDROP , BIT (port ), 0 );
732+ VSC73XX_ARBDISC , BIT (port ), BIT (port ));
733+
734+ /* Wait until queue is empty */
735+ ret = read_poll_timeout (vsc73xx_read , err ,
736+ err < 0 || (val & BIT (port )),
737+ VSC73XX_POLL_SLEEP_US ,
738+ VSC73XX_POLL_TIMEOUT_US , false,
739+ vsc , VSC73XX_BLOCK_ARBITER , 0 ,
740+ VSC73XX_ARBEMPTY , & val );
741+ if (ret )
742+ dev_err (vsc -> dev ,
743+ "timeout waiting for block arbiter\n" );
744+ else if (err < 0 )
745+ dev_err (vsc -> dev , "error reading arbiter\n" );
747746
748- /* Enable TX, RX, deassert reset, stop loading seed */
749- vsc73xx_update_bits (vsc , VSC73XX_BLOCK_MAC , port ,
750- VSC73XX_MAC_CFG ,
751- VSC73XX_MAC_CFG_RESET | VSC73XX_MAC_CFG_SEED_LOAD |
752- VSC73XX_MAC_CFG_TX_EN | VSC73XX_MAC_CFG_RX_EN ,
753- VSC73XX_MAC_CFG_TX_EN | VSC73XX_MAC_CFG_RX_EN );
747+ /* Put this port into reset */
748+ vsc73xx_write (vsc , VSC73XX_BLOCK_MAC , port , VSC73XX_MAC_CFG ,
749+ VSC73XX_MAC_CFG_RESET | initval );
754750}
755751
756- static void vsc73xx_adjust_link (struct dsa_switch * ds , int port ,
757- struct phy_device * phydev )
752+ static void vsc73xx_mac_config (struct phylink_config * config , unsigned int mode ,
753+ const struct phylink_link_state * state )
758754{
759- struct vsc73xx * vsc = ds -> priv ;
760- u32 val ;
755+ struct dsa_port * dp = dsa_phylink_to_port (config );
756+ struct vsc73xx * vsc = dp -> ds -> priv ;
757+ int port = dp -> index ;
761758
762759 /* Special handling of the CPU-facing port */
763760 if (port == CPU_PORT ) {
@@ -774,104 +771,93 @@ static void vsc73xx_adjust_link(struct dsa_switch *ds, int port,
774771 VSC73XX_ADVPORTM_ENA_GTX |
775772 VSC73XX_ADVPORTM_DDR_MODE );
776773 }
774+ }
775+
776+ static void vsc73xx_mac_link_down (struct phylink_config * config ,
777+ unsigned int mode , phy_interface_t interface )
778+ {
779+ struct dsa_port * dp = dsa_phylink_to_port (config );
780+ struct vsc73xx * vsc = dp -> ds -> priv ;
781+ int port = dp -> index ;
777782
778- /* This is the MAC confiuration that always need to happen
779- * after a PHY or the CPU port comes up or down.
783+ /* This routine is described in the datasheet (below ARBDISC register
784+ * description)
780785 */
781- if (!phydev -> link ) {
782- int maxloop = 10 ;
783-
784- dev_dbg (vsc -> dev , "port %d: went down\n" ,
785- port );
786-
787- /* Disable RX on this port */
788- vsc73xx_update_bits (vsc , VSC73XX_BLOCK_MAC , port ,
789- VSC73XX_MAC_CFG ,
790- VSC73XX_MAC_CFG_RX_EN , 0 );
791-
792- /* Discard packets */
793- vsc73xx_update_bits (vsc , VSC73XX_BLOCK_ARBITER , 0 ,
794- VSC73XX_ARBDISC , BIT (port ), BIT (port ));
795-
796- /* Wait until queue is empty */
797- vsc73xx_read (vsc , VSC73XX_BLOCK_ARBITER , 0 ,
798- VSC73XX_ARBEMPTY , & val );
799- while (!(val & BIT (port ))) {
800- msleep (1 );
801- vsc73xx_read (vsc , VSC73XX_BLOCK_ARBITER , 0 ,
802- VSC73XX_ARBEMPTY , & val );
803- if (-- maxloop == 0 ) {
804- dev_err (vsc -> dev ,
805- "timeout waiting for block arbiter\n" );
806- /* Continue anyway */
807- break ;
808- }
809- }
786+ vsc73xx_reset_port (vsc , port , 0 );
787+
788+ /* Allow backward dropping of frames from this port */
789+ vsc73xx_update_bits (vsc , VSC73XX_BLOCK_ARBITER , 0 ,
790+ VSC73XX_SBACKWDROP , BIT (port ), BIT (port ));
791+
792+ /* Receive mask (disable forwarding) */
793+ vsc73xx_update_bits (vsc , VSC73XX_BLOCK_ANALYZER , 0 ,
794+ VSC73XX_RECVMASK , BIT (port ), 0 );
795+ }
796+
797+ static void vsc73xx_mac_link_up (struct phylink_config * config ,
798+ struct phy_device * phy , unsigned int mode ,
799+ phy_interface_t interface , int speed ,
800+ int duplex , bool tx_pause , bool rx_pause )
801+ {
802+ struct dsa_port * dp = dsa_phylink_to_port (config );
803+ struct vsc73xx * vsc = dp -> ds -> priv ;
804+ int port = dp -> index ;
805+ u32 val ;
806+ u8 seed ;
810807
811- /* Put this port into reset */
812- vsc73xx_write (vsc , VSC73XX_BLOCK_MAC , port , VSC73XX_MAC_CFG ,
813- VSC73XX_MAC_CFG_RESET );
808+ if (speed == SPEED_1000 )
809+ val = VSC73XX_MAC_CFG_GIGA_MODE | VSC73XX_MAC_CFG_TX_IPG_1000M ;
810+ else
811+ val = VSC73XX_MAC_CFG_TX_IPG_100_10M ;
814812
815- /* Accept packets again */
816- vsc73xx_update_bits (vsc , VSC73XX_BLOCK_ARBITER , 0 ,
817- VSC73XX_ARBDISC , BIT (port ), 0 );
813+ if (phy_interface_mode_is_rgmii (interface ))
814+ val |= VSC73XX_MAC_CFG_CLK_SEL_1000M ;
815+ else
816+ val |= VSC73XX_MAC_CFG_CLK_SEL_EXT ;
818817
819- /* Allow backward dropping of frames from this port */
820- vsc73xx_update_bits (vsc , VSC73XX_BLOCK_ARBITER , 0 ,
821- VSC73XX_SBACKWDROP , BIT (port ), BIT (port ));
818+ if (duplex == DUPLEX_FULL )
819+ val |= VSC73XX_MAC_CFG_FDX ;
822820
823- /* Receive mask (disable forwarding) */
824- vsc73xx_update_bits (vsc , VSC73XX_BLOCK_ANALYZER , 0 ,
825- VSC73XX_RECVMASK , BIT (port ), 0 );
821+ /* This routine is described in the datasheet (below ARBDISC register
822+ * description)
823+ */
824+ vsc73xx_reset_port (vsc , port , val );
826825
827- return ;
828- }
826+ /* Seed the port randomness with randomness */
827+ get_random_bytes (& seed , 1 );
828+ val |= seed << VSC73XX_MAC_CFG_SEED_OFFSET ;
829+ val |= VSC73XX_MAC_CFG_SEED_LOAD ;
830+ val |= VSC73XX_MAC_CFG_WEXC_DIS ;
831+ vsc73xx_write (vsc , VSC73XX_BLOCK_MAC , port , VSC73XX_MAC_CFG , val );
829832
830- /* Figure out what speed was negotiated */
831- if (phydev -> speed == SPEED_1000 ) {
832- dev_dbg (vsc -> dev , "port %d: 1000 Mbit mode full duplex\n" ,
833- port );
834-
835- /* Set up default for internal port or external RGMII */
836- if (phydev -> interface == PHY_INTERFACE_MODE_RGMII )
837- val = VSC73XX_MAC_CFG_1000M_F_RGMII ;
838- else
839- val = VSC73XX_MAC_CFG_1000M_F_PHY ;
840- vsc73xx_adjust_enable_port (vsc , port , phydev , val );
841- } else if (phydev -> speed == SPEED_100 ) {
842- if (phydev -> duplex == DUPLEX_FULL ) {
843- val = VSC73XX_MAC_CFG_100_10M_F_PHY ;
844- dev_dbg (vsc -> dev ,
845- "port %d: 100 Mbit full duplex mode\n" ,
846- port );
847- } else {
848- val = VSC73XX_MAC_CFG_100_10M_H_PHY ;
849- dev_dbg (vsc -> dev ,
850- "port %d: 100 Mbit half duplex mode\n" ,
851- port );
852- }
853- vsc73xx_adjust_enable_port (vsc , port , phydev , val );
854- } else if (phydev -> speed == SPEED_10 ) {
855- if (phydev -> duplex == DUPLEX_FULL ) {
856- val = VSC73XX_MAC_CFG_100_10M_F_PHY ;
857- dev_dbg (vsc -> dev ,
858- "port %d: 10 Mbit full duplex mode\n" ,
859- port );
860- } else {
861- val = VSC73XX_MAC_CFG_100_10M_H_PHY ;
862- dev_dbg (vsc -> dev ,
863- "port %d: 10 Mbit half duplex mode\n" ,
864- port );
865- }
866- vsc73xx_adjust_enable_port (vsc , port , phydev , val );
867- } else {
868- dev_err (vsc -> dev ,
869- "could not adjust link: unknown speed\n" );
870- }
833+ /* Flow control for the PHY facing ports:
834+ * Use a zero delay pause frame when pause condition is left
835+ * Obey pause control frames
836+ * When generating pause frames, use 0xff as pause value
837+ */
838+ vsc73xx_write (vsc , VSC73XX_BLOCK_MAC , port , VSC73XX_FCCONF ,
839+ VSC73XX_FCCONF_ZERO_PAUSE_EN |
840+ VSC73XX_FCCONF_FLOW_CTRL_OBEY |
841+ 0xff );
871842
872- /* Enable port (forwarding) in the receieve mask */
843+ /* Accept packets again */
844+ vsc73xx_update_bits (vsc , VSC73XX_BLOCK_ARBITER , 0 ,
845+ VSC73XX_ARBDISC , BIT (port ), 0 );
846+
847+ /* Enable port (forwarding) in the receive mask */
873848 vsc73xx_update_bits (vsc , VSC73XX_BLOCK_ANALYZER , 0 ,
874849 VSC73XX_RECVMASK , BIT (port ), BIT (port ));
850+
851+ /* Disallow backward dropping of frames from this port */
852+ vsc73xx_update_bits (vsc , VSC73XX_BLOCK_ARBITER , 0 ,
853+ VSC73XX_SBACKWDROP , BIT (port ), 0 );
854+
855+ /* Enable TX, RX, deassert reset, stop loading seed */
856+ vsc73xx_update_bits (vsc , VSC73XX_BLOCK_MAC , port ,
857+ VSC73XX_MAC_CFG ,
858+ VSC73XX_MAC_CFG_RESET | VSC73XX_MAC_CFG_SEED_LOAD |
859+ VSC73XX_MAC_CFG_TX_EN | VSC73XX_MAC_CFG_RX_EN ,
860+ VSC73XX_MAC_CFG_TX_EN | VSC73XX_MAC_CFG_RX_EN );
875861}
876862
877863static int vsc73xx_port_enable (struct dsa_switch * ds , int port ,
@@ -1053,12 +1039,17 @@ static void vsc73xx_phylink_get_caps(struct dsa_switch *dsa, int port,
10531039 config -> mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 | MAC_1000 ;
10541040}
10551041
1042+ static const struct phylink_mac_ops vsc73xx_phylink_mac_ops = {
1043+ .mac_config = vsc73xx_mac_config ,
1044+ .mac_link_down = vsc73xx_mac_link_down ,
1045+ .mac_link_up = vsc73xx_mac_link_up ,
1046+ };
1047+
10561048static const struct dsa_switch_ops vsc73xx_ds_ops = {
10571049 .get_tag_protocol = vsc73xx_get_tag_protocol ,
10581050 .setup = vsc73xx_setup ,
10591051 .phy_read = vsc73xx_phy_read ,
10601052 .phy_write = vsc73xx_phy_write ,
1061- .adjust_link = vsc73xx_adjust_link ,
10621053 .get_strings = vsc73xx_get_strings ,
10631054 .get_ethtool_stats = vsc73xx_get_ethtool_stats ,
10641055 .get_sset_count = vsc73xx_get_sset_count ,
@@ -1195,26 +1186,16 @@ int vsc73xx_probe(struct vsc73xx *vsc)
11951186 vsc -> addr [0 ], vsc -> addr [1 ], vsc -> addr [2 ],
11961187 vsc -> addr [3 ], vsc -> addr [4 ], vsc -> addr [5 ]);
11971188
1198- /* The VSC7395 switch chips have 5+1 ports which means 5
1199- * ordinary ports and a sixth CPU port facing the processor
1200- * with an RGMII interface. These ports are numbered 0..4
1201- * and 6, so they leave a "hole" in the port map for port 5,
1202- * which is invalid.
1203- *
1204- * The VSC7398 has 8 ports, port 7 is again the CPU port.
1205- *
1206- * We allocate 8 ports and avoid access to the nonexistant
1207- * ports.
1208- */
12091189 vsc -> ds = devm_kzalloc (dev , sizeof (* vsc -> ds ), GFP_KERNEL );
12101190 if (!vsc -> ds )
12111191 return - ENOMEM ;
12121192
12131193 vsc -> ds -> dev = dev ;
1214- vsc -> ds -> num_ports = 8 ;
1194+ vsc -> ds -> num_ports = VSC73XX_MAX_NUM_PORTS ;
12151195 vsc -> ds -> priv = vsc ;
12161196
12171197 vsc -> ds -> ops = & vsc73xx_ds_ops ;
1198+ vsc -> ds -> phylink_mac_ops = & vsc73xx_phylink_mac_ops ;
12181199 ret = dsa_register_switch (vsc -> ds );
12191200 if (ret ) {
12201201 dev_err (dev , "unable to register switch (%d)\n" , ret );
0 commit comments