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 "sparx5_main_regs.h" 8 #include "sparx5_main.h" 9 #include "sparx5_port.h" 10 11 /* The IFH bit position of the first VSTAX bit. This is because the 12 * VSTAX bit positions in Data sheet is starting from zero. 13 */ 14 #define VSTAX 73 15 16 #define ifh_encode_bitfield(ifh, value, pos, _width) \ 17 ({ \ 18 u32 width = (_width); \ 19 \ 20 /* Max width is 5 bytes - 40 bits. In worst case this will 21 * spread over 6 bytes - 48 bits 22 */ \ 23 compiletime_assert(width <= 40, \ 24 "Unsupported width, must be <= 40"); \ 25 __ifh_encode_bitfield((ifh), (value), (pos), width); \ 26 }) 27 28 static void __ifh_encode_bitfield(void *ifh, u64 value, u32 pos, u32 width) 29 { 30 u8 *ifh_hdr = ifh; 31 /* Calculate the Start IFH byte position of this IFH bit position */ 32 u32 byte = (35 - (pos / 8)); 33 /* Calculate the Start bit position in the Start IFH byte */ 34 u32 bit = (pos % 8); 35 u64 encode = GENMASK_ULL(bit + width - 1, bit) & (value << bit); 36 37 /* The b0-b7 goes into the start IFH byte */ 38 if (encode & 0xFF) 39 ifh_hdr[byte] |= (u8)((encode & 0xFF)); 40 /* The b8-b15 goes into the next IFH byte */ 41 if (encode & 0xFF00) 42 ifh_hdr[byte - 1] |= (u8)((encode & 0xFF00) >> 8); 43 /* The b16-b23 goes into the next IFH byte */ 44 if (encode & 0xFF0000) 45 ifh_hdr[byte - 2] |= (u8)((encode & 0xFF0000) >> 16); 46 /* The b24-b31 goes into the next IFH byte */ 47 if (encode & 0xFF000000) 48 ifh_hdr[byte - 3] |= (u8)((encode & 0xFF000000) >> 24); 49 /* The b32-b39 goes into the next IFH byte */ 50 if (encode & 0xFF00000000) 51 ifh_hdr[byte - 4] |= (u8)((encode & 0xFF00000000) >> 32); 52 /* The b40-b47 goes into the next IFH byte */ 53 if (encode & 0xFF0000000000) 54 ifh_hdr[byte - 5] |= (u8)((encode & 0xFF0000000000) >> 40); 55 } 56 57 void sparx5_set_port_ifh(void *ifh_hdr, u16 portno) 58 { 59 /* VSTAX.RSV = 1. MSBit must be 1 */ 60 ifh_encode_bitfield(ifh_hdr, 1, VSTAX + 79, 1); 61 /* VSTAX.INGR_DROP_MODE = Enable. Don't make head-of-line blocking */ 62 ifh_encode_bitfield(ifh_hdr, 1, VSTAX + 55, 1); 63 /* MISC.CPU_MASK/DPORT = Destination port */ 64 ifh_encode_bitfield(ifh_hdr, portno, 29, 8); 65 /* MISC.PIPELINE_PT */ 66 ifh_encode_bitfield(ifh_hdr, 16, 37, 5); 67 /* MISC.PIPELINE_ACT */ 68 ifh_encode_bitfield(ifh_hdr, 1, 42, 3); 69 /* FWD.SRC_PORT = CPU */ 70 ifh_encode_bitfield(ifh_hdr, SPX5_PORT_CPU, 46, 7); 71 /* FWD.SFLOW_ID (disable SFlow sampling) */ 72 ifh_encode_bitfield(ifh_hdr, 124, 57, 7); 73 /* FWD.UPDATE_FCS = Enable. Enforce update of FCS. */ 74 ifh_encode_bitfield(ifh_hdr, 1, 67, 1); 75 } 76 77 void sparx5_set_port_ifh_rew_op(void *ifh_hdr, u32 rew_op) 78 { 79 ifh_encode_bitfield(ifh_hdr, rew_op, VSTAX + 32, 10); 80 } 81 82 void sparx5_set_port_ifh_pdu_type(void *ifh_hdr, u32 pdu_type) 83 { 84 ifh_encode_bitfield(ifh_hdr, pdu_type, 191, 4); 85 } 86 87 void sparx5_set_port_ifh_pdu_w16_offset(void *ifh_hdr, u32 pdu_w16_offset) 88 { 89 ifh_encode_bitfield(ifh_hdr, pdu_w16_offset, 195, 6); 90 } 91 92 void sparx5_set_port_ifh_timestamp(void *ifh_hdr, u64 timestamp) 93 { 94 ifh_encode_bitfield(ifh_hdr, timestamp, 232, 40); 95 } 96 97 static int sparx5_port_open(struct net_device *ndev) 98 { 99 struct sparx5_port *port = netdev_priv(ndev); 100 int err = 0; 101 102 sparx5_port_enable(port, true); 103 err = phylink_of_phy_connect(port->phylink, port->of_node, 0); 104 if (err) { 105 netdev_err(ndev, "Could not attach to PHY\n"); 106 return err; 107 } 108 109 phylink_start(port->phylink); 110 111 if (!ndev->phydev) { 112 /* power up serdes */ 113 port->conf.power_down = false; 114 if (port->conf.serdes_reset) 115 err = sparx5_serdes_set(port->sparx5, port, &port->conf); 116 else 117 err = phy_power_on(port->serdes); 118 if (err) 119 netdev_err(ndev, "%s failed\n", __func__); 120 } 121 122 return err; 123 } 124 125 static int sparx5_port_stop(struct net_device *ndev) 126 { 127 struct sparx5_port *port = netdev_priv(ndev); 128 int err = 0; 129 130 sparx5_port_enable(port, false); 131 phylink_stop(port->phylink); 132 phylink_disconnect_phy(port->phylink); 133 134 if (!ndev->phydev) { 135 /* power down serdes */ 136 port->conf.power_down = true; 137 if (port->conf.serdes_reset) 138 err = sparx5_serdes_set(port->sparx5, port, &port->conf); 139 else 140 err = phy_power_off(port->serdes); 141 if (err) 142 netdev_err(ndev, "%s failed\n", __func__); 143 } 144 return 0; 145 } 146 147 static void sparx5_set_rx_mode(struct net_device *dev) 148 { 149 struct sparx5_port *port = netdev_priv(dev); 150 struct sparx5 *sparx5 = port->sparx5; 151 152 if (!test_bit(port->portno, sparx5->bridge_mask)) 153 __dev_mc_sync(dev, sparx5_mc_sync, sparx5_mc_unsync); 154 } 155 156 static int sparx5_port_get_phys_port_name(struct net_device *dev, 157 char *buf, size_t len) 158 { 159 struct sparx5_port *port = netdev_priv(dev); 160 int ret; 161 162 ret = snprintf(buf, len, "p%d", port->portno); 163 if (ret >= len) 164 return -EINVAL; 165 166 return 0; 167 } 168 169 static int sparx5_set_mac_address(struct net_device *dev, void *p) 170 { 171 struct sparx5_port *port = netdev_priv(dev); 172 struct sparx5 *sparx5 = port->sparx5; 173 const struct sockaddr *addr = p; 174 175 if (!is_valid_ether_addr(addr->sa_data)) 176 return -EADDRNOTAVAIL; 177 178 /* Remove current */ 179 sparx5_mact_forget(sparx5, dev->dev_addr, port->pvid); 180 181 /* Add new */ 182 sparx5_mact_learn(sparx5, PGID_CPU, addr->sa_data, port->pvid); 183 184 /* Record the address */ 185 eth_hw_addr_set(dev, addr->sa_data); 186 187 return 0; 188 } 189 190 static int sparx5_get_port_parent_id(struct net_device *dev, 191 struct netdev_phys_item_id *ppid) 192 { 193 struct sparx5_port *sparx5_port = netdev_priv(dev); 194 struct sparx5 *sparx5 = sparx5_port->sparx5; 195 196 ppid->id_len = sizeof(sparx5->base_mac); 197 memcpy(&ppid->id, &sparx5->base_mac, ppid->id_len); 198 199 return 0; 200 } 201 202 static int sparx5_port_ioctl(struct net_device *dev, struct ifreq *ifr, 203 int cmd) 204 { 205 struct sparx5_port *sparx5_port = netdev_priv(dev); 206 struct sparx5 *sparx5 = sparx5_port->sparx5; 207 208 if (!phy_has_hwtstamp(dev->phydev) && sparx5->ptp) { 209 switch (cmd) { 210 case SIOCSHWTSTAMP: 211 return sparx5_ptp_hwtstamp_set(sparx5_port, ifr); 212 case SIOCGHWTSTAMP: 213 return sparx5_ptp_hwtstamp_get(sparx5_port, ifr); 214 } 215 } 216 217 return phy_mii_ioctl(dev->phydev, ifr, cmd); 218 } 219 220 static const struct net_device_ops sparx5_port_netdev_ops = { 221 .ndo_open = sparx5_port_open, 222 .ndo_stop = sparx5_port_stop, 223 .ndo_start_xmit = sparx5_port_xmit_impl, 224 .ndo_set_rx_mode = sparx5_set_rx_mode, 225 .ndo_get_phys_port_name = sparx5_port_get_phys_port_name, 226 .ndo_set_mac_address = sparx5_set_mac_address, 227 .ndo_validate_addr = eth_validate_addr, 228 .ndo_get_stats64 = sparx5_get_stats64, 229 .ndo_get_port_parent_id = sparx5_get_port_parent_id, 230 .ndo_eth_ioctl = sparx5_port_ioctl, 231 }; 232 233 bool sparx5_netdevice_check(const struct net_device *dev) 234 { 235 return dev && (dev->netdev_ops == &sparx5_port_netdev_ops); 236 } 237 238 struct net_device *sparx5_create_netdev(struct sparx5 *sparx5, u32 portno) 239 { 240 struct sparx5_port *spx5_port; 241 struct net_device *ndev; 242 243 ndev = devm_alloc_etherdev(sparx5->dev, sizeof(struct sparx5_port)); 244 if (!ndev) 245 return ERR_PTR(-ENOMEM); 246 247 SET_NETDEV_DEV(ndev, sparx5->dev); 248 spx5_port = netdev_priv(ndev); 249 spx5_port->ndev = ndev; 250 spx5_port->sparx5 = sparx5; 251 spx5_port->portno = portno; 252 253 ndev->netdev_ops = &sparx5_port_netdev_ops; 254 ndev->ethtool_ops = &sparx5_ethtool_ops; 255 256 eth_hw_addr_gen(ndev, sparx5->base_mac, portno + 1); 257 258 return ndev; 259 } 260 261 int sparx5_register_netdevs(struct sparx5 *sparx5) 262 { 263 int portno; 264 int err; 265 266 for (portno = 0; portno < SPX5_PORTS; portno++) 267 if (sparx5->ports[portno]) { 268 err = register_netdev(sparx5->ports[portno]->ndev); 269 if (err) { 270 dev_err(sparx5->dev, 271 "port: %02u: netdev registration failed\n", 272 portno); 273 return err; 274 } 275 sparx5_port_inj_timer_setup(sparx5->ports[portno]); 276 } 277 return 0; 278 } 279 280 void sparx5_destroy_netdevs(struct sparx5 *sparx5) 281 { 282 struct sparx5_port *port; 283 int portno; 284 285 for (portno = 0; portno < SPX5_PORTS; portno++) { 286 port = sparx5->ports[portno]; 287 if (port && port->phylink) { 288 /* Disconnect the phy */ 289 rtnl_lock(); 290 sparx5_port_stop(port->ndev); 291 phylink_disconnect_phy(port->phylink); 292 rtnl_unlock(); 293 phylink_destroy(port->phylink); 294 port->phylink = NULL; 295 } 296 } 297 } 298 299 void sparx5_unregister_netdevs(struct sparx5 *sparx5) 300 { 301 int portno; 302 303 for (portno = 0; portno < SPX5_PORTS; portno++) 304 if (sparx5->ports[portno]) 305 unregister_netdev(sparx5->ports[portno]->ndev); 306 } 307 308