2009-11-29 15:15:25 +00:00
/****************************************************************************
* Driver for Solarflare Solarstorm network controllers and boards
* Copyright 2009 Solarflare Communications Inc .
*
* 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 , incorporated herein by reference .
*/
# include "net_driver.h"
# include "efx.h"
# include "mac.h"
# include "mcdi.h"
# include "mcdi_pcol.h"
static int efx_mcdi_set_mac ( struct efx_nic * efx )
{
u32 reject , fcntl ;
u8 cmdbytes [ MC_CMD_SET_MAC_IN_LEN ] ;
memcpy ( cmdbytes + MC_CMD_SET_MAC_IN_ADDR_OFST ,
efx - > net_dev - > dev_addr , ETH_ALEN ) ;
MCDI_SET_DWORD ( cmdbytes , SET_MAC_IN_MTU ,
EFX_MAX_FRAME_LEN ( efx - > net_dev - > mtu ) ) ;
MCDI_SET_DWORD ( cmdbytes , SET_MAC_IN_DRAIN , 0 ) ;
/* The MCDI command provides for controlling accept/reject
* of broadcast packets too , but the driver doesn ' t currently
* expose this . */
reject = ( efx - > promiscuous ) ? 0 :
( 1 < < MC_CMD_SET_MAC_IN_REJECT_UNCST_LBN ) ;
MCDI_SET_DWORD ( cmdbytes , SET_MAC_IN_REJECT , reject ) ;
switch ( efx - > wanted_fc ) {
case EFX_FC_RX | EFX_FC_TX :
fcntl = MC_CMD_FCNTL_BIDIR ;
break ;
case EFX_FC_RX :
fcntl = MC_CMD_FCNTL_RESPOND ;
break ;
default :
fcntl = MC_CMD_FCNTL_OFF ;
break ;
}
if ( efx - > wanted_fc & EFX_FC_AUTO )
fcntl = MC_CMD_FCNTL_AUTO ;
MCDI_SET_DWORD ( cmdbytes , SET_MAC_IN_FCNTL , fcntl ) ;
return efx_mcdi_rpc ( efx , MC_CMD_SET_MAC , cmdbytes , sizeof ( cmdbytes ) ,
NULL , 0 , NULL ) ;
}
static int efx_mcdi_get_mac_faults ( struct efx_nic * efx , u32 * faults )
{
u8 outbuf [ MC_CMD_GET_LINK_OUT_LEN ] ;
size_t outlength ;
int rc ;
BUILD_BUG_ON ( MC_CMD_GET_LINK_IN_LEN ! = 0 ) ;
rc = efx_mcdi_rpc ( efx , MC_CMD_GET_LINK , NULL , 0 ,
outbuf , sizeof ( outbuf ) , & outlength ) ;
if ( rc )
goto fail ;
* faults = MCDI_DWORD ( outbuf , GET_LINK_OUT_MAC_FAULT ) ;
return 0 ;
fail :
2010-06-23 11:30:07 +00:00
netif_err ( efx , hw , efx - > net_dev , " %s: failed rc=%d \n " ,
__func__ , rc ) ;
2009-11-29 15:15:25 +00:00
return rc ;
}
int efx_mcdi_mac_stats ( struct efx_nic * efx , dma_addr_t dma_addr ,
u32 dma_len , int enable , int clear )
{
u8 inbuf [ MC_CMD_MAC_STATS_IN_LEN ] ;
int rc ;
efx_dword_t * cmd_ptr ;
2010-04-28 09:29:32 +00:00
int period = enable ? 1000 : 0 ;
2009-11-29 15:15:25 +00:00
u32 addr_hi ;
u32 addr_lo ;
BUILD_BUG_ON ( MC_CMD_MAC_STATS_OUT_LEN ! = 0 ) ;
addr_lo = ( ( u64 ) dma_addr ) > > 0 ;
addr_hi = ( ( u64 ) dma_addr ) > > 32 ;
MCDI_SET_DWORD ( inbuf , MAC_STATS_IN_DMA_ADDR_LO , addr_lo ) ;
MCDI_SET_DWORD ( inbuf , MAC_STATS_IN_DMA_ADDR_HI , addr_hi ) ;
cmd_ptr = ( efx_dword_t * ) MCDI_PTR ( inbuf , MAC_STATS_IN_CMD ) ;
2010-04-28 09:29:32 +00:00
EFX_POPULATE_DWORD_7 ( * cmd_ptr ,
MC_CMD_MAC_STATS_CMD_DMA , ! ! enable ,
MC_CMD_MAC_STATS_CMD_CLEAR , clear ,
MC_CMD_MAC_STATS_CMD_PERIODIC_CHANGE , 1 ,
MC_CMD_MAC_STATS_CMD_PERIODIC_ENABLE , ! ! enable ,
MC_CMD_MAC_STATS_CMD_PERIODIC_CLEAR , 0 ,
MC_CMD_MAC_STATS_CMD_PERIODIC_NOEVENT , 1 ,
MC_CMD_MAC_STATS_CMD_PERIOD_MS , period ) ;
2009-11-29 15:15:25 +00:00
MCDI_SET_DWORD ( inbuf , MAC_STATS_IN_DMA_LEN , dma_len ) ;
rc = efx_mcdi_rpc ( efx , MC_CMD_MAC_STATS , inbuf , sizeof ( inbuf ) ,
NULL , 0 , NULL ) ;
if ( rc )
goto fail ;
return 0 ;
fail :
2010-06-23 11:30:07 +00:00
netif_err ( efx , hw , efx - > net_dev , " %s: %s failed rc=%d \n " ,
__func__ , enable ? " enable " : " disable " , rc ) ;
2009-11-29 15:15:25 +00:00
return rc ;
}
static int efx_mcdi_mac_reconfigure ( struct efx_nic * efx )
{
int rc ;
rc = efx_mcdi_set_mac ( efx ) ;
if ( rc ! = 0 )
return rc ;
/* Restore the multicast hash registers. */
efx - > type - > push_multicast_hash ( efx ) ;
return 0 ;
}
static bool efx_mcdi_mac_check_fault ( struct efx_nic * efx )
{
u32 faults ;
int rc = efx_mcdi_get_mac_faults ( efx , & faults ) ;
return ( rc ! = 0 ) | | ( faults ! = 0 ) ;
}
struct efx_mac_operations efx_mcdi_mac_operations = {
. reconfigure = efx_mcdi_mac_reconfigure ,
. update_stats = efx_port_dummy_op_void ,
. check_fault = efx_mcdi_mac_check_fault ,
} ;