Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /* Microchip Sparx5 Switch driver
0003  *
0004  * Copyright (c) 2021 Microchip Technology Inc. and its subsidiaries.
0005  */
0006 
0007 #include "sparx5_main_regs.h"
0008 #include "sparx5_main.h"
0009 #include "sparx5_port.h"
0010 
0011 /* The IFH bit position of the first VSTAX bit. This is because the
0012  * VSTAX bit positions in Data sheet is starting from zero.
0013  */
0014 #define VSTAX 73
0015 
0016 #define ifh_encode_bitfield(ifh, value, pos, _width)            \
0017     ({                              \
0018         u32 width = (_width);                   \
0019                                     \
0020         /* Max width is 5 bytes - 40 bits. In worst case this will
0021          * spread over 6 bytes - 48 bits
0022          */                         \
0023         compiletime_assert(width <= 40,             \
0024                    "Unsupported width, must be <= 40"); \
0025         __ifh_encode_bitfield((ifh), (value), (pos), width);    \
0026     })
0027 
0028 static void __ifh_encode_bitfield(void *ifh, u64 value, u32 pos, u32 width)
0029 {
0030     u8 *ifh_hdr = ifh;
0031     /* Calculate the Start IFH byte position of this IFH bit position */
0032     u32 byte = (35 - (pos / 8));
0033     /* Calculate the Start bit position in the Start IFH byte */
0034     u32 bit  = (pos % 8);
0035     u64 encode = GENMASK_ULL(bit + width - 1, bit) & (value << bit);
0036 
0037     /* The b0-b7 goes into the start IFH byte */
0038     if (encode & 0xFF)
0039         ifh_hdr[byte] |= (u8)((encode & 0xFF));
0040     /* The b8-b15 goes into the next IFH byte */
0041     if (encode & 0xFF00)
0042         ifh_hdr[byte - 1] |= (u8)((encode & 0xFF00) >> 8);
0043     /* The b16-b23 goes into the next IFH byte */
0044     if (encode & 0xFF0000)
0045         ifh_hdr[byte - 2] |= (u8)((encode & 0xFF0000) >> 16);
0046     /* The b24-b31 goes into the next IFH byte */
0047     if (encode & 0xFF000000)
0048         ifh_hdr[byte - 3] |= (u8)((encode & 0xFF000000) >> 24);
0049     /* The b32-b39 goes into the next IFH byte */
0050     if (encode & 0xFF00000000)
0051         ifh_hdr[byte - 4] |= (u8)((encode & 0xFF00000000) >> 32);
0052     /* The b40-b47 goes into the next IFH byte */
0053     if (encode & 0xFF0000000000)
0054         ifh_hdr[byte - 5] |= (u8)((encode & 0xFF0000000000) >> 40);
0055 }
0056 
0057 void sparx5_set_port_ifh(void *ifh_hdr, u16 portno)
0058 {
0059     /* VSTAX.RSV = 1. MSBit must be 1 */
0060     ifh_encode_bitfield(ifh_hdr, 1, VSTAX + 79,  1);
0061     /* VSTAX.INGR_DROP_MODE = Enable. Don't make head-of-line blocking */
0062     ifh_encode_bitfield(ifh_hdr, 1, VSTAX + 55,  1);
0063     /* MISC.CPU_MASK/DPORT = Destination port */
0064     ifh_encode_bitfield(ifh_hdr, portno,   29, 8);
0065     /* MISC.PIPELINE_PT */
0066     ifh_encode_bitfield(ifh_hdr, 16,       37, 5);
0067     /* MISC.PIPELINE_ACT */
0068     ifh_encode_bitfield(ifh_hdr, 1,        42, 3);
0069     /* FWD.SRC_PORT = CPU */
0070     ifh_encode_bitfield(ifh_hdr, SPX5_PORT_CPU, 46, 7);
0071     /* FWD.SFLOW_ID (disable SFlow sampling) */
0072     ifh_encode_bitfield(ifh_hdr, 124,      57, 7);
0073     /* FWD.UPDATE_FCS = Enable. Enforce update of FCS. */
0074     ifh_encode_bitfield(ifh_hdr, 1,        67, 1);
0075 }
0076 
0077 void sparx5_set_port_ifh_rew_op(void *ifh_hdr, u32 rew_op)
0078 {
0079     ifh_encode_bitfield(ifh_hdr, rew_op, VSTAX + 32,  10);
0080 }
0081 
0082 void sparx5_set_port_ifh_pdu_type(void *ifh_hdr, u32 pdu_type)
0083 {
0084     ifh_encode_bitfield(ifh_hdr, pdu_type, 191, 4);
0085 }
0086 
0087 void sparx5_set_port_ifh_pdu_w16_offset(void *ifh_hdr, u32 pdu_w16_offset)
0088 {
0089     ifh_encode_bitfield(ifh_hdr, pdu_w16_offset, 195, 6);
0090 }
0091 
0092 void sparx5_set_port_ifh_timestamp(void *ifh_hdr, u64 timestamp)
0093 {
0094     ifh_encode_bitfield(ifh_hdr, timestamp, 232,  40);
0095 }
0096 
0097 static int sparx5_port_open(struct net_device *ndev)
0098 {
0099     struct sparx5_port *port = netdev_priv(ndev);
0100     int err = 0;
0101 
0102     sparx5_port_enable(port, true);
0103     err = phylink_of_phy_connect(port->phylink, port->of_node, 0);
0104     if (err) {
0105         netdev_err(ndev, "Could not attach to PHY\n");
0106         return err;
0107     }
0108 
0109     phylink_start(port->phylink);
0110 
0111     if (!ndev->phydev) {
0112         /* power up serdes */
0113         port->conf.power_down = false;
0114         if (port->conf.serdes_reset)
0115             err = sparx5_serdes_set(port->sparx5, port, &port->conf);
0116         else
0117             err = phy_power_on(port->serdes);
0118         if (err)
0119             netdev_err(ndev, "%s failed\n", __func__);
0120     }
0121 
0122     return err;
0123 }
0124 
0125 static int sparx5_port_stop(struct net_device *ndev)
0126 {
0127     struct sparx5_port *port = netdev_priv(ndev);
0128     int err = 0;
0129 
0130     sparx5_port_enable(port, false);
0131     phylink_stop(port->phylink);
0132     phylink_disconnect_phy(port->phylink);
0133 
0134     if (!ndev->phydev) {
0135         /* power down serdes */
0136         port->conf.power_down = true;
0137         if (port->conf.serdes_reset)
0138             err = sparx5_serdes_set(port->sparx5, port, &port->conf);
0139         else
0140             err = phy_power_off(port->serdes);
0141         if (err)
0142             netdev_err(ndev, "%s failed\n", __func__);
0143     }
0144     return 0;
0145 }
0146 
0147 static void sparx5_set_rx_mode(struct net_device *dev)
0148 {
0149     struct sparx5_port *port = netdev_priv(dev);
0150     struct sparx5 *sparx5 = port->sparx5;
0151 
0152     if (!test_bit(port->portno, sparx5->bridge_mask))
0153         __dev_mc_sync(dev, sparx5_mc_sync, sparx5_mc_unsync);
0154 }
0155 
0156 static int sparx5_port_get_phys_port_name(struct net_device *dev,
0157                       char *buf, size_t len)
0158 {
0159     struct sparx5_port *port = netdev_priv(dev);
0160     int ret;
0161 
0162     ret = snprintf(buf, len, "p%d", port->portno);
0163     if (ret >= len)
0164         return -EINVAL;
0165 
0166     return 0;
0167 }
0168 
0169 static int sparx5_set_mac_address(struct net_device *dev, void *p)
0170 {
0171     struct sparx5_port *port = netdev_priv(dev);
0172     struct sparx5 *sparx5 = port->sparx5;
0173     const struct sockaddr *addr = p;
0174 
0175     if (!is_valid_ether_addr(addr->sa_data))
0176         return -EADDRNOTAVAIL;
0177 
0178     /* Remove current */
0179     sparx5_mact_forget(sparx5, dev->dev_addr,  port->pvid);
0180 
0181     /* Add new */
0182     sparx5_mact_learn(sparx5, PGID_CPU, addr->sa_data, port->pvid);
0183 
0184     /* Record the address */
0185     eth_hw_addr_set(dev, addr->sa_data);
0186 
0187     return 0;
0188 }
0189 
0190 static int sparx5_get_port_parent_id(struct net_device *dev,
0191                      struct netdev_phys_item_id *ppid)
0192 {
0193     struct sparx5_port *sparx5_port = netdev_priv(dev);
0194     struct sparx5 *sparx5 = sparx5_port->sparx5;
0195 
0196     ppid->id_len = sizeof(sparx5->base_mac);
0197     memcpy(&ppid->id, &sparx5->base_mac, ppid->id_len);
0198 
0199     return 0;
0200 }
0201 
0202 static int sparx5_port_ioctl(struct net_device *dev, struct ifreq *ifr,
0203                  int cmd)
0204 {
0205     struct sparx5_port *sparx5_port = netdev_priv(dev);
0206     struct sparx5 *sparx5 = sparx5_port->sparx5;
0207 
0208     if (!phy_has_hwtstamp(dev->phydev) && sparx5->ptp) {
0209         switch (cmd) {
0210         case SIOCSHWTSTAMP:
0211             return sparx5_ptp_hwtstamp_set(sparx5_port, ifr);
0212         case SIOCGHWTSTAMP:
0213             return sparx5_ptp_hwtstamp_get(sparx5_port, ifr);
0214         }
0215     }
0216 
0217     return phy_mii_ioctl(dev->phydev, ifr, cmd);
0218 }
0219 
0220 static const struct net_device_ops sparx5_port_netdev_ops = {
0221     .ndo_open               = sparx5_port_open,
0222     .ndo_stop               = sparx5_port_stop,
0223     .ndo_start_xmit         = sparx5_port_xmit_impl,
0224     .ndo_set_rx_mode        = sparx5_set_rx_mode,
0225     .ndo_get_phys_port_name = sparx5_port_get_phys_port_name,
0226     .ndo_set_mac_address    = sparx5_set_mac_address,
0227     .ndo_validate_addr      = eth_validate_addr,
0228     .ndo_get_stats64        = sparx5_get_stats64,
0229     .ndo_get_port_parent_id = sparx5_get_port_parent_id,
0230     .ndo_eth_ioctl          = sparx5_port_ioctl,
0231 };
0232 
0233 bool sparx5_netdevice_check(const struct net_device *dev)
0234 {
0235     return dev && (dev->netdev_ops == &sparx5_port_netdev_ops);
0236 }
0237 
0238 struct net_device *sparx5_create_netdev(struct sparx5 *sparx5, u32 portno)
0239 {
0240     struct sparx5_port *spx5_port;
0241     struct net_device *ndev;
0242 
0243     ndev = devm_alloc_etherdev(sparx5->dev, sizeof(struct sparx5_port));
0244     if (!ndev)
0245         return ERR_PTR(-ENOMEM);
0246 
0247     SET_NETDEV_DEV(ndev, sparx5->dev);
0248     spx5_port = netdev_priv(ndev);
0249     spx5_port->ndev = ndev;
0250     spx5_port->sparx5 = sparx5;
0251     spx5_port->portno = portno;
0252 
0253     ndev->netdev_ops = &sparx5_port_netdev_ops;
0254     ndev->ethtool_ops = &sparx5_ethtool_ops;
0255 
0256     eth_hw_addr_gen(ndev, sparx5->base_mac, portno + 1);
0257 
0258     return ndev;
0259 }
0260 
0261 int sparx5_register_netdevs(struct sparx5 *sparx5)
0262 {
0263     int portno;
0264     int err;
0265 
0266     for (portno = 0; portno < SPX5_PORTS; portno++)
0267         if (sparx5->ports[portno]) {
0268             err = register_netdev(sparx5->ports[portno]->ndev);
0269             if (err) {
0270                 dev_err(sparx5->dev,
0271                     "port: %02u: netdev registration failed\n",
0272                     portno);
0273                 return err;
0274             }
0275             sparx5_port_inj_timer_setup(sparx5->ports[portno]);
0276         }
0277     return 0;
0278 }
0279 
0280 void sparx5_destroy_netdevs(struct sparx5 *sparx5)
0281 {
0282     struct sparx5_port *port;
0283     int portno;
0284 
0285     for (portno = 0; portno < SPX5_PORTS; portno++) {
0286         port = sparx5->ports[portno];
0287         if (port && port->phylink) {
0288             /* Disconnect the phy */
0289             rtnl_lock();
0290             sparx5_port_stop(port->ndev);
0291             phylink_disconnect_phy(port->phylink);
0292             rtnl_unlock();
0293             phylink_destroy(port->phylink);
0294             port->phylink = NULL;
0295         }
0296     }
0297 }
0298 
0299 void sparx5_unregister_netdevs(struct sparx5 *sparx5)
0300 {
0301     int portno;
0302 
0303     for (portno = 0; portno < SPX5_PORTS; portno++)
0304         if (sparx5->ports[portno])
0305             unregister_netdev(sparx5->ports[portno]->ndev);
0306 }
0307