[<prev] [next>] [<thread-prev] [thread-next>] [month] [year] [list]
Date: Thu, 01 Nov 2007 11:50:53 +0200
From: "Eliezer Tamir" <eliezert@...adcom.com>
To: davem@...emloft.net
Subject: Re: [PATCH][BNX2X] added register coments - bnx2x.c
posting individual files for comments.
---
/* bnx2x.c: Broadcom Everest network driver.
*
* Copyright (c) 2007 Broadcom Corporation
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation.
*
* Written by: Eliezer Tamir <eliezert@...adcom.com>
* Based on code from Michael Chan's bnx2 driver
* UDP CSUM errata workaround by Arik Gendelman
* Slowpath rework by Vladislav Zolotarov
* Statistics and Link managment by Yitchak Gertner
*
*/
/* define this to make the driver freeze on error
* -for now this is the defualt.
*/
#define BNX2X_STOP_ON_ERROR
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/device.h> /* for dev_info() */
#include <linux/timer.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/dma-mapping.h>
#include <linux/bitops.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/delay.h>
#include <asm/byteorder.h>
#include <linux/time.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
#ifdef NETIF_F_HW_VLAN_TX
#include <linux/if_vlan.h>
#define BCM_VLAN 1
#endif
#include <net/ip.h>
#include <net/tcp.h>
#include <net/checksum.h>
#include <linux/workqueue.h>
#include <linux/crc32.h>
#include <linux/prefetch.h>
#include <linux/zlib.h>
#include <linux/version.h>
#include "bnx2x_reg.h"
#include "bnx2x_fw_defs.h"
#include "bnx2x_hsi.h"
#include "bnx2x.h"
#include "bnx2x_init.h"
#define DRV_MODULE_VERSION "0.40.12"
#define DRV_MODULE_RELDATE "$DateTime$"
#define BNX2X_BC_VER 0x040009
/* Time in jiffies before concluding the transmitter is hung. */
#define TX_TIMEOUT (5*HZ)
static const char version[] __devinitdata =
"Broadcom NetXtreme II 577xx 10Gigabit Ethernet Driver "
DRV_MODULE_NAME " " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
MODULE_AUTHOR("Eliezer Tamir <eliezert@...adcom.com>");
MODULE_DESCRIPTION("Broadcom NetXtreme II BCM57710 Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_MODULE_VERSION);
MODULE_INFO(cvs_version, "$Revision$");
static int use_inta;
static int poll;
static int onefunc;
static int nomcp;
static int debug;
module_param(use_inta, int, 0);
module_param(poll, int, 0);
module_param(onefunc, int, 0);
module_param(debug, int, 0);
MODULE_PARM_DESC(use_inta, "use INT#A instead of MSI-X");
MODULE_PARM_DESC(poll, "use polling (for debug)");
MODULE_PARM_DESC(onefunc, "enable only first function");
MODULE_PARM_DESC(nomcp, "ignore managment CPU (Implies onefunc)");
MODULE_PARM_DESC(debug, "defualt debug msglevel");
enum bnx2x_board_type {
BCM57710 = 0,
};
/* indexed by board_t, above */
static const struct {
char *name;
} board_info[] __devinitdata = {
{ "Broadcom NetXtreme II BCM57710 XGb" }
};
#ifndef PCI_DEVICE_ID_NX2_57710
#define PCI_DEVICE_ID_NX2_57710 0x164e
#endif
static const struct pci_device_id bnx2x_pci_tbl[] = {
{ PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_57710,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM57710 },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, bnx2x_pci_tbl);
/****************************************************************************
* General service functions
****************************************************************************/
/* does not need locking since it is used only at init */
static void bnx2x_reg_wr_ind(struct bnx2x *bp, u32 addr, u32 val)
{
pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, addr);
pci_write_config_dword(bp->pdev, PCICFG_GRC_DATA, val);
pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS,
PCICFG_VENDOR_ID_OFFSET);
}
#ifdef BNX2X_IND_RD
static u32 bnx2x_reg_rd_ind(struct bnx2x *bp, u32 addr)
{
u32 val;
pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS, addr);
pci_read_config_dword(bp->pdev, PCICFG_GRC_DATA, &val);
pci_write_config_dword(bp->pdev, PCICFG_GRC_ADDRESS,
PCICFG_VENDOR_ID_OFFSET);
return val;
}
#endif
/* copy command into DMAE command memory */
static void bnx2x_post_dmae(struct bnx2x *bp, int idx)
{
struct dmae_command *dmae = &bp->dmae;
u32 cmd_offset;
int i;
cmd_offset = (DMAE_REG_CMD_MEM + sizeof(struct dmae_command) * idx);
for (i = 0; i < (sizeof(struct dmae_command)/4); i++) {
REG_WR32(bp, cmd_offset + i*4, *(((u32 *)dmae) + i));
/* DP(NETIF_MSG_DMAE, "DMAE cmd[%d].%d (0x%08x) : 0x%08x\n",
idx, i, cmd_offset + i*4, *(((u32 *)dmae) + i)); */
}
}
/* DMAE command positions used
* Port0 14
* Port1 15
*/
static void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr,
u32 dst_addr, u32 len32)
{
struct dmae_command *dmae = &bp->dmae;
int port = bp->port;
u32 *wb_comp = bnx2x_sp(bp, wb_comp);
int timeout = 200;
memset(dmae, 0, sizeof(struct dmae_command));
dmae->opcode = (DMAE_CMD_SRC_PCI | DMAE_CMD_DST_GRC |
DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
#ifdef __BIG_ENDIAN
DMAE_CMD_ENDIANITY_B_DW_SWAP |
#else
DMAE_CMD_ENDIANITY_DW_SWAP |
#endif
(port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0));
dmae->src_addr_lo = U64_LO(dma_addr);
dmae->src_addr_hi = U64_HI(dma_addr);
dmae->dst_addr_lo = dst_addr >> 2;
dmae->dst_addr_hi = 0;
dmae->len = len32;
dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_comp));
dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp));
dmae->comp_val = BNX2X_WB_COMP_VAL;
/*
DP(NETIF_MSG_DMAE, "dmae: opcode 0x%08x\n"
DP_LEVEL "src_addr [%x:%08x] len [%d *4] "
"dst_addr [%x:%08x (%08x)]\n"
DP_LEVEL "comp_addr [%x:%08x] comp_val 0x%08x\n",
dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo,
dmae->len, dmae->dst_addr_hi, dmae->dst_addr_lo, dst_addr,
dmae->comp_addr_hi, dmae->comp_addr_lo, dmae->comp_val);
*/
/*
DP(NETIF_MSG_DMAE, "data [0x%08x 0x%08x 0x%08x 0x%08x]\n",
bp->slowpath->wb_data[0], bp->slowpath->wb_data[1],
bp->slowpath->wb_data[2], bp->slowpath->wb_data[3]);
*/
*wb_comp = 0;
bnx2x_post_dmae(bp, port ? 15 : 14);
REG_WR32(bp, (bp->port ? DMAE_REG_GO_C15 : DMAE_REG_GO_C14), 1);
udelay(5);
while (*wb_comp != BNX2X_WB_COMP_VAL) {
/* DP(NETIF_MSG_DMAE, "wb_comp 0x%08x\n", *wb_comp); */
udelay(5);
if (!timeout) {
BNX2X_ERR("dmae timeout!\n");
break;
}
timeout--;
}
}
#ifdef BNX2X_DMAE_RD
static void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32)
{
struct dmae_command *dmae = &bp->dmae;
int port = bp->port;
u32 *wb_comp = bnx2x_sp(bp, wb_comp);
int timeout = 200;
memset(bnx2x_sp(bp, wb_data[0]), 0, sizeof(u32) * 4);
memset(dmae, 0, sizeof(struct dmae_command));
dmae->opcode = (DMAE_CMD_SRC_GRC | DMAE_CMD_DST_PCI |
DMAE_CMD_C_DST_PCI | DMAE_CMD_C_ENABLE |
DMAE_CMD_SRC_RESET | DMAE_CMD_DST_RESET |
#ifdef __BIG_ENDIAN
DMAE_CMD_ENDIANITY_B_DW_SWAP |
#else
DMAE_CMD_ENDIANITY_DW_SWAP |
#endif
(port ? DMAE_CMD_PORT_1 : DMAE_CMD_PORT_0));
dmae->src_addr_lo = src_addr >> 2;
dmae->src_addr_hi = 0;
dmae->dst_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_data));
dmae->dst_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_data));
dmae->len = len32;
dmae->comp_addr_lo = U64_LO(bnx2x_sp_mapping(bp, wb_comp));
dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp));
dmae->comp_val = BNX2X_WB_COMP_VAL;
/*
DP(NETIF_MSG_DMAE, "dmae: opcode 0x%08x\n"
DP_LEVEL "src_addr [%x:%08x] len [%d *4] "
"dst_addr [%x:%08x (%08x)]\n"
DP_LEVEL "comp_addr [%x:%08x] comp_val 0x%08x\n",
dmae->opcode, dmae->src_addr_hi, dmae->src_addr_lo,
dmae->len, dmae->dst_addr_hi, dmae->dst_addr_lo, src_addr,
dmae->comp_addr_hi, dmae->comp_addr_lo, dmae->comp_val);
*/
*wb_comp = 0;
bnx2x_post_dmae(bp, port ? 15 : 14);
REG_WR32(bp, (bp->port ? DMAE_REG_GO_C15 : DMAE_REG_GO_C14), 1);
udelay(5);
while (*wb_comp != BNX2X_WB_COMP_VAL) {
udelay(5);
if (!timeout) {
BNX2X_ERR("dmae timeout!\n");
break;
}
timeout--;
}
/*
DP(NETIF_MSG_DMAE, "data [0x%08x 0x%08x 0x%08x 0x%08x]\n",
bp->slowpath->wb_data[0], bp->slowpath->wb_data[1],
bp->slowpath->wb_data[2], bp->slowpath->wb_data[3]);
*/
}
#endif
/* print microcode asserts to the kernel log */
static int bnx2x_mc_assert(struct bnx2x *bp)
{
u8 i, j;
int rc = 0;
char last_idx;
const char storm[] = {"XTCU"};
const u32 intmem_base[] = {
BAR_XSTRORM_INTMEM,
BAR_TSTRORM_INTMEM,
BAR_CSTRORM_INTMEM,
BAR_USTRORM_INTMEM
};
/* Go through all instances of all SEMIs */
for (i = 0; i < 4; i++) {
last_idx = REG_RD8(bp, XSTORM_ASSERT_LIST_INDEX_OFFSET +
intmem_base[i]);
BNX2X_ERR("DATA %cSTORM_ASSERT_LIST_INDEX 0x%x\n",
storm[i], last_idx);
/* print the asserts */
#define STROM_ASSERT_ARRAY_SIZE 50
for (j = 0; j < STROM_ASSERT_ARRAY_SIZE; j++) {
u32 row0, row1, row2, row3;
row0 = REG_RD(bp, XSTORM_ASSERT_LIST_OFFSET(j) +
intmem_base[i]);
row1 = REG_RD(bp, XSTORM_ASSERT_LIST_OFFSET(j) + 4 +
intmem_base[i]);
row2 = REG_RD(bp, XSTORM_ASSERT_LIST_OFFSET(j) + 8 +
intmem_base[i]);
row3 = REG_RD(bp, XSTORM_ASSERT_LIST_OFFSET(j) + 12 +
intmem_base[i]);
if (row0 != COMMON_ASM_INVALID_ASSERT_OPCODE) {
BNX2X_ERR("DATA %cSTORM_ASSERT_INDEX 0x%x ="
" 0x%08x 0x%08x 0x%08x 0x%08x\n",
storm[i], j, row3, row2, row1, row0);
rc++;
} else {
break;
}
}
}
return rc;
}
static void bnx2x_panic_dump(struct bnx2x *bp)
{
int i;
u16 j, start, end;
BNX2X_ERR("begin crash dump -----------------\n");
for_each_queue(bp, i) {
struct bnx2x_fastpath *fp = &bp->fp[i];
struct eth_tx_db_data *hw_prods = fp->hw_tx_prods;
BNX2X_ERR("queue[%d]: tx_pkt_prod(%x) tx_pkt_cons(%x)"
" tx_bd_prod(%x) tx_bd_cons(%x) *tx_cons_sb(%x)"
" *rx_cons_sb(%x) rx_comp_prod(%x)"
" rx_comp_cons(%x) fp_c_idx(%x) fp_u_idx(%x)"
" bd data(%x,%x)\n",
i, fp->tx_pkt_prod, fp->tx_pkt_cons, fp->tx_bd_prod,
fp->tx_bd_cons, *fp->tx_cons_sb, *fp->rx_cons_sb,
fp->rx_comp_prod, fp->rx_comp_cons, fp->fp_c_idx,
fp->fp_u_idx, hw_prods->packets_prod,
hw_prods->bds_prod);
start = TX_BD(le16_to_cpu(*fp->tx_cons_sb) - 10);
end = TX_BD(le16_to_cpu(*fp->tx_cons_sb) + 245);
for (j = start; j < end; j++) {
struct sw_tx_bd *sw_bd = &fp->tx_buf_ring[j];
BNX2X_ERR("packet[%x]=[%p,%x]\n", j,
sw_bd->skb, sw_bd->first_bd);
}
start = TX_BD(fp->tx_bd_cons - 10);
end = TX_BD(fp->tx_bd_cons + 254);
for (j = start; j < end; j++) {
u32 *tx_bd = (u32 *)&fp->tx_desc_ring[j];
BNX2X_ERR("tx_bd[%x]=[%x:%x:%x:%x]\n",
j, tx_bd[0], tx_bd[1], tx_bd[2], tx_bd[3]);
}
start = RX_BD(le16_to_cpu(*fp->rx_cons_sb) - 10);
end = RX_BD(le16_to_cpu(*fp->rx_cons_sb) + 503);
for (j = start; j < end; j++) {
u32 *rx_bd = (u32 *)&fp->rx_desc_ring[j];
struct sw_rx_bd *sw_bd = &fp->rx_buf_ring[j];
BNX2X_ERR("rx_bd[%x]=[%x:%x] sw_bd=[%p]\n",
j, rx_bd[0], rx_bd[1], sw_bd->skb);
}
start = RCQ_BD(fp->rx_comp_cons - 10);
end = RCQ_BD(fp->rx_comp_cons + 503);
for (j = start; j < end; j++) {
u32 *cqe = (u32 *)&fp->rx_comp_ring[j];
BNX2X_ERR("cqe[%x]=[%x:%x:%x:%x]\n",
j, cqe[0], cqe[1], cqe[2], cqe[3]);
}
}
BNX2X_ERR("def_c_idx(%u) def_u_idx(%u) def_t_idx(%u)"
" def_x_idx(%u) def_att_idx(%u) attn_state(%u)"
" spq_prod_idx(%u) spq_cons_idx(%u)\n",
bp->def_c_idx, bp->def_u_idx, bp->def_t_idx, bp->def_x_idx,
bp->def_att_idx, bp->attn_state, bp->spq_prod_idx,
bp->spq_cons_idx);
bnx2x_mc_assert(bp);
BNX2X_ERR("end crash dump -----------------\n");
bp->stats_state = STATS_STATE_DISABLE;
DP(BNX2X_MSG_STATS, "stats_state - DISABLE\n");
}
static void bnx2x_enable_int(struct bnx2x *bp)
{
int port = bp->port;
u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0;
u32 val = REG_RD(bp, addr);
int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0;
if (msix) {
val &= ~HC_CONFIG_0_REG_SINGLE_ISR_EN_0;
val |= (HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 |
HC_CONFIG_0_REG_ATTN_BIT_EN_0);
} else {
val |= (HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
HC_CONFIG_0_REG_INT_LINE_EN_0 |
HC_CONFIG_0_REG_ATTN_BIT_EN_0);
val &= ~HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0;
}
DP(NETIF_MSG_INTR, "write %x to HC %d (addr 0x%x) msi %d\n",
val, port, addr, msix);
REG_WR(bp, addr, val);
}
static void bnx2x_disable_int(struct bnx2x *bp)
{
int port = bp->port;
u32 addr = port ? HC_REG_CONFIG_1 : HC_REG_CONFIG_0;
u32 val = REG_RD(bp, addr);
val &= ~(HC_CONFIG_0_REG_SINGLE_ISR_EN_0 |
HC_CONFIG_0_REG_MSI_MSIX_INT_EN_0 |
HC_CONFIG_0_REG_INT_LINE_EN_0 |
HC_CONFIG_0_REG_ATTN_BIT_EN_0);
DP(NETIF_MSG_INTR, "write %x to HC %d (addr 0x%x)\n",
val, port, addr);
REG_WR(bp, addr, val);
if (REG_RD(bp, addr) != val)
BNX2X_ERR("BUG! proper val not read from IGU!\n");
}
static void bnx2x_disable_int_sync(struct bnx2x *bp)
{
int msix = (bp->flags & USING_MSIX_FLAG) ? 1 : 0;
int i;
atomic_inc(&bp->intr_sem);
bnx2x_disable_int(bp);
/* Disable SP tasklet */
tasklet_disable(&bp->sp_task);
if (msix) {
for_each_queue(bp, i) {
synchronize_irq(bp->msix_table[i].vector);
}
/* one more for the Slow Path IRQ */
synchronize_irq(bp->msix_table[i].vector);
} else {
synchronize_irq(bp->pdev->irq);
}
}
/* fast path */
/****************************************************************************
* General service functions
****************************************************************************/
static inline void bnx2x_ack_sb(struct bnx2x *bp, u8 id,
u8 storm, u16 index, u8 op, u8 update)
{
u32 igu_addr = (IGU_ADDR_INT_ACK + IGU_PORT_BASE * bp->port) * 8;
struct igu_ack_register igu_ack;
igu_ack.status_block_index = index;
igu_ack.sb_id_and_flags =
((id << IGU_ACK_REGISTER_STATUS_BLOCK_ID_SHIFT) |
(storm << IGU_ACK_REGISTER_STORM_ID_SHIFT) |
(update << IGU_ACK_REGISTER_UPDATE_INDEX_SHIFT) |
(op << IGU_ACK_REGISTER_INTERRUPT_MODE_SHIFT));
/* DP(NETIF_MSG_INTR, "write 0x%08x to IGU addr 0x%x\n",
(*(u32 *)&igu_ack), BAR_IGU_INTMEM + igu_addr); */
REG_WR(bp, BAR_IGU_INTMEM + igu_addr, (*(u32 *)&igu_ack));
}
static inline u16 bnx2x_update_fpsb_idx(struct bnx2x_fastpath *fp)
{
struct host_status_block *fpsb = fp->status_blk;
u16 rc = 0;
barrier(); /* status block is written to by the chip */
if (fp->fp_c_idx != fpsb->c_status_block.status_block_index) {
fp->fp_c_idx = fpsb->c_status_block.status_block_index;
rc |= 1;
}
if (fp->fp_u_idx != fpsb->u_status_block.status_block_index) {
fp->fp_u_idx = fpsb->u_status_block.status_block_index;
rc |= 2;
}
return rc;
}
static inline int bnx2x_has_work(struct bnx2x_fastpath *fp)
{
u16 rx_cons_sb = le16_to_cpu(*fp->rx_cons_sb);
if ((rx_cons_sb & MAX_RCQ_DESC_CNT) == MAX_RCQ_DESC_CNT)
rx_cons_sb++;
if ((rx_cons_sb != fp->rx_comp_cons) ||
(le16_to_cpu(*fp->tx_cons_sb) != fp->tx_pkt_cons))
return 1;
return 0;
}
static u16 bnx2x_ack_int(struct bnx2x *bp)
{
u32 igu_addr = (IGU_ADDR_SIMD_MASK + IGU_PORT_BASE * bp->port) * 8;
u32 result = REG_RD(bp, BAR_IGU_INTMEM + igu_addr);
/* DP(NETIF_MSG_INTR, "read 0x%08x from IGU addr 0x%x\n",
result, BAR_IGU_INTMEM + igu_addr); */
#ifdef IGU_DEBUG
#warning IGU_DEBUG active
if (result == 0) {
BNX2X_ERR("read %x from IGU\n", result);
REG_WR(bp, TM_REG_TIMER_SOFT_RST, 0);
}
#endif
return result;
}
/****************************************************************************
* fast path service functions
****************************************************************************/
/* free skb in the packet ring at pos idx
return idx of last bd freed */
static u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fastpath *fp,
u16 idx)
{
struct sw_tx_bd *tx_buf = &fp->tx_buf_ring[idx];
struct eth_tx_bd *tx_bd;
struct sk_buff *skb = tx_buf->skb;
u16 bd_idx = tx_buf->first_bd;
int nbd;
DP(BNX2X_MSG_OFF, "pkt_idx %d buff @(%p)->skb %p\n",
idx, tx_buf, skb);
/* unmap first bd */
DP(BNX2X_MSG_OFF, "free bd_idx %d\n", bd_idx);
tx_bd = &fp->tx_desc_ring[bd_idx];
pci_unmap_single(bp->pdev, BD_UNMAP_ADDR(tx_bd),
BD_UNMAP_LEN(tx_bd), PCI_DMA_TODEVICE);
nbd = le16_to_cpu(tx_bd->nbd) - 1;
#ifdef BNX2X_STOP_ON_ERROR
if (nbd > (MAX_SKB_FRAGS + 2)) {
BNX2X_ERR("bad nbd!\n");
bnx2x_panic();
}
#endif
/* Skip a parse bd and the TSO split header bd
since they have no mapping */
if (nbd)
bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
if (tx_bd->bd_flags.as_bitfield & (ETH_TX_BD_FLAGS_IP_CSUM |
ETH_TX_BD_FLAGS_TCP_CSUM |
ETH_TX_BD_FLAGS_SW_LSO)) {
if (--nbd)
bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
tx_bd = &fp->tx_desc_ring[bd_idx];
/* is this a TSO split header bd? */
if (tx_bd->bd_flags.as_bitfield & ETH_TX_BD_FLAGS_SW_LSO) {
if (--nbd)
bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
}
}
/* now free frags */
while (nbd > 0) {
DP(BNX2X_MSG_OFF, "free frag bd_idx %d\n", bd_idx);
tx_bd = &fp->tx_desc_ring[bd_idx];
pci_unmap_page(bp->pdev, BD_UNMAP_ADDR(tx_bd),
BD_UNMAP_LEN(tx_bd), PCI_DMA_TODEVICE);
if (--nbd)
bd_idx = TX_BD(NEXT_TX_IDX(bd_idx));
}
/* release skb */
BUG_TRAP(skb);
dev_kfree_skb(skb);
tx_buf->first_bd = 0;
tx_buf->skb = NULL;
return bd_idx;
}
static inline u32 bnx2x_tx_avail(struct bnx2x_fastpath *fp)
{
u16 used;
u32 prod;
u32 cons;
/* Tell compiler that prod and cons can change */
barrier();
prod = fp->tx_bd_prod;
cons = fp->tx_bd_cons;
used = (NUM_TX_BD - NUM_TX_RINGS + prod - cons +
(cons / TX_DESC_CNT) - (prod / TX_DESC_CNT));
if (prod >= cons) {
/* used = prod - cons - prod/size + cons/size */
used -= NUM_TX_BD - NUM_TX_RINGS;
}
BUG_TRAP(used <= fp->bp->tx_ring_size);
BUG_TRAP((fp->bp->tx_ring_size - used) <= MAX_TX_AVAIL);
return (fp->bp->tx_ring_size - used);
}
static void bnx2x_tx_int(struct bnx2x_fastpath *fp, int work)
{
struct bnx2x *bp = fp->bp;
u16 hw_cons, sw_c
[ TRUNCATED ]
Hosted by DataForce ISP -
Powered by Openwall GNU/*/Linux