1 // SPDX-License-Identifier: GPL-2.0+ 2 /* Microchip Sparx5 Switch driver 3 * 4 * Copyright (c) 2021 Microchip Technology Inc. and its subsidiaries. 5 */ 6 7 #include <linux/module.h> 8 #include <linux/phylink.h> 9 #include <linux/device.h> 10 #include <linux/netdevice.h> 11 #include <linux/sfp.h> 12 13 #include "sparx5_main_regs.h" 14 #include "sparx5_main.h" 15 #include "sparx5_port.h" 16 17 static bool port_conf_has_changed(struct sparx5_port_config *a, struct sparx5_port_config *b) 18 { 19 if (a->speed != b->speed || 20 a->portmode != b->portmode || 21 a->autoneg != b->autoneg || 22 a->pause_adv != b->pause_adv || 23 a->power_down != b->power_down || 24 a->media != b->media) 25 return true; 26 return false; 27 } 28 29 static void sparx5_phylink_validate(struct phylink_config *config, 30 unsigned long *supported, 31 struct phylink_link_state *state) 32 { 33 struct sparx5_port *port = netdev_priv(to_net_dev(config->dev)); 34 __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, }; 35 36 phylink_set(mask, Autoneg); 37 phylink_set_port_modes(mask); 38 phylink_set(mask, Pause); 39 phylink_set(mask, Asym_Pause); 40 41 switch (state->interface) { 42 case PHY_INTERFACE_MODE_5GBASER: 43 case PHY_INTERFACE_MODE_10GBASER: 44 case PHY_INTERFACE_MODE_25GBASER: 45 case PHY_INTERFACE_MODE_NA: 46 if (port->conf.bandwidth == SPEED_5000) 47 phylink_set(mask, 5000baseT_Full); 48 if (port->conf.bandwidth == SPEED_10000) { 49 phylink_set(mask, 5000baseT_Full); 50 phylink_set(mask, 10000baseT_Full); 51 phylink_set(mask, 10000baseCR_Full); 52 phylink_set(mask, 10000baseSR_Full); 53 phylink_set(mask, 10000baseLR_Full); 54 phylink_set(mask, 10000baseLRM_Full); 55 phylink_set(mask, 10000baseER_Full); 56 } 57 if (port->conf.bandwidth == SPEED_25000) { 58 phylink_set(mask, 5000baseT_Full); 59 phylink_set(mask, 10000baseT_Full); 60 phylink_set(mask, 10000baseCR_Full); 61 phylink_set(mask, 10000baseSR_Full); 62 phylink_set(mask, 10000baseLR_Full); 63 phylink_set(mask, 10000baseLRM_Full); 64 phylink_set(mask, 10000baseER_Full); 65 phylink_set(mask, 25000baseCR_Full); 66 phylink_set(mask, 25000baseSR_Full); 67 } 68 if (state->interface != PHY_INTERFACE_MODE_NA) 69 break; 70 fallthrough; 71 case PHY_INTERFACE_MODE_SGMII: 72 case PHY_INTERFACE_MODE_QSGMII: 73 phylink_set(mask, 10baseT_Half); 74 phylink_set(mask, 10baseT_Full); 75 phylink_set(mask, 100baseT_Half); 76 phylink_set(mask, 100baseT_Full); 77 phylink_set(mask, 1000baseT_Full); 78 phylink_set(mask, 1000baseX_Full); 79 if (state->interface != PHY_INTERFACE_MODE_NA) 80 break; 81 fallthrough; 82 case PHY_INTERFACE_MODE_1000BASEX: 83 case PHY_INTERFACE_MODE_2500BASEX: 84 if (state->interface != PHY_INTERFACE_MODE_2500BASEX) { 85 phylink_set(mask, 1000baseT_Full); 86 phylink_set(mask, 1000baseX_Full); 87 } 88 if (state->interface == PHY_INTERFACE_MODE_2500BASEX || 89 state->interface == PHY_INTERFACE_MODE_NA) { 90 phylink_set(mask, 2500baseT_Full); 91 phylink_set(mask, 2500baseX_Full); 92 } 93 break; 94 default: 95 bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS); 96 return; 97 } 98 bitmap_and(supported, supported, mask, __ETHTOOL_LINK_MODE_MASK_NBITS); 99 bitmap_and(state->advertising, state->advertising, mask, 100 __ETHTOOL_LINK_MODE_MASK_NBITS); 101 } 102 103 static void sparx5_phylink_mac_config(struct phylink_config *config, 104 unsigned int mode, 105 const struct phylink_link_state *state) 106 { 107 /* Currently not used */ 108 } 109 110 static void sparx5_phylink_mac_link_up(struct phylink_config *config, 111 struct phy_device *phy, 112 unsigned int mode, 113 phy_interface_t interface, 114 int speed, int duplex, 115 bool tx_pause, bool rx_pause) 116 { 117 struct sparx5_port *port = netdev_priv(to_net_dev(config->dev)); 118 struct sparx5_port_config conf; 119 int err; 120 121 conf = port->conf; 122 conf.duplex = duplex; 123 conf.pause = 0; 124 conf.pause |= tx_pause ? MLO_PAUSE_TX : 0; 125 conf.pause |= rx_pause ? MLO_PAUSE_RX : 0; 126 conf.speed = speed; 127 /* Configure the port to speed/duplex/pause */ 128 err = sparx5_port_config(port->sparx5, port, &conf); 129 if (err) 130 netdev_err(port->ndev, "port config failed: %d\n", err); 131 } 132 133 static void sparx5_phylink_mac_link_down(struct phylink_config *config, 134 unsigned int mode, 135 phy_interface_t interface) 136 { 137 /* Currently not used */ 138 } 139 140 static struct sparx5_port *sparx5_pcs_to_port(struct phylink_pcs *pcs) 141 { 142 return container_of(pcs, struct sparx5_port, phylink_pcs); 143 } 144 145 static void sparx5_pcs_get_state(struct phylink_pcs *pcs, 146 struct phylink_link_state *state) 147 { 148 struct sparx5_port *port = sparx5_pcs_to_port(pcs); 149 struct sparx5_port_status status; 150 151 sparx5_get_port_status(port->sparx5, port, &status); 152 state->link = status.link && !status.link_down; 153 state->an_complete = status.an_complete; 154 state->speed = status.speed; 155 state->duplex = status.duplex; 156 state->pause = status.pause; 157 } 158 159 static int sparx5_pcs_config(struct phylink_pcs *pcs, 160 unsigned int mode, 161 phy_interface_t interface, 162 const unsigned long *advertising, 163 bool permit_pause_to_mac) 164 { 165 struct sparx5_port *port = sparx5_pcs_to_port(pcs); 166 struct sparx5_port_config conf; 167 int ret = 0; 168 169 conf = port->conf; 170 conf.power_down = false; 171 conf.portmode = interface; 172 conf.inband = phylink_autoneg_inband(mode); 173 conf.autoneg = phylink_test(advertising, Autoneg); 174 conf.pause_adv = 0; 175 if (phylink_test(advertising, Pause)) 176 conf.pause_adv |= ADVERTISE_1000XPAUSE; 177 if (phylink_test(advertising, Asym_Pause)) 178 conf.pause_adv |= ADVERTISE_1000XPSE_ASYM; 179 if (sparx5_is_baser(interface)) { 180 if (phylink_test(advertising, FIBRE)) 181 conf.media = PHY_MEDIA_SR; 182 else 183 conf.media = PHY_MEDIA_DAC; 184 } 185 if (!port_conf_has_changed(&port->conf, &conf)) 186 return ret; 187 /* Enable the PCS matching this interface type */ 188 ret = sparx5_port_pcs_set(port->sparx5, port, &conf); 189 if (ret) 190 netdev_err(port->ndev, "port PCS config failed: %d\n", ret); 191 return ret; 192 } 193 194 static void sparx5_pcs_aneg_restart(struct phylink_pcs *pcs) 195 { 196 /* Currently not used */ 197 } 198 199 const struct phylink_pcs_ops sparx5_phylink_pcs_ops = { 200 .pcs_get_state = sparx5_pcs_get_state, 201 .pcs_config = sparx5_pcs_config, 202 .pcs_an_restart = sparx5_pcs_aneg_restart, 203 }; 204 205 const struct phylink_mac_ops sparx5_phylink_mac_ops = { 206 .validate = sparx5_phylink_validate, 207 .mac_config = sparx5_phylink_mac_config, 208 .mac_link_down = sparx5_phylink_mac_link_down, 209 .mac_link_up = sparx5_phylink_mac_link_up, 210 }; 211