root/drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. rmnet_vnd_rx_fixup
  2. rmnet_vnd_tx_fixup
  3. rmnet_vnd_start_xmit
  4. rmnet_vnd_change_mtu
  5. rmnet_vnd_get_iflink
  6. rmnet_vnd_init
  7. rmnet_vnd_uninit
  8. rmnet_get_stats64
  9. rmnet_get_strings
  10. rmnet_get_sset_count
  11. rmnet_get_ethtool_stats
  12. rmnet_vnd_setup
  13. rmnet_vnd_newlink
  14. rmnet_vnd_dellink
  15. rmnet_vnd_do_flow_control

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
   3  *
   4  * RMNET Data virtual network driver
   5  */
   6 
   7 #include <linux/etherdevice.h>
   8 #include <linux/if_arp.h>
   9 #include <net/pkt_sched.h>
  10 #include "rmnet_config.h"
  11 #include "rmnet_handlers.h"
  12 #include "rmnet_private.h"
  13 #include "rmnet_map.h"
  14 #include "rmnet_vnd.h"
  15 
  16 /* RX/TX Fixup */
  17 
  18 void rmnet_vnd_rx_fixup(struct sk_buff *skb, struct net_device *dev)
  19 {
  20         struct rmnet_priv *priv = netdev_priv(dev);
  21         struct rmnet_pcpu_stats *pcpu_ptr;
  22 
  23         pcpu_ptr = this_cpu_ptr(priv->pcpu_stats);
  24 
  25         u64_stats_update_begin(&pcpu_ptr->syncp);
  26         pcpu_ptr->stats.rx_pkts++;
  27         pcpu_ptr->stats.rx_bytes += skb->len;
  28         u64_stats_update_end(&pcpu_ptr->syncp);
  29 }
  30 
  31 void rmnet_vnd_tx_fixup(struct sk_buff *skb, struct net_device *dev)
  32 {
  33         struct rmnet_priv *priv = netdev_priv(dev);
  34         struct rmnet_pcpu_stats *pcpu_ptr;
  35 
  36         pcpu_ptr = this_cpu_ptr(priv->pcpu_stats);
  37 
  38         u64_stats_update_begin(&pcpu_ptr->syncp);
  39         pcpu_ptr->stats.tx_pkts++;
  40         pcpu_ptr->stats.tx_bytes += skb->len;
  41         u64_stats_update_end(&pcpu_ptr->syncp);
  42 }
  43 
  44 /* Network Device Operations */
  45 
  46 static netdev_tx_t rmnet_vnd_start_xmit(struct sk_buff *skb,
  47                                         struct net_device *dev)
  48 {
  49         struct rmnet_priv *priv;
  50 
  51         priv = netdev_priv(dev);
  52         if (priv->real_dev) {
  53                 rmnet_egress_handler(skb);
  54         } else {
  55                 this_cpu_inc(priv->pcpu_stats->stats.tx_drops);
  56                 kfree_skb(skb);
  57         }
  58         return NETDEV_TX_OK;
  59 }
  60 
  61 static int rmnet_vnd_change_mtu(struct net_device *rmnet_dev, int new_mtu)
  62 {
  63         if (new_mtu < 0 || new_mtu > RMNET_MAX_PACKET_SIZE)
  64                 return -EINVAL;
  65 
  66         rmnet_dev->mtu = new_mtu;
  67         return 0;
  68 }
  69 
  70 static int rmnet_vnd_get_iflink(const struct net_device *dev)
  71 {
  72         struct rmnet_priv *priv = netdev_priv(dev);
  73 
  74         return priv->real_dev->ifindex;
  75 }
  76 
  77 static int rmnet_vnd_init(struct net_device *dev)
  78 {
  79         struct rmnet_priv *priv = netdev_priv(dev);
  80         int err;
  81 
  82         priv->pcpu_stats = alloc_percpu(struct rmnet_pcpu_stats);
  83         if (!priv->pcpu_stats)
  84                 return -ENOMEM;
  85 
  86         err = gro_cells_init(&priv->gro_cells, dev);
  87         if (err) {
  88                 free_percpu(priv->pcpu_stats);
  89                 return err;
  90         }
  91 
  92         return 0;
  93 }
  94 
  95 static void rmnet_vnd_uninit(struct net_device *dev)
  96 {
  97         struct rmnet_priv *priv = netdev_priv(dev);
  98 
  99         gro_cells_destroy(&priv->gro_cells);
 100         free_percpu(priv->pcpu_stats);
 101 }
 102 
 103 static void rmnet_get_stats64(struct net_device *dev,
 104                               struct rtnl_link_stats64 *s)
 105 {
 106         struct rmnet_priv *priv = netdev_priv(dev);
 107         struct rmnet_vnd_stats total_stats;
 108         struct rmnet_pcpu_stats *pcpu_ptr;
 109         unsigned int cpu, start;
 110 
 111         memset(&total_stats, 0, sizeof(struct rmnet_vnd_stats));
 112 
 113         for_each_possible_cpu(cpu) {
 114                 pcpu_ptr = per_cpu_ptr(priv->pcpu_stats, cpu);
 115 
 116                 do {
 117                         start = u64_stats_fetch_begin_irq(&pcpu_ptr->syncp);
 118                         total_stats.rx_pkts += pcpu_ptr->stats.rx_pkts;
 119                         total_stats.rx_bytes += pcpu_ptr->stats.rx_bytes;
 120                         total_stats.tx_pkts += pcpu_ptr->stats.tx_pkts;
 121                         total_stats.tx_bytes += pcpu_ptr->stats.tx_bytes;
 122                 } while (u64_stats_fetch_retry_irq(&pcpu_ptr->syncp, start));
 123 
 124                 total_stats.tx_drops += pcpu_ptr->stats.tx_drops;
 125         }
 126 
 127         s->rx_packets = total_stats.rx_pkts;
 128         s->rx_bytes = total_stats.rx_bytes;
 129         s->tx_packets = total_stats.tx_pkts;
 130         s->tx_bytes = total_stats.tx_bytes;
 131         s->tx_dropped = total_stats.tx_drops;
 132 }
 133 
 134 static const struct net_device_ops rmnet_vnd_ops = {
 135         .ndo_start_xmit = rmnet_vnd_start_xmit,
 136         .ndo_change_mtu = rmnet_vnd_change_mtu,
 137         .ndo_get_iflink = rmnet_vnd_get_iflink,
 138         .ndo_add_slave  = rmnet_add_bridge,
 139         .ndo_del_slave  = rmnet_del_bridge,
 140         .ndo_init       = rmnet_vnd_init,
 141         .ndo_uninit     = rmnet_vnd_uninit,
 142         .ndo_get_stats64 = rmnet_get_stats64,
 143 };
 144 
 145 static const char rmnet_gstrings_stats[][ETH_GSTRING_LEN] = {
 146         "Checksum ok",
 147         "Checksum valid bit not set",
 148         "Checksum validation failed",
 149         "Checksum error bad buffer",
 150         "Checksum error bad ip version",
 151         "Checksum error bad transport",
 152         "Checksum skipped on ip fragment",
 153         "Checksum skipped",
 154         "Checksum computed in software",
 155 };
 156 
 157 static void rmnet_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
 158 {
 159         switch (stringset) {
 160         case ETH_SS_STATS:
 161                 memcpy(buf, &rmnet_gstrings_stats,
 162                        sizeof(rmnet_gstrings_stats));
 163                 break;
 164         }
 165 }
 166 
 167 static int rmnet_get_sset_count(struct net_device *dev, int sset)
 168 {
 169         switch (sset) {
 170         case ETH_SS_STATS:
 171                 return ARRAY_SIZE(rmnet_gstrings_stats);
 172         default:
 173                 return -EOPNOTSUPP;
 174         }
 175 }
 176 
 177 static void rmnet_get_ethtool_stats(struct net_device *dev,
 178                                     struct ethtool_stats *stats, u64 *data)
 179 {
 180         struct rmnet_priv *priv = netdev_priv(dev);
 181         struct rmnet_priv_stats *st = &priv->stats;
 182 
 183         if (!data)
 184                 return;
 185 
 186         memcpy(data, st, ARRAY_SIZE(rmnet_gstrings_stats) * sizeof(u64));
 187 }
 188 
 189 static const struct ethtool_ops rmnet_ethtool_ops = {
 190         .get_ethtool_stats = rmnet_get_ethtool_stats,
 191         .get_strings = rmnet_get_strings,
 192         .get_sset_count = rmnet_get_sset_count,
 193 };
 194 
 195 /* Called by kernel whenever a new rmnet<n> device is created. Sets MTU,
 196  * flags, ARP type, needed headroom, etc...
 197  */
 198 void rmnet_vnd_setup(struct net_device *rmnet_dev)
 199 {
 200         rmnet_dev->netdev_ops = &rmnet_vnd_ops;
 201         rmnet_dev->mtu = RMNET_DFLT_PACKET_SIZE;
 202         rmnet_dev->needed_headroom = RMNET_NEEDED_HEADROOM;
 203         eth_random_addr(rmnet_dev->dev_addr);
 204         rmnet_dev->tx_queue_len = RMNET_TX_QUEUE_LEN;
 205 
 206         /* Raw IP mode */
 207         rmnet_dev->header_ops = NULL;  /* No header */
 208         rmnet_dev->type = ARPHRD_RAWIP;
 209         rmnet_dev->hard_header_len = 0;
 210         rmnet_dev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST);
 211 
 212         rmnet_dev->needs_free_netdev = true;
 213         rmnet_dev->ethtool_ops = &rmnet_ethtool_ops;
 214 
 215         /* This perm addr will be used as interface identifier by IPv6 */
 216         rmnet_dev->addr_assign_type = NET_ADDR_RANDOM;
 217         eth_random_addr(rmnet_dev->perm_addr);
 218 }
 219 
 220 /* Exposed API */
 221 
 222 int rmnet_vnd_newlink(u8 id, struct net_device *rmnet_dev,
 223                       struct rmnet_port *port,
 224                       struct net_device *real_dev,
 225                       struct rmnet_endpoint *ep)
 226 {
 227         struct rmnet_priv *priv = netdev_priv(rmnet_dev);
 228         int rc;
 229 
 230         if (ep->egress_dev)
 231                 return -EINVAL;
 232 
 233         if (rmnet_get_endpoint(port, id))
 234                 return -EBUSY;
 235 
 236         rmnet_dev->hw_features = NETIF_F_RXCSUM;
 237         rmnet_dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
 238         rmnet_dev->hw_features |= NETIF_F_SG;
 239 
 240         priv->real_dev = real_dev;
 241 
 242         rc = register_netdevice(rmnet_dev);
 243         if (!rc) {
 244                 ep->egress_dev = rmnet_dev;
 245                 ep->mux_id = id;
 246                 port->nr_rmnet_devs++;
 247 
 248                 rmnet_dev->rtnl_link_ops = &rmnet_link_ops;
 249 
 250                 priv->mux_id = id;
 251 
 252                 netdev_dbg(rmnet_dev, "rmnet dev created\n");
 253         }
 254 
 255         return rc;
 256 }
 257 
 258 int rmnet_vnd_dellink(u8 id, struct rmnet_port *port,
 259                       struct rmnet_endpoint *ep)
 260 {
 261         if (id >= RMNET_MAX_LOGICAL_EP || !ep->egress_dev)
 262                 return -EINVAL;
 263 
 264         ep->egress_dev = NULL;
 265         port->nr_rmnet_devs--;
 266         return 0;
 267 }
 268 
 269 int rmnet_vnd_do_flow_control(struct net_device *rmnet_dev, int enable)
 270 {
 271         netdev_dbg(rmnet_dev, "Setting VND TX queue state to %d\n", enable);
 272         /* Although we expect similar number of enable/disable
 273          * commands, optimize for the disable. That is more
 274          * latency sensitive than enable
 275          */
 276         if (unlikely(enable))
 277                 netif_wake_queue(rmnet_dev);
 278         else
 279                 netif_stop_queue(rmnet_dev);
 280 
 281         return 0;
 282 }

/* [<][>][^][v][top][bottom][index][help] */