mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-22 20:24:29 +07:00
009e1b2b7a
rmnet_rtnl_validate() was checking for upto mux_id 254, however the
rmnet_devices devices could hold upto 32 entries only. Fix this by
increasing the size of the rmnet_devices.
Fixes: ceed73a2cf
("drivers: net: ethernet: qualcomm: rmnet: Initial implementation")
Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
Cc: Dan Williams <dcbw@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
168 lines
3.9 KiB
C
168 lines
3.9 KiB
C
/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 and
|
|
* only version 2 as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
*
|
|
* RMNET Data virtual network driver
|
|
*
|
|
*/
|
|
|
|
#include <linux/etherdevice.h>
|
|
#include <linux/if_arp.h>
|
|
#include <net/pkt_sched.h>
|
|
#include "rmnet_config.h"
|
|
#include "rmnet_handlers.h"
|
|
#include "rmnet_private.h"
|
|
#include "rmnet_map.h"
|
|
#include "rmnet_vnd.h"
|
|
|
|
/* RX/TX Fixup */
|
|
|
|
void rmnet_vnd_rx_fixup(struct sk_buff *skb, struct net_device *dev)
|
|
{
|
|
dev->stats.rx_packets++;
|
|
dev->stats.rx_bytes += skb->len;
|
|
}
|
|
|
|
void rmnet_vnd_tx_fixup(struct sk_buff *skb, struct net_device *dev)
|
|
{
|
|
dev->stats.tx_packets++;
|
|
dev->stats.tx_bytes += skb->len;
|
|
}
|
|
|
|
/* Network Device Operations */
|
|
|
|
static netdev_tx_t rmnet_vnd_start_xmit(struct sk_buff *skb,
|
|
struct net_device *dev)
|
|
{
|
|
struct rmnet_priv *priv;
|
|
|
|
priv = netdev_priv(dev);
|
|
if (priv->local_ep.egress_dev) {
|
|
rmnet_egress_handler(skb, &priv->local_ep);
|
|
} else {
|
|
dev->stats.tx_dropped++;
|
|
kfree_skb(skb);
|
|
}
|
|
return NETDEV_TX_OK;
|
|
}
|
|
|
|
static int rmnet_vnd_change_mtu(struct net_device *rmnet_dev, int new_mtu)
|
|
{
|
|
if (new_mtu < 0 || new_mtu > RMNET_MAX_PACKET_SIZE)
|
|
return -EINVAL;
|
|
|
|
rmnet_dev->mtu = new_mtu;
|
|
return 0;
|
|
}
|
|
|
|
static const struct net_device_ops rmnet_vnd_ops = {
|
|
.ndo_start_xmit = rmnet_vnd_start_xmit,
|
|
.ndo_change_mtu = rmnet_vnd_change_mtu,
|
|
};
|
|
|
|
/* Called by kernel whenever a new rmnet<n> device is created. Sets MTU,
|
|
* flags, ARP type, needed headroom, etc...
|
|
*/
|
|
void rmnet_vnd_setup(struct net_device *rmnet_dev)
|
|
{
|
|
netdev_dbg(rmnet_dev, "Setting up device %s\n", rmnet_dev->name);
|
|
|
|
rmnet_dev->netdev_ops = &rmnet_vnd_ops;
|
|
rmnet_dev->mtu = RMNET_DFLT_PACKET_SIZE;
|
|
rmnet_dev->needed_headroom = RMNET_NEEDED_HEADROOM;
|
|
random_ether_addr(rmnet_dev->dev_addr);
|
|
rmnet_dev->tx_queue_len = RMNET_TX_QUEUE_LEN;
|
|
|
|
/* Raw IP mode */
|
|
rmnet_dev->header_ops = NULL; /* No header */
|
|
rmnet_dev->type = ARPHRD_RAWIP;
|
|
rmnet_dev->hard_header_len = 0;
|
|
rmnet_dev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST);
|
|
|
|
rmnet_dev->needs_free_netdev = true;
|
|
}
|
|
|
|
/* Exposed API */
|
|
|
|
int rmnet_vnd_newlink(u8 id, struct net_device *rmnet_dev,
|
|
struct rmnet_real_dev_info *r)
|
|
{
|
|
int rc;
|
|
|
|
if (r->rmnet_devices[id])
|
|
return -EINVAL;
|
|
|
|
rc = register_netdevice(rmnet_dev);
|
|
if (!rc) {
|
|
r->rmnet_devices[id] = rmnet_dev;
|
|
r->nr_rmnet_devs++;
|
|
rmnet_dev->rtnl_link_ops = &rmnet_link_ops;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
int rmnet_vnd_dellink(u8 id, struct rmnet_real_dev_info *r)
|
|
{
|
|
if (id >= RMNET_MAX_LOGICAL_EP || !r->rmnet_devices[id])
|
|
return -EINVAL;
|
|
|
|
r->rmnet_devices[id] = NULL;
|
|
r->nr_rmnet_devs--;
|
|
return 0;
|
|
}
|
|
|
|
u8 rmnet_vnd_get_mux(struct net_device *rmnet_dev)
|
|
{
|
|
struct rmnet_priv *priv;
|
|
|
|
priv = netdev_priv(rmnet_dev);
|
|
return priv->mux_id;
|
|
}
|
|
|
|
void rmnet_vnd_set_mux(struct net_device *rmnet_dev, u8 mux_id)
|
|
{
|
|
struct rmnet_priv *priv;
|
|
|
|
priv = netdev_priv(rmnet_dev);
|
|
priv->mux_id = mux_id;
|
|
}
|
|
|
|
/* Gets the logical endpoint configuration for a RmNet virtual network device
|
|
* node. Caller should confirm that devices is a RmNet VND before calling.
|
|
*/
|
|
struct rmnet_endpoint *rmnet_vnd_get_endpoint(struct net_device *rmnet_dev)
|
|
{
|
|
struct rmnet_priv *priv;
|
|
|
|
if (!rmnet_dev)
|
|
return NULL;
|
|
|
|
priv = netdev_priv(rmnet_dev);
|
|
|
|
return &priv->local_ep;
|
|
}
|
|
|
|
int rmnet_vnd_do_flow_control(struct net_device *rmnet_dev, int enable)
|
|
{
|
|
netdev_dbg(rmnet_dev, "Setting VND TX queue state to %d\n", enable);
|
|
/* Although we expect similar number of enable/disable
|
|
* commands, optimize for the disable. That is more
|
|
* latency sensitive than enable
|
|
*/
|
|
if (unlikely(enable))
|
|
netif_wake_queue(rmnet_dev);
|
|
else
|
|
netif_stop_queue(rmnet_dev);
|
|
|
|
return 0;
|
|
}
|