2017-01-23 22:09:12 -08:00
/*
* aQuantia Corporation Network Driver
* Copyright ( C ) 2014 - 2017 aQuantia Corporation . All rights reserved
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
*/
/* File aq_main.c: Main file for aQuantia Linux driver. */
# include "aq_main.h"
# include "aq_nic.h"
# include "aq_pci_func.h"
# include "aq_ethtool.h"
# include <linux/netdevice.h>
# include <linux/module.h>
MODULE_LICENSE ( " GPL v2 " ) ;
MODULE_VERSION ( AQ_CFG_DRV_VERSION ) ;
MODULE_AUTHOR ( AQ_CFG_DRV_AUTHOR ) ;
MODULE_DESCRIPTION ( AQ_CFG_DRV_DESC ) ;
2018-01-15 16:41:18 +03:00
static const struct net_device_ops aq_ndev_ops ;
struct net_device * aq_ndev_alloc ( void )
2017-01-23 22:09:12 -08:00
{
2018-01-15 16:41:18 +03:00
struct net_device * ndev = NULL ;
struct aq_nic_s * aq_nic = NULL ;
2017-01-23 22:09:12 -08:00
2018-01-15 16:41:18 +03:00
ndev = alloc_etherdev_mq ( sizeof ( struct aq_nic_s ) , AQ_CFG_VECS_MAX ) ;
if ( ! ndev )
return NULL ;
2017-01-23 22:09:12 -08:00
2018-01-15 16:41:18 +03:00
aq_nic = netdev_priv ( ndev ) ;
aq_nic - > ndev = ndev ;
ndev - > netdev_ops = & aq_ndev_ops ;
ndev - > ethtool_ops = & aq_ethtool_ops ;
return ndev ;
2017-01-23 22:09:12 -08:00
}
static int aq_ndev_open ( struct net_device * ndev )
{
int err = 0 ;
2018-01-19 17:03:21 +03:00
struct aq_nic_s * aq_nic = netdev_priv ( ndev ) ;
2017-01-23 22:09:12 -08:00
err = aq_nic_init ( aq_nic ) ;
if ( err < 0 )
goto err_exit ;
err = aq_nic_start ( aq_nic ) ;
if ( err < 0 )
goto err_exit ;
err_exit :
if ( err < 0 )
aq_nic_deinit ( aq_nic ) ;
return err ;
}
static int aq_ndev_close ( struct net_device * ndev )
{
int err = 0 ;
struct aq_nic_s * aq_nic = netdev_priv ( ndev ) ;
err = aq_nic_stop ( aq_nic ) ;
if ( err < 0 )
goto err_exit ;
aq_nic_deinit ( aq_nic ) ;
err_exit :
return err ;
}
static int aq_ndev_start_xmit ( struct sk_buff * skb , struct net_device * ndev )
{
struct aq_nic_s * aq_nic = netdev_priv ( ndev ) ;
2017-02-20 22:36:43 +03:00
return aq_nic_xmit ( aq_nic , skb ) ;
2017-01-23 22:09:12 -08:00
}
static int aq_ndev_change_mtu ( struct net_device * ndev , int new_mtu )
{
struct aq_nic_s * aq_nic = netdev_priv ( ndev ) ;
2017-02-20 22:36:41 +03:00
int err = aq_nic_set_mtu ( aq_nic , new_mtu + ETH_HLEN ) ;
2017-01-23 22:09:12 -08:00
if ( err < 0 )
goto err_exit ;
2017-03-13 19:07:16 -04:00
ndev - > mtu = new_mtu ;
2017-01-23 22:09:12 -08:00
err_exit :
return err ;
}
static int aq_ndev_set_features ( struct net_device * ndev ,
netdev_features_t features )
{
struct aq_nic_s * aq_nic = netdev_priv ( ndev ) ;
struct aq_nic_cfg_s * aq_cfg = aq_nic_get_cfg ( aq_nic ) ;
bool is_lro = false ;
if ( aq_cfg - > hw_features & NETIF_F_LRO ) {
is_lro = features & NETIF_F_LRO ;
if ( aq_cfg - > is_lro ! = is_lro ) {
aq_cfg - > is_lro = is_lro ;
if ( netif_running ( ndev ) ) {
aq_ndev_close ( ndev ) ;
aq_ndev_open ( ndev ) ;
}
}
}
return 0 ;
}
static int aq_ndev_set_mac_address ( struct net_device * ndev , void * addr )
{
struct aq_nic_s * aq_nic = netdev_priv ( ndev ) ;
int err = 0 ;
err = eth_mac_addr ( ndev , addr ) ;
if ( err < 0 )
goto err_exit ;
err = aq_nic_set_mac ( aq_nic , ndev ) ;
if ( err < 0 )
goto err_exit ;
err_exit :
return err ;
}
static void aq_ndev_set_multicast_settings ( struct net_device * ndev )
{
struct aq_nic_s * aq_nic = netdev_priv ( ndev ) ;
2018-07-05 17:01:09 +03:00
aq_nic_set_packet_filter ( aq_nic , ndev - > flags ) ;
2017-01-23 22:09:12 -08:00
2018-07-05 17:01:09 +03:00
aq_nic_set_multicast_list ( aq_nic , ndev ) ;
2017-01-23 22:09:12 -08:00
}
static const struct net_device_ops aq_ndev_ops = {
. ndo_open = aq_ndev_open ,
. ndo_stop = aq_ndev_close ,
. ndo_start_xmit = aq_ndev_start_xmit ,
. ndo_set_rx_mode = aq_ndev_set_multicast_settings ,
. ndo_change_mtu = aq_ndev_change_mtu ,
. ndo_set_mac_address = aq_ndev_set_mac_address ,
. ndo_set_features = aq_ndev_set_features
} ;