1
linux/drivers/infiniband/hw/nes/nes_hw.c
Roland Dreier 0f39cf3d54 IB/core: Add support for "send with invalidate" work requests
Add a new IB_WR_SEND_WITH_INV send opcode that can be used to mark a
"send with invalidate" work request as defined in the iWARP verbs and
the InfiniBand base memory management extensions.  Also put "imm_data"
and a new "invalidate_rkey" member in a new "ex" union in struct
ib_send_wr. The invalidate_rkey member can be used to pass in an
R_Key/STag to be invalidated.  Add this new union to struct
ib_uverbs_send_wr.  Add code to copy the invalidate_rkey field in
ib_uverbs_post_send().

Fix up low-level drivers to deal with the change to struct ib_send_wr,
and just remove the imm_data initialization from net/sunrpc/xprtrdma/,
since that code never does any send with immediate operations.

Also, move the existing IB_DEVICE_SEND_W_INV flag to a new bit, since
the iWARP drivers currently in the tree set the bit.  The amso1100
driver at least will silently fail to honor the IB_SEND_INVALIDATE bit
if passed in as part of userspace send requests (since it does not
implement kernel bypass work request queueing).  Remove the flag from
all existing drivers that set it until we know which ones are OK.

The values chosen for the new flag is not consecutive to avoid clashing
with flags defined in the XRC patches, which are not merged yet but
which are already in use and are likely to be merged soon.

This resurrects a patch sent long ago by Mikkel Hagen <mhagen@iol.unh.edu>.

Signed-off-by: Roland Dreier <rolandd@cisco.com>
2008-04-16 21:09:32 -07:00

3091 lines
104 KiB
C

/*
* Copyright (c) 2006 - 2008 NetEffect, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/if_vlan.h>
#include "nes.h"
static u32 crit_err_count;
u32 int_mod_timer_init;
u32 int_mod_cq_depth_256;
u32 int_mod_cq_depth_128;
u32 int_mod_cq_depth_32;
u32 int_mod_cq_depth_24;
u32 int_mod_cq_depth_16;
u32 int_mod_cq_depth_4;
u32 int_mod_cq_depth_1;
#include "nes_cm.h"
static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq);
static void nes_init_csr_ne020(struct nes_device *nesdev, u8 hw_rev, u8 port_count);
static int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count,
u8 OneG_Mode);
static void nes_nic_napi_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq);
static void nes_process_aeq(struct nes_device *nesdev, struct nes_hw_aeq *aeq);
static void nes_process_ceq(struct nes_device *nesdev, struct nes_hw_ceq *ceq);
static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
struct nes_hw_aeqe *aeqe);
static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number);
static unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_Mode);
#ifdef CONFIG_INFINIBAND_NES_DEBUG
static unsigned char *nes_iwarp_state_str[] = {
"Non-Existant",
"Idle",
"RTS",
"Closing",
"RSVD1",
"Terminate",
"Error",
"RSVD2",
};
static unsigned char *nes_tcp_state_str[] = {
"Non-Existant",
"Closed",
"Listen",
"SYN Sent",
"SYN Rcvd",
"Established",
"Close Wait",
"FIN Wait 1",
"Closing",
"Last Ack",
"FIN Wait 2",
"Time Wait",
"RSVD1",
"RSVD2",
"RSVD3",
"RSVD4",
};
#endif
/**
* nes_nic_init_timer_defaults
*/
void nes_nic_init_timer_defaults(struct nes_device *nesdev, u8 jumbomode)
{
unsigned long flags;
struct nes_adapter *nesadapter = nesdev->nesadapter;
struct nes_hw_tune_timer *shared_timer = &nesadapter->tune_timer;
spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags);
shared_timer->timer_in_use_min = NES_NIC_FAST_TIMER_LOW;
shared_timer->timer_in_use_max = NES_NIC_FAST_TIMER_HIGH;
if (jumbomode) {
shared_timer->threshold_low = DEFAULT_JUMBO_NES_QL_LOW;
shared_timer->threshold_target = DEFAULT_JUMBO_NES_QL_TARGET;
shared_timer->threshold_high = DEFAULT_JUMBO_NES_QL_HIGH;
} else {
shared_timer->threshold_low = DEFAULT_NES_QL_LOW;
shared_timer->threshold_target = DEFAULT_NES_QL_TARGET;
shared_timer->threshold_high = DEFAULT_NES_QL_HIGH;
}
/* todo use netdev->mtu to set thresholds */
spin_unlock_irqrestore(&nesadapter->periodic_timer_lock, flags);
}
/**
* nes_nic_init_timer
*/
static void nes_nic_init_timer(struct nes_device *nesdev)
{
unsigned long flags;
struct nes_adapter *nesadapter = nesdev->nesadapter;
struct nes_hw_tune_timer *shared_timer = &nesadapter->tune_timer;
spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags);
if (shared_timer->timer_in_use_old == 0) {
nesdev->deepcq_count = 0;
shared_timer->timer_direction_upward = 0;
shared_timer->timer_direction_downward = 0;
shared_timer->timer_in_use = NES_NIC_FAST_TIMER;
shared_timer->timer_in_use_old = 0;
}
if (shared_timer->timer_in_use != shared_timer->timer_in_use_old) {
shared_timer->timer_in_use_old = shared_timer->timer_in_use;
nes_write32(nesdev->regs+NES_PERIODIC_CONTROL,
0x80000000 | ((u32)(shared_timer->timer_in_use*8)));
}
/* todo use netdev->mtu to set thresholds */
spin_unlock_irqrestore(&nesadapter->periodic_timer_lock, flags);
}
/**
* nes_nic_tune_timer
*/
static void nes_nic_tune_timer(struct nes_device *nesdev)
{
unsigned long flags;
struct nes_adapter *nesadapter = nesdev->nesadapter;
struct nes_hw_tune_timer *shared_timer = &nesadapter->tune_timer;
u16 cq_count = nesdev->currcq_count;
spin_lock_irqsave(&nesadapter->periodic_timer_lock, flags);
if (shared_timer->cq_count_old <= cq_count)
shared_timer->cq_direction_downward = 0;
else
shared_timer->cq_direction_downward++;
shared_timer->cq_count_old = cq_count;
if (shared_timer->cq_direction_downward > NES_NIC_CQ_DOWNWARD_TREND) {
if (cq_count <= shared_timer->threshold_low &&
shared_timer->threshold_low > 4) {
shared_timer->threshold_low = shared_timer->threshold_low/2;
shared_timer->cq_direction_downward=0;
nesdev->currcq_count = 0;
spin_unlock_irqrestore(&nesadapter->periodic_timer_lock, flags);
return;
}
}
if (cq_count > 1) {
nesdev->deepcq_count += cq_count;
if (cq_count <= shared_timer->threshold_low) { /* increase timer gently */
shared_timer->timer_direction_upward++;
shared_timer->timer_direction_downward = 0;
} else if (cq_count <= shared_timer->threshold_target) { /* balanced */
shared_timer->timer_direction_upward = 0;
shared_timer->timer_direction_downward = 0;
} else if (cq_count <= shared_timer->threshold_high) { /* decrease timer gently */
shared_timer->timer_direction_downward++;
shared_timer->timer_direction_upward = 0;
} else if (cq_count <= (shared_timer->threshold_high) * 2) {
shared_timer->timer_in_use -= 2;
shared_timer->timer_direction_upward = 0;
shared_timer->timer_direction_downward++;
} else {
shared_timer->timer_in_use -= 4;
shared_timer->timer_direction_upward = 0;
shared_timer->timer_direction_downward++;
}
if (shared_timer->timer_direction_upward > 3 ) { /* using history */
shared_timer->timer_in_use += 3;
shared_timer->timer_direction_upward = 0;
shared_timer->timer_direction_downward = 0;
}
if (shared_timer->timer_direction_downward > 5) { /* using history */
shared_timer->timer_in_use -= 4 ;
shared_timer->timer_direction_downward = 0;
shared_timer->timer_direction_upward = 0;
}
}
/* boundary checking */
if (shared_timer->timer_in_use > NES_NIC_FAST_TIMER_HIGH)
shared_timer->timer_in_use = NES_NIC_FAST_TIMER_HIGH;
else if (shared_timer->timer_in_use < NES_NIC_FAST_TIMER_LOW) {
shared_timer->timer_in_use = NES_NIC_FAST_TIMER_LOW;
}
nesdev->currcq_count = 0;
spin_unlock_irqrestore(&nesadapter->periodic_timer_lock, flags);
}
/**
* nes_init_adapter - initialize adapter
*/
struct nes_adapter *nes_init_adapter(struct nes_device *nesdev, u8 hw_rev) {
struct nes_adapter *nesadapter = NULL;
unsigned long num_pds;
u32 u32temp;
u32 port_count;
u16 max_rq_wrs;
u16 max_sq_wrs;
u32 max_mr;
u32 max_256pbl;
u32 max_4kpbl;
u32 max_qp;
u32 max_irrq;
u32 max_cq;
u32 hte_index_mask;
u32 adapter_size;
u32 arp_table_size;
u16 vendor_id;
u8 OneG_Mode;
u8 func_index;
/* search the list of existing adapters */
list_for_each_entry(nesadapter, &nes_adapter_list, list) {
nes_debug(NES_DBG_INIT, "Searching Adapter list for PCI devfn = 0x%X,"
" adapter PCI slot/bus = %u/%u, pci devices PCI slot/bus = %u/%u, .\n",
nesdev->pcidev->devfn,
PCI_SLOT(nesadapter->devfn),
nesadapter->bus_number,
PCI_SLOT(nesdev->pcidev->devfn),
nesdev->pcidev->bus->number );
if ((PCI_SLOT(nesadapter->devfn) == PCI_SLOT(nesdev->pcidev->devfn)) &&
(nesadapter->bus_number == nesdev->pcidev->bus->number)) {
nesadapter->ref_count++;
return nesadapter;
}
}
/* no adapter found */
num_pds = pci_resource_len(nesdev->pcidev, BAR_1) >> PAGE_SHIFT;
if ((hw_rev != NE020_REV) && (hw_rev != NE020_REV1)) {
nes_debug(NES_DBG_INIT, "NE020 driver detected unknown hardware revision 0x%x\n",
hw_rev);
return NULL;
}
nes_debug(NES_DBG_INIT, "Determine Soft Reset, QP_control=0x%x, CPU0=0x%x, CPU1=0x%x, CPU2=0x%x\n",
nes_read_indexed(nesdev, NES_IDX_QP_CONTROL + PCI_FUNC(nesdev->pcidev->devfn) * 8),
nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS),
nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS + 4),
nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS + 8));
nes_debug(NES_DBG_INIT, "Reset and init NE020\n");
if ((port_count = nes_reset_adapter_ne020(nesdev, &OneG_Mode)) == 0)
return NULL;
if (nes_init_serdes(nesdev, hw_rev, port_count, OneG_Mode))
return NULL;
nes_init_csr_ne020(nesdev, hw_rev, port_count);
max_qp = nes_read_indexed(nesdev, NES_IDX_QP_CTX_SIZE);
nes_debug(NES_DBG_INIT, "QP_CTX_SIZE=%u\n", max_qp);
u32temp = nes_read_indexed(nesdev, NES_IDX_QUAD_HASH_TABLE_SIZE);
if (max_qp > ((u32)1 << (u32temp & 0x001f))) {
nes_debug(NES_DBG_INIT, "Reducing Max QPs to %u due to hash table size = 0x%08X\n",
max_qp, u32temp);
max_qp = (u32)1 << (u32temp & 0x001f);
}
hte_index_mask = ((u32)1 << ((u32temp & 0x001f)+1))-1;
nes_debug(NES_DBG_INIT, "Max QP = %u, hte_index_mask = 0x%08X.\n",
max_qp, hte_index_mask);
u32temp = nes_read_indexed(nesdev, NES_IDX_IRRQ_COUNT);
max_irrq = 1 << (u32temp & 0x001f);
if (max_qp > max_irrq) {
max_qp = max_irrq;
nes_debug(NES_DBG_INIT, "Reducing Max QPs to %u due to Available Q1s.\n",
max_qp);
}
/* there should be no reason to allocate more pds than qps */
if (num_pds > max_qp)
num_pds = max_qp;
u32temp = nes_read_indexed(nesdev, NES_IDX_MRT_SIZE);
max_mr = (u32)8192 << (u32temp & 0x7);
u32temp = nes_read_indexed(nesdev, NES_IDX_PBL_REGION_SIZE);
max_256pbl = (u32)1 << (u32temp & 0x0000001f);
max_4kpbl = (u32)1 << ((u32temp >> 16) & 0x0000001f);
max_cq = nes_read_indexed(nesdev, NES_IDX_CQ_CTX_SIZE);
u32temp = nes_read_indexed(nesdev, NES_IDX_ARP_CACHE_SIZE);
arp_table_size = 1 << u32temp;
adapter_size = (sizeof(struct nes_adapter) +
(sizeof(unsigned long)-1)) & (~(sizeof(unsigned long)-1));
adapter_size += sizeof(unsigned long) * BITS_TO_LONGS(max_qp);
adapter_size += sizeof(unsigned long) * BITS_TO_LONGS(max_mr);
adapter_size += sizeof(unsigned long) * BITS_TO_LONGS(max_cq);
adapter_size += sizeof(unsigned long) * BITS_TO_LONGS(num_pds);
adapter_size += sizeof(unsigned long) * BITS_TO_LONGS(arp_table_size);
adapter_size += sizeof(struct nes_qp **) * max_qp;
/* allocate a new adapter struct */
nesadapter = kzalloc(adapter_size, GFP_KERNEL);
if (nesadapter == NULL) {
return NULL;
}
nes_debug(NES_DBG_INIT, "Allocating new nesadapter @ %p, size = %u (actual size = %u).\n",
nesadapter, (u32)sizeof(struct nes_adapter), adapter_size);
/* populate the new nesadapter */
nesadapter->devfn = nesdev->pcidev->devfn;
nesadapter->bus_number = nesdev->pcidev->bus->number;
nesadapter->ref_count = 1;
nesadapter->timer_int_req = 0xffff0000;
nesadapter->OneG_Mode = OneG_Mode;
nesadapter->doorbell_start = nesdev->doorbell_region;
/* nesadapter->tick_delta = clk_divisor; */
nesadapter->hw_rev = hw_rev;
nesadapter->port_count = port_count;
nesadapter->max_qp = max_qp;
nesadapter->hte_index_mask = hte_index_mask;
nesadapter->max_irrq = max_irrq;
nesadapter->max_mr = max_mr;
nesadapter->max_256pbl = max_256pbl - 1;
nesadapter->max_4kpbl = max_4kpbl - 1;
nesadapter->max_cq = max_cq;
nesadapter->free_256pbl = max_256pbl - 1;
nesadapter->free_4kpbl = max_4kpbl - 1;
nesadapter->max_pd = num_pds;
nesadapter->arp_table_size = arp_table_size;
nesadapter->et_pkt_rate_low = NES_TIMER_ENABLE_LIMIT;
if (nes_drv_opt & NES_DRV_OPT_DISABLE_INT_MOD) {
nesadapter->et_use_adaptive_rx_coalesce = 0;
nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT;
nesadapter->et_rx_coalesce_usecs_irq = interrupt_mod_interval;
} else {
nesadapter->et_use_adaptive_rx_coalesce = 1;
nesadapter->timer_int_limit = NES_TIMER_INT_LIMIT_DYNAMIC;
nesadapter->et_rx_coalesce_usecs_irq = 0;
printk(PFX "%s: Using Adaptive Interrupt Moderation\n", __func__);
}
/* Setup and enable the periodic timer */
if (nesadapter->et_rx_coalesce_usecs_irq)
nes_write32(nesdev->regs+NES_PERIODIC_CONTROL, 0x80000000 |
((u32)(nesadapter->et_rx_coalesce_usecs_irq * 8)));
else
nes_write32(nesdev->regs+NES_PERIODIC_CONTROL, 0x00000000);
nesadapter->base_pd = 1;
nesadapter->device_cap_flags =
IB_DEVICE_ZERO_STAG | IB_DEVICE_MEM_WINDOW;
nesadapter->allocated_qps = (unsigned long *)&(((unsigned char *)nesadapter)
[(sizeof(struct nes_adapter)+(sizeof(unsigned long)-1))&(~(sizeof(unsigned long)-1))]);
nesadapter->allocated_cqs = &nesadapter->allocated_qps[BITS_TO_LONGS(max_qp)];
nesadapter->allocated_mrs = &nesadapter->allocated_cqs[BITS_TO_LONGS(max_cq)];
nesadapter->allocated_pds = &nesadapter->allocated_mrs[BITS_TO_LONGS(max_mr)];
nesadapter->allocated_arps = &nesadapter->allocated_pds[BITS_TO_LONGS(num_pds)];
nesadapter->qp_table = (struct nes_qp **)(&nesadapter->allocated_arps[BITS_TO_LONGS(arp_table_size)]);
/* mark the usual suspect QPs and CQs as in use */
for (u32temp = 0; u32temp < NES_FIRST_QPN; u32temp++) {
set_bit(u32temp, nesadapter->allocated_qps);
set_bit(u32temp, nesadapter->allocated_cqs);
}
for (u32temp = 0; u32temp < 20; u32temp++)
set_bit(u32temp, nesadapter->allocated_pds);
u32temp = nes_read_indexed(nesdev, NES_IDX_QP_MAX_CFG_SIZES);
max_rq_wrs = ((u32temp >> 8) & 3);
switch (max_rq_wrs) {
case 0:
max_rq_wrs = 4;
break;
case 1:
max_rq_wrs = 16;
break;
case 2:
max_rq_wrs = 32;
break;
case 3:
max_rq_wrs = 512;
break;
}
max_sq_wrs = (u32temp & 3);
switch (max_sq_wrs) {
case 0:
max_sq_wrs = 4;
break;
case 1:
max_sq_wrs = 16;
break;
case 2:
max_sq_wrs = 32;
break;
case 3:
max_sq_wrs = 512;
break;
}
nesadapter->max_qp_wr = min(max_rq_wrs, max_sq_wrs);
nesadapter->max_irrq_wr = (u32temp >> 16) & 3;
nesadapter->max_sge = 4;
nesadapter->max_cqe = 32767;
if (nes_read_eeprom_values(nesdev, nesadapter)) {
printk(KERN_ERR PFX "Unable to read EEPROM data.\n");
kfree(nesadapter);
return NULL;
}
u32temp = nes_read_indexed(nesdev, NES_IDX_TCP_TIMER_CONFIG);
nes_write_indexed(nesdev, NES_IDX_TCP_TIMER_CONFIG,
(u32temp & 0xff000000) | (nesadapter->tcp_timer_core_clk_divisor & 0x00ffffff));
/* setup port configuration */
if (nesadapter->port_count == 1) {
u32temp = 0x00000000;
if (nes_drv_opt & NES_DRV_OPT_DUAL_LOGICAL_PORT)
nes_write_indexed(nesdev, NES_IDX_TX_POOL_SIZE, 0x00000002);
else
nes_write_indexed(nesdev, NES_IDX_TX_POOL_SIZE, 0x00000003);
} else {
if (nesadapter->port_count == 2)
u32temp = 0x00000044;
else
u32temp = 0x000000e4;
nes_write_indexed(nesdev, NES_IDX_TX_POOL_SIZE, 0x00000003);
}
nes_write_indexed(nesdev, NES_IDX_NIC_LOGPORT_TO_PHYPORT, u32temp);
nes_debug(NES_DBG_INIT, "Probe time, LOG2PHY=%u\n",
nes_read_indexed(nesdev, NES_IDX_NIC_LOGPORT_TO_PHYPORT));
spin_lock_init(&nesadapter->resource_lock);
spin_lock_init(&nesadapter->phy_lock);
spin_lock_init(&nesadapter->pbl_lock);
spin_lock_init(&nesadapter->periodic_timer_lock);
INIT_LIST_HEAD(&nesadapter->nesvnic_list[0]);
INIT_LIST_HEAD(&nesadapter->nesvnic_list[1]);
INIT_LIST_HEAD(&nesadapter->nesvnic_list[2]);
INIT_LIST_HEAD(&nesadapter->nesvnic_list[3]);
if ((!nesadapter->OneG_Mode) && (nesadapter->port_count == 2)) {
u32 pcs_control_status0, pcs_control_status1;
u32 reset_value;
u32 i = 0;
u32 int_cnt = 0;
u32 ext_cnt = 0;
unsigned long flags;
u32 j = 0;
pcs_control_status0 = nes_read_indexed(nesdev,
NES_IDX_PHY_PCS_CONTROL_STATUS0);
pcs_control_status1 = nes_read_indexed(nesdev,
NES_IDX_PHY_PCS_CONTROL_STATUS0 + 0x200);
for (i = 0; i < NES_MAX_LINK_CHECK; i++) {
pcs_control_status0 = nes_read_indexed(nesdev,
NES_IDX_PHY_PCS_CONTROL_STATUS0);
pcs_control_status1 = nes_read_indexed(nesdev,
NES_IDX_PHY_PCS_CONTROL_STATUS0 + 0x200);
if ((0x0F000100 == (pcs_control_status0 & 0x0F000100))
|| (0x0F000100 == (pcs_control_status1 & 0x0F000100)))
int_cnt++;
msleep(1);
}
if (int_cnt > 1) {
spin_lock_irqsave(&nesadapter->phy_lock, flags);
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, 0x0000F088);
mh_detected++;
reset_value = nes_read32(nesdev->regs+NES_SOFTWARE_RESET);
reset_value |= 0x0000003d;
nes_write32(nesdev->regs+NES_SOFTWARE_RESET, reset_value);
while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET)
& 0x00000040) != 0x00000040) && (j++ < 5000));
spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
pcs_control_status0 = nes_read_indexed(nesdev,
NES_IDX_PHY_PCS_CONTROL_STATUS0);
pcs_control_status1 = nes_read_indexed(nesdev,
NES_IDX_PHY_PCS_CONTROL_STATUS0 + 0x200);
for (i = 0; i < NES_MAX_LINK_CHECK; i++) {
pcs_control_status0 = nes_read_indexed(nesdev,
NES_IDX_PHY_PCS_CONTROL_STATUS0);
pcs_control_status1 = nes_read_indexed(nesdev,
NES_IDX_PHY_PCS_CONTROL_STATUS0 + 0x200);
if ((0x0F000100 == (pcs_control_status0 & 0x0F000100))
|| (0x0F000100 == (pcs_control_status1 & 0x0F000100))) {
if (++ext_cnt > int_cnt) {
spin_lock_irqsave(&nesadapter->phy_lock, flags);
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1,
0x0000F0C8);
mh_detected++;
reset_value = nes_read32(nesdev->regs+NES_SOFTWARE_RESET);
reset_value |= 0x0000003d;
nes_write32(nesdev->regs+NES_SOFTWARE_RESET, reset_value);
while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET)
& 0x00000040) != 0x00000040) && (j++ < 5000));
spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
break;
}
}
msleep(1);
}
}
}
if (nesadapter->hw_rev == NE020_REV) {
init_timer(&nesadapter->mh_timer);
nesadapter->mh_timer.function = nes_mh_fix;
nesadapter->mh_timer.expires = jiffies + (HZ/5); /* 1 second */
nesadapter->mh_timer.data = (unsigned long)nesdev;
add_timer(&nesadapter->mh_timer);
} else {
nes_write32(nesdev->regs+NES_INTF_INT_STAT, 0x0f000000);
}
init_timer(&nesadapter->lc_timer);
nesadapter->lc_timer.function = nes_clc;
nesadapter->lc_timer.expires = jiffies + 3600 * HZ; /* 1 hour */
nesadapter->lc_timer.data = (unsigned long)nesdev;
add_timer(&nesadapter->lc_timer);
list_add_tail(&nesadapter->list, &nes_adapter_list);
for (func_index = 0; func_index < 8; func_index++) {
pci_bus_read_config_word(nesdev->pcidev->bus,
PCI_DEVFN(PCI_SLOT(nesdev->pcidev->devfn),
func_index), 0, &vendor_id);
if (vendor_id == 0xffff)
break;
}
nes_debug(NES_DBG_INIT, "%s %d functions found for %s.\n", __func__,
func_index, pci_name(nesdev->pcidev));
nesadapter->adapter_fcn_count = func_index;
return nesadapter;
}
/**
* nes_reset_adapter_ne020
*/
static unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_Mode)
{
u32 port_count;
u32 u32temp;
u32 i;
u32temp = nes_read32(nesdev->regs+NES_SOFTWARE_RESET);
port_count = ((u32temp & 0x00000300) >> 8) + 1;
/* TODO: assuming that both SERDES are set the same for now */
*OneG_Mode = (u32temp & 0x00003c00) ? 0 : 1;
nes_debug(NES_DBG_INIT, "Initial Software Reset = 0x%08X, port_count=%u\n",
u32temp, port_count);
if (*OneG_Mode)
nes_debug(NES_DBG_INIT, "Running in 1G mode.\n");
u32temp &= 0xff00ffc0;
switch (port_count) {
case 1:
u32temp |= 0x00ee0000;
break;
case 2:
u32temp |= 0x00cc0000;
break;
case 4:
u32temp |= 0x00000000;
break;
default:
return 0;
break;
}
/* check and do full reset if needed */
if (nes_read_indexed(nesdev, NES_IDX_QP_CONTROL+(PCI_FUNC(nesdev->pcidev->devfn)*8))) {
nes_debug(NES_DBG_INIT, "Issuing Full Soft reset = 0x%08X\n", u32temp | 0xd);
nes_write32(nesdev->regs+NES_SOFTWARE_RESET, u32temp | 0xd);
i = 0;
while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET) & 0x00000040) == 0) && i++ < 10000)
mdelay(1);
if (i >= 10000) {
nes_debug(NES_DBG_INIT, "Did not see full soft reset done.\n");
return 0;
}
}
/* port reset */
switch (port_count) {
case 1:
u32temp |= 0x00ee0010;
break;
case 2:
u32temp |= 0x00cc0030;
break;
case 4:
u32temp |= 0x00000030;
break;
}
nes_debug(NES_DBG_INIT, "Issuing Port Soft reset = 0x%08X\n", u32temp | 0xd);
nes_write32(nesdev->regs+NES_SOFTWARE_RESET, u32temp | 0xd);
i = 0;
while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET) & 0x00000040) == 0) && i++ < 10000)
mdelay(1);
if (i >= 10000) {
nes_debug(NES_DBG_INIT, "Did not see port soft reset done.\n");
return 0;
}
/* serdes 0 */
i = 0;
while (((u32temp = (nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0)
& 0x0000000f)) != 0x0000000f) && i++ < 5000)
mdelay(1);
if (i >= 5000) {
nes_debug(NES_DBG_INIT, "Serdes 0 not ready, status=%x\n", u32temp);
return 0;
}
/* serdes 1 */
if (port_count > 1) {
i = 0;
while (((u32temp = (nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS1)
& 0x0000000f)) != 0x0000000f) && i++ < 5000)
mdelay(1);
if (i >= 5000) {
nes_debug(NES_DBG_INIT, "Serdes 1 not ready, status=%x\n", u32temp);
return 0;
}
}
i = 0;
while ((nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS) != 0x80) && i++ < 10000)
mdelay(1);
if (i >= 10000) {
printk(KERN_ERR PFX "Internal CPU not ready, status = %02X\n",
nes_read_indexed(nesdev, NES_IDX_INT_CPU_STATUS));
return 0;
}
return port_count;
}
/**
* nes_init_serdes
*/
static int nes_init_serdes(struct nes_device *nesdev, u8 hw_rev, u8 port_count,
u8 OneG_Mode)
{
int i;
u32 u32temp;
if (hw_rev != NE020_REV) {
/* init serdes 0 */
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000FF);
if (!OneG_Mode)
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_HIGHZ_LANE_MODE0, 0x11110000);
if (port_count > 1) {
/* init serdes 1 */
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL1, 0x000000FF);
if (!OneG_Mode)
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_HIGHZ_LANE_MODE1, 0x11110000);
}
} else {
/* init serdes 0 */
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL0, 0x00000008);
i = 0;
while (((u32temp = (nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0)
& 0x0000000f)) != 0x0000000f) && i++ < 5000)
mdelay(1);
if (i >= 5000) {
nes_debug(NES_DBG_PHY, "Init: serdes 0 not ready, status=%x\n", u32temp);
return 1;
}
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_EMP0, 0x000bdef7);
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_DRIVE0, 0x9ce73000);
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_MODE0, 0x0ff00000);
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_SIGDET0, 0x00000000);
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_BYPASS0, 0x00000000);
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_LOOPBACK_CONTROL0, 0x00000000);
if (OneG_Mode)
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_EQ_CONTROL0, 0xf0182222);
else
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_EQ_CONTROL0, 0xf0042222);
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL0, 0x000000ff);
if (port_count > 1) {
/* init serdes 1 */
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, 0x00000048);
i = 0;
while (((u32temp = (nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS1)
& 0x0000000f)) != 0x0000000f) && (i++ < 5000))
mdelay(1);
if (i >= 5000) {
printk("%s: Init: serdes 1 not ready, status=%x\n", __func__, u32temp);
/* return 1; */
}
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_EMP1, 0x000bdef7);
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_TX_DRIVE1, 0x9ce73000);
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_MODE1, 0x0ff00000);
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_SIGDET1, 0x00000000);
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_BYPASS1, 0x00000000);
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_LOOPBACK_CONTROL1, 0x00000000);
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_RX_EQ_CONTROL1, 0xf0002222);
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_CDR_CONTROL1, 0x000000ff);
}
}
return 0;
}
/**
* nes_init_csr_ne020
* Initialize registers for ne020 hardware
*/
static void nes_init_csr_ne020(struct nes_device *nesdev, u8 hw_rev, u8 port_count)
{
u32 u32temp;
nes_debug(NES_DBG_INIT, "port_count=%d\n", port_count);
nes_write_indexed(nesdev, 0x000001E4, 0x00000007);
/* nes_write_indexed(nesdev, 0x000001E8, 0x000208C4); */
nes_write_indexed(nesdev, 0x000001E8, 0x00020874);
nes_write_indexed(nesdev, 0x000001D8, 0x00048002);
/* nes_write_indexed(nesdev, 0x000001D8, 0x0004B002); */
nes_write_indexed(nesdev, 0x000001FC, 0x00050005);
nes_write_indexed(nesdev, 0x00000600, 0x55555555);
nes_write_indexed(nesdev, 0x00000604, 0x55555555);
/* TODO: move these MAC register settings to NIC bringup */
nes_write_indexed(nesdev, 0x00002000, 0x00000001);
nes_write_indexed(nesdev, 0x00002004, 0x00000001);
nes_write_indexed(nesdev, 0x00002008, 0x0000FFFF);
nes_write_indexed(nesdev, 0x0000200C, 0x00000001);
nes_write_indexed(nesdev, 0x00002010, 0x000003c1);
nes_write_indexed(nesdev, 0x0000201C, 0x75345678);
if (port_count > 1) {
nes_write_indexed(nesdev, 0x00002200, 0x00000001);
nes_write_indexed(nesdev, 0x00002204, 0x00000001);
nes_write_indexed(nesdev, 0x00002208, 0x0000FFFF);
nes_write_indexed(nesdev, 0x0000220C, 0x00000001);
nes_write_indexed(nesdev, 0x00002210, 0x000003c1);
nes_write_indexed(nesdev, 0x0000221C, 0x75345678);
nes_write_indexed(nesdev, 0x00000908, 0x20000001);
}
if (port_count > 2) {
nes_write_indexed(nesdev, 0x00002400, 0x00000001);
nes_write_indexed(nesdev, 0x00002404, 0x00000001);
nes_write_indexed(nesdev, 0x00002408, 0x0000FFFF);
nes_write_indexed(nesdev, 0x0000240C, 0x00000001);
nes_write_indexed(nesdev, 0x00002410, 0x000003c1);
nes_write_indexed(nesdev, 0x0000241C, 0x75345678);
nes_write_indexed(nesdev, 0x00000910, 0x20000001);
nes_write_indexed(nesdev, 0x00002600, 0x00000001);
nes_write_indexed(nesdev, 0x00002604, 0x00000001);
nes_write_indexed(nesdev, 0x00002608, 0x0000FFFF);
nes_write_indexed(nesdev, 0x0000260C, 0x00000001);
nes_write_indexed(nesdev, 0x00002610, 0x000003c1);
nes_write_indexed(nesdev, 0x0000261C, 0x75345678);
nes_write_indexed(nesdev, 0x00000918, 0x20000001);
}
nes_write_indexed(nesdev, 0x00005000, 0x00018000);
/* nes_write_indexed(nesdev, 0x00005000, 0x00010000); */
nes_write_indexed(nesdev, 0x00005004, 0x00020001);
nes_write_indexed(nesdev, 0x00005008, 0x1F1F1F1F);
nes_write_indexed(nesdev, 0x00005010, 0x1F1F1F1F);
nes_write_indexed(nesdev, 0x00005018, 0x1F1F1F1F);
nes_write_indexed(nesdev, 0x00005020, 0x1F1F1F1F);
nes_write_indexed(nesdev, 0x00006090, 0xFFFFFFFF);
/* TODO: move this to code, get from EEPROM */
nes_write_indexed(nesdev, 0x00000900, 0x20000001);
nes_write_indexed(nesdev, 0x000060C0, 0x0000028e);
nes_write_indexed(nesdev, 0x000060C8, 0x00000020);
//
nes_write_indexed(nesdev, 0x000001EC, 0x7b2625a0);
/* nes_write_indexed(nesdev, 0x000001EC, 0x5f2625a0); */
if (hw_rev != NE020_REV) {
u32temp = nes_read_indexed(nesdev, 0x000008e8);
u32temp |= 0x80000000;
nes_write_indexed(nesdev, 0x000008e8, u32temp);
u32temp = nes_read_indexed(nesdev, 0x000021f8);
u32temp &= 0x7fffffff;
u32temp |= 0x7fff0010;
nes_write_indexed(nesdev, 0x000021f8, u32temp);
}
}
/**
* nes_destroy_adapter - destroy the adapter structure
*/
void nes_destroy_adapter(struct nes_adapter *nesadapter)
{
struct nes_adapter *tmp_adapter;
list_for_each_entry(tmp_adapter, &nes_adapter_list, list) {
nes_debug(NES_DBG_SHUTDOWN, "Nes Adapter list entry = 0x%p.\n",
tmp_adapter);
}
nesadapter->ref_count--;
if (!nesadapter->ref_count) {
if (nesadapter->hw_rev == NE020_REV) {
del_timer(&nesadapter->mh_timer);
}
del_timer(&nesadapter->lc_timer);
list_del(&nesadapter->list);
kfree(nesadapter);
}
}
/**
* nes_init_cqp
*/
int nes_init_cqp(struct nes_device *nesdev)
{
struct nes_adapter *nesadapter = nesdev->nesadapter;
struct nes_hw_cqp_qp_context *cqp_qp_context;
struct nes_hw_cqp_wqe *cqp_wqe;
struct nes_hw_ceq *ceq;
struct nes_hw_ceq *nic_ceq;
struct nes_hw_aeq *aeq;
void *vmem;
dma_addr_t pmem;
u32 count=0;
u32 cqp_head;
u64 u64temp;
u32 u32temp;
/* allocate CQP memory */
/* Need to add max_cq to the aeq size once cq overflow checking is added back */
/* SQ is 512 byte aligned, others are 256 byte aligned */
nesdev->cqp_mem_size = 512 +
(sizeof(struct nes_hw_cqp_wqe) * NES_CQP_SQ_SIZE) +
(sizeof(struct nes_hw_cqe) * NES_CCQ_SIZE) +
max(((u32)sizeof(struct nes_hw_ceqe) * NES_CCEQ_SIZE), (u32)256) +
max(((u32)sizeof(struct nes_hw_ceqe) * NES_NIC_CEQ_SIZE), (u32)256) +
(sizeof(struct nes_hw_aeqe) * nesadapter->max_qp) +
sizeof(struct nes_hw_cqp_qp_context);
nesdev->cqp_vbase = pci_alloc_consistent(nesdev->pcidev, nesdev->cqp_mem_size,
&nesdev->cqp_pbase);
if (!nesdev->cqp_vbase) {
nes_debug(NES_DBG_INIT, "Unable to allocate memory for host descriptor rings\n");
return -ENOMEM;
}
memset(nesdev->cqp_vbase, 0, nesdev->cqp_mem_size);
/* Allocate a twice the number of CQP requests as the SQ size */
nesdev->nes_cqp_requests = kzalloc(sizeof(struct nes_cqp_request) *
2 * NES_CQP_SQ_SIZE, GFP_KERNEL);
if (nesdev->nes_cqp_requests == NULL) {
nes_debug(NES_DBG_INIT, "Unable to allocate memory CQP request entries.\n");
pci_free_consistent(nesdev->pcidev, nesdev->cqp_mem_size, nesdev->cqp.sq_vbase,
nesdev->cqp.sq_pbase);
return -ENOMEM;
}
nes_debug(NES_DBG_INIT, "Allocated CQP structures at %p (phys = %016lX), size = %u.\n",
nesdev->cqp_vbase, (unsigned long)nesdev->cqp_pbase, nesdev->cqp_mem_size);
spin_lock_init(&nesdev->cqp.lock);
init_waitqueue_head(&nesdev->cqp.waitq);
/* Setup Various Structures */
vmem = (void *)(((unsigned long)nesdev->cqp_vbase + (512 - 1)) &
~(unsigned long)(512 - 1));
pmem = (dma_addr_t)(((unsigned long long)nesdev->cqp_pbase + (512 - 1)) &
~(unsigned long long)(512 - 1));
nesdev->cqp.sq_vbase = vmem;
nesdev->cqp.sq_pbase = pmem;
nesdev->cqp.sq_size = NES_CQP_SQ_SIZE;
nesdev->cqp.sq_head = 0;
nesdev->cqp.sq_tail = 0;
nesdev->cqp.qp_id = PCI_FUNC(nesdev->pcidev->devfn);
vmem += (sizeof(struct nes_hw_cqp_wqe) * nesdev->cqp.sq_size);
pmem += (sizeof(struct nes_hw_cqp_wqe) * nesdev->cqp.sq_size);
nesdev->ccq.cq_vbase = vmem;
nesdev->ccq.cq_pbase = pmem;
nesdev->ccq.cq_size = NES_CCQ_SIZE;
nesdev->ccq.cq_head = 0;
nesdev->ccq.ce_handler = nes_cqp_ce_handler;
nesdev->ccq.cq_number = PCI_FUNC(nesdev->pcidev->devfn);
vmem += (sizeof(struct nes_hw_cqe) * nesdev->ccq.cq_size);
pmem += (sizeof(struct nes_hw_cqe) * nesdev->ccq.cq_size);
nesdev->ceq_index = PCI_FUNC(nesdev->pcidev->devfn);
ceq = &nesadapter->ceq[nesdev->ceq_index];
ceq->ceq_vbase = vmem;
ceq->ceq_pbase = pmem;
ceq->ceq_size = NES_CCEQ_SIZE;
ceq->ceq_head = 0;
vmem += max(((u32)sizeof(struct nes_hw_ceqe) * ceq->ceq_size), (u32)256);
pmem += max(((u32)sizeof(struct nes_hw_ceqe) * ceq->ceq_size), (u32)256);
nesdev->nic_ceq_index = PCI_FUNC(nesdev->pcidev->devfn) + 8;
nic_ceq = &nesadapter->ceq[nesdev->nic_ceq_index];
nic_ceq->ceq_vbase = vmem;
nic_ceq->ceq_pbase = pmem;
nic_ceq->ceq_size = NES_NIC_CEQ_SIZE;
nic_ceq->ceq_head = 0;
vmem += max(((u32)sizeof(struct nes_hw_ceqe) * nic_ceq->ceq_size), (u32)256);
pmem += max(((u32)sizeof(struct nes_hw_ceqe) * nic_ceq->ceq_size), (u32)256);
aeq = &nesadapter->aeq[PCI_FUNC(nesdev->pcidev->devfn)];
aeq->aeq_vbase = vmem;
aeq->aeq_pbase = pmem;
aeq->aeq_size = nesadapter->max_qp;
aeq->aeq_head = 0;
/* Setup QP Context */
vmem += (sizeof(struct nes_hw_aeqe) * aeq->aeq_size);
pmem += (sizeof(struct nes_hw_aeqe) * aeq->aeq_size);
cqp_qp_context = vmem;
cqp_qp_context->context_words[0] =
cpu_to_le32((PCI_FUNC(nesdev->pcidev->devfn) << 12) + (2 << 10));
cqp_qp_context->context_words[1] = 0;
cqp_qp_context->context_words[2] = cpu_to_le32((u32)nesdev->cqp.sq_pbase);
cqp_qp_context->context_words[3] = cpu_to_le32(((u64)nesdev->cqp.sq_pbase) >> 32);
/* Write the address to Create CQP */
if ((sizeof(dma_addr_t) > 4)) {
nes_write_indexed(nesdev,
NES_IDX_CREATE_CQP_HIGH + (PCI_FUNC(nesdev->pcidev->devfn) * 8),
((u64)pmem) >> 32);
} else {
nes_write_indexed(nesdev,
NES_IDX_CREATE_CQP_HIGH + (PCI_FUNC(nesdev->pcidev->devfn) * 8), 0);
}
nes_write_indexed(nesdev,
NES_IDX_CREATE_CQP_LOW + (PCI_FUNC(nesdev->pcidev->devfn) * 8),
(u32)pmem);
INIT_LIST_HEAD(&nesdev->cqp_avail_reqs);
INIT_LIST_HEAD(&nesdev->cqp_pending_reqs);
for (count = 0; count < 2*NES_CQP_SQ_SIZE; count++) {
init_waitqueue_head(&nesdev->nes_cqp_requests[count].waitq);
list_add_tail(&nesdev->nes_cqp_requests[count].list, &nesdev->cqp_avail_reqs);
}
/* Write Create CCQ WQE */
cqp_head = nesdev->cqp.sq_head++;
cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
(NES_CQP_CREATE_CQ | NES_CQP_CQ_CEQ_VALID |
NES_CQP_CQ_CHK_OVERFLOW | ((u32)nesdev->ccq.cq_size << 16)));
set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX,
(nesdev->ccq.cq_number |
((u32)nesdev->ceq_index << 16)));
u64temp = (u64)nesdev->ccq.cq_pbase;
set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_CQ_WQE_PBL_LOW_IDX, u64temp);
cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] = 0;
u64temp = (unsigned long)&nesdev->ccq;
cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_LOW_IDX] =
cpu_to_le32((u32)(u64temp >> 1));
cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] =
cpu_to_le32(((u32)((u64temp) >> 33)) & 0x7FFFFFFF);
cqp_wqe->wqe_words[NES_CQP_CQ_WQE_DOORBELL_INDEX_HIGH_IDX] = 0;
/* Write Create CEQ WQE */
cqp_head = nesdev->cqp.sq_head++;
cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
(NES_CQP_CREATE_CEQ + ((u32)nesdev->ceq_index << 8)));
set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_CEQ_WQE_ELEMENT_COUNT_IDX, ceq->ceq_size);
u64temp = (u64)ceq->ceq_pbase;
set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_CQ_WQE_PBL_LOW_IDX, u64temp);
/* Write Create AEQ WQE */
cqp_head = nesdev->cqp.sq_head++;
cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
(NES_CQP_CREATE_AEQ + ((u32)PCI_FUNC(nesdev->pcidev->devfn) << 8)));
set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_AEQ_WQE_ELEMENT_COUNT_IDX, aeq->aeq_size);
u64temp = (u64)aeq->aeq_pbase;
set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_CQ_WQE_PBL_LOW_IDX, u64temp);
/* Write Create NIC CEQ WQE */
cqp_head = nesdev->cqp.sq_head++;
cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
(NES_CQP_CREATE_CEQ + ((u32)nesdev->nic_ceq_index << 8)));
set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_CEQ_WQE_ELEMENT_COUNT_IDX, nic_ceq->ceq_size);
u64temp = (u64)nic_ceq->ceq_pbase;
set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_CQ_WQE_PBL_LOW_IDX, u64temp);
/* Poll until CCQP done */
count = 0;
do {
if (count++ > 1000) {
printk(KERN_ERR PFX "Error creating CQP\n");
pci_free_consistent(nesdev->pcidev, nesdev->cqp_mem_size,
nesdev->cqp_vbase, nesdev->cqp_pbase);
return -1;
}
udelay(10);
} while (!(nes_read_indexed(nesdev,
NES_IDX_QP_CONTROL + (PCI_FUNC(nesdev->pcidev->devfn) * 8)) & (1 << 8)));
nes_debug(NES_DBG_INIT, "CQP Status = 0x%08X\n", nes_read_indexed(nesdev,
NES_IDX_QP_CONTROL+(PCI_FUNC(nesdev->pcidev->devfn)*8)));
u32temp = 0x04800000;
nes_write32(nesdev->regs+NES_WQE_ALLOC, u32temp | nesdev->cqp.qp_id);
/* wait for the CCQ, CEQ, and AEQ to get created */
count = 0;
do {
if (count++ > 1000) {
printk(KERN_ERR PFX "Error creating CCQ, CEQ, and AEQ\n");
pci_free_consistent(nesdev->pcidev, nesdev->cqp_mem_size,
nesdev->cqp_vbase, nesdev->cqp_pbase);
return -1;
}
udelay(10);
} while (((nes_read_indexed(nesdev,
NES_IDX_QP_CONTROL+(PCI_FUNC(nesdev->pcidev->devfn)*8)) & (15<<8)) != (15<<8)));
/* dump the QP status value */
nes_debug(NES_DBG_INIT, "QP Status = 0x%08X\n", nes_read_indexed(nesdev,
NES_IDX_QP_CONTROL+(PCI_FUNC(nesdev->pcidev->devfn)*8)));
nesdev->cqp.sq_tail++;
return 0;
}
/**
* nes_destroy_cqp
*/
int nes_destroy_cqp(struct nes_device *nesdev)
{
struct nes_hw_cqp_wqe *cqp_wqe;
u32 count = 0;
u32 cqp_head;
unsigned long flags;
do {
if (count++ > 1000)
break;
udelay(10);
} while (!(nesdev->cqp.sq_head == nesdev->cqp.sq_tail));
/* Reset CCQ */
nes_write32(nesdev->regs+NES_CQE_ALLOC, NES_CQE_ALLOC_RESET |
nesdev->ccq.cq_number);
/* Disable device interrupts */
nes_write32(nesdev->regs+NES_INT_MASK, 0x7fffffff);
spin_lock_irqsave(&nesdev->cqp.lock, flags);
/* Destroy the AEQ */
cqp_head = nesdev->cqp.sq_head++;
nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_AEQ |
((u32)PCI_FUNC(nesdev->pcidev->devfn) << 8));
cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] = 0;
/* Destroy the NIC CEQ */
cqp_head = nesdev->cqp.sq_head++;
nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_CEQ |
((u32)nesdev->nic_ceq_index << 8));
/* Destroy the CEQ */
cqp_head = nesdev->cqp.sq_head++;
nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_CEQ |
(nesdev->ceq_index << 8));
/* Destroy the CCQ */
cqp_head = nesdev->cqp.sq_head++;
nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_CQ);
cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(nesdev->ccq.cq_number |
((u32)nesdev->ceq_index << 16));
/* Destroy CQP */
cqp_head = nesdev->cqp.sq_head++;
nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_QP |
NES_CQP_QP_TYPE_CQP);
cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(nesdev->cqp.qp_id);
barrier();
/* Ring doorbell (5 WQEs) */
nes_write32(nesdev->regs+NES_WQE_ALLOC, 0x05800000 | nesdev->cqp.qp_id);
spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
/* wait for the CCQ, CEQ, and AEQ to get destroyed */
count = 0;
do {
if (count++ > 1000) {
printk(KERN_ERR PFX "Function%d: Error destroying CCQ, CEQ, and AEQ\n",
PCI_FUNC(nesdev->pcidev->devfn));
break;
}
udelay(10);
} while (((nes_read_indexed(nesdev,
NES_IDX_QP_CONTROL + (PCI_FUNC(nesdev->pcidev->devfn)*8)) & (15 << 8)) != 0));
/* dump the QP status value */
nes_debug(NES_DBG_SHUTDOWN, "Function%d: QP Status = 0x%08X\n",
PCI_FUNC(nesdev->pcidev->devfn),
nes_read_indexed(nesdev,
NES_IDX_QP_CONTROL+(PCI_FUNC(nesdev->pcidev->devfn)*8)));
kfree(nesdev->nes_cqp_requests);
/* Free the control structures */
pci_free_consistent(nesdev->pcidev, nesdev->cqp_mem_size, nesdev->cqp.sq_vbase,
nesdev->cqp.sq_pbase);
return 0;
}
/**
* nes_init_phy
*/
int nes_init_phy(struct nes_device *nesdev)
{
struct nes_adapter *nesadapter = nesdev->nesadapter;
u32 counter = 0;
u32 mac_index = nesdev->mac_index;
u32 tx_config;
u16 phy_data;
if (nesadapter->OneG_Mode) {
nes_debug(NES_DBG_PHY, "1G PHY, mac_index = %d.\n", mac_index);
if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_1G) {
printk(PFX "%s: Programming mdc config for 1G\n", __func__);
tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG);
tx_config |= 0x04;
nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config);
}
nes_read_1G_phy_reg(nesdev, 1, nesadapter->phy_index[mac_index], &phy_data);
nes_debug(NES_DBG_PHY, "Phy data from register 1 phy address %u = 0x%X.\n",
nesadapter->phy_index[mac_index], phy_data);
nes_write_1G_phy_reg(nesdev, 23, nesadapter->phy_index[mac_index], 0xb000);
/* Reset the PHY */
nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], 0x8000);
udelay(100);
counter = 0;
do {
nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], &phy_data);
nes_debug(NES_DBG_PHY, "Phy data from register 0 = 0x%X.\n", phy_data);
if (counter++ > 100) break;
} while (phy_data & 0x8000);
/* Setting no phy loopback */
phy_data &= 0xbfff;
phy_data |= 0x1140;
nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], phy_data);
nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], &phy_data);
nes_debug(NES_DBG_PHY, "Phy data from register 0 = 0x%X.\n", phy_data);
nes_read_1G_phy_reg(nesdev, 0x17, nesadapter->phy_index[mac_index], &phy_data);
nes_debug(NES_DBG_PHY, "Phy data from register 0x17 = 0x%X.\n", phy_data);
nes_read_1G_phy_reg(nesdev, 0x1e, nesadapter->phy_index[mac_index], &phy_data);
nes_debug(NES_DBG_PHY, "Phy data from register 0x1e = 0x%X.\n", phy_data);
/* Setting the interrupt mask */
nes_read_1G_phy_reg(nesdev, 0x19, nesadapter->phy_index[mac_index], &phy_data);
nes_debug(NES_DBG_PHY, "Phy data from register 0x19 = 0x%X.\n", phy_data);
nes_write_1G_phy_reg(nesdev, 0x19, nesadapter->phy_index[mac_index], 0xffee);
nes_read_1G_phy_reg(nesdev, 0x19, nesadapter->phy_index[mac_index], &phy_data);
nes_debug(NES_DBG_PHY, "Phy data from register 0x19 = 0x%X.\n", phy_data);
/* turning on flow control */
nes_read_1G_phy_reg(nesdev, 4, nesadapter->phy_index[mac_index], &phy_data);
nes_debug(NES_DBG_PHY, "Phy data from register 0x4 = 0x%X.\n", phy_data);
nes_write_1G_phy_reg(nesdev, 4, nesadapter->phy_index[mac_index],
(phy_data & ~(0x03E0)) | 0xc00);
/* nes_write_1G_phy_reg(nesdev, 4, nesadapter->phy_index[mac_index],
phy_data | 0xc00); */
nes_read_1G_phy_reg(nesdev, 4, nesadapter->phy_index[mac_index], &phy_data);
nes_debug(NES_DBG_PHY, "Phy data from register 0x4 = 0x%X.\n", phy_data);
nes_read_1G_phy_reg(nesdev, 9, nesadapter->phy_index[mac_index], &phy_data);
nes_debug(NES_DBG_PHY, "Phy data from register 0x9 = 0x%X.\n", phy_data);
/* Clear Half duplex */
nes_write_1G_phy_reg(nesdev, 9, nesadapter->phy_index[mac_index],
phy_data & ~(0x0100));
nes_read_1G_phy_reg(nesdev, 9, nesadapter->phy_index[mac_index], &phy_data);
nes_debug(NES_DBG_PHY, "Phy data from register 0x9 = 0x%X.\n", phy_data);
nes_read_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], &phy_data);
nes_write_1G_phy_reg(nesdev, 0, nesadapter->phy_index[mac_index], phy_data | 0x0300);
} else {
if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_IRIS) {
/* setup 10G MDIO operation */
tx_config = nes_read_indexed(nesdev, NES_IDX_MAC_TX_CONFIG);
tx_config |= 0x14;
nes_write_indexed(nesdev, NES_IDX_MAC_TX_CONFIG, tx_config);
}
}
return 0;
}
/**
* nes_replenish_nic_rq
*/
static void nes_replenish_nic_rq(struct nes_vnic *nesvnic)
{
unsigned long flags;
dma_addr_t bus_address;
struct sk_buff *skb;
struct nes_hw_nic_rq_wqe *nic_rqe;
struct nes_hw_nic *nesnic;
struct nes_device *nesdev;
u32 rx_wqes_posted = 0;
nesnic = &nesvnic->nic;
nesdev = nesvnic->nesdev;
spin_lock_irqsave(&nesnic->rq_lock, flags);
if (nesnic->replenishing_rq !=0) {
if (((nesnic->rq_size-1) == atomic_read(&nesvnic->rx_skbs_needed)) &&
(atomic_read(&nesvnic->rx_skb_timer_running) == 0)) {
atomic_set(&nesvnic->rx_skb_timer_running, 1);
spin_unlock_irqrestore(&nesnic->rq_lock, flags);
nesvnic->rq_wqes_timer.expires = jiffies + (HZ/2); /* 1/2 second */
add_timer(&nesvnic->rq_wqes_timer);
} else
spin_unlock_irqrestore(&nesnic->rq_lock, flags);
return;
}
nesnic->replenishing_rq = 1;
spin_unlock_irqrestore(&nesnic->rq_lock, flags);
do {
skb = dev_alloc_skb(nesvnic->max_frame_size);
if (skb) {
skb->dev = nesvnic->netdev;
bus_address = pci_map_single(nesdev->pcidev,
skb->data, nesvnic->max_frame_size, PCI_DMA_FROMDEVICE);
nic_rqe = &nesnic->rq_vbase[nesvnic->nic.rq_head];
nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_1_0_IDX] =
cpu_to_le32(nesvnic->max_frame_size);
nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_3_2_IDX] = 0;
nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX] =
cpu_to_le32((u32)bus_address);
nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX] =
cpu_to_le32((u32)((u64)bus_address >> 32));
nesnic->rx_skb[nesnic->rq_head] = skb;
nesnic->rq_head++;
nesnic->rq_head &= nesnic->rq_size - 1;
atomic_dec(&nesvnic->rx_skbs_needed);
barrier();
if (++rx_wqes_posted == 255) {
nes_write32(nesdev->regs+NES_WQE_ALLOC, (rx_wqes_posted << 24) | nesnic->qp_id);
rx_wqes_posted = 0;
}
} else {
spin_lock_irqsave(&nesnic->rq_lock, flags);
if (((nesnic->rq_size-1) == atomic_read(&nesvnic->rx_skbs_needed)) &&
(atomic_read(&nesvnic->rx_skb_timer_running) == 0)) {
atomic_set(&nesvnic->rx_skb_timer_running, 1);
spin_unlock_irqrestore(&nesnic->rq_lock, flags);
nesvnic->rq_wqes_timer.expires = jiffies + (HZ/2); /* 1/2 second */
add_timer(&nesvnic->rq_wqes_timer);
} else
spin_unlock_irqrestore(&nesnic->rq_lock, flags);
break;
}
} while (atomic_read(&nesvnic->rx_skbs_needed));
barrier();
if (rx_wqes_posted)
nes_write32(nesdev->regs+NES_WQE_ALLOC, (rx_wqes_posted << 24) | nesnic->qp_id);
nesnic->replenishing_rq = 0;
}
/**
* nes_rq_wqes_timeout
*/
static void nes_rq_wqes_timeout(unsigned long parm)
{
struct nes_vnic *nesvnic = (struct nes_vnic *)parm;
printk("%s: Timer fired.\n", __func__);
atomic_set(&nesvnic->rx_skb_timer_running, 0);
if (atomic_read(&nesvnic->rx_skbs_needed))
nes_replenish_nic_rq(nesvnic);
}
/**
* nes_init_nic_qp
*/
int nes_init_nic_qp(struct nes_device *nesdev, struct net_device *netdev)
{
struct nes_hw_cqp_wqe *cqp_wqe;
struct nes_hw_nic_sq_wqe *nic_sqe;
struct nes_hw_nic_qp_context *nic_context;
struct sk_buff *skb;
struct nes_hw_nic_rq_wqe *nic_rqe;
struct nes_vnic *nesvnic = netdev_priv(netdev);
unsigned long flags;
void *vmem;
dma_addr_t pmem;
u64 u64temp;
int ret;
u32 cqp_head;
u32 counter;
u32 wqe_count;
u8 jumbomode=0;
/* Allocate fragment, SQ, RQ, and CQ; Reuse CEQ based on the PCI function */
nesvnic->nic_mem_size = 256 +
(NES_NIC_WQ_SIZE * sizeof(struct nes_first_frag)) +
(NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_sq_wqe)) +
(NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_rq_wqe)) +
(NES_NIC_WQ_SIZE * 2 * sizeof(struct nes_hw_nic_cqe)) +
sizeof(struct nes_hw_nic_qp_context);
nesvnic->nic_vbase = pci_alloc_consistent(nesdev->pcidev, nesvnic->nic_mem_size,
&nesvnic->nic_pbase);
if (!nesvnic->nic_vbase) {
nes_debug(NES_DBG_INIT, "Unable to allocate memory for NIC host descriptor rings\n");
return -ENOMEM;
}
memset(nesvnic->nic_vbase, 0, nesvnic->nic_mem_size);
nes_debug(NES_DBG_INIT, "Allocated NIC QP structures at %p (phys = %016lX), size = %u.\n",
nesvnic->nic_vbase, (unsigned long)nesvnic->nic_pbase, nesvnic->nic_mem_size);
vmem = (void *)(((unsigned long)nesvnic->nic_vbase + (256 - 1)) &
~(unsigned long)(256 - 1));
pmem = (dma_addr_t)(((unsigned long long)nesvnic->nic_pbase + (256 - 1)) &
~(unsigned long long)(256 - 1));
/* Setup the first Fragment buffers */
nesvnic->nic.first_frag_vbase = vmem;
for (counter = 0; counter < NES_NIC_WQ_SIZE; counter++) {
nesvnic->nic.frag_paddr[counter] = pmem;
pmem += sizeof(struct nes_first_frag);
}
/* setup the SQ */
vmem += (NES_NIC_WQ_SIZE * sizeof(struct nes_first_frag));
nesvnic->nic.sq_vbase = (void *)vmem;
nesvnic->nic.sq_pbase = pmem;
nesvnic->nic.sq_head = 0;
nesvnic->nic.sq_tail = 0;
nesvnic->nic.sq_size = NES_NIC_WQ_SIZE;
for (counter = 0; counter < NES_NIC_WQ_SIZE; counter++) {
nic_sqe = &nesvnic->nic.sq_vbase[counter];
nic_sqe->wqe_words[NES_NIC_SQ_WQE_MISC_IDX] =
cpu_to_le32(NES_NIC_SQ_WQE_DISABLE_CHKSUM |
NES_NIC_SQ_WQE_COMPLETION);
nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_0_TAG_IDX] =
cpu_to_le32((u32)NES_FIRST_FRAG_SIZE << 16);
nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX] =
cpu_to_le32((u32)nesvnic->nic.frag_paddr[counter]);
nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX] =
cpu_to_le32((u32)((u64)nesvnic->nic.frag_paddr[counter] >> 32));
}
nesvnic->get_cqp_request = nes_get_cqp_request;
nesvnic->post_cqp_request = nes_post_cqp_request;
nesvnic->mcrq_mcast_filter = NULL;
spin_lock_init(&nesvnic->nic.sq_lock);
spin_lock_init(&nesvnic->nic.rq_lock);
/* setup the RQ */
vmem += (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_sq_wqe));
pmem += (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_sq_wqe));
nesvnic->nic.rq_vbase = vmem;
nesvnic->nic.rq_pbase = pmem;
nesvnic->nic.rq_head = 0;
nesvnic->nic.rq_tail = 0;
nesvnic->nic.rq_size = NES_NIC_WQ_SIZE;
/* setup the CQ */
vmem += (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_rq_wqe));
pmem += (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_rq_wqe));
if (nesdev->nesadapter->netdev_count > 2)
nesvnic->mcrq_qp_id = nesvnic->nic_index + 32;
else
nesvnic->mcrq_qp_id = nesvnic->nic.qp_id + 4;
nesvnic->nic_cq.cq_vbase = vmem;
nesvnic->nic_cq.cq_pbase = pmem;
nesvnic->nic_cq.cq_head = 0;
nesvnic->nic_cq.cq_size = NES_NIC_WQ_SIZE * 2;
nesvnic->nic_cq.ce_handler = nes_nic_napi_ce_handler;
/* Send CreateCQ request to CQP */
spin_lock_irqsave(&nesdev->cqp.lock, flags);
cqp_head = nesdev->cqp.sq_head;
cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(
NES_CQP_CREATE_CQ | NES_CQP_CQ_CEQ_VALID |
((u32)nesvnic->nic_cq.cq_size << 16));
cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(
nesvnic->nic_cq.cq_number | ((u32)nesdev->nic_ceq_index << 16));
u64temp = (u64)nesvnic->nic_cq.cq_pbase;
set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_CQ_WQE_PBL_LOW_IDX, u64temp);
cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] = 0;
u64temp = (unsigned long)&nesvnic->nic_cq;
cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_LOW_IDX] = cpu_to_le32((u32)(u64temp >> 1));
cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] =
cpu_to_le32(((u32)((u64temp) >> 33)) & 0x7FFFFFFF);
cqp_wqe->wqe_words[NES_CQP_CQ_WQE_DOORBELL_INDEX_HIGH_IDX] = 0;
if (++cqp_head >= nesdev->cqp.sq_size)
cqp_head = 0;
cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
/* Send CreateQP request to CQP */
nic_context = (void *)(&nesvnic->nic_cq.cq_vbase[nesvnic->nic_cq.cq_size]);
nic_context->context_words[NES_NIC_CTX_MISC_IDX] =
cpu_to_le32((u32)NES_NIC_CTX_SIZE |
((u32)PCI_FUNC(nesdev->pcidev->devfn) << 12));
nes_debug(NES_DBG_INIT, "RX_WINDOW_BUFFER_PAGE_TABLE_SIZE = 0x%08X, RX_WINDOW_BUFFER_SIZE = 0x%08X\n",
nes_read_indexed(nesdev, NES_IDX_RX_WINDOW_BUFFER_PAGE_TABLE_SIZE),
nes_read_indexed(nesdev, NES_IDX_RX_WINDOW_BUFFER_SIZE));
if (nes_read_indexed(nesdev, NES_IDX_RX_WINDOW_BUFFER_SIZE) != 0) {
nic_context->context_words[NES_NIC_CTX_MISC_IDX] |= cpu_to_le32(NES_NIC_BACK_STORE);
}
u64temp = (u64)nesvnic->nic.sq_pbase;
nic_context->context_words[NES_NIC_CTX_SQ_LOW_IDX] = cpu_to_le32((u32)u64temp);
nic_context->context_words[NES_NIC_CTX_SQ_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32));
u64temp = (u64)nesvnic->nic.rq_pbase;
nic_context->context_words[NES_NIC_CTX_RQ_LOW_IDX] = cpu_to_le32((u32)u64temp);
nic_context->context_words[NES_NIC_CTX_RQ_HIGH_IDX] = cpu_to_le32((u32)(u64temp >> 32));
cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_CREATE_QP |
NES_CQP_QP_TYPE_NIC);
cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(nesvnic->nic.qp_id);
u64temp = (u64)nesvnic->nic_cq.cq_pbase +
(nesvnic->nic_cq.cq_size * sizeof(struct nes_hw_nic_cqe));
set_wqe_64bit_value(cqp_wqe->wqe_words, NES_CQP_QP_WQE_CONTEXT_LOW_IDX, u64temp);
if (++cqp_head >= nesdev->cqp.sq_size)
cqp_head = 0;
nesdev->cqp.sq_head = cqp_head;
barrier();
/* Ring doorbell (2 WQEs) */
nes_write32(nesdev->regs+NES_WQE_ALLOC, 0x02800000 | nesdev->cqp.qp_id);
spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
nes_debug(NES_DBG_INIT, "Waiting for create NIC QP%u to complete.\n",
nesvnic->nic.qp_id);
ret = wait_event_timeout(nesdev->cqp.waitq, (nesdev->cqp.sq_tail == cqp_head),
NES_EVENT_TIMEOUT);
nes_debug(NES_DBG_INIT, "Create NIC QP%u completed, wait_event_timeout ret = %u.\n",
nesvnic->nic.qp_id, ret);
if (!ret) {
nes_debug(NES_DBG_INIT, "NIC QP%u create timeout expired\n", nesvnic->nic.qp_id);
pci_free_consistent(nesdev->pcidev, nesvnic->nic_mem_size, nesvnic->nic_vbase,
nesvnic->nic_pbase);
return -EIO;
}
/* Populate the RQ */
for (counter = 0; counter < (NES_NIC_WQ_SIZE - 1); counter++) {
skb = dev_alloc_skb(nesvnic->max_frame_size);
if (!skb) {
nes_debug(NES_DBG_INIT, "%s: out of memory for receive skb\n", netdev->name);
nes_destroy_nic_qp(nesvnic);
return -ENOMEM;
}
skb->dev = netdev;
pmem = pci_map_single(nesdev->pcidev, skb->data,
nesvnic->max_frame_size, PCI_DMA_FROMDEVICE);
nic_rqe = &nesvnic->nic.rq_vbase[counter];
nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_1_0_IDX] = cpu_to_le32(nesvnic->max_frame_size);
nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_3_2_IDX] = 0;
nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX] = cpu_to_le32((u32)pmem);
nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX] = cpu_to_le32((u32)((u64)pmem >> 32));
nesvnic->nic.rx_skb[counter] = skb;
}
wqe_count = NES_NIC_WQ_SIZE - 1;
nesvnic->nic.rq_head = wqe_count;
barrier();
do {
counter = min(wqe_count, ((u32)255));
wqe_count -= counter;
nes_write32(nesdev->regs+NES_WQE_ALLOC, (counter << 24) | nesvnic->nic.qp_id);
} while (wqe_count);
init_timer(&nesvnic->rq_wqes_timer);
nesvnic->rq_wqes_timer.function = nes_rq_wqes_timeout;
nesvnic->rq_wqes_timer.data = (unsigned long)nesvnic;
nes_debug(NES_DBG_INIT, "NAPI support Enabled\n");
if (nesdev->nesadapter->et_use_adaptive_rx_coalesce)
{
nes_nic_init_timer(nesdev);
if (netdev->mtu > 1500)
jumbomode = 1;
nes_nic_init_timer_defaults(nesdev, jumbomode);
}
return 0;
}
/**
* nes_destroy_nic_qp
*/
void nes_destroy_nic_qp(struct nes_vnic *nesvnic)
{
struct nes_device *nesdev = nesvnic->nesdev;
struct nes_hw_cqp_wqe *cqp_wqe;
struct nes_hw_nic_rq_wqe *nic_rqe;
u64 wqe_frag;
u32 cqp_head;
unsigned long flags;
int ret;
/* Free remaining NIC receive buffers */
while (nesvnic->nic.rq_head != nesvnic->nic.rq_tail) {
nic_rqe = &nesvnic->nic.rq_vbase[nesvnic->nic.rq_tail];
wqe_frag = (u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX]);
wqe_frag |= ((u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX])) << 32;
pci_unmap_single(nesdev->pcidev, (dma_addr_t)wqe_frag,
nesvnic->max_frame_size, PCI_DMA_FROMDEVICE);
dev_kfree_skb(nesvnic->nic.rx_skb[nesvnic->nic.rq_tail++]);
nesvnic->nic.rq_tail &= (nesvnic->nic.rq_size - 1);
}
spin_lock_irqsave(&nesdev->cqp.lock, flags);
/* Destroy NIC QP */
cqp_head = nesdev->cqp.sq_head;
cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
(NES_CQP_DESTROY_QP | NES_CQP_QP_TYPE_NIC));
set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX,
nesvnic->nic.qp_id);
if (++cqp_head >= nesdev->cqp.sq_size)
cqp_head = 0;
cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
/* Destroy NIC CQ */
nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX,
(NES_CQP_DESTROY_CQ | ((u32)nesvnic->nic_cq.cq_size << 16)));
set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX,
(nesvnic->nic_cq.cq_number | ((u32)nesdev->nic_ceq_index << 16)));
if (++cqp_head >= nesdev->cqp.sq_size)
cqp_head = 0;
nesdev->cqp.sq_head = cqp_head;
barrier();
/* Ring doorbell (2 WQEs) */
nes_write32(nesdev->regs+NES_WQE_ALLOC, 0x02800000 | nesdev->cqp.qp_id);
spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
nes_debug(NES_DBG_SHUTDOWN, "Waiting for CQP, cqp_head=%u, cqp.sq_head=%u,"
" cqp.sq_tail=%u, cqp.sq_size=%u\n",
cqp_head, nesdev->cqp.sq_head,
nesdev->cqp.sq_tail, nesdev->cqp.sq_size);
ret = wait_event_timeout(nesdev->cqp.waitq, (nesdev->cqp.sq_tail == cqp_head),
NES_EVENT_TIMEOUT);
nes_debug(NES_DBG_SHUTDOWN, "Destroy NIC QP returned, wait_event_timeout ret = %u, cqp_head=%u,"
" cqp.sq_head=%u, cqp.sq_tail=%u\n",
ret, cqp_head, nesdev->cqp.sq_head, nesdev->cqp.sq_tail);
if (!ret) {
nes_debug(NES_DBG_SHUTDOWN, "NIC QP%u destroy timeout expired\n",
nesvnic->nic.qp_id);
}
pci_free_consistent(nesdev->pcidev, nesvnic->nic_mem_size, nesvnic->nic_vbase,
nesvnic->nic_pbase);
}
/**
* nes_napi_isr
*/
int nes_napi_isr(struct nes_device *nesdev)
{
struct nes_adapter *nesadapter = nesdev->nesadapter;
u32 int_stat;
if (nesdev->napi_isr_ran) {
/* interrupt status has already been read in ISR */
int_stat = nesdev->int_stat;
} else {
int_stat = nes_read32(nesdev->regs + NES_INT_STAT);
nesdev->int_stat = int_stat;
nesdev->napi_isr_ran = 1;
}
int_stat &= nesdev->int_req;
/* iff NIC, process here, else wait for DPC */
if ((int_stat) && ((int_stat & 0x0000ff00) == int_stat)) {
nesdev->napi_isr_ran = 0;
nes_write32(nesdev->regs+NES_INT_STAT,
(int_stat &
~(NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0|NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3)));
/* Process the CEQs */
nes_process_ceq(nesdev, &nesdev->nesadapter->ceq[nesdev->nic_ceq_index]);
if (unlikely((((nesadapter->et_rx_coalesce_usecs_irq) &&
(!nesadapter->et_use_adaptive_rx_coalesce)) ||
((nesadapter->et_use_adaptive_rx_coalesce) &&
(nesdev->deepcq_count > nesadapter->et_pkt_rate_low)))) ) {
if ((nesdev->int_req & NES_INT_TIMER) == 0) {
/* Enable Periodic timer interrupts */
nesdev->int_req |= NES_INT_TIMER;
/* ack any pending periodic timer interrupts so we don't get an immediate interrupt */
/* TODO: need to also ack other unused periodic timer values, get from nesadapter */
nes_write32(nesdev->regs+NES_TIMER_STAT,
nesdev->timer_int_req | ~(nesdev->nesadapter->timer_int_req));
nes_write32(nesdev->regs+NES_INTF_INT_MASK,
~(nesdev->intf_int_req | NES_INTF_PERIODIC_TIMER));
}
if (unlikely(nesadapter->et_use_adaptive_rx_coalesce))
{
nes_nic_init_timer(nesdev);
}
/* Enable interrupts, except CEQs */
nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff | (~nesdev->int_req));
} else {
/* Enable interrupts, make sure timer is off */
nesdev->int_req &= ~NES_INT_TIMER;
nes_write32(nesdev->regs+NES_INTF_INT_MASK, ~(nesdev->intf_int_req));
nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
}
nesdev->deepcq_count = 0;
return 1;
} else {
return 0;
}
}
/**
* nes_dpc
*/
void nes_dpc(unsigned long param)
{
struct nes_device *nesdev = (struct nes_device *)param;
struct nes_adapter *nesadapter = nesdev->nesadapter;
u32 counter;
u32 loop_counter = 0;
u32 int_status_bit;
u32 int_stat;
u32 timer_stat;
u32 temp_int_stat;
u32 intf_int_stat;
u32 debug_error;
u32 processed_intf_int = 0;
u16 processed_timer_int = 0;
u16 completion_ints = 0;
u16 timer_ints = 0;
/* nes_debug(NES_DBG_ISR, "\n"); */
do {
timer_stat = 0;
if (nesdev->napi_isr_ran) {
nesdev->napi_isr_ran = 0;
int_stat = nesdev->int_stat;
} else
int_stat = nes_read32(nesdev->regs+NES_INT_STAT);
if (processed_intf_int != 0)
int_stat &= nesdev->int_req & ~NES_INT_INTF;
else
int_stat &= nesdev->int_req;
if (processed_timer_int == 0) {
processed_timer_int = 1;
if (int_stat & NES_INT_TIMER) {
timer_stat = nes_read32(nesdev->regs + NES_TIMER_STAT);
if ((timer_stat & nesdev->timer_int_req) == 0) {
int_stat &= ~NES_INT_TIMER;
}
}
} else {
int_stat &= ~NES_INT_TIMER;
}
if (int_stat) {
if (int_stat & ~(NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0|
NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3)) {
/* Ack the interrupts */
nes_write32(nesdev->regs+NES_INT_STAT,
(int_stat & ~(NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0|
NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3)));
}
temp_int_stat = int_stat;
for (counter = 0, int_status_bit = 1; counter < 16; counter++) {
if (int_stat & int_status_bit) {
nes_process_ceq(nesdev, &nesadapter->ceq[counter]);
temp_int_stat &= ~int_status_bit;
completion_ints = 1;
}
if (!(temp_int_stat & 0x0000ffff))
break;
int_status_bit <<= 1;
}
/* Process the AEQ for this pci function */
int_status_bit = 1 << (16 + PCI_FUNC(nesdev->pcidev->devfn));
if (int_stat & int_status_bit) {
nes_process_aeq(nesdev, &nesadapter->aeq[PCI_FUNC(nesdev->pcidev->devfn)]);
}
/* Process the MAC interrupt for this pci function */
int_status_bit = 1 << (24 + nesdev->mac_index);
if (int_stat & int_status_bit) {
nes_process_mac_intr(nesdev, nesdev->mac_index);
}
if (int_stat & NES_INT_TIMER) {
if (timer_stat & nesdev->timer_int_req) {
nes_write32(nesdev->regs + NES_TIMER_STAT,
(timer_stat & nesdev->timer_int_req) |
~(nesdev->nesadapter->timer_int_req));
timer_ints = 1;
}
}
if (int_stat & NES_INT_INTF) {
processed_intf_int = 1;
intf_int_stat = nes_read32(nesdev->regs+NES_INTF_INT_STAT);
intf_int_stat &= nesdev->intf_int_req;
if (NES_INTF_INT_CRITERR & intf_int_stat) {
debug_error = nes_read_indexed(nesdev, NES_IDX_DEBUG_ERROR_CONTROL_STATUS);
printk(KERN_ERR PFX "Critical Error reported by device!!! 0x%02X\n",
(u16)debug_error);
nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_CONTROL_STATUS,
0x01010000 | (debug_error & 0x0000ffff));
/* BUG(); */
if (crit_err_count++ > 10)
nes_write_indexed(nesdev, NES_IDX_DEBUG_ERROR_MASKS1, 1 << 0x17);
}
if (NES_INTF_INT_PCIERR & intf_int_stat) {
printk(KERN_ERR PFX "PCI Error reported by device!!!\n");
BUG();
}
if (NES_INTF_INT_AEQ_OFLOW & intf_int_stat) {
printk(KERN_ERR PFX "AEQ Overflow reported by device!!!\n");
BUG();
}
nes_write32(nesdev->regs+NES_INTF_INT_STAT, intf_int_stat);
}
if (int_stat & NES_INT_TSW) {
}
}
/* Don't use the interface interrupt bit stay in loop */
int_stat &= ~NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0|
NES_INT_MAC1|NES_INT_MAC2|NES_INT_MAC3;
} while ((int_stat != 0) && (loop_counter++ < MAX_DPC_ITERATIONS));
if (timer_ints == 1) {
if ((nesadapter->et_rx_coalesce_usecs_irq) || (nesadapter->et_use_adaptive_rx_coalesce)) {
if (completion_ints == 0) {
nesdev->timer_only_int_count++;
if (nesdev->timer_only_int_count>=nesadapter->timer_int_limit) {
nesdev->timer_only_int_count = 0;
nesdev->int_req &= ~NES_INT_TIMER;
nes_write32(nesdev->regs + NES_INTF_INT_MASK, ~(nesdev->intf_int_req));
nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
} else {
nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff|(~nesdev->int_req));
}
} else {
if (unlikely(nesadapter->et_use_adaptive_rx_coalesce))
{
nes_nic_init_timer(nesdev);
}
nesdev->timer_only_int_count = 0;
nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff|(~nesdev->int_req));
}
} else {
nesdev->timer_only_int_count = 0;
nesdev->int_req &= ~NES_INT_TIMER;
nes_write32(nesdev->regs+NES_INTF_INT_MASK, ~(nesdev->intf_int_req));
nes_write32(nesdev->regs+NES_TIMER_STAT,
nesdev->timer_int_req | ~(nesdev->nesadapter->timer_int_req));
nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
}
} else {
if ( (completion_ints == 1) &&
(((nesadapter->et_rx_coalesce_usecs_irq) &&
(!nesadapter->et_use_adaptive_rx_coalesce)) ||
((nesdev->deepcq_count > nesadapter->et_pkt_rate_low) &&
(nesadapter->et_use_adaptive_rx_coalesce) )) ) {
/* nes_debug(NES_DBG_ISR, "Enabling periodic timer interrupt.\n" ); */
nesdev->timer_only_int_count = 0;
nesdev->int_req |= NES_INT_TIMER;
nes_write32(nesdev->regs+NES_TIMER_STAT,
nesdev->timer_int_req | ~(nesdev->nesadapter->timer_int_req));
nes_write32(nesdev->regs+NES_INTF_INT_MASK,
~(nesdev->intf_int_req | NES_INTF_PERIODIC_TIMER));
nes_write32(nesdev->regs+NES_INT_MASK, 0x0000ffff | (~nesdev->int_req));
} else {
nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
}
}
nesdev->deepcq_count = 0;
}
/**
* nes_process_ceq
*/
static void nes_process_ceq(struct nes_device *nesdev, struct nes_hw_ceq *ceq)
{
u64 u64temp;
struct nes_hw_cq *cq;
u32 head;
u32 ceq_size;
/* nes_debug(NES_DBG_CQ, "\n"); */
head = ceq->ceq_head;
ceq_size = ceq->ceq_size;
do {
if (le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX]) &
NES_CEQE_VALID) {
u64temp = (((u64)(le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX])))<<32) |
((u64)(le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_LOW_IDX])));
u64temp <<= 1;
cq = *((struct nes_hw_cq **)&u64temp);
/* nes_debug(NES_DBG_CQ, "pCQ = %p\n", cq); */
barrier();
ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX] = 0;
/* call the event handler */
cq->ce_handler(nesdev, cq);
if (++head >= ceq_size)
head = 0;
} else {
break;
}
} while (1);
ceq->ceq_head = head;
}
/**
* nes_process_aeq
*/
static void nes_process_aeq(struct nes_device *nesdev, struct nes_hw_aeq *aeq)
{
// u64 u64temp;
u32 head;
u32 aeq_size;
u32 aeqe_misc;
u32 aeqe_cq_id;
struct nes_hw_aeqe volatile *aeqe;
head = aeq->aeq_head;
aeq_size = aeq->aeq_size;
do {
aeqe = &aeq->aeq_vbase[head];
if ((le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]) & NES_AEQE_VALID) == 0)
break;
aeqe_misc = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]);
aeqe_cq_id = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]);
if (aeqe_misc & (NES_AEQE_QP|NES_AEQE_CQ)) {
if (aeqe_cq_id >= NES_FIRST_QPN) {
/* dealing with an accelerated QP related AE */
// u64temp = (((u64)(le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])))<<32) |
// ((u64)(le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX])));
nes_process_iwarp_aeqe(nesdev, (struct nes_hw_aeqe *)aeqe);
} else {
/* TODO: dealing with a CQP related AE */
nes_debug(NES_DBG_AEQ, "Processing CQP related AE, misc = 0x%04X\n",
(u16)(aeqe_misc >> 16));
}
}
aeqe->aeqe_words[NES_AEQE_MISC_IDX] = 0;
if (++head >= aeq_size)
head = 0;
}
while (1);
aeq->aeq_head = head;
}
static void nes_reset_link(struct nes_device *nesdev, u32 mac_index)
{
struct nes_adapter *nesadapter = nesdev->nesadapter;
u32 reset_value;
u32 i=0;
u32 u32temp;
if (nesadapter->hw_rev == NE020_REV) {
return;
}
mh_detected++;
reset_value = nes_read32(nesdev->regs+NES_SOFTWARE_RESET);
if ((mac_index == 0) || ((mac_index == 1) && (nesadapter->OneG_Mode)))
reset_value |= 0x0000001d;
else
reset_value |= 0x0000002d;
if (4 <= (nesadapter->link_interrupt_count[mac_index] / ((u16)NES_MAX_LINK_INTERRUPTS))) {
if ((!nesadapter->OneG_Mode) && (nesadapter->port_count == 2)) {
nesadapter->link_interrupt_count[0] = 0;
nesadapter->link_interrupt_count[1] = 0;
u32temp = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1);
if (0x00000040 & u32temp)
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, 0x0000F088);
else
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, 0x0000F0C8);
reset_value |= 0x0000003d;
}
nesadapter->link_interrupt_count[mac_index] = 0;
}
nes_write32(nesdev->regs+NES_SOFTWARE_RESET, reset_value);
while (((nes_read32(nesdev->regs+NES_SOFTWARE_RESET)
& 0x00000040) != 0x00000040) && (i++ < 5000));
if (0x0000003d == (reset_value & 0x0000003d)) {
u32 pcs_control_status0, pcs_control_status1;
for (i = 0; i < 10; i++) {
pcs_control_status0 = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0);
pcs_control_status1 = nes_read_indexed(nesdev, NES_IDX_PHY_PCS_CONTROL_STATUS0 + 0x200);
if (((0x0F000000 == (pcs_control_status0 & 0x0F000000))
&& (pcs_control_status0 & 0x00100000))
|| ((0x0F000000 == (pcs_control_status1 & 0x0F000000))
&& (pcs_control_status1 & 0x00100000)))
continue;
else
break;
}
if (10 == i) {
u32temp = nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1);
if (0x00000040 & u32temp)
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, 0x0000F088);
else
nes_write_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_CONTROL1, 0x0000F0C8);
nes_write32(nesdev->regs+NES_SOFTWARE_RESET, reset_value);
while (((nes_read32(nesdev->regs + NES_SOFTWARE_RESET)
& 0x00000040) != 0x00000040) && (i++ < 5000));
}
}
}
/**
* nes_process_mac_intr
*/
static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number)
{
unsigned long flags;
u32 pcs_control_status;
struct nes_adapter *nesadapter = nesdev->nesadapter;
struct nes_vnic *nesvnic;
u32 mac_status;
u32 mac_index = nesdev->mac_index;
u32 u32temp;
u16 phy_data;
u16 temp_phy_data;
spin_lock_irqsave(&nesadapter->phy_lock, flags);
if (nesadapter->mac_sw_state[mac_number] != NES_MAC_SW_IDLE) {
spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
return;
}
nesadapter->mac_sw_state[mac_number] = NES_MAC_SW_INTERRUPT;
spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
/* ack the MAC interrupt */
mac_status = nes_read_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (mac_index * 0x200));
/* Clear the interrupt */
nes_write_indexed(nesdev, NES_IDX_MAC_INT_STATUS + (mac_index * 0x200), mac_status);
nes_debug(NES_DBG_PHY, "MAC%u interrupt status = 0x%X.\n", mac_number, mac_status);
if (mac_status & (NES_MAC_INT_LINK_STAT_CHG | NES_MAC_INT_XGMII_EXT)) {
nesdev->link_status_interrupts++;
if (0 == (++nesadapter->link_interrupt_count[mac_index] % ((u16)NES_MAX_LINK_INTERRUPTS))) {
spin_lock_irqsave(&nesadapter->phy_lock, flags);
nes_reset_link(nesdev, mac_index);
spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
}
/* read the PHY interrupt status register */
if (nesadapter->OneG_Mode) {
do {
nes_read_1G_phy_reg(nesdev, 0x1a,
nesadapter->phy_index[mac_index], &phy_data);
nes_debug(NES_DBG_PHY, "Phy%d data from register 0x1a = 0x%X.\n",
nesadapter->phy_index[mac_index], phy_data);
} while (phy_data&0x8000);
temp_phy_data = 0;
do {
nes_read_1G_phy_reg(nesdev, 0x11,
nesadapter->phy_index[mac_index], &phy_data);
nes_debug(NES_DBG_PHY, "Phy%d data from register 0x11 = 0x%X.\n",
nesadapter->phy_index[mac_index], phy_data);
if (temp_phy_data == phy_data)
break;
temp_phy_data = phy_data;
} while (1);
nes_read_1G_phy_reg(nesdev, 0x1e,
nesadapter->phy_index[mac_index], &phy_data);
nes_debug(NES_DBG_PHY, "Phy%d data from register 0x1e = 0x%X.\n",
nesadapter->phy_index[mac_index], phy_data);
nes_read_1G_phy_reg(nesdev, 1,
nesadapter->phy_index[mac_index], &phy_data);
nes_debug(NES_DBG_PHY, "1G phy%u data from register 1 = 0x%X\n",
nesadapter->phy_index[mac_index], phy_data);
if (temp_phy_data & 0x1000) {
nes_debug(NES_DBG_PHY, "The Link is up according to the PHY\n");
phy_data = 4;
} else {
nes_debug(NES_DBG_PHY, "The Link is down according to the PHY\n");
}
}
nes_debug(NES_DBG_PHY, "Eth SERDES Common Status: 0=0x%08X, 1=0x%08X\n",
nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0),
nes_read_indexed(nesdev, NES_IDX_ETH_SERDES_COMMON_STATUS0+0x200));
pcs_control_status = nes_read_indexed(nesdev,
NES_IDX_PHY_PCS_CONTROL_STATUS0 + ((mac_index&1)*0x200));
pcs_control_status = nes_read_indexed(nesdev,
NES_IDX_PHY_PCS_CONTROL_STATUS0 + ((mac_index&1)*0x200));
nes_debug(NES_DBG_PHY, "PCS PHY Control/Status%u: 0x%08X\n",
mac_index, pcs_control_status);
if (nesadapter->OneG_Mode) {
u32temp = 0x01010000;
if (nesadapter->port_count > 2) {
u32temp |= 0x02020000;
}
if ((pcs_control_status & u32temp)!= u32temp) {
phy_data = 0;
nes_debug(NES_DBG_PHY, "PCS says the link is down\n");
}
} else if (nesadapter->phy_type[mac_index] == NES_PHY_TYPE_IRIS) {
nes_read_10G_phy_reg(nesdev, 1, nesadapter->phy_index[mac_index]);
temp_phy_data = (u16)nes_read_indexed(nesdev,
NES_IDX_MAC_MDIO_CONTROL);
u32temp = 20;
do {
nes_read_10G_phy_reg(nesdev, 1, nesadapter->phy_index[mac_index]);
phy_data = (u16)nes_read_indexed(nesdev,
NES_IDX_MAC_MDIO_CONTROL);
if ((phy_data == temp_phy_data) || (!(--u32temp)))
break;
temp_phy_data = phy_data;
} while (1);
nes_debug(NES_DBG_PHY, "%s: Phy data = 0x%04X, link was %s.\n",
__func__, phy_data, nesadapter->mac_link_down ? "DOWN" : "UP");
} else {
phy_data = (0x0f0f0000 == (pcs_control_status & 0x0f1f0000)) ? 4 : 0;
}
if (phy_data & 0x0004) {
nesadapter->mac_link_down[mac_index] = 0;
list_for_each_entry(nesvnic, &nesadapter->nesvnic_list[mac_index], list) {
nes_debug(NES_DBG_PHY, "The Link is UP!!. linkup was %d\n",
nesvnic->linkup);
if (nesvnic->linkup == 0) {
printk(PFX "The Link is now up for port %u, netdev %p.\n",
mac_index, nesvnic->netdev);
if (netif_queue_stopped(nesvnic->netdev))
netif_start_queue(nesvnic->netdev);
nesvnic->linkup = 1;
netif_carrier_on(nesvnic->netdev);
}
}
} else {
nesadapter->mac_link_down[mac_index] = 1;
list_for_each_entry(nesvnic, &nesadapter->nesvnic_list[mac_index], list) {
nes_debug(NES_DBG_PHY, "The Link is Down!!. linkup was %d\n",
nesvnic->linkup);
if (nesvnic->linkup == 1) {
printk(PFX "The Link is now down for port %u, netdev %p.\n",
mac_index, nesvnic->netdev);
if (!(netif_queue_stopped(nesvnic->netdev)))
netif_stop_queue(nesvnic->netdev);
nesvnic->linkup = 0;
netif_carrier_off(nesvnic->netdev);
}
}
}
}
nesadapter->mac_sw_state[mac_number] = NES_MAC_SW_IDLE;
}
static void nes_nic_napi_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)
{
struct nes_vnic *nesvnic = container_of(cq, struct nes_vnic, nic_cq);
netif_rx_schedule(nesdev->netdev[nesvnic->netdev_index], &nesvnic->napi);
}
/* The MAX_RQES_TO_PROCESS defines how many max read requests to complete before
* getting out of nic_ce_handler
*/
#define MAX_RQES_TO_PROCESS 384
/**
* nes_nic_ce_handler
*/
void nes_nic_ce_handler(struct nes_device *nesdev, struct nes_hw_nic_cq *cq)
{
u64 u64temp;
dma_addr_t bus_address;
struct nes_hw_nic *nesnic;
struct nes_vnic *nesvnic = container_of(cq, struct nes_vnic, nic_cq);
struct nes_adapter *nesadapter = nesdev->nesadapter;
struct nes_hw_nic_rq_wqe *nic_rqe;
struct nes_hw_nic_sq_wqe *nic_sqe;
struct sk_buff *skb;
struct sk_buff *rx_skb;
__le16 *wqe_fragment_length;
u32 head;
u32 cq_size;
u32 rx_pkt_size;
u32 cqe_count=0;
u32 cqe_errv;
u32 cqe_misc;
u16 wqe_fragment_index = 1; /* first fragment (0) is used by copy buffer */
u16 vlan_tag;
u16 pkt_type;
u16 rqes_processed = 0;
u8 sq_cqes = 0;
head = cq->cq_head;
cq_size = cq->cq_size;
cq->cqes_pending = 1;
do {
if (le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX]) &
NES_NIC_CQE_VALID) {
nesnic = &nesvnic->nic;
cqe_misc = le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX]);
if (cqe_misc & NES_NIC_CQE_SQ) {
sq_cqes++;
wqe_fragment_index = 1;
nic_sqe = &nesnic->sq_vbase[nesnic->sq_tail];
skb = nesnic->tx_skb[nesnic->sq_tail];
wqe_fragment_length = (__le16 *)&nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_0_TAG_IDX];
/* bump past the vlan tag */
wqe_fragment_length++;
if (le16_to_cpu(wqe_fragment_length[wqe_fragment_index]) != 0) {
u64temp = (u64) le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX+wqe_fragment_index*2]);
u64temp += ((u64)le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX+wqe_fragment_index*2]))<<32;
bus_address = (dma_addr_t)u64temp;
if (test_and_clear_bit(nesnic->sq_tail, nesnic->first_frag_overflow)) {
pci_unmap_single(nesdev->pcidev,
bus_address,
le16_to_cpu(wqe_fragment_length[wqe_fragment_index++]),
PCI_DMA_TODEVICE);
}
for (; wqe_fragment_index < 5; wqe_fragment_index++) {
if (wqe_fragment_length[wqe_fragment_index]) {
u64temp = le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX+wqe_fragment_index*2]);
u64temp += ((u64)le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX+wqe_fragment_index*2]))<<32;
bus_address = (dma_addr_t)u64temp;
pci_unmap_page(nesdev->pcidev,
bus_address,
le16_to_cpu(wqe_fragment_length[wqe_fragment_index]),
PCI_DMA_TODEVICE);
} else
break;
}
if (skb)
dev_kfree_skb_any(skb);
}
nesnic->sq_tail++;
nesnic->sq_tail &= nesnic->sq_size-1;
if (sq_cqes > 128) {
barrier();
/* restart the queue if it had been stopped */
if (netif_queue_stopped(nesvnic->netdev))
netif_wake_queue(nesvnic->netdev);
sq_cqes = 0;
}
} else {
rqes_processed ++;
cq->rx_cqes_completed++;
cq->rx_pkts_indicated++;
rx_pkt_size = cqe_misc & 0x0000ffff;
nic_rqe = &nesnic->rq_vbase[nesnic->rq_tail];
/* Get the skb */
rx_skb = nesnic->rx_skb[nesnic->rq_tail];
nic_rqe = &nesnic->rq_vbase[nesvnic->nic.rq_tail];
bus_address = (dma_addr_t)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX]);
bus_address += ((u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX])) << 32;
pci_unmap_single(nesdev->pcidev, bus_address,
nesvnic->max_frame_size, PCI_DMA_FROMDEVICE);
/* rx_skb->tail = rx_skb->data + rx_pkt_size; */
/* rx_skb->len = rx_pkt_size; */
rx_skb->len = 0; /* TODO: see if this is necessary */
skb_put(rx_skb, rx_pkt_size);
rx_skb->protocol = eth_type_trans(rx_skb, nesvnic->netdev);
nesnic->rq_tail++;
nesnic->rq_tail &= nesnic->rq_size - 1;
atomic_inc(&nesvnic->rx_skbs_needed);
if (atomic_read(&nesvnic->rx_skbs_needed) > (nesvnic->nic.rq_size>>1)) {
nes_write32(nesdev->regs+NES_CQE_ALLOC,
cq->cq_number | (cqe_count << 16));
// nesadapter->tune_timer.cq_count += cqe_count;
nesdev->currcq_count += cqe_count;
cqe_count = 0;
nes_replenish_nic_rq(nesvnic);
}
pkt_type = (u16)(le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_NIC_CQE_TAG_PKT_TYPE_IDX]));
cqe_errv = (cqe_misc & NES_NIC_CQE_ERRV_MASK) >> NES_NIC_CQE_ERRV_SHIFT;
rx_skb->ip_summed = CHECKSUM_NONE;
if ((NES_PKT_TYPE_TCPV4_BITS == (pkt_type & NES_PKT_TYPE_TCPV4_MASK)) ||
(NES_PKT_TYPE_UDPV4_BITS == (pkt_type & NES_PKT_TYPE_UDPV4_MASK))) {
if ((cqe_errv &
(NES_NIC_ERRV_BITS_IPV4_CSUM_ERR | NES_NIC_ERRV_BITS_TCPUDP_CSUM_ERR |
NES_NIC_ERRV_BITS_IPH_ERR | NES_NIC_ERRV_BITS_WQE_OVERRUN)) == 0) {
if (nesvnic->rx_checksum_disabled == 0) {
rx_skb->ip_summed = CHECKSUM_UNNECESSARY;
}
} else
nes_debug(NES_DBG_CQ, "%s: unsuccessfully checksummed TCP or UDP packet."
" errv = 0x%X, pkt_type = 0x%X.\n",
nesvnic->netdev->name, cqe_errv, pkt_type);
} else if ((pkt_type & NES_PKT_TYPE_IPV4_MASK) == NES_PKT_TYPE_IPV4_BITS) {
if ((cqe_errv &
(NES_NIC_ERRV_BITS_IPV4_CSUM_ERR | NES_NIC_ERRV_BITS_IPH_ERR |
NES_NIC_ERRV_BITS_WQE_OVERRUN)) == 0) {
if (nesvnic->rx_checksum_disabled == 0) {
rx_skb->ip_summed = CHECKSUM_UNNECESSARY;
/* nes_debug(NES_DBG_CQ, "%s: Reporting successfully checksummed IPv4 packet.\n",
nesvnic->netdev->name); */
}
} else
nes_debug(NES_DBG_CQ, "%s: unsuccessfully checksummed TCP or UDP packet."
" errv = 0x%X, pkt_type = 0x%X.\n",
nesvnic->netdev->name, cqe_errv, pkt_type);
}
/* nes_debug(NES_DBG_CQ, "pkt_type=%x, APBVT_MASK=%x\n",
pkt_type, (pkt_type & NES_PKT_TYPE_APBVT_MASK)); */
if ((pkt_type & NES_PKT_TYPE_APBVT_MASK) == NES_PKT_TYPE_APBVT_BITS) {
nes_cm_recv(rx_skb, nesvnic->netdev);
} else {
if ((cqe_misc & NES_NIC_CQE_TAG_VALID) && (nesvnic->vlan_grp != NULL)) {
vlan_tag = (u16)(le32_to_cpu(
cq->cq_vbase[head].cqe_words[NES_NIC_CQE_TAG_PKT_TYPE_IDX])
>> 16);
nes_debug(NES_DBG_CQ, "%s: Reporting stripped VLAN packet. Tag = 0x%04X\n",
nesvnic->netdev->name, vlan_tag);
nes_vlan_rx(rx_skb, nesvnic->vlan_grp, vlan_tag);
} else {
nes_netif_rx(rx_skb);
}
}
nesvnic->netdev->last_rx = jiffies;
/* nesvnic->netstats.rx_packets++; */
/* nesvnic->netstats.rx_bytes += rx_pkt_size; */
}
cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX] = 0;
/* Accounting... */
cqe_count++;
if (++head >= cq_size)
head = 0;
if (cqe_count == 255) {
/* Replenish Nic CQ */
nes_write32(nesdev->regs+NES_CQE_ALLOC,
cq->cq_number | (cqe_count << 16));
// nesdev->nesadapter->tune_timer.cq_count += cqe_count;
nesdev->currcq_count += cqe_count;
cqe_count = 0;
}
if (cq->rx_cqes_completed >= nesvnic->budget)
break;
} else {
cq->cqes_pending = 0;
break;
}
} while (1);
if (sq_cqes) {
barrier();
/* restart the queue if it had been stopped */
if (netif_queue_stopped(nesvnic->netdev))
netif_wake_queue(nesvnic->netdev);
}
cq->cq_head = head;
/* nes_debug(NES_DBG_CQ, "CQ%u Processed = %u cqes, new head = %u.\n",
cq->cq_number, cqe_count, cq->cq_head); */
cq->cqe_allocs_pending = cqe_count;
if (unlikely(nesadapter->et_use_adaptive_rx_coalesce))
{
// nesdev->nesadapter->tune_timer.cq_count += cqe_count;
nesdev->currcq_count += cqe_count;
nes_nic_tune_timer(nesdev);
}
if (atomic_read(&nesvnic->rx_skbs_needed))
nes_replenish_nic_rq(nesvnic);
}
/**
* nes_cqp_ce_handler
*/
static void nes_cqp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *cq)
{
u64 u64temp;
unsigned long flags;
struct nes_hw_cqp *cqp = NULL;
struct nes_cqp_request *cqp_request;
struct nes_hw_cqp_wqe *cqp_wqe;
u32 head;
u32 cq_size;
u32 cqe_count=0;
u32 error_code;
/* u32 counter; */
head = cq->cq_head;
cq_size = cq->cq_size;
do {
/* process the CQE */
/* nes_debug(NES_DBG_CQP, "head=%u cqe_words=%08X\n", head,
le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX])); */
if (le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX]) & NES_CQE_VALID) {
u64temp = (((u64)(le32_to_cpu(cq->cq_vbase[head].
cqe_words[NES_CQE_COMP_COMP_CTX_HIGH_IDX])))<<32) |
((u64)(le32_to_cpu(cq->cq_vbase[head].
cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX])));
cqp = *((struct nes_hw_cqp **)&u64temp);
error_code = le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_ERROR_CODE_IDX]);
if (error_code) {
nes_debug(NES_DBG_CQP, "Bad Completion code for opcode 0x%02X from CQP,"
" Major/Minor codes = 0x%04X:%04X.\n",
le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX])&0x3f,
(u16)(error_code >> 16),
(u16)error_code);
nes_debug(NES_DBG_CQP, "cqp: qp_id=%u, sq_head=%u, sq_tail=%u\n",
cqp->qp_id, cqp->sq_head, cqp->sq_tail);
}
u64temp = (((u64)(le32_to_cpu(nesdev->cqp.sq_vbase[cqp->sq_tail].
wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX])))<<32) |
((u64)(le32_to_cpu(nesdev->cqp.sq_vbase[cqp->sq_tail].
wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX])));
cqp_request = *((struct nes_cqp_request **)&u64temp);
if (cqp_request) {
if (cqp_request->waiting) {
/* nes_debug(NES_DBG_CQP, "%s: Waking up requestor\n"); */
cqp_request->major_code = (u16)(error_code >> 16);
cqp_request->minor_code = (u16)error_code;
barrier();
cqp_request->request_done = 1;
wake_up(&cqp_request->waitq);
if (atomic_dec_and_test(&cqp_request->refcount)) {
nes_debug(NES_DBG_CQP, "CQP request %p (opcode 0x%02X) freed.\n",
cqp_request,
le32_to_cpu(cqp_request->cqp_wqe.wqe_words[NES_CQP_WQE_OPCODE_IDX])&0x3f);
if (cqp_request->dynamic) {
kfree(cqp_request);
} else {
spin_lock_irqsave(&nesdev->cqp.lock, flags);
list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
}
}
} else if (cqp_request->callback) {
/* Envoke the callback routine */
cqp_request->cqp_callback(nesdev, cqp_request);
if (cqp_request->dynamic) {
kfree(cqp_request);
} else {
spin_lock_irqsave(&nesdev->cqp.lock, flags);
list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
}
} else {
nes_debug(NES_DBG_CQP, "CQP request %p (opcode 0x%02X) freed.\n",
cqp_request,
le32_to_cpu(cqp_request->cqp_wqe.wqe_words[NES_CQP_WQE_OPCODE_IDX])&0x3f);
if (cqp_request->dynamic) {
kfree(cqp_request);
} else {
spin_lock_irqsave(&nesdev->cqp.lock, flags);
list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
}
}
} else {
wake_up(&nesdev->cqp.waitq);
}
cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX] = 0;
nes_write32(nesdev->regs+NES_CQE_ALLOC, cq->cq_number | (1 << 16));
if (++cqp->sq_tail >= cqp->sq_size)
cqp->sq_tail = 0;
/* Accounting... */
cqe_count++;
if (++head >= cq_size)
head = 0;
} else {
break;
}
} while (1);
cq->cq_head = head;
spin_lock_irqsave(&nesdev->cqp.lock, flags);
while ((!list_empty(&nesdev->cqp_pending_reqs)) &&
((((nesdev->cqp.sq_tail+nesdev->cqp.sq_size)-nesdev->cqp.sq_head) &
(nesdev->cqp.sq_size - 1)) != 1)) {
cqp_request = list_entry(nesdev->cqp_pending_reqs.next,
struct nes_cqp_request, list);
list_del_init(&cqp_request->list);
head = nesdev->cqp.sq_head++;
nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1;
cqp_wqe = &nesdev->cqp.sq_vbase[head];
memcpy(cqp_wqe, &cqp_request->cqp_wqe, sizeof(*cqp_wqe));
barrier();
cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] =
cpu_to_le32((u32)((unsigned long)cqp_request));
cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] =
cpu_to_le32((u32)(upper_32_bits((unsigned long)cqp_request)));
nes_debug(NES_DBG_CQP, "CQP request %p (opcode 0x%02X) put on CQPs SQ wqe%u.\n",
cqp_request, le32_to_cpu(cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX])&0x3f, head);
/* Ring doorbell (1 WQEs) */
barrier();
nes_write32(nesdev->regs+NES_WQE_ALLOC, 0x01800000 | nesdev->cqp.qp_id);
}
spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
/* Arm the CCQ */
nes_write32(nesdev->regs+NES_CQE_ALLOC, NES_CQE_ALLOC_NOTIFY_NEXT |
cq->cq_number);
nes_read32(nesdev->regs+NES_CQE_ALLOC);
}
/**
* nes_process_iwarp_aeqe
*/
static void nes_process_iwarp_aeqe(struct nes_device *nesdev,
struct nes_hw_aeqe *aeqe)
{
u64 context;
u64 aeqe_context = 0;
unsigned long flags;
struct nes_qp *nesqp;
int resource_allocated;
/* struct iw_cm_id *cm_id; */
struct nes_adapter *nesadapter = nesdev->nesadapter;
struct ib_event ibevent;
/* struct iw_cm_event cm_event; */
u32 aeq_info;
u32 next_iwarp_state = 0;
u16 async_event_id;
u8 tcp_state;
u8 iwarp_state;
nes_debug(NES_DBG_AEQ, "\n");
aeq_info = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]);
if ((NES_AEQE_INBOUND_RDMA&aeq_info) || (!(NES_AEQE_QP&aeq_info))) {
context = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]);
context += ((u64)le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])) << 32;
} else {
aeqe_context = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]);
aeqe_context += ((u64)le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])) << 32;
context = (unsigned long)nesadapter->qp_table[le32_to_cpu(
aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX])-NES_FIRST_QPN];
BUG_ON(!context);
}
async_event_id = (u16)aeq_info;
tcp_state = (aeq_info & NES_AEQE_TCP_STATE_MASK) >> NES_AEQE_TCP_STATE_SHIFT;
iwarp_state = (aeq_info & NES_AEQE_IWARP_STATE_MASK) >> NES_AEQE_IWARP_STATE_SHIFT;
nes_debug(NES_DBG_AEQ, "aeid = 0x%04X, qp-cq id = %d, aeqe = %p,"
" Tcp state = %s, iWARP state = %s\n",
async_event_id,
le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]), aeqe,
nes_tcp_state_str[tcp_state], nes_iwarp_state_str[iwarp_state]);
switch (async_event_id) {
case NES_AEQE_AEID_LLP_FIN_RECEIVED:
nesqp = *((struct nes_qp **)&context);
if (atomic_inc_return(&nesqp->close_timer_started) == 1) {
nesqp->cm_id->add_ref(nesqp->cm_id);
nes_add_ref(&nesqp->ibqp);
schedule_nes_timer(nesqp->cm_node, (struct sk_buff *)nesqp,
NES_TIMER_TYPE_CLOSE, 1, 0);
nes_debug(NES_DBG_AEQ, "QP%u Not decrementing QP refcount (%d),"
" need ae to finish up, original_last_aeq = 0x%04X."
" last_aeq = 0x%04X, scheduling timer. TCP state = %d\n",
nesqp->hwqp.qp_id, atomic_read(&nesqp->refcount),
async_event_id, nesqp->last_aeq, tcp_state);
}
if ((tcp_state != NES_AEQE_TCP_STATE_CLOSE_WAIT) ||
(nesqp->ibqp_state != IB_QPS_RTS)) {
/* FIN Received but tcp state or IB state moved on,
should expect a close complete */
return;
}
case NES_AEQE_AEID_LLP_CLOSE_COMPLETE:
case NES_AEQE_AEID_LLP_CONNECTION_RESET:
case NES_AEQE_AEID_TERMINATE_SENT:
case NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE:
case NES_AEQE_AEID_RESET_SENT:
nesqp = *((struct nes_qp **)&context);
if (async_event_id == NES_AEQE_AEID_RESET_SENT) {
tcp_state = NES_AEQE_TCP_STATE_CLOSED;
}
nes_add_ref(&nesqp->ibqp);
spin_lock_irqsave(&nesqp->lock, flags);
nesqp->hw_iwarp_state = iwarp_state;
nesqp->hw_tcp_state = tcp_state;
nesqp->last_aeq = async_event_id;
if ((tcp_state == NES_AEQE_TCP_STATE_CLOSED) ||
(tcp_state == NES_AEQE_TCP_STATE_TIME_WAIT)) {
nesqp->hte_added = 0;
spin_unlock_irqrestore(&nesqp->lock, flags);
nes_debug(NES_DBG_AEQ, "issuing hw modifyqp for QP%u to remove hte\n",
nesqp->hwqp.qp_id);
nes_hw_modify_qp(nesdev, nesqp,
NES_CQP_QP_IWARP_STATE_ERROR | NES_CQP_QP_DEL_HTE, 0);
spin_lock_irqsave(&nesqp->lock, flags);
}
if ((nesqp->ibqp_state == IB_QPS_RTS) &&
((tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) ||
(async_event_id == NES_AEQE_AEID_LLP_CONNECTION_RESET))) {
switch (nesqp->hw_iwarp_state) {
case NES_AEQE_IWARP_STATE_RTS:
next_iwarp_state = NES_CQP_QP_IWARP_STATE_CLOSING;
nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_CLOSING;
break;
case NES_AEQE_IWARP_STATE_TERMINATE:
next_iwarp_state = NES_CQP_QP_IWARP_STATE_TERMINATE;
nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_TERMINATE;
if (async_event_id == NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) {
next_iwarp_state |= 0x02000000;
nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
}
break;
default:
next_iwarp_state = 0;
}
spin_unlock_irqrestore(&nesqp->lock, flags);
if (next_iwarp_state) {
nes_add_ref(&nesqp->ibqp);
nes_debug(NES_DBG_AEQ, "issuing hw modifyqp for QP%u. next state = 0x%08X,"
" also added another reference\n",
nesqp->hwqp.qp_id, next_iwarp_state);
nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0);
}
nes_cm_disconn(nesqp);
} else {
if (async_event_id == NES_AEQE_AEID_LLP_FIN_RECEIVED) {
/* FIN Received but ib state not RTS,
close complete will be on its way */
spin_unlock_irqrestore(&nesqp->lock, flags);
nes_rem_ref(&nesqp->ibqp);
return;
}
spin_unlock_irqrestore(&nesqp->lock, flags);
if (async_event_id == NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE) {
next_iwarp_state = NES_CQP_QP_IWARP_STATE_TERMINATE | 0x02000000;
nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
nes_debug(NES_DBG_AEQ, "issuing hw modifyqp for QP%u. next state = 0x%08X,"
" also added another reference\n",
nesqp->hwqp.qp_id, next_iwarp_state);
nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0);
}
nes_cm_disconn(nesqp);
}
break;
case NES_AEQE_AEID_LLP_TERMINATE_RECEIVED:
nesqp = *((struct nes_qp **)&context);
spin_lock_irqsave(&nesqp->lock, flags);
nesqp->hw_iwarp_state = iwarp_state;
nesqp->hw_tcp_state = tcp_state;
nesqp->last_aeq = async_event_id;
spin_unlock_irqrestore(&nesqp->lock, flags);
nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_LLP_TERMINATE_RECEIVED"
" event on QP%u \n Q2 Data:\n",
nesqp->hwqp.qp_id);
if (nesqp->ibqp.event_handler) {
ibevent.device = nesqp->ibqp.device;
ibevent.element.qp = &nesqp->ibqp;
ibevent.event = IB_EVENT_QP_FATAL;
nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
}
if ((tcp_state == NES_AEQE_TCP_STATE_CLOSE_WAIT) ||
((nesqp->ibqp_state == IB_QPS_RTS)&&
(async_event_id == NES_AEQE_AEID_LLP_CONNECTION_RESET))) {
nes_add_ref(&nesqp->ibqp);
nes_cm_disconn(nesqp);
} else {
nesqp->in_disconnect = 0;
wake_up(&nesqp->kick_waitq);
}
break;
case NES_AEQE_AEID_LLP_TOO_MANY_RETRIES:
nesqp = *((struct nes_qp **)&context);
nes_add_ref(&nesqp->ibqp);
spin_lock_irqsave(&nesqp->lock, flags);
nesqp->hw_iwarp_state = NES_AEQE_IWARP_STATE_ERROR;
nesqp->hw_tcp_state = NES_AEQE_TCP_STATE_CLOSED;
nesqp->last_aeq = async_event_id;
if (nesqp->cm_id) {
nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_LLP_TOO_MANY_RETRIES"
" event on QP%u, remote IP = 0x%08X \n",
nesqp->hwqp.qp_id,
ntohl(nesqp->cm_id->remote_addr.sin_addr.s_addr));
} else {
nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_LLP_TOO_MANY_RETRIES"
" event on QP%u \n",
nesqp->hwqp.qp_id);
}
spin_unlock_irqrestore(&nesqp->lock, flags);
next_iwarp_state = NES_CQP_QP_IWARP_STATE_ERROR | NES_CQP_QP_RESET;
nes_hw_modify_qp(nesdev, nesqp, next_iwarp_state, 0);
if (nesqp->ibqp.event_handler) {
ibevent.device = nesqp->ibqp.device;
ibevent.element.qp = &nesqp->ibqp;
ibevent.event = IB_EVENT_QP_FATAL;
nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
}
break;
case NES_AEQE_AEID_AMP_BAD_STAG_INDEX:
if (NES_AEQE_INBOUND_RDMA&aeq_info) {
nesqp = nesadapter->qp_table[le32_to_cpu(
aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX])-NES_FIRST_QPN];
} else {
/* TODO: get the actual WQE and mask off wqe index */
context &= ~((u64)511);
nesqp = *((struct nes_qp **)&context);
}
spin_lock_irqsave(&nesqp->lock, flags);
nesqp->hw_iwarp_state = iwarp_state;
nesqp->hw_tcp_state = tcp_state;
nesqp->last_aeq = async_event_id;
spin_unlock_irqrestore(&nesqp->lock, flags);
nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_AMP_BAD_STAG_INDEX event on QP%u\n",
nesqp->hwqp.qp_id);
if (nesqp->ibqp.event_handler) {
ibevent.device = nesqp->ibqp.device;
ibevent.element.qp = &nesqp->ibqp;
ibevent.event = IB_EVENT_QP_ACCESS_ERR;
nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
}
break;
case NES_AEQE_AEID_AMP_UNALLOCATED_STAG:
nesqp = *((struct nes_qp **)&context);
spin_lock_irqsave(&nesqp->lock, flags);
nesqp->hw_iwarp_state = iwarp_state;
nesqp->hw_tcp_state = tcp_state;
nesqp->last_aeq = async_event_id;
spin_unlock_irqrestore(&nesqp->lock, flags);
nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_AMP_UNALLOCATED_STAG event on QP%u\n",
nesqp->hwqp.qp_id);
if (nesqp->ibqp.event_handler) {
ibevent.device = nesqp->ibqp.device;
ibevent.element.qp = &nesqp->ibqp;
ibevent.event = IB_EVENT_QP_ACCESS_ERR;
nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
}
break;
case NES_AEQE_AEID_PRIV_OPERATION_DENIED:
nesqp = nesadapter->qp_table[le32_to_cpu(aeqe->aeqe_words
[NES_AEQE_COMP_QP_CQ_ID_IDX])-NES_FIRST_QPN];
spin_lock_irqsave(&nesqp->lock, flags);
nesqp->hw_iwarp_state = iwarp_state;
nesqp->hw_tcp_state = tcp_state;
nesqp->last_aeq = async_event_id;
spin_unlock_irqrestore(&nesqp->lock, flags);
nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_PRIV_OPERATION_DENIED event on QP%u,"
" nesqp = %p, AE reported %p\n",
nesqp->hwqp.qp_id, nesqp, *((struct nes_qp **)&context));
if (nesqp->ibqp.event_handler) {
ibevent.device = nesqp->ibqp.device;
ibevent.element.qp = &nesqp->ibqp;
ibevent.event = IB_EVENT_QP_ACCESS_ERR;
nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
}
break;
case NES_AEQE_AEID_CQ_OPERATION_ERROR:
context <<= 1;
nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_CQ_OPERATION_ERROR event on CQ%u, %p\n",
le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]), (void *)(unsigned long)context);
resource_allocated = nes_is_resource_allocated(nesadapter, nesadapter->allocated_cqs,
le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]));
if (resource_allocated) {
printk(KERN_ERR PFX "%s: Processing an NES_AEQE_AEID_CQ_OPERATION_ERROR event on CQ%u\n",
__func__, le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]));
}
break;
case NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER:
nesqp = nesadapter->qp_table[le32_to_cpu(
aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX])-NES_FIRST_QPN];
spin_lock_irqsave(&nesqp->lock, flags);
nesqp->hw_iwarp_state = iwarp_state;
nesqp->hw_tcp_state = tcp_state;
nesqp->last_aeq = async_event_id;
spin_unlock_irqrestore(&nesqp->lock, flags);
nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG"
"_FOR_AVAILABLE_BUFFER event on QP%u\n",
nesqp->hwqp.qp_id);
if (nesqp->ibqp.event_handler) {
ibevent.device = nesqp->ibqp.device;
ibevent.element.qp = &nesqp->ibqp;
ibevent.event = IB_EVENT_QP_ACCESS_ERR;
nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
}
/* tell cm to disconnect, cm will queue work to thread */
nes_add_ref(&nesqp->ibqp);
nes_cm_disconn(nesqp);
break;
case NES_AEQE_AEID_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE:
nesqp = *((struct nes_qp **)&context);
spin_lock_irqsave(&nesqp->lock, flags);
nesqp->hw_iwarp_state = iwarp_state;
nesqp->hw_tcp_state = tcp_state;
nesqp->last_aeq = async_event_id;
spin_unlock_irqrestore(&nesqp->lock, flags);
nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_DDP_UBE_INVALID_MSN"
"_NO_BUFFER_AVAILABLE event on QP%u\n",
nesqp->hwqp.qp_id);
if (nesqp->ibqp.event_handler) {
ibevent.device = nesqp->ibqp.device;
ibevent.element.qp = &nesqp->ibqp;
ibevent.event = IB_EVENT_QP_FATAL;
nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
}
/* tell cm to disconnect, cm will queue work to thread */
nes_add_ref(&nesqp->ibqp);
nes_cm_disconn(nesqp);
break;
case NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR:
nesqp = *((struct nes_qp **)&context);
spin_lock_irqsave(&nesqp->lock, flags);
nesqp->hw_iwarp_state = iwarp_state;
nesqp->hw_tcp_state = tcp_state;
nesqp->last_aeq = async_event_id;
spin_unlock_irqrestore(&nesqp->lock, flags);
nes_debug(NES_DBG_AEQ, "Processing an NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR"
" event on QP%u \n Q2 Data:\n",
nesqp->hwqp.qp_id);
if (nesqp->ibqp.event_handler) {
ibevent.device = nesqp->ibqp.device;
ibevent.element.qp = &nesqp->ibqp;
ibevent.event = IB_EVENT_QP_FATAL;
nesqp->ibqp.event_handler(&ibevent, nesqp->ibqp.qp_context);
}
/* tell cm to disconnect, cm will queue work to thread */
nes_add_ref(&nesqp->ibqp);
nes_cm_disconn(nesqp);
break;
/* TODO: additional AEs need to be here */
default:
nes_debug(NES_DBG_AEQ, "Processing an iWARP related AE for QP, misc = 0x%04X\n",
async_event_id);
break;
}
}
/**
* nes_iwarp_ce_handler
*/
void nes_iwarp_ce_handler(struct nes_device *nesdev, struct nes_hw_cq *hw_cq)
{
struct nes_cq *nescq = container_of(hw_cq, struct nes_cq, hw_cq);
/* nes_debug(NES_DBG_CQ, "Processing completion event for iWARP CQ%u.\n",
nescq->hw_cq.cq_number); */
nes_write32(nesdev->regs+NES_CQ_ACK, nescq->hw_cq.cq_number);
if (nescq->ibcq.comp_handler)
nescq->ibcq.comp_handler(&nescq->ibcq, nescq->ibcq.cq_context);
return;
}
/**
* nes_manage_apbvt()
*/
int nes_manage_apbvt(struct nes_vnic *nesvnic, u32 accel_local_port,
u32 nic_index, u32 add_port)
{
struct nes_device *nesdev = nesvnic->nesdev;
struct nes_hw_cqp_wqe *cqp_wqe;
unsigned long flags;
struct nes_cqp_request *cqp_request;
int ret = 0;
u16 major_code;
/* Send manage APBVT request to CQP */
cqp_request = nes_get_cqp_request(nesdev);
if (cqp_request == NULL) {
nes_debug(NES_DBG_QP, "Failed to get a cqp_request.\n");
return -ENOMEM;
}
cqp_request->waiting = 1;
cqp_wqe = &cqp_request->cqp_wqe;
nes_debug(NES_DBG_QP, "%s APBV for local port=%u(0x%04x), nic_index=%u\n",
(add_port == NES_MANAGE_APBVT_ADD) ? "ADD" : "DEL",
accel_local_port, accel_local_port, nic_index);
nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_OPCODE_IDX, (NES_CQP_MANAGE_APBVT |
((add_port == NES_MANAGE_APBVT_ADD) ? NES_CQP_APBVT_ADD : 0)));
set_wqe_32bit_value(cqp_wqe->wqe_words, NES_CQP_WQE_ID_IDX,
((nic_index << NES_CQP_APBVT_NIC_SHIFT) | accel_local_port));
nes_debug(NES_DBG_QP, "Waiting for CQP completion for APBVT.\n");
atomic_set(&cqp_request->refcount, 2);
nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_RING_DOORBELL);
if (add_port == NES_MANAGE_APBVT_ADD)
ret = wait_event_timeout(cqp_request->waitq, (cqp_request->request_done != 0),
NES_EVENT_TIMEOUT);
nes_debug(NES_DBG_QP, "Completed, ret=%u, CQP Major:Minor codes = 0x%04X:0x%04X\n",
ret, cqp_request->major_code, cqp_request->minor_code);
major_code = cqp_request->major_code;
if (atomic_dec_and_test(&cqp_request->refcount)) {
if (cqp_request->dynamic) {
kfree(cqp_request);
} else {
spin_lock_irqsave(&nesdev->cqp.lock, flags);
list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
}
}
if (!ret)
return -ETIME;
else if (major_code)
return -EIO;
else
return 0;
}
/**
* nes_manage_arp_cache
*/
void nes_manage_arp_cache(struct net_device *netdev, unsigned char *mac_addr,
u32 ip_addr, u32 action)
{
struct nes_hw_cqp_wqe *cqp_wqe;
struct nes_vnic *nesvnic = netdev_priv(netdev);
struct nes_device *nesdev;
struct nes_cqp_request *cqp_request;
int arp_index;
nesdev = nesvnic->nesdev;
arp_index = nes_arp_table(nesdev, ip_addr, mac_addr, action);
if (arp_index == -1) {
return;
}
/* update the ARP entry */
cqp_request = nes_get_cqp_request(nesdev);
if (cqp_request == NULL) {
nes_debug(NES_DBG_NETDEV, "Failed to get a cqp_request.\n");
return;
}
cqp_request->waiting = 0;
cqp_wqe = &cqp_request->cqp_wqe;
nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(
NES_CQP_MANAGE_ARP_CACHE | NES_CQP_ARP_PERM);
cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |= cpu_to_le32(
(u32)PCI_FUNC(nesdev->pcidev->devfn) << NES_CQP_ARP_AEQ_INDEX_SHIFT);
cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(arp_index);
if (action == NES_ARP_ADD) {
cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] |= cpu_to_le32(NES_CQP_ARP_VALID);
cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_ADDR_LOW_IDX] = cpu_to_le32(
(((u32)mac_addr[2]) << 24) | (((u32)mac_addr[3]) << 16) |
(((u32)mac_addr[4]) << 8) | (u32)mac_addr[5]);
cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_HIGH_IDX] = cpu_to_le32(
(((u32)mac_addr[0]) << 16) | (u32)mac_addr[1]);
} else {
cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_ADDR_LOW_IDX] = 0;
cqp_wqe->wqe_words[NES_CQP_ARP_WQE_MAC_HIGH_IDX] = 0;
}
nes_debug(NES_DBG_NETDEV, "Not waiting for CQP, cqp.sq_head=%u, cqp.sq_tail=%u\n",
nesdev->cqp.sq_head, nesdev->cqp.sq_tail);
atomic_set(&cqp_request->refcount, 1);
nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_RING_DOORBELL);
}
/**
* flush_wqes
*/
void flush_wqes(struct nes_device *nesdev, struct nes_qp *nesqp,
u32 which_wq, u32 wait_completion)
{
unsigned long flags;
struct nes_cqp_request *cqp_request;
struct nes_hw_cqp_wqe *cqp_wqe;
int ret;
cqp_request = nes_get_cqp_request(nesdev);
if (cqp_request == NULL) {
nes_debug(NES_DBG_QP, "Failed to get a cqp_request.\n");
return;
}
if (wait_completion) {
cqp_request->waiting = 1;
atomic_set(&cqp_request->refcount, 2);
} else {
cqp_request->waiting = 0;
}
cqp_wqe = &cqp_request->cqp_wqe;
nes_fill_init_cqp_wqe(cqp_wqe, nesdev);
cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] =
cpu_to_le32(NES_CQP_FLUSH_WQES | which_wq);
cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(nesqp->hwqp.qp_id);
nes_post_cqp_request(nesdev, cqp_request, NES_CQP_REQUEST_RING_DOORBELL);
if (wait_completion) {
/* Wait for CQP */
ret = wait_event_timeout(cqp_request->waitq, (cqp_request->request_done != 0),
NES_EVENT_TIMEOUT);
nes_debug(NES_DBG_QP, "Flush SQ QP WQEs completed, ret=%u,"
" CQP Major:Minor codes = 0x%04X:0x%04X\n",
ret, cqp_request->major_code, cqp_request->minor_code);
if (atomic_dec_and_test(&cqp_request->refcount)) {
if (cqp_request->dynamic) {
kfree(cqp_request);
} else {
spin_lock_irqsave(&nesdev->cqp.lock, flags);
list_add_tail(&cqp_request->list, &nesdev->cqp_avail_reqs);
spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
}
}
}
}