2013-01-01 03:20:19 +00:00
# include "qlcnic.h"
# include <linux/if_vlan.h>
# include <linux/ipv6.h>
# include <linux/ethtool.h>
# include <linux/interrupt.h>
# define QLCNIC_MAX_TX_QUEUES 1
# define QLCNIC_MBX_RSP(reg) LSW(reg)
# define QLCNIC_MBX_NUM_REGS(reg) (MSW(reg) & 0x1FF)
# define QLCNIC_MBX_STATUS(reg) (((reg) >> 25) & 0x7F)
# define QLCNIC_MBX_HOST(ahw, i) ((ahw)->pci_base0 + ((i) * 4))
# define QLCNIC_MBX_FW(ahw, i) ((ahw)->pci_base0 + 0x800 + ((i) * 4))
# define RSS_HASHTYPE_IP_TCP 0x3
/* status descriptor mailbox data
* @ phy_addr : physical address of buffer
* @ sds_ring_size : buffer size
* @ intrpt_id : interrupt id
* @ intrpt_val : source of interrupt
*/
struct qlcnic_sds_mbx {
u64 phy_addr ;
u8 rsvd1 [ 16 ] ;
u16 sds_ring_size ;
u16 rsvd2 [ 3 ] ;
u16 intrpt_id ;
u8 intrpt_val ;
u8 rsvd3 [ 5 ] ;
} __packed ;
/* receive descriptor buffer data
* phy_addr_reg : physical address of regular buffer
* phy_addr_jmb : physical address of jumbo buffer
* reg_ring_sz : size of regular buffer
* reg_ring_len : no . of entries in regular buffer
* jmb_ring_len : no . of entries in jumbo buffer
* jmb_ring_sz : size of jumbo buffer
*/
struct qlcnic_rds_mbx {
u64 phy_addr_reg ;
u64 phy_addr_jmb ;
u16 reg_ring_sz ;
u16 reg_ring_len ;
u16 jmb_ring_sz ;
u16 jmb_ring_len ;
} __packed ;
/* host producers for regular and jumbo rings */
struct __host_producer_mbx {
u32 reg_buf ;
u32 jmb_buf ;
} __packed ;
/* Receive context mailbox data outbox registers
* @ state : state of the context
* @ vport_id : virtual port id
* @ context_id : receive context id
* @ num_pci_func : number of pci functions of the port
* @ phy_port : physical port id
*/
struct qlcnic_rcv_mbx_out {
u8 rcv_num ;
u8 sts_num ;
u16 ctx_id ;
u8 state ;
u8 num_pci_func ;
u8 phy_port ;
u8 vport_id ;
u32 host_csmr [ QLCNIC_MAX_RING_SETS ] ;
struct __host_producer_mbx host_prod [ QLCNIC_MAX_RING_SETS ] ;
} __packed ;
struct qlcnic_add_rings_mbx_out {
u8 rcv_num ;
u8 sts_num ;
u16 ctx_id ;
u32 host_csmr [ QLCNIC_MAX_RING_SETS ] ;
struct __host_producer_mbx host_prod [ QLCNIC_MAX_RING_SETS ] ;
} __packed ;
/* Transmit context mailbox inbox registers
* @ phys_addr : DMA address of the transmit buffer
* @ cnsmr_index : host consumer index
* @ size : legth of transmit buffer ring
* @ intr_id : interrput id
* @ src : src of interrupt
*/
struct qlcnic_tx_mbx {
u64 phys_addr ;
u64 cnsmr_index ;
u16 size ;
u16 intr_id ;
u8 src ;
u8 rsvd [ 3 ] ;
} __packed ;
/* Transmit context mailbox outbox registers
* @ host_prod : host producer index
* @ ctx_id : transmit context id
* @ state : state of the transmit context
*/
struct qlcnic_tx_mbx_out {
u32 host_prod ;
u16 ctx_id ;
u8 state ;
u8 rsvd ;
} __packed ;
static const struct qlcnic_mailbox_metadata qlcnic_83xx_mbx_tbl [ ] = {
{ QLCNIC_CMD_CONFIGURE_IP_ADDR , 6 , 1 } ,
{ QLCNIC_CMD_CONFIG_INTRPT , 18 , 34 } ,
{ QLCNIC_CMD_CREATE_RX_CTX , 136 , 27 } ,
{ QLCNIC_CMD_DESTROY_RX_CTX , 2 , 1 } ,
{ QLCNIC_CMD_CREATE_TX_CTX , 54 , 18 } ,
{ QLCNIC_CMD_DESTROY_TX_CTX , 2 , 1 } ,
{ QLCNIC_CMD_CONFIGURE_MAC_LEARNING , 2 , 1 } ,
{ QLCNIC_CMD_INTRPT_TEST , 22 , 12 } ,
{ QLCNIC_CMD_SET_MTU , 3 , 1 } ,
{ QLCNIC_CMD_READ_PHY , 4 , 2 } ,
{ QLCNIC_CMD_WRITE_PHY , 5 , 1 } ,
{ QLCNIC_CMD_READ_HW_REG , 4 , 1 } ,
{ QLCNIC_CMD_GET_FLOW_CTL , 4 , 2 } ,
{ QLCNIC_CMD_SET_FLOW_CTL , 4 , 1 } ,
{ QLCNIC_CMD_READ_MAX_MTU , 4 , 2 } ,
{ QLCNIC_CMD_READ_MAX_LRO , 4 , 2 } ,
{ QLCNIC_CMD_MAC_ADDRESS , 4 , 3 } ,
{ QLCNIC_CMD_GET_PCI_INFO , 1 , 66 } ,
{ QLCNIC_CMD_GET_NIC_INFO , 2 , 19 } ,
{ QLCNIC_CMD_SET_NIC_INFO , 32 , 1 } ,
{ QLCNIC_CMD_GET_ESWITCH_CAPABILITY , 4 , 3 } ,
{ QLCNIC_CMD_TOGGLE_ESWITCH , 4 , 1 } ,
{ QLCNIC_CMD_GET_ESWITCH_STATUS , 4 , 3 } ,
{ QLCNIC_CMD_SET_PORTMIRRORING , 4 , 1 } ,
{ QLCNIC_CMD_CONFIGURE_ESWITCH , 4 , 1 } ,
{ QLCNIC_CMD_GET_ESWITCH_PORT_CONFIG , 4 , 3 } ,
{ QLCNIC_CMD_GET_ESWITCH_STATS , 5 , 1 } ,
{ QLCNIC_CMD_CONFIG_PORT , 4 , 1 } ,
{ QLCNIC_CMD_TEMP_SIZE , 1 , 4 } ,
{ QLCNIC_CMD_GET_TEMP_HDR , 5 , 5 } ,
{ QLCNIC_CMD_GET_LINK_EVENT , 2 , 1 } ,
{ QLCNIC_CMD_CONFIG_MAC_VLAN , 4 , 3 } ,
{ QLCNIC_CMD_CONFIG_INTR_COAL , 6 , 1 } ,
{ QLCNIC_CMD_CONFIGURE_RSS , 14 , 1 } ,
{ QLCNIC_CMD_CONFIGURE_LED , 2 , 1 } ,
{ QLCNIC_CMD_CONFIGURE_MAC_RX_MODE , 2 , 1 } ,
{ QLCNIC_CMD_CONFIGURE_HW_LRO , 2 , 1 } ,
{ QLCNIC_CMD_GET_STATISTICS , 2 , 80 } ,
{ QLCNIC_CMD_SET_PORT_CONFIG , 2 , 1 } ,
{ QLCNIC_CMD_GET_PORT_CONFIG , 2 , 2 } ,
{ QLCNIC_CMD_GET_LINK_STATUS , 2 , 4 } ,
{ QLCNIC_CMD_IDC_ACK , 5 , 1 } ,
{ QLCNIC_CMD_INIT_NIC_FUNC , 2 , 1 } ,
{ QLCNIC_CMD_STOP_NIC_FUNC , 2 , 1 } ,
{ QLCNIC_CMD_SET_LED_CONFIG , 5 , 1 } ,
{ QLCNIC_CMD_GET_LED_CONFIG , 1 , 5 } ,
{ QLCNIC_CMD_ADD_RCV_RINGS , 130 , 26 } ,
} ;
static const u32 qlcnic_83xx_ext_reg_tbl [ ] = {
0x38CC , /* Global Reset */
0x38F0 , /* Wildcard */
0x38FC , /* Informant */
0x3038 , /* Host MBX ctrl */
0x303C , /* FW MBX ctrl */
0x355C , /* BOOT LOADER ADDRESS REG */
0x3560 , /* BOOT LOADER SIZE REG */
0x3564 , /* FW IMAGE ADDR REG */
0x1000 , /* MBX intr enable */
0x1200 , /* Default Intr mask */
0x1204 , /* Default Interrupt ID */
0x3780 , /* QLC_83XX_IDC_MAJ_VERSION */
0x3784 , /* QLC_83XX_IDC_DEV_STATE */
0x3788 , /* QLC_83XX_IDC_DRV_PRESENCE */
0x378C , /* QLC_83XX_IDC_DRV_ACK */
0x3790 , /* QLC_83XX_IDC_CTRL */
0x3794 , /* QLC_83XX_IDC_DRV_AUDIT */
0x3798 , /* QLC_83XX_IDC_MIN_VERSION */
0x379C , /* QLC_83XX_RECOVER_DRV_LOCK */
0x37A0 , /* QLC_83XX_IDC_PF_0 */
0x37A4 , /* QLC_83XX_IDC_PF_1 */
0x37A8 , /* QLC_83XX_IDC_PF_2 */
0x37AC , /* QLC_83XX_IDC_PF_3 */
0x37B0 , /* QLC_83XX_IDC_PF_4 */
0x37B4 , /* QLC_83XX_IDC_PF_5 */
0x37B8 , /* QLC_83XX_IDC_PF_6 */
0x37BC , /* QLC_83XX_IDC_PF_7 */
0x37C0 , /* QLC_83XX_IDC_PF_8 */
0x37C4 , /* QLC_83XX_IDC_PF_9 */
0x37C8 , /* QLC_83XX_IDC_PF_10 */
0x37CC , /* QLC_83XX_IDC_PF_11 */
0x37D0 , /* QLC_83XX_IDC_PF_12 */
0x37D4 , /* QLC_83XX_IDC_PF_13 */
0x37D8 , /* QLC_83XX_IDC_PF_14 */
0x37DC , /* QLC_83XX_IDC_PF_15 */
0x37E0 , /* QLC_83XX_IDC_DEV_PARTITION_INFO_1 */
0x37E4 , /* QLC_83XX_IDC_DEV_PARTITION_INFO_2 */
0x37F0 , /* QLC_83XX_DRV_OP_MODE */
0x37F4 , /* QLC_83XX_VNIC_STATE */
0x3868 , /* QLC_83XX_DRV_LOCK */
0x386C , /* QLC_83XX_DRV_UNLOCK */
0x3504 , /* QLC_83XX_DRV_LOCK_ID */
0x34A4 , /* QLC_83XX_ASIC_TEMP */
} ;
static const u32 qlcnic_83xx_reg_tbl [ ] = {
0x34A8 , /* PEG_HALT_STAT1 */
0x34AC , /* PEG_HALT_STAT2 */
0x34B0 , /* FW_HEARTBEAT */
0x3500 , /* FLASH LOCK_ID */
0x3528 , /* FW_CAPABILITIES */
0x3538 , /* Driver active, DRV_REG0 */
0x3540 , /* Device state, DRV_REG1 */
0x3544 , /* Driver state, DRV_REG2 */
0x3548 , /* Driver scratch, DRV_REG3 */
0x354C , /* Device partiton info, DRV_REG4 */
0x3524 , /* Driver IDC ver, DRV_REG5 */
0x3550 , /* FW_VER_MAJOR */
0x3554 , /* FW_VER_MINOR */
0x3558 , /* FW_VER_SUB */
0x359C , /* NPAR STATE */
0x35FC , /* FW_IMG_VALID */
0x3650 , /* CMD_PEG_STATE */
0x373C , /* RCV_PEG_STATE */
0x37B4 , /* ASIC TEMP */
0x356C , /* FW API */
0x3570 , /* DRV OP MODE */
0x3850 , /* FLASH LOCK */
0x3854 , /* FLASH UNLOCK */
} ;
static struct qlcnic_hardware_ops qlcnic_83xx_hw_ops = {
. read_crb = qlcnic_83xx_read_crb ,
. write_crb = qlcnic_83xx_write_crb ,
. read_reg = qlcnic_83xx_rd_reg_indirect ,
. write_reg = qlcnic_83xx_wrt_reg_indirect ,
. get_mac_address = qlcnic_83xx_get_mac_address ,
. setup_intr = qlcnic_83xx_setup_intr ,
. alloc_mbx_args = qlcnic_83xx_alloc_mbx_args ,
. mbx_cmd = qlcnic_83xx_mbx_op ,
. get_func_no = qlcnic_83xx_get_func_no ,
. api_lock = qlcnic_83xx_cam_lock ,
. api_unlock = qlcnic_83xx_cam_unlock ,
2013-01-01 03:20:22 +00:00
. add_sysfs = qlcnic_83xx_add_sysfs ,
. remove_sysfs = qlcnic_83xx_remove_sysfs ,
2013-01-01 03:20:20 +00:00
. process_lb_rcv_ring_diag = qlcnic_83xx_process_rcv_ring_diag ,
2013-01-01 03:20:19 +00:00
. create_rx_ctx = qlcnic_83xx_create_rx_ctx ,
. create_tx_ctx = qlcnic_83xx_create_tx_ctx ,
. setup_link_event = qlcnic_83xx_setup_link_event ,
. get_nic_info = qlcnic_83xx_get_nic_info ,
. get_pci_info = qlcnic_83xx_get_pci_info ,
. set_nic_info = qlcnic_83xx_set_nic_info ,
. change_macvlan = qlcnic_83xx_sre_macaddr_change ,
2013-01-01 03:20:20 +00:00
. napi_enable = qlcnic_83xx_napi_enable ,
. napi_disable = qlcnic_83xx_napi_disable ,
2013-01-01 03:20:19 +00:00
. config_intr_coal = qlcnic_83xx_config_intr_coal ,
. config_rss = qlcnic_83xx_config_rss ,
. config_hw_lro = qlcnic_83xx_config_hw_lro ,
. config_loopback = qlcnic_83xx_set_lb_mode ,
. clear_loopback = qlcnic_83xx_clear_lb_mode ,
. config_promisc_mode = qlcnic_83xx_nic_set_promisc ,
. change_l2_filter = qlcnic_83xx_change_l2_filter ,
. get_board_info = qlcnic_83xx_get_port_info ,
} ;
static struct qlcnic_nic_template qlcnic_83xx_ops = {
. config_bridged_mode = qlcnic_config_bridged_mode ,
. config_led = qlcnic_config_led ,
2013-01-01 03:20:20 +00:00
. napi_add = qlcnic_83xx_napi_add ,
. napi_del = qlcnic_83xx_napi_del ,
2013-01-01 03:20:19 +00:00
. config_ipaddr = qlcnic_83xx_config_ipaddr ,
. clear_legacy_intr = qlcnic_83xx_clear_legacy_intr ,
} ;
void qlcnic_83xx_register_map ( struct qlcnic_hardware_context * ahw )
{
ahw - > hw_ops = & qlcnic_83xx_hw_ops ;
ahw - > reg_tbl = ( u32 * ) qlcnic_83xx_reg_tbl ;
ahw - > ext_reg_tbl = ( u32 * ) qlcnic_83xx_ext_reg_tbl ;
}
int qlcnic_83xx_get_fw_version ( struct qlcnic_adapter * adapter )
{
u32 fw_major , fw_minor , fw_build ;
struct pci_dev * pdev = adapter - > pdev ;
fw_major = QLC_SHARED_REG_RD32 ( adapter , QLCNIC_FW_VERSION_MAJOR ) ;
fw_minor = QLC_SHARED_REG_RD32 ( adapter , QLCNIC_FW_VERSION_MINOR ) ;
fw_build = QLC_SHARED_REG_RD32 ( adapter , QLCNIC_FW_VERSION_SUB ) ;
adapter - > fw_version = QLCNIC_VERSION_CODE ( fw_major , fw_minor , fw_build ) ;
dev_info ( & pdev - > dev , " Driver v%s, firmware version %d.%d.%d \n " ,
QLCNIC_LINUX_VERSIONID , fw_major , fw_minor , fw_build ) ;
return adapter - > fw_version ;
}
static int __qlcnic_set_win_base ( struct qlcnic_adapter * adapter , u32 addr )
{
void __iomem * base ;
u32 val ;
base = adapter - > ahw - > pci_base0 +
QLC_83XX_CRB_WIN_FUNC ( adapter - > ahw - > pci_func ) ;
writel ( addr , base ) ;
val = readl ( base ) ;
if ( val ! = addr )
return - EIO ;
return 0 ;
}
int qlcnic_83xx_rd_reg_indirect ( struct qlcnic_adapter * adapter , ulong addr )
{
int ret ;
struct qlcnic_hardware_context * ahw = adapter - > ahw ;
ret = __qlcnic_set_win_base ( adapter , ( u32 ) addr ) ;
if ( ! ret ) {
return QLCRDX ( ahw , QLCNIC_WILDCARD ) ;
} else {
dev_err ( & adapter - > pdev - > dev ,
" %s failed, addr = 0x%x \n " , __func__ , ( int ) addr ) ;
return - EIO ;
}
}
int qlcnic_83xx_wrt_reg_indirect ( struct qlcnic_adapter * adapter , ulong addr ,
u32 data )
{
int err ;
struct qlcnic_hardware_context * ahw = adapter - > ahw ;
err = __qlcnic_set_win_base ( adapter , ( u32 ) addr ) ;
if ( ! err ) {
QLCWRX ( ahw , QLCNIC_WILDCARD , data ) ;
return 0 ;
} else {
dev_err ( & adapter - > pdev - > dev ,
" %s failed, addr = 0x%x data = 0x%x \n " ,
__func__ , ( int ) addr , data ) ;
return err ;
}
}
int qlcnic_83xx_setup_intr ( struct qlcnic_adapter * adapter , u8 num_intr )
{
int err , i , num_msix ;
struct qlcnic_hardware_context * ahw = adapter - > ahw ;
if ( ! num_intr )
num_intr = QLCNIC_DEF_NUM_STS_DESC_RINGS ;
num_msix = rounddown_pow_of_two ( min_t ( int , num_online_cpus ( ) ,
num_intr ) ) ;
/* account for AEN interrupt MSI-X based interrupts */
num_msix + = 1 ;
num_msix + = adapter - > max_drv_tx_rings ;
err = qlcnic_enable_msix ( adapter , num_msix ) ;
if ( err = = - ENOMEM )
return err ;
if ( adapter - > flags & QLCNIC_MSIX_ENABLED )
num_msix = adapter - > ahw - > num_msix ;
else
num_msix = 1 ;
/* setup interrupt mapping table for fw */
ahw - > intr_tbl = vzalloc ( num_msix *
sizeof ( struct qlcnic_intrpt_config ) ) ;
if ( ! ahw - > intr_tbl )
return - ENOMEM ;
if ( ! ( adapter - > flags & QLCNIC_MSIX_ENABLED ) ) {
/* MSI-X enablement failed, use legacy interrupt */
adapter - > tgt_status_reg = ahw - > pci_base0 + QLC_83XX_INTX_PTR ;
adapter - > tgt_mask_reg = ahw - > pci_base0 + QLC_83XX_INTX_MASK ;
adapter - > isr_int_vec = ahw - > pci_base0 + QLC_83XX_INTX_TRGR ;
adapter - > msix_entries [ 0 ] . vector = adapter - > pdev - > irq ;
dev_info ( & adapter - > pdev - > dev , " using legacy interrupt \n " ) ;
}
for ( i = 0 ; i < num_msix ; i + + ) {
if ( adapter - > flags & QLCNIC_MSIX_ENABLED )
ahw - > intr_tbl [ i ] . type = QLCNIC_INTRPT_MSIX ;
else
ahw - > intr_tbl [ i ] . type = QLCNIC_INTRPT_INTX ;
ahw - > intr_tbl [ i ] . id = i ;
ahw - > intr_tbl [ i ] . src = 0 ;
}
return 0 ;
}
inline void qlcnic_83xx_enable_intr ( struct qlcnic_adapter * adapter ,
struct qlcnic_host_sds_ring * sds_ring )
{
writel ( 0 , sds_ring - > crb_intr_mask ) ;
if ( ! QLCNIC_IS_MSI_FAMILY ( adapter ) )
writel ( 0 , adapter - > tgt_mask_reg ) ;
}
static inline void qlcnic_83xx_get_mbx_data ( struct qlcnic_adapter * adapter ,
struct qlcnic_cmd_args * cmd )
{
int i ;
for ( i = 0 ; i < cmd - > rsp . num ; i + + )
cmd - > rsp . arg [ i ] = readl ( QLCNIC_MBX_FW ( adapter - > ahw , i ) ) ;
}
irqreturn_t qlcnic_83xx_clear_legacy_intr ( struct qlcnic_adapter * adapter )
{
u32 intr_val ;
struct qlcnic_hardware_context * ahw = adapter - > ahw ;
int retries = 0 ;
intr_val = readl ( adapter - > tgt_status_reg ) ;
if ( ! QLC_83XX_VALID_INTX_BIT31 ( intr_val ) )
return IRQ_NONE ;
if ( QLC_83XX_INTX_FUNC ( intr_val ) ! = adapter - > ahw - > pci_func ) {
adapter - > stats . spurious_intr + + ;
return IRQ_NONE ;
}
/* clear the interrupt trigger control register */
writel ( 0 , adapter - > isr_int_vec ) ;
do {
intr_val = readl ( adapter - > tgt_status_reg ) ;
if ( QLC_83XX_INTX_FUNC ( intr_val ) ! = ahw - > pci_func )
break ;
retries + + ;
} while ( QLC_83XX_VALID_INTX_BIT30 ( intr_val ) & &
( retries < QLC_83XX_LEGACY_INTX_MAX_RETRY ) ) ;
if ( retries = = QLC_83XX_LEGACY_INTX_MAX_RETRY ) {
dev_info ( & adapter - > pdev - > dev ,
" Reached maximum retries to clear legacy interrupt \n " ) ;
return IRQ_NONE ;
}
mdelay ( QLC_83XX_LEGACY_INTX_DELAY ) ;
return IRQ_HANDLED ;
}
irqreturn_t qlcnic_83xx_tmp_intr ( int irq , void * data )
{
struct qlcnic_host_sds_ring * sds_ring = data ;
struct qlcnic_adapter * adapter = sds_ring - > adapter ;
if ( adapter - > flags & QLCNIC_MSIX_ENABLED )
goto done ;
if ( adapter - > nic_ops - > clear_legacy_intr ( adapter ) = = IRQ_NONE )
return IRQ_NONE ;
done :
adapter - > ahw - > diag_cnt + + ;
qlcnic_83xx_enable_intr ( adapter , sds_ring ) ;
return IRQ_HANDLED ;
}
void qlcnic_83xx_free_mbx_intr ( struct qlcnic_adapter * adapter )
{
u32 val = 0 ;
u32 num_msix = adapter - > ahw - > num_msix - 1 ;
val = ( num_msix < < 8 ) ;
QLCWRX ( adapter - > ahw , QLCNIC_MBX_INTR_ENBL , val ) ;
if ( adapter - > flags & QLCNIC_MSIX_ENABLED )
free_irq ( adapter - > msix_entries [ num_msix ] . vector , adapter ) ;
}
int qlcnic_83xx_setup_mbx_intr ( struct qlcnic_adapter * adapter )
{
irq_handler_t handler ;
u32 val ;
char name [ 32 ] ;
int err = 0 ;
unsigned long flags = 0 ;
if ( ! ( adapter - > flags & QLCNIC_MSI_ENABLED ) & &
! ( adapter - > flags & QLCNIC_MSIX_ENABLED ) )
flags | = IRQF_SHARED ;
if ( adapter - > flags & QLCNIC_MSIX_ENABLED ) {
handler = qlcnic_83xx_handle_aen ;
val = adapter - > msix_entries [ adapter - > ahw - > num_msix - 1 ] . vector ;
snprintf ( name , ( IFNAMSIZ + 4 ) ,
" %s[%s] " , adapter - > netdev - > name , " aen " ) ;
err = request_irq ( val , handler , flags , name , adapter ) ;
if ( err ) {
dev_err ( & adapter - > pdev - > dev ,
" failed to register MBX interrupt \n " ) ;
return err ;
}
}
/* Enable mailbox interrupt */
qlcnic_83xx_enable_mbx_intrpt ( adapter ) ;
if ( adapter - > flags & QLCNIC_MSIX_ENABLED )
err = qlcnic_83xx_config_intrpt ( adapter , 1 ) ;
return err ;
}
void qlcnic_83xx_get_func_no ( struct qlcnic_adapter * adapter )
{
u32 val = QLCRDX ( adapter - > ahw , QLCNIC_INFORMANT ) ;
adapter - > ahw - > pci_func = val & 0xf ;
}
int qlcnic_83xx_cam_lock ( struct qlcnic_adapter * adapter )
{
void __iomem * addr ;
u32 val , limit = 0 ;
struct qlcnic_hardware_context * ahw = adapter - > ahw ;
addr = ahw - > pci_base0 + QLC_83XX_SEM_LOCK_FUNC ( ahw - > pci_func ) ;
do {
val = readl ( addr ) ;
if ( val ) {
/* write the function number to register */
QLC_SHARED_REG_WR32 ( adapter , QLCNIC_FLASH_LOCK_OWNER ,
ahw - > pci_func ) ;
return 0 ;
}
usleep_range ( 1000 , 2000 ) ;
} while ( + + limit < = QLCNIC_PCIE_SEM_TIMEOUT ) ;
return - EIO ;
}
void qlcnic_83xx_cam_unlock ( struct qlcnic_adapter * adapter )
{
void __iomem * addr ;
u32 val ;
struct qlcnic_hardware_context * ahw = adapter - > ahw ;
addr = ahw - > pci_base0 + QLC_83XX_SEM_UNLOCK_FUNC ( ahw - > pci_func ) ;
val = readl ( addr ) ;
}
void qlcnic_83xx_read_crb ( struct qlcnic_adapter * adapter , char * buf ,
loff_t offset , size_t size )
{
int ret ;
u32 data ;
if ( qlcnic_api_lock ( adapter ) ) {
dev_err ( & adapter - > pdev - > dev ,
" %s: failed to acquire lock. addr offset 0x%x \n " ,
__func__ , ( u32 ) offset ) ;
return ;
}
ret = qlcnic_83xx_rd_reg_indirect ( adapter , ( u32 ) offset ) ;
qlcnic_api_unlock ( adapter ) ;
if ( ret = = - EIO ) {
dev_err ( & adapter - > pdev - > dev ,
" %s: failed. addr offset 0x%x \n " ,
__func__ , ( u32 ) offset ) ;
return ;
}
data = ret ;
memcpy ( buf , & data , size ) ;
}
void qlcnic_83xx_write_crb ( struct qlcnic_adapter * adapter , char * buf ,
loff_t offset , size_t size )
{
u32 data ;
memcpy ( & data , buf , size ) ;
qlcnic_83xx_wrt_reg_indirect ( adapter , ( u32 ) offset , data ) ;
}
int qlcnic_83xx_get_port_info ( struct qlcnic_adapter * adapter )
{
int status ;
status = qlcnic_83xx_get_port_config ( adapter ) ;
if ( status ) {
dev_err ( & adapter - > pdev - > dev ,
" Get Port Info failed \n " ) ;
} else {
if ( QLC_83XX_SFP_10G_CAPABLE ( adapter - > ahw - > port_config ) )
adapter - > ahw - > port_type = QLCNIC_XGBE ;
else
adapter - > ahw - > port_type = QLCNIC_GBE ;
if ( QLC_83XX_AUTONEG ( adapter - > ahw - > port_config ) )
adapter - > ahw - > link_autoneg = AUTONEG_ENABLE ;
}
return status ;
}
void qlcnic_83xx_enable_mbx_intrpt ( struct qlcnic_adapter * adapter )
{
u32 val ;
if ( adapter - > flags & QLCNIC_MSIX_ENABLED )
val = BIT_2 | ( ( adapter - > ahw - > num_msix - 1 ) < < 8 ) ;
else
val = BIT_2 ;
QLCWRX ( adapter - > ahw , QLCNIC_MBX_INTR_ENBL , val ) ;
}
void qlcnic_83xx_check_vf ( struct qlcnic_adapter * adapter ,
const struct pci_device_id * ent )
{
u32 op_mode , priv_level ;
struct qlcnic_hardware_context * ahw = adapter - > ahw ;
/* Determine FW API version */
ahw - > fw_hal_version = 2 ;
/* Find PCI function number */
qlcnic_get_func_no ( adapter ) ;
/* Determine function privilege level */
op_mode = QLCRDX ( adapter - > ahw , QLC_83XX_DRV_OP_MODE ) ;
if ( op_mode = = QLC_83XX_DEFAULT_OPMODE )
priv_level = QLCNIC_MGMT_FUNC ;
else
priv_level = QLC_83XX_GET_FUNC_PRIVILEGE ( op_mode ,
ahw - > pci_func ) ;
if ( priv_level = = QLCNIC_NON_PRIV_FUNC ) {
ahw - > op_mode = QLCNIC_NON_PRIV_FUNC ;
dev_info ( & adapter - > pdev - > dev ,
" HAL Version: %d Non Privileged function \n " ,
ahw - > fw_hal_version ) ;
adapter - > nic_ops = & qlcnic_vf_ops ;
} else {
adapter - > nic_ops = & qlcnic_83xx_ops ;
}
}
static void qlcnic_83xx_handle_link_aen ( struct qlcnic_adapter * adapter ,
u32 data [ ] ) ;
static void qlcnic_83xx_handle_idc_comp_aen ( struct qlcnic_adapter * adapter ,
u32 data [ ] ) ;
static void qlcnic_dump_mbx ( struct qlcnic_adapter * adapter ,
struct qlcnic_cmd_args * cmd )
{
int i ;
dev_info ( & adapter - > pdev - > dev ,
" Host MBX regs(%d) \n " , cmd - > req . num ) ;
for ( i = 0 ; i < cmd - > req . num ; i + + ) {
if ( i & & ! ( i % 8 ) )
pr_info ( " \n " ) ;
pr_info ( " %08x " , cmd - > req . arg [ i ] ) ;
}
pr_info ( " \n " ) ;
dev_info ( & adapter - > pdev - > dev ,
" FW MBX regs(%d) \n " , cmd - > rsp . num ) ;
for ( i = 0 ; i < cmd - > rsp . num ; i + + ) {
if ( i & & ! ( i % 8 ) )
pr_info ( " \n " ) ;
pr_info ( " %08x " , cmd - > rsp . arg [ i ] ) ;
}
pr_info ( " \n " ) ;
}
static u32 qlcnic_83xx_mbx_poll ( struct qlcnic_adapter * adapter )
{
u32 data ;
unsigned long wait_time = 0 ;
struct qlcnic_hardware_context * ahw = adapter - > ahw ;
/* wait for mailbox completion */
do {
data = QLCRDX ( ahw , QLCNIC_FW_MBX_CTRL ) ;
if ( + + wait_time > QLCNIC_MBX_TIMEOUT ) {
data = QLCNIC_RCODE_TIMEOUT ;
break ;
}
mdelay ( 1 ) ;
} while ( ! data ) ;
return data ;
}
int qlcnic_83xx_mbx_op ( struct qlcnic_adapter * adapter ,
struct qlcnic_cmd_args * cmd )
{
int i ;
u16 opcode ;
u8 mbx_err_code , mac_cmd_rcode ;
u32 rsp , mbx_val , fw_data , rsp_num , mbx_cmd , temp , fw [ 8 ] ;
struct qlcnic_hardware_context * ahw = adapter - > ahw ;
opcode = LSW ( cmd - > req . arg [ 0 ] ) ;
spin_lock ( & ahw - > mbx_lock ) ;
mbx_val = QLCRDX ( ahw , QLCNIC_HOST_MBX_CTRL ) ;
if ( mbx_val ) {
QLCDB ( adapter , DRV ,
" Mailbox cmd attempted, 0x%x \n " , opcode ) ;
QLCDB ( adapter , DRV ,
" Mailbox not available, 0x%x, collect FW dump \n " ,
mbx_val ) ;
cmd - > rsp . arg [ 0 ] = QLCNIC_RCODE_TIMEOUT ;
spin_unlock ( & ahw - > mbx_lock ) ;
return cmd - > rsp . arg [ 0 ] ;
}
/* Fill in mailbox registers */
mbx_cmd = cmd - > req . arg [ 0 ] ;
writel ( mbx_cmd , QLCNIC_MBX_HOST ( ahw , 0 ) ) ;
for ( i = 1 ; i < cmd - > req . num ; i + + )
writel ( cmd - > req . arg [ i ] , QLCNIC_MBX_HOST ( ahw , i ) ) ;
/* Signal FW about the impending command */
QLCWRX ( ahw , QLCNIC_HOST_MBX_CTRL , QLCNIC_SET_OWNER ) ;
poll :
rsp = qlcnic_83xx_mbx_poll ( adapter ) ;
/* Get the FW response data */
fw_data = readl ( QLCNIC_MBX_FW ( ahw , 0 ) ) ;
mbx_err_code = QLCNIC_MBX_STATUS ( fw_data ) ;
rsp_num = QLCNIC_MBX_NUM_REGS ( fw_data ) ;
opcode = QLCNIC_MBX_RSP ( fw_data ) ;
if ( rsp ! = QLCNIC_RCODE_TIMEOUT ) {
if ( opcode = = QLCNIC_MBX_LINK_EVENT ) {
for ( i = 0 ; i < rsp_num ; i + + ) {
temp = readl ( QLCNIC_MBX_FW ( ahw , i ) ) ;
fw [ i ] = temp ;
}
qlcnic_83xx_handle_link_aen ( adapter , fw ) ;
/* clear fw mbx control register */
QLCWRX ( ahw , QLCNIC_FW_MBX_CTRL , QLCNIC_CLR_OWNER ) ;
mbx_val = QLCRDX ( ahw , QLCNIC_HOST_MBX_CTRL ) ;
if ( mbx_val )
goto poll ;
} else if ( opcode = = QLCNIC_MBX_COMP_EVENT ) {
for ( i = 0 ; i < rsp_num ; i + + ) {
temp = readl ( QLCNIC_MBX_FW ( ahw , i ) ) ;
fw [ i ] = temp ;
}
qlcnic_83xx_handle_idc_comp_aen ( adapter , fw ) ;
/* clear fw mbx control register */
QLCWRX ( ahw , QLCNIC_FW_MBX_CTRL , QLCNIC_CLR_OWNER ) ;
mbx_val = QLCRDX ( ahw , QLCNIC_HOST_MBX_CTRL ) ;
if ( mbx_val )
goto poll ;
} else if ( opcode = = QLCNIC_MBX_REQUEST_EVENT ) {
/* IDC Request Notification */
for ( i = 0 ; i < rsp_num ; i + + ) {
temp = readl ( QLCNIC_MBX_FW ( ahw , i ) ) ;
fw [ i ] = temp ;
}
for ( i = 0 ; i < QLC_83XX_MBX_AEN_CNT ; i + + ) {
temp = QLCNIC_MBX_RSP ( fw [ i ] ) ;
adapter - > ahw - > mbox_aen [ i ] = temp ;
}
queue_delayed_work ( adapter - > qlcnic_wq ,
& adapter - > idc_aen_work , 0 ) ;
/* clear fw mbx control register */
QLCWRX ( ahw , QLCNIC_FW_MBX_CTRL , QLCNIC_CLR_OWNER ) ;
mbx_val = QLCRDX ( ahw , QLCNIC_HOST_MBX_CTRL ) ;
if ( mbx_val )
goto poll ;
} else if ( ( mbx_err_code = = QLCNIC_MBX_RSP_OK ) | |
( mbx_err_code = = QLCNIC_MBX_PORT_RSP_OK ) ) {
qlcnic_83xx_get_mbx_data ( adapter , cmd ) ;
rsp = QLCNIC_RCODE_SUCCESS ;
} else {
qlcnic_83xx_get_mbx_data ( adapter , cmd ) ;
if ( opcode = = QLCNIC_CMD_CONFIG_MAC_VLAN ) {
fw_data = readl ( QLCNIC_MBX_FW ( ahw , 2 ) ) ;
mac_cmd_rcode = ( u8 ) fw_data ;
if ( mac_cmd_rcode = = QLC_83XX_NO_NIC_RESOURCE | |
mac_cmd_rcode = = QLC_83XX_MAC_PRESENT | |
mac_cmd_rcode = = QLC_83XX_MAC_ABSENT ) {
rsp = QLCNIC_RCODE_SUCCESS ;
goto out ;
}
}
dev_info ( & adapter - > pdev - > dev ,
" MBX command 0x%x failed with err:0x%x \n " ,
opcode , mbx_err_code ) ;
rsp = mbx_err_code ;
qlcnic_dump_mbx ( adapter , cmd ) ;
}
} else {
dev_info ( & adapter - > pdev - > dev ,
" MBX command 0x%x timed out \n " , opcode ) ;
qlcnic_dump_mbx ( adapter , cmd ) ;
}
out :
/* clear fw mbx control register */
QLCWRX ( ahw , QLCNIC_FW_MBX_CTRL , QLCNIC_CLR_OWNER ) ;
spin_unlock ( & ahw - > mbx_lock ) ;
return rsp ;
}
int qlcnic_83xx_alloc_mbx_args ( struct qlcnic_cmd_args * mbx ,
struct qlcnic_adapter * adapter , u32 type )
{
int i , size ;
u32 temp ;
const struct qlcnic_mailbox_metadata * mbx_tbl ;
mbx_tbl = qlcnic_83xx_mbx_tbl ;
size = ARRAY_SIZE ( qlcnic_83xx_mbx_tbl ) ;
for ( i = 0 ; i < size ; i + + ) {
if ( type = = mbx_tbl [ i ] . cmd ) {
mbx - > req . num = mbx_tbl [ i ] . in_args ;
mbx - > rsp . num = mbx_tbl [ i ] . out_args ;
mbx - > req . arg = kcalloc ( mbx - > req . num , sizeof ( u32 ) ,
GFP_ATOMIC ) ;
if ( ! mbx - > req . arg )
return - ENOMEM ;
mbx - > rsp . arg = kcalloc ( mbx - > rsp . num , sizeof ( u32 ) ,
GFP_ATOMIC ) ;
if ( ! mbx - > rsp . arg ) {
kfree ( mbx - > req . arg ) ;
mbx - > req . arg = NULL ;
return - ENOMEM ;
}
memset ( mbx - > req . arg , 0 , sizeof ( u32 ) * mbx - > req . num ) ;
memset ( mbx - > rsp . arg , 0 , sizeof ( u32 ) * mbx - > rsp . num ) ;
temp = adapter - > ahw - > fw_hal_version < < 29 ;
mbx - > req . arg [ 0 ] = ( type | ( mbx - > req . num < < 16 ) | temp ) ;
break ;
}
}
return 0 ;
}
void qlcnic_83xx_idc_aen_work ( struct work_struct * work )
{
struct qlcnic_adapter * adapter ;
struct qlcnic_cmd_args cmd ;
int i , err = 0 ;
adapter = container_of ( work , struct qlcnic_adapter , idc_aen_work . work ) ;
qlcnic_alloc_mbx_args ( & cmd , adapter , QLCNIC_CMD_IDC_ACK ) ;
for ( i = 1 ; i < QLC_83XX_MBX_AEN_CNT ; i + + )
cmd . req . arg [ i ] = adapter - > ahw - > mbox_aen [ i ] ;
err = qlcnic_issue_cmd ( adapter , & cmd ) ;
if ( err )
dev_info ( & adapter - > pdev - > dev ,
" %s: Mailbox IDC ACK failed. \n " , __func__ ) ;
qlcnic_free_mbx_args ( & cmd ) ;
}
static void qlcnic_83xx_handle_idc_comp_aen ( struct qlcnic_adapter * adapter ,
u32 data [ ] )
{
dev_dbg ( & adapter - > pdev - > dev , " Completion AEN:0x%x. \n " ,
QLCNIC_MBX_RSP ( data [ 0 ] ) ) ;
return ;
}
void qlcnic_83xx_process_aen ( struct qlcnic_adapter * adapter )
{
u32 mask , resp , event [ QLC_83XX_MBX_AEN_CNT ] ;
int i ;
struct qlcnic_hardware_context * ahw = adapter - > ahw ;
if ( ! spin_trylock ( & ahw - > mbx_lock ) ) {
mask = QLCRDX ( adapter - > ahw , QLCNIC_DEF_INT_MASK ) ;
writel ( 0 , adapter - > ahw - > pci_base0 + mask ) ;
return ;
}
resp = QLCRDX ( ahw , QLCNIC_FW_MBX_CTRL ) ;
if ( ! ( resp & QLCNIC_SET_OWNER ) )
goto out ;
for ( i = 0 ; i < QLC_83XX_MBX_AEN_CNT ; i + + )
event [ i ] = readl ( QLCNIC_MBX_FW ( ahw , i ) ) ;
switch ( QLCNIC_MBX_RSP ( event [ 0 ] ) ) {
case QLCNIC_MBX_LINK_EVENT :
qlcnic_83xx_handle_link_aen ( adapter , event ) ;
break ;
case QLCNIC_MBX_COMP_EVENT :
qlcnic_83xx_handle_idc_comp_aen ( adapter , event ) ;
break ;
case QLCNIC_MBX_REQUEST_EVENT :
for ( i = 0 ; i < QLC_83XX_MBX_AEN_CNT ; i + + )
adapter - > ahw - > mbox_aen [ i ] = QLCNIC_MBX_RSP ( event [ i ] ) ;
queue_delayed_work ( adapter - > qlcnic_wq ,
& adapter - > idc_aen_work , 0 ) ;
break ;
case QLCNIC_MBX_TIME_EXTEND_EVENT :
break ;
case QLCNIC_MBX_SFP_INSERT_EVENT :
dev_info ( & adapter - > pdev - > dev , " SFP+ Insert AEN:0x%x. \n " ,
QLCNIC_MBX_RSP ( event [ 0 ] ) ) ;
break ;
case QLCNIC_MBX_SFP_REMOVE_EVENT :
dev_info ( & adapter - > pdev - > dev , " SFP Removed AEN:0x%x. \n " ,
QLCNIC_MBX_RSP ( event [ 0 ] ) ) ;
break ;
default :
dev_dbg ( & adapter - > pdev - > dev , " Unsupported AEN:0x%x. \n " ,
QLCNIC_MBX_RSP ( event [ 0 ] ) ) ;
break ;
}
QLCWRX ( ahw , QLCNIC_FW_MBX_CTRL , QLCNIC_CLR_OWNER ) ;
out :
mask = QLCRDX ( adapter - > ahw , QLCNIC_DEF_INT_MASK ) ;
writel ( 0 , adapter - > ahw - > pci_base0 + mask ) ;
spin_unlock ( & ahw - > mbx_lock ) ;
}
static int qlcnic_83xx_add_rings ( struct qlcnic_adapter * adapter )
{
int index , i , err , sds_mbx_size ;
u32 * buf , intrpt_id , intr_mask ;
u16 context_id ;
u8 num_sds ;
struct qlcnic_cmd_args cmd ;
struct qlcnic_host_sds_ring * sds ;
struct qlcnic_sds_mbx sds_mbx ;
struct qlcnic_add_rings_mbx_out * mbx_out ;
struct qlcnic_recv_context * recv_ctx = adapter - > recv_ctx ;
struct qlcnic_hardware_context * ahw = adapter - > ahw ;
sds_mbx_size = sizeof ( struct qlcnic_sds_mbx ) ;
context_id = recv_ctx - > context_id ;
num_sds = ( adapter - > max_sds_rings - QLCNIC_MAX_RING_SETS ) ;
ahw - > hw_ops - > alloc_mbx_args ( & cmd , adapter ,
QLCNIC_CMD_ADD_RCV_RINGS ) ;
cmd . req . arg [ 1 ] = 0 | ( num_sds < < 8 ) | ( context_id < < 16 ) ;
/* set up status rings, mbx 2-81 */
index = 2 ;
for ( i = 8 ; i < adapter - > max_sds_rings ; i + + ) {
memset ( & sds_mbx , 0 , sds_mbx_size ) ;
sds = & recv_ctx - > sds_rings [ i ] ;
sds - > consumer = 0 ;
memset ( sds - > desc_head , 0 , STATUS_DESC_RINGSIZE ( sds ) ) ;
sds_mbx . phy_addr = sds - > phys_addr ;
sds_mbx . sds_ring_size = sds - > num_desc ;
if ( adapter - > flags & QLCNIC_MSIX_ENABLED )
intrpt_id = ahw - > intr_tbl [ i ] . id ;
else
intrpt_id = QLCRDX ( ahw , QLCNIC_DEF_INT_ID ) ;
if ( adapter - > ahw - > diag_test ! = QLCNIC_LOOPBACK_TEST )
sds_mbx . intrpt_id = intrpt_id ;
else
sds_mbx . intrpt_id = 0xffff ;
sds_mbx . intrpt_val = 0 ;
buf = & cmd . req . arg [ index ] ;
memcpy ( buf , & sds_mbx , sds_mbx_size ) ;
index + = sds_mbx_size / sizeof ( u32 ) ;
}
/* send the mailbox command */
err = ahw - > hw_ops - > mbx_cmd ( adapter , & cmd ) ;
if ( err ) {
dev_err ( & adapter - > pdev - > dev ,
" Failed to add rings %d \n " , err ) ;
goto out ;
}
mbx_out = ( struct qlcnic_add_rings_mbx_out * ) & cmd . rsp . arg [ 1 ] ;
index = 0 ;
/* status descriptor ring */
for ( i = 8 ; i < adapter - > max_sds_rings ; i + + ) {
sds = & recv_ctx - > sds_rings [ i ] ;
sds - > crb_sts_consumer = ahw - > pci_base0 +
mbx_out - > host_csmr [ index ] ;
if ( adapter - > flags & QLCNIC_MSIX_ENABLED )
intr_mask = ahw - > intr_tbl [ i ] . src ;
else
intr_mask = QLCRDX ( ahw , QLCNIC_DEF_INT_MASK ) ;
sds - > crb_intr_mask = ahw - > pci_base0 + intr_mask ;
index + + ;
}
out :
qlcnic_free_mbx_args ( & cmd ) ;
return err ;
}
int qlcnic_83xx_create_rx_ctx ( struct qlcnic_adapter * adapter )
{
int i , err , index , sds_mbx_size , rds_mbx_size ;
u8 num_sds , num_rds ;
u32 * buf , intrpt_id , intr_mask , cap = 0 ;
struct qlcnic_host_sds_ring * sds ;
struct qlcnic_host_rds_ring * rds ;
struct qlcnic_sds_mbx sds_mbx ;
struct qlcnic_rds_mbx rds_mbx ;
struct qlcnic_cmd_args cmd ;
struct qlcnic_rcv_mbx_out * mbx_out ;
struct qlcnic_recv_context * recv_ctx = adapter - > recv_ctx ;
struct qlcnic_hardware_context * ahw = adapter - > ahw ;
num_rds = adapter - > max_rds_rings ;
if ( adapter - > max_sds_rings < = QLCNIC_MAX_RING_SETS )
num_sds = adapter - > max_sds_rings ;
else
num_sds = QLCNIC_MAX_RING_SETS ;
sds_mbx_size = sizeof ( struct qlcnic_sds_mbx ) ;
rds_mbx_size = sizeof ( struct qlcnic_rds_mbx ) ;
cap = QLCNIC_CAP0_LEGACY_CONTEXT ;
if ( adapter - > flags & QLCNIC_FW_LRO_MSS_CAP )
cap | = QLC_83XX_FW_CAP_LRO_MSS ;
/* set mailbox hdr and capabilities */
qlcnic_alloc_mbx_args ( & cmd , adapter ,
QLCNIC_CMD_CREATE_RX_CTX ) ;
cmd . req . arg [ 1 ] = cap ;
cmd . req . arg [ 5 ] = 1 | ( num_rds < < 5 ) | ( num_sds < < 8 ) |
( QLC_83XX_HOST_RDS_MODE_UNIQUE < < 16 ) ;
/* set up status rings, mbx 8-57/87 */
index = QLC_83XX_HOST_SDS_MBX_IDX ;
for ( i = 0 ; i < num_sds ; i + + ) {
memset ( & sds_mbx , 0 , sds_mbx_size ) ;
sds = & recv_ctx - > sds_rings [ i ] ;
sds - > consumer = 0 ;
memset ( sds - > desc_head , 0 , STATUS_DESC_RINGSIZE ( sds ) ) ;
sds_mbx . phy_addr = sds - > phys_addr ;
sds_mbx . sds_ring_size = sds - > num_desc ;
if ( adapter - > flags & QLCNIC_MSIX_ENABLED )
intrpt_id = ahw - > intr_tbl [ i ] . id ;
else
intrpt_id = QLCRDX ( ahw , QLCNIC_DEF_INT_ID ) ;
if ( adapter - > ahw - > diag_test ! = QLCNIC_LOOPBACK_TEST )
sds_mbx . intrpt_id = intrpt_id ;
else
sds_mbx . intrpt_id = 0xffff ;
sds_mbx . intrpt_val = 0 ;
buf = & cmd . req . arg [ index ] ;
memcpy ( buf , & sds_mbx , sds_mbx_size ) ;
index + = sds_mbx_size / sizeof ( u32 ) ;
}
/* set up receive rings, mbx 88-111/135 */
index = QLCNIC_HOST_RDS_MBX_IDX ;
rds = & recv_ctx - > rds_rings [ 0 ] ;
rds - > producer = 0 ;
memset ( & rds_mbx , 0 , rds_mbx_size ) ;
rds_mbx . phy_addr_reg = rds - > phys_addr ;
rds_mbx . reg_ring_sz = rds - > dma_size ;
rds_mbx . reg_ring_len = rds - > num_desc ;
/* Jumbo ring */
rds = & recv_ctx - > rds_rings [ 1 ] ;
rds - > producer = 0 ;
rds_mbx . phy_addr_jmb = rds - > phys_addr ;
rds_mbx . jmb_ring_sz = rds - > dma_size ;
rds_mbx . jmb_ring_len = rds - > num_desc ;
buf = & cmd . req . arg [ index ] ;
memcpy ( buf , & rds_mbx , rds_mbx_size ) ;
/* send the mailbox command */
err = ahw - > hw_ops - > mbx_cmd ( adapter , & cmd ) ;
if ( err ) {
dev_err ( & adapter - > pdev - > dev ,
" Failed to create Rx ctx in firmware%d \n " , err ) ;
goto out ;
}
mbx_out = ( struct qlcnic_rcv_mbx_out * ) & cmd . rsp . arg [ 1 ] ;
recv_ctx - > context_id = mbx_out - > ctx_id ;
recv_ctx - > state = mbx_out - > state ;
recv_ctx - > virt_port = mbx_out - > vport_id ;
dev_info ( & adapter - > pdev - > dev , " Rx Context[%d] Created, state:0x%x \n " ,
recv_ctx - > context_id , recv_ctx - > state ) ;
/* Receive descriptor ring */
/* Standard ring */
rds = & recv_ctx - > rds_rings [ 0 ] ;
rds - > crb_rcv_producer = ahw - > pci_base0 +
mbx_out - > host_prod [ 0 ] . reg_buf ;
/* Jumbo ring */
rds = & recv_ctx - > rds_rings [ 1 ] ;
rds - > crb_rcv_producer = ahw - > pci_base0 +
mbx_out - > host_prod [ 0 ] . jmb_buf ;
/* status descriptor ring */
for ( i = 0 ; i < num_sds ; i + + ) {
sds = & recv_ctx - > sds_rings [ i ] ;
sds - > crb_sts_consumer = ahw - > pci_base0 +
mbx_out - > host_csmr [ i ] ;
if ( adapter - > flags & QLCNIC_MSIX_ENABLED )
intr_mask = ahw - > intr_tbl [ i ] . src ;
else
intr_mask = QLCRDX ( ahw , QLCNIC_DEF_INT_MASK ) ;
sds - > crb_intr_mask = ahw - > pci_base0 + intr_mask ;
}
if ( adapter - > max_sds_rings > QLCNIC_MAX_RING_SETS )
err = qlcnic_83xx_add_rings ( adapter ) ;
out :
qlcnic_free_mbx_args ( & cmd ) ;
return err ;
}
int qlcnic_83xx_create_tx_ctx ( struct qlcnic_adapter * adapter ,
struct qlcnic_host_tx_ring * tx , int ring )
{
int err ;
u16 msix_id ;
u32 * buf , intr_mask ;
struct qlcnic_cmd_args cmd ;
struct qlcnic_tx_mbx mbx ;
struct qlcnic_tx_mbx_out * mbx_out ;
struct qlcnic_hardware_context * ahw = adapter - > ahw ;
/* Reset host resources */
tx - > producer = 0 ;
tx - > sw_consumer = 0 ;
* ( tx - > hw_consumer ) = 0 ;
memset ( & mbx , 0 , sizeof ( struct qlcnic_tx_mbx ) ) ;
/* setup mailbox inbox registerss */
mbx . phys_addr = tx - > phys_addr ;
mbx . cnsmr_index = tx - > hw_cons_phys_addr ;
mbx . size = tx - > num_desc ;
if ( adapter - > flags & QLCNIC_MSIX_ENABLED )
msix_id = ahw - > intr_tbl [ adapter - > max_sds_rings + ring ] . id ;
else
msix_id = QLCRDX ( ahw , QLCNIC_DEF_INT_ID ) ;
if ( adapter - > ahw - > diag_test ! = QLCNIC_LOOPBACK_TEST )
mbx . intr_id = msix_id ;
else
mbx . intr_id = 0xffff ;
mbx . src = 0 ;
qlcnic_alloc_mbx_args ( & cmd , adapter , QLCNIC_CMD_CREATE_TX_CTX ) ;
cmd . req . arg [ 1 ] = QLCNIC_CAP0_LEGACY_CONTEXT ;
cmd . req . arg [ 5 ] = QLCNIC_MAX_TX_QUEUES ;
buf = & cmd . req . arg [ 6 ] ;
memcpy ( buf , & mbx , sizeof ( struct qlcnic_tx_mbx ) ) ;
/* send the mailbox command*/
err = qlcnic_issue_cmd ( adapter , & cmd ) ;
if ( err ) {
dev_err ( & adapter - > pdev - > dev ,
" Failed to create Tx ctx in firmware 0x%x \n " , err ) ;
goto out ;
}
mbx_out = ( struct qlcnic_tx_mbx_out * ) & cmd . rsp . arg [ 2 ] ;
tx - > crb_cmd_producer = ahw - > pci_base0 + mbx_out - > host_prod ;
tx - > ctx_id = mbx_out - > ctx_id ;
if ( adapter - > flags & QLCNIC_MSIX_ENABLED ) {
intr_mask = ahw - > intr_tbl [ adapter - > max_sds_rings + ring ] . src ;
tx - > crb_intr_mask = ahw - > pci_base0 + intr_mask ;
}
dev_info ( & adapter - > pdev - > dev , " Tx Context[0x%x] Created, state:0x%x \n " ,
tx - > ctx_id , mbx_out - > state ) ;
out :
qlcnic_free_mbx_args ( & cmd ) ;
return err ;
}
2013-01-01 03:20:22 +00:00
int qlcnic_83xx_config_led ( struct qlcnic_adapter * adapter , u32 state ,
u32 beacon )
{
struct qlcnic_cmd_args cmd ;
u32 mbx_in ;
int i , status = 0 ;
if ( state ) {
/* Get LED configuration */
qlcnic_alloc_mbx_args ( & cmd , adapter ,
QLCNIC_CMD_GET_LED_CONFIG ) ;
status = qlcnic_issue_cmd ( adapter , & cmd ) ;
if ( status ) {
dev_err ( & adapter - > pdev - > dev ,
" Get led config failed. \n " ) ;
goto mbx_err ;
} else {
for ( i = 0 ; i < 4 ; i + + )
adapter - > ahw - > mbox_reg [ i ] = cmd . rsp . arg [ i + 1 ] ;
}
qlcnic_free_mbx_args ( & cmd ) ;
/* Set LED Configuration */
mbx_in = ( LSW ( QLC_83XX_LED_CONFIG ) < < 16 ) |
LSW ( QLC_83XX_LED_CONFIG ) ;
qlcnic_alloc_mbx_args ( & cmd , adapter ,
QLCNIC_CMD_SET_LED_CONFIG ) ;
cmd . req . arg [ 1 ] = mbx_in ;
cmd . req . arg [ 2 ] = mbx_in ;
cmd . req . arg [ 3 ] = mbx_in ;
if ( beacon )
cmd . req . arg [ 4 ] = QLC_83XX_ENABLE_BEACON ;
status = qlcnic_issue_cmd ( adapter , & cmd ) ;
if ( status ) {
dev_err ( & adapter - > pdev - > dev ,
" Set led config failed. \n " ) ;
}
mbx_err :
qlcnic_free_mbx_args ( & cmd ) ;
return status ;
} else {
/* Restoring default LED configuration */
qlcnic_alloc_mbx_args ( & cmd , adapter ,
QLCNIC_CMD_SET_LED_CONFIG ) ;
cmd . req . arg [ 1 ] = adapter - > ahw - > mbox_reg [ 0 ] ;
cmd . req . arg [ 2 ] = adapter - > ahw - > mbox_reg [ 1 ] ;
cmd . req . arg [ 3 ] = adapter - > ahw - > mbox_reg [ 2 ] ;
if ( beacon )
cmd . req . arg [ 4 ] = adapter - > ahw - > mbox_reg [ 3 ] ;
status = qlcnic_issue_cmd ( adapter , & cmd ) ;
if ( status )
dev_err ( & adapter - > pdev - > dev ,
" Restoring led config failed. \n " ) ;
qlcnic_free_mbx_args ( & cmd ) ;
return status ;
}
}
2013-01-01 03:20:19 +00:00
void qlcnic_83xx_register_nic_idc_func ( struct qlcnic_adapter * adapter ,
int enable )
{
struct qlcnic_cmd_args cmd ;
int status ;
if ( enable ) {
qlcnic_alloc_mbx_args ( & cmd , adapter , QLCNIC_CMD_INIT_NIC_FUNC ) ;
cmd . req . arg [ 1 ] = 1 | BIT_0 ;
} else {
qlcnic_alloc_mbx_args ( & cmd , adapter , QLCNIC_CMD_STOP_NIC_FUNC ) ;
cmd . req . arg [ 1 ] = 0 | BIT_0 ;
}
status = qlcnic_issue_cmd ( adapter , & cmd ) ;
if ( status )
dev_err ( & adapter - > pdev - > dev ,
" Failed to %s in NIC IDC function event. \n " ,
( enable ? " register " : " unregister " ) ) ;
qlcnic_free_mbx_args ( & cmd ) ;
}
int qlcnic_83xx_set_port_config ( struct qlcnic_adapter * adapter )
{
struct qlcnic_cmd_args cmd ;
int err ;
qlcnic_alloc_mbx_args ( & cmd , adapter , QLCNIC_CMD_SET_PORT_CONFIG ) ;
cmd . req . arg [ 1 ] = adapter - > ahw - > port_config ;
err = qlcnic_issue_cmd ( adapter , & cmd ) ;
if ( err )
dev_info ( & adapter - > pdev - > dev , " Set Port Config failed. \n " ) ;
qlcnic_free_mbx_args ( & cmd ) ;
return err ;
}
int qlcnic_83xx_get_port_config ( struct qlcnic_adapter * adapter )
{
struct qlcnic_cmd_args cmd ;
int err ;
qlcnic_alloc_mbx_args ( & cmd , adapter , QLCNIC_CMD_GET_PORT_CONFIG ) ;
err = qlcnic_issue_cmd ( adapter , & cmd ) ;
if ( err )
dev_info ( & adapter - > pdev - > dev , " Get Port config failed \n " ) ;
else
adapter - > ahw - > port_config = cmd . rsp . arg [ 1 ] ;
qlcnic_free_mbx_args ( & cmd ) ;
return err ;
}
int qlcnic_83xx_setup_link_event ( struct qlcnic_adapter * adapter , int enable )
{
int err ;
u32 temp ;
struct qlcnic_cmd_args cmd ;
qlcnic_alloc_mbx_args ( & cmd , adapter , QLCNIC_CMD_GET_LINK_EVENT ) ;
temp = adapter - > recv_ctx - > context_id < < 16 ;
cmd . req . arg [ 1 ] = ( enable ? 1 : 0 ) | BIT_8 | temp ;
err = qlcnic_issue_cmd ( adapter , & cmd ) ;
if ( err )
dev_info ( & adapter - > pdev - > dev ,
" Setup linkevent mailbox failed \n " ) ;
qlcnic_free_mbx_args ( & cmd ) ;
return err ;
}
int qlcnic_83xx_nic_set_promisc ( struct qlcnic_adapter * adapter , u32 mode )
{
int err ;
u32 temp ;
struct qlcnic_cmd_args cmd ;
if ( adapter - > recv_ctx - > state = = QLCNIC_HOST_CTX_STATE_FREED )
return - EIO ;
qlcnic_alloc_mbx_args ( & cmd , adapter , QLCNIC_CMD_CONFIGURE_MAC_RX_MODE ) ;
temp = adapter - > recv_ctx - > context_id < < 16 ;
cmd . req . arg [ 1 ] = ( mode ? 1 : 0 ) | temp ;
err = qlcnic_issue_cmd ( adapter , & cmd ) ;
if ( err )
dev_info ( & adapter - > pdev - > dev ,
" Promiscous mode config failed \n " ) ;
qlcnic_free_mbx_args ( & cmd ) ;
return err ;
}
int qlcnic_83xx_set_lb_mode ( struct qlcnic_adapter * adapter , u8 mode )
{
struct qlcnic_hardware_context * ahw = adapter - > ahw ;
int status = 0 ;
u32 config ;
status = qlcnic_83xx_get_port_config ( adapter ) ;
if ( status )
return status ;
config = ahw - > port_config ;
if ( mode = = QLCNIC_ILB_MODE )
ahw - > port_config | = QLC_83XX_CFG_LOOPBACK_HSS ;
if ( mode = = QLCNIC_ELB_MODE )
ahw - > port_config | = QLC_83XX_CFG_LOOPBACK_EXT ;
status = qlcnic_83xx_set_port_config ( adapter ) ;
if ( status ) {
dev_err ( & adapter - > pdev - > dev ,
" Failed to Set Loopback Mode = 0x%x. \n " ,
ahw - > port_config ) ;
ahw - > port_config = config ;
return status ;
}
qlcnic_sre_macaddr_change ( adapter , adapter - > mac_addr , 0 ,
QLCNIC_MAC_ADD ) ;
return status ;
}
int qlcnic_83xx_clear_lb_mode ( struct qlcnic_adapter * adapter , u8 mode )
{
struct qlcnic_hardware_context * ahw = adapter - > ahw ;
int status = 0 ;
u32 config = ahw - > port_config ;
if ( mode = = QLCNIC_ILB_MODE )
ahw - > port_config & = ~ QLC_83XX_CFG_LOOPBACK_HSS ;
if ( mode = = QLCNIC_ELB_MODE )
ahw - > port_config & = ~ QLC_83XX_CFG_LOOPBACK_EXT ;
status = qlcnic_83xx_set_port_config ( adapter ) ;
if ( status ) {
dev_err ( & adapter - > pdev - > dev ,
" Failed to Clear Loopback Mode = 0x%x. \n " ,
ahw - > port_config ) ;
ahw - > port_config = config ;
return status ;
}
qlcnic_sre_macaddr_change ( adapter , adapter - > mac_addr , 0 ,
QLCNIC_MAC_DEL ) ;
return status ;
}
void qlcnic_83xx_config_ipaddr ( struct qlcnic_adapter * adapter , __be32 ip ,
int mode )
{
int err ;
u32 temp ;
struct qlcnic_cmd_args cmd ;
qlcnic_alloc_mbx_args ( & cmd , adapter , QLCNIC_CMD_CONFIGURE_IP_ADDR ) ;
if ( mode = = QLCNIC_IP_UP ) {
temp = adapter - > recv_ctx - > context_id < < 16 ;
cmd . req . arg [ 1 ] = 1 | temp ;
} else {
temp = adapter - > recv_ctx - > context_id < < 16 ;
cmd . req . arg [ 1 ] = 2 | temp ;
}
cmd . req . arg [ 2 ] = ntohl ( ip ) ;
err = qlcnic_issue_cmd ( adapter , & cmd ) ;
if ( err ! = QLCNIC_RCODE_SUCCESS )
dev_err ( & adapter - > netdev - > dev ,
" could not notify %s IP 0x%x request \n " ,
( mode = = QLCNIC_IP_UP ) ? " Add " : " Remove " , ip ) ;
qlcnic_free_mbx_args ( & cmd ) ;
}
int qlcnic_83xx_config_hw_lro ( struct qlcnic_adapter * adapter , int mode )
{
int err ;
u32 temp , arg1 ;
struct qlcnic_cmd_args cmd ;
if ( adapter - > recv_ctx - > state = = QLCNIC_HOST_CTX_STATE_FREED )
return 0 ;
qlcnic_alloc_mbx_args ( & cmd , adapter , QLCNIC_CMD_CONFIGURE_HW_LRO ) ;
temp = adapter - > recv_ctx - > context_id < < 16 ;
arg1 = ( mode ? ( BIT_0 | BIT_1 | BIT_3 ) : 0 ) | temp ;
cmd . req . arg [ 1 ] = arg1 ;
err = qlcnic_issue_cmd ( adapter , & cmd ) ;
if ( err )
dev_info ( & adapter - > pdev - > dev , " LRO config failed \n " ) ;
qlcnic_free_mbx_args ( & cmd ) ;
return err ;
}
int qlcnic_83xx_config_rss ( struct qlcnic_adapter * adapter , int enable )
{
int err ;
u32 word ;
struct qlcnic_cmd_args cmd ;
const u64 key [ ] = { 0xbeac01fa6a42b73bULL , 0x8030f20c77cb2da3ULL ,
0xae7b30b4d0ca2bcbULL , 0x43a38fb04167253dULL ,
0x255b0ec26d5a56daULL } ;
qlcnic_alloc_mbx_args ( & cmd , adapter , QLCNIC_CMD_CONFIGURE_RSS ) ;
/*
* RSS request :
* bits 3 - 0 : Rsvd
* 5 - 4 : hash_type_ipv4
* 7 - 6 : hash_type_ipv6
* 8 : enable
* 9 : use indirection table
* 16 - 31 : indirection table mask
*/
word = ( ( u32 ) ( RSS_HASHTYPE_IP_TCP & 0x3 ) < < 4 ) |
( ( u32 ) ( RSS_HASHTYPE_IP_TCP & 0x3 ) < < 6 ) |
( ( u32 ) ( enable & 0x1 ) < < 8 ) |
( ( 0x7ULL ) < < 16 ) ;
cmd . req . arg [ 1 ] = ( adapter - > recv_ctx - > context_id ) ;
cmd . req . arg [ 2 ] = word ;
memcpy ( & cmd . req . arg [ 4 ] , key , sizeof ( key ) ) ;
err = qlcnic_issue_cmd ( adapter , & cmd ) ;
if ( err )
dev_info ( & adapter - > pdev - > dev , " RSS config failed \n " ) ;
qlcnic_free_mbx_args ( & cmd ) ;
return err ;
}
int qlcnic_83xx_sre_macaddr_change ( struct qlcnic_adapter * adapter , u8 * addr ,
__le16 vlan_id , u8 op )
{
int err ;
u32 * buf ;
struct qlcnic_cmd_args cmd ;
struct qlcnic_macvlan_mbx mv ;
if ( adapter - > recv_ctx - > state = = QLCNIC_HOST_CTX_STATE_FREED )
return - EIO ;
err = qlcnic_alloc_mbx_args ( & cmd , adapter , QLCNIC_CMD_CONFIG_MAC_VLAN ) ;
if ( err )
return err ;
cmd . req . arg [ 1 ] = op | ( 1 < < 8 ) |
( adapter - > recv_ctx - > context_id < < 16 ) ;
mv . vlan = le16_to_cpu ( vlan_id ) ;
memcpy ( & mv . mac , addr , ETH_ALEN ) ;
buf = & cmd . req . arg [ 2 ] ;
memcpy ( buf , & mv , sizeof ( struct qlcnic_macvlan_mbx ) ) ;
err = qlcnic_issue_cmd ( adapter , & cmd ) ;
if ( err )
dev_err ( & adapter - > pdev - > dev ,
" MAC-VLAN %s to CAM failed, err=%d. \n " ,
( ( op = = 1 ) ? " add " : " delete " ) , err ) ;
qlcnic_free_mbx_args ( & cmd ) ;
return err ;
}
void qlcnic_83xx_change_l2_filter ( struct qlcnic_adapter * adapter , u64 * addr ,
__le16 vlan_id )
{
u8 mac [ ETH_ALEN ] ;
memcpy ( & mac , addr , ETH_ALEN ) ;
qlcnic_83xx_sre_macaddr_change ( adapter , mac , vlan_id , QLCNIC_MAC_ADD ) ;
}
void qlcnic_83xx_configure_mac ( struct qlcnic_adapter * adapter , u8 * mac ,
u8 type , struct qlcnic_cmd_args * cmd )
{
switch ( type ) {
case QLCNIC_SET_STATION_MAC :
case QLCNIC_SET_FAC_DEF_MAC :
memcpy ( & cmd - > req . arg [ 2 ] , mac , sizeof ( u32 ) ) ;
memcpy ( & cmd - > req . arg [ 3 ] , & mac [ 4 ] , sizeof ( u16 ) ) ;
break ;
}
cmd - > req . arg [ 1 ] = type ;
}
int qlcnic_83xx_get_mac_address ( struct qlcnic_adapter * adapter , u8 * mac )
{
int err , i ;
struct qlcnic_cmd_args cmd ;
u32 mac_low , mac_high ;
qlcnic_alloc_mbx_args ( & cmd , adapter , QLCNIC_CMD_MAC_ADDRESS ) ;
qlcnic_83xx_configure_mac ( adapter , mac , QLCNIC_GET_CURRENT_MAC , & cmd ) ;
err = qlcnic_issue_cmd ( adapter , & cmd ) ;
if ( err = = QLCNIC_RCODE_SUCCESS ) {
mac_low = cmd . rsp . arg [ 1 ] ;
mac_high = cmd . rsp . arg [ 2 ] ;
for ( i = 0 ; i < 2 ; i + + )
mac [ i ] = ( u8 ) ( mac_high > > ( ( 1 - i ) * 8 ) ) ;
for ( i = 2 ; i < 6 ; i + + )
mac [ i ] = ( u8 ) ( mac_low > > ( ( 5 - i ) * 8 ) ) ;
} else {
dev_err ( & adapter - > pdev - > dev , " Failed to get mac address%d \n " ,
err ) ;
err = - EIO ;
}
qlcnic_free_mbx_args ( & cmd ) ;
return err ;
}
void qlcnic_83xx_config_intr_coal ( struct qlcnic_adapter * adapter )
{
int err ;
u32 temp ;
struct qlcnic_cmd_args cmd ;
struct qlcnic_nic_intr_coalesce * coal = & adapter - > ahw - > coal ;
if ( adapter - > recv_ctx - > state = = QLCNIC_HOST_CTX_STATE_FREED )
return ;
qlcnic_alloc_mbx_args ( & cmd , adapter , QLCNIC_CMD_CONFIG_INTR_COAL ) ;
cmd . req . arg [ 1 ] = 1 | ( adapter - > recv_ctx - > context_id < < 16 ) ;
cmd . req . arg [ 3 ] = coal - > flag ;
temp = coal - > rx_time_us < < 16 ;
cmd . req . arg [ 2 ] = coal - > rx_packets | temp ;
err = qlcnic_issue_cmd ( adapter , & cmd ) ;
if ( err ! = QLCNIC_RCODE_SUCCESS )
dev_info ( & adapter - > pdev - > dev ,
" Failed to send interrupt coalescence parameters \n " ) ;
qlcnic_free_mbx_args ( & cmd ) ;
}
static void qlcnic_83xx_handle_link_aen ( struct qlcnic_adapter * adapter ,
u32 data [ ] )
{
u8 link_status , duplex ;
/* link speed */
link_status = LSB ( data [ 3 ] ) & 1 ;
adapter - > ahw - > link_speed = MSW ( data [ 2 ] ) ;
adapter - > ahw - > link_autoneg = MSB ( MSW ( data [ 3 ] ) ) ;
adapter - > ahw - > module_type = MSB ( LSW ( data [ 3 ] ) ) ;
duplex = LSB ( MSW ( data [ 3 ] ) ) ;
if ( duplex )
adapter - > ahw - > link_duplex = DUPLEX_FULL ;
else
adapter - > ahw - > link_duplex = DUPLEX_HALF ;
adapter - > ahw - > has_link_events = 1 ;
qlcnic_advert_link_change ( adapter , link_status ) ;
}
irqreturn_t qlcnic_83xx_handle_aen ( int irq , void * data )
{
struct qlcnic_adapter * adapter = data ;
qlcnic_83xx_process_aen ( adapter ) ;
return IRQ_HANDLED ;
}
int qlcnic_enable_eswitch ( struct qlcnic_adapter * adapter , u8 port , u8 enable )
{
int err = - EIO ;
struct qlcnic_cmd_args cmd ;
if ( adapter - > ahw - > op_mode ! = QLCNIC_MGMT_FUNC ) {
dev_err ( & adapter - > pdev - > dev ,
" %s: Error, invoked by non management func \n " ,
__func__ ) ;
return err ;
}
qlcnic_alloc_mbx_args ( & cmd , adapter , QLCNIC_CMD_TOGGLE_ESWITCH ) ;
cmd . req . arg [ 1 ] = ( port & 0xf ) | BIT_4 ;
err = qlcnic_issue_cmd ( adapter , & cmd ) ;
if ( err ! = QLCNIC_RCODE_SUCCESS ) {
dev_err ( & adapter - > pdev - > dev , " Failed to enable eswitch%d \n " ,
err ) ;
err = - EIO ;
}
qlcnic_free_mbx_args ( & cmd ) ;
return err ;
}
int qlcnic_83xx_set_nic_info ( struct qlcnic_adapter * adapter ,
struct qlcnic_info * nic )
{
int i , err = - EIO ;
struct qlcnic_cmd_args cmd ;
if ( adapter - > ahw - > op_mode ! = QLCNIC_MGMT_FUNC ) {
dev_err ( & adapter - > pdev - > dev ,
" %s: Error, invoked by non management func \n " ,
__func__ ) ;
return err ;
}
qlcnic_alloc_mbx_args ( & cmd , adapter , QLCNIC_CMD_SET_NIC_INFO ) ;
cmd . req . arg [ 1 ] = ( nic - > pci_func < < 16 ) ;
cmd . req . arg [ 2 ] = 0x1 < < 16 ;
cmd . req . arg [ 3 ] = nic - > phys_port | ( nic - > switch_mode < < 16 ) ;
cmd . req . arg [ 4 ] = nic - > capabilities ;
cmd . req . arg [ 5 ] = ( nic - > max_mac_filters & 0xFF ) | ( ( nic - > max_mtu ) < < 16 ) ;
cmd . req . arg [ 6 ] = ( nic - > max_tx_ques ) | ( ( nic - > max_rx_ques ) < < 16 ) ;
cmd . req . arg [ 7 ] = ( nic - > min_tx_bw ) | ( ( nic - > max_tx_bw ) < < 16 ) ;
for ( i = 8 ; i < 32 ; i + + )
cmd . req . arg [ i ] = 0 ;
err = qlcnic_issue_cmd ( adapter , & cmd ) ;
if ( err ! = QLCNIC_RCODE_SUCCESS ) {
dev_err ( & adapter - > pdev - > dev , " Failed to set nic info%d \n " ,
err ) ;
err = - EIO ;
}
qlcnic_free_mbx_args ( & cmd ) ;
return err ;
}
int qlcnic_83xx_get_nic_info ( struct qlcnic_adapter * adapter ,
struct qlcnic_info * npar_info , u8 func_id )
{
int err ;
u32 temp ;
u8 op = 0 ;
struct qlcnic_cmd_args cmd ;
qlcnic_alloc_mbx_args ( & cmd , adapter , QLCNIC_CMD_GET_NIC_INFO ) ;
if ( func_id ! = adapter - > ahw - > pci_func ) {
temp = func_id < < 16 ;
cmd . req . arg [ 1 ] = op | BIT_31 | temp ;
} else {
cmd . req . arg [ 1 ] = adapter - > ahw - > pci_func < < 16 ;
}
err = qlcnic_issue_cmd ( adapter , & cmd ) ;
if ( err ) {
dev_info ( & adapter - > pdev - > dev ,
" Failed to get nic info %d \n " , err ) ;
goto out ;
}
npar_info - > op_type = cmd . rsp . arg [ 1 ] ;
npar_info - > pci_func = cmd . rsp . arg [ 2 ] & 0xFFFF ;
npar_info - > op_mode = ( cmd . rsp . arg [ 2 ] & 0xFFFF0000 ) > > 16 ;
npar_info - > phys_port = cmd . rsp . arg [ 3 ] & 0xFFFF ;
npar_info - > switch_mode = ( cmd . rsp . arg [ 3 ] & 0xFFFF0000 ) > > 16 ;
npar_info - > capabilities = cmd . rsp . arg [ 4 ] ;
npar_info - > max_mac_filters = cmd . rsp . arg [ 5 ] & 0xFF ;
npar_info - > max_mtu = ( cmd . rsp . arg [ 5 ] & 0xFFFF0000 ) > > 16 ;
npar_info - > max_tx_ques = cmd . rsp . arg [ 6 ] & 0xFFFF ;
npar_info - > max_rx_ques = ( cmd . rsp . arg [ 6 ] & 0xFFFF0000 ) > > 16 ;
npar_info - > min_tx_bw = cmd . rsp . arg [ 7 ] & 0xFFFF ;
npar_info - > max_tx_bw = ( cmd . rsp . arg [ 7 ] & 0xFFFF0000 ) > > 16 ;
if ( cmd . rsp . arg [ 8 ] & 0x1 )
npar_info - > max_bw_reg_offset = ( cmd . rsp . arg [ 8 ] & 0x7FFE ) > > 1 ;
if ( cmd . rsp . arg [ 8 ] & 0x10000 ) {
temp = ( cmd . rsp . arg [ 8 ] & 0x7FFE0000 ) > > 17 ;
npar_info - > max_linkspeed_reg_offset = temp ;
}
out :
qlcnic_free_mbx_args ( & cmd ) ;
return err ;
}
int qlcnic_83xx_get_pci_info ( struct qlcnic_adapter * adapter ,
struct qlcnic_pci_info * pci_info )
{
int i , err = 0 , j = 0 ;
u32 temp ;
struct qlcnic_cmd_args cmd ;
qlcnic_alloc_mbx_args ( & cmd , adapter , QLCNIC_CMD_GET_PCI_INFO ) ;
err = qlcnic_issue_cmd ( adapter , & cmd ) ;
adapter - > ahw - > act_pci_func = 0 ;
if ( err = = QLCNIC_RCODE_SUCCESS ) {
pci_info - > func_count = cmd . rsp . arg [ 1 ] & 0xFF ;
dev_info ( & adapter - > pdev - > dev ,
" %s: total functions = %d \n " ,
__func__ , pci_info - > func_count ) ;
for ( i = 2 , j = 0 ; j < QLCNIC_MAX_PCI_FUNC ; j + + , pci_info + + ) {
pci_info - > id = cmd . rsp . arg [ i ] & 0xFFFF ;
pci_info - > active = ( cmd . rsp . arg [ i ] & 0xFFFF0000 ) > > 16 ;
i + + ;
pci_info - > type = cmd . rsp . arg [ i ] & 0xFFFF ;
if ( pci_info - > type = = QLCNIC_TYPE_NIC )
adapter - > ahw - > act_pci_func + + ;
temp = ( cmd . rsp . arg [ i ] & 0xFFFF0000 ) > > 16 ;
pci_info - > default_port = temp ;
i + + ;
pci_info - > tx_min_bw = cmd . rsp . arg [ i ] & 0xFFFF ;
temp = ( cmd . rsp . arg [ i ] & 0xFFFF0000 ) > > 16 ;
pci_info - > tx_max_bw = temp ;
i = i + 2 ;
memcpy ( pci_info - > mac , & cmd . rsp . arg [ i ] , ETH_ALEN - 2 ) ;
i + + ;
memcpy ( pci_info - > mac + sizeof ( u32 ) , & cmd . rsp . arg [ i ] , 2 ) ;
i = i + 3 ;
dev_info ( & adapter - > pdev - > dev , " %s: \n "
" \t id = %d active = %d type = %d \n "
" \t port = %d min bw = %d max bw = %d \n "
" \t mac_addr = %pM \n " , __func__ ,
pci_info - > id , pci_info - > active , pci_info - > type ,
pci_info - > default_port , pci_info - > tx_min_bw ,
pci_info - > tx_max_bw , pci_info - > mac ) ;
}
} else {
dev_err ( & adapter - > pdev - > dev , " Failed to get PCI Info%d \n " ,
err ) ;
err = - EIO ;
}
qlcnic_free_mbx_args ( & cmd ) ;
return err ;
}
int qlcnic_83xx_config_intrpt ( struct qlcnic_adapter * adapter , bool op_type )
{
int i , index , err ;
bool type ;
u8 max_ints ;
u32 val , temp ;
struct qlcnic_cmd_args cmd ;
max_ints = adapter - > ahw - > num_msix ;
qlcnic_alloc_mbx_args ( & cmd , adapter , QLCNIC_CMD_CONFIG_INTRPT ) ;
cmd . req . arg [ 1 ] = max_ints ;
for ( i = 0 , index = 2 ; i < max_ints ; i + + ) {
type = op_type ? QLCNIC_INTRPT_ADD : QLCNIC_INTRPT_DEL ;
val = type | ( adapter - > ahw - > intr_tbl [ i ] . type < < 4 ) ;
if ( adapter - > ahw - > intr_tbl [ i ] . type = = QLCNIC_INTRPT_MSIX )
val | = ( adapter - > ahw - > intr_tbl [ i ] . id < < 16 ) ;
cmd . req . arg [ index + + ] = val ;
}
err = qlcnic_issue_cmd ( adapter , & cmd ) ;
if ( err ) {
dev_err ( & adapter - > pdev - > dev ,
" Failed to configure interrupts 0x%x \n " , err ) ;
goto out ;
}
max_ints = cmd . rsp . arg [ 1 ] ;
for ( i = 0 , index = 2 ; i < max_ints ; i + + , index + = 2 ) {
val = cmd . rsp . arg [ index ] ;
if ( LSB ( val ) ) {
dev_info ( & adapter - > pdev - > dev ,
" Can't configure interrupt %d \n " ,
adapter - > ahw - > intr_tbl [ i ] . id ) ;
continue ;
}
if ( op_type ) {
adapter - > ahw - > intr_tbl [ i ] . id = MSW ( val ) ;
adapter - > ahw - > intr_tbl [ i ] . enabled = 1 ;
temp = cmd . rsp . arg [ index + 1 ] ;
adapter - > ahw - > intr_tbl [ i ] . src = temp ;
} else {
adapter - > ahw - > intr_tbl [ i ] . id = i ;
adapter - > ahw - > intr_tbl [ i ] . enabled = 0 ;
adapter - > ahw - > intr_tbl [ i ] . src = 0 ;
}
}
out :
qlcnic_free_mbx_args ( & cmd ) ;
return err ;
}
2013-01-01 03:20:23 +00:00
int qlcnic_83xx_lock_flash ( struct qlcnic_adapter * adapter )
{
int id , timeout = 0 ;
u32 status = 0 ;
while ( status = = 0 ) {
status = QLC_SHARED_REG_RD32 ( adapter , QLCNIC_FLASH_LOCK ) ;
if ( status )
break ;
if ( + + timeout > = QLC_83XX_FLASH_LOCK_TIMEOUT ) {
id = QLC_SHARED_REG_RD32 ( adapter ,
QLCNIC_FLASH_LOCK_OWNER ) ;
dev_err ( & adapter - > pdev - > dev ,
" %s: failed, lock held by %d \n " , __func__ , id ) ;
return - EIO ;
}
usleep_range ( 1000 , 2000 ) ;
}
QLC_SHARED_REG_WR32 ( adapter , QLCNIC_FLASH_LOCK_OWNER , adapter - > portnum ) ;
return 0 ;
}
void qlcnic_83xx_unlock_flash ( struct qlcnic_adapter * adapter )
{
QLC_SHARED_REG_RD32 ( adapter , QLCNIC_FLASH_UNLOCK ) ;
QLC_SHARED_REG_WR32 ( adapter , QLCNIC_FLASH_LOCK_OWNER , 0xFF ) ;
}
static int qlcnic_83xx_lockless_flash_read32 ( struct qlcnic_adapter * adapter ,
u32 flash_addr , u8 * p_data ,
int count )
{
int i , ret ;
u32 word , range , flash_offset , addr = flash_addr ;
ulong indirect_add , direct_window ;
flash_offset = addr & ( QLCNIC_FLASH_SECTOR_SIZE - 1 ) ;
if ( addr & 0x3 ) {
dev_err ( & adapter - > pdev - > dev , " Illegal addr = 0x%x \n " , addr ) ;
return - EIO ;
}
qlcnic_83xx_wrt_reg_indirect ( adapter , QLC_83XX_FLASH_DIRECT_WINDOW ,
( addr ) ) ;
range = flash_offset + ( count * sizeof ( u32 ) ) ;
/* Check if data is spread across multiple sectors */
if ( range > ( QLCNIC_FLASH_SECTOR_SIZE - 1 ) ) {
/* Multi sector read */
for ( i = 0 ; i < count ; i + + ) {
indirect_add = QLC_83XX_FLASH_DIRECT_DATA ( addr ) ;
ret = qlcnic_83xx_rd_reg_indirect ( adapter ,
indirect_add ) ;
if ( ret = = - EIO )
return - EIO ;
word = ret ;
* ( u32 * ) p_data = word ;
p_data = p_data + 4 ;
addr = addr + 4 ;
flash_offset = flash_offset + 4 ;
if ( flash_offset > ( QLCNIC_FLASH_SECTOR_SIZE - 1 ) ) {
direct_window = QLC_83XX_FLASH_DIRECT_WINDOW ;
/* This write is needed once for each sector */
qlcnic_83xx_wrt_reg_indirect ( adapter ,
direct_window ,
( addr ) ) ;
flash_offset = 0 ;
}
}
} else {
/* Single sector read */
for ( i = 0 ; i < count ; i + + ) {
indirect_add = QLC_83XX_FLASH_DIRECT_DATA ( addr ) ;
ret = qlcnic_83xx_rd_reg_indirect ( adapter ,
indirect_add ) ;
if ( ret = = - EIO )
return - EIO ;
word = ret ;
* ( u32 * ) p_data = word ;
p_data = p_data + 4 ;
addr = addr + 4 ;
}
}
return 0 ;
}
static int qlcnic_83xx_poll_flash_status_reg ( struct qlcnic_adapter * adapter )
{
u32 status ;
int retries = QLC_83XX_FLASH_READ_RETRY_COUNT ;
do {
status = qlcnic_83xx_rd_reg_indirect ( adapter ,
QLC_83XX_FLASH_STATUS ) ;
if ( ( status & QLC_83XX_FLASH_STATUS_READY ) = =
QLC_83XX_FLASH_STATUS_READY )
break ;
msleep ( QLC_83XX_FLASH_STATUS_REG_POLL_DELAY ) ;
} while ( - - retries ) ;
if ( ! retries )
return - EIO ;
return 0 ;
}
static int qlcnic_83xx_enable_flash_write_op ( struct qlcnic_adapter * adapter )
{
int ret ;
u32 cmd ;
cmd = adapter - > ahw - > fdt . write_statusreg_cmd ;
qlcnic_83xx_wrt_reg_indirect ( adapter , QLC_83XX_FLASH_ADDR ,
( QLC_83XX_FLASH_FDT_WRITE_DEF_SIG | cmd ) ) ;
qlcnic_83xx_wrt_reg_indirect ( adapter , QLC_83XX_FLASH_WRDATA ,
adapter - > ahw - > fdt . write_enable_bits ) ;
qlcnic_83xx_wrt_reg_indirect ( adapter , QLC_83XX_FLASH_CONTROL ,
QLC_83XX_FLASH_SECOND_ERASE_MS_VAL ) ;
ret = qlcnic_83xx_poll_flash_status_reg ( adapter ) ;
if ( ret )
return - EIO ;
return 0 ;
}
static int qlcnic_83xx_disable_flash_write_op ( struct qlcnic_adapter * adapter )
{
int ret ;
qlcnic_83xx_wrt_reg_indirect ( adapter , QLC_83XX_FLASH_ADDR ,
( QLC_83XX_FLASH_FDT_WRITE_DEF_SIG |
adapter - > ahw - > fdt . write_statusreg_cmd ) ) ;
qlcnic_83xx_wrt_reg_indirect ( adapter , QLC_83XX_FLASH_WRDATA ,
adapter - > ahw - > fdt . write_disable_bits ) ;
qlcnic_83xx_wrt_reg_indirect ( adapter , QLC_83XX_FLASH_CONTROL ,
QLC_83XX_FLASH_SECOND_ERASE_MS_VAL ) ;
ret = qlcnic_83xx_poll_flash_status_reg ( adapter ) ;
if ( ret )
return - EIO ;
return 0 ;
}
int qlcnic_83xx_read_flash_mfg_id ( struct qlcnic_adapter * adapter )
{
int ret , mfg_id ;
if ( qlcnic_83xx_lock_flash ( adapter ) )
return - EIO ;
qlcnic_83xx_wrt_reg_indirect ( adapter , QLC_83XX_FLASH_ADDR ,
QLC_83XX_FLASH_FDT_READ_MFG_ID_VAL ) ;
qlcnic_83xx_wrt_reg_indirect ( adapter , QLC_83XX_FLASH_CONTROL ,
QLC_83XX_FLASH_READ_CTRL ) ;
ret = qlcnic_83xx_poll_flash_status_reg ( adapter ) ;
if ( ret ) {
qlcnic_83xx_unlock_flash ( adapter ) ;
return - EIO ;
}
mfg_id = qlcnic_83xx_rd_reg_indirect ( adapter , QLC_83XX_FLASH_RDDATA ) ;
if ( mfg_id = = - EIO )
return - EIO ;
adapter - > flash_mfg_id = ( mfg_id & 0xFF ) ;
qlcnic_83xx_unlock_flash ( adapter ) ;
return 0 ;
}
int qlcnic_83xx_read_flash_descriptor_table ( struct qlcnic_adapter * adapter )
{
int count , fdt_size , ret = 0 ;
fdt_size = sizeof ( struct qlcnic_fdt ) ;
count = fdt_size / sizeof ( u32 ) ;
if ( qlcnic_83xx_lock_flash ( adapter ) )
return - EIO ;
memset ( & adapter - > ahw - > fdt , 0 , fdt_size ) ;
ret = qlcnic_83xx_lockless_flash_read32 ( adapter , QLCNIC_FDT_LOCATION ,
( u8 * ) & adapter - > ahw - > fdt ,
count ) ;
qlcnic_83xx_unlock_flash ( adapter ) ;
return ret ;
}
int qlcnic_83xx_erase_flash_sector ( struct qlcnic_adapter * adapter ,
u32 sector_start_addr )
{
u32 reversed_addr , addr1 , addr2 , cmd ;
int ret = - EIO ;
if ( qlcnic_83xx_lock_flash ( adapter ) ! = 0 )
return - EIO ;
if ( adapter - > ahw - > fdt . mfg_id = = adapter - > flash_mfg_id ) {
ret = qlcnic_83xx_enable_flash_write_op ( adapter ) ;
if ( ret ) {
qlcnic_83xx_unlock_flash ( adapter ) ;
dev_err ( & adapter - > pdev - > dev ,
" %s failed at %d \n " ,
__func__ , __LINE__ ) ;
return ret ;
}
}
ret = qlcnic_83xx_poll_flash_status_reg ( adapter ) ;
if ( ret ) {
qlcnic_83xx_unlock_flash ( adapter ) ;
dev_err ( & adapter - > pdev - > dev ,
" %s: failed at %d \n " , __func__ , __LINE__ ) ;
return - EIO ;
}
addr1 = ( sector_start_addr & 0xFF ) < < 16 ;
addr2 = ( sector_start_addr & 0xFF0000 ) > > 16 ;
reversed_addr = addr1 | addr2 ;
qlcnic_83xx_wrt_reg_indirect ( adapter , QLC_83XX_FLASH_WRDATA ,
reversed_addr ) ;
cmd = QLC_83XX_FLASH_FDT_ERASE_DEF_SIG | adapter - > ahw - > fdt . erase_cmd ;
if ( adapter - > ahw - > fdt . mfg_id = = adapter - > flash_mfg_id )
qlcnic_83xx_wrt_reg_indirect ( adapter , QLC_83XX_FLASH_ADDR , cmd ) ;
else
qlcnic_83xx_wrt_reg_indirect ( adapter , QLC_83XX_FLASH_ADDR ,
QLC_83XX_FLASH_OEM_ERASE_SIG ) ;
qlcnic_83xx_wrt_reg_indirect ( adapter , QLC_83XX_FLASH_CONTROL ,
QLC_83XX_FLASH_LAST_ERASE_MS_VAL ) ;
ret = qlcnic_83xx_poll_flash_status_reg ( adapter ) ;
if ( ret ) {
qlcnic_83xx_unlock_flash ( adapter ) ;
dev_err ( & adapter - > pdev - > dev ,
" %s: failed at %d \n " , __func__ , __LINE__ ) ;
return - EIO ;
}
if ( adapter - > ahw - > fdt . mfg_id = = adapter - > flash_mfg_id ) {
ret = qlcnic_83xx_disable_flash_write_op ( adapter ) ;
if ( ret ) {
qlcnic_83xx_unlock_flash ( adapter ) ;
dev_err ( & adapter - > pdev - > dev ,
" %s: failed at %d \n " , __func__ , __LINE__ ) ;
return ret ;
}
}
qlcnic_83xx_unlock_flash ( adapter ) ;
return 0 ;
}
int qlcnic_83xx_flash_write32 ( struct qlcnic_adapter * adapter , u32 addr ,
u32 * p_data )
{
int ret = - EIO ;
u32 addr1 = 0x00800000 | ( addr > > 2 ) ;
qlcnic_83xx_wrt_reg_indirect ( adapter , QLC_83XX_FLASH_ADDR , addr1 ) ;
qlcnic_83xx_wrt_reg_indirect ( adapter , QLC_83XX_FLASH_WRDATA , * p_data ) ;
qlcnic_83xx_wrt_reg_indirect ( adapter , QLC_83XX_FLASH_CONTROL ,
QLC_83XX_FLASH_LAST_ERASE_MS_VAL ) ;
ret = qlcnic_83xx_poll_flash_status_reg ( adapter ) ;
if ( ret ) {
dev_err ( & adapter - > pdev - > dev ,
" %s: failed at %d \n " , __func__ , __LINE__ ) ;
return - EIO ;
}
return 0 ;
}
int qlcnic_83xx_flash_bulk_write ( struct qlcnic_adapter * adapter , u32 addr ,
u32 * p_data , int count )
{
u32 temp ;
int ret = - EIO ;
if ( ( count < QLC_83XX_FLASH_BULK_WRITE_MIN ) | |
( count > QLC_83XX_FLASH_BULK_WRITE_MAX ) ) {
dev_err ( & adapter - > pdev - > dev ,
" %s: Invalid word count \n " , __func__ ) ;
return - EIO ;
}
temp = qlcnic_83xx_rd_reg_indirect ( adapter ,
QLC_83XX_FLASH_SPI_CONTROL ) ;
qlcnic_83xx_wrt_reg_indirect ( adapter , QLC_83XX_FLASH_SPI_CONTROL ,
( temp | QLC_83XX_FLASH_SPI_CTRL ) ) ;
qlcnic_83xx_wrt_reg_indirect ( adapter , QLC_83XX_FLASH_ADDR ,
QLC_83XX_FLASH_ADDR_TEMP_VAL ) ;
/* First DWORD write */
qlcnic_83xx_wrt_reg_indirect ( adapter , QLC_83XX_FLASH_WRDATA , * p_data + + ) ;
qlcnic_83xx_wrt_reg_indirect ( adapter , QLC_83XX_FLASH_CONTROL ,
QLC_83XX_FLASH_FIRST_MS_PATTERN ) ;
ret = qlcnic_83xx_poll_flash_status_reg ( adapter ) ;
if ( ret ) {
dev_err ( & adapter - > pdev - > dev ,
" %s: failed at %d \n " , __func__ , __LINE__ ) ;
return - EIO ;
}
count - - ;
qlcnic_83xx_wrt_reg_indirect ( adapter , QLC_83XX_FLASH_ADDR ,
QLC_83XX_FLASH_ADDR_SECOND_TEMP_VAL ) ;
/* Second to N-1 DWORD writes */
while ( count ! = 1 ) {
qlcnic_83xx_wrt_reg_indirect ( adapter , QLC_83XX_FLASH_WRDATA ,
* p_data + + ) ;
qlcnic_83xx_wrt_reg_indirect ( adapter , QLC_83XX_FLASH_CONTROL ,
QLC_83XX_FLASH_SECOND_MS_PATTERN ) ;
ret = qlcnic_83xx_poll_flash_status_reg ( adapter ) ;
if ( ret ) {
dev_err ( & adapter - > pdev - > dev ,
" %s: failed at %d \n " , __func__ , __LINE__ ) ;
return - EIO ;
}
count - - ;
}
qlcnic_83xx_wrt_reg_indirect ( adapter , QLC_83XX_FLASH_ADDR ,
QLC_83XX_FLASH_ADDR_TEMP_VAL |
( addr > > 2 ) ) ;
/* Last DWORD write */
qlcnic_83xx_wrt_reg_indirect ( adapter , QLC_83XX_FLASH_WRDATA , * p_data + + ) ;
qlcnic_83xx_wrt_reg_indirect ( adapter , QLC_83XX_FLASH_CONTROL ,
QLC_83XX_FLASH_LAST_MS_PATTERN ) ;
ret = qlcnic_83xx_poll_flash_status_reg ( adapter ) ;
if ( ret ) {
dev_err ( & adapter - > pdev - > dev ,
" %s: failed at %d \n " , __func__ , __LINE__ ) ;
return - EIO ;
}
ret = qlcnic_83xx_rd_reg_indirect ( adapter , QLC_83XX_FLASH_SPI_STATUS ) ;
if ( ( ret & QLC_83XX_FLASH_SPI_CTRL ) = = QLC_83XX_FLASH_SPI_CTRL ) {
dev_err ( & adapter - > pdev - > dev , " %s: failed at %d \n " ,
__func__ , __LINE__ ) ;
/* Operation failed, clear error bit */
temp = qlcnic_83xx_rd_reg_indirect ( adapter ,
QLC_83XX_FLASH_SPI_CONTROL ) ;
qlcnic_83xx_wrt_reg_indirect ( adapter ,
QLC_83XX_FLASH_SPI_CONTROL ,
( temp | QLC_83XX_FLASH_SPI_CTRL ) ) ;
}
return 0 ;
}