2009-03-11 23:32:03 -07:00
/*
2013-03-06 20:05:05 +00:00
* Copyright ( C ) 2005 - 2013 Emulex
2009-03-11 23:32:03 -07:00
* 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
* as published by the Free Software Foundation . The full GNU General
* Public License is included in this distribution in the file called COPYING .
*
* Contact Information :
2011-03-16 08:20:46 +00:00
* linux - drivers @ emulex . com
2009-03-11 23:32:03 -07:00
*
2011-03-16 08:20:46 +00:00
* Emulex
* 3333 Susan Street
* Costa Mesa , CA 92626
2009-03-11 23:32:03 -07:00
*/
# include "be.h"
2009-07-27 22:52:03 +00:00
# include "be_cmds.h"
2009-03-11 23:32:03 -07:00
# include <linux/ethtool.h>
struct be_ethtool_stat {
char desc [ ETH_GSTRING_LEN ] ;
int type ;
int size ;
int offset ;
} ;
2011-07-25 19:10:14 +00:00
enum { DRVSTAT_TX , DRVSTAT_RX , DRVSTAT } ;
2009-03-11 23:32:03 -07:00
# define FIELDINFO(_struct, field) FIELD_SIZEOF(_struct, field), \
offsetof ( _struct , field )
2010-10-03 22:12:27 -07:00
# define DRVSTAT_TX_INFO(field) #field, DRVSTAT_TX,\
FIELDINFO ( struct be_tx_stats , field )
# define DRVSTAT_RX_INFO(field) #field, DRVSTAT_RX,\
FIELDINFO ( struct be_rx_stats , field )
2011-02-20 11:42:07 +00:00
# define DRVSTAT_INFO(field) #field, DRVSTAT,\
2011-07-25 19:10:14 +00:00
FIELDINFO ( struct be_drv_stats , field )
2009-03-11 23:32:03 -07:00
static const struct be_ethtool_stat et_stats [ ] = {
2011-05-16 07:36:18 +00:00
{ DRVSTAT_INFO ( rx_crc_errors ) } ,
{ DRVSTAT_INFO ( rx_alignment_symbol_errors ) } ,
{ DRVSTAT_INFO ( rx_pause_frames ) } ,
{ DRVSTAT_INFO ( rx_control_frames ) } ,
2012-01-29 20:17:39 +00:00
/* Received packets dropped when the Ethernet length field
* is not equal to the actual Ethernet data length .
*/
2011-05-16 07:36:18 +00:00
{ DRVSTAT_INFO ( rx_in_range_errors ) } ,
2012-01-29 20:17:39 +00:00
/* Received packets dropped when their length field is >= 1501 bytes
* and < = 1535 bytes .
*/
2011-05-16 07:36:18 +00:00
{ DRVSTAT_INFO ( rx_out_range_errors ) } ,
2012-01-29 20:17:39 +00:00
/* Received packets dropped when they are longer than 9216 bytes */
2011-05-16 07:36:18 +00:00
{ DRVSTAT_INFO ( rx_frame_too_long ) } ,
2012-01-29 20:17:39 +00:00
/* Received packets dropped when they don't pass the unicast or
* multicast address filtering .
*/
2013-04-25 23:03:21 +00:00
{ DRVSTAT_INFO ( rx_address_filtered ) } ,
2012-01-29 20:17:39 +00:00
/* Received packets dropped when IP packet length field is less than
* the IP header length field .
*/
2011-05-16 07:36:18 +00:00
{ DRVSTAT_INFO ( rx_dropped_too_small ) } ,
2012-01-29 20:17:39 +00:00
/* Received packets dropped when IP length field is greater than
* the actual packet length .
*/
2011-05-16 07:36:18 +00:00
{ DRVSTAT_INFO ( rx_dropped_too_short ) } ,
2012-01-29 20:17:39 +00:00
/* Received packets dropped when the IP header length field is less
* than 5.
*/
2011-05-16 07:36:18 +00:00
{ DRVSTAT_INFO ( rx_dropped_header_too_small ) } ,
2012-01-29 20:17:39 +00:00
/* Received packets dropped when the TCP header length field is less
* than 5 or the TCP header length + IP header length is more
* than IP packet length .
*/
2011-05-16 07:36:18 +00:00
{ DRVSTAT_INFO ( rx_dropped_tcp_length ) } ,
{ DRVSTAT_INFO ( rx_dropped_runt ) } ,
2012-01-29 20:17:39 +00:00
/* Number of received packets dropped when a fifo for descriptors going
* into the packet demux block overflows . In normal operation , this
* fifo must never overflow .
*/
2011-05-16 07:36:18 +00:00
{ DRVSTAT_INFO ( rxpp_fifo_overflow_drop ) } ,
{ DRVSTAT_INFO ( rx_input_fifo_overflow_drop ) } ,
{ DRVSTAT_INFO ( rx_ip_checksum_errs ) } ,
{ DRVSTAT_INFO ( rx_tcp_checksum_errs ) } ,
{ DRVSTAT_INFO ( rx_udp_checksum_errs ) } ,
{ DRVSTAT_INFO ( tx_pauseframes ) } ,
{ DRVSTAT_INFO ( tx_controlframes ) } ,
{ DRVSTAT_INFO ( rx_priority_pause_frames ) } ,
2013-05-01 09:38:00 +00:00
{ DRVSTAT_INFO ( tx_priority_pauseframes ) } ,
2012-01-29 20:17:39 +00:00
/* Received packets dropped when an internal fifo going into
* main packet buffer tank ( PMEM ) overflows .
*/
2011-05-16 07:36:18 +00:00
{ DRVSTAT_INFO ( pmem_fifo_overflow_drop ) } ,
{ DRVSTAT_INFO ( jabber_events ) } ,
2012-01-29 20:17:39 +00:00
/* Received packets dropped due to lack of available HW packet buffers
* used to temporarily hold the received packets .
*/
2011-05-16 07:36:18 +00:00
{ DRVSTAT_INFO ( rx_drops_no_pbuf ) } ,
2012-01-29 20:17:39 +00:00
/* Received packets dropped due to input receive buffer
* descriptor fifo overflowing .
*/
2011-05-16 07:36:18 +00:00
{ DRVSTAT_INFO ( rx_drops_no_erx_descr ) } ,
2012-01-29 20:17:39 +00:00
/* Packets dropped because the internal FIFO to the offloaded TCP
* receive processing block is full . This could happen only for
* offloaded iSCSI or FCoE trarffic .
*/
2011-05-16 07:36:18 +00:00
{ DRVSTAT_INFO ( rx_drops_no_tpre_descr ) } ,
2012-01-29 20:17:39 +00:00
/* Received packets dropped when they need more than 8
* receive buffers . This cannot happen as the driver configures
* 2048 byte receive buffers .
*/
2011-05-16 07:36:18 +00:00
{ DRVSTAT_INFO ( rx_drops_too_many_frags ) } ,
{ DRVSTAT_INFO ( forwarded_packets ) } ,
2012-01-29 20:17:39 +00:00
/* Received packets dropped when the frame length
* is more than 9018 bytes
*/
2011-05-16 07:36:18 +00:00
{ DRVSTAT_INFO ( rx_drops_mtu ) } ,
2012-01-29 20:17:39 +00:00
/* Number of packets dropped due to random early drop function */
2011-05-16 07:36:18 +00:00
{ DRVSTAT_INFO ( eth_red_drops ) } ,
2013-10-03 16:16:50 -05:00
{ DRVSTAT_INFO ( be_on_die_temperature ) } ,
{ DRVSTAT_INFO ( rx_roce_bytes_lsd ) } ,
{ DRVSTAT_INFO ( rx_roce_bytes_msd ) } ,
{ DRVSTAT_INFO ( rx_roce_frames ) } ,
{ DRVSTAT_INFO ( roce_drops_payload_len ) } ,
{ DRVSTAT_INFO ( roce_drops_crc ) }
2009-03-11 23:32:03 -07:00
} ;
# define ETHTOOL_STATS_NUM ARRAY_SIZE(et_stats)
2011-07-25 19:10:15 +00:00
/* Stats related to multi RX queues: get_stats routine assumes bytes, pkts
* are first and second members respectively .
*/
2010-10-03 22:12:27 -07:00
static const struct be_ethtool_stat et_rx_stats [ ] = {
2011-07-25 19:10:15 +00:00
{ DRVSTAT_RX_INFO ( rx_bytes ) } , /* If moving this member see above note */
{ DRVSTAT_RX_INFO ( rx_pkts ) } , /* If moving this member see above note */
2010-10-03 22:12:27 -07:00
{ DRVSTAT_RX_INFO ( rx_compl ) } ,
{ DRVSTAT_RX_INFO ( rx_mcast_pkts ) } ,
2012-01-29 20:17:39 +00:00
/* Number of page allocation failures while posting receive buffers
* to HW .
*/
2010-10-03 22:12:27 -07:00
{ DRVSTAT_RX_INFO ( rx_post_fail ) } ,
2012-01-29 20:17:39 +00:00
/* Recevied packets dropped due to skb allocation failure */
2011-07-25 19:10:14 +00:00
{ DRVSTAT_RX_INFO ( rx_drops_no_skbs ) } ,
2012-01-29 20:17:39 +00:00
/* Received packets dropped due to lack of available fetched buffers
* posted by the driver .
*/
2011-07-25 19:10:14 +00:00
{ DRVSTAT_RX_INFO ( rx_drops_no_frags ) }
2010-10-03 22:12:27 -07:00
} ;
# define ETHTOOL_RXSTATS_NUM (ARRAY_SIZE(et_rx_stats))
2011-07-25 19:10:15 +00:00
/* Stats related to multi TX queues: get_stats routine assumes compl is the
* first member
*/
2011-06-12 20:01:58 +00:00
static const struct be_ethtool_stat et_tx_stats [ ] = {
2011-07-25 19:10:15 +00:00
{ DRVSTAT_TX_INFO ( tx_compl ) } , /* If moving this member see above note */
2011-07-25 19:10:14 +00:00
{ DRVSTAT_TX_INFO ( tx_bytes ) } ,
{ DRVSTAT_TX_INFO ( tx_pkts ) } ,
2012-01-29 20:17:39 +00:00
/* Number of skbs queued for trasmission by the driver */
2011-07-25 19:10:14 +00:00
{ DRVSTAT_TX_INFO ( tx_reqs ) } ,
2012-01-29 20:17:39 +00:00
/* Number of TX work request blocks DMAed to HW */
2011-07-25 19:10:14 +00:00
{ DRVSTAT_TX_INFO ( tx_wrbs ) } ,
2012-01-29 20:17:39 +00:00
/* Number of times the TX queue was stopped due to lack
* of spaces in the TXQ .
*/
2013-10-01 16:00:01 +05:30
{ DRVSTAT_TX_INFO ( tx_stops ) } ,
/* Pkts dropped in the driver's transmit path */
{ DRVSTAT_TX_INFO ( tx_drv_drops ) }
2011-06-12 20:01:58 +00:00
} ;
# define ETHTOOL_TXSTATS_NUM (ARRAY_SIZE(et_tx_stats))
2009-12-03 16:15:52 -08:00
static const char et_self_tests [ ] [ ETH_GSTRING_LEN ] = {
" MAC Loopback test " ,
" PHY Loopback test " ,
" External Loopback test " ,
2011-02-20 11:41:20 +00:00
" DDR DMA test " ,
2010-01-19 05:15:36 +00:00
" Link test "
2009-12-03 16:15:52 -08:00
} ;
# define ETHTOOL_TESTS_NUM ARRAY_SIZE(et_self_tests)
# define BE_MAC_LOOPBACK 0x0
# define BE_PHY_LOOPBACK 0x1
# define BE_ONE_PORT_EXT_LOOPBACK 0x2
2009-12-23 04:41:44 +00:00
# define BE_NO_LOOPBACK 0xff
2009-12-03 16:15:52 -08:00
2011-09-27 13:30:27 -04:00
static void be_get_drvinfo ( struct net_device * netdev ,
struct ethtool_drvinfo * drvinfo )
2009-03-11 23:32:03 -07:00
{
struct be_adapter * adapter = netdev_priv ( netdev ) ;
2011-11-07 13:29:27 +00:00
strlcpy ( drvinfo - > driver , DRV_NAME , sizeof ( drvinfo - > driver ) ) ;
strlcpy ( drvinfo - > version , DRV_VER , sizeof ( drvinfo - > version ) ) ;
2013-05-26 21:08:36 +00:00
if ( ! memcmp ( adapter - > fw_ver , adapter - > fw_on_flash , FW_VER_LEN ) )
2013-01-06 00:44:26 +00:00
strlcpy ( drvinfo - > fw_version , adapter - > fw_ver ,
sizeof ( drvinfo - > fw_version ) ) ;
else
snprintf ( drvinfo - > fw_version , sizeof ( drvinfo - > fw_version ) ,
2013-05-26 21:08:36 +00:00
" %s [%s] " , adapter - > fw_ver , adapter - > fw_on_flash ) ;
2011-09-27 13:30:27 -04:00
2011-11-07 13:29:27 +00:00
strlcpy ( drvinfo - > bus_info , pci_name ( adapter - > pdev ) ,
sizeof ( drvinfo - > bus_info ) ) ;
2009-03-11 23:32:03 -07:00
drvinfo - > testinfo_len = 0 ;
drvinfo - > regdump_len = 0 ;
drvinfo - > eedump_len = 0 ;
}
2011-11-16 02:02:43 +00:00
static u32
lancer_cmd_get_file_len ( struct be_adapter * adapter , u8 * file_name )
{
u32 data_read = 0 , eof ;
u8 addn_status ;
struct be_dma_mem data_len_cmd ;
int status ;
memset ( & data_len_cmd , 0 , sizeof ( data_len_cmd ) ) ;
/* data_offset and data_size should be 0 to get reg len */
status = lancer_cmd_read_object ( adapter , & data_len_cmd , 0 , 0 ,
file_name , & data_read , & eof , & addn_status ) ;
return data_read ;
}
static int
lancer_cmd_read_file ( struct be_adapter * adapter , u8 * file_name ,
u32 buf_len , void * buf )
{
struct be_dma_mem read_cmd ;
u32 read_len = 0 , total_read_len = 0 , chunk_size ;
u32 eof = 0 ;
u8 addn_status ;
int status = 0 ;
read_cmd . size = LANCER_READ_FILE_CHUNK ;
read_cmd . va = pci_alloc_consistent ( adapter - > pdev , read_cmd . size ,
& read_cmd . dma ) ;
if ( ! read_cmd . va ) {
dev_err ( & adapter - > pdev - > dev ,
" Memory allocation failure while reading dump \n " ) ;
return - ENOMEM ;
}
while ( ( total_read_len < buf_len ) & & ! eof ) {
chunk_size = min_t ( u32 , ( buf_len - total_read_len ) ,
LANCER_READ_FILE_CHUNK ) ;
chunk_size = ALIGN ( chunk_size , 4 ) ;
status = lancer_cmd_read_object ( adapter , & read_cmd , chunk_size ,
total_read_len , file_name , & read_len ,
& eof , & addn_status ) ;
if ( ! status ) {
memcpy ( buf + total_read_len , read_cmd . va , read_len ) ;
total_read_len + = read_len ;
eof & = LANCER_READ_FILE_EOF_MASK ;
} else {
status = - EIO ;
break ;
}
}
pci_free_consistent ( adapter - > pdev , read_cmd . size , read_cmd . va ,
read_cmd . dma ) ;
return status ;
}
2011-03-16 21:22:43 +00:00
static int
be_get_reg_len ( struct net_device * netdev )
{
struct be_adapter * adapter = netdev_priv ( netdev ) ;
u32 log_size = 0 ;
2012-10-20 06:02:52 +00:00
if ( ! check_privilege ( adapter , MAX_PRIVILEGES ) )
return 0 ;
2011-11-16 02:02:43 +00:00
if ( be_physfn ( adapter ) ) {
if ( lancer_chip ( adapter ) )
log_size = lancer_cmd_get_file_len ( adapter ,
LANCER_FW_DUMP_FILE ) ;
else
be_cmd_get_reg_len ( adapter , & log_size ) ;
}
2011-03-16 21:22:43 +00:00
return log_size ;
}
static void
be_get_regs ( struct net_device * netdev , struct ethtool_regs * regs , void * buf )
{
struct be_adapter * adapter = netdev_priv ( netdev ) ;
2011-04-19 12:10:43 +00:00
if ( be_physfn ( adapter ) ) {
memset ( buf , 0 , regs - > len ) ;
2011-11-16 02:02:43 +00:00
if ( lancer_chip ( adapter ) )
lancer_cmd_read_file ( adapter , LANCER_FW_DUMP_FILE ,
regs - > len , buf ) ;
else
be_cmd_get_regs ( adapter , regs - > len , buf ) ;
2011-04-19 12:10:43 +00:00
}
2011-03-16 21:22:43 +00:00
}
2012-02-09 18:05:27 +00:00
static int be_get_coalesce ( struct net_device * netdev ,
struct ethtool_coalesce * et )
2009-03-11 23:32:03 -07:00
{
struct be_adapter * adapter = netdev_priv ( netdev ) ;
2013-10-01 16:00:00 +05:30
struct be_aic_obj * aic = & adapter - > aic_obj [ 0 ] ;
2012-02-09 18:05:27 +00:00
2009-03-11 23:32:03 -07:00
2013-10-01 16:00:00 +05:30
et - > rx_coalesce_usecs = aic - > prev_eqd ;
et - > rx_coalesce_usecs_high = aic - > max_eqd ;
et - > rx_coalesce_usecs_low = aic - > min_eqd ;
2009-03-11 23:32:03 -07:00
2013-10-01 16:00:00 +05:30
et - > tx_coalesce_usecs = aic - > prev_eqd ;
et - > tx_coalesce_usecs_high = aic - > max_eqd ;
et - > tx_coalesce_usecs_low = aic - > min_eqd ;
2009-03-11 23:32:03 -07:00
2013-10-01 16:00:00 +05:30
et - > use_adaptive_rx_coalesce = aic - > enable ;
et - > use_adaptive_tx_coalesce = aic - > enable ;
2009-03-11 23:32:03 -07:00
return 0 ;
}
2012-02-09 18:05:27 +00:00
/* TX attributes are ignored. Only RX attributes are considered
* eqd cmd is issued in the worker thread .
2009-03-11 23:32:03 -07:00
*/
2012-02-09 18:05:27 +00:00
static int be_set_coalesce ( struct net_device * netdev ,
struct ethtool_coalesce * et )
2009-03-11 23:32:03 -07:00
{
struct be_adapter * adapter = netdev_priv ( netdev ) ;
2013-10-01 16:00:00 +05:30
struct be_aic_obj * aic = & adapter - > aic_obj [ 0 ] ;
2012-02-09 18:05:27 +00:00
struct be_eq_obj * eqo ;
int i ;
for_all_evt_queues ( adapter , eqo , i ) {
2013-10-01 16:00:00 +05:30
aic - > enable = et - > use_adaptive_rx_coalesce ;
aic - > max_eqd = min ( et - > rx_coalesce_usecs_high , BE_MAX_EQD ) ;
aic - > min_eqd = min ( et - > rx_coalesce_usecs_low , aic - > max_eqd ) ;
aic - > et_eqd = min ( et - > rx_coalesce_usecs , aic - > max_eqd ) ;
aic - > et_eqd = max ( aic - > et_eqd , aic - > min_eqd ) ;
aic + + ;
2009-03-11 23:32:03 -07:00
}
return 0 ;
}
static void
be_get_ethtool_stats ( struct net_device * netdev ,
struct ethtool_stats * stats , uint64_t * data )
{
struct be_adapter * adapter = netdev_priv ( netdev ) ;
2010-10-03 22:12:27 -07:00
struct be_rx_obj * rxo ;
2011-06-12 20:01:58 +00:00
struct be_tx_obj * txo ;
2011-07-25 19:10:14 +00:00
void * p ;
2011-07-25 19:10:15 +00:00
unsigned int i , j , base = 0 , start ;
2009-03-11 23:32:03 -07:00
for ( i = 0 ; i < ETHTOOL_STATS_NUM ; i + + ) {
2011-07-25 19:10:14 +00:00
p = ( u8 * ) & adapter - > drv_stats + et_stats [ i ] . offset ;
2011-07-25 19:10:15 +00:00
data [ i ] = * ( u32 * ) p ;
2009-03-11 23:32:03 -07:00
}
2011-07-25 19:10:15 +00:00
base + = ETHTOOL_STATS_NUM ;
2010-10-03 22:12:27 -07:00
for_all_rx_queues ( adapter , rxo , j ) {
2011-07-25 19:10:15 +00:00
struct be_rx_stats * stats = rx_stats ( rxo ) ;
do {
start = u64_stats_fetch_begin_bh ( & stats - > sync ) ;
data [ base ] = stats - > rx_bytes ;
data [ base + 1 ] = stats - > rx_pkts ;
} while ( u64_stats_fetch_retry_bh ( & stats - > sync , start ) ) ;
for ( i = 2 ; i < ETHTOOL_RXSTATS_NUM ; i + + ) {
p = ( u8 * ) stats + et_rx_stats [ i ] . offset ;
data [ base + i ] = * ( u32 * ) p ;
2010-10-03 22:12:27 -07:00
}
2011-07-25 19:10:15 +00:00
base + = ETHTOOL_RXSTATS_NUM ;
2010-10-03 22:12:27 -07:00
}
2011-06-12 20:01:58 +00:00
for_all_tx_queues ( adapter , txo , j ) {
2011-07-25 19:10:15 +00:00
struct be_tx_stats * stats = tx_stats ( txo ) ;
do {
start = u64_stats_fetch_begin_bh ( & stats - > sync_compl ) ;
data [ base ] = stats - > tx_compl ;
} while ( u64_stats_fetch_retry_bh ( & stats - > sync_compl , start ) ) ;
do {
start = u64_stats_fetch_begin_bh ( & stats - > sync ) ;
for ( i = 1 ; i < ETHTOOL_TXSTATS_NUM ; i + + ) {
p = ( u8 * ) stats + et_tx_stats [ i ] . offset ;
data [ base + i ] =
( et_tx_stats [ i ] . size = = sizeof ( u64 ) ) ?
* ( u64 * ) p : * ( u32 * ) p ;
}
} while ( u64_stats_fetch_retry_bh ( & stats - > sync , start ) ) ;
base + = ETHTOOL_TXSTATS_NUM ;
2011-06-12 20:01:58 +00:00
}
2009-03-11 23:32:03 -07:00
}
static void
be_get_stat_strings ( struct net_device * netdev , uint32_t stringset ,
uint8_t * data )
{
2010-10-03 22:12:27 -07:00
struct be_adapter * adapter = netdev_priv ( netdev ) ;
int i , j ;
2009-03-11 23:32:03 -07:00
switch ( stringset ) {
case ETH_SS_STATS :
for ( i = 0 ; i < ETHTOOL_STATS_NUM ; i + + ) {
memcpy ( data , et_stats [ i ] . desc , ETH_GSTRING_LEN ) ;
data + = ETH_GSTRING_LEN ;
}
2010-10-03 22:12:27 -07:00
for ( i = 0 ; i < adapter - > num_rx_qs ; i + + ) {
for ( j = 0 ; j < ETHTOOL_RXSTATS_NUM ; j + + ) {
sprintf ( data , " rxq%d: %s " , i ,
et_rx_stats [ j ] . desc ) ;
data + = ETH_GSTRING_LEN ;
}
}
2011-06-12 20:01:58 +00:00
for ( i = 0 ; i < adapter - > num_tx_qs ; i + + ) {
for ( j = 0 ; j < ETHTOOL_TXSTATS_NUM ; j + + ) {
sprintf ( data , " txq%d: %s " , i ,
et_tx_stats [ j ] . desc ) ;
data + = ETH_GSTRING_LEN ;
}
}
2009-03-11 23:32:03 -07:00
break ;
2009-12-03 16:15:52 -08:00
case ETH_SS_TEST :
for ( i = 0 ; i < ETHTOOL_TESTS_NUM ; i + + ) {
memcpy ( data , et_self_tests [ i ] , ETH_GSTRING_LEN ) ;
data + = ETH_GSTRING_LEN ;
}
break ;
2009-03-11 23:32:03 -07:00
}
}
2009-10-01 11:58:24 +00:00
static int be_get_sset_count ( struct net_device * netdev , int stringset )
2009-03-11 23:32:03 -07:00
{
2010-10-03 22:12:27 -07:00
struct be_adapter * adapter = netdev_priv ( netdev ) ;
2009-10-01 11:58:24 +00:00
switch ( stringset ) {
2009-12-03 16:15:52 -08:00
case ETH_SS_TEST :
return ETHTOOL_TESTS_NUM ;
2009-10-01 11:58:24 +00:00
case ETH_SS_STATS :
2010-10-03 22:12:27 -07:00
return ETHTOOL_STATS_NUM +
2011-06-12 20:01:58 +00:00
adapter - > num_rx_qs * ETHTOOL_RXSTATS_NUM +
adapter - > num_tx_qs * ETHTOOL_TXSTATS_NUM ;
2009-10-01 11:58:24 +00:00
default :
return - EINVAL ;
}
2009-03-11 23:32:03 -07:00
}
2012-04-21 18:53:22 +00:00
static u32 be_get_port_type ( u32 phy_type , u32 dac_cable_len )
{
u32 port ;
switch ( phy_type ) {
case PHY_TYPE_BASET_1GB :
case PHY_TYPE_BASEX_1GB :
case PHY_TYPE_SGMII :
port = PORT_TP ;
break ;
case PHY_TYPE_SFP_PLUS_10GB :
port = dac_cable_len ? PORT_DA : PORT_FIBRE ;
break ;
case PHY_TYPE_XFP_10GB :
case PHY_TYPE_SFP_1GB :
port = PORT_FIBRE ;
break ;
case PHY_TYPE_BASET_10GB :
port = PORT_TP ;
break ;
default :
port = PORT_OTHER ;
}
return port ;
}
static u32 convert_to_et_setting ( u32 if_type , u32 if_speeds )
{
u32 val = 0 ;
switch ( if_type ) {
case PHY_TYPE_BASET_1GB :
case PHY_TYPE_BASEX_1GB :
case PHY_TYPE_SGMII :
val | = SUPPORTED_TP ;
if ( if_speeds & BE_SUPPORTED_SPEED_1GBPS )
val | = SUPPORTED_1000baseT_Full ;
if ( if_speeds & BE_SUPPORTED_SPEED_100MBPS )
val | = SUPPORTED_100baseT_Full ;
if ( if_speeds & BE_SUPPORTED_SPEED_10MBPS )
val | = SUPPORTED_10baseT_Full ;
break ;
case PHY_TYPE_KX4_10GB :
val | = SUPPORTED_Backplane ;
if ( if_speeds & BE_SUPPORTED_SPEED_1GBPS )
val | = SUPPORTED_1000baseKX_Full ;
if ( if_speeds & BE_SUPPORTED_SPEED_10GBPS )
val | = SUPPORTED_10000baseKX4_Full ;
break ;
case PHY_TYPE_KR_10GB :
val | = SUPPORTED_Backplane |
SUPPORTED_10000baseKR_Full ;
break ;
case PHY_TYPE_SFP_PLUS_10GB :
case PHY_TYPE_XFP_10GB :
case PHY_TYPE_SFP_1GB :
val | = SUPPORTED_FIBRE ;
if ( if_speeds & BE_SUPPORTED_SPEED_10GBPS )
val | = SUPPORTED_10000baseT_Full ;
if ( if_speeds & BE_SUPPORTED_SPEED_1GBPS )
val | = SUPPORTED_1000baseT_Full ;
break ;
case PHY_TYPE_BASET_10GB :
val | = SUPPORTED_TP ;
if ( if_speeds & BE_SUPPORTED_SPEED_10GBPS )
val | = SUPPORTED_10000baseT_Full ;
if ( if_speeds & BE_SUPPORTED_SPEED_1GBPS )
val | = SUPPORTED_1000baseT_Full ;
if ( if_speeds & BE_SUPPORTED_SPEED_100MBPS )
val | = SUPPORTED_100baseT_Full ;
break ;
default :
val | = SUPPORTED_TP ;
}
return val ;
}
bool be_pause_supported ( struct be_adapter * adapter )
{
return ( adapter - > phy . interface_type = = PHY_TYPE_SFP_PLUS_10GB | |
adapter - > phy . interface_type = = PHY_TYPE_XFP_10GB ) ?
false : true ;
}
2009-03-11 23:32:03 -07:00
static int be_get_settings ( struct net_device * netdev , struct ethtool_cmd * ecmd )
{
2009-10-28 04:15:20 -07:00
struct be_adapter * adapter = netdev_priv ( netdev ) ;
2011-12-30 12:15:40 +00:00
u8 link_status ;
2012-09-28 04:39:43 +00:00
u16 link_speed = 0 ;
2009-11-29 17:57:46 +00:00
int status ;
2012-10-20 06:03:04 +00:00
u32 auto_speeds ;
u32 fixed_speeds ;
u32 dac_cable_len ;
u16 interface_type ;
2009-11-29 17:57:46 +00:00
2012-09-28 04:39:43 +00:00
if ( adapter - > phy . link_speed < 0 ) {
status = be_cmd_link_status_query ( adapter , & link_speed ,
& link_status , 0 ) ;
if ( ! status )
be_link_status_update ( adapter , link_status ) ;
ethtool_cmd_speed_set ( ecmd , link_speed ) ;
2012-04-21 18:53:22 +00:00
status = be_cmd_get_phy_info ( adapter ) ;
2012-10-20 06:03:04 +00:00
if ( ! status ) {
interface_type = adapter - > phy . interface_type ;
auto_speeds = adapter - > phy . auto_speeds_supported ;
fixed_speeds = adapter - > phy . fixed_speeds_supported ;
dac_cable_len = adapter - > phy . dac_cable_len ;
ecmd - > supported =
convert_to_et_setting ( interface_type ,
auto_speeds |
fixed_speeds ) ;
ecmd - > advertising =
convert_to_et_setting ( interface_type ,
auto_speeds ) ;
ecmd - > port = be_get_port_type ( interface_type ,
dac_cable_len ) ;
if ( adapter - > phy . auto_speeds_supported ) {
ecmd - > supported | = SUPPORTED_Autoneg ;
ecmd - > autoneg = AUTONEG_ENABLE ;
ecmd - > advertising | = ADVERTISED_Autoneg ;
}
2012-04-21 18:53:22 +00:00
ecmd - > supported | = SUPPORTED_Pause ;
2012-10-20 06:03:04 +00:00
if ( be_pause_supported ( adapter ) )
ecmd - > advertising | = ADVERTISED_Pause ;
switch ( adapter - > phy . interface_type ) {
case PHY_TYPE_KR_10GB :
case PHY_TYPE_KX4_10GB :
ecmd - > transceiver = XCVR_INTERNAL ;
break ;
default :
ecmd - > transceiver = XCVR_EXTERNAL ;
break ;
}
} else {
ecmd - > port = PORT_OTHER ;
ecmd - > autoneg = AUTONEG_DISABLE ;
ecmd - > transceiver = XCVR_DUMMY1 ;
2009-10-28 04:15:20 -07:00
}
2009-11-29 17:57:46 +00:00
/* Save for future use */
2012-04-21 18:53:22 +00:00
adapter - > phy . link_speed = ethtool_cmd_speed ( ecmd ) ;
adapter - > phy . port_type = ecmd - > port ;
adapter - > phy . transceiver = ecmd - > transceiver ;
adapter - > phy . autoneg = ecmd - > autoneg ;
adapter - > phy . advertising = ecmd - > advertising ;
adapter - > phy . supported = ecmd - > supported ;
2009-11-29 17:57:46 +00:00
} else {
2012-04-21 18:53:22 +00:00
ethtool_cmd_speed_set ( ecmd , adapter - > phy . link_speed ) ;
ecmd - > port = adapter - > phy . port_type ;
ecmd - > transceiver = adapter - > phy . transceiver ;
ecmd - > autoneg = adapter - > phy . autoneg ;
ecmd - > advertising = adapter - > phy . advertising ;
ecmd - > supported = adapter - > phy . supported ;
2009-10-28 04:15:20 -07:00
}
2009-11-29 17:57:46 +00:00
2012-05-02 03:40:32 +00:00
ecmd - > duplex = netif_carrier_ok ( netdev ) ? DUPLEX_FULL : DUPLEX_UNKNOWN ;
2009-10-28 04:15:20 -07:00
ecmd - > phy_address = adapter - > port_num ;
2010-07-01 03:51:00 +00:00
2009-03-11 23:32:03 -07:00
return 0 ;
}
2011-12-13 00:58:49 +00:00
static void be_get_ringparam ( struct net_device * netdev ,
struct ethtool_ringparam * ring )
2009-03-11 23:32:03 -07:00
{
struct be_adapter * adapter = netdev_priv ( netdev ) ;
2011-12-13 00:58:49 +00:00
ring - > rx_max_pending = ring - > rx_pending = adapter - > rx_obj [ 0 ] . q . len ;
ring - > tx_max_pending = ring - > tx_pending = adapter - > tx_obj [ 0 ] . q . len ;
2009-03-11 23:32:03 -07:00
}
static void
be_get_pauseparam ( struct net_device * netdev , struct ethtool_pauseparam * ecmd )
{
struct be_adapter * adapter = netdev_priv ( netdev ) ;
2009-07-27 22:52:03 +00:00
be_cmd_get_flow_control ( adapter , & ecmd - > tx_pause , & ecmd - > rx_pause ) ;
2012-04-21 18:53:22 +00:00
ecmd - > autoneg = adapter - > phy . fc_autoneg ;
2009-03-11 23:32:03 -07:00
}
static int
be_set_pauseparam ( struct net_device * netdev , struct ethtool_pauseparam * ecmd )
{
struct be_adapter * adapter = netdev_priv ( netdev ) ;
int status ;
2012-07-12 03:56:11 +00:00
if ( ecmd - > autoneg ! = adapter - > phy . fc_autoneg )
2009-03-11 23:32:03 -07:00
return - EINVAL ;
2009-11-06 02:06:59 +00:00
adapter - > tx_fc = ecmd - > tx_pause ;
adapter - > rx_fc = ecmd - > rx_pause ;
2009-03-11 23:32:03 -07:00
2009-11-06 02:06:59 +00:00
status = be_cmd_set_flow_control ( adapter ,
adapter - > tx_fc , adapter - > rx_fc ) ;
if ( status )
2009-03-11 23:32:03 -07:00
dev_warn ( & adapter - > pdev - > dev , " Pause param set failed. \n " ) ;
return status ;
}
2009-10-12 04:23:15 -07:00
static int
2011-04-04 11:06:40 +00:00
be_set_phys_id ( struct net_device * netdev ,
enum ethtool_phys_id_state state )
2009-10-12 04:23:15 -07:00
{
struct be_adapter * adapter = netdev_priv ( netdev ) ;
2011-04-04 11:06:40 +00:00
switch ( state ) {
case ETHTOOL_ID_ACTIVE :
be_cmd_get_beacon_state ( adapter , adapter - > hba_port_num ,
& adapter - > beacon_state ) ;
2011-04-13 13:09:10 +00:00
return 1 ; /* cycle on/off once per second */
2009-10-12 04:23:15 -07:00
2011-04-04 11:06:40 +00:00
case ETHTOOL_ID_ON :
be_cmd_set_beacon_state ( adapter , adapter - > hba_port_num , 0 , 0 ,
BEACON_STATE_ENABLED ) ;
break ;
2009-10-12 04:23:15 -07:00
2011-04-04 11:06:40 +00:00
case ETHTOOL_ID_OFF :
be_cmd_set_beacon_state ( adapter , adapter - > hba_port_num , 0 , 0 ,
BEACON_STATE_DISABLED ) ;
break ;
2009-10-12 04:23:15 -07:00
2011-04-04 11:06:40 +00:00
case ETHTOOL_ID_INACTIVE :
be_cmd_set_beacon_state ( adapter , adapter - > hba_port_num , 0 , 0 ,
adapter - > beacon_state ) ;
}
2009-10-12 04:23:15 -07:00
2011-04-04 11:06:40 +00:00
return 0 ;
2009-10-12 04:23:15 -07:00
}
2013-05-30 02:52:23 +00:00
static int be_set_dump ( struct net_device * netdev , struct ethtool_dump * dump )
{
struct be_adapter * adapter = netdev_priv ( netdev ) ;
struct device * dev = & adapter - > pdev - > dev ;
int status ;
if ( ! lancer_chip ( adapter ) ) {
dev_err ( dev , " FW dump not supported \n " ) ;
return - EOPNOTSUPP ;
}
if ( dump_present ( adapter ) ) {
dev_err ( dev , " Previous dump not cleared, not forcing dump \n " ) ;
return 0 ;
}
switch ( dump - > flag ) {
case LANCER_INITIATE_FW_DUMP :
status = lancer_initiate_dump ( adapter ) ;
if ( ! status )
dev_info ( dev , " F/w dump initiated successfully \n " ) ;
break ;
default :
dev_err ( dev , " Invalid dump level: 0x%x \n " , dump - > flag ) ;
return - EINVAL ;
}
return status ;
}
2011-02-11 13:39:30 +00:00
2009-12-03 06:16:59 +00:00
static void
be_get_wol ( struct net_device * netdev , struct ethtool_wolinfo * wol )
{
struct be_adapter * adapter = netdev_priv ( netdev ) ;
2012-03-18 06:23:11 +00:00
if ( be_is_wol_supported ( adapter ) ) {
wol - > supported | = WAKE_MAGIC ;
2013-04-25 00:56:56 +00:00
if ( adapter - > wol )
wol - > wolopts | = WAKE_MAGIC ;
2012-03-18 06:23:11 +00:00
} else
2009-12-03 06:16:59 +00:00
wol - > wolopts = 0 ;
memset ( & wol - > sopass , 0 , sizeof ( wol - > sopass ) ) ;
}
static int
be_set_wol ( struct net_device * netdev , struct ethtool_wolinfo * wol )
{
struct be_adapter * adapter = netdev_priv ( netdev ) ;
if ( wol - > wolopts & ~ WAKE_MAGIC )
2012-03-18 06:23:11 +00:00
return - EOPNOTSUPP ;
if ( ! be_is_wol_supported ( adapter ) ) {
dev_warn ( & adapter - > pdev - > dev , " WOL not supported \n " ) ;
return - EOPNOTSUPP ;
}
2009-12-03 06:16:59 +00:00
2012-03-18 06:23:11 +00:00
if ( wol - > wolopts & WAKE_MAGIC )
2009-12-03 06:16:59 +00:00
adapter - > wol = true ;
else
adapter - > wol = false ;
return 0 ;
}
2009-12-03 16:15:52 -08:00
static int
be_test_ddr_dma ( struct be_adapter * adapter )
{
int ret , i ;
struct be_dma_mem ddrdma_cmd ;
2010-12-21 02:16:10 -08:00
static const u64 pattern [ 2 ] = {
0x5a5a5a5a5a5a5a5aULL , 0xa5a5a5a5a5a5a5a5ULL
} ;
2009-12-03 16:15:52 -08:00
ddrdma_cmd . size = sizeof ( struct be_cmd_req_ddrdma_test ) ;
2011-02-02 08:05:12 +00:00
ddrdma_cmd . va = dma_alloc_coherent ( & adapter - > pdev - > dev , ddrdma_cmd . size ,
& ddrdma_cmd . dma , GFP_KERNEL ) ;
2013-03-14 13:07:21 +00:00
if ( ! ddrdma_cmd . va )
2009-12-03 16:15:52 -08:00
return - ENOMEM ;
for ( i = 0 ; i < 2 ; i + + ) {
ret = be_cmd_ddr_dma_test ( adapter , pattern [ i ] ,
4096 , & ddrdma_cmd ) ;
if ( ret ! = 0 )
goto err ;
}
err :
2011-02-02 08:05:12 +00:00
dma_free_coherent ( & adapter - > pdev - > dev , ddrdma_cmd . size , ddrdma_cmd . va ,
ddrdma_cmd . dma ) ;
2009-12-03 16:15:52 -08:00
return ret ;
}
2009-12-23 04:41:44 +00:00
static u64 be_loopback_test ( struct be_adapter * adapter , u8 loopback_type ,
u64 * status )
{
2011-02-20 11:42:22 +00:00
be_cmd_set_loopback ( adapter , adapter - > hba_port_num ,
2009-12-23 04:41:44 +00:00
loopback_type , 1 ) ;
2011-02-20 11:42:22 +00:00
* status = be_cmd_loopback_test ( adapter , adapter - > hba_port_num ,
2009-12-23 04:41:44 +00:00
loopback_type , 1500 ,
2 , 0xabc ) ;
2011-02-20 11:42:22 +00:00
be_cmd_set_loopback ( adapter , adapter - > hba_port_num ,
2009-12-23 04:41:44 +00:00
BE_NO_LOOPBACK , 1 ) ;
return * status ;
}
2009-12-03 16:15:52 -08:00
static void
be_self_test ( struct net_device * netdev , struct ethtool_test * test , u64 * data )
{
struct be_adapter * adapter = netdev_priv ( netdev ) ;
2012-09-28 04:39:43 +00:00
int status ;
u8 link_status = 0 ;
2009-12-03 16:15:52 -08:00
2013-04-25 23:03:22 +00:00
if ( adapter - > function_caps & BE_FUNCTION_CAPS_SUPER_NIC ) {
dev_err ( & adapter - > pdev - > dev , " Self test not supported \n " ) ;
test - > flags | = ETH_TEST_FL_FAILED ;
return ;
}
2009-12-03 16:15:52 -08:00
memset ( data , 0 , sizeof ( u64 ) * ETHTOOL_TESTS_NUM ) ;
if ( test - > flags & ETH_TEST_FL_OFFLINE ) {
2009-12-23 04:41:44 +00:00
if ( be_loopback_test ( adapter , BE_MAC_LOOPBACK ,
& data [ 0 ] ) ! = 0 ) {
2009-12-03 16:15:52 -08:00
test - > flags | = ETH_TEST_FL_FAILED ;
2009-12-23 04:41:44 +00:00
}
if ( be_loopback_test ( adapter , BE_PHY_LOOPBACK ,
& data [ 1 ] ) ! = 0 ) {
2009-12-03 16:15:52 -08:00
test - > flags | = ETH_TEST_FL_FAILED ;
2009-12-23 04:41:44 +00:00
}
if ( be_loopback_test ( adapter , BE_ONE_PORT_EXT_LOOPBACK ,
& data [ 2 ] ) ! = 0 ) {
2009-12-03 16:15:52 -08:00
test - > flags | = ETH_TEST_FL_FAILED ;
2009-12-23 04:41:44 +00:00
}
2010-01-19 05:15:00 +00:00
}
2009-12-03 16:15:52 -08:00
2012-04-25 01:46:28 +00:00
if ( ! lancer_chip ( adapter ) & & be_test_ddr_dma ( adapter ) ! = 0 ) {
2010-01-19 05:15:00 +00:00
data [ 3 ] = 1 ;
test - > flags | = ETH_TEST_FL_FAILED ;
2009-12-03 16:15:52 -08:00
}
2012-09-28 04:39:43 +00:00
status = be_cmd_link_status_query ( adapter , NULL , & link_status , 0 ) ;
if ( status ) {
2010-01-19 05:15:36 +00:00
test - > flags | = ETH_TEST_FL_FAILED ;
data [ 4 ] = - 1 ;
2012-09-28 04:39:43 +00:00
} else if ( ! link_status ) {
2011-02-20 11:41:20 +00:00
test - > flags | = ETH_TEST_FL_FAILED ;
2010-01-19 05:15:36 +00:00
data [ 4 ] = 1 ;
}
2009-12-03 16:15:52 -08:00
}
2009-09-04 03:12:16 +00:00
static int
be_do_flash ( struct net_device * netdev , struct ethtool_flash * efl )
{
struct be_adapter * adapter = netdev_priv ( netdev ) ;
2012-02-01 09:32:25 +00:00
return be_load_fw ( adapter , efl - > data ) ;
2009-09-04 03:12:16 +00:00
}
2010-01-08 00:07:27 -08:00
static int
be_get_eeprom_len ( struct net_device * netdev )
{
2011-11-16 02:03:07 +00:00
struct be_adapter * adapter = netdev_priv ( netdev ) ;
2012-10-20 06:02:52 +00:00
if ( ! check_privilege ( adapter , MAX_PRIVILEGES ) )
return 0 ;
2011-11-16 02:03:07 +00:00
if ( lancer_chip ( adapter ) ) {
if ( be_physfn ( adapter ) )
return lancer_cmd_get_file_len ( adapter ,
LANCER_VPD_PF_FILE ) ;
else
return lancer_cmd_get_file_len ( adapter ,
LANCER_VPD_VF_FILE ) ;
} else {
return BE_READ_SEEPROM_LEN ;
}
2010-01-08 00:07:27 -08:00
}
static int
be_read_eeprom ( struct net_device * netdev , struct ethtool_eeprom * eeprom ,
uint8_t * data )
{
struct be_adapter * adapter = netdev_priv ( netdev ) ;
struct be_dma_mem eeprom_cmd ;
struct be_cmd_resp_seeprom_read * resp ;
int status ;
if ( ! eeprom - > len )
return - EINVAL ;
2011-11-16 02:03:07 +00:00
if ( lancer_chip ( adapter ) ) {
if ( be_physfn ( adapter ) )
return lancer_cmd_read_file ( adapter , LANCER_VPD_PF_FILE ,
eeprom - > len , data ) ;
else
return lancer_cmd_read_file ( adapter , LANCER_VPD_VF_FILE ,
eeprom - > len , data ) ;
}
2010-01-08 00:07:27 -08:00
eeprom - > magic = BE_VENDOR_ID | ( adapter - > pdev - > device < < 16 ) ;
memset ( & eeprom_cmd , 0 , sizeof ( struct be_dma_mem ) ) ;
eeprom_cmd . size = sizeof ( struct be_cmd_req_seeprom_read ) ;
2011-02-02 08:05:12 +00:00
eeprom_cmd . va = dma_alloc_coherent ( & adapter - > pdev - > dev , eeprom_cmd . size ,
& eeprom_cmd . dma , GFP_KERNEL ) ;
2010-01-08 00:07:27 -08:00
2013-03-14 13:07:21 +00:00
if ( ! eeprom_cmd . va )
2010-01-08 00:07:27 -08:00
return - ENOMEM ;
status = be_cmd_get_seeprom_data ( adapter , & eeprom_cmd ) ;
if ( ! status ) {
2011-06-16 19:08:06 +00:00
resp = eeprom_cmd . va ;
2010-02-08 17:51:26 +00:00
memcpy ( data , resp - > seeprom_data + eeprom - > offset , eeprom - > len ) ;
2010-01-08 00:07:27 -08:00
}
2011-02-02 08:05:12 +00:00
dma_free_coherent ( & adapter - > pdev - > dev , eeprom_cmd . size , eeprom_cmd . va ,
eeprom_cmd . dma ) ;
2010-01-08 00:07:27 -08:00
return status ;
}
2012-05-17 22:59:03 +00:00
static u32 be_get_msg_level ( struct net_device * netdev )
{
struct be_adapter * adapter = netdev_priv ( netdev ) ;
if ( lancer_chip ( adapter ) ) {
dev_err ( & adapter - > pdev - > dev , " Operation not supported \n " ) ;
return - EOPNOTSUPP ;
}
return adapter - > msg_enable ;
}
static void be_set_fw_log_level ( struct be_adapter * adapter , u32 level )
{
struct be_dma_mem extfat_cmd ;
struct be_fat_conf_params * cfgs ;
int status ;
int i , j ;
memset ( & extfat_cmd , 0 , sizeof ( struct be_dma_mem ) ) ;
extfat_cmd . size = sizeof ( struct be_cmd_resp_get_ext_fat_caps ) ;
extfat_cmd . va = pci_alloc_consistent ( adapter - > pdev , extfat_cmd . size ,
& extfat_cmd . dma ) ;
if ( ! extfat_cmd . va ) {
dev_err ( & adapter - > pdev - > dev , " %s: Memory allocation failure \n " ,
__func__ ) ;
goto err ;
}
status = be_cmd_get_ext_fat_capabilites ( adapter , & extfat_cmd ) ;
if ( ! status ) {
cfgs = ( struct be_fat_conf_params * ) ( extfat_cmd . va +
sizeof ( struct be_cmd_resp_hdr ) ) ;
2012-07-24 15:05:25 +00:00
for ( i = 0 ; i < le32_to_cpu ( cfgs - > num_modules ) ; i + + ) {
u32 num_modes = le32_to_cpu ( cfgs - > module [ i ] . num_modes ) ;
for ( j = 0 ; j < num_modes ; j + + ) {
2012-05-17 22:59:03 +00:00
if ( cfgs - > module [ i ] . trace_lvl [ j ] . mode = =
MODE_UART )
cfgs - > module [ i ] . trace_lvl [ j ] . dbg_lvl =
cpu_to_le32 ( level ) ;
}
}
status = be_cmd_set_ext_fat_capabilites ( adapter , & extfat_cmd ,
cfgs ) ;
if ( status )
dev_err ( & adapter - > pdev - > dev ,
" Message level set failed \n " ) ;
} else {
dev_err ( & adapter - > pdev - > dev , " Message level get failed \n " ) ;
}
pci_free_consistent ( adapter - > pdev , extfat_cmd . size , extfat_cmd . va ,
extfat_cmd . dma ) ;
err :
return ;
}
static void be_set_msg_level ( struct net_device * netdev , u32 level )
{
struct be_adapter * adapter = netdev_priv ( netdev ) ;
if ( lancer_chip ( adapter ) ) {
dev_err ( & adapter - > pdev - > dev , " Operation not supported \n " ) ;
return ;
}
if ( adapter - > msg_enable = = level )
return ;
if ( ( level & NETIF_MSG_HW ) ! = ( adapter - > msg_enable & NETIF_MSG_HW ) )
be_set_fw_log_level ( adapter , level & NETIF_MSG_HW ?
FW_LOG_LEVEL_DEFAULT : FW_LOG_LEVEL_FATAL ) ;
adapter - > msg_enable = level ;
return ;
}
2013-04-25 23:03:20 +00:00
static u64 be_get_rss_hash_opts ( struct be_adapter * adapter , u64 flow_type )
{
u64 data = 0 ;
switch ( flow_type ) {
case TCP_V4_FLOW :
if ( adapter - > rss_flags & RSS_ENABLE_IPV4 )
data | = RXH_IP_DST | RXH_IP_SRC ;
if ( adapter - > rss_flags & RSS_ENABLE_TCP_IPV4 )
data | = RXH_L4_B_0_1 | RXH_L4_B_2_3 ;
break ;
case UDP_V4_FLOW :
if ( adapter - > rss_flags & RSS_ENABLE_IPV4 )
data | = RXH_IP_DST | RXH_IP_SRC ;
if ( adapter - > rss_flags & RSS_ENABLE_UDP_IPV4 )
data | = RXH_L4_B_0_1 | RXH_L4_B_2_3 ;
break ;
case TCP_V6_FLOW :
if ( adapter - > rss_flags & RSS_ENABLE_IPV6 )
data | = RXH_IP_DST | RXH_IP_SRC ;
if ( adapter - > rss_flags & RSS_ENABLE_TCP_IPV6 )
data | = RXH_L4_B_0_1 | RXH_L4_B_2_3 ;
break ;
case UDP_V6_FLOW :
if ( adapter - > rss_flags & RSS_ENABLE_IPV6 )
data | = RXH_IP_DST | RXH_IP_SRC ;
if ( adapter - > rss_flags & RSS_ENABLE_UDP_IPV6 )
data | = RXH_L4_B_0_1 | RXH_L4_B_2_3 ;
break ;
}
return data ;
}
static int be_get_rxnfc ( struct net_device * netdev , struct ethtool_rxnfc * cmd ,
u32 * rule_locs )
{
struct be_adapter * adapter = netdev_priv ( netdev ) ;
if ( ! be_multi_rxq ( adapter ) ) {
dev_info ( & adapter - > pdev - > dev ,
" ethtool::get_rxnfc: RX flow hashing is disabled \n " ) ;
return - EINVAL ;
}
switch ( cmd - > cmd ) {
case ETHTOOL_GRXFH :
cmd - > data = be_get_rss_hash_opts ( adapter , cmd - > flow_type ) ;
break ;
case ETHTOOL_GRXRINGS :
cmd - > data = adapter - > num_rx_qs - 1 ;
break ;
default :
return - EINVAL ;
}
return 0 ;
}
static int be_set_rss_hash_opts ( struct be_adapter * adapter ,
struct ethtool_rxnfc * cmd )
{
struct be_rx_obj * rxo ;
int status = 0 , i , j ;
u8 rsstable [ 128 ] ;
u32 rss_flags = adapter - > rss_flags ;
if ( cmd - > data ! = L3_RSS_FLAGS & &
cmd - > data ! = ( L3_RSS_FLAGS | L4_RSS_FLAGS ) )
return - EINVAL ;
switch ( cmd - > flow_type ) {
case TCP_V4_FLOW :
if ( cmd - > data = = L3_RSS_FLAGS )
rss_flags & = ~ RSS_ENABLE_TCP_IPV4 ;
else if ( cmd - > data = = ( L3_RSS_FLAGS | L4_RSS_FLAGS ) )
rss_flags | = RSS_ENABLE_IPV4 |
RSS_ENABLE_TCP_IPV4 ;
break ;
case TCP_V6_FLOW :
if ( cmd - > data = = L3_RSS_FLAGS )
rss_flags & = ~ RSS_ENABLE_TCP_IPV6 ;
else if ( cmd - > data = = ( L3_RSS_FLAGS | L4_RSS_FLAGS ) )
rss_flags | = RSS_ENABLE_IPV6 |
RSS_ENABLE_TCP_IPV6 ;
break ;
case UDP_V4_FLOW :
if ( ( cmd - > data = = ( L3_RSS_FLAGS | L4_RSS_FLAGS ) ) & &
BEx_chip ( adapter ) )
return - EINVAL ;
if ( cmd - > data = = L3_RSS_FLAGS )
rss_flags & = ~ RSS_ENABLE_UDP_IPV4 ;
else if ( cmd - > data = = ( L3_RSS_FLAGS | L4_RSS_FLAGS ) )
rss_flags | = RSS_ENABLE_IPV4 |
RSS_ENABLE_UDP_IPV4 ;
break ;
case UDP_V6_FLOW :
if ( ( cmd - > data = = ( L3_RSS_FLAGS | L4_RSS_FLAGS ) ) & &
BEx_chip ( adapter ) )
return - EINVAL ;
if ( cmd - > data = = L3_RSS_FLAGS )
rss_flags & = ~ RSS_ENABLE_UDP_IPV6 ;
else if ( cmd - > data = = ( L3_RSS_FLAGS | L4_RSS_FLAGS ) )
rss_flags | = RSS_ENABLE_IPV6 |
RSS_ENABLE_UDP_IPV6 ;
break ;
default :
return - EINVAL ;
}
if ( rss_flags = = adapter - > rss_flags )
return status ;
if ( be_multi_rxq ( adapter ) ) {
for ( j = 0 ; j < 128 ; j + = adapter - > num_rx_qs - 1 ) {
for_all_rss_queues ( adapter , rxo , i ) {
if ( ( j + i ) > = 128 )
break ;
rsstable [ j + i ] = rxo - > rss_id ;
}
}
}
status = be_cmd_rss_config ( adapter , rsstable , rss_flags , 128 ) ;
if ( ! status )
adapter - > rss_flags = rss_flags ;
return status ;
}
static int be_set_rxnfc ( struct net_device * netdev , struct ethtool_rxnfc * cmd )
{
struct be_adapter * adapter = netdev_priv ( netdev ) ;
int status = 0 ;
if ( ! be_multi_rxq ( adapter ) ) {
dev_err ( & adapter - > pdev - > dev ,
" ethtool::set_rxnfc: RX flow hashing is disabled \n " ) ;
return - EINVAL ;
}
switch ( cmd - > cmd ) {
case ETHTOOL_SRXFH :
status = be_set_rss_hash_opts ( adapter , cmd ) ;
break ;
default :
return - EINVAL ;
}
return status ;
}
2013-08-27 16:57:35 +05:30
static void be_get_channels ( struct net_device * netdev ,
struct ethtool_channels * ch )
{
struct be_adapter * adapter = netdev_priv ( netdev ) ;
ch - > combined_count = adapter - > num_evt_qs ;
ch - > max_combined = be_max_qs ( adapter ) ;
}
static int be_set_channels ( struct net_device * netdev ,
struct ethtool_channels * ch )
{
struct be_adapter * adapter = netdev_priv ( netdev ) ;
if ( ch - > rx_count | | ch - > tx_count | | ch - > other_count | |
! ch - > combined_count | | ch - > combined_count > be_max_qs ( adapter ) )
return - EINVAL ;
adapter - > cfg_num_qs = ch - > combined_count ;
return be_update_queues ( adapter ) ;
}
2009-09-02 01:03:33 -07:00
const struct ethtool_ops be_ethtool_ops = {
2009-03-11 23:32:03 -07:00
. get_settings = be_get_settings ,
. get_drvinfo = be_get_drvinfo ,
2009-12-03 06:16:59 +00:00
. get_wol = be_get_wol ,
. set_wol = be_set_wol ,
2009-03-11 23:32:03 -07:00
. get_link = ethtool_op_get_link ,
2010-01-08 00:07:27 -08:00
. get_eeprom_len = be_get_eeprom_len ,
. get_eeprom = be_read_eeprom ,
2009-03-11 23:32:03 -07:00
. get_coalesce = be_get_coalesce ,
. set_coalesce = be_set_coalesce ,
. get_ringparam = be_get_ringparam ,
. get_pauseparam = be_get_pauseparam ,
. set_pauseparam = be_set_pauseparam ,
. get_strings = be_get_stat_strings ,
2011-04-04 11:06:40 +00:00
. set_phys_id = be_set_phys_id ,
2013-05-30 02:52:23 +00:00
. set_dump = be_set_dump ,
2012-05-17 22:59:03 +00:00
. get_msglevel = be_get_msg_level ,
. set_msglevel = be_set_msg_level ,
2009-10-01 11:58:24 +00:00
. get_sset_count = be_get_sset_count ,
2009-03-11 23:32:03 -07:00
. get_ethtool_stats = be_get_ethtool_stats ,
2011-03-16 21:22:43 +00:00
. get_regs_len = be_get_reg_len ,
. get_regs = be_get_regs ,
2009-09-04 03:12:16 +00:00
. flash_device = be_do_flash ,
2009-12-03 16:15:52 -08:00
. self_test = be_self_test ,
2013-04-25 23:03:20 +00:00
. get_rxnfc = be_get_rxnfc ,
. set_rxnfc = be_set_rxnfc ,
2013-08-27 16:57:35 +05:30
. get_channels = be_get_channels ,
. set_channels = be_set_channels
2009-03-11 23:32:03 -07:00
} ;