2009-03-11 23:32:03 -07:00
/*
* Copyright ( C ) 2005 - 2009 ServerEngines
* 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 :
* linux - drivers @ serverengines . com
*
* ServerEngines
* 209 N . Fair Oaks Ave
* Sunnyvale , CA 94085
*/
# include "be.h"
2009-07-27 22:52:03 +00:00
# include "be_cmds.h"
2009-03-27 00:25:24 -07:00
# include <asm/div64.h>
2009-03-11 23:32:03 -07:00
MODULE_VERSION ( DRV_VER ) ;
MODULE_DEVICE_TABLE ( pci , be_dev_ids ) ;
MODULE_DESCRIPTION ( DRV_DESC " " DRV_VER ) ;
MODULE_AUTHOR ( " ServerEngines Corporation " ) ;
MODULE_LICENSE ( " GPL " ) ;
static unsigned int rx_frag_size = 2048 ;
module_param ( rx_frag_size , uint , S_IRUGO ) ;
MODULE_PARM_DESC ( rx_frag_size , " Size of a fragment that holds rcvd data. " ) ;
static DEFINE_PCI_DEVICE_TABLE ( be_dev_ids ) = {
2009-05-18 15:38:55 -07:00
{ PCI_DEVICE ( BE_VENDOR_ID , BE_DEVICE_ID1 ) } ,
2009-10-29 01:11:06 -07:00
{ PCI_DEVICE ( BE_VENDOR_ID , BE_DEVICE_ID2 ) } ,
2009-05-18 15:38:55 -07:00
{ PCI_DEVICE ( BE_VENDOR_ID , OC_DEVICE_ID1 ) } ,
{ PCI_DEVICE ( BE_VENDOR_ID , OC_DEVICE_ID2 ) } ,
2009-10-29 01:11:06 -07:00
{ PCI_DEVICE ( BE_VENDOR_ID , OC_DEVICE_ID3 ) } ,
2009-03-11 23:32:03 -07:00
{ 0 }
} ;
MODULE_DEVICE_TABLE ( pci , be_dev_ids ) ;
static void be_queue_free ( struct be_adapter * adapter , struct be_queue_info * q )
{
struct be_dma_mem * mem = & q - > dma_mem ;
if ( mem - > va )
pci_free_consistent ( adapter - > pdev , mem - > size ,
mem - > va , mem - > dma ) ;
}
static int be_queue_alloc ( struct be_adapter * adapter , struct be_queue_info * q ,
u16 len , u16 entry_size )
{
struct be_dma_mem * mem = & q - > dma_mem ;
memset ( q , 0 , sizeof ( * q ) ) ;
q - > len = len ;
q - > entry_size = entry_size ;
mem - > size = len * entry_size ;
mem - > va = pci_alloc_consistent ( adapter - > pdev , mem - > size , & mem - > dma ) ;
if ( ! mem - > va )
return - 1 ;
memset ( mem - > va , 0 , mem - > size ) ;
return 0 ;
}
2009-07-27 22:52:03 +00:00
static void be_intr_set ( struct be_adapter * adapter , bool enable )
2009-03-11 23:32:03 -07:00
{
2009-07-27 22:52:03 +00:00
u8 __iomem * addr = adapter - > pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET ;
2009-03-11 23:32:03 -07:00
u32 reg = ioread32 ( addr ) ;
u32 enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK ;
2009-07-27 22:52:56 +00:00
if ( ! enabled & & enable )
2009-03-11 23:32:03 -07:00
reg | = MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK ;
2009-07-27 22:52:56 +00:00
else if ( enabled & & ! enable )
2009-03-11 23:32:03 -07:00
reg & = ~ MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK ;
2009-07-27 22:52:56 +00:00
else
2009-03-11 23:32:03 -07:00
return ;
2009-07-27 22:52:56 +00:00
2009-03-11 23:32:03 -07:00
iowrite32 ( reg , addr ) ;
}
2009-07-27 22:52:03 +00:00
static void be_rxq_notify ( struct be_adapter * adapter , u16 qid , u16 posted )
2009-03-11 23:32:03 -07:00
{
u32 val = 0 ;
val | = qid & DB_RQ_RING_ID_MASK ;
val | = posted < < DB_RQ_NUM_POSTED_SHIFT ;
2009-07-27 22:52:03 +00:00
iowrite32 ( val , adapter - > db + DB_RQ_OFFSET ) ;
2009-03-11 23:32:03 -07:00
}
2009-07-27 22:52:03 +00:00
static void be_txq_notify ( struct be_adapter * adapter , u16 qid , u16 posted )
2009-03-11 23:32:03 -07:00
{
u32 val = 0 ;
val | = qid & DB_TXULP_RING_ID_MASK ;
val | = ( posted & DB_TXULP_NUM_POSTED_MASK ) < < DB_TXULP_NUM_POSTED_SHIFT ;
2009-07-27 22:52:03 +00:00
iowrite32 ( val , adapter - > db + DB_TXULP1_OFFSET ) ;
2009-03-11 23:32:03 -07:00
}
2009-07-27 22:52:03 +00:00
static void be_eq_notify ( struct be_adapter * adapter , u16 qid ,
2009-03-11 23:32:03 -07:00
bool arm , bool clear_int , u16 num_popped )
{
u32 val = 0 ;
val | = qid & DB_EQ_RING_ID_MASK ;
if ( arm )
val | = 1 < < DB_EQ_REARM_SHIFT ;
if ( clear_int )
val | = 1 < < DB_EQ_CLR_SHIFT ;
val | = 1 < < DB_EQ_EVNT_SHIFT ;
val | = num_popped < < DB_EQ_NUM_POPPED_SHIFT ;
2009-07-27 22:52:03 +00:00
iowrite32 ( val , adapter - > db + DB_EQ_OFFSET ) ;
2009-03-11 23:32:03 -07:00
}
2009-07-27 22:52:03 +00:00
void be_cq_notify ( struct be_adapter * adapter , u16 qid , bool arm , u16 num_popped )
2009-03-11 23:32:03 -07:00
{
u32 val = 0 ;
val | = qid & DB_CQ_RING_ID_MASK ;
if ( arm )
val | = 1 < < DB_CQ_REARM_SHIFT ;
val | = num_popped < < DB_CQ_NUM_POPPED_SHIFT ;
2009-07-27 22:52:03 +00:00
iowrite32 ( val , adapter - > db + DB_CQ_OFFSET ) ;
2009-03-11 23:32:03 -07:00
}
static int be_mac_addr_set ( struct net_device * netdev , void * p )
{
struct be_adapter * adapter = netdev_priv ( netdev ) ;
struct sockaddr * addr = p ;
int status = 0 ;
2009-11-29 17:56:26 +00:00
if ( ! is_valid_ether_addr ( addr - > sa_data ) )
return - EADDRNOTAVAIL ;
2009-08-17 00:58:04 +00:00
status = be_cmd_pmac_del ( adapter , adapter - > if_handle , adapter - > pmac_id ) ;
if ( status )
return status ;
2009-03-11 23:32:03 -07:00
2009-08-17 00:58:04 +00:00
status = be_cmd_pmac_add ( adapter , ( u8 * ) addr - > sa_data ,
adapter - > if_handle , & adapter - > pmac_id ) ;
2009-03-11 23:32:03 -07:00
if ( ! status )
memcpy ( netdev - > dev_addr , addr - > sa_data , netdev - > addr_len ) ;
return status ;
}
2009-09-17 10:30:13 -07:00
void netdev_stats_update ( struct be_adapter * adapter )
2009-03-11 23:32:03 -07:00
{
struct be_hw_stats * hw_stats = hw_stats_from_cmd ( adapter - > stats . cmd . va ) ;
struct be_rxf_stats * rxf_stats = & hw_stats - > rxf ;
struct be_port_rxf_stats * port_stats =
& rxf_stats - > port [ adapter - > port_num ] ;
2009-10-07 03:11:20 -07:00
struct net_device_stats * dev_stats = & adapter - > netdev - > stats ;
2009-06-10 02:21:16 +00:00
struct be_erx_stats * erx_stats = & hw_stats - > erx ;
2009-03-11 23:32:03 -07:00
dev_stats - > rx_packets = port_stats - > rx_total_frames ;
dev_stats - > tx_packets = port_stats - > tx_unicastframes +
port_stats - > tx_multicastframes + port_stats - > tx_broadcastframes ;
dev_stats - > rx_bytes = ( u64 ) port_stats - > rx_bytes_msd < < 32 |
( u64 ) port_stats - > rx_bytes_lsd ;
dev_stats - > tx_bytes = ( u64 ) port_stats - > tx_bytes_msd < < 32 |
( u64 ) port_stats - > tx_bytes_lsd ;
/* bad pkts received */
dev_stats - > rx_errors = port_stats - > rx_crc_errors +
port_stats - > rx_alignment_symbol_errors +
port_stats - > rx_in_range_errors +
2009-06-10 02:21:16 +00:00
port_stats - > rx_out_range_errors +
port_stats - > rx_frame_too_long +
port_stats - > rx_dropped_too_small +
port_stats - > rx_dropped_too_short +
port_stats - > rx_dropped_header_too_small +
port_stats - > rx_dropped_tcp_length +
port_stats - > rx_dropped_runt +
port_stats - > rx_tcp_checksum_errs +
port_stats - > rx_ip_checksum_errs +
port_stats - > rx_udp_checksum_errs ;
/* no space in linux buffers: best possible approximation */
2009-11-22 22:01:31 +00:00
dev_stats - > rx_dropped =
erx_stats - > rx_drops_no_fragments [ adapter - > rx_obj . q . id ] ;
2009-03-11 23:32:03 -07:00
/* detailed rx errors */
dev_stats - > rx_length_errors = port_stats - > rx_in_range_errors +
2009-06-10 02:21:16 +00:00
port_stats - > rx_out_range_errors +
port_stats - > rx_frame_too_long ;
2009-03-11 23:32:03 -07:00
/* receive ring buffer overflow */
dev_stats - > rx_over_errors = 0 ;
2009-06-10 02:21:16 +00:00
2009-03-11 23:32:03 -07:00
dev_stats - > rx_crc_errors = port_stats - > rx_crc_errors ;
/* frame alignment errors */
dev_stats - > rx_frame_errors = port_stats - > rx_alignment_symbol_errors ;
2009-06-10 02:21:16 +00:00
2009-03-11 23:32:03 -07:00
/* receiver fifo overrun */
/* drops_no_pbuf is no per i/f, it's per BE card */
dev_stats - > rx_fifo_errors = port_stats - > rx_fifo_overflow +
port_stats - > rx_input_fifo_overflow +
rxf_stats - > rx_drops_no_pbuf ;
/* receiver missed packetd */
dev_stats - > rx_missed_errors = 0 ;
2009-06-10 02:21:16 +00:00
/* packet transmit problems */
dev_stats - > tx_errors = 0 ;
/* no space available in linux */
dev_stats - > tx_dropped = 0 ;
2009-10-05 02:21:51 +00:00
dev_stats - > multicast = port_stats - > rx_multicast_frames ;
2009-06-10 02:21:16 +00:00
dev_stats - > collisions = 0 ;
2009-03-11 23:32:03 -07:00
/* detailed tx_errors */
dev_stats - > tx_aborted_errors = 0 ;
dev_stats - > tx_carrier_errors = 0 ;
dev_stats - > tx_fifo_errors = 0 ;
dev_stats - > tx_heartbeat_errors = 0 ;
dev_stats - > tx_window_errors = 0 ;
}
2009-07-27 22:52:03 +00:00
void be_link_status_update ( struct be_adapter * adapter , bool link_up )
2009-03-11 23:32:03 -07:00
{
struct net_device * netdev = adapter - > netdev ;
/* If link came up or went down */
2009-06-18 00:10:27 +00:00
if ( adapter - > link_up ! = link_up ) {
2009-11-29 17:57:46 +00:00
adapter - > link_speed = - 1 ;
2009-06-18 00:10:27 +00:00
if ( link_up ) {
2009-03-11 23:32:03 -07:00
netif_start_queue ( netdev ) ;
netif_carrier_on ( netdev ) ;
printk ( KERN_INFO " %s: Link up \n " , netdev - > name ) ;
2009-06-18 00:10:27 +00:00
} else {
netif_stop_queue ( netdev ) ;
netif_carrier_off ( netdev ) ;
printk ( KERN_INFO " %s: Link down \n " , netdev - > name ) ;
2009-03-11 23:32:03 -07:00
}
2009-06-18 00:10:27 +00:00
adapter - > link_up = link_up ;
2009-03-11 23:32:03 -07:00
}
}
/* Update the EQ delay n BE based on the RX frags consumed / sec */
static void be_rx_eqd_update ( struct be_adapter * adapter )
{
struct be_eq_obj * rx_eq = & adapter - > rx_eq ;
struct be_drvr_stats * stats = & adapter - > stats . drvr_stats ;
2009-03-24 16:40:13 -07:00
ulong now = jiffies ;
u32 eqd ;
if ( ! rx_eq - > enable_aic )
return ;
/* Wrapped around */
if ( time_before ( now , stats - > rx_fps_jiffies ) ) {
stats - > rx_fps_jiffies = now ;
return ;
}
2009-03-11 23:32:03 -07:00
/* Update once a second */
2009-03-24 16:40:13 -07:00
if ( ( now - stats - > rx_fps_jiffies ) < HZ )
2009-03-11 23:32:03 -07:00
return ;
stats - > be_rx_fps = ( stats - > be_rx_frags - stats - > be_prev_rx_frags ) /
2009-03-24 16:40:13 -07:00
( ( now - stats - > rx_fps_jiffies ) / HZ ) ;
2009-03-11 23:32:03 -07:00
2009-03-24 16:40:13 -07:00
stats - > rx_fps_jiffies = now ;
2009-03-11 23:32:03 -07:00
stats - > be_prev_rx_frags = stats - > be_rx_frags ;
eqd = stats - > be_rx_fps / 110000 ;
eqd = eqd < < 3 ;
if ( eqd > rx_eq - > max_eqd )
eqd = rx_eq - > max_eqd ;
if ( eqd < rx_eq - > min_eqd )
eqd = rx_eq - > min_eqd ;
if ( eqd < 10 )
eqd = 0 ;
if ( eqd ! = rx_eq - > cur_eqd )
2009-07-27 22:52:03 +00:00
be_cmd_modify_eqd ( adapter , rx_eq - > q . id , eqd ) ;
2009-03-11 23:32:03 -07:00
rx_eq - > cur_eqd = eqd ;
}
static struct net_device_stats * be_get_stats ( struct net_device * dev )
{
2009-10-07 03:11:20 -07:00
return & dev - > stats ;
2009-03-11 23:32:03 -07:00
}
2009-03-27 00:25:24 -07:00
static u32 be_calc_rate ( u64 bytes , unsigned long ticks )
{
u64 rate = bytes ;
do_div ( rate , ticks / HZ ) ;
rate < < = 3 ; /* bytes/sec -> bits/sec */
do_div ( rate , 1000000ul ) ; /* MB/Sec */
return rate ;
}
2009-03-24 16:40:13 -07:00
static void be_tx_rate_update ( struct be_adapter * adapter )
{
struct be_drvr_stats * stats = drvr_stats ( adapter ) ;
ulong now = jiffies ;
/* Wrapped around? */
if ( time_before ( now , stats - > be_tx_jiffies ) ) {
stats - > be_tx_jiffies = now ;
return ;
}
/* Update tx rate once in two seconds */
if ( ( now - stats - > be_tx_jiffies ) > 2 * HZ ) {
2009-03-27 00:25:24 -07:00
stats - > be_tx_rate = be_calc_rate ( stats - > be_tx_bytes
- stats - > be_tx_bytes_prev ,
now - stats - > be_tx_jiffies ) ;
2009-03-24 16:40:13 -07:00
stats - > be_tx_jiffies = now ;
stats - > be_tx_bytes_prev = stats - > be_tx_bytes ;
}
}
2009-03-11 23:32:03 -07:00
static void be_tx_stats_update ( struct be_adapter * adapter ,
u32 wrb_cnt , u32 copied , bool stopped )
{
2009-03-24 16:40:13 -07:00
struct be_drvr_stats * stats = drvr_stats ( adapter ) ;
2009-03-11 23:32:03 -07:00
stats - > be_tx_reqs + + ;
stats - > be_tx_wrbs + = wrb_cnt ;
stats - > be_tx_bytes + = copied ;
if ( stopped )
stats - > be_tx_stops + + ;
}
/* Determine number of WRB entries needed to xmit data in an skb */
static u32 wrb_cnt_for_skb ( struct sk_buff * skb , bool * dummy )
{
2009-06-09 01:01:31 -07:00
int cnt = ( skb - > len > skb - > data_len ) ;
cnt + = skb_shinfo ( skb ) - > nr_frags ;
2009-03-11 23:32:03 -07:00
/* to account for hdr wrb */
cnt + + ;
if ( cnt & 1 ) {
/* add a dummy to make it an even num */
cnt + + ;
* dummy = true ;
} else
* dummy = false ;
BUG_ON ( cnt > BE_MAX_TX_FRAG_COUNT ) ;
return cnt ;
}
static inline void wrb_fill ( struct be_eth_wrb * wrb , u64 addr , int len )
{
wrb - > frag_pa_hi = upper_32_bits ( addr ) ;
wrb - > frag_pa_lo = addr & 0xFFFFFFFF ;
wrb - > frag_len = len & ETH_WRB_FRAG_LEN_MASK ;
}
static void wrb_fill_hdr ( struct be_eth_hdr_wrb * hdr , struct sk_buff * skb ,
bool vlan , u32 wrb_cnt , u32 len )
{
memset ( hdr , 0 , sizeof ( * hdr ) ) ;
AMAP_SET_BITS ( struct amap_eth_hdr_wrb , crc , hdr , 1 ) ;
if ( skb_shinfo ( skb ) - > gso_segs > 1 & & skb_shinfo ( skb ) - > gso_size ) {
AMAP_SET_BITS ( struct amap_eth_hdr_wrb , lso , hdr , 1 ) ;
AMAP_SET_BITS ( struct amap_eth_hdr_wrb , lso_mss ,
hdr , skb_shinfo ( skb ) - > gso_size ) ;
} else if ( skb - > ip_summed = = CHECKSUM_PARTIAL ) {
if ( is_tcp_pkt ( skb ) )
AMAP_SET_BITS ( struct amap_eth_hdr_wrb , tcpcs , hdr , 1 ) ;
else if ( is_udp_pkt ( skb ) )
AMAP_SET_BITS ( struct amap_eth_hdr_wrb , udpcs , hdr , 1 ) ;
}
if ( vlan & & vlan_tx_tag_present ( skb ) ) {
AMAP_SET_BITS ( struct amap_eth_hdr_wrb , vlan , hdr , 1 ) ;
AMAP_SET_BITS ( struct amap_eth_hdr_wrb , vlan_tag ,
hdr , vlan_tx_tag_get ( skb ) ) ;
}
AMAP_SET_BITS ( struct amap_eth_hdr_wrb , event , hdr , 1 ) ;
AMAP_SET_BITS ( struct amap_eth_hdr_wrb , complete , hdr , 1 ) ;
AMAP_SET_BITS ( struct amap_eth_hdr_wrb , num_wrb , hdr , wrb_cnt ) ;
AMAP_SET_BITS ( struct amap_eth_hdr_wrb , len , hdr , len ) ;
}
static int make_tx_wrbs ( struct be_adapter * adapter ,
struct sk_buff * skb , u32 wrb_cnt , bool dummy_wrb )
{
u64 busaddr ;
u32 i , copied = 0 ;
struct pci_dev * pdev = adapter - > pdev ;
struct sk_buff * first_skb = skb ;
struct be_queue_info * txq = & adapter - > tx_obj . q ;
struct be_eth_wrb * wrb ;
struct be_eth_hdr_wrb * hdr ;
hdr = queue_head_node ( txq ) ;
2009-09-04 03:12:29 +00:00
atomic_add ( wrb_cnt , & txq - > used ) ;
2009-03-11 23:32:03 -07:00
queue_head_inc ( txq ) ;
2009-06-09 01:01:31 -07:00
if ( skb - > len > skb - > data_len ) {
int len = skb - > len - skb - > data_len ;
2009-12-02 16:48:18 +00:00
busaddr = pci_map_single ( pdev , skb - > data , len ,
PCI_DMA_TODEVICE ) ;
2009-06-09 01:01:31 -07:00
wrb = queue_head_node ( txq ) ;
wrb_fill ( wrb , busaddr , len ) ;
be_dws_cpu_to_le ( wrb , sizeof ( * wrb ) ) ;
queue_head_inc ( txq ) ;
copied + = len ;
}
2009-03-11 23:32:03 -07:00
2009-06-09 01:01:31 -07:00
for ( i = 0 ; i < skb_shinfo ( skb ) - > nr_frags ; i + + ) {
struct skb_frag_struct * frag =
& skb_shinfo ( skb ) - > frags [ i ] ;
2009-12-02 16:48:18 +00:00
busaddr = pci_map_page ( pdev , frag - > page ,
frag - > page_offset ,
frag - > size , PCI_DMA_TODEVICE ) ;
2009-06-09 01:01:31 -07:00
wrb = queue_head_node ( txq ) ;
wrb_fill ( wrb , busaddr , frag - > size ) ;
be_dws_cpu_to_le ( wrb , sizeof ( * wrb ) ) ;
queue_head_inc ( txq ) ;
copied + = frag - > size ;
2009-03-11 23:32:03 -07:00
}
if ( dummy_wrb ) {
wrb = queue_head_node ( txq ) ;
wrb_fill ( wrb , 0 , 0 ) ;
be_dws_cpu_to_le ( wrb , sizeof ( * wrb ) ) ;
queue_head_inc ( txq ) ;
}
wrb_fill_hdr ( hdr , first_skb , adapter - > vlan_grp ? true : false ,
wrb_cnt , copied ) ;
be_dws_cpu_to_le ( hdr , sizeof ( * hdr ) ) ;
return copied ;
}
2009-08-31 19:50:58 +00:00
static netdev_tx_t be_xmit ( struct sk_buff * skb ,
2009-09-17 10:30:13 -07:00
struct net_device * netdev )
2009-03-11 23:32:03 -07:00
{
struct be_adapter * adapter = netdev_priv ( netdev ) ;
struct be_tx_obj * tx_obj = & adapter - > tx_obj ;
struct be_queue_info * txq = & tx_obj - > q ;
u32 wrb_cnt = 0 , copied = 0 ;
u32 start = txq - > head ;
bool dummy_wrb , stopped = false ;
wrb_cnt = wrb_cnt_for_skb ( skb , & dummy_wrb ) ;
copied = make_tx_wrbs ( adapter , skb , wrb_cnt , dummy_wrb ) ;
2009-09-04 03:12:29 +00:00
if ( copied ) {
/* record the sent skb in the sent_skb table */
BUG_ON ( tx_obj - > sent_skb_list [ start ] ) ;
tx_obj - > sent_skb_list [ start ] = skb ;
/* Ensure txq has space for the next skb; Else stop the queue
* * BEFORE * ringing the tx doorbell , so that we serialze the
* tx compls of the current transmit which ' ll wake up the queue
*/
if ( ( BE_MAX_TX_FRAG_COUNT + atomic_read ( & txq - > used ) ) > =
txq - > len ) {
netif_stop_queue ( netdev ) ;
stopped = true ;
}
2009-03-11 23:32:03 -07:00
2009-09-04 03:12:29 +00:00
be_txq_notify ( adapter , txq - > id , wrb_cnt ) ;
2009-03-11 23:32:03 -07:00
2009-09-04 03:12:29 +00:00
be_tx_stats_update ( adapter , wrb_cnt , copied , stopped ) ;
} else {
txq - > head = start ;
dev_kfree_skb_any ( skb ) ;
2009-03-11 23:32:03 -07:00
}
return NETDEV_TX_OK ;
}
static int be_change_mtu ( struct net_device * netdev , int new_mtu )
{
struct be_adapter * adapter = netdev_priv ( netdev ) ;
if ( new_mtu < BE_MIN_MTU | |
new_mtu > BE_MAX_JUMBO_FRAME_SIZE ) {
dev_info ( & adapter - > pdev - > dev ,
" MTU must be between %d and %d bytes \n " ,
BE_MIN_MTU , BE_MAX_JUMBO_FRAME_SIZE ) ;
return - EINVAL ;
}
dev_info ( & adapter - > pdev - > dev , " MTU changed from %d to %d bytes \n " ,
netdev - > mtu , new_mtu ) ;
netdev - > mtu = new_mtu ;
return 0 ;
}
/*
* if there are BE_NUM_VLANS_SUPPORTED or lesser number of VLANS configured ,
* program them in BE . If more than BE_NUM_VLANS_SUPPORTED are configured ,
* set the BE in promiscuous VLAN mode .
*/
2009-09-17 10:30:13 -07:00
static int be_vid_config ( struct be_adapter * adapter )
2009-03-11 23:32:03 -07:00
{
u16 vtag [ BE_NUM_VLANS_SUPPORTED ] ;
u16 ntags = 0 , i ;
2009-09-17 10:30:13 -07:00
int status ;
2009-03-11 23:32:03 -07:00
if ( adapter - > num_vlans < = BE_NUM_VLANS_SUPPORTED ) {
/* Construct VLAN Table to give to HW */
for ( i = 0 ; i < VLAN_GROUP_ARRAY_LEN ; i + + ) {
if ( adapter - > vlan_tag [ i ] ) {
vtag [ ntags ] = cpu_to_le16 ( i ) ;
ntags + + ;
}
}
2009-09-17 10:30:13 -07:00
status = be_cmd_vlan_config ( adapter , adapter - > if_handle ,
vtag , ntags , 1 , 0 ) ;
2009-03-11 23:32:03 -07:00
} else {
2009-09-17 10:30:13 -07:00
status = be_cmd_vlan_config ( adapter , adapter - > if_handle ,
NULL , 0 , 1 , 1 ) ;
2009-03-11 23:32:03 -07:00
}
2009-09-17 10:30:13 -07:00
return status ;
2009-03-11 23:32:03 -07:00
}
static void be_vlan_register ( struct net_device * netdev , struct vlan_group * grp )
{
struct be_adapter * adapter = netdev_priv ( netdev ) ;
struct be_eq_obj * rx_eq = & adapter - > rx_eq ;
struct be_eq_obj * tx_eq = & adapter - > tx_eq ;
2009-07-27 22:52:03 +00:00
be_eq_notify ( adapter , rx_eq - > q . id , false , false , 0 ) ;
be_eq_notify ( adapter , tx_eq - > q . id , false , false , 0 ) ;
2009-03-11 23:32:03 -07:00
adapter - > vlan_grp = grp ;
2009-07-27 22:52:03 +00:00
be_eq_notify ( adapter , rx_eq - > q . id , true , false , 0 ) ;
be_eq_notify ( adapter , tx_eq - > q . id , true , false , 0 ) ;
2009-03-11 23:32:03 -07:00
}
static void be_vlan_add_vid ( struct net_device * netdev , u16 vid )
{
struct be_adapter * adapter = netdev_priv ( netdev ) ;
adapter - > num_vlans + + ;
adapter - > vlan_tag [ vid ] = 1 ;
2009-09-17 10:30:13 -07:00
be_vid_config ( adapter ) ;
2009-03-11 23:32:03 -07:00
}
static void be_vlan_rem_vid ( struct net_device * netdev , u16 vid )
{
struct be_adapter * adapter = netdev_priv ( netdev ) ;
adapter - > num_vlans - - ;
adapter - > vlan_tag [ vid ] = 0 ;
vlan_group_set_device ( adapter - > vlan_grp , vid , NULL ) ;
2009-09-17 10:30:13 -07:00
be_vid_config ( adapter ) ;
2009-03-11 23:32:03 -07:00
}
2009-06-18 00:09:25 +00:00
static void be_set_multicast_list ( struct net_device * netdev )
2009-03-11 23:32:03 -07:00
{
struct be_adapter * adapter = netdev_priv ( netdev ) ;
2009-06-18 00:09:25 +00:00
if ( netdev - > flags & IFF_PROMISC ) {
2009-07-27 22:52:03 +00:00
be_cmd_promiscuous_config ( adapter , adapter - > port_num , 1 ) ;
2009-06-18 00:09:25 +00:00
adapter - > promiscuous = true ;
goto done ;
2009-03-11 23:32:03 -07:00
}
2009-06-18 00:09:25 +00:00
/* BE was previously in promiscous mode; disable it */
if ( adapter - > promiscuous ) {
adapter - > promiscuous = false ;
2009-07-27 22:52:03 +00:00
be_cmd_promiscuous_config ( adapter , adapter - > port_num , 0 ) ;
2009-03-11 23:32:03 -07:00
}
2009-11-22 22:01:10 +00:00
/* Enable multicast promisc if num configured exceeds what we support */
if ( netdev - > flags & IFF_ALLMULTI | | netdev - > mc_count > BE_MAX_MC ) {
be_cmd_multicast_set ( adapter , adapter - > if_handle , NULL , 0 ,
& adapter - > mc_cmd_mem ) ;
2009-06-18 00:09:25 +00:00
goto done ;
2009-03-11 23:32:03 -07:00
}
2009-07-27 22:52:03 +00:00
be_cmd_multicast_set ( adapter , adapter - > if_handle , netdev - > mc_list ,
2009-11-22 22:01:10 +00:00
netdev - > mc_count , & adapter - > mc_cmd_mem ) ;
2009-06-18 00:09:25 +00:00
done :
return ;
2009-03-11 23:32:03 -07:00
}
2009-03-24 16:40:13 -07:00
static void be_rx_rate_update ( struct be_adapter * adapter )
2009-03-11 23:32:03 -07:00
{
2009-03-24 16:40:13 -07:00
struct be_drvr_stats * stats = drvr_stats ( adapter ) ;
ulong now = jiffies ;
2009-03-11 23:32:03 -07:00
2009-03-24 16:40:13 -07:00
/* Wrapped around */
if ( time_before ( now , stats - > be_rx_jiffies ) ) {
stats - > be_rx_jiffies = now ;
return ;
}
2009-03-11 23:32:03 -07:00
/* Update the rate once in two seconds */
2009-03-24 16:40:13 -07:00
if ( ( now - stats - > be_rx_jiffies ) < 2 * HZ )
2009-03-11 23:32:03 -07:00
return ;
2009-03-27 00:25:24 -07:00
stats - > be_rx_rate = be_calc_rate ( stats - > be_rx_bytes
- stats - > be_rx_bytes_prev ,
now - stats - > be_rx_jiffies ) ;
2009-03-24 16:40:13 -07:00
stats - > be_rx_jiffies = now ;
2009-03-11 23:32:03 -07:00
stats - > be_rx_bytes_prev = stats - > be_rx_bytes ;
}
2009-03-24 16:40:13 -07:00
static void be_rx_stats_update ( struct be_adapter * adapter ,
u32 pktsize , u16 numfrags )
{
struct be_drvr_stats * stats = drvr_stats ( adapter ) ;
stats - > be_rx_compl + + ;
stats - > be_rx_frags + = numfrags ;
stats - > be_rx_bytes + = pktsize ;
}
2009-04-13 15:41:22 -07:00
static inline bool do_pkt_csum ( struct be_eth_rx_compl * rxcp , bool cso )
{
u8 l4_cksm , ip_version , ipcksm , tcpf = 0 , udpf = 0 , ipv6_chk ;
l4_cksm = AMAP_GET_BITS ( struct amap_eth_rx_compl , l4_cksm , rxcp ) ;
ipcksm = AMAP_GET_BITS ( struct amap_eth_rx_compl , ipcksm , rxcp ) ;
ip_version = AMAP_GET_BITS ( struct amap_eth_rx_compl , ip_version , rxcp ) ;
if ( ip_version ) {
tcpf = AMAP_GET_BITS ( struct amap_eth_rx_compl , tcpf , rxcp ) ;
udpf = AMAP_GET_BITS ( struct amap_eth_rx_compl , udpf , rxcp ) ;
}
ipv6_chk = ( ip_version & & ( tcpf | | udpf ) ) ;
return ( ( l4_cksm & & ipv6_chk & & ipcksm ) & & cso ) ? false : true ;
}
2009-03-11 23:32:03 -07:00
static struct be_rx_page_info *
get_rx_page_info ( struct be_adapter * adapter , u16 frag_idx )
{
struct be_rx_page_info * rx_page_info ;
struct be_queue_info * rxq = & adapter - > rx_obj . q ;
rx_page_info = & adapter - > rx_obj . page_info_tbl [ frag_idx ] ;
BUG_ON ( ! rx_page_info - > page ) ;
if ( rx_page_info - > last_page_user )
pci_unmap_page ( adapter - > pdev , pci_unmap_addr ( rx_page_info , bus ) ,
adapter - > big_page_size , PCI_DMA_FROMDEVICE ) ;
atomic_dec ( & rxq - > used ) ;
return rx_page_info ;
}
/* Throwaway the data in the Rx completion */
static void be_rx_compl_discard ( struct be_adapter * adapter ,
struct be_eth_rx_compl * rxcp )
{
struct be_queue_info * rxq = & adapter - > rx_obj . q ;
struct be_rx_page_info * page_info ;
u16 rxq_idx , i , num_rcvd ;
rxq_idx = AMAP_GET_BITS ( struct amap_eth_rx_compl , fragndx , rxcp ) ;
num_rcvd = AMAP_GET_BITS ( struct amap_eth_rx_compl , numfrags , rxcp ) ;
for ( i = 0 ; i < num_rcvd ; i + + ) {
page_info = get_rx_page_info ( adapter , rxq_idx ) ;
put_page ( page_info - > page ) ;
memset ( page_info , 0 , sizeof ( * page_info ) ) ;
index_inc ( & rxq_idx , rxq - > len ) ;
}
}
/*
* skb_fill_rx_data forms a complete skb for an ether frame
* indicated by rxcp .
*/
static void skb_fill_rx_data ( struct be_adapter * adapter ,
struct sk_buff * skb , struct be_eth_rx_compl * rxcp )
{
struct be_queue_info * rxq = & adapter - > rx_obj . q ;
struct be_rx_page_info * page_info ;
2009-06-26 02:51:07 +00:00
u16 rxq_idx , i , num_rcvd , j ;
2009-07-22 09:28:55 -07:00
u32 pktsize , hdr_len , curr_frag_len , size ;
2009-03-11 23:32:03 -07:00
u8 * start ;
rxq_idx = AMAP_GET_BITS ( struct amap_eth_rx_compl , fragndx , rxcp ) ;
pktsize = AMAP_GET_BITS ( struct amap_eth_rx_compl , pktsize , rxcp ) ;
num_rcvd = AMAP_GET_BITS ( struct amap_eth_rx_compl , numfrags , rxcp ) ;
page_info = get_rx_page_info ( adapter , rxq_idx ) ;
start = page_address ( page_info - > page ) + page_info - > page_offset ;
prefetch ( start ) ;
/* Copy data in the first descriptor of this completion */
curr_frag_len = min ( pktsize , rx_frag_size ) ;
/* Copy the header portion into skb_data */
hdr_len = min ( ( u32 ) BE_HDR_LEN , curr_frag_len ) ;
memcpy ( skb - > data , start , hdr_len ) ;
skb - > len = curr_frag_len ;
if ( curr_frag_len < = BE_HDR_LEN ) { /* tiny packet */
/* Complete packet has now been moved to data */
put_page ( page_info - > page ) ;
skb - > data_len = 0 ;
skb - > tail + = curr_frag_len ;
} else {
skb_shinfo ( skb ) - > nr_frags = 1 ;
skb_shinfo ( skb ) - > frags [ 0 ] . page = page_info - > page ;
skb_shinfo ( skb ) - > frags [ 0 ] . page_offset =
page_info - > page_offset + hdr_len ;
skb_shinfo ( skb ) - > frags [ 0 ] . size = curr_frag_len - hdr_len ;
skb - > data_len = curr_frag_len - hdr_len ;
skb - > tail + = hdr_len ;
}
memset ( page_info , 0 , sizeof ( * page_info ) ) ;
if ( pktsize < = rx_frag_size ) {
BUG_ON ( num_rcvd ! = 1 ) ;
2009-06-10 02:21:56 +00:00
goto done ;
2009-03-11 23:32:03 -07:00
}
/* More frags present for this completion */
2009-07-22 09:28:55 -07:00
size = pktsize ;
2009-06-26 02:51:07 +00:00
for ( i = 1 , j = 0 ; i < num_rcvd ; i + + ) {
2009-07-22 09:28:55 -07:00
size - = curr_frag_len ;
2009-03-11 23:32:03 -07:00
index_inc ( & rxq_idx , rxq - > len ) ;
page_info = get_rx_page_info ( adapter , rxq_idx ) ;
2009-07-22 09:28:55 -07:00
curr_frag_len = min ( size , rx_frag_size ) ;
2009-03-11 23:32:03 -07:00
2009-06-26 02:51:07 +00:00
/* Coalesce all frags from the same physical page in one slot */
if ( page_info - > page_offset = = 0 ) {
/* Fresh page */
j + + ;
skb_shinfo ( skb ) - > frags [ j ] . page = page_info - > page ;
skb_shinfo ( skb ) - > frags [ j ] . page_offset =
page_info - > page_offset ;
skb_shinfo ( skb ) - > frags [ j ] . size = 0 ;
skb_shinfo ( skb ) - > nr_frags + + ;
} else {
put_page ( page_info - > page ) ;
}
skb_shinfo ( skb ) - > frags [ j ] . size + = curr_frag_len ;
2009-03-11 23:32:03 -07:00
skb - > len + = curr_frag_len ;
skb - > data_len + = curr_frag_len ;
memset ( page_info , 0 , sizeof ( * page_info ) ) ;
}
2009-06-26 02:51:07 +00:00
BUG_ON ( j > MAX_SKB_FRAGS ) ;
2009-03-11 23:32:03 -07:00
2009-06-10 02:21:56 +00:00
done :
2009-03-24 16:40:13 -07:00
be_rx_stats_update ( adapter , pktsize , num_rcvd ) ;
2009-03-11 23:32:03 -07:00
return ;
}
2009-07-21 12:36:19 -07:00
/* Process the RX completion indicated by rxcp when GRO is disabled */
2009-03-11 23:32:03 -07:00
static void be_rx_compl_process ( struct be_adapter * adapter ,
struct be_eth_rx_compl * rxcp )
{
struct sk_buff * skb ;
2009-09-30 21:58:22 -07:00
u32 vlanf , vid ;
u8 vtm ;
2009-03-11 23:32:03 -07:00
2009-09-30 21:58:22 -07:00
vlanf = AMAP_GET_BITS ( struct amap_eth_rx_compl , vtp , rxcp ) ;
vtm = AMAP_GET_BITS ( struct amap_eth_rx_compl , vtm , rxcp ) ;
/* vlanf could be wrongly set in some cards.
* ignore if vtm is not set */
2009-12-11 22:59:09 -08:00
if ( ( adapter - > cap & 0x400 ) & & ! vtm )
2009-09-30 21:58:22 -07:00
vlanf = 0 ;
2009-03-11 23:32:03 -07:00
2009-10-13 05:34:20 +00:00
skb = netdev_alloc_skb_ip_align ( adapter - > netdev , BE_HDR_LEN ) ;
2009-03-11 23:32:03 -07:00
if ( ! skb ) {
if ( net_ratelimit ( ) )
dev_warn ( & adapter - > pdev - > dev , " skb alloc failed \n " ) ;
be_rx_compl_discard ( adapter , rxcp ) ;
return ;
}
skb_fill_rx_data ( adapter , skb , rxcp ) ;
2009-04-13 15:41:22 -07:00
if ( do_pkt_csum ( rxcp , adapter - > rx_csum ) )
2009-03-11 23:32:03 -07:00
skb - > ip_summed = CHECKSUM_NONE ;
2009-04-13 15:41:22 -07:00
else
skb - > ip_summed = CHECKSUM_UNNECESSARY ;
2009-03-11 23:32:03 -07:00
skb - > truesize = skb - > len + sizeof ( struct sk_buff ) ;
skb - > protocol = eth_type_trans ( skb , adapter - > netdev ) ;
skb - > dev = adapter - > netdev ;
2009-09-30 21:58:22 -07:00
if ( vlanf ) {
2009-03-11 23:32:03 -07:00
if ( ! adapter - > vlan_grp | | adapter - > num_vlans = = 0 ) {
kfree_skb ( skb ) ;
return ;
}
vid = AMAP_GET_BITS ( struct amap_eth_rx_compl , vlan_tag , rxcp ) ;
vid = be16_to_cpu ( vid ) ;
vlan_hwaccel_receive_skb ( skb , adapter - > vlan_grp , vid ) ;
} else {
netif_receive_skb ( skb ) ;
}
return ;
}
2009-07-21 12:36:19 -07:00
/* Process the RX completion indicated by rxcp when GRO is enabled */
static void be_rx_compl_process_gro ( struct be_adapter * adapter ,
2009-03-11 23:32:03 -07:00
struct be_eth_rx_compl * rxcp )
{
struct be_rx_page_info * page_info ;
2009-07-21 12:36:19 -07:00
struct sk_buff * skb = NULL ;
2009-03-11 23:32:03 -07:00
struct be_queue_info * rxq = & adapter - > rx_obj . q ;
2009-07-21 12:36:19 -07:00
struct be_eq_obj * eq_obj = & adapter - > rx_eq ;
2009-03-11 23:32:03 -07:00
u32 num_rcvd , pkt_size , remaining , vlanf , curr_frag_len ;
2009-06-26 02:51:07 +00:00
u16 i , rxq_idx = 0 , vid , j ;
2009-09-30 21:58:22 -07:00
u8 vtm ;
2009-03-11 23:32:03 -07:00
num_rcvd = AMAP_GET_BITS ( struct amap_eth_rx_compl , numfrags , rxcp ) ;
pkt_size = AMAP_GET_BITS ( struct amap_eth_rx_compl , pktsize , rxcp ) ;
vlanf = AMAP_GET_BITS ( struct amap_eth_rx_compl , vtp , rxcp ) ;
rxq_idx = AMAP_GET_BITS ( struct amap_eth_rx_compl , fragndx , rxcp ) ;
2009-09-30 21:58:22 -07:00
vtm = AMAP_GET_BITS ( struct amap_eth_rx_compl , vtm , rxcp ) ;
/* vlanf could be wrongly set in some cards.
* ignore if vtm is not set */
2009-12-11 22:59:09 -08:00
if ( ( adapter - > cap & 0x400 ) & & ! vtm )
2009-09-30 21:58:22 -07:00
vlanf = 0 ;
2009-03-11 23:32:03 -07:00
2009-07-21 12:36:19 -07:00
skb = napi_get_frags ( & eq_obj - > napi ) ;
if ( ! skb ) {
be_rx_compl_discard ( adapter , rxcp ) ;
return ;
}
2009-03-11 23:32:03 -07:00
remaining = pkt_size ;
2009-06-26 02:51:07 +00:00
for ( i = 0 , j = - 1 ; i < num_rcvd ; i + + ) {
2009-03-11 23:32:03 -07:00
page_info = get_rx_page_info ( adapter , rxq_idx ) ;
curr_frag_len = min ( remaining , rx_frag_size ) ;
2009-06-26 02:51:07 +00:00
/* Coalesce all frags from the same physical page in one slot */
if ( i = = 0 | | page_info - > page_offset = = 0 ) {
/* First frag or Fresh page */
j + + ;
2009-07-21 12:36:19 -07:00
skb_shinfo ( skb ) - > frags [ j ] . page = page_info - > page ;
skb_shinfo ( skb ) - > frags [ j ] . page_offset =
page_info - > page_offset ;
skb_shinfo ( skb ) - > frags [ j ] . size = 0 ;
2009-06-26 02:51:07 +00:00
} else {
put_page ( page_info - > page ) ;
}
2009-07-21 12:36:19 -07:00
skb_shinfo ( skb ) - > frags [ j ] . size + = curr_frag_len ;
2009-03-11 23:32:03 -07:00
2009-06-26 02:51:07 +00:00
remaining - = curr_frag_len ;
2009-03-11 23:32:03 -07:00
index_inc ( & rxq_idx , rxq - > len ) ;
memset ( page_info , 0 , sizeof ( * page_info ) ) ;
}
2009-06-26 02:51:07 +00:00
BUG_ON ( j > MAX_SKB_FRAGS ) ;
2009-03-11 23:32:03 -07:00
2009-07-21 12:36:19 -07:00
skb_shinfo ( skb ) - > nr_frags = j + 1 ;
skb - > len = pkt_size ;
skb - > data_len = pkt_size ;
skb - > truesize + = pkt_size ;
skb - > ip_summed = CHECKSUM_UNNECESSARY ;
2009-03-11 23:32:03 -07:00
if ( likely ( ! vlanf ) ) {
2009-07-21 12:36:19 -07:00
napi_gro_frags ( & eq_obj - > napi ) ;
2009-03-11 23:32:03 -07:00
} else {
vid = AMAP_GET_BITS ( struct amap_eth_rx_compl , vlan_tag , rxcp ) ;
vid = be16_to_cpu ( vid ) ;
if ( ! adapter - > vlan_grp | | adapter - > num_vlans = = 0 )
return ;
2009-07-21 12:36:19 -07:00
vlan_gro_frags ( & eq_obj - > napi , adapter - > vlan_grp , vid ) ;
2009-03-11 23:32:03 -07:00
}
2009-03-24 16:40:13 -07:00
be_rx_stats_update ( adapter , pkt_size , num_rcvd ) ;
2009-03-11 23:32:03 -07:00
return ;
}
static struct be_eth_rx_compl * be_rx_compl_get ( struct be_adapter * adapter )
{
struct be_eth_rx_compl * rxcp = queue_tail_node ( & adapter - > rx_obj . cq ) ;
if ( rxcp - > dw [ offsetof ( struct amap_eth_rx_compl , valid ) / 32 ] = = 0 )
return NULL ;
be_dws_le_to_cpu ( rxcp , sizeof ( * rxcp ) ) ;
queue_tail_inc ( & adapter - > rx_obj . cq ) ;
return rxcp ;
}
2009-06-10 02:23:28 +00:00
/* To reset the valid bit, we need to reset the whole word as
* when walking the queue the valid entries are little - endian
* and invalid entries are host endian
*/
static inline void be_rx_compl_reset ( struct be_eth_rx_compl * rxcp )
{
rxcp - > dw [ offsetof ( struct amap_eth_rx_compl , valid ) / 32 ] = 0 ;
}
2009-03-11 23:32:03 -07:00
static inline struct page * be_alloc_pages ( u32 size )
{
gfp_t alloc_flags = GFP_ATOMIC ;
u32 order = get_order ( size ) ;
if ( order > 0 )
alloc_flags | = __GFP_COMP ;
return alloc_pages ( alloc_flags , order ) ;
}
/*
* Allocate a page , split it to fragments of size rx_frag_size and post as
* receive buffers to BE
*/
static void be_post_rx_frags ( struct be_adapter * adapter )
{
struct be_rx_page_info * page_info_tbl = adapter - > rx_obj . page_info_tbl ;
2010-01-21 22:52:08 -08:00
struct be_rx_page_info * page_info = NULL , * prev_page_info = NULL ;
2009-03-11 23:32:03 -07:00
struct be_queue_info * rxq = & adapter - > rx_obj . q ;
struct page * pagep = NULL ;
struct be_eth_rx_d * rxd ;
u64 page_dmaaddr = 0 , frag_dmaaddr ;
u32 posted , page_offset = 0 ;
page_info = & page_info_tbl [ rxq - > head ] ;
for ( posted = 0 ; posted < MAX_RX_POST & & ! page_info - > page ; posted + + ) {
if ( ! pagep ) {
pagep = be_alloc_pages ( adapter - > big_page_size ) ;
if ( unlikely ( ! pagep ) ) {
drvr_stats ( adapter ) - > be_ethrx_post_fail + + ;
break ;
}
page_dmaaddr = pci_map_page ( adapter - > pdev , pagep , 0 ,
adapter - > big_page_size ,
PCI_DMA_FROMDEVICE ) ;
page_info - > page_offset = 0 ;
} else {
get_page ( pagep ) ;
page_info - > page_offset = page_offset + rx_frag_size ;
}
page_offset = page_info - > page_offset ;
page_info - > page = pagep ;
pci_unmap_addr_set ( page_info , bus , page_dmaaddr ) ;
frag_dmaaddr = page_dmaaddr + page_info - > page_offset ;
rxd = queue_head_node ( rxq ) ;
rxd - > fragpa_lo = cpu_to_le32 ( frag_dmaaddr & 0xFFFFFFFF ) ;
rxd - > fragpa_hi = cpu_to_le32 ( upper_32_bits ( frag_dmaaddr ) ) ;
/* Any space left in the current big page for another frag? */
if ( ( page_offset + rx_frag_size + rx_frag_size ) >
adapter - > big_page_size ) {
pagep = NULL ;
page_info - > last_page_user = true ;
}
2010-01-21 22:52:08 -08:00
prev_page_info = page_info ;
queue_head_inc ( rxq ) ;
2009-03-11 23:32:03 -07:00
page_info = & page_info_tbl [ rxq - > head ] ;
}
if ( pagep )
2010-01-21 22:52:08 -08:00
prev_page_info - > last_page_user = true ;
2009-03-11 23:32:03 -07:00
if ( posted ) {
atomic_add ( posted , & rxq - > used ) ;
2009-07-27 22:52:03 +00:00
be_rxq_notify ( adapter , rxq - > id , posted ) ;
2009-03-19 23:56:20 -07:00
} else if ( atomic_read ( & rxq - > used ) = = 0 ) {
/* Let be_worker replenish when memory is available */
adapter - > rx_post_starved = true ;
2009-03-11 23:32:03 -07:00
}
return ;
}
2009-06-18 00:02:59 +00:00
static struct be_eth_tx_compl * be_tx_compl_get ( struct be_queue_info * tx_cq )
2009-03-11 23:32:03 -07:00
{
struct be_eth_tx_compl * txcp = queue_tail_node ( tx_cq ) ;
if ( txcp - > dw [ offsetof ( struct amap_eth_tx_compl , valid ) / 32 ] = = 0 )
return NULL ;
be_dws_le_to_cpu ( txcp , sizeof ( * txcp ) ) ;
txcp - > dw [ offsetof ( struct amap_eth_tx_compl , valid ) / 32 ] = 0 ;
queue_tail_inc ( tx_cq ) ;
return txcp ;
}
static void be_tx_compl_process ( struct be_adapter * adapter , u16 last_index )
{
struct be_queue_info * txq = & adapter - > tx_obj . q ;
2009-12-02 16:48:18 +00:00
struct be_eth_wrb * wrb ;
2009-03-11 23:32:03 -07:00
struct sk_buff * * sent_skbs = adapter - > tx_obj . sent_skb_list ;
struct sk_buff * sent_skb ;
2009-12-02 16:48:18 +00:00
u64 busaddr ;
2009-03-11 23:32:03 -07:00
u16 cur_index , num_wrbs = 0 ;
cur_index = txq - > tail ;
sent_skb = sent_skbs [ cur_index ] ;
BUG_ON ( ! sent_skb ) ;
sent_skbs [ cur_index ] = NULL ;
2009-12-02 16:48:18 +00:00
wrb = queue_tail_node ( txq ) ;
be_dws_le_to_cpu ( wrb , sizeof ( * wrb ) ) ;
busaddr = ( ( u64 ) wrb - > frag_pa_hi < < 32 ) | ( u64 ) wrb - > frag_pa_lo ;
if ( busaddr ! = 0 ) {
pci_unmap_single ( adapter - > pdev , busaddr ,
wrb - > frag_len , PCI_DMA_TODEVICE ) ;
}
num_wrbs + + ;
queue_tail_inc ( txq ) ;
2009-03-11 23:32:03 -07:00
2009-12-02 16:48:18 +00:00
while ( cur_index ! = last_index ) {
2009-03-11 23:32:03 -07:00
cur_index = txq - > tail ;
2009-12-02 16:48:18 +00:00
wrb = queue_tail_node ( txq ) ;
be_dws_le_to_cpu ( wrb , sizeof ( * wrb ) ) ;
busaddr = ( ( u64 ) wrb - > frag_pa_hi < < 32 ) | ( u64 ) wrb - > frag_pa_lo ;
if ( busaddr ! = 0 ) {
pci_unmap_page ( adapter - > pdev , busaddr ,
wrb - > frag_len , PCI_DMA_TODEVICE ) ;
}
2009-03-11 23:32:03 -07:00
num_wrbs + + ;
queue_tail_inc ( txq ) ;
2009-12-02 16:48:18 +00:00
}
2009-03-11 23:32:03 -07:00
atomic_sub ( num_wrbs , & txq - > used ) ;
2009-12-02 16:48:18 +00:00
2009-03-11 23:32:03 -07:00
kfree_skb ( sent_skb ) ;
}
2009-08-10 03:43:51 +00:00
static inline struct be_eq_entry * event_get ( struct be_eq_obj * eq_obj )
{
struct be_eq_entry * eqe = queue_tail_node ( & eq_obj - > q ) ;
if ( ! eqe - > evt )
return NULL ;
eqe - > evt = le32_to_cpu ( eqe - > evt ) ;
queue_tail_inc ( & eq_obj - > q ) ;
return eqe ;
}
static int event_handle ( struct be_adapter * adapter ,
struct be_eq_obj * eq_obj )
{
struct be_eq_entry * eqe ;
u16 num = 0 ;
while ( ( eqe = event_get ( eq_obj ) ) ! = NULL ) {
eqe - > evt = 0 ;
num + + ;
}
/* Deal with any spurious interrupts that come
* without events
*/
be_eq_notify ( adapter , eq_obj - > q . id , true , true , num ) ;
if ( num )
napi_schedule ( & eq_obj - > napi ) ;
return num ;
}
/* Just read and notify events without processing them.
* Used at the time of destroying event queues */
static void be_eq_clean ( struct be_adapter * adapter ,
struct be_eq_obj * eq_obj )
{
struct be_eq_entry * eqe ;
u16 num = 0 ;
while ( ( eqe = event_get ( eq_obj ) ) ! = NULL ) {
eqe - > evt = 0 ;
num + + ;
}
if ( num )
be_eq_notify ( adapter , eq_obj - > q . id , false , true , num ) ;
}
2009-03-11 23:32:03 -07:00
static void be_rx_q_clean ( struct be_adapter * adapter )
{
struct be_rx_page_info * page_info ;
struct be_queue_info * rxq = & adapter - > rx_obj . q ;
struct be_queue_info * rx_cq = & adapter - > rx_obj . cq ;
struct be_eth_rx_compl * rxcp ;
u16 tail ;
/* First cleanup pending rx completions */
while ( ( rxcp = be_rx_compl_get ( adapter ) ) ! = NULL ) {
be_rx_compl_discard ( adapter , rxcp ) ;
2009-06-10 02:23:28 +00:00
be_rx_compl_reset ( rxcp ) ;
2009-07-27 22:52:03 +00:00
be_cq_notify ( adapter , rx_cq - > id , true , 1 ) ;
2009-03-11 23:32:03 -07:00
}
/* Then free posted rx buffer that were not used */
tail = ( rxq - > head + rxq - > len - atomic_read ( & rxq - > used ) ) % rxq - > len ;
2009-08-10 03:43:23 +00:00
for ( ; atomic_read ( & rxq - > used ) > 0 ; index_inc ( & tail , rxq - > len ) ) {
2009-03-11 23:32:03 -07:00
page_info = get_rx_page_info ( adapter , tail ) ;
put_page ( page_info - > page ) ;
memset ( page_info , 0 , sizeof ( * page_info ) ) ;
}
BUG_ON ( atomic_read ( & rxq - > used ) ) ;
}
2009-08-10 03:42:43 +00:00
static void be_tx_compl_clean ( struct be_adapter * adapter )
2009-03-11 23:32:03 -07:00
{
2009-08-10 03:42:43 +00:00
struct be_queue_info * tx_cq = & adapter - > tx_obj . cq ;
2009-03-11 23:32:03 -07:00
struct be_queue_info * txq = & adapter - > tx_obj . q ;
2009-08-10 03:42:43 +00:00
struct be_eth_tx_compl * txcp ;
u16 end_idx , cmpl = 0 , timeo = 0 ;
/* Wait for a max of 200ms for all the tx-completions to arrive. */
do {
while ( ( txcp = be_tx_compl_get ( tx_cq ) ) ) {
end_idx = AMAP_GET_BITS ( struct amap_eth_tx_compl ,
wrb_index , txcp ) ;
be_tx_compl_process ( adapter , end_idx ) ;
cmpl + + ;
}
if ( cmpl ) {
be_cq_notify ( adapter , tx_cq - > id , false , cmpl ) ;
cmpl = 0 ;
}
if ( atomic_read ( & txq - > used ) = = 0 | | + + timeo > 200 )
break ;
mdelay ( 1 ) ;
} while ( true ) ;
if ( atomic_read ( & txq - > used ) )
dev_err ( & adapter - > pdev - > dev , " %d pending tx-completions \n " ,
atomic_read ( & txq - > used ) ) ;
2009-03-11 23:32:03 -07:00
}
2009-06-18 00:02:59 +00:00
static void be_mcc_queues_destroy ( struct be_adapter * adapter )
{
struct be_queue_info * q ;
2009-07-27 22:52:03 +00:00
q = & adapter - > mcc_obj . q ;
2009-06-18 00:02:59 +00:00
if ( q - > created )
2009-07-27 22:52:03 +00:00
be_cmd_q_destroy ( adapter , q , QTYPE_MCCQ ) ;
2009-06-18 00:02:59 +00:00
be_queue_free ( adapter , q ) ;
2009-07-27 22:52:03 +00:00
q = & adapter - > mcc_obj . cq ;
2009-06-18 00:02:59 +00:00
if ( q - > created )
2009-07-27 22:52:03 +00:00
be_cmd_q_destroy ( adapter , q , QTYPE_CQ ) ;
2009-06-18 00:02:59 +00:00
be_queue_free ( adapter , q ) ;
}
/* Must be called only after TX qs are created as MCC shares TX EQ */
static int be_mcc_queues_create ( struct be_adapter * adapter )
{
struct be_queue_info * q , * cq ;
/* Alloc MCC compl queue */
2009-07-27 22:52:03 +00:00
cq = & adapter - > mcc_obj . cq ;
2009-06-18 00:02:59 +00:00
if ( be_queue_alloc ( adapter , cq , MCC_CQ_LEN ,
2009-07-27 22:53:10 +00:00
sizeof ( struct be_mcc_compl ) ) )
2009-06-18 00:02:59 +00:00
goto err ;
/* Ask BE to create MCC compl queue; share TX's eq */
2009-07-27 22:52:03 +00:00
if ( be_cmd_cq_create ( adapter , cq , & adapter - > tx_eq . q , false , true , 0 ) )
2009-06-18 00:02:59 +00:00
goto mcc_cq_free ;
/* Alloc MCC queue */
2009-07-27 22:52:03 +00:00
q = & adapter - > mcc_obj . q ;
2009-06-18 00:02:59 +00:00
if ( be_queue_alloc ( adapter , q , MCC_Q_LEN , sizeof ( struct be_mcc_wrb ) ) )
goto mcc_cq_destroy ;
/* Ask BE to create MCC queue */
2009-07-27 22:52:03 +00:00
if ( be_cmd_mccq_create ( adapter , q , cq ) )
2009-06-18 00:02:59 +00:00
goto mcc_q_free ;
return 0 ;
mcc_q_free :
be_queue_free ( adapter , q ) ;
mcc_cq_destroy :
2009-07-27 22:52:03 +00:00
be_cmd_q_destroy ( adapter , cq , QTYPE_CQ ) ;
2009-06-18 00:02:59 +00:00
mcc_cq_free :
be_queue_free ( adapter , cq ) ;
err :
return - 1 ;
}
2009-03-11 23:32:03 -07:00
static void be_tx_queues_destroy ( struct be_adapter * adapter )
{
struct be_queue_info * q ;
q = & adapter - > tx_obj . q ;
2009-08-10 03:42:43 +00:00
if ( q - > created )
2009-07-27 22:52:03 +00:00
be_cmd_q_destroy ( adapter , q , QTYPE_TXQ ) ;
2009-03-11 23:32:03 -07:00
be_queue_free ( adapter , q ) ;
q = & adapter - > tx_obj . cq ;
if ( q - > created )
2009-07-27 22:52:03 +00:00
be_cmd_q_destroy ( adapter , q , QTYPE_CQ ) ;
2009-03-11 23:32:03 -07:00
be_queue_free ( adapter , q ) ;
2009-08-10 03:43:51 +00:00
/* Clear any residual events */
be_eq_clean ( adapter , & adapter - > tx_eq ) ;
2009-03-11 23:32:03 -07:00
q = & adapter - > tx_eq . q ;
if ( q - > created )
2009-07-27 22:52:03 +00:00
be_cmd_q_destroy ( adapter , q , QTYPE_EQ ) ;
2009-03-11 23:32:03 -07:00
be_queue_free ( adapter , q ) ;
}
static int be_tx_queues_create ( struct be_adapter * adapter )
{
struct be_queue_info * eq , * q , * cq ;
adapter - > tx_eq . max_eqd = 0 ;
adapter - > tx_eq . min_eqd = 0 ;
adapter - > tx_eq . cur_eqd = 96 ;
adapter - > tx_eq . enable_aic = false ;
/* Alloc Tx Event queue */
eq = & adapter - > tx_eq . q ;
if ( be_queue_alloc ( adapter , eq , EVNT_Q_LEN , sizeof ( struct be_eq_entry ) ) )
return - 1 ;
/* Ask BE to create Tx Event queue */
2009-07-27 22:52:03 +00:00
if ( be_cmd_eq_create ( adapter , eq , adapter - > tx_eq . cur_eqd ) )
2009-03-11 23:32:03 -07:00
goto tx_eq_free ;
/* Alloc TX eth compl queue */
cq = & adapter - > tx_obj . cq ;
if ( be_queue_alloc ( adapter , cq , TX_CQ_LEN ,
sizeof ( struct be_eth_tx_compl ) ) )
goto tx_eq_destroy ;
/* Ask BE to create Tx eth compl queue */
2009-07-27 22:52:03 +00:00
if ( be_cmd_cq_create ( adapter , cq , eq , false , false , 3 ) )
2009-03-11 23:32:03 -07:00
goto tx_cq_free ;
/* Alloc TX eth queue */
q = & adapter - > tx_obj . q ;
if ( be_queue_alloc ( adapter , q , TX_Q_LEN , sizeof ( struct be_eth_wrb ) ) )
goto tx_cq_destroy ;
/* Ask BE to create Tx eth queue */
2009-07-27 22:52:03 +00:00
if ( be_cmd_txq_create ( adapter , q , cq ) )
2009-03-11 23:32:03 -07:00
goto tx_q_free ;
return 0 ;
tx_q_free :
be_queue_free ( adapter , q ) ;
tx_cq_destroy :
2009-07-27 22:52:03 +00:00
be_cmd_q_destroy ( adapter , cq , QTYPE_CQ ) ;
2009-03-11 23:32:03 -07:00
tx_cq_free :
be_queue_free ( adapter , cq ) ;
tx_eq_destroy :
2009-07-27 22:52:03 +00:00
be_cmd_q_destroy ( adapter , eq , QTYPE_EQ ) ;
2009-03-11 23:32:03 -07:00
tx_eq_free :
be_queue_free ( adapter , eq ) ;
return - 1 ;
}
static void be_rx_queues_destroy ( struct be_adapter * adapter )
{
struct be_queue_info * q ;
q = & adapter - > rx_obj . q ;
if ( q - > created ) {
2009-07-27 22:52:03 +00:00
be_cmd_q_destroy ( adapter , q , QTYPE_RXQ ) ;
2009-03-11 23:32:03 -07:00
be_rx_q_clean ( adapter ) ;
}
be_queue_free ( adapter , q ) ;
q = & adapter - > rx_obj . cq ;
if ( q - > created )
2009-07-27 22:52:03 +00:00
be_cmd_q_destroy ( adapter , q , QTYPE_CQ ) ;
2009-03-11 23:32:03 -07:00
be_queue_free ( adapter , q ) ;
2009-08-10 03:43:51 +00:00
/* Clear any residual events */
be_eq_clean ( adapter , & adapter - > rx_eq ) ;
2009-03-11 23:32:03 -07:00
q = & adapter - > rx_eq . q ;
if ( q - > created )
2009-07-27 22:52:03 +00:00
be_cmd_q_destroy ( adapter , q , QTYPE_EQ ) ;
2009-03-11 23:32:03 -07:00
be_queue_free ( adapter , q ) ;
}
static int be_rx_queues_create ( struct be_adapter * adapter )
{
struct be_queue_info * eq , * q , * cq ;
int rc ;
adapter - > big_page_size = ( 1 < < get_order ( rx_frag_size ) ) * PAGE_SIZE ;
adapter - > rx_eq . max_eqd = BE_MAX_EQD ;
adapter - > rx_eq . min_eqd = 0 ;
adapter - > rx_eq . cur_eqd = 0 ;
adapter - > rx_eq . enable_aic = true ;
/* Alloc Rx Event queue */
eq = & adapter - > rx_eq . q ;
rc = be_queue_alloc ( adapter , eq , EVNT_Q_LEN ,
sizeof ( struct be_eq_entry ) ) ;
if ( rc )
return rc ;
/* Ask BE to create Rx Event queue */
2009-07-27 22:52:03 +00:00
rc = be_cmd_eq_create ( adapter , eq , adapter - > rx_eq . cur_eqd ) ;
2009-03-11 23:32:03 -07:00
if ( rc )
goto rx_eq_free ;
/* Alloc RX eth compl queue */
cq = & adapter - > rx_obj . cq ;
rc = be_queue_alloc ( adapter , cq , RX_CQ_LEN ,
sizeof ( struct be_eth_rx_compl ) ) ;
if ( rc )
goto rx_eq_destroy ;
/* Ask BE to create Rx eth compl queue */
2009-07-27 22:52:03 +00:00
rc = be_cmd_cq_create ( adapter , cq , eq , false , false , 3 ) ;
2009-03-11 23:32:03 -07:00
if ( rc )
goto rx_cq_free ;
/* Alloc RX eth queue */
q = & adapter - > rx_obj . q ;
rc = be_queue_alloc ( adapter , q , RX_Q_LEN , sizeof ( struct be_eth_rx_d ) ) ;
if ( rc )
goto rx_cq_destroy ;
/* Ask BE to create Rx eth queue */
2009-07-27 22:52:03 +00:00
rc = be_cmd_rxq_create ( adapter , q , cq - > id , rx_frag_size ,
2009-03-11 23:32:03 -07:00
BE_MAX_JUMBO_FRAME_SIZE , adapter - > if_handle , false ) ;
if ( rc )
goto rx_q_free ;
return 0 ;
rx_q_free :
be_queue_free ( adapter , q ) ;
rx_cq_destroy :
2009-07-27 22:52:03 +00:00
be_cmd_q_destroy ( adapter , cq , QTYPE_CQ ) ;
2009-03-11 23:32:03 -07:00
rx_cq_free :
be_queue_free ( adapter , cq ) ;
rx_eq_destroy :
2009-07-27 22:52:03 +00:00
be_cmd_q_destroy ( adapter , eq , QTYPE_EQ ) ;
2009-03-11 23:32:03 -07:00
rx_eq_free :
be_queue_free ( adapter , eq ) ;
return rc ;
}
2009-08-17 00:58:26 +00:00
/* There are 8 evt ids per func. Retruns the evt id's bit number */
static inline int be_evt_bit_get ( struct be_adapter * adapter , u32 eq_id )
{
return eq_id - 8 * be_pci_func ( adapter ) ;
}
2009-03-11 23:32:03 -07:00
static irqreturn_t be_intx ( int irq , void * dev )
{
struct be_adapter * adapter = dev ;
2009-07-27 22:52:03 +00:00
int isr ;
2009-03-11 23:32:03 -07:00
2009-07-27 22:52:03 +00:00
isr = ioread32 ( adapter - > csr + CEV_ISR0_OFFSET +
2009-07-27 22:52:23 +00:00
be_pci_func ( adapter ) * CEV_ISR_SIZE ) ;
2009-07-01 01:06:07 +00:00
if ( ! isr )
2009-07-27 22:52:03 +00:00
return IRQ_NONE ;
2009-03-11 23:32:03 -07:00
2009-07-27 22:52:03 +00:00
event_handle ( adapter , & adapter - > tx_eq ) ;
event_handle ( adapter , & adapter - > rx_eq ) ;
2009-07-01 01:06:07 +00:00
2009-07-27 22:52:03 +00:00
return IRQ_HANDLED ;
2009-03-11 23:32:03 -07:00
}
static irqreturn_t be_msix_rx ( int irq , void * dev )
{
struct be_adapter * adapter = dev ;
2009-07-27 22:52:03 +00:00
event_handle ( adapter , & adapter - > rx_eq ) ;
2009-03-11 23:32:03 -07:00
return IRQ_HANDLED ;
}
2009-06-18 00:02:59 +00:00
static irqreturn_t be_msix_tx_mcc ( int irq , void * dev )
2009-03-11 23:32:03 -07:00
{
struct be_adapter * adapter = dev ;
2009-07-27 22:52:03 +00:00
event_handle ( adapter , & adapter - > tx_eq ) ;
2009-03-11 23:32:03 -07:00
return IRQ_HANDLED ;
}
2009-07-21 12:36:19 -07:00
static inline bool do_gro ( struct be_adapter * adapter ,
2009-03-11 23:32:03 -07:00
struct be_eth_rx_compl * rxcp )
{
int err = AMAP_GET_BITS ( struct amap_eth_rx_compl , err , rxcp ) ;
int tcp_frame = AMAP_GET_BITS ( struct amap_eth_rx_compl , tcpf , rxcp ) ;
if ( err )
drvr_stats ( adapter ) - > be_rxcp_err + + ;
2009-07-21 12:36:19 -07:00
return ( tcp_frame & & ! err ) ? true : false ;
2009-03-11 23:32:03 -07:00
}
int be_poll_rx ( struct napi_struct * napi , int budget )
{
struct be_eq_obj * rx_eq = container_of ( napi , struct be_eq_obj , napi ) ;
struct be_adapter * adapter =
container_of ( rx_eq , struct be_adapter , rx_eq ) ;
struct be_queue_info * rx_cq = & adapter - > rx_obj . cq ;
struct be_eth_rx_compl * rxcp ;
u32 work_done ;
2009-11-29 17:57:22 +00:00
adapter - > stats . drvr_stats . be_rx_polls + + ;
2009-03-11 23:32:03 -07:00
for ( work_done = 0 ; work_done < budget ; work_done + + ) {
rxcp = be_rx_compl_get ( adapter ) ;
if ( ! rxcp )
break ;
2009-07-21 12:36:19 -07:00
if ( do_gro ( adapter , rxcp ) )
be_rx_compl_process_gro ( adapter , rxcp ) ;
2009-03-11 23:32:03 -07:00
else
be_rx_compl_process ( adapter , rxcp ) ;
2009-06-10 02:23:28 +00:00
be_rx_compl_reset ( rxcp ) ;
2009-03-11 23:32:03 -07:00
}
/* Refill the queue */
if ( atomic_read ( & adapter - > rx_obj . q . used ) < RX_FRAGS_REFILL_WM )
be_post_rx_frags ( adapter ) ;
/* All consumed */
if ( work_done < budget ) {
napi_complete ( napi ) ;
2009-07-27 22:52:03 +00:00
be_cq_notify ( adapter , rx_cq - > id , true , work_done ) ;
2009-03-11 23:32:03 -07:00
} else {
/* More to be consumed; continue with interrupts disabled */
2009-07-27 22:52:03 +00:00
be_cq_notify ( adapter , rx_cq - > id , false , work_done ) ;
2009-03-11 23:32:03 -07:00
}
return work_done ;
}
2009-06-18 00:02:59 +00:00
void be_process_tx ( struct be_adapter * adapter )
2009-03-11 23:32:03 -07:00
{
2009-06-18 00:02:59 +00:00
struct be_queue_info * txq = & adapter - > tx_obj . q ;
struct be_queue_info * tx_cq = & adapter - > tx_obj . cq ;
2009-03-11 23:32:03 -07:00
struct be_eth_tx_compl * txcp ;
u32 num_cmpl = 0 ;
u16 end_idx ;
2009-06-18 00:02:59 +00:00
while ( ( txcp = be_tx_compl_get ( tx_cq ) ) ) {
2009-03-11 23:32:03 -07:00
end_idx = AMAP_GET_BITS ( struct amap_eth_tx_compl ,
wrb_index , txcp ) ;
be_tx_compl_process ( adapter , end_idx ) ;
num_cmpl + + ;
}
2009-06-18 00:02:59 +00:00
if ( num_cmpl ) {
2009-07-27 22:52:03 +00:00
be_cq_notify ( adapter , tx_cq - > id , true , num_cmpl ) ;
2009-06-18 00:02:59 +00:00
/* As Tx wrbs have been freed up, wake up netdev queue if
* it was stopped due to lack of tx wrbs .
*/
if ( netif_queue_stopped ( adapter - > netdev ) & &
2009-03-11 23:32:03 -07:00
atomic_read ( & txq - > used ) < txq - > len / 2 ) {
2009-06-18 00:02:59 +00:00
netif_wake_queue ( adapter - > netdev ) ;
}
drvr_stats ( adapter ) - > be_tx_events + + ;
drvr_stats ( adapter ) - > be_tx_compl + = num_cmpl ;
2009-03-11 23:32:03 -07:00
}
2009-06-18 00:02:59 +00:00
}
/* As TX and MCC share the same EQ check for both TX and MCC completions.
* For TX / MCC we don ' t honour budget ; consume everything
*/
static int be_poll_tx_mcc ( struct napi_struct * napi , int budget )
{
struct be_eq_obj * tx_eq = container_of ( napi , struct be_eq_obj , napi ) ;
struct be_adapter * adapter =
container_of ( tx_eq , struct be_adapter , tx_eq ) ;
2009-03-11 23:32:03 -07:00
napi_complete ( napi ) ;
2009-06-18 00:02:59 +00:00
be_process_tx ( adapter ) ;
2009-03-11 23:32:03 -07:00
2009-07-27 22:52:03 +00:00
be_process_mcc ( adapter ) ;
2009-03-11 23:32:03 -07:00
return 1 ;
}
2009-03-19 23:56:20 -07:00
static void be_worker ( struct work_struct * work )
{
struct be_adapter * adapter =
container_of ( work , struct be_adapter , work . work ) ;
2009-09-17 10:30:13 -07:00
be_cmd_get_stats ( adapter , & adapter - > stats . cmd ) ;
2009-03-19 23:56:20 -07:00
/* Set EQ delay */
be_rx_eqd_update ( adapter ) ;
2009-03-24 16:40:13 -07:00
be_tx_rate_update ( adapter ) ;
be_rx_rate_update ( adapter ) ;
2009-03-19 23:56:20 -07:00
if ( adapter - > rx_post_starved ) {
adapter - > rx_post_starved = false ;
be_post_rx_frags ( adapter ) ;
}
schedule_delayed_work ( & adapter - > work , msecs_to_jiffies ( 1000 ) ) ;
}
2009-11-22 22:02:26 +00:00
static void be_msix_disable ( struct be_adapter * adapter )
{
if ( adapter - > msix_enabled ) {
pci_disable_msix ( adapter - > pdev ) ;
adapter - > msix_enabled = false ;
}
}
2009-03-11 23:32:03 -07:00
static void be_msix_enable ( struct be_adapter * adapter )
{
int i , status ;
for ( i = 0 ; i < BE_NUM_MSIX_VECTORS ; i + + )
adapter - > msix_entries [ i ] . entry = i ;
status = pci_enable_msix ( adapter - > pdev , adapter - > msix_entries ,
BE_NUM_MSIX_VECTORS ) ;
if ( status = = 0 )
adapter - > msix_enabled = true ;
return ;
}
static inline int be_msix_vec_get ( struct be_adapter * adapter , u32 eq_id )
{
2009-08-17 00:58:26 +00:00
return adapter - > msix_entries [
be_evt_bit_get ( adapter , eq_id ) ] . vector ;
2009-03-11 23:32:03 -07:00
}
2009-08-17 00:58:26 +00:00
static int be_request_irq ( struct be_adapter * adapter ,
struct be_eq_obj * eq_obj ,
void * handler , char * desc )
2009-03-11 23:32:03 -07:00
{
struct net_device * netdev = adapter - > netdev ;
2009-08-17 00:58:26 +00:00
int vec ;
sprintf ( eq_obj - > desc , " %s-%s " , netdev - > name , desc ) ;
vec = be_msix_vec_get ( adapter , eq_obj - > q . id ) ;
return request_irq ( vec , handler , 0 , eq_obj - > desc , adapter ) ;
}
static void be_free_irq ( struct be_adapter * adapter , struct be_eq_obj * eq_obj )
{
int vec = be_msix_vec_get ( adapter , eq_obj - > q . id ) ;
free_irq ( vec , adapter ) ;
}
2009-03-11 23:32:03 -07:00
2009-08-17 00:58:26 +00:00
static int be_msix_register ( struct be_adapter * adapter )
{
int status ;
status = be_request_irq ( adapter , & adapter - > tx_eq , be_msix_tx_mcc , " tx " ) ;
2009-03-11 23:32:03 -07:00
if ( status )
goto err ;
2009-08-17 00:58:26 +00:00
status = be_request_irq ( adapter , & adapter - > rx_eq , be_msix_rx , " rx " ) ;
if ( status )
goto free_tx_irq ;
2009-03-11 23:32:03 -07:00
return 0 ;
2009-08-17 00:58:26 +00:00
free_tx_irq :
be_free_irq ( adapter , & adapter - > tx_eq ) ;
2009-03-11 23:32:03 -07:00
err :
dev_warn ( & adapter - > pdev - > dev ,
" MSIX Request IRQ failed - err %d \n " , status ) ;
pci_disable_msix ( adapter - > pdev ) ;
adapter - > msix_enabled = false ;
return status ;
}
static int be_irq_register ( struct be_adapter * adapter )
{
struct net_device * netdev = adapter - > netdev ;
int status ;
if ( adapter - > msix_enabled ) {
status = be_msix_register ( adapter ) ;
if ( status = = 0 )
goto done ;
}
/* INTx */
netdev - > irq = adapter - > pdev - > irq ;
status = request_irq ( netdev - > irq , be_intx , IRQF_SHARED , netdev - > name ,
adapter ) ;
if ( status ) {
dev_err ( & adapter - > pdev - > dev ,
" INTx request IRQ failed - err %d \n " , status ) ;
return status ;
}
done :
adapter - > isr_registered = true ;
return 0 ;
}
static void be_irq_unregister ( struct be_adapter * adapter )
{
struct net_device * netdev = adapter - > netdev ;
if ( ! adapter - > isr_registered )
return ;
/* INTx */
if ( ! adapter - > msix_enabled ) {
free_irq ( netdev - > irq , adapter ) ;
goto done ;
}
/* MSIx */
2009-08-17 00:58:26 +00:00
be_free_irq ( adapter , & adapter - > tx_eq ) ;
be_free_irq ( adapter , & adapter - > rx_eq ) ;
2009-03-11 23:32:03 -07:00
done :
adapter - > isr_registered = false ;
return ;
}
static int be_open ( struct net_device * netdev )
{
struct be_adapter * adapter = netdev_priv ( netdev ) ;
struct be_eq_obj * rx_eq = & adapter - > rx_eq ;
struct be_eq_obj * tx_eq = & adapter - > tx_eq ;
2009-06-18 00:10:27 +00:00
bool link_up ;
int status ;
2009-10-28 04:15:20 -07:00
u8 mac_speed ;
u16 link_speed ;
2009-06-18 00:02:59 +00:00
/* First time posting */
be_post_rx_frags ( adapter ) ;
napi_enable ( & rx_eq - > napi ) ;
napi_enable ( & tx_eq - > napi ) ;
be_irq_register ( adapter ) ;
2009-07-27 22:52:03 +00:00
be_intr_set ( adapter , true ) ;
2009-06-18 00:02:59 +00:00
/* The evt queues are created in unarmed state; arm them */
2009-07-27 22:52:03 +00:00
be_eq_notify ( adapter , rx_eq - > q . id , true , false , 0 ) ;
be_eq_notify ( adapter , tx_eq - > q . id , true , false , 0 ) ;
2009-06-18 00:02:59 +00:00
/* Rx compl queue may be in unarmed state; rearm it */
2009-07-27 22:52:03 +00:00
be_cq_notify ( adapter , adapter - > rx_obj . cq . id , true , 0 ) ;
2009-06-18 00:02:59 +00:00
2009-10-28 04:15:20 -07:00
status = be_cmd_link_status_query ( adapter , & link_up , & mac_speed ,
& link_speed ) ;
2009-06-18 00:10:27 +00:00
if ( status )
2009-11-06 02:07:32 +00:00
goto ret_sts ;
2009-06-18 00:10:27 +00:00
be_link_status_update ( adapter , link_up ) ;
2009-06-18 00:02:59 +00:00
2009-11-06 02:07:32 +00:00
status = be_vid_config ( adapter ) ;
if ( status )
goto ret_sts ;
status = be_cmd_set_flow_control ( adapter ,
adapter - > tx_fc , adapter - > rx_fc ) ;
if ( status )
goto ret_sts ;
2009-06-18 00:02:59 +00:00
schedule_delayed_work ( & adapter - > work , msecs_to_jiffies ( 100 ) ) ;
2009-11-06 02:07:32 +00:00
ret_sts :
return status ;
2009-06-18 00:02:59 +00:00
}
2009-12-03 06:16:59 +00:00
static int be_setup_wol ( struct be_adapter * adapter , bool enable )
{
struct be_dma_mem cmd ;
int status = 0 ;
u8 mac [ ETH_ALEN ] ;
memset ( mac , 0 , ETH_ALEN ) ;
cmd . size = sizeof ( struct be_cmd_req_acpi_wol_magic_config ) ;
cmd . va = pci_alloc_consistent ( adapter - > pdev , cmd . size , & cmd . dma ) ;
if ( cmd . va = = NULL )
return - 1 ;
memset ( cmd . va , 0 , cmd . size ) ;
if ( enable ) {
status = pci_write_config_dword ( adapter - > pdev ,
PCICFG_PM_CONTROL_OFFSET , PCICFG_PM_CONTROL_MASK ) ;
if ( status ) {
dev_err ( & adapter - > pdev - > dev ,
" Could not enable Wake-on-lan \n " ) ;
pci_free_consistent ( adapter - > pdev , cmd . size , cmd . va ,
cmd . dma ) ;
return status ;
}
status = be_cmd_enable_magic_wol ( adapter ,
adapter - > netdev - > dev_addr , & cmd ) ;
pci_enable_wake ( adapter - > pdev , PCI_D3hot , 1 ) ;
pci_enable_wake ( adapter - > pdev , PCI_D3cold , 1 ) ;
} else {
status = be_cmd_enable_magic_wol ( adapter , mac , & cmd ) ;
pci_enable_wake ( adapter - > pdev , PCI_D3hot , 0 ) ;
pci_enable_wake ( adapter - > pdev , PCI_D3cold , 0 ) ;
}
pci_free_consistent ( adapter - > pdev , cmd . size , cmd . va , cmd . dma ) ;
return status ;
}
2009-06-18 00:02:59 +00:00
static int be_setup ( struct be_adapter * adapter )
{
struct net_device * netdev = adapter - > netdev ;
2009-10-14 20:20:42 +00:00
u32 cap_flags , en_flags ;
2009-03-11 23:32:03 -07:00
int status ;
2009-10-14 20:20:42 +00:00
cap_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
BE_IF_FLAGS_MCAST_PROMISCUOUS |
BE_IF_FLAGS_PROMISCUOUS |
BE_IF_FLAGS_PASS_L3L4_ERRORS ;
en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
BE_IF_FLAGS_PASS_L3L4_ERRORS ;
status = be_cmd_if_create ( adapter , cap_flags , en_flags ,
netdev - > dev_addr , false /* pmac_invalid */ ,
& adapter - > if_handle , & adapter - > pmac_id ) ;
2009-03-11 23:32:03 -07:00
if ( status ! = 0 )
goto do_none ;
status = be_tx_queues_create ( adapter ) ;
if ( status ! = 0 )
goto if_destroy ;
status = be_rx_queues_create ( adapter ) ;
if ( status ! = 0 )
goto tx_qs_destroy ;
2009-06-18 00:02:59 +00:00
status = be_mcc_queues_create ( adapter ) ;
if ( status ! = 0 )
goto rx_qs_destroy ;
2009-03-11 23:32:03 -07:00
2009-11-29 17:57:46 +00:00
adapter - > link_speed = - 1 ;
2009-03-11 23:32:03 -07:00
return 0 ;
2009-06-18 00:02:59 +00:00
rx_qs_destroy :
be_rx_queues_destroy ( adapter ) ;
2009-03-11 23:32:03 -07:00
tx_qs_destroy :
be_tx_queues_destroy ( adapter ) ;
if_destroy :
2009-07-27 22:52:03 +00:00
be_cmd_if_destroy ( adapter , adapter - > if_handle ) ;
2009-03-11 23:32:03 -07:00
do_none :
return status ;
}
2009-06-18 00:02:59 +00:00
static int be_clear ( struct be_adapter * adapter )
{
2009-08-17 00:58:41 +00:00
be_mcc_queues_destroy ( adapter ) ;
2009-06-18 00:02:59 +00:00
be_rx_queues_destroy ( adapter ) ;
be_tx_queues_destroy ( adapter ) ;
2009-07-27 22:52:03 +00:00
be_cmd_if_destroy ( adapter , adapter - > if_handle ) ;
2009-06-18 00:02:59 +00:00
2009-11-22 22:02:03 +00:00
/* tell fw we're done with firing cmds */
be_cmd_fw_clean ( adapter ) ;
2009-06-18 00:02:59 +00:00
return 0 ;
}
2009-03-11 23:32:03 -07:00
static int be_close ( struct net_device * netdev )
{
struct be_adapter * adapter = netdev_priv ( netdev ) ;
struct be_eq_obj * rx_eq = & adapter - > rx_eq ;
struct be_eq_obj * tx_eq = & adapter - > tx_eq ;
int vec ;
2009-06-10 02:18:35 +00:00
cancel_delayed_work_sync ( & adapter - > work ) ;
2009-03-11 23:32:03 -07:00
netif_stop_queue ( netdev ) ;
netif_carrier_off ( netdev ) ;
2009-06-18 00:10:27 +00:00
adapter - > link_up = false ;
2009-03-11 23:32:03 -07:00
2009-07-27 22:52:03 +00:00
be_intr_set ( adapter , false ) ;
2009-03-11 23:32:03 -07:00
if ( adapter - > msix_enabled ) {
vec = be_msix_vec_get ( adapter , tx_eq - > q . id ) ;
synchronize_irq ( vec ) ;
vec = be_msix_vec_get ( adapter , rx_eq - > q . id ) ;
synchronize_irq ( vec ) ;
} else {
synchronize_irq ( netdev - > irq ) ;
}
be_irq_unregister ( adapter ) ;
napi_disable ( & rx_eq - > napi ) ;
napi_disable ( & tx_eq - > napi ) ;
2009-08-10 03:42:43 +00:00
/* Wait for all pending tx completions to arrive so that
* all tx skbs are freed .
*/
be_tx_compl_clean ( adapter ) ;
2009-03-11 23:32:03 -07:00
return 0 ;
}
2009-09-04 03:12:16 +00:00
# define FW_FILE_HDR_SIGN "ServerEngines Corp. "
char flash_cookie [ 2 ] [ 16 ] = { " *** SE FLAS " ,
" H DIRECTORY *** " } ;
2009-11-20 14:23:47 -08:00
static bool be_flash_redboot ( struct be_adapter * adapter ,
const u8 * p )
{
u32 crc_offset ;
u8 flashed_crc [ 4 ] ;
int status ;
crc_offset = FLASH_REDBOOT_START + FLASH_REDBOOT_IMAGE_MAX_SIZE - 4
+ sizeof ( struct flash_file_hdr ) - 32 * 1024 ;
p + = crc_offset ;
status = be_cmd_get_flash_crc ( adapter , flashed_crc ) ;
if ( status ) {
dev_err ( & adapter - > pdev - > dev ,
" could not get crc from flash, not flashing redboot \n " ) ;
return false ;
}
/*update redboot only if crc does not match*/
if ( ! memcmp ( flashed_crc , p , 4 ) )
return false ;
else
return true ;
}
2009-09-04 03:12:16 +00:00
static int be_flash_image ( struct be_adapter * adapter ,
const struct firmware * fw ,
struct be_dma_mem * flash_cmd , u32 flash_type )
{
int status ;
u32 flash_op , image_offset = 0 , total_bytes , image_size = 0 ;
int num_bytes ;
const u8 * p = fw - > data ;
struct be_cmd_write_flashrom * req = flash_cmd - > va ;
switch ( flash_type ) {
case FLASHROM_TYPE_ISCSI_ACTIVE :
image_offset = FLASH_iSCSI_PRIMARY_IMAGE_START ;
image_size = FLASH_IMAGE_MAX_SIZE ;
break ;
case FLASHROM_TYPE_ISCSI_BACKUP :
image_offset = FLASH_iSCSI_BACKUP_IMAGE_START ;
image_size = FLASH_IMAGE_MAX_SIZE ;
break ;
case FLASHROM_TYPE_FCOE_FW_ACTIVE :
image_offset = FLASH_FCoE_PRIMARY_IMAGE_START ;
image_size = FLASH_IMAGE_MAX_SIZE ;
break ;
case FLASHROM_TYPE_FCOE_FW_BACKUP :
image_offset = FLASH_FCoE_BACKUP_IMAGE_START ;
image_size = FLASH_IMAGE_MAX_SIZE ;
break ;
case FLASHROM_TYPE_BIOS :
image_offset = FLASH_iSCSI_BIOS_START ;
image_size = FLASH_BIOS_IMAGE_MAX_SIZE ;
break ;
case FLASHROM_TYPE_FCOE_BIOS :
image_offset = FLASH_FCoE_BIOS_START ;
image_size = FLASH_BIOS_IMAGE_MAX_SIZE ;
break ;
case FLASHROM_TYPE_PXE_BIOS :
image_offset = FLASH_PXE_BIOS_START ;
image_size = FLASH_BIOS_IMAGE_MAX_SIZE ;
break ;
2009-11-20 14:23:47 -08:00
case FLASHROM_TYPE_REDBOOT :
if ( ! be_flash_redboot ( adapter , fw - > data ) )
return 0 ;
image_offset = FLASH_REDBOOT_ISM_START ;
image_size = FLASH_REDBOOT_IMAGE_MAX_SIZE ;
break ;
2009-09-04 03:12:16 +00:00
default :
return 0 ;
}
p + = sizeof ( struct flash_file_hdr ) + image_offset ;
if ( p + image_size > fw - > data + fw - > size )
return - 1 ;
total_bytes = image_size ;
while ( total_bytes ) {
if ( total_bytes > 32 * 1024 )
num_bytes = 32 * 1024 ;
else
num_bytes = total_bytes ;
total_bytes - = num_bytes ;
if ( ! total_bytes )
flash_op = FLASHROM_OPER_FLASH ;
else
flash_op = FLASHROM_OPER_SAVE ;
memcpy ( req - > params . data_buf , p , num_bytes ) ;
p + = num_bytes ;
status = be_cmd_write_flashrom ( adapter , flash_cmd ,
flash_type , flash_op , num_bytes ) ;
if ( status ) {
dev_err ( & adapter - > pdev - > dev ,
" cmd to write to flash rom failed. type/op %d/%d \n " ,
flash_type , flash_op ) ;
return - 1 ;
}
yield ( ) ;
}
return 0 ;
}
int be_load_fw ( struct be_adapter * adapter , u8 * func )
{
char fw_file [ ETHTOOL_FLASH_MAX_FILENAME ] ;
const struct firmware * fw ;
struct flash_file_hdr * fhdr ;
struct flash_section_info * fsec = NULL ;
struct be_dma_mem flash_cmd ;
int status ;
const u8 * p ;
bool entry_found = false ;
int flash_type ;
char fw_ver [ FW_VER_LEN ] ;
char fw_cfg ;
status = be_cmd_get_fw_ver ( adapter , fw_ver ) ;
if ( status )
return status ;
fw_cfg = * ( fw_ver + 2 ) ;
if ( fw_cfg = = ' 0 ' )
fw_cfg = ' 1 ' ;
strcpy ( fw_file , func ) ;
status = request_firmware ( & fw , fw_file , & adapter - > pdev - > dev ) ;
if ( status )
goto fw_exit ;
p = fw - > data ;
fhdr = ( struct flash_file_hdr * ) p ;
if ( memcmp ( fhdr - > sign , FW_FILE_HDR_SIGN , strlen ( FW_FILE_HDR_SIGN ) ) ) {
dev_err ( & adapter - > pdev - > dev ,
" Firmware(%s) load error (signature did not match) \n " ,
fw_file ) ;
status = - 1 ;
goto fw_exit ;
}
dev_info ( & adapter - > pdev - > dev , " Flashing firmware file %s \n " , fw_file ) ;
p + = sizeof ( struct flash_file_hdr ) ;
while ( p < ( fw - > data + fw - > size ) ) {
fsec = ( struct flash_section_info * ) p ;
if ( ! memcmp ( flash_cookie , fsec - > cookie , sizeof ( flash_cookie ) ) ) {
entry_found = true ;
break ;
}
p + = 32 ;
}
if ( ! entry_found ) {
status = - 1 ;
dev_err ( & adapter - > pdev - > dev ,
" Flash cookie not found in firmware image \n " ) ;
goto fw_exit ;
}
flash_cmd . size = sizeof ( struct be_cmd_write_flashrom ) + 32 * 1024 ;
flash_cmd . va = pci_alloc_consistent ( adapter - > pdev , flash_cmd . size ,
& flash_cmd . dma ) ;
if ( ! flash_cmd . va ) {
status = - ENOMEM ;
dev_err ( & adapter - > pdev - > dev ,
" Memory allocation failure while flashing \n " ) ;
goto fw_exit ;
}
for ( flash_type = FLASHROM_TYPE_ISCSI_ACTIVE ;
flash_type < = FLASHROM_TYPE_FCOE_FW_BACKUP ; flash_type + + ) {
status = be_flash_image ( adapter , fw , & flash_cmd ,
flash_type ) ;
if ( status )
break ;
}
pci_free_consistent ( adapter - > pdev , flash_cmd . size , flash_cmd . va ,
flash_cmd . dma ) ;
if ( status ) {
dev_err ( & adapter - > pdev - > dev , " Firmware load error \n " ) ;
goto fw_exit ;
}
tree-wide: fix assorted typos all over the place
That is "success", "unknown", "through", "performance", "[re|un]mapping"
, "access", "default", "reasonable", "[con]currently", "temperature"
, "channel", "[un]used", "application", "example","hierarchy", "therefore"
, "[over|under]flow", "contiguous", "threshold", "enough" and others.
Signed-off-by: André Goddard Rosa <andre.goddard@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
2009-11-14 13:09:05 -02:00
dev_info ( & adapter - > pdev - > dev , " Firmware flashed successfully \n " ) ;
2009-09-04 03:12:16 +00:00
fw_exit :
release_firmware ( fw ) ;
return status ;
}
2009-03-11 23:32:03 -07:00
static struct net_device_ops be_netdev_ops = {
. ndo_open = be_open ,
. ndo_stop = be_close ,
. ndo_start_xmit = be_xmit ,
. ndo_get_stats = be_get_stats ,
. ndo_set_rx_mode = be_set_multicast_list ,
. ndo_set_mac_address = be_mac_addr_set ,
. ndo_change_mtu = be_change_mtu ,
. ndo_validate_addr = eth_validate_addr ,
. ndo_vlan_rx_register = be_vlan_register ,
. ndo_vlan_rx_add_vid = be_vlan_add_vid ,
. ndo_vlan_rx_kill_vid = be_vlan_rem_vid ,
} ;
static void be_netdev_init ( struct net_device * netdev )
{
struct be_adapter * adapter = netdev_priv ( netdev ) ;
netdev - > features | = NETIF_F_SG | NETIF_F_HW_VLAN_RX | NETIF_F_TSO |
2009-10-05 02:22:19 +00:00
NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | NETIF_F_HW_CSUM |
NETIF_F_GRO ;
2009-03-11 23:32:03 -07:00
2009-11-29 17:54:54 +00:00
netdev - > vlan_features | = NETIF_F_SG | NETIF_F_TSO | NETIF_F_HW_CSUM ;
2009-03-11 23:32:03 -07:00
netdev - > flags | = IFF_MULTICAST ;
2009-04-13 15:41:22 -07:00
adapter - > rx_csum = true ;
2009-11-06 02:06:59 +00:00
/* Default settings for Rx and Tx flow control */
adapter - > rx_fc = true ;
adapter - > tx_fc = true ;
2009-09-04 03:12:29 +00:00
netif_set_gso_max_size ( netdev , 65535 ) ;
2009-03-11 23:32:03 -07:00
BE_SET_NETDEV_OPS ( netdev , & be_netdev_ops ) ;
SET_ETHTOOL_OPS ( netdev , & be_ethtool_ops ) ;
netif_napi_add ( netdev , & adapter - > rx_eq . napi , be_poll_rx ,
BE_NAPI_WEIGHT ) ;
2009-06-18 00:02:59 +00:00
netif_napi_add ( netdev , & adapter - > tx_eq . napi , be_poll_tx_mcc ,
2009-03-11 23:32:03 -07:00
BE_NAPI_WEIGHT ) ;
netif_carrier_off ( netdev ) ;
netif_stop_queue ( netdev ) ;
}
static void be_unmap_pci_bars ( struct be_adapter * adapter )
{
2009-07-27 22:52:03 +00:00
if ( adapter - > csr )
iounmap ( adapter - > csr ) ;
if ( adapter - > db )
iounmap ( adapter - > db ) ;
if ( adapter - > pcicfg )
iounmap ( adapter - > pcicfg ) ;
2009-03-11 23:32:03 -07:00
}
static int be_map_pci_bars ( struct be_adapter * adapter )
{
u8 __iomem * addr ;
2010-01-27 21:56:44 +00:00
int pcicfg_reg ;
2009-03-11 23:32:03 -07:00
addr = ioremap_nocache ( pci_resource_start ( adapter - > pdev , 2 ) ,
pci_resource_len ( adapter - > pdev , 2 ) ) ;
if ( addr = = NULL )
return - ENOMEM ;
2009-07-27 22:52:03 +00:00
adapter - > csr = addr ;
2009-03-11 23:32:03 -07:00
addr = ioremap_nocache ( pci_resource_start ( adapter - > pdev , 4 ) ,
128 * 1024 ) ;
if ( addr = = NULL )
goto pci_map_err ;
2009-07-27 22:52:03 +00:00
adapter - > db = addr ;
2009-03-11 23:32:03 -07:00
2010-01-27 21:56:44 +00:00
if ( adapter - > generation = = BE_GEN2 )
pcicfg_reg = 1 ;
else
pcicfg_reg = 0 ;
addr = ioremap_nocache ( pci_resource_start ( adapter - > pdev , pcicfg_reg ) ,
pci_resource_len ( adapter - > pdev , pcicfg_reg ) ) ;
2009-03-11 23:32:03 -07:00
if ( addr = = NULL )
goto pci_map_err ;
2009-07-27 22:52:03 +00:00
adapter - > pcicfg = addr ;
2009-03-11 23:32:03 -07:00
return 0 ;
pci_map_err :
be_unmap_pci_bars ( adapter ) ;
return - ENOMEM ;
}
static void be_ctrl_cleanup ( struct be_adapter * adapter )
{
2009-07-27 22:52:03 +00:00
struct be_dma_mem * mem = & adapter - > mbox_mem_alloced ;
2009-03-11 23:32:03 -07:00
be_unmap_pci_bars ( adapter ) ;
if ( mem - > va )
pci_free_consistent ( adapter - > pdev , mem - > size ,
mem - > va , mem - > dma ) ;
2009-11-22 22:01:10 +00:00
mem = & adapter - > mc_cmd_mem ;
if ( mem - > va )
pci_free_consistent ( adapter - > pdev , mem - > size ,
mem - > va , mem - > dma ) ;
2009-03-11 23:32:03 -07:00
}
static int be_ctrl_init ( struct be_adapter * adapter )
{
2009-07-27 22:52:03 +00:00
struct be_dma_mem * mbox_mem_alloc = & adapter - > mbox_mem_alloced ;
struct be_dma_mem * mbox_mem_align = & adapter - > mbox_mem ;
2009-11-22 22:01:10 +00:00
struct be_dma_mem * mc_cmd_mem = & adapter - > mc_cmd_mem ;
2009-03-11 23:32:03 -07:00
int status ;
status = be_map_pci_bars ( adapter ) ;
if ( status )
2009-11-22 22:01:10 +00:00
goto done ;
2009-03-11 23:32:03 -07:00
mbox_mem_alloc - > size = sizeof ( struct be_mcc_mailbox ) + 16 ;
mbox_mem_alloc - > va = pci_alloc_consistent ( adapter - > pdev ,
mbox_mem_alloc - > size , & mbox_mem_alloc - > dma ) ;
if ( ! mbox_mem_alloc - > va ) {
2009-11-22 22:01:10 +00:00
status = - ENOMEM ;
goto unmap_pci_bars ;
2009-03-11 23:32:03 -07:00
}
2009-11-22 22:01:10 +00:00
2009-03-11 23:32:03 -07:00
mbox_mem_align - > size = sizeof ( struct be_mcc_mailbox ) ;
mbox_mem_align - > va = PTR_ALIGN ( mbox_mem_alloc - > va , 16 ) ;
mbox_mem_align - > dma = PTR_ALIGN ( mbox_mem_alloc - > dma , 16 ) ;
memset ( mbox_mem_align - > va , 0 , sizeof ( struct be_mcc_mailbox ) ) ;
2009-11-22 22:01:10 +00:00
mc_cmd_mem - > size = sizeof ( struct be_cmd_req_mcast_mac_config ) ;
mc_cmd_mem - > va = pci_alloc_consistent ( adapter - > pdev , mc_cmd_mem - > size ,
& mc_cmd_mem - > dma ) ;
if ( mc_cmd_mem - > va = = NULL ) {
status = - ENOMEM ;
goto free_mbox ;
}
memset ( mc_cmd_mem - > va , 0 , mc_cmd_mem - > size ) ;
2009-07-27 22:52:03 +00:00
spin_lock_init ( & adapter - > mbox_lock ) ;
spin_lock_init ( & adapter - > mcc_lock ) ;
spin_lock_init ( & adapter - > mcc_cq_lock ) ;
2009-06-18 00:10:27 +00:00
2009-03-11 23:32:03 -07:00
return 0 ;
2009-11-22 22:01:10 +00:00
free_mbox :
pci_free_consistent ( adapter - > pdev , mbox_mem_alloc - > size ,
mbox_mem_alloc - > va , mbox_mem_alloc - > dma ) ;
unmap_pci_bars :
be_unmap_pci_bars ( adapter ) ;
done :
return status ;
2009-03-11 23:32:03 -07:00
}
static void be_stats_cleanup ( struct be_adapter * adapter )
{
struct be_stats_obj * stats = & adapter - > stats ;
struct be_dma_mem * cmd = & stats - > cmd ;
if ( cmd - > va )
pci_free_consistent ( adapter - > pdev , cmd - > size ,
cmd - > va , cmd - > dma ) ;
}
static int be_stats_init ( struct be_adapter * adapter )
{
struct be_stats_obj * stats = & adapter - > stats ;
struct be_dma_mem * cmd = & stats - > cmd ;
cmd - > size = sizeof ( struct be_cmd_req_get_stats ) ;
cmd - > va = pci_alloc_consistent ( adapter - > pdev , cmd - > size , & cmd - > dma ) ;
if ( cmd - > va = = NULL )
return - 1 ;
2010-01-27 21:56:44 +00:00
memset ( cmd - > va , cmd - > size , 0 ) ;
2009-03-11 23:32:03 -07:00
return 0 ;
}
static void __devexit be_remove ( struct pci_dev * pdev )
{
struct be_adapter * adapter = pci_get_drvdata ( pdev ) ;
2009-11-22 22:02:26 +00:00
2009-03-11 23:32:03 -07:00
if ( ! adapter )
return ;
unregister_netdev ( adapter - > netdev ) ;
2009-06-18 00:02:59 +00:00
be_clear ( adapter ) ;
2009-03-11 23:32:03 -07:00
be_stats_cleanup ( adapter ) ;
be_ctrl_cleanup ( adapter ) ;
2009-11-22 22:02:26 +00:00
be_msix_disable ( adapter ) ;
2009-03-11 23:32:03 -07:00
pci_set_drvdata ( pdev , NULL ) ;
pci_release_regions ( pdev ) ;
pci_disable_device ( pdev ) ;
free_netdev ( adapter - > netdev ) ;
}
2009-11-22 22:02:03 +00:00
static int be_get_config ( struct be_adapter * adapter )
2009-03-11 23:32:03 -07:00
{
int status ;
2009-11-22 22:02:03 +00:00
u8 mac [ ETH_ALEN ] ;
2009-03-11 23:32:03 -07:00
2009-11-22 22:02:03 +00:00
status = be_cmd_get_fw_ver ( adapter , adapter - > fw_ver ) ;
2009-03-11 23:32:03 -07:00
if ( status )
return status ;
2009-11-22 22:02:03 +00:00
status = be_cmd_query_fw_cfg ( adapter ,
& adapter - > port_num , & adapter - > cap ) ;
2009-10-14 20:21:17 +00:00
if ( status )
return status ;
2009-11-22 22:02:03 +00:00
memset ( mac , 0 , ETH_ALEN ) ;
status = be_cmd_mac_addr_query ( adapter , mac ,
MAC_ADDRESS_TYPE_NETWORK , true /*permanent */ , 0 ) ;
2009-03-11 23:32:03 -07:00
if ( status )
return status ;
2009-11-29 17:56:26 +00:00
if ( ! is_valid_ether_addr ( mac ) )
return - EADDRNOTAVAIL ;
2009-11-22 22:02:03 +00:00
memcpy ( adapter - > netdev - > dev_addr , mac , ETH_ALEN ) ;
2009-11-29 17:55:39 +00:00
memcpy ( adapter - > netdev - > perm_addr , mac , ETH_ALEN ) ;
2009-03-11 23:32:03 -07:00
2009-11-22 22:02:03 +00:00
return 0 ;
2009-03-11 23:32:03 -07:00
}
static int __devinit be_probe ( struct pci_dev * pdev ,
const struct pci_device_id * pdev_id )
{
int status = 0 ;
struct be_adapter * adapter ;
struct net_device * netdev ;
status = pci_enable_device ( pdev ) ;
if ( status )
goto do_none ;
status = pci_request_regions ( pdev , DRV_NAME ) ;
if ( status )
goto disable_dev ;
pci_set_master ( pdev ) ;
netdev = alloc_etherdev ( sizeof ( struct be_adapter ) ) ;
if ( netdev = = NULL ) {
status = - ENOMEM ;
goto rel_reg ;
}
adapter = netdev_priv ( netdev ) ;
2010-01-27 21:56:44 +00:00
switch ( pdev - > device ) {
case BE_DEVICE_ID1 :
case OC_DEVICE_ID1 :
adapter - > generation = BE_GEN2 ;
break ;
case BE_DEVICE_ID2 :
case OC_DEVICE_ID2 :
adapter - > generation = BE_GEN3 ;
break ;
default :
adapter - > generation = 0 ;
}
2009-03-11 23:32:03 -07:00
adapter - > pdev = pdev ;
pci_set_drvdata ( pdev , adapter ) ;
adapter - > netdev = netdev ;
2009-11-22 22:02:03 +00:00
be_netdev_init ( netdev ) ;
SET_NETDEV_DEV ( netdev , & pdev - > dev ) ;
2009-03-11 23:32:03 -07:00
be_msix_enable ( adapter ) ;
2009-04-13 14:40:14 -07:00
status = pci_set_dma_mask ( pdev , DMA_BIT_MASK ( 64 ) ) ;
2009-03-11 23:32:03 -07:00
if ( ! status ) {
netdev - > features | = NETIF_F_HIGHDMA ;
} else {
2009-04-13 14:40:14 -07:00
status = pci_set_dma_mask ( pdev , DMA_BIT_MASK ( 32 ) ) ;
2009-03-11 23:32:03 -07:00
if ( status ) {
dev_err ( & pdev - > dev , " Could not set PCI DMA Mask \n " ) ;
goto free_netdev ;
}
}
status = be_ctrl_init ( adapter ) ;
if ( status )
goto free_netdev ;
2009-11-22 22:02:03 +00:00
/* sync up with fw's ready state */
status = be_cmd_POST ( adapter ) ;
2009-03-11 23:32:03 -07:00
if ( status )
goto ctrl_clean ;
2009-11-22 22:02:03 +00:00
/* tell fw we're ready to fire cmds */
status = be_cmd_fw_init ( adapter ) ;
2009-03-11 23:32:03 -07:00
if ( status )
2009-11-22 22:02:03 +00:00
goto ctrl_clean ;
status = be_cmd_reset_function ( adapter ) ;
if ( status )
goto ctrl_clean ;
2009-03-11 23:32:03 -07:00
2009-11-22 22:02:03 +00:00
status = be_stats_init ( adapter ) ;
if ( status )
goto ctrl_clean ;
status = be_get_config ( adapter ) ;
2009-03-11 23:32:03 -07:00
if ( status )
goto stats_clean ;
INIT_DELAYED_WORK ( & adapter - > work , be_worker ) ;
2009-06-18 00:02:59 +00:00
status = be_setup ( adapter ) ;
if ( status )
goto stats_clean ;
2009-11-22 22:02:03 +00:00
2009-03-11 23:32:03 -07:00
status = register_netdev ( netdev ) ;
if ( status ! = 0 )
2009-06-18 00:02:59 +00:00
goto unsetup ;
2009-03-11 23:32:03 -07:00
2009-05-18 15:38:55 -07:00
dev_info ( & pdev - > dev , " %s port %d \n " , nic_name ( pdev ) , adapter - > port_num ) ;
2009-03-11 23:32:03 -07:00
return 0 ;
2009-06-18 00:02:59 +00:00
unsetup :
be_clear ( adapter ) ;
2009-03-11 23:32:03 -07:00
stats_clean :
be_stats_cleanup ( adapter ) ;
ctrl_clean :
be_ctrl_cleanup ( adapter ) ;
free_netdev :
2009-11-22 22:02:26 +00:00
be_msix_disable ( adapter ) ;
2009-03-11 23:32:03 -07:00
free_netdev ( adapter - > netdev ) ;
2009-11-22 22:02:26 +00:00
pci_set_drvdata ( pdev , NULL ) ;
2009-03-11 23:32:03 -07:00
rel_reg :
pci_release_regions ( pdev ) ;
disable_dev :
pci_disable_device ( pdev ) ;
do_none :
2009-05-18 15:38:55 -07:00
dev_err ( & pdev - > dev , " %s initialization failed \n " , nic_name ( pdev ) ) ;
2009-03-11 23:32:03 -07:00
return status ;
}
static int be_suspend ( struct pci_dev * pdev , pm_message_t state )
{
struct be_adapter * adapter = pci_get_drvdata ( pdev ) ;
struct net_device * netdev = adapter - > netdev ;
2009-12-03 06:16:59 +00:00
if ( adapter - > wol )
be_setup_wol ( adapter , true ) ;
2009-03-11 23:32:03 -07:00
netif_device_detach ( netdev ) ;
if ( netif_running ( netdev ) ) {
rtnl_lock ( ) ;
be_close ( netdev ) ;
rtnl_unlock ( ) ;
}
2009-11-06 02:06:59 +00:00
be_cmd_get_flow_control ( adapter , & adapter - > tx_fc , & adapter - > rx_fc ) ;
2009-08-12 21:01:29 +00:00
be_clear ( adapter ) ;
2009-03-11 23:32:03 -07:00
pci_save_state ( pdev ) ;
pci_disable_device ( pdev ) ;
pci_set_power_state ( pdev , pci_choose_state ( pdev , state ) ) ;
return 0 ;
}
static int be_resume ( struct pci_dev * pdev )
{
int status = 0 ;
struct be_adapter * adapter = pci_get_drvdata ( pdev ) ;
struct net_device * netdev = adapter - > netdev ;
netif_device_detach ( netdev ) ;
status = pci_enable_device ( pdev ) ;
if ( status )
return status ;
pci_set_power_state ( pdev , 0 ) ;
pci_restore_state ( pdev ) ;
2009-11-22 22:02:03 +00:00
/* tell fw we're ready to fire cmds */
status = be_cmd_fw_init ( adapter ) ;
if ( status )
return status ;
2009-08-12 21:01:29 +00:00
be_setup ( adapter ) ;
2009-03-11 23:32:03 -07:00
if ( netif_running ( netdev ) ) {
rtnl_lock ( ) ;
be_open ( netdev ) ;
rtnl_unlock ( ) ;
}
netif_device_attach ( netdev ) ;
2009-12-03 06:16:59 +00:00
if ( adapter - > wol )
be_setup_wol ( adapter , false ) ;
2009-03-11 23:32:03 -07:00
return 0 ;
}
static struct pci_driver be_driver = {
. name = DRV_NAME ,
. id_table = be_dev_ids ,
. probe = be_probe ,
. remove = be_remove ,
. suspend = be_suspend ,
. resume = be_resume
} ;
static int __init be_init_module ( void )
{
2009-12-03 07:58:21 +00:00
if ( rx_frag_size ! = 8192 & & rx_frag_size ! = 4096 & &
rx_frag_size ! = 2048 ) {
2009-03-11 23:32:03 -07:00
printk ( KERN_WARNING DRV_NAME
" : Module param rx_frag_size must be 2048/4096/8192. "
" Using 2048 \n " ) ;
rx_frag_size = 2048 ;
}
return pci_register_driver ( & be_driver ) ;
}
module_init ( be_init_module ) ;
static void __exit be_exit_module ( void )
{
pci_unregister_driver ( & be_driver ) ;
}
module_exit ( be_exit_module ) ;