2010-01-13 03:37:25 +03:00
/*
* Copyright ( C ) 2009 - QLogic Corporation .
* 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
* as published by the Free Software Foundation ; either version 2
* of the License , or ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful , but
* WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place - Suite 330 , Boston ,
* MA 02111 - 1307 , USA .
*
* The full GNU General Public License is included in this distribution
* in the file called " COPYING " .
*
*/
# include "qlcnic.h"
static u32
qlcnic_poll_rsp ( struct qlcnic_adapter * adapter )
{
u32 rsp ;
int timeout = 0 ;
do {
/* give atleast 1ms for firmware to respond */
msleep ( 1 ) ;
if ( + + timeout > QLCNIC_OS_CRB_RETRY_COUNT )
return QLCNIC_CDRP_RSP_TIMEOUT ;
rsp = QLCRD32 ( adapter , QLCNIC_CDRP_CRB_OFFSET ) ;
} while ( ! QLCNIC_CDRP_IS_RSP ( rsp ) ) ;
return rsp ;
}
2010-02-01 08:24:59 +03:00
u32
2010-01-13 03:37:25 +03:00
qlcnic_issue_cmd ( struct qlcnic_adapter * adapter ,
u32 pci_fn , u32 version , u32 arg1 , u32 arg2 , u32 arg3 , u32 cmd )
{
u32 rsp ;
u32 signature ;
u32 rcode = QLCNIC_RCODE_SUCCESS ;
struct pci_dev * pdev = adapter - > pdev ;
signature = QLCNIC_CDRP_SIGNATURE_MAKE ( pci_fn , version ) ;
/* Acquire semaphore before accessing CRB */
if ( qlcnic_api_lock ( adapter ) )
return QLCNIC_RCODE_TIMEOUT ;
QLCWR32 ( adapter , QLCNIC_SIGN_CRB_OFFSET , signature ) ;
QLCWR32 ( adapter , QLCNIC_ARG1_CRB_OFFSET , arg1 ) ;
QLCWR32 ( adapter , QLCNIC_ARG2_CRB_OFFSET , arg2 ) ;
QLCWR32 ( adapter , QLCNIC_ARG3_CRB_OFFSET , arg3 ) ;
QLCWR32 ( adapter , QLCNIC_CDRP_CRB_OFFSET , QLCNIC_CDRP_FORM_CMD ( cmd ) ) ;
rsp = qlcnic_poll_rsp ( adapter ) ;
if ( rsp = = QLCNIC_CDRP_RSP_TIMEOUT ) {
dev_err ( & pdev - > dev , " card response timeout. \n " ) ;
rcode = QLCNIC_RCODE_TIMEOUT ;
} else if ( rsp = = QLCNIC_CDRP_RSP_FAIL ) {
rcode = QLCRD32 ( adapter , QLCNIC_ARG1_CRB_OFFSET ) ;
dev_err ( & pdev - > dev , " failed card response code:0x%x \n " ,
rcode ) ;
}
/* Release semaphore */
qlcnic_api_unlock ( adapter ) ;
return rcode ;
}
int
qlcnic_fw_cmd_set_mtu ( struct qlcnic_adapter * adapter , int mtu )
{
struct qlcnic_recv_context * recv_ctx = & adapter - > recv_ctx ;
if ( recv_ctx - > state = = QLCNIC_HOST_CTX_STATE_ACTIVE ) {
if ( qlcnic_issue_cmd ( adapter ,
2010-06-01 15:28:51 +04:00
adapter - > ahw . pci_func ,
adapter - > fw_hal_version ,
recv_ctx - > context_id ,
mtu ,
0 ,
QLCNIC_CDRP_CMD_SET_MTU ) ) {
2010-01-13 03:37:25 +03:00
dev_err ( & adapter - > pdev - > dev , " Failed to set mtu \n " ) ;
return - EIO ;
}
}
return 0 ;
}
static int
qlcnic_fw_cmd_create_rx_ctx ( struct qlcnic_adapter * adapter )
{
void * addr ;
struct qlcnic_hostrq_rx_ctx * prq ;
struct qlcnic_cardrsp_rx_ctx * prsp ;
struct qlcnic_hostrq_rds_ring * prq_rds ;
struct qlcnic_hostrq_sds_ring * prq_sds ;
struct qlcnic_cardrsp_rds_ring * prsp_rds ;
struct qlcnic_cardrsp_sds_ring * prsp_sds ;
struct qlcnic_host_rds_ring * rds_ring ;
struct qlcnic_host_sds_ring * sds_ring ;
dma_addr_t hostrq_phys_addr , cardrsp_phys_addr ;
u64 phys_addr ;
int i , nrds_rings , nsds_rings ;
size_t rq_size , rsp_size ;
2010-06-01 15:28:51 +04:00
u32 cap , reg , val , reg2 ;
2010-01-13 03:37:25 +03:00
int err ;
struct qlcnic_recv_context * recv_ctx = & adapter - > recv_ctx ;
nrds_rings = adapter - > max_rds_rings ;
nsds_rings = adapter - > max_sds_rings ;
rq_size =
SIZEOF_HOSTRQ_RX ( struct qlcnic_hostrq_rx_ctx , nrds_rings ,
nsds_rings ) ;
rsp_size =
SIZEOF_CARDRSP_RX ( struct qlcnic_cardrsp_rx_ctx , nrds_rings ,
nsds_rings ) ;
addr = pci_alloc_consistent ( adapter - > pdev ,
rq_size , & hostrq_phys_addr ) ;
if ( addr = = NULL )
return - ENOMEM ;
prq = ( struct qlcnic_hostrq_rx_ctx * ) addr ;
addr = pci_alloc_consistent ( adapter - > pdev ,
rsp_size , & cardrsp_phys_addr ) ;
if ( addr = = NULL ) {
err = - ENOMEM ;
goto out_free_rq ;
}
prsp = ( struct qlcnic_cardrsp_rx_ctx * ) addr ;
prq - > host_rsp_dma_addr = cpu_to_le64 ( cardrsp_phys_addr ) ;
2010-06-17 06:56:40 +04:00
cap = ( QLCNIC_CAP0_LEGACY_CONTEXT | QLCNIC_CAP0_LEGACY_MN
| QLCNIC_CAP0_VALIDOFF ) ;
2010-01-13 03:37:25 +03:00
cap | = ( QLCNIC_CAP0_JUMBO_CONTIGUOUS | QLCNIC_CAP0_LRO_CONTIGUOUS ) ;
2010-06-17 06:56:40 +04:00
prq - > valid_field_offset = offsetof ( struct qlcnic_hostrq_rx_ctx ,
msix_handler ) ;
prq - > txrx_sds_binding = nsds_rings - 1 ;
2010-01-13 03:37:25 +03:00
prq - > capabilities [ 0 ] = cpu_to_le32 ( cap ) ;
prq - > host_int_crb_mode =
cpu_to_le32 ( QLCNIC_HOST_INT_CRB_MODE_SHARED ) ;
prq - > host_rds_crb_mode =
cpu_to_le32 ( QLCNIC_HOST_RDS_CRB_MODE_UNIQUE ) ;
prq - > num_rds_rings = cpu_to_le16 ( nrds_rings ) ;
prq - > num_sds_rings = cpu_to_le16 ( nsds_rings ) ;
prq - > rds_ring_offset = cpu_to_le32 ( 0 ) ;
val = le32_to_cpu ( prq - > rds_ring_offset ) +
( sizeof ( struct qlcnic_hostrq_rds_ring ) * nrds_rings ) ;
prq - > sds_ring_offset = cpu_to_le32 ( val ) ;
prq_rds = ( struct qlcnic_hostrq_rds_ring * ) ( prq - > data +
le32_to_cpu ( prq - > rds_ring_offset ) ) ;
for ( i = 0 ; i < nrds_rings ; i + + ) {
rds_ring = & recv_ctx - > rds_rings [ i ] ;
2010-06-22 07:19:01 +04:00
rds_ring - > producer = 0 ;
2010-01-13 03:37:25 +03:00
prq_rds [ i ] . host_phys_addr = cpu_to_le64 ( rds_ring - > phys_addr ) ;
prq_rds [ i ] . ring_size = cpu_to_le32 ( rds_ring - > num_desc ) ;
prq_rds [ i ] . ring_kind = cpu_to_le32 ( i ) ;
prq_rds [ i ] . buff_size = cpu_to_le64 ( rds_ring - > dma_size ) ;
}
prq_sds = ( struct qlcnic_hostrq_sds_ring * ) ( prq - > data +
le32_to_cpu ( prq - > sds_ring_offset ) ) ;
for ( i = 0 ; i < nsds_rings ; i + + ) {
sds_ring = & recv_ctx - > sds_rings [ i ] ;
2010-06-22 07:19:01 +04:00
sds_ring - > consumer = 0 ;
memset ( sds_ring - > desc_head , 0 , STATUS_DESC_RINGSIZE ( sds_ring ) ) ;
2010-01-13 03:37:25 +03:00
prq_sds [ i ] . host_phys_addr = cpu_to_le64 ( sds_ring - > phys_addr ) ;
prq_sds [ i ] . ring_size = cpu_to_le32 ( sds_ring - > num_desc ) ;
prq_sds [ i ] . msi_index = cpu_to_le16 ( i ) ;
}
phys_addr = hostrq_phys_addr ;
err = qlcnic_issue_cmd ( adapter ,
adapter - > ahw . pci_func ,
2010-06-01 15:28:51 +04:00
adapter - > fw_hal_version ,
2010-01-13 03:37:25 +03:00
( u32 ) ( phys_addr > > 32 ) ,
( u32 ) ( phys_addr & 0xffffffff ) ,
rq_size ,
QLCNIC_CDRP_CMD_CREATE_RX_CTX ) ;
if ( err ) {
dev_err ( & adapter - > pdev - > dev ,
" Failed to create rx ctx in firmware%d \n " , err ) ;
goto out_free_rsp ;
}
prsp_rds = ( ( struct qlcnic_cardrsp_rds_ring * )
& prsp - > data [ le32_to_cpu ( prsp - > rds_ring_offset ) ] ) ;
for ( i = 0 ; i < le16_to_cpu ( prsp - > num_rds_rings ) ; i + + ) {
rds_ring = & recv_ctx - > rds_rings [ i ] ;
reg = le32_to_cpu ( prsp_rds [ i ] . host_producer_crb ) ;
2010-06-01 15:28:51 +04:00
if ( adapter - > fw_hal_version = = QLCNIC_FW_BASE )
rds_ring - > crb_rcv_producer = qlcnic_get_ioaddr ( adapter ,
2010-01-13 03:37:25 +03:00
QLCNIC_REG ( reg - 0x200 ) ) ;
2010-06-01 15:28:51 +04:00
else
rds_ring - > crb_rcv_producer = adapter - > ahw . pci_base0 +
reg ;
2010-01-13 03:37:25 +03:00
}
prsp_sds = ( ( struct qlcnic_cardrsp_sds_ring * )
& prsp - > data [ le32_to_cpu ( prsp - > sds_ring_offset ) ] ) ;
for ( i = 0 ; i < le16_to_cpu ( prsp - > num_sds_rings ) ; i + + ) {
sds_ring = & recv_ctx - > sds_rings [ i ] ;
reg = le32_to_cpu ( prsp_sds [ i ] . host_consumer_crb ) ;
2010-06-01 15:28:51 +04:00
reg2 = le32_to_cpu ( prsp_sds [ i ] . interrupt_crb ) ;
2010-01-13 03:37:25 +03:00
2010-06-01 15:28:51 +04:00
if ( adapter - > fw_hal_version = = QLCNIC_FW_BASE ) {
sds_ring - > crb_sts_consumer = qlcnic_get_ioaddr ( adapter ,
2010-01-13 03:37:25 +03:00
QLCNIC_REG ( reg - 0x200 ) ) ;
2010-06-01 15:28:51 +04:00
sds_ring - > crb_intr_mask = qlcnic_get_ioaddr ( adapter ,
QLCNIC_REG ( reg2 - 0x200 ) ) ;
} else {
sds_ring - > crb_sts_consumer = adapter - > ahw . pci_base0 +
reg ;
sds_ring - > crb_intr_mask = adapter - > ahw . pci_base0 + reg2 ;
}
2010-01-13 03:37:25 +03:00
}
recv_ctx - > state = le32_to_cpu ( prsp - > host_ctx_state ) ;
recv_ctx - > context_id = le16_to_cpu ( prsp - > context_id ) ;
recv_ctx - > virt_port = prsp - > virt_port ;
out_free_rsp :
pci_free_consistent ( adapter - > pdev , rsp_size , prsp , cardrsp_phys_addr ) ;
out_free_rq :
pci_free_consistent ( adapter - > pdev , rq_size , prq , hostrq_phys_addr ) ;
return err ;
}
static void
qlcnic_fw_cmd_destroy_rx_ctx ( struct qlcnic_adapter * adapter )
{
struct qlcnic_recv_context * recv_ctx = & adapter - > recv_ctx ;
if ( qlcnic_issue_cmd ( adapter ,
adapter - > ahw . pci_func ,
2010-06-01 15:28:51 +04:00
adapter - > fw_hal_version ,
2010-01-13 03:37:25 +03:00
recv_ctx - > context_id ,
QLCNIC_DESTROY_CTX_RESET ,
0 ,
QLCNIC_CDRP_CMD_DESTROY_RX_CTX ) ) {
dev_err ( & adapter - > pdev - > dev ,
" Failed to destroy rx ctx in firmware \n " ) ;
}
2010-06-22 07:19:04 +04:00
recv_ctx - > state = QLCNIC_HOST_CTX_STATE_FREED ;
2010-01-13 03:37:25 +03:00
}
static int
qlcnic_fw_cmd_create_tx_ctx ( struct qlcnic_adapter * adapter )
{
struct qlcnic_hostrq_tx_ctx * prq ;
struct qlcnic_hostrq_cds_ring * prq_cds ;
struct qlcnic_cardrsp_tx_ctx * prsp ;
void * rq_addr , * rsp_addr ;
size_t rq_size , rsp_size ;
u32 temp ;
int err ;
u64 phys_addr ;
dma_addr_t rq_phys_addr , rsp_phys_addr ;
struct qlcnic_host_tx_ring * tx_ring = adapter - > tx_ring ;
2010-06-22 07:19:01 +04:00
/* reset host resources */
tx_ring - > producer = 0 ;
tx_ring - > sw_consumer = 0 ;
* ( tx_ring - > hw_consumer ) = 0 ;
2010-01-13 03:37:25 +03:00
rq_size = SIZEOF_HOSTRQ_TX ( struct qlcnic_hostrq_tx_ctx ) ;
rq_addr = pci_alloc_consistent ( adapter - > pdev ,
rq_size , & rq_phys_addr ) ;
if ( ! rq_addr )
return - ENOMEM ;
rsp_size = SIZEOF_CARDRSP_TX ( struct qlcnic_cardrsp_tx_ctx ) ;
rsp_addr = pci_alloc_consistent ( adapter - > pdev ,
rsp_size , & rsp_phys_addr ) ;
if ( ! rsp_addr ) {
err = - ENOMEM ;
goto out_free_rq ;
}
memset ( rq_addr , 0 , rq_size ) ;
prq = ( struct qlcnic_hostrq_tx_ctx * ) rq_addr ;
memset ( rsp_addr , 0 , rsp_size ) ;
prsp = ( struct qlcnic_cardrsp_tx_ctx * ) rsp_addr ;
prq - > host_rsp_dma_addr = cpu_to_le64 ( rsp_phys_addr ) ;
temp = ( QLCNIC_CAP0_LEGACY_CONTEXT | QLCNIC_CAP0_LEGACY_MN |
QLCNIC_CAP0_LSO ) ;
prq - > capabilities [ 0 ] = cpu_to_le32 ( temp ) ;
prq - > host_int_crb_mode =
cpu_to_le32 ( QLCNIC_HOST_INT_CRB_MODE_SHARED ) ;
prq - > interrupt_ctl = 0 ;
prq - > msi_index = 0 ;
prq - > cmd_cons_dma_addr = cpu_to_le64 ( tx_ring - > hw_cons_phys_addr ) ;
prq_cds = & prq - > cds_ring ;
prq_cds - > host_phys_addr = cpu_to_le64 ( tx_ring - > phys_addr ) ;
prq_cds - > ring_size = cpu_to_le32 ( tx_ring - > num_desc ) ;
phys_addr = rq_phys_addr ;
err = qlcnic_issue_cmd ( adapter ,
adapter - > ahw . pci_func ,
2010-06-01 15:28:51 +04:00
adapter - > fw_hal_version ,
2010-01-13 03:37:25 +03:00
( u32 ) ( phys_addr > > 32 ) ,
( ( u32 ) phys_addr & 0xffffffff ) ,
rq_size ,
QLCNIC_CDRP_CMD_CREATE_TX_CTX ) ;
if ( err = = QLCNIC_RCODE_SUCCESS ) {
temp = le32_to_cpu ( prsp - > cds_ring . host_producer_crb ) ;
2010-06-01 15:28:51 +04:00
if ( adapter - > fw_hal_version = = QLCNIC_FW_BASE )
tx_ring - > crb_cmd_producer = qlcnic_get_ioaddr ( adapter ,
2010-01-13 03:37:25 +03:00
QLCNIC_REG ( temp - 0x200 ) ) ;
2010-06-01 15:28:51 +04:00
else
tx_ring - > crb_cmd_producer = adapter - > ahw . pci_base0 +
temp ;
2010-01-13 03:37:25 +03:00
adapter - > tx_context_id =
le16_to_cpu ( prsp - > context_id ) ;
} else {
dev_err ( & adapter - > pdev - > dev ,
" Failed to create tx ctx in firmware%d \n " , err ) ;
err = - EIO ;
}
pci_free_consistent ( adapter - > pdev , rsp_size , rsp_addr , rsp_phys_addr ) ;
out_free_rq :
pci_free_consistent ( adapter - > pdev , rq_size , rq_addr , rq_phys_addr ) ;
return err ;
}
static void
qlcnic_fw_cmd_destroy_tx_ctx ( struct qlcnic_adapter * adapter )
{
if ( qlcnic_issue_cmd ( adapter ,
adapter - > ahw . pci_func ,
2010-06-01 15:28:51 +04:00
adapter - > fw_hal_version ,
2010-01-13 03:37:25 +03:00
adapter - > tx_context_id ,
QLCNIC_DESTROY_CTX_RESET ,
0 ,
QLCNIC_CDRP_CMD_DESTROY_TX_CTX ) ) {
dev_err ( & adapter - > pdev - > dev ,
" Failed to destroy tx ctx in firmware \n " ) ;
}
}
int
qlcnic_fw_cmd_query_phy ( struct qlcnic_adapter * adapter , u32 reg , u32 * val )
{
if ( qlcnic_issue_cmd ( adapter ,
adapter - > ahw . pci_func ,
2010-06-01 15:28:51 +04:00
adapter - > fw_hal_version ,
2010-01-13 03:37:25 +03:00
reg ,
0 ,
0 ,
QLCNIC_CDRP_CMD_READ_PHY ) ) {
return - EIO ;
}
return QLCRD32 ( adapter , QLCNIC_ARG1_CRB_OFFSET ) ;
}
int
qlcnic_fw_cmd_set_phy ( struct qlcnic_adapter * adapter , u32 reg , u32 val )
{
return qlcnic_issue_cmd ( adapter ,
adapter - > ahw . pci_func ,
2010-06-01 15:28:51 +04:00
adapter - > fw_hal_version ,
2010-01-13 03:37:25 +03:00
reg ,
val ,
0 ,
QLCNIC_CDRP_CMD_WRITE_PHY ) ;
}
int qlcnic_alloc_hw_resources ( struct qlcnic_adapter * adapter )
{
void * addr ;
int err ;
int ring ;
struct qlcnic_recv_context * recv_ctx ;
struct qlcnic_host_rds_ring * rds_ring ;
struct qlcnic_host_sds_ring * sds_ring ;
struct qlcnic_host_tx_ring * tx_ring ;
struct pci_dev * pdev = adapter - > pdev ;
recv_ctx = & adapter - > recv_ctx ;
tx_ring = adapter - > tx_ring ;
tx_ring - > hw_consumer = ( __le32 * ) pci_alloc_consistent ( pdev , sizeof ( u32 ) ,
& tx_ring - > hw_cons_phys_addr ) ;
if ( tx_ring - > hw_consumer = = NULL ) {
dev_err ( & pdev - > dev , " failed to allocate tx consumer \n " ) ;
return - ENOMEM ;
}
* ( tx_ring - > hw_consumer ) = 0 ;
/* cmd desc ring */
addr = pci_alloc_consistent ( pdev , TX_DESC_RINGSIZE ( tx_ring ) ,
& tx_ring - > phys_addr ) ;
if ( addr = = NULL ) {
dev_err ( & pdev - > dev , " failed to allocate tx desc ring \n " ) ;
2010-05-17 05:22:08 +04:00
err = - ENOMEM ;
goto err_out_free ;
2010-01-13 03:37:25 +03:00
}
tx_ring - > desc_head = ( struct cmd_desc_type0 * ) addr ;
for ( ring = 0 ; ring < adapter - > max_rds_rings ; ring + + ) {
rds_ring = & recv_ctx - > rds_rings [ ring ] ;
addr = pci_alloc_consistent ( adapter - > pdev ,
RCV_DESC_RINGSIZE ( rds_ring ) ,
& rds_ring - > phys_addr ) ;
if ( addr = = NULL ) {
dev_err ( & pdev - > dev ,
" failed to allocate rds ring [%d] \n " , ring ) ;
err = - ENOMEM ;
goto err_out_free ;
}
rds_ring - > desc_head = ( struct rcv_desc * ) addr ;
}
for ( ring = 0 ; ring < adapter - > max_sds_rings ; ring + + ) {
sds_ring = & recv_ctx - > sds_rings [ ring ] ;
addr = pci_alloc_consistent ( adapter - > pdev ,
STATUS_DESC_RINGSIZE ( sds_ring ) ,
& sds_ring - > phys_addr ) ;
if ( addr = = NULL ) {
dev_err ( & pdev - > dev ,
" failed to allocate sds ring [%d] \n " , ring ) ;
err = - ENOMEM ;
goto err_out_free ;
}
sds_ring - > desc_head = ( struct status_desc * ) addr ;
}
return 0 ;
err_out_free :
qlcnic_free_hw_resources ( adapter ) ;
return err ;
}
2010-06-22 07:19:01 +04:00
int qlcnic_fw_create_ctx ( struct qlcnic_adapter * adapter )
2010-01-13 03:37:25 +03:00
{
2010-06-22 07:19:01 +04:00
int err ;
err = qlcnic_fw_cmd_create_rx_ctx ( adapter ) ;
if ( err )
return err ;
err = qlcnic_fw_cmd_create_tx_ctx ( adapter ) ;
if ( err ) {
qlcnic_fw_cmd_destroy_rx_ctx ( adapter ) ;
return err ;
}
2010-01-13 03:37:25 +03:00
2010-06-22 07:19:01 +04:00
set_bit ( __QLCNIC_FW_ATTACHED , & adapter - > state ) ;
return 0 ;
}
2010-01-13 03:37:25 +03:00
2010-06-22 07:19:01 +04:00
void qlcnic_fw_destroy_ctx ( struct qlcnic_adapter * adapter )
{
2010-01-13 03:37:25 +03:00
if ( test_and_clear_bit ( __QLCNIC_FW_ATTACHED , & adapter - > state ) ) {
qlcnic_fw_cmd_destroy_rx_ctx ( adapter ) ;
qlcnic_fw_cmd_destroy_tx_ctx ( adapter ) ;
/* Allow dma queues to drain after context reset */
msleep ( 20 ) ;
}
2010-06-22 07:19:01 +04:00
}
void qlcnic_free_hw_resources ( struct qlcnic_adapter * adapter )
{
struct qlcnic_recv_context * recv_ctx ;
struct qlcnic_host_rds_ring * rds_ring ;
struct qlcnic_host_sds_ring * sds_ring ;
struct qlcnic_host_tx_ring * tx_ring ;
int ring ;
2010-01-13 03:37:25 +03:00
recv_ctx = & adapter - > recv_ctx ;
tx_ring = adapter - > tx_ring ;
if ( tx_ring - > hw_consumer ! = NULL ) {
pci_free_consistent ( adapter - > pdev ,
sizeof ( u32 ) ,
tx_ring - > hw_consumer ,
tx_ring - > hw_cons_phys_addr ) ;
tx_ring - > hw_consumer = NULL ;
}
if ( tx_ring - > desc_head ! = NULL ) {
pci_free_consistent ( adapter - > pdev ,
TX_DESC_RINGSIZE ( tx_ring ) ,
tx_ring - > desc_head , tx_ring - > phys_addr ) ;
tx_ring - > desc_head = NULL ;
}
for ( ring = 0 ; ring < adapter - > max_rds_rings ; ring + + ) {
rds_ring = & recv_ctx - > rds_rings [ ring ] ;
if ( rds_ring - > desc_head ! = NULL ) {
pci_free_consistent ( adapter - > pdev ,
RCV_DESC_RINGSIZE ( rds_ring ) ,
rds_ring - > desc_head ,
rds_ring - > phys_addr ) ;
rds_ring - > desc_head = NULL ;
}
}
for ( ring = 0 ; ring < adapter - > max_sds_rings ; ring + + ) {
sds_ring = & recv_ctx - > sds_rings [ ring ] ;
if ( sds_ring - > desc_head ! = NULL ) {
pci_free_consistent ( adapter - > pdev ,
STATUS_DESC_RINGSIZE ( sds_ring ) ,
sds_ring - > desc_head ,
sds_ring - > phys_addr ) ;
sds_ring - > desc_head = NULL ;
}
}
}
2010-06-01 15:28:51 +04:00
/* Set MAC address of a NIC partition */
int qlcnic_set_mac_address ( struct qlcnic_adapter * adapter , u8 * mac )
{
int err = 0 ;
u32 arg1 , arg2 , arg3 ;
arg1 = adapter - > ahw . pci_func | BIT_9 ;
arg2 = mac [ 0 ] | ( mac [ 1 ] < < 8 ) | ( mac [ 2 ] < < 16 ) | ( mac [ 3 ] < < 24 ) ;
arg3 = mac [ 4 ] | ( mac [ 5 ] < < 16 ) ;
err = qlcnic_issue_cmd ( adapter ,
adapter - > ahw . pci_func ,
adapter - > fw_hal_version ,
arg1 ,
arg2 ,
arg3 ,
QLCNIC_CDRP_CMD_MAC_ADDRESS ) ;
if ( err ! = QLCNIC_RCODE_SUCCESS ) {
dev_err ( & adapter - > pdev - > dev ,
" Failed to set mac address%d \n " , err ) ;
err = - EIO ;
}
return err ;
}
/* Get MAC address of a NIC partition */
int qlcnic_get_mac_address ( struct qlcnic_adapter * adapter , u8 * mac )
{
int err ;
u32 arg1 ;
arg1 = adapter - > ahw . pci_func | BIT_8 ;
err = qlcnic_issue_cmd ( adapter ,
adapter - > ahw . pci_func ,
adapter - > fw_hal_version ,
arg1 ,
0 ,
0 ,
QLCNIC_CDRP_CMD_MAC_ADDRESS ) ;
2010-06-17 06:56:39 +04:00
if ( err = = QLCNIC_RCODE_SUCCESS )
2010-06-01 15:28:51 +04:00
qlcnic_fetch_mac ( adapter , QLCNIC_ARG1_CRB_OFFSET ,
QLCNIC_ARG2_CRB_OFFSET , 0 , mac ) ;
2010-06-17 06:56:39 +04:00
else {
2010-06-01 15:28:51 +04:00
dev_err ( & adapter - > pdev - > dev ,
" Failed to get mac address%d \n " , err ) ;
err = - EIO ;
}
return err ;
}
/* Get info of a NIC partition */
int qlcnic_get_nic_info ( struct qlcnic_adapter * adapter , u8 func_id )
{
int err ;
dma_addr_t nic_dma_t ;
struct qlcnic_info * nic_info ;
void * nic_info_addr ;
size_t nic_size = sizeof ( struct qlcnic_info ) ;
nic_info_addr = pci_alloc_consistent ( adapter - > pdev ,
nic_size , & nic_dma_t ) ;
if ( ! nic_info_addr )
return - ENOMEM ;
memset ( nic_info_addr , 0 , nic_size ) ;
nic_info = ( struct qlcnic_info * ) nic_info_addr ;
err = qlcnic_issue_cmd ( adapter ,
adapter - > ahw . pci_func ,
adapter - > fw_hal_version ,
MSD ( nic_dma_t ) ,
LSD ( nic_dma_t ) ,
( func_id < < 16 | nic_size ) ,
QLCNIC_CDRP_CMD_GET_NIC_INFO ) ;
if ( err = = QLCNIC_RCODE_SUCCESS ) {
adapter - > physical_port = le16_to_cpu ( nic_info - > phys_port ) ;
adapter - > switch_mode = le16_to_cpu ( nic_info - > switch_mode ) ;
adapter - > max_tx_ques = le16_to_cpu ( nic_info - > max_tx_ques ) ;
adapter - > max_rx_ques = le16_to_cpu ( nic_info - > max_rx_ques ) ;
adapter - > min_tx_bw = le16_to_cpu ( nic_info - > min_tx_bw ) ;
adapter - > max_tx_bw = le16_to_cpu ( nic_info - > max_tx_bw ) ;
adapter - > max_mtu = le16_to_cpu ( nic_info - > max_mtu ) ;
adapter - > capabilities = le32_to_cpu ( nic_info - > capabilities ) ;
adapter - > max_mac_filters = nic_info - > max_mac_filters ;
2010-06-16 13:07:27 +04:00
if ( adapter - > capabilities & BIT_6 )
adapter - > flags | = QLCNIC_ESWITCH_ENABLED ;
else
adapter - > flags & = ~ QLCNIC_ESWITCH_ENABLED ;
2010-06-01 15:28:51 +04:00
dev_info ( & adapter - > pdev - > dev ,
" phy port: %d switch_mode: %d, \n "
" \t max_tx_q: %d max_rx_q: %d min_tx_bw: 0x%x, \n "
" \t max_tx_bw: 0x%x max_mtu:0x%x, capabilities: 0x%x \n " ,
adapter - > physical_port , adapter - > switch_mode ,
adapter - > max_tx_ques , adapter - > max_rx_ques ,
adapter - > min_tx_bw , adapter - > max_tx_bw ,
adapter - > max_mtu , adapter - > capabilities ) ;
} else {
dev_err ( & adapter - > pdev - > dev ,
" Failed to get nic info%d \n " , err ) ;
err = - EIO ;
}
pci_free_consistent ( adapter - > pdev , nic_size , nic_info_addr , nic_dma_t ) ;
return err ;
}
/* Configure a NIC partition */
int qlcnic_set_nic_info ( struct qlcnic_adapter * adapter , struct qlcnic_info * nic )
{
int err = - EIO ;
u32 func_state ;
dma_addr_t nic_dma_t ;
void * nic_info_addr ;
struct qlcnic_info * nic_info ;
size_t nic_size = sizeof ( struct qlcnic_info ) ;
if ( adapter - > op_mode ! = QLCNIC_MGMT_FUNC )
return err ;
if ( qlcnic_api_lock ( adapter ) )
return err ;
func_state = QLCRD32 ( adapter , QLCNIC_CRB_DEV_REF_COUNT ) ;
if ( QLC_DEV_CHECK_ACTIVE ( func_state , nic - > pci_func ) ) {
qlcnic_api_unlock ( adapter ) ;
return err ;
}
qlcnic_api_unlock ( adapter ) ;
nic_info_addr = pci_alloc_consistent ( adapter - > pdev , nic_size ,
& nic_dma_t ) ;
if ( ! nic_info_addr )
return - ENOMEM ;
memset ( nic_info_addr , 0 , nic_size ) ;
nic_info = ( struct qlcnic_info * ) nic_info_addr ;
nic_info - > pci_func = cpu_to_le16 ( nic - > pci_func ) ;
nic_info - > op_mode = cpu_to_le16 ( nic - > op_mode ) ;
nic_info - > phys_port = cpu_to_le16 ( nic - > phys_port ) ;
nic_info - > switch_mode = cpu_to_le16 ( nic - > switch_mode ) ;
nic_info - > capabilities = cpu_to_le32 ( nic - > capabilities ) ;
nic_info - > max_mac_filters = nic - > max_mac_filters ;
nic_info - > max_tx_ques = cpu_to_le16 ( nic - > max_tx_ques ) ;
nic_info - > max_rx_ques = cpu_to_le16 ( nic - > max_rx_ques ) ;
nic_info - > min_tx_bw = cpu_to_le16 ( nic - > min_tx_bw ) ;
nic_info - > max_tx_bw = cpu_to_le16 ( nic - > max_tx_bw ) ;
err = qlcnic_issue_cmd ( adapter ,
adapter - > ahw . pci_func ,
adapter - > fw_hal_version ,
MSD ( nic_dma_t ) ,
LSD ( nic_dma_t ) ,
nic_size ,
QLCNIC_CDRP_CMD_SET_NIC_INFO ) ;
if ( err ! = QLCNIC_RCODE_SUCCESS ) {
dev_err ( & adapter - > pdev - > dev ,
" Failed to set nic info%d \n " , err ) ;
err = - EIO ;
}
pci_free_consistent ( adapter - > pdev , nic_size , nic_info_addr , nic_dma_t ) ;
return err ;
}
/* Get PCI Info of a partition */
int qlcnic_get_pci_info ( struct qlcnic_adapter * adapter )
{
int err = 0 , i ;
dma_addr_t pci_info_dma_t ;
struct qlcnic_pci_info * npar ;
void * pci_info_addr ;
size_t npar_size = sizeof ( struct qlcnic_pci_info ) ;
size_t pci_size = npar_size * QLCNIC_MAX_PCI_FUNC ;
pci_info_addr = pci_alloc_consistent ( adapter - > pdev , pci_size ,
& pci_info_dma_t ) ;
if ( ! pci_info_addr )
return - ENOMEM ;
memset ( pci_info_addr , 0 , pci_size ) ;
if ( ! adapter - > npars )
adapter - > npars = kzalloc ( pci_size , GFP_KERNEL ) ;
if ( ! adapter - > npars ) {
err = - ENOMEM ;
goto err_npar ;
}
if ( ! adapter - > eswitch )
adapter - > eswitch = kzalloc ( sizeof ( struct qlcnic_eswitch ) *
QLCNIC_NIU_MAX_XG_PORTS , GFP_KERNEL ) ;
if ( ! adapter - > eswitch ) {
err = - ENOMEM ;
goto err_eswitch ;
}
npar = ( struct qlcnic_pci_info * ) pci_info_addr ;
err = qlcnic_issue_cmd ( adapter ,
adapter - > ahw . pci_func ,
adapter - > fw_hal_version ,
MSD ( pci_info_dma_t ) ,
LSD ( pci_info_dma_t ) ,
pci_size ,
QLCNIC_CDRP_CMD_GET_PCI_INFO ) ;
if ( err = = QLCNIC_RCODE_SUCCESS ) {
for ( i = 0 ; i < QLCNIC_MAX_PCI_FUNC ; i + + , npar + + ) {
adapter - > npars [ i ] . id = le32_to_cpu ( npar - > id ) ;
adapter - > npars [ i ] . active = le32_to_cpu ( npar - > active ) ;
adapter - > npars [ i ] . type = le32_to_cpu ( npar - > type ) ;
adapter - > npars [ i ] . default_port =
le32_to_cpu ( npar - > default_port ) ;
adapter - > npars [ i ] . tx_min_bw =
le32_to_cpu ( npar - > tx_min_bw ) ;
adapter - > npars [ i ] . tx_max_bw =
le32_to_cpu ( npar - > tx_max_bw ) ;
memcpy ( adapter - > npars [ i ] . mac , npar - > mac , ETH_ALEN ) ;
}
} else {
dev_err ( & adapter - > pdev - > dev ,
" Failed to get PCI Info%d \n " , err ) ;
kfree ( adapter - > npars ) ;
err = - EIO ;
}
goto err_npar ;
err_eswitch :
kfree ( adapter - > npars ) ;
adapter - > npars = NULL ;
err_npar :
pci_free_consistent ( adapter - > pdev , pci_size , pci_info_addr ,
pci_info_dma_t ) ;
return err ;
}
/* Reset a NIC partition */
int qlcnic_reset_partition ( struct qlcnic_adapter * adapter , u8 func_no )
{
int err = - EIO ;
if ( adapter - > op_mode ! = QLCNIC_MGMT_FUNC )
return err ;
err = qlcnic_issue_cmd ( adapter ,
adapter - > ahw . pci_func ,
adapter - > fw_hal_version ,
func_no ,
0 ,
0 ,
QLCNIC_CDRP_CMD_RESET_NPAR ) ;
if ( err ! = QLCNIC_RCODE_SUCCESS ) {
dev_err ( & adapter - > pdev - > dev ,
" Failed to issue reset partition%d \n " , err ) ;
err = - EIO ;
}
return err ;
}
/* Get eSwitch Capabilities */
int qlcnic_get_eswitch_capabilities ( struct qlcnic_adapter * adapter , u8 port ,
struct qlcnic_eswitch * eswitch )
{
int err = - EIO ;
u32 arg1 , arg2 ;
if ( adapter - > op_mode = = QLCNIC_NON_PRIV_FUNC )
return err ;
err = qlcnic_issue_cmd ( adapter ,
adapter - > ahw . pci_func ,
adapter - > fw_hal_version ,
port ,
0 ,
0 ,
QLCNIC_CDRP_CMD_GET_ESWITCH_CAPABILITY ) ;
if ( err = = QLCNIC_RCODE_SUCCESS ) {
arg1 = QLCRD32 ( adapter , QLCNIC_ARG1_CRB_OFFSET ) ;
arg2 = QLCRD32 ( adapter , QLCNIC_ARG2_CRB_OFFSET ) ;
eswitch - > port = arg1 & 0xf ;
eswitch - > active_vports = LSB ( arg2 ) ;
eswitch - > max_ucast_filters = MSB ( arg2 ) ;
eswitch - > max_active_vlans = LSB ( MSW ( arg2 ) ) ;
if ( arg1 & BIT_6 )
eswitch - > flags | = QLCNIC_SWITCH_VLAN_FILTERING ;
if ( arg1 & BIT_7 )
eswitch - > flags | = QLCNIC_SWITCH_PROMISC_MODE ;
if ( arg1 & BIT_8 )
eswitch - > flags | = QLCNIC_SWITCH_PORT_MIRRORING ;
} else {
dev_err ( & adapter - > pdev - > dev ,
" Failed to get eswitch capabilities%d \n " , err ) ;
}
return err ;
}
/* Get current status of eswitch */
int qlcnic_get_eswitch_status ( struct qlcnic_adapter * adapter , u8 port ,
struct qlcnic_eswitch * eswitch )
{
int err = - EIO ;
u32 arg1 , arg2 ;
if ( adapter - > op_mode ! = QLCNIC_MGMT_FUNC )
return err ;
err = qlcnic_issue_cmd ( adapter ,
adapter - > ahw . pci_func ,
adapter - > fw_hal_version ,
port ,
0 ,
0 ,
QLCNIC_CDRP_CMD_GET_ESWITCH_STATUS ) ;
if ( err = = QLCNIC_RCODE_SUCCESS ) {
arg1 = QLCRD32 ( adapter , QLCNIC_ARG1_CRB_OFFSET ) ;
arg2 = QLCRD32 ( adapter , QLCNIC_ARG2_CRB_OFFSET ) ;
eswitch - > port = arg1 & 0xf ;
eswitch - > active_vports = LSB ( arg2 ) ;
eswitch - > active_ucast_filters = MSB ( arg2 ) ;
eswitch - > active_vlans = LSB ( MSW ( arg2 ) ) ;
if ( arg1 & BIT_6 )
eswitch - > flags | = QLCNIC_SWITCH_VLAN_FILTERING ;
if ( arg1 & BIT_8 )
eswitch - > flags | = QLCNIC_SWITCH_PORT_MIRRORING ;
} else {
dev_err ( & adapter - > pdev - > dev ,
" Failed to get eswitch status%d \n " , err ) ;
}
return err ;
}
/* Enable/Disable eSwitch */
int qlcnic_toggle_eswitch ( struct qlcnic_adapter * adapter , u8 id , u8 enable )
{
int err = - EIO ;
u32 arg1 , arg2 ;
struct qlcnic_eswitch * eswitch ;
if ( adapter - > op_mode ! = QLCNIC_MGMT_FUNC )
return err ;
eswitch = & adapter - > eswitch [ id ] ;
if ( ! eswitch )
return err ;
arg1 = eswitch - > port | ( enable ? BIT_4 : 0 ) ;
arg2 = eswitch - > active_vports | ( eswitch - > max_ucast_filters < < 8 ) |
( eswitch - > max_active_vlans < < 16 ) ;
err = qlcnic_issue_cmd ( adapter ,
adapter - > ahw . pci_func ,
adapter - > fw_hal_version ,
arg1 ,
arg2 ,
0 ,
QLCNIC_CDRP_CMD_TOGGLE_ESWITCH ) ;
if ( err ! = QLCNIC_RCODE_SUCCESS ) {
dev_err ( & adapter - > pdev - > dev ,
" Failed to enable eswitch%d \n " , eswitch - > port ) ;
eswitch - > flags & = ~ QLCNIC_SWITCH_ENABLE ;
err = - EIO ;
} else {
eswitch - > flags | = QLCNIC_SWITCH_ENABLE ;
dev_info ( & adapter - > pdev - > dev ,
" Enabled eSwitch for port %d \n " , eswitch - > port ) ;
}
return err ;
}
/* Configure eSwitch for port mirroring */
int qlcnic_config_port_mirroring ( struct qlcnic_adapter * adapter , u8 id ,
u8 enable_mirroring , u8 pci_func )
{
int err = - EIO ;
u32 arg1 ;
if ( adapter - > op_mode ! = QLCNIC_MGMT_FUNC | |
! ( adapter - > eswitch [ id ] . flags & QLCNIC_SWITCH_ENABLE ) )
return err ;
arg1 = id | ( enable_mirroring ? BIT_4 : 0 ) ;
arg1 | = pci_func < < 8 ;
err = qlcnic_issue_cmd ( adapter ,
adapter - > ahw . pci_func ,
adapter - > fw_hal_version ,
arg1 ,
0 ,
0 ,
QLCNIC_CDRP_CMD_SET_PORTMIRRORING ) ;
if ( err ! = QLCNIC_RCODE_SUCCESS ) {
dev_err ( & adapter - > pdev - > dev ,
" Failed to configure port mirroring%d on eswitch:%d \n " ,
pci_func , id ) ;
} else {
dev_info ( & adapter - > pdev - > dev ,
" Configured eSwitch %d for port mirroring:%d \n " ,
id , pci_func ) ;
}
return err ;
}
/* Configure eSwitch port */
int qlcnic_config_switch_port ( struct qlcnic_adapter * adapter , u8 id ,
int vlan_tagging , u8 discard_tagged , u8 promsc_mode ,
u8 mac_learn , u8 pci_func , u16 vlan_id )
{
int err = - EIO ;
u32 arg1 ;
struct qlcnic_eswitch * eswitch ;
if ( adapter - > op_mode ! = QLCNIC_MGMT_FUNC )
return err ;
eswitch = & adapter - > eswitch [ id ] ;
if ( ! ( eswitch - > flags & QLCNIC_SWITCH_ENABLE ) )
return err ;
arg1 = eswitch - > port | ( discard_tagged ? BIT_4 : 0 ) ;
arg1 | = ( promsc_mode ? BIT_6 : 0 ) | ( mac_learn ? BIT_7 : 0 ) ;
arg1 | = pci_func < < 8 ;
if ( vlan_tagging )
arg1 | = BIT_5 | ( vlan_id < < 16 ) ;
err = qlcnic_issue_cmd ( adapter ,
adapter - > ahw . pci_func ,
adapter - > fw_hal_version ,
arg1 ,
0 ,
0 ,
QLCNIC_CDRP_CMD_CONFIGURE_ESWITCH ) ;
if ( err ! = QLCNIC_RCODE_SUCCESS ) {
dev_err ( & adapter - > pdev - > dev ,
" Failed to configure eswitch port%d \n " , eswitch - > port ) ;
eswitch - > flags | = QLCNIC_SWITCH_ENABLE ;
} else {
eswitch - > flags & = ~ QLCNIC_SWITCH_ENABLE ;
dev_info ( & adapter - > pdev - > dev ,
" Configured eSwitch for port %d \n " , eswitch - > port ) ;
}
return err ;
}