[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <200911010503.nA153ESA019066@blc-10-10.brocade.com>
Date: Sat, 31 Oct 2009 22:03:14 -0700
From: Rasesh Mody <rmody@...cade.com>
To: <netdev@...r.kernel.org>
CC: <adapter_linux_open_src_team@...cade.com>
Subject: Subject: [PATCH 2/6] bna: Brocade 10Gb Ethernet device driver
From: Rasesh Mody <rmody@...cade.com>
This is patch 2/6 which contains linux driver source for
Brocade's BR1010/BR1020 10Gb CEE capable ethernet adapter.
Re-based source against net-next-2.6 and re-submitting the
patch with few fixes.
We wish this patch to be considered for inclusion in net-next-2.6
Signed-off-by: Rasesh Mody <rmody@...cade.com>
---
bfa_timer.c | 97 ++
bfad_fwimg.c | 102 ++
bna_fn.c | 1982 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
bna_queue.c | 496 ++++++++++++++
bnad_ethtool.c | 1094 +++++++++++++++++++++++++++++++
5 files changed, 3771 insertions(+)
diff -ruP net-next-2.6-orig/drivers/net/bna/bfa_timer.c net-next-2.6-mod/drivers/net/bna/bfa_timer.c
--- net-next-2.6-orig/drivers/net/bna/bfa_timer.c 1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6-mod/drivers/net/bna/bfa_timer.c 2009-10-31 21:34:47.660532000 -0700
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * See LICENSE.bna for copyright and licensing details.
+ */
+
+#include <bfa_timer.h>
+#include <cs/bfa_debug.h>
+
+void
+bfa_timer_init(struct bfa_timer_mod_s *mod)
+{
+ INIT_LIST_HEAD(&mod->timer_q);
+}
+
+void
+bfa_timer_beat(struct bfa_timer_mod_s *mod)
+{
+ struct list_head *qh = &mod->timer_q;
+ struct list_head *qe, *qe_next;
+ struct bfa_timer_s *elem;
+ struct list_head timedout_q;
+
+ INIT_LIST_HEAD(&timedout_q);
+
+ qe = bfa_q_next(qh);
+
+ while (qe != qh) {
+ qe_next = bfa_q_next(qe);
+
+ elem = (struct bfa_timer_s *) qe;
+ if (elem->timeout <= BFA_TIMER_FREQ) {
+ elem->timeout = 0;
+ list_del(&elem->qe);
+ list_add_tail(&elem->qe, &timedout_q);
+ } else {
+ elem->timeout -= BFA_TIMER_FREQ;
+ }
+
+ qe = qe_next; /* go to next elem */
+ }
+
+ /*
+ * Pop all the timeout entries
+ */
+ while (!list_empty(&timedout_q)) {
+ bfa_q_deq(&timedout_q, &elem);
+ elem->timercb(elem->arg);
+ }
+}
+
+/**
+ * Should be called with lock protection
+ */
+void
+bfa_timer_begin(struct bfa_timer_mod_s *mod, struct bfa_timer_s *timer,
+ void (*timercb) (void *), void *arg, unsigned int timeout)
+{
+
+ bfa_assert(timercb != NULL);
+ bfa_assert(!bfa_q_is_on_q(&mod->timer_q, timer));
+
+ timer->timeout = timeout;
+ timer->timercb = timercb;
+ timer->arg = arg;
+
+ list_add_tail(&timer->qe, &mod->timer_q);
+}
+
+/**
+ * Should be called with lock protection
+ */
+void
+bfa_timer_stop(struct bfa_timer_s *timer)
+{
+ bfa_assert(!list_empty(&timer->qe));
+
+ list_del(&timer->qe);
+}
diff -ruP net-next-2.6-orig/drivers/net/bna/bfad_fwimg.c net-next-2.6-mod/drivers/net/bna/bfad_fwimg.c
--- net-next-2.6-orig/drivers/net/bna/bfad_fwimg.c 1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6-mod/drivers/net/bna/bfad_fwimg.c 2009-10-31 21:34:47.667534000 -0700
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * See LICENSE.bna for copyright and licensing details.
+ */
+
+/**
+ * bfad_fwimg.c Linux driver PCI interface module.
+ */
+#include <bfa_os_inc.h>
+#include <defs/bfa_defs_version.h>
+#include <defs/bfa_defs_pci.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>
+#include <asm/fcntl.h>
+#include <linux/pci.h>
+#include <linux/firmware.h>
+#include <bfa_fwimg_priv.h>
+
+u32 bfi_image_ct_size;
+u32 bfi_image_cb_size;
+u32 *bfi_image_ct;
+u32 *bfi_image_cb;
+
+
+#define BFAD_FW_FILE_CT "ctfw.bin"
+#define BFAD_FW_FILE_CB "cbfw.bin"
+
+u32 *
+bfad_read_firmware(struct pci_dev *pdev, u32 **bfi_image,
+ u32 *bfi_image_size, char *fw_name)
+{
+ const struct firmware *fw;
+
+ if (request_firmware(&fw, fw_name, &pdev->dev)) {
+ printk(KERN_ALERT "Can't locate firmware %s\n", fw_name);
+ goto error;
+ }
+
+ *bfi_image = vmalloc(fw->size);
+ if (NULL == *bfi_image) {
+ printk(KERN_ALERT "Fail to allocate buffer for fw image "
+ "size=%x!\n", (u32) fw->size);
+ goto error;
+ }
+
+ memcpy(*bfi_image, fw->data, fw->size);
+ *bfi_image_size = fw->size/sizeof(u32);
+
+ return *bfi_image;
+
+error:
+ return NULL;
+}
+
+u32 *
+bfad_get_firmware_buf(struct pci_dev *pdev)
+{
+ if (pdev->device == BFA_PCI_DEVICE_ID_CT) {
+ if (bfi_image_ct_size == 0)
+ bfad_read_firmware(pdev, &bfi_image_ct,
+ &bfi_image_ct_size, BFAD_FW_FILE_CT);
+ return bfi_image_ct;
+ } else {
+ if (bfi_image_cb_size == 0)
+ bfad_read_firmware(pdev, &bfi_image_cb,
+ &bfi_image_cb_size, BFAD_FW_FILE_CB);
+ return bfi_image_cb;
+ }
+}
+
+u32 *
+bfi_image_ct_get_chunk(u32 off)
+{ return (u32 *)(bfi_image_ct + off); }
+
+u32 *
+bfi_image_cb_get_chunk(u32 off)
+{ return (u32 *)(bfi_image_cb + off); }
+
+
+char bfa_version[BFA_VERSION_LEN] = "rmody_pvt_bld 08/26/2009 11.26.03";
diff -ruP net-next-2.6-orig/drivers/net/bna/bna_fn.c net-next-2.6-mod/drivers/net/bna/bna_fn.c
--- net-next-2.6-orig/drivers/net/bna/bna_fn.c 1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6-mod/drivers/net/bna/bna_fn.c 2009-10-31 21:34:47.675535000 -0700
@@ -0,0 +1,1982 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2007-2008 Brocade Communications Systems, Inc.
+ * All rights reserved.
+ *
+ * @file bna_fn.c BNA Rx and Tx Function Management
+ */
+
+#include <bna_os.h>
+#include "bna.h"
+#include "bna_hwreg.h"
+#include "bna_priv.h"
+#include <bfi/bfi_ll.h>
+#include <bfi/bfi_cee.h>
+
+
+/*
+ * 12 bit Max VLAN Id mask used to
+ * wrap overflowing VLANs wraps around the
+ * max value of 4095
+ */
+#define BNA_MAX_VLAN_ID_MASK 0x00000fff
+
+const struct bna_chip_regs_offset reg_offset[] =
+ { {HOST_PAGE_NUM_FN0, HOSTFN0_INT_STATUS,
+ HOSTFN0_INT_MASK, HOST_MSIX_ERR_INDEX_FN0},
+ {HOST_PAGE_NUM_FN1, HOSTFN1_INT_STATUS,
+ HOSTFN1_INT_MASK, HOST_MSIX_ERR_INDEX_FN1},
+ {HOST_PAGE_NUM_FN2, HOSTFN2_INT_STATUS,
+ HOSTFN2_INT_MASK, HOST_MSIX_ERR_INDEX_FN2},
+ {HOST_PAGE_NUM_FN3, HOSTFN3_INT_STATUS,
+ HOSTFN3_INT_MASK, HOST_MSIX_ERR_INDEX_FN3},
+ };
+/**
+ * bna_init()
+ *
+ * Called by the driver during initialization. The driver is
+ * expected to allocate bna_dev_s structure for the BNA layer.
+ *
+ * @param[in] bar0 - BAR0 value
+ * @param[in] bna_handle - pointer to BNA device structure
+ * allocated by the calling driver
+ * @return BNA_OK - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+void
+bna_init(struct bna_dev_s *dev, void *bar0, void *stats,
+ struct bna_dma_addr stats_dma, struct bfa_trc_mod_s *trcmod)
+{
+ u32 pcifn;
+
+ memset(dev, 0, sizeof(struct bna_dev_s));
+
+ dev->trcmod = trcmod;
+
+ dev->bar0 = (u8 *)bar0;
+ dev->hw_stats = (struct bfi_ll_stats *)stats;
+ dev->hw_stats_dma.msb = stats_dma.msb;
+ dev->hw_stats_dma.lsb = stats_dma.lsb;
+
+ dev->rxf_promiscuous_id = BNA_RXF_ID_NONE;
+ dev->rxf_default_id = BNA_RXF_ID_NONE;
+
+ pcifn = bna_reg_read(dev->bar0 + FNC_ID_REG);
+ pcifn = bna_reg_read(dev->bar0 + FNC_ID_REG);
+ BNA_ASSERT(pcifn <= 3);
+
+ dev->regs.page_addr = dev->bar0 + reg_offset[pcifn].page_addr;
+ dev->regs.fn_int_status = dev->bar0 + reg_offset[pcifn].fn_int_status;
+ dev->regs.fn_int_mask = dev->bar0 + reg_offset[pcifn].fn_int_mask;
+
+ if (pcifn < 3)
+ dev->port = 0;
+ else
+ dev->port = 1;
+
+ dev->pci_fn = pcifn;
+ DPRINTK(DEBUG, "LL Driver Using PCI fn (%d)\n", dev->pci_fn);
+
+ dev->ioc_disable_pending = 0;
+}
+
+/**
+ * bna_uninit()
+ *
+ * Called by the driver during removal/unload.
+ *
+ * @param[in] bna_handle - pointer to BNA device structure
+ * allocated by the calling driver
+ *
+ * @return BNA_OK - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status_e bna_uninit(void *bna_handle)
+{
+ return BNA_OK;
+}
+
+/**
+ * bna_rit_config_set()
+ *
+ * Loads RIT entries "rit" into RIT starting from RIT index "rit_id".
+ * Care must be taken not to overlap regions within the RIT.
+ *
+ * @param[in] dev - pointer to BNA device structure
+ * @param[in] rit_offset - offset into the RIT
+ * @param[in] rit - RIT entry
+ * @param[in] rit_size - size of RIT entry
+ *
+ * @return BNA_OK - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+void
+bna_rit_config_set(struct bna_dev_s *dev, unsigned int rit_offset,
+ const struct bna_rit_entry rit[], unsigned int rit_size)
+{
+ int i;
+
+ struct bna_rit_mem *rit_mem;
+
+ BNA_ASSERT(BNA_POWER_OF_2(rit_size));
+ BNA_ASSERT((rit_offset + rit_size) < BNA_RIT_SIZE);
+
+ rit_mem = (struct bna_rit_mem *)
+ BNA_GET_MEM_BASE_ADDR(dev->bar0, FUNCTION_TO_RXQ_TRANSLATE);
+
+ dev->rit_size[rit_offset] = rit_size;
+
+ bna_reg_write(dev->regs.page_addr,
+ BNA_GET_PAGE_NUM(RXA0_MEM_BLK_BASE_PG_NUM + dev->port,
+ FUNCTION_TO_RXQ_TRANSLATE));
+
+ for (i = 0; i < rit_size; i++) {
+ bna_mem_writew(&rit_mem[i + rit_offset],
+ rit[i].large_rxq_id << 6 | rit[i].small_rxq_id);
+ }
+}
+
+/**
+ * bna_rxf_config_set()
+ *
+ * For RxF "rxf_id", it configures RxF based on "cfg_ptr", and indicates
+ * to the statistics collector to collect statistics for this Rx-Function.
+ *
+ * @param[in] dev - pointer to BNA device structure
+ * @param[in] rxf_id - rx-function ID.
+ * @param[in] cfg_ptr - pointer to rx-function configuration.
+ *
+ * @return BNA_OK - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status_e
+bna_rxf_config_set(struct bna_dev_s *dev, unsigned int rxf_id,
+ const struct bna_rxf_config *cfg_ptr)
+{
+ u32 i;
+
+ struct bna_rss_mem *rss_mem;
+ struct bna_rx_fndb_ram *rx_fndb_ram;
+
+ BNA_ASSERT(rxf_id < BNA_RXF_ID_MAX);
+
+ rss_mem = (struct bna_rss_mem *)
+ BNA_GET_MEM_BASE_ADDR(dev->bar0, RSS_TABLE_BASE_OFFSET);
+ rx_fndb_ram = (struct bna_rx_fndb_ram *)
+ BNA_GET_MEM_BASE_ADDR(dev->bar0, RX_FNDB_RAM_BASE_OFFSET);
+
+ /* Need to revisit, don't do this check */
+ if (((cfg_ptr->flags & BNA_RXF_CF_SM_LG_RXQ)) &&
+ (cfg_ptr->hds.type == 1)) {
+ /* HDS and small-large RxQs are mutually exclusive */
+ DPRINTK(ERR,
+ "Small/Large & HDS cannot be set simultaneously\n");
+ return BNA_FAIL;
+ }
+
+ if (cfg_ptr->flags & BNA_RXF_CF_RSS_ENABLE) {
+ BNA_ASSERT(cfg_ptr->rss.hash_mask ==
+ dev->rit_size[cfg_ptr->rit_offset] - 1);
+
+ /* configure RSS Table */
+ bna_reg_write(dev->regs.page_addr, BNA_GET_PAGE_NUM(
+ RAD0_MEM_BLK_BASE_PG_NUM + dev->port,
+ RSS_TABLE_BASE_OFFSET));
+
+ /* temporarily disable RSS, while hash value is being written */
+ bna_mem_writew(&rss_mem[0].type_n_hash, 0);
+
+ for (i = 0; i < BNA_RSS_HASH_KEY_LEN; i++) {
+ bna_mem_writew(
+ &rss_mem[0].hash_key[(
+ BNA_RSS_HASH_KEY_LEN - 1) - i],
+ bna_os_htonl(cfg_ptr->rss.toeplitz_hash_key[i]));
+ }
+
+ bna_mem_writew(&rss_mem[0].type_n_hash, cfg_ptr->rss.type |
+ cfg_ptr->rss.hash_mask);
+
+ }
+ /* configure RxF based on "cfg_ptr" */
+ bna_reg_write(dev->regs.page_addr, BNA_GET_PAGE_NUM(
+ LUT0_MEM_BLK_BASE_PG_NUM + (dev->port * 2),
+ RX_FNDB_RAM_BASE_OFFSET));
+
+ /* we always use RSS table 0 */
+ bna_mem_writew(&rx_fndb_ram[rxf_id].rss_prop,
+ cfg_ptr->flags & BNA_RXF_CF_RSS_ENABLE);
+
+ /* small large buffer enable/disable */
+ bna_mem_writew(&rx_fndb_ram[rxf_id].size_routing_props,
+ (cfg_ptr->flags & BNA_RXF_CF_SM_LG_RXQ) | 0x80);
+
+ /* RIT offset, HDS forced offset, multicast RxQ Id*/
+ bna_mem_writew(&rx_fndb_ram[rxf_id].rit_hds_mcastq,
+ (cfg_ptr->rit_offset << 16) |
+ (cfg_ptr->hds.forced_offset << 8) |
+ (cfg_ptr->hds.type & BNA_HDS_FORCED) |
+ cfg_ptr->mcast_rxq_id);
+
+ /* default vlan tag, default function enable, strip vlan bytes,
+ HDS type, header size */
+ bna_mem_writew(&rx_fndb_ram[rxf_id].control_flags,
+ (cfg_ptr->default_vlan << 16) | (cfg_ptr->flags &
+ (BNA_RXF_CF_DEFAULT_VLAN |
+ BNA_RXF_CF_DEFAULT_FUNCTION_ENABLE |
+ BNA_RXF_CF_VLAN_STRIP)) |
+ (cfg_ptr->hds.type & ~BNA_HDS_FORCED) |
+ cfg_ptr->hds.header_size);
+
+ /* turn on statistics collection for this RxF */
+ dev->rxf_active |= ((u64)1 << rxf_id);
+ return BNA_OK;
+}
+
+/**
+ * bna_rxf_config_clear()
+ *
+ * For RxF "rxf_id", it clear its configuration and indicates to the
+ * statistics collector to stop collecting statistics for this
+ * Rx-Function.
+ *
+ * @param[in] dev - pointer to BNA device structure
+ * @param[in] rxf_id - rx-function ID.
+ *
+ * @return BNA_OK - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+void
+bna_rxf_config_clear(struct bna_dev_s *dev, unsigned int rxf_id)
+{
+ struct bna_rx_fndb_ram *rx_fndb_ram;
+
+ BNA_ASSERT(rxf_id < BNA_RXF_ID_MAX);
+
+ rx_fndb_ram = (struct bna_rx_fndb_ram *)
+ BNA_GET_MEM_BASE_ADDR(dev->bar0, RX_FNDB_RAM_BASE_OFFSET);
+
+ /* clear configuration of RxF base */
+ bna_reg_write(dev->regs.page_addr,
+ BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM +
+ (dev->port * 2), RX_FNDB_RAM_BASE_OFFSET));
+
+ /* we always use RSS table 0 */
+ bna_mem_writew(&rx_fndb_ram[rxf_id].rss_prop, 0);
+
+ /* small large buffer enable/disable */
+ bna_mem_writew(&rx_fndb_ram[rxf_id].size_routing_props, 0x80);
+
+ /* RIT offset, HDS forced offset, multicast RxQ Id*/
+ bna_mem_writew(&rx_fndb_ram[rxf_id].rit_hds_mcastq, 0);
+
+ /* default vlan tag, default function enable, strip vlan bytes,
+ HDS type, header size */
+ bna_mem_writew(&rx_fndb_ram[rxf_id].control_flags, 0);
+
+ /* turn off statistics collection for this RxF */
+ dev->rxf_active &= ~((u64)1 << rxf_id);
+}
+
+/**
+ * bna_rxf_disable()
+ *
+ * Disables the Rx Function without clearing the configuration
+ * Also disables collection of statistics.
+ *
+ * @param[in] dev - Pointer to BNA device handle
+ * @param[in] rxf_id - Id of the Rx Function to be disabled
+ *
+ * @return BNA_OK if mbox command succeeded, else BNA_FAIL
+ */
+enum bna_status_e
+bna_rxf_disable(struct bna_dev_s *dev, unsigned int rxf_id)
+{
+ struct bfi_ll_rxf_multi_req ll_req;
+ u64 bit_mask = 1 << rxf_id;
+ enum bna_status_e status;
+
+ bfi_h2i_set(ll_req.mh, BFI_MC_LL, BFI_LL_H2I_RX_REQ, 0);
+ ll_req.rxf_id_mask[0] = bna_os_htonl((u32)bit_mask);
+ ll_req.rxf_id_mask[1] = bna_os_htonl((u32)(bit_mask >> 32));
+ ll_req.enable = 0;
+
+ status = bna_mbox_send(dev, &ll_req, sizeof(ll_req), dev->cbarg);
+ if (!status)
+ dev->rxf_active &= ~bit_mask;
+ return status;
+}
+
+
+/* TODO : Delete when Windows migration is complete */
+void
+bna_rxf_disable_old(struct bna_dev_s *dev, unsigned int rxf_id)
+{
+ struct bna_rx_fndb_ram *rx_fndb_ram;
+ u32 ctl_flags;
+
+ BNA_ASSERT(rxf_id < BNA_RXF_ID_MAX);
+
+ /* Clear the vlan table first, before writing to the Rx Fn DB */
+ bna_rxf_vlan_del_all(dev, rxf_id);
+
+ rx_fndb_ram = (struct bna_rx_fndb_ram *)
+ BNA_GET_MEM_BASE_ADDR(dev->bar0, RX_FNDB_RAM_BASE_OFFSET);
+
+ bna_reg_write(dev->regs.page_addr,
+ BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM + (dev->port * 2),
+ RX_FNDB_RAM_BASE_OFFSET));
+
+ ctl_flags = bna_mem_readw(&rx_fndb_ram[rxf_id].control_flags);
+
+ /* Enable setting of the default vlan tag for untagged packets */
+ /* Don't need to store these already there in the BNA config */
+ ctl_flags |= BNA_RXF_CF_DEFAULT_VLAN;
+
+ bna_mem_writew(&rx_fndb_ram[rxf_id].control_flags, ctl_flags);
+
+ /* turn off statistics collection for this RxF */
+ dev->rxf_active &= ~((u64)1 << rxf_id);
+}
+
+/**
+ * bna_rxf_enable()
+ *
+ * Enables the Rx Function
+ *
+ * @param[in] dev - Pointer to BNA device handle
+ * @param[in] rxf_id - Id of the Rx Function to be disabled
+ *
+ * @return BNA_OK if mbox command succeeded, else BNA_FAIL
+ */
+enum bna_status_e
+bna_rxf_enable(struct bna_dev_s *dev, unsigned int rxf_id)
+{
+ struct bfi_ll_rxf_multi_req ll_req;
+ u64 bit_mask = 1 << rxf_id;
+ enum bna_status_e status;
+
+ bfi_h2i_set(ll_req.mh, BFI_MC_LL, BFI_LL_H2I_RX_REQ, 0);
+ ll_req.rxf_id_mask[0] = bna_os_htonl((u32)bit_mask);
+ ll_req.rxf_id_mask[1] = bna_os_htonl((u32)(bit_mask >> 32));
+ ll_req.enable = 1;
+
+ status = bna_mbox_send(dev, &ll_req, sizeof(ll_req), dev->cbarg);
+ if (!status)
+ dev->rxf_active |= bit_mask;
+ return status;
+}
+
+
+enum bna_status_e
+bna_multi_rxf_active(struct bna_dev_s *dev, u64 rxf_id_mask, u8 enable)
+{
+ struct bfi_ll_rxf_multi_req ll_req;
+ enum bna_status_e status;
+
+ bfi_h2i_set(ll_req.mh, BFI_MC_LL, BFI_LL_H2I_RX_REQ, 0);
+ ll_req.rxf_id_mask[0] = bna_os_htonl((u32)rxf_id_mask);
+ ll_req.rxf_id_mask[1] = bna_os_htonl((u32)(rxf_id_mask >> 32));
+ ll_req.enable = enable;
+
+ status = bna_mbox_send(dev, &ll_req, sizeof(ll_req), dev->cbarg);
+ if (!status) {
+ if (enable)
+ dev->rxf_active |= rxf_id_mask;
+ else
+ dev->rxf_active &= ~rxf_id_mask;
+ }
+ return status;
+}
+
+/**
+ * bna_rxf_ucast_mac_set()
+ *
+ * For RxF "rxf_id", it overwrites the burnt-in unicast MAC with
+ * the one specified by "mac_ptr".
+ *
+ * @param[in] dev - pointer to BNA device structure
+ * @param[in] rxf_id - rx-function ID.
+ * @param[in] mac_addr_ptr - pointer to mac adddress to set
+ *
+ * @return BNA_OK - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status_e
+bna_rxf_ucast_mac_set(struct bna_dev_s *dev, unsigned int rxf_id,
+ const u8 *mac_addr_ptr)
+{
+ struct bfi_ll_mac_addr_req cmd;
+
+ BNA_ASSERT(rxf_id < BNA_RXF_ID_MAX);
+
+ /* we are supposed to set MAC adresses for default RxF only */
+ if (dev->rxf_default_id == BNA_RXF_ID_NONE) {
+ if (rxf_id != BNA_DEFAULT_RXF_ID) {
+ DPRINTK(ERR,
+ "RxF Id [%d] Not Default RxF Id\n", rxf_id);
+ return BNA_FAIL;
+ }
+ } else {
+ if (rxf_id != dev->rxf_default_id) {
+ DPRINTK(ERR,
+ "RxF Id[%d] Not current Default RxF Id" "[%d]\n",
+ rxf_id, dev->rxf_default_id);
+ return BNA_FAIL;
+ }
+ }
+
+ bfi_h2i_set(cmd.mh, BFI_MC_LL, BFI_LL_H2I_MAC_UCAST_SET_REQ, 0);
+ cmd.rxf_id = rxf_id;
+ bna_os_memcpy(&cmd.mac_addr, mac_addr_ptr, sizeof(cmd.mac_addr));
+
+ return bna_mbox_send(dev, &cmd, sizeof(cmd), dev->cbarg);
+}
+
+/**
+ * bna_rxf_ucast_mac_add()
+ *
+ * For RxF "rxf_id", it adds the unicast MAC specified by "mac_ptr".
+ *
+ * @param[in] dev - pointer to BNA device structure
+ * @param[in] rxf_id - rx-function ID.
+ * @param[in] mac_addr_ptr - pointer to mac adddress to add
+ *
+ * @return BNA_OK - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status_e
+bna_rxf_ucast_mac_add(struct bna_dev_s *dev, unsigned int rxf_id,
+ const u8 *mac_addr_ptr)
+{
+ struct bfi_ll_mac_addr_req cmd;
+
+
+ BNA_ASSERT(rxf_id < BNA_RXF_ID_MAX);
+ /* we are not supposed to add MAC adresses to default RxF */
+ if (rxf_id == dev->rxf_default_id) {
+ DPRINTK(ERR,
+ "Cannot add MAC address for default RxF[%d]\n", rxf_id);
+ return BNA_FAIL;
+ }
+
+ bfi_h2i_set(cmd.mh, BFI_MC_LL, BFI_LL_H2I_MAC_UCAST_ADD_REQ, 0);
+
+ cmd.rxf_id = rxf_id;
+ bna_os_memcpy(&cmd.mac_addr, mac_addr_ptr, sizeof(cmd.mac_addr));
+
+ /* send command to firmware */
+ return bna_mbox_send(dev, &cmd, sizeof(cmd), dev->cbarg);
+}
+
+/**
+ * bna_rxf_ucast_mac_del()
+ *
+ * For RxF "rxf_id", it deletes the unicast MAC specified by "mac_ptr".
+ *
+ * @param[in] dev - pointer to BNA device structure
+ * @param[in] rxf_id - rx-function ID.
+ * @param[in] mac_addr_ptr - pointer to mac adddress to add
+ *
+ * @return BNA_OK - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status_e
+bna_rxf_ucast_mac_del(struct bna_dev_s *dev, unsigned int rxf_id,
+ const u8 *mac_addr_ptr)
+{
+ struct bfi_ll_mac_addr_req cmd;
+
+ BNA_ASSERT(rxf_id < BNA_RXF_ID_MAX);
+
+ /* we are not supposed to delete MAC adresses from default RxF */
+ if (rxf_id == dev->rxf_default_id) {
+ DPRINTK(ERR,
+ "Cannot del MAC address for default RxF[%d]\n", rxf_id);
+ return BNA_FAIL;
+ }
+
+ bfi_h2i_set(cmd.mh, BFI_MC_LL, BFI_LL_H2I_MAC_UCAST_DEL_REQ, 0);
+
+ cmd.rxf_id = rxf_id;
+ bna_os_memcpy(&cmd.mac_addr, mac_addr_ptr, sizeof(cmd.mac_addr));
+
+ /* send command to firmware */
+ return bna_mbox_send(dev, &cmd, sizeof(cmd), dev->cbarg);
+}
+
+/**
+ * bna_rxf_mcast_mac_add()
+ *
+ * For RxF "rxf_id", it adds the multicast MAC specified by
+ * "mac_ptr".
+ *
+ * @param[in] dev - pointer to BNA device structure
+ * @param[in] rxf_id - rx-function ID.
+ * @param[in] mac_addr_ptr - pointer to mac adddress to add
+ *
+ * @return BNA_OK - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status_e
+bna_rxf_mcast_mac_add(struct bna_dev_s *dev, unsigned int rxf_id,
+ const u8 *mac_addr_ptr)
+{
+ u32 mac_47_32, mac_31_0, i;
+ u8 *mac_ptr = (u8 *)mac_addr_ptr;
+ struct bfi_ll_mac_addr_req cmd;
+
+ BNA_ASSERT(rxf_id < BNA_RXF_ID_MAX);
+
+ mac_47_32 = (mac_ptr[0] << 8) | mac_ptr[1];
+ mac_31_0 = (mac_ptr[2] << 24) | (mac_ptr[3] << 16) |
+ (mac_ptr[4] << 8) | mac_ptr[5];
+
+ for (i = 0; i < BNA_MCAST_TABLE_SIZE; i++) {
+ if ((mac_47_32 == dev->mcast_47_32[i]) &&
+ (mac_31_0 == dev->mcast_31_0[i])) {
+ /* existing entry found, stop and use it */
+ break;
+ }
+ }
+
+ if (i == BNA_MCAST_TABLE_SIZE) {
+ /* no existing entry found we need to find the
+ first unused entry */
+ for (i = 0; i < BNA_MCAST_TABLE_SIZE; i++) {
+ if ((dev->mcast_47_32[i] == 0) &&
+ (dev->mcast_31_0[i] == 0)) {
+ /* unused entry found, stop and use it */
+ break;
+ }
+ }
+ }
+
+ if (i == BNA_MCAST_TABLE_SIZE) {
+ /* no entry available, table full */
+ DPRINTK(ERR, "Multicast MAC table is full\n");
+ return BNA_FAIL;
+ }
+
+ dev->mcast_47_32[i] = mac_47_32;
+ dev->mcast_31_0[i] = mac_31_0;
+
+
+ bfi_h2i_set(cmd.mh, BFI_MC_LL, BFI_LL_H2I_MAC_MCAST_ADD_REQ, 0);
+
+ cmd.rxf_id = rxf_id;
+ bna_os_memcpy(&cmd.mac_addr, mac_addr_ptr, sizeof(cmd.mac_addr));
+
+ /* send command to firmware */
+ return bna_mbox_send(dev, &cmd, sizeof(cmd), dev->cbarg);
+}
+
+/**
+ * bna_rxf_mcast_mac_del()
+ *
+ * For RxF "rxf_id", it deletes the multicast MAC specified by
+ * "mac_ptr".
+ *
+ * @param[in] dev - pointer to BNA device structure
+ * @param[in] rxf_id - rx-function ID.
+ * @param[in] mac_addr_ptr - pointer to mac adddress to add
+ *
+ * @return BNA_OK - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status_e
+bna_rxf_mcast_mac_del(struct bna_dev_s *dev, unsigned int rxf_id,
+ const u8 *mac_addr_ptr)
+{
+ u32 mac_47_32, mac_31_0, i;
+ u8 *mac_ptr = (u8 *)mac_addr_ptr;
+ struct bfi_ll_mac_addr_req cmd;
+
+ BNA_ASSERT(rxf_id < BNA_RXF_ID_MAX);
+
+ mac_47_32 = (mac_ptr[0] << 8) | mac_ptr[1];
+ mac_31_0 = (mac_ptr[2] << 24) | (mac_ptr[3] << 16) |
+ (mac_ptr[4] << 8) | mac_ptr[5];
+
+ for (i = 0; i < BNA_MCAST_TABLE_SIZE; i++) {
+ if ((mac_47_32 == dev->mcast_47_32[i]) &&
+ (mac_31_0 == dev->mcast_31_0[i])) {
+ /* existing entry found, stop and use it */
+ break;
+ }
+ }
+
+ if (i == BNA_MCAST_TABLE_SIZE) {
+ /* no existing entry found */
+ DPRINTK(ERR, "MAC 0x%x:%x not found\n", mac_47_32, mac_31_0);
+ return BNA_FAIL;
+ }
+
+ bfi_h2i_set(cmd.mh, BFI_MC_LL, BFI_LL_H2I_MAC_MCAST_DEL_REQ, 0);
+
+ cmd.rxf_id = rxf_id;
+ bna_os_memcpy(&cmd.mac_addr, mac_addr_ptr, sizeof(cmd.mac_addr));
+
+
+ dev->mcast_47_32[i] = 0;
+ dev->mcast_31_0[i] = 0;
+
+ /* send command to firmware */
+ return bna_mbox_send(dev, &cmd, sizeof(cmd), dev->cbarg);
+}
+
+static void
+bna_mac_addr_to_string(u32 mac_47_32, u32 mac_31_0, u8 *mac)
+{
+ u8 *mac_ptr = (u8 *)mac;
+ int i;
+
+ for (i = 1; i >= 0; i--)
+ mac_ptr[1-i] = ((mac_47_32) & (0xff << (i*8))) >> (i * 8);
+
+ mac_ptr = &mac_ptr[2];
+ for (i = 3; i >= 0; i--)
+ mac_ptr[3-i] = ((mac_31_0) & (0xff << (i*8))) >> (i * 8);
+}
+
+/**
+ * bna_rxf_mcast_mac_set_list()
+ *
+ * For RxF "rxf_id", it sets the multicast MAC addresses
+ * specified by "mac_addr_ptr". The function first deletes the MAC addresses in
+ * the existing list that is not found in the new list. It then adds the new
+ * addresses that are in the new list but not in the old list. It then replaces
+ * the old list with the new list in the bna_dev structure.
+ *
+ * @param[in] dev - pointer to BNA device structure
+ * @param[in] rxf_id - rx-function ID.
+ * @param[in] mac_addr_ptr - pointer to the list of mac
+ * adddresses to set
+ * @param[in] mac_addr_num - number of mac addresses in the
+ * list
+ *
+ * @return BNA_OK - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status_e
+bna_rxf_mcast_mac_set_list(struct bna_dev_s *dev, unsigned int rxf_id,
+ const u8 *mac_addr_ptr ,
+ unsigned int mac_addr_num)
+{
+ u32 *mcast_47_32 = &dev->tmp_mc_47_32[0];
+ u32 *mcast_31_0 = &dev->tmp_mc_31_0[0];
+ u32 i, j;
+ u8 *mac_ptr = (u8 *)mac_addr_ptr;
+ int found;
+ struct bfi_ll_mac_addr_req cmd;
+ u8 tmp_mac[ETH_ALEN];
+
+ bna_os_memset(mcast_47_32, 0, sizeof(u32) * BNA_MCAST_TABLE_SIZE);
+ bna_os_memset(mcast_31_0, 0, sizeof(u32) * BNA_MCAST_TABLE_SIZE);
+
+ BNA_ASSERT(rxf_id < BNA_RXF_ID_MAX);
+ if (mac_addr_num > BNA_MCAST_TABLE_SIZE) {
+ DPRINTK(ERR,
+ "Too many Multicast Addresses [%d]\n", mac_addr_num);
+ return BNA_FAIL;
+ }
+
+ for (i = 0; i < mac_addr_num; i++) {
+ if (!BNA_MAC_IS_MULTICAST(mac_ptr[i * 6]))
+ return BNA_FAIL;
+ mcast_47_32[i] = (mac_ptr[i * 6] << 8) | mac_ptr[i * 6 + 1];
+ mcast_31_0[i] = (mac_ptr[i * 6 + 2] << 24) |
+ (mac_ptr[i * 6 + 3] << 16) |
+ (mac_ptr[i * 6 + 4] << 8) |
+ mac_ptr[i * 6 + 5];
+ if ((mcast_47_32[i] == 0) && (mcast_31_0[i] == 0))
+ return BNA_FAIL;
+ DPRINTK(DEBUG, "Multicast Addr %d : 0x%x:0x%x\n",
+ i, mcast_47_32[i], mcast_31_0[i]);
+ }
+
+ /* find MAC addresses to delete */
+ for (i = 0; i < BNA_MCAST_TABLE_SIZE; i++) {
+ if ((dev->mcast_47_32[i] == 0) && (dev->mcast_31_0[i] == 0))
+ continue;
+
+ found = 0;
+ for (j = 0; j < mac_addr_num; j++) {
+ if ((mcast_47_32[j] == dev->mcast_47_32[i]) &&
+ (mcast_31_0[j] == dev->mcast_31_0[i])) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ bfi_h2i_set(cmd.mh, BFI_MC_LL,
+ BFI_LL_H2I_MAC_MCAST_DEL_REQ, 0);
+ cmd.rxf_id = rxf_id;
+ bna_mac_addr_to_string(dev->mcast_47_32[i],
+ dev->mcast_31_0[i],
+ &tmp_mac[0]);
+ bna_os_memcpy(&cmd.mac_addr, &tmp_mac,
+ sizeof(cmd.mac_addr));
+
+ DPRINTK(INFO,
+ "Deleting MCAST MAC 0x%x:0x%x on port %u RxF %u\n",
+ dev->mcast_47_32[i], dev->mcast_31_0[i],
+ dev->port, rxf_id);
+
+
+ if (BNA_FAIL == bna_mbox_send(dev, &cmd, sizeof(cmd),
+ dev->cbarg)) {
+ DPRINTK(ERR,
+ "Failed to add to cmd [%d/%d] "
+ "for RxF %d to Q.. Aborting\n",
+ cmd.mh.msg_class, cmd.mh.msg_id,
+ cmd.rxf_id);
+ return BNA_FAIL;
+ }
+ }
+ }
+
+ /* find MAC addresses to add */
+ for (i = 0; i < mac_addr_num; i++) {
+ found = 0;
+
+ for (j = 0; j < BNA_MCAST_TABLE_SIZE; j++) {
+ if ((mcast_47_32[i] == dev->mcast_47_32[j]) &&
+ (mcast_31_0[i] == dev->mcast_31_0[j])) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ bfi_h2i_set(cmd.mh, BFI_MC_LL,
+ BFI_LL_H2I_MAC_MCAST_ADD_REQ, 0);
+ cmd.rxf_id = rxf_id;
+ bna_mac_addr_to_string(mcast_47_32[i],
+ mcast_31_0[i], &tmp_mac[0]);
+ bna_os_memcpy(&cmd.mac_addr, &tmp_mac,
+ sizeof(cmd.mac_addr));
+
+ DPRINTK(INFO,
+ "Adding MCAST MAC 0x%x:0x%x on port %u RxF %u\n",
+ mcast_47_32[i], mcast_31_0[i],
+ dev->port, rxf_id);
+
+
+ if (BNA_FAIL == bna_mbox_send(dev, &cmd, sizeof(cmd),
+ dev->cbarg)) {
+ DPRINTK(ERR,
+ "Failed to add to cmd [%d/%d] "
+ "for RxF %d to Q.. Aborting\n",
+ cmd.mh.msg_class, cmd.mh.msg_id,
+ cmd.rxf_id);
+ return BNA_FAIL;
+ }
+ }
+ }
+
+ bna_os_memset(&dev->mcast_47_32[0], 0, sizeof(u32) *
+ BNA_MCAST_TABLE_SIZE);
+ bna_os_memset(&dev->mcast_31_0[0], 0, sizeof(u32) *
+ BNA_MCAST_TABLE_SIZE);
+
+ bna_os_memcpy(&dev->mcast_47_32[0], &mcast_47_32[0],
+ sizeof(u32) * mac_addr_num);
+ bna_os_memcpy(&dev->mcast_31_0[0], &mcast_31_0[0],
+ sizeof(u32) * mac_addr_num);
+
+ return BNA_OK;
+}
+
+/**
+ * bna_mcast_mac_reset_list()
+ *
+ * Resets the multicast MAC address list kept by driver.
+ * Called when the hw gets reset.
+ *
+ * @param[in] dev - pointer to BNA device structure
+ *
+ * @return BNA_OK - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+void
+bna_mcast_mac_reset_list(struct bna_dev_s *dev)
+{
+
+ bna_os_memset(&dev->mcast_47_32[0], 0, sizeof(u32) *
+ BNA_MCAST_TABLE_SIZE);
+ bna_os_memset(&dev->mcast_31_0[0], 0, sizeof(u32) *
+ BNA_MCAST_TABLE_SIZE);
+}
+
+/**
+ * bna_rxf_broadcast()
+ *
+ * For RxF "rxf_id", it enables/disables the broadcast address.
+ *
+ * @param[in] dev - pointer to BNA device structure
+ * @param[in] rxf_id - rx-function ID.
+ * @param[in] enable - enable/disable broadcast address
+ *
+ * @return BNA_OK - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status_e
+bna_rxf_broadcast(struct bna_dev_s *dev, unsigned int rxf_id,
+ enum bna_enable_e enable)
+{
+ const u8 broadcast_addr[ETH_ALEN] =
+ {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+ if (enable)
+ return bna_rxf_mcast_mac_add(dev, rxf_id, &broadcast_addr[0]);
+
+ return bna_rxf_mcast_mac_del(dev, rxf_id, &broadcast_addr[0]);
+}
+
+/**
+ * bna_rxf_vlan_add()
+ *
+ * For RxF "rxf_id", it adds this function as a member of the
+ * specified "vlan_id".
+ *
+ * @param[in] dev - pointer to BNA device structure
+ * @param[in] rxf_id - rx-function ID.
+ * @param[in] vlan_id - VLAN id to be added
+ *
+ * @return void
+ */
+void bna_rxf_vlan_add(struct bna_dev_s *dev, unsigned int rxf_id,
+ unsigned int vlan_id)
+{
+
+ u32 new_vlan_id;
+
+ BNA_ASSERT((rxf_id <= BNA_RXF_ID_MAX));
+ /*
+ * wrap the vlan_id around in case it
+ * overflows the max limit
+ */
+ new_vlan_id = vlan_id & BNA_VLAN_ID_MAX;
+ BNA_BIT_TABLE_SET(dev->vlan_table[rxf_id], new_vlan_id);
+
+ if (dev->vlan_filter_enable[rxf_id] &&
+ (dev->rxf_active & ((u64)1 << rxf_id))) {
+ /* add VLAN ID on this function */
+ bna_reg_write(dev->regs.page_addr,
+ BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM +
+ (dev->port * 2),
+ VLAN_RAM_BASE_OFFSET));
+ bna_mem_writew(BNA_GET_VLAN_MEM_ENTRY_ADDR(dev->bar0, rxf_id ,
+ new_vlan_id), dev->vlan_table[rxf_id][new_vlan_id/32]);
+ }
+}
+
+/**
+ * bna_rxf_vlan_del()
+ *
+ * For RxF "rxf_id", it removes this function as a member of the
+ * specified "vlan_id".
+ *
+ * @param[in] dev - pointer to BNA device structure
+ * @param[in] rxf_id - rx-function ID.
+ * @param[in] vlan_id - VLAN id to be removed
+ *
+ * @return void
+ */
+void bna_rxf_vlan_del(struct bna_dev_s *dev, unsigned int rxf_id,
+ unsigned int vlan_id)
+{
+
+ u32 new_vlan_id;
+ BNA_ASSERT(rxf_id < BNA_RXF_ID_MAX);
+
+ new_vlan_id = vlan_id & BNA_VLAN_ID_MAX;
+ BNA_BIT_TABLE_CLEAR(dev->vlan_table[rxf_id], new_vlan_id);
+
+ if (dev->vlan_filter_enable[rxf_id] &&
+ (dev->rxf_active & ((u64)1 << rxf_id))) {
+ bna_reg_write(dev->regs.page_addr,
+ BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM +
+ (dev->port * 2), VLAN_RAM_BASE_OFFSET));
+ bna_mem_writew(BNA_GET_VLAN_MEM_ENTRY_ADDR(dev->bar0, rxf_id ,
+ new_vlan_id), dev->vlan_table[rxf_id][new_vlan_id/32]);
+ }
+}
+
+/**
+ * bna_rxf_vlan_filter()
+ *
+ * For RxF "rxf_id", it enables/disables the VLAN filter.
+ * Disabling the VLAN Filter allows reception of any VLAN-tagged frame.
+ *
+ * @param[in] dev - pointer to BNA device structure
+ * @param[in] rxf_id - rx-function ID.
+ * @param[in] enable - enable/disable VLAN Filtering.
+ *
+ * @return void
+ */
+void bna_rxf_vlan_filter(struct bna_dev_s *dev, unsigned int rxf_id,
+ enum bna_enable_e enable)
+{
+ u32 i;
+
+ BNA_ASSERT(rxf_id < BNA_RXF_ID_MAX);
+
+ dev->vlan_filter_enable[rxf_id] = enable;
+
+ bna_reg_write(dev->regs.page_addr,
+ BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM + (dev->port * 2),
+ VLAN_RAM_BASE_OFFSET));
+
+ if (enable) {
+ /* enable VLAN filtering on this function */
+ for (i = 0; i <= BNA_VLAN_ID_MAX/32; i++) {
+ bna_mem_writew(BNA_GET_VLAN_MEM_ENTRY_ADDR(dev->bar0,
+ rxf_id, i * 32), dev->vlan_table[rxf_id][i]);
+ }
+ } else {
+ /* disable VLAN filtering on this function */
+ for (i = 0; i <= BNA_VLAN_ID_MAX/32; i++) {
+ bna_mem_writew(BNA_GET_VLAN_MEM_ENTRY_ADDR(dev->bar0,
+ rxf_id, i * 32), 0xffffffff);
+ }
+ }
+}
+
+/**
+ * bna_rxf_vlan_del_all()
+ *
+ * For RxF "rxf_id", it clears all the VLANs.
+ *
+ * @param[in] dev - pointer to BNA device structure
+ * @param[in] rxf_id - rx-function ID.
+ *
+ * @return void
+ */
+void
+bna_rxf_vlan_del_all(struct bna_dev_s *dev, unsigned int rxf_id)
+{
+ u32 i;
+
+ BNA_ASSERT(rxf_id < BNA_RXF_ID_MAX);
+
+ bna_reg_write(dev->regs.page_addr,
+ BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM + (dev->port * 2),
+ VLAN_RAM_BASE_OFFSET));
+
+ /* clear all VLANs for this function */
+ for (i = 0; i <= BNA_VLAN_ID_MAX/32; i++) {
+ bna_mem_writew(BNA_GET_VLAN_MEM_ENTRY_ADDR(dev->bar0, rxf_id,
+ i * 32), 0);
+ }
+}
+
+
+/**
+ * bna_rxf_mcast_filter()
+ *
+ * For RxF "rxf_id", it enables/disables the multicast filter.
+ * Disabling the multicast filter allows reception of any
+ * multicast frame.
+ *
+ * @param[in] dev - pointer to BNA device structure
+ * @param[in] rxf_id - rx-function ID.
+ * @param[in] enable - enable/disable multicast Filtering.
+ *
+ * @return BNA_OK - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status_e bna_rxf_mcast_filter(struct bna_dev_s *dev,
+ unsigned int rxf_id, enum bna_enable_e enable)
+{
+
+ struct bfi_ll_mcast_filter_req cmd;
+
+ BNA_ASSERT(rxf_id < BNA_RXF_ID_MAX);
+
+ bfi_h2i_set(cmd.mh, BFI_MC_LL, BFI_LL_H2I_MAC_MCAST_FILTER_REQ, 0);
+
+ cmd.rxf_id = rxf_id;
+ cmd.enable = enable;
+
+ /* send command to firmware*/
+ return bna_mbox_send(dev, &cmd, sizeof(cmd), dev->cbarg);
+}
+
+/**
+ * bna_rxf_mcast_del_all()
+ *
+ * For RxF "rxf_id", it clears the MCAST cam and MVT.
+ * This functionality is required by some of the drivers.
+ *
+ * @param[in] dev - pointer to BNA device structure
+ * @param[in] rxf_id - rx-function ID.
+ *
+ * @return BNA_OK - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status_e
+bna_rxf_mcast_del_all(struct bna_dev_s *dev, unsigned int rxf_id)
+{
+ struct bfi_ll_mcast_del_all_req cmd;
+
+ BNA_ASSERT(rxf_id < BNA_RXF_ID_MAX);
+
+ bfi_h2i_set(cmd.mh, BFI_MC_LL, BFI_LL_H2I_MAC_MCAST_DEL_ALL_REQ, 0);
+
+ cmd.rxf_id = rxf_id;
+
+ /* send command to firmware*/
+ return bna_mbox_send(dev, &cmd, sizeof(cmd), dev->cbarg);
+}
+
+/**
+ * bna_rxf_promiscuous()
+ *
+ * For RxF "rxf_id", it enables/disables promiscuous mode.
+ *
+ * @param[in] dev - pointer to BNA device structure
+ * @param[in] rxf_id - rx-function ID.
+ * @param[in] enable - enable/disable promiscious mode
+ *
+ * @return BNA_OK - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status_e bna_rxf_promiscuous(struct bna_dev_s *dev,
+ unsigned int rxf_id, enum bna_enable_e enable)
+{
+ struct bfi_ll_rxf_req cmd;
+
+ BNA_ASSERT(rxf_id < BNA_RXF_ID_MAX);
+
+
+ bfi_h2i_set(cmd.mh, BFI_MC_LL, BFI_LL_H2I_RXF_PROMISCUOUS_SET_REQ, 0);
+
+ cmd.rxf_id = rxf_id;
+ cmd.enable = enable;
+
+
+ /*
+ * Need to revisit.
+ * Can the second check be an ASSERT ?
+ */
+ if (enable && (dev->rxf_promiscuous_id == BNA_RXF_ID_NONE)) {
+ dev->rxf_promiscuous_id = rxf_id;
+
+ /* allow all VLANs*/
+ bna_rxf_vlan_filter(dev, rxf_id, BNA_DISABLE);
+
+ return bna_mbox_send(dev, &cmd, sizeof(cmd), dev->cbarg);
+ } else if (!enable && (dev->rxf_promiscuous_id == rxf_id)) {
+ dev->rxf_promiscuous_id = BNA_RXF_ID_NONE;
+
+ /* Revert VLAN filtering */
+ bna_rxf_vlan_filter(dev, rxf_id,
+ dev->vlan_filter_enable[rxf_id]);
+
+ return bna_mbox_send(dev, &cmd, sizeof(cmd), dev->cbarg);
+ }
+
+ return BNA_FAIL;
+}
+
+/**
+ * bna_rxf_default_mode()
+ *
+ * For RxF "rxf_id", it enables/disables default mode.
+ * Must be called after the RxF has been configured.
+ * Must remove all unicast MAC associated to this RxF.
+ *
+ * @param[in] dev - pointer to BNA device structure
+ * @param[in] rxf_id - rx-function ID.
+ * @param[in] enable - enable/disable default mode
+ *
+ * @return BNA_OK - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status_e bna_rxf_default_mode(struct bna_dev_s *dev,
+ unsigned int rxf_id, enum bna_enable_e enable)
+{
+ struct bna_rx_fndb_ram *rx_fndb_ram;
+ u32 i, ctl_flags;
+ struct bfi_ll_rxf_req cmd;
+
+ BNA_ASSERT(rxf_id < BNA_RXF_ID_MAX);
+
+
+ rx_fndb_ram = (struct bna_rx_fndb_ram *)
+ BNA_GET_MEM_BASE_ADDR(dev->bar0, RX_FNDB_RAM_BASE_OFFSET);
+
+ bfi_h2i_set(cmd.mh, BFI_MC_LL, BFI_LL_H2I_RXF_DEFAULT_SET_REQ, 0);
+
+ cmd.rxf_id = rxf_id;
+ cmd.enable = enable;
+
+ /*
+ * Need to revisit.
+ * Can the second check be an ASSERT ?
+ */
+ if (enable && (dev->rxf_default_id == BNA_RXF_ID_NONE)) {
+ dev->rxf_default_id = rxf_id;
+
+ /* allow all VLANs*/
+ bna_rxf_vlan_filter(dev, rxf_id, BNA_DISABLE);
+
+ bna_reg_write(dev->regs.page_addr,
+ BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM +
+ (dev->port * 2),
+ RX_FNDB_RAM_BASE_OFFSET));
+
+ for (i = 0; i < BNA_RXF_ID_MAX; i++) {
+ if (i == rxf_id)
+ continue;
+
+ ctl_flags =
+ bna_mem_readw(&rx_fndb_ram[i].control_flags);
+ ctl_flags |= BNA_RXF_CF_DEFAULT_FUNCTION_ENABLE;
+ bna_mem_writew(&rx_fndb_ram[i].control_flags,
+ ctl_flags);
+ }
+ return bna_mbox_send(dev, &cmd, sizeof(cmd), dev->cbarg);
+ } else if (!enable && (dev->rxf_default_id == rxf_id)) {
+ dev->rxf_default_id = BNA_RXF_ID_NONE;
+
+ /* Revert VLAN filtering */
+ bna_rxf_vlan_filter(dev, rxf_id,
+ dev->vlan_filter_enable[rxf_id]);
+
+ bna_reg_write(dev->regs.page_addr,
+ BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM +
+ (dev->port * 2),
+ RX_FNDB_RAM_BASE_OFFSET));
+
+ for (i = 0; i < BNA_RXF_ID_MAX; i++) {
+ ctl_flags =
+ bna_mem_readw(&rx_fndb_ram[i].control_flags);
+ ctl_flags &= ~BNA_RXF_CF_DEFAULT_FUNCTION_ENABLE;
+ bna_mem_writew(&rx_fndb_ram[i].control_flags,
+ ctl_flags);
+ }
+ return bna_mbox_send(dev, &cmd, sizeof(cmd), dev->cbarg);
+ }
+
+ return BNA_FAIL;
+}
+
+/**
+ * bna_rxf_frame_stats_get()
+ *
+ * For RxF "rxf_id", it loads frame statistics into "stats_ptr".
+ *
+ * @param[in] dev - pointer to BNA device structure
+ * @param[in] rxf_id - rx-function ID.
+ * @param[out] stats_ptr - pointer to stats structure to fill
+ *
+ * @return BNA_OK - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+void
+bna_rxf_frame_stats_get(struct bna_dev_s *dev, unsigned int rxf_id,
+ struct bna_stats_rxf **stats_ptr)
+{
+
+ BNA_ASSERT(rxf_id < BNA_RXF_ID_MAX);
+
+ *stats_ptr = &dev->stats.rxf_stats[rxf_id];
+}
+
+/**
+ * bna_txf_frame_stats_get()
+ *
+ * For TxF "txf_id", it loads frame statistics into "stats_ptr".
+ *
+ * @param[in] dev - pointer to BNA device structure
+ * @param[in] txf_id - tx-function ID.
+ * @param[out] stats_ptr - pointer to tx-function statistics.
+ *
+ * @return BNA_OK - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+void
+bna_txf_frame_stats_get(struct bna_dev_s *dev, unsigned int txf_id,
+ struct bna_stats_txf **stats_ptr)
+{
+
+ BNA_ASSERT(txf_id < BNA_TXF_ID_MAX);
+
+ *stats_ptr = &dev->stats.txf_stats[txf_id];
+}
+
+/**
+ * bna_mac_rx_stats_get()
+ *
+ * Loads MAC Rx statistics into "stats_ptr".
+ *
+ * @param[in] dev - pointer to BNA device structure
+
+ * @param[out] stats_ptr - pointer to stats structure to fill
+ *
+ * @return BNA_OK - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+void
+bna_mac_rx_stats_get(struct bna_dev_s *dev, struct cna_stats_mac_rx **stats_ptr)
+{
+ *stats_ptr = &dev->stats.mac_rx_stats;
+}
+
+/**
+ * bna_mac_tx_stats_get()
+ *
+ * Loads MAC Tx statistics into "stats_ptr".
+ *
+ * @param[in] dev - pointer to BNA device structure
+
+ * @param[out] stats_ptr - pointer to stats structure to fill
+ *
+ * @return BNA_OK - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+void
+bna_mac_tx_stats_get(struct bna_dev_s *dev, struct cna_stats_mac_tx **stats_ptr)
+{
+ *stats_ptr = &dev->stats.mac_tx_stats;
+}
+
+/**
+ * bna_all_stats_get()
+ *
+ * Loads all statistics into "stats_ptr".
+ *
+ * @param[in] dev - pointer to BNA device structure
+
+ * @param[out] stats_ptr - pointer to stats structure
+ *
+ * @return void
+ */
+void
+bna_all_stats_get(struct bna_dev_s *dev, struct bna_stats **stats_ptr)
+{
+ *stats_ptr = &dev->stats;
+}
+
+/**
+ * bna_stats_get()
+ *
+ * Get the statistics from the device. This function needs to
+ * be scheduled every second to get periodic update of the
+ * statistics data from hardware.
+ *
+ * @param[in] dev - pointer to BNA device structure.
+ *
+ * @return BNA_OK - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status_e bna_stats_get(struct bna_dev_s *dev)
+{
+ struct bfi_ll_stats_req cmd;
+
+ bfi_h2i_set(cmd.mh, BFI_MC_LL, BFI_LL_H2I_STATS_GET_REQ, 0);
+
+ cmd.stats_mask = bna_os_htons(BFI_LL_STATS_ALL);
+ cmd.rxf_id_mask[0] = bna_os_htonl(
+ (u32)(dev->rxf_active & 0xffffffff));
+ cmd.rxf_id_mask[1] = bna_os_htonl(
+ (u32)(dev->rxf_active >> 32));
+
+ cmd.txf_id_mask[0] = bna_os_htonl(
+ (u32)(dev->txf_active & 0xffffffff));
+ cmd.txf_id_mask[1] = bna_os_htonl((u32)(dev->txf_active >> 32));
+
+ cmd.host_buffer.a32.addr_hi = dev->hw_stats_dma.msb;
+ cmd.host_buffer.a32.addr_lo = dev->hw_stats_dma.lsb;
+
+ dev->rxf_active_last = dev->rxf_active;
+ dev->txf_active_last = dev->txf_active;
+
+ /* send command to firmware */
+ return bna_mbox_send(dev, &cmd, sizeof(cmd), dev->cbarg);
+}
+
+/**
+ * bna_stats_clear()
+ *
+ * Clear the statistics in the device.
+ *
+ * @param[in] dev - pointer to BNA device structure.
+ *
+ * @return BNA_OK - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status_e
+bna_stats_clear(struct bna_dev_s *dev)
+{
+ struct bfi_ll_stats_req cmd;
+
+ bfi_h2i_set(cmd.mh, BFI_MC_LL, BFI_LL_H2I_STATS_CLEAR_REQ, 0);
+
+ cmd.stats_mask = bna_os_htons(BFI_LL_STATS_ALL);
+ cmd.rxf_id_mask[0] = bna_os_htonl(
+ (u32)(dev->rxf_active & 0xffffffff));
+ cmd.rxf_id_mask[1] = bna_os_htonl((u32)(dev->rxf_active >> 32));
+
+ cmd.txf_id_mask[0] = bna_os_htonl(
+ (u32)(dev->txf_active & 0xffffffff));
+ cmd.txf_id_mask[1] = bna_os_htonl((u32)(dev->txf_active >> 32));
+
+ /* send command to firmware */
+ return bna_mbox_send(dev, &cmd, sizeof(cmd), dev->cbarg);
+}
+/**
+ * bna_rxf_stats_clear()
+ *
+ * Clear the statistics for specified txf.
+ *
+ * @param[in] dev - pointer to BNA device structure.
+ * @param[in] rxf_id - rx-function ID.
+ *
+ * @return BNA_OK - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status_e
+bna_rxf_stats_clear(struct bna_dev_s *dev, unsigned int rxf_id)
+{
+ struct bfi_ll_stats_req cmd;
+
+ BNA_ASSERT(rxf_id < BNA_RXF_ID_MAX);
+
+ bfi_h2i_set(cmd.mh, BFI_MC_LL, BFI_LL_H2I_STATS_CLEAR_REQ, 0);
+
+ cmd.stats_mask = 0;
+
+ if (rxf_id < 32) {
+ cmd.rxf_id_mask[0] = bna_os_htonl((u32)(1 << rxf_id));
+ cmd.rxf_id_mask[1] = 0;
+ } else {
+ cmd.rxf_id_mask[0] = 0;
+ cmd.rxf_id_mask[1] = bna_os_htonl(
+ (u32)(1 << (rxf_id - 32)));
+ }
+
+ cmd.txf_id_mask[0] = 0;
+ cmd.txf_id_mask[1] = 0;
+
+ /* send command to firmware */
+ return bna_mbox_send(dev, &cmd, sizeof(cmd), dev->cbarg);
+}
+
+/**
+ * bna_lldp_stats_clear()
+ *
+ * Clear the DCBCX-LLDP statistics in the f/w.
+ *
+ * @param[in] dev - pointer to BNA device structure.
+ *
+ * @return BNA_OK - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status_e
+bna_lldp_stats_clear(struct bna_dev_s *dev)
+{
+ struct bfi_lldp_reset_stats_s cmd;
+
+ bfi_h2i_set(cmd.mh, BFI_MC_CEE, BFI_CEE_H2I_RESET_STATS, 0);
+
+ /* send command to firmware */
+ return bna_mbox_send(dev, &cmd, sizeof(cmd), dev->cbarg);
+}
+
+/**
+ * bna_get_cfg_req()
+ *
+ * Request to get the LLDP-DCBCX Config.
+ *
+ * @param[in] dev - pointer to BNA device structure.
+ * @param[in] dma_ddr - dma address in "bna_dma_addr_t" format.
+ *
+ * @return BNA_OK - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status_e
+bna_get_cfg_req(struct bna_dev_s *dev, struct bna_dma_addr *dma_addr)
+{
+ struct bfi_cee_get_req_s cmd;
+
+ bfi_h2i_set(cmd.mh, BFI_MC_CEE, BFI_CEE_H2I_GET_CFG_REQ, 0);
+ cmd.dma_addr.a32.addr_lo = dma_addr->lsb;
+ cmd.dma_addr.a32.addr_hi = dma_addr->msb;
+ /* send command to firmware */
+ return bna_mbox_send(dev, &cmd, sizeof(cmd), dev->cbarg);
+}
+
+/**
+ * bna_get_cee_stats_req()
+ *
+ * Request to get the LLDP-DCBCX stats.
+ *
+ * @param[in] dev - pointer to BNA device structure.
+ * @param[in] dma_ddr - dma address in "bna_dma_addr_t" format.
+ *
+ * @return BNA_OK - successful
+ * @return BNA_FAIL - failed on sanity checks.
+ */
+enum bna_status_e
+bna_get_cee_stats_req(struct bna_dev_s *dev, struct bna_dma_addr *dma_addr)
+{
+ struct bfi_cee_get_req_s cmd;
+
+ bfi_h2i_set(cmd.mh, BFI_MC_CEE, BFI_CEE_H2I_GET_STATS_REQ, 0);
+ cmd.dma_addr.a32.addr_lo = dma_addr->lsb;
+ cmd.dma_addr.a32.addr_hi = dma_addr->msb;
+ /* send command to firmware */
+ return bna_mbox_send(dev, &cmd, sizeof(cmd), dev->cbarg);
+}
+
+/**
+ * bna_stats_process()
+ *
+ * Process the statistics data DMAed from the device. This
+ * function needs to be scheduled upon getting an asynchronous
+ * notification from the firmware.
+ *
+ * @param[in] dev - pointer to BNA device structure.
+ *
+ * @return void
+ */
+void
+bna_stats_process(struct bna_dev_s *dev)
+{
+ u32 i, j;
+ struct bna_stats_rxf *rxf_hw_stats;
+ struct bna_stats_txf *txf_hw_stats;
+
+ dev->stats.fc_tx_stats.txf_ucast_octets = bna_hw_stats_to_stats(
+ dev->hw_stats->fc_tx_stats.txf_ucast_octets);
+ dev->stats.fc_tx_stats.txf_ucast = bna_hw_stats_to_stats(
+ dev->hw_stats->fc_tx_stats.txf_ucast);
+ dev->stats.fc_tx_stats.txf_ucast_vlan = bna_hw_stats_to_stats(
+ dev->hw_stats->fc_tx_stats.txf_ucast_vlan);
+
+ dev->stats.fc_tx_stats.txf_mcast_octets = bna_hw_stats_to_stats(
+ dev->hw_stats->fc_tx_stats.txf_mcast_octets);
+ dev->stats.fc_tx_stats.txf_mcast = bna_hw_stats_to_stats(
+ dev->hw_stats->fc_tx_stats.txf_mcast);
+ dev->stats.fc_tx_stats.txf_mcast_vlan = bna_hw_stats_to_stats(
+ dev->hw_stats->fc_tx_stats.txf_mcast_vlan);
+
+ dev->stats.fc_tx_stats.txf_bcast_octets = bna_hw_stats_to_stats(
+ dev->hw_stats->fc_tx_stats.txf_bcast_octets);
+ dev->stats.fc_tx_stats.txf_bcast = bna_hw_stats_to_stats(
+ dev->hw_stats->fc_tx_stats.txf_bcast);
+ dev->stats.fc_tx_stats.txf_bcast_vlan = bna_hw_stats_to_stats(
+ dev->hw_stats->fc_tx_stats.txf_bcast_vlan);
+
+ dev->stats.fc_tx_stats.txf_parity_errors = bna_hw_stats_to_stats(
+ dev->hw_stats->fc_tx_stats.txf_parity_errors);
+ dev->stats.fc_tx_stats.txf_timeout = bna_hw_stats_to_stats(
+ dev->hw_stats->fc_tx_stats.txf_timeout);
+ dev->stats.fc_tx_stats.txf_fid_parity_errors = bna_hw_stats_to_stats(
+ dev->hw_stats->fc_tx_stats.txf_fid_parity_errors);
+
+ for (i = 0; i < 8; i++) {
+ dev->stats.bpc_tx_stats.tx_pause[i] = bna_hw_stats_to_stats(
+ dev->hw_stats->bpc_stats.tx_pause[i]);
+ dev->stats.bpc_tx_stats.tx_zero_pause[i] =
+ bna_hw_stats_to_stats(
+ dev->hw_stats->bpc_stats.tx_zero_pause[i]);
+ dev->stats.bpc_tx_stats.tx_first_pause[i] =
+ bna_hw_stats_to_stats(
+ dev->hw_stats->bpc_stats.tx_first_pause[i]);
+ }
+
+ dev->stats.mac_tx_stats.tx_bytes = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.tx_bytes);
+ dev->stats.mac_tx_stats.tx_packets = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.tx_packets);
+ dev->stats.mac_tx_stats.tx_multicast = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.tx_multicast);
+ dev->stats.mac_tx_stats.tx_broadcast = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.tx_broadcast);
+ dev->stats.mac_tx_stats.tx_pause = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.tx_pause);
+ dev->stats.mac_tx_stats.tx_deferral = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.tx_deferral);
+ dev->stats.mac_tx_stats.tx_excessive_deferral = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.tx_excessive_deferral);
+ dev->stats.mac_tx_stats.tx_single_collision = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.tx_single_collision);
+ dev->stats.mac_tx_stats.tx_muliple_collision = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.tx_muliple_collision);
+ dev->stats.mac_tx_stats.tx_late_collision = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.tx_late_collision);
+ dev->stats.mac_tx_stats.tx_excessive_collision = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.tx_excessive_collision);
+ dev->stats.mac_tx_stats.tx_total_collision = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.tx_total_collision);
+ dev->stats.mac_tx_stats.tx_pause_honored = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.tx_pause_honored);
+ dev->stats.mac_tx_stats.tx_drop = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.tx_drop);
+ dev->stats.mac_tx_stats.tx_jabber = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.tx_jabber);
+ dev->stats.mac_tx_stats.tx_fcs_error = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.tx_fcs_error);
+ dev->stats.mac_tx_stats.tx_control_frame = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.tx_control_frame);
+ dev->stats.mac_tx_stats.tx_oversize = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.tx_oversize);
+ dev->stats.mac_tx_stats.tx_undersize = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.tx_undersize);
+ dev->stats.mac_tx_stats.tx_fragments = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.tx_fragments);
+
+ dev->stats.fc_rx_stats.rxf_ucast_octets = bna_hw_stats_to_stats(
+ dev->hw_stats->fc_rx_stats.rxf_ucast_octets);
+ dev->stats.fc_rx_stats.rxf_ucast = bna_hw_stats_to_stats(
+ dev->hw_stats->fc_rx_stats.rxf_ucast);
+ dev->stats.fc_rx_stats.rxf_ucast_vlan = bna_hw_stats_to_stats(
+ dev->hw_stats->fc_rx_stats.rxf_ucast_vlan);
+
+ dev->stats.fc_rx_stats.rxf_mcast_octets = bna_hw_stats_to_stats(
+ dev->hw_stats->fc_rx_stats.rxf_mcast_octets);
+ dev->stats.fc_rx_stats.rxf_mcast = bna_hw_stats_to_stats(
+ dev->hw_stats->fc_rx_stats.rxf_mcast);
+ dev->stats.fc_rx_stats.rxf_mcast_vlan = bna_hw_stats_to_stats(
+ dev->hw_stats->fc_rx_stats.rxf_mcast_vlan);
+
+ dev->stats.fc_rx_stats.rxf_bcast_octets = bna_hw_stats_to_stats(
+ dev->hw_stats->fc_rx_stats.rxf_bcast_octets);
+ dev->stats.fc_rx_stats.rxf_bcast = bna_hw_stats_to_stats(
+ dev->hw_stats->fc_rx_stats.rxf_bcast);
+ dev->stats.fc_rx_stats.rxf_bcast_vlan = bna_hw_stats_to_stats(
+ dev->hw_stats->fc_rx_stats.rxf_bcast_vlan);
+
+ for (i = 0; i < 8; i++) {
+ dev->stats.bpc_rx_stats.rx_pause[i] = bna_hw_stats_to_stats(
+ dev->hw_stats->bpc_stats.rx_pause[i]);
+ dev->stats.bpc_rx_stats.rx_zero_pause[i] =
+ bna_hw_stats_to_stats(
+ dev->hw_stats->bpc_stats.rx_zero_pause[i]);
+ dev->stats.bpc_rx_stats.rx_first_pause[i] =
+ bna_hw_stats_to_stats(
+ dev->hw_stats->bpc_stats.rx_first_pause[i]);
+ }
+
+ dev->stats.rad_stats.rx_frames = bna_hw_stats_to_stats(
+ dev->hw_stats->rad_stats.rx_frames);
+ dev->stats.rad_stats.rx_octets = bna_hw_stats_to_stats(
+ dev->hw_stats->rad_stats.rx_octets);
+ dev->stats.rad_stats.rx_vlan_frames = bna_hw_stats_to_stats(
+ dev->hw_stats->rad_stats.rx_vlan_frames);
+
+ dev->stats.rad_stats.rx_ucast = bna_hw_stats_to_stats(
+ dev->hw_stats->rad_stats.rx_ucast);
+ dev->stats.rad_stats.rx_ucast_octets = bna_hw_stats_to_stats(
+ dev->hw_stats->rad_stats.rx_ucast_octets);
+ dev->stats.rad_stats.rx_ucast_vlan = bna_hw_stats_to_stats(
+ dev->hw_stats->rad_stats.rx_ucast_vlan);
+
+ dev->stats.rad_stats.rx_mcast = bna_hw_stats_to_stats(
+ dev->hw_stats->rad_stats.rx_mcast);
+ dev->stats.rad_stats.rx_mcast_octets = bna_hw_stats_to_stats(
+ dev->hw_stats->rad_stats.rx_mcast_octets);
+ dev->stats.rad_stats.rx_mcast_vlan = bna_hw_stats_to_stats(
+ dev->hw_stats->rad_stats.rx_mcast_vlan);
+
+ dev->stats.rad_stats.rx_bcast = bna_hw_stats_to_stats(
+ dev->hw_stats->rad_stats.rx_bcast);
+ dev->stats.rad_stats.rx_bcast_octets = bna_hw_stats_to_stats(
+ dev->hw_stats->rad_stats.rx_bcast_octets);
+ dev->stats.rad_stats.rx_bcast_vlan = bna_hw_stats_to_stats(
+ dev->hw_stats->rad_stats.rx_bcast_vlan);
+
+ dev->stats.rad_stats.rx_drops = bna_hw_stats_to_stats(
+ dev->hw_stats->rad_stats.rx_drops);
+
+ dev->stats.mac_rx_stats.frame_64 = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.frame_64);
+ dev->stats.mac_rx_stats.frame_65_127 = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.frame_65_127);
+ dev->stats.mac_rx_stats.frame_128_255 = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.frame_128_255);
+ dev->stats.mac_rx_stats.frame_256_511 = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.frame_256_511);
+ dev->stats.mac_rx_stats.frame_512_1023 = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.frame_512_1023);
+ dev->stats.mac_rx_stats.frame_1024_1518 = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.frame_1024_1518);
+ dev->stats.mac_rx_stats.frame_1518_1522 = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.frame_1519_1522);
+ dev->stats.mac_rx_stats.rx_bytes = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.rx_bytes);
+ dev->stats.mac_rx_stats.rx_packets = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.rx_packets);
+ dev->stats.mac_rx_stats.rx_fcs_error = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.rx_fcs_error);
+ dev->stats.mac_rx_stats.rx_multicast = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.rx_multicast);
+ dev->stats.mac_rx_stats.rx_broadcast = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.rx_broadcast);
+ dev->stats.mac_rx_stats.rx_control_frames = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.rx_control_frames);
+ dev->stats.mac_rx_stats.rx_pause = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.rx_pause);
+ dev->stats.mac_rx_stats.rx_unknown_opcode = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.rx_unknown_opcode);
+ dev->stats.mac_rx_stats.rx_alignment_error = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.rx_alignment_error);
+ dev->stats.mac_rx_stats.rx_frame_length_error = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.rx_frame_length_error);
+ dev->stats.mac_rx_stats.rx_code_error = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.rx_code_error);
+ dev->stats.mac_rx_stats.rx_carrier_sense_error = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.rx_carrier_sense_error);
+ dev->stats.mac_rx_stats.rx_undersize = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.rx_undersize);
+ dev->stats.mac_rx_stats.rx_oversize = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.rx_oversize);
+ dev->stats.mac_rx_stats.rx_fragments = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.rx_jabber);
+ dev->stats.mac_rx_stats.rx_jabber = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.rx_jabber);
+ dev->stats.mac_rx_stats.rx_drop = bna_hw_stats_to_stats(
+ dev->hw_stats->mac_stats.rx_drop);
+
+ rxf_hw_stats = (struct bna_stats_rxf *)&dev->hw_stats->rxf_stats[0];
+ j = 0;
+
+ for (i = 0; i < BNA_RXF_ID_MAX; i++) {
+ if (dev->rxf_active_last & ((u64)1 << i)) {
+ dev->stats.rxf_stats[i].ucast_octets =
+ bna_hw_stats_to_stats(
+ rxf_hw_stats[j].ucast_octets);
+ dev->stats.rxf_stats[i].ucast = bna_hw_stats_to_stats(
+ rxf_hw_stats[j].ucast);
+ dev->stats.rxf_stats[i].ucast_vlan = bna_hw_stats_to_stats(
+ rxf_hw_stats[j].ucast_vlan);
+
+ dev->stats.rxf_stats[i].mcast_octets = bna_hw_stats_to_stats(
+ rxf_hw_stats[j].mcast_octets);
+ dev->stats.rxf_stats[i].mcast = bna_hw_stats_to_stats(
+ rxf_hw_stats[j].mcast);
+ dev->stats.rxf_stats[i].mcast_vlan = bna_hw_stats_to_stats(
+ rxf_hw_stats[j].mcast_vlan);
+
+ dev->stats.rxf_stats[i].bcast_octets = bna_hw_stats_to_stats(
+ rxf_hw_stats[j].bcast_octets);
+ dev->stats.rxf_stats[i].bcast = bna_hw_stats_to_stats(
+ rxf_hw_stats[j].bcast);
+ dev->stats.rxf_stats[i].bcast_vlan = bna_hw_stats_to_stats(
+ rxf_hw_stats[j].bcast_vlan);
+
+ dev->stats.rxf_stats[i].frame_drops = bna_hw_stats_to_stats(
+ rxf_hw_stats[j].frame_drops);
+
+ j++;
+ }
+ }
+
+ txf_hw_stats = (struct bna_stats_txf *)&rxf_hw_stats[j];
+ j = 0;
+
+ for (i = 0; i < BNA_TXF_ID_MAX; i++) {
+ if (dev->txf_active_last & ((u64)1 << i)) {
+ dev->stats.txf_stats[i].ucast_octets =
+ bna_hw_stats_to_stats(
+ txf_hw_stats[j].ucast_octets);
+ dev->stats.txf_stats[i].ucast = bna_hw_stats_to_stats(
+ txf_hw_stats[j].ucast);
+ dev->stats.txf_stats[i].ucast_vlan = bna_hw_stats_to_stats(
+ txf_hw_stats[j].ucast_vlan);
+
+ dev->stats.txf_stats[i].mcast_octets = bna_hw_stats_to_stats(
+ txf_hw_stats[j].mcast_octets);
+ dev->stats.txf_stats[i].mcast = bna_hw_stats_to_stats(
+ txf_hw_stats[j].mcast);
+ dev->stats.txf_stats[i].mcast_vlan = bna_hw_stats_to_stats(
+ txf_hw_stats[j].mcast_vlan);
+
+ dev->stats.txf_stats[i].bcast_octets = bna_hw_stats_to_stats(
+ txf_hw_stats[j].bcast_octets);
+ dev->stats.txf_stats[i].bcast = bna_hw_stats_to_stats(
+ txf_hw_stats[j].bcast);
+ dev->stats.txf_stats[i].bcast_vlan = bna_hw_stats_to_stats(
+ txf_hw_stats[j].bcast_vlan);
+
+ dev->stats.txf_stats[i].errors = bna_hw_stats_to_stats(
+ txf_hw_stats[j].errors);
+ dev->stats.txf_stats[i].filter_vlan = bna_hw_stats_to_stats(
+ txf_hw_stats[j].filter_vlan);
+ dev->stats.txf_stats[i].filter_mac_sa = bna_hw_stats_to_stats(
+ txf_hw_stats[j].filter_mac_sa);
+
+ j++;
+ }
+ }
+}
+
+/**
+ * bna_txf_config_set()
+ *
+ * For TxF "txf_id", it configures the TxF specified by "cfg_ptr" and
+ * indicates to the statistics collector to collect statistics for this
+ * Tx-Function.
+ *
+ * @param[in] dev - pointer to BNA device structure
+ * @param[in] txf_id - tx-function ID.
+ * @param[in] cfg_ptr - pointer to tx-function configuration.
+ *
+ * @return void
+ */
+void
+bna_txf_config_set(struct bna_dev_s *dev, unsigned int txf_id,
+ const struct bna_txf_config *cfg_ptr)
+{
+
+ struct bna_tx_fndb_ram *tx_fndb;
+
+ BNA_ASSERT(txf_id < BNA_TXF_ID_MAX);
+
+ tx_fndb = (struct bna_tx_fndb_ram *)
+ BNA_GET_MEM_BASE_ADDR(dev->bar0, TX_FNDB_RAM_BASE_OFFSET);
+
+ bna_reg_write(dev->regs.page_addr, BNA_GET_PAGE_NUM(
+ LUT0_MEM_BLK_BASE_PG_NUM + (dev->port * 2),
+ TX_FNDB_RAM_BASE_OFFSET));
+
+ bna_mem_writew(&tx_fndb[txf_id],
+ (cfg_ptr->vlan << 16) | cfg_ptr->flags);
+
+ /* turn on statistics collection */
+ dev->txf_active |= ((u64)1 << txf_id);
+}
+
+/**
+ * bna_txf_config_clear()
+ *
+ * For TxF "txf_id", it clears its configuration and indicates to the
+ * statistics collector to stop collecting statistics for this
+ * Tx-Function.
+ *
+ * @param[in] dev - pointer to BNA device structure
+ * @param[in] txf_id - tx-function ID.
+ *
+ * @return void
+ */
+void
+bna_txf_config_clear(struct bna_dev_s *dev, unsigned int txf_id)
+{
+
+ struct bna_tx_fndb_ram *tx_fndb;
+
+ BNA_ASSERT(txf_id < BNA_TXF_ID_MAX);
+
+ tx_fndb = (struct bna_tx_fndb_ram *)
+ BNA_GET_MEM_BASE_ADDR(dev->bar0, TX_FNDB_RAM_BASE_OFFSET);
+
+ bna_reg_write(dev->regs.page_addr,
+ BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM + (dev->port * 2),
+ TX_FNDB_RAM_BASE_OFFSET));
+
+ bna_mem_writew(&tx_fndb[txf_id], 0);
+
+ /* turn off statistics collection */
+ dev->txf_active &= ~((u64)1 << txf_id);
+}
+
+/**
+ * bna_txf_disable()
+ *
+ * Disables the Tx Function without clearing the configuration
+ * Also disables collection of statistics.
+ *
+ * @param[in] bna_dev - Pointer to BNA device handle
+ * @param[in] txf_id - Id of the Tx Function to be disabled
+ *
+ * @return void
+ */
+void
+bna_txf_disable(struct bna_dev_s *dev, unsigned int txf_id)
+{
+ struct bna_tx_fndb_ram *tx_fndb;
+ u32 page_num, ctl_flags;
+
+ BNA_ASSERT(txf_id < BNA_TXF_ID_MAX);
+
+ tx_fndb = (struct bna_tx_fndb_ram *)
+ BNA_GET_MEM_BASE_ADDR(dev->bar0, TX_FNDB_RAM_BASE_OFFSET);
+
+ /* Write the page number register */
+ page_num =
+ BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM + (dev->port * 2),
+ TX_FNDB_RAM_BASE_OFFSET);
+ bna_reg_write(dev->regs.page_addr, page_num);
+
+ ctl_flags = bna_mem_readw(&tx_fndb[txf_id].vlan_n_ctrl_flags);
+
+ ctl_flags &= ~BNA_TXF_CF_ENABLE;
+
+ bna_mem_writew(&tx_fndb[txf_id].vlan_n_ctrl_flags, ctl_flags);
+
+ /* turn off statistics collection */
+ dev->txf_active &= ~((u64)1 << txf_id);
+}
+
+/**
+ * bna_txf_enable()
+ *
+ * Enables the Tx Function without reconfiguring.
+ * Also disables collection of statistics.
+ *
+ * @param[in] bna_dev - Pointer to BNA device handle
+ * @param[in] txf_id - Id of the Tx Function to be disabled
+ *
+ * @return void
+ */
+void
+bna_txf_enable(struct bna_dev_s *dev, unsigned int txf_id)
+{
+ struct bna_tx_fndb_ram *tx_fndb;
+ u32 page_num, ctl_flags;
+
+ BNA_ASSERT(txf_id < BNA_TXF_ID_MAX);
+
+ tx_fndb = (struct bna_tx_fndb_ram *)
+ BNA_GET_MEM_BASE_ADDR(dev->bar0, TX_FNDB_RAM_BASE_OFFSET);
+
+ /* Write the page number register */
+ page_num = BNA_GET_PAGE_NUM(LUT0_MEM_BLK_BASE_PG_NUM +
+ (dev->port * 2), TX_FNDB_RAM_BASE_OFFSET);
+ bna_reg_write(dev->regs.page_addr, page_num);
+
+ ctl_flags = bna_mem_readw(&tx_fndb[txf_id].vlan_n_ctrl_flags);
+
+ ctl_flags |= BNA_TXF_CF_ENABLE;
+
+ bna_mem_writew(&tx_fndb[txf_id].vlan_n_ctrl_flags, ctl_flags);
+
+ /* turn on statistics collection */
+ dev->txf_active |= ((u64)1 << txf_id);
+}
+
+/**
+ * bna_set_pause_config()
+ *
+ * Enable/disable Tx/Rx pause through F/W
+ *
+ * @param[in] dev - pointer to BNA device structure
+ * @param[in] pause - pointer to struct bna_pause_config
+ *
+ * @return BNA_OK in case of success BNA_FAIL otherwise.
+ */
+enum bna_status_e
+bna_set_pause_config(struct bna_dev_s *dev, struct bna_pause_config *pause,
+ void *cbarg)
+{
+ struct bfi_ll_set_pause_req ll_req;
+
+ bfi_h2i_set(ll_req.mh, BFI_MC_LL, BFI_LL_H2I_SET_PAUSE_REQ, 0);
+
+ ll_req.tx_pause = pause->tx_pause;
+ ll_req.rx_pause = pause->rx_pause;
+
+ DPRINTK(INFO, "Port %d tx_pause %d rx_pause %d\n",
+ dev->port, ll_req.tx_pause, ll_req.rx_pause);
+
+ /* send to f/w */
+ return bna_mbox_send(dev, &ll_req, sizeof(ll_req), cbarg);
+}
+
+/**
+ * bna_mtu_info()
+ *
+ * Send MTU information to F/W.
+ * This is required to do PAUSE efficiently.
+ *
+ * @param[in] dev - pointer to BNA device structure
+ * @param[in] mtu - current mtu size
+ * @param[in] cbarg - argument for the callback function
+ *
+ * @return BNA_OK in case of success BNA_FAIL otherwise.
+ */
+enum bna_status_e
+bna_mtu_info(struct bna_dev_s *dev, u16 mtu, void *cbarg)
+{
+ struct bfi_ll_mtu_info_req ll_req;
+
+ bfi_h2i_set(ll_req.mh, BFI_MC_LL, BFI_LL_H2I_MTU_INFO_REQ, 0);
+ ll_req.mtu = bna_os_htons(mtu);
+
+ DPRINTK(INFO, "Port %d MTU %d\n", dev->port, mtu);
+
+ /* send to f/w */
+ return bna_mbox_send(dev, &ll_req, sizeof(ll_req), cbarg);
+}
+
+/* Currently we assume just 2 columns, col 0 = small, col 1 = large */
+u32 intr_mod_vector[BNA_LOAD_TYPES + 1][BNA_BIAS_TYPES] = {
+ { 12, 12 },
+ { 6, 10 },
+ { 5, 10 },
+ { 4, 8 },
+ { 3, 6 },
+ { 3, 6 },
+ { 2, 4 },
+ { 1, 2 },
+ };
+
+/**
+ * Returns the coalescing timer value
+ */
+u8
+bna_calc_coalescing_timer(struct bna_dev_s *dev, struct bna_pkt_rate *pkt)
+{
+ u32 load, bias;
+ u32 pkt_rt = 0, small_rt, large_rt;
+
+
+ small_rt = pkt->small_pkt_cnt;
+ large_rt = pkt->large_pkt_cnt;
+
+ pkt_rt = small_rt + large_rt;
+
+ if (pkt_rt < BNA_10K_PKT_RATE)
+ load = BNA_LOW_LOAD_4;
+ else if (pkt_rt < BNA_20K_PKT_RATE)
+ load = BNA_LOW_LOAD_3;
+ else if (pkt_rt < BNA_30K_PKT_RATE)
+ load = BNA_LOW_LOAD_2;
+ else if (pkt_rt < BNA_40K_PKT_RATE)
+ load = BNA_LOW_LOAD_1;
+ else if (pkt_rt < BNA_50K_PKT_RATE)
+ load = BNA_HIGH_LOAD_1;
+ else if (pkt_rt < BNA_60K_PKT_RATE)
+ load = BNA_HIGH_LOAD_2;
+ else if (pkt_rt < BNA_80K_PKT_RATE)
+ load = BNA_HIGH_LOAD_3;
+ else
+ load = BNA_HIGH_LOAD_4;
+
+
+ if (small_rt > (large_rt << 1))
+ bias = 0;
+ else
+ bias = 1;
+
+ pkt->small_pkt_cnt = pkt->large_pkt_cnt = 0;
+ return intr_mod_vector[load][bias];
+}
diff -ruP net-next-2.6-orig/drivers/net/bna/bna_queue.c net-next-2.6-mod/drivers/net/bna/bna_queue.c
--- net-next-2.6-orig/drivers/net/bna/bna_queue.c 1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6-mod/drivers/net/bna/bna_queue.c 2009-10-31 21:34:47.682533000 -0700
@@ -0,0 +1,496 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2007-2008 Brocade Communications Systems, Inc.
+ * All rights reserved.
+ *
+ * @file bna_queue.c BNA Queues
+ */
+
+#include <bna_os.h>
+#include "bna.h"
+#include "bna_hwreg.h"
+#include "bna_priv.h"
+#include <bfi/bfi_ll.h>
+
+
+#define BNA_Q_IDLE_STATE 0x00008001
+/*
+ *-----------------------------------------------------------------------------
+ * bna_txq_config()
+ *
+ * For TxQ "txq_id", it configures the Tx-Queue as specified by "cfg_ptr".
+ *-----------------------------------------------------------------------------
+ */
+void bna_txq_config(struct bna_dev_s *dev, struct bna_txq *q_ptr,
+ unsigned int txq_id, const struct bna_txq_config *cfg_ptr)
+{
+ struct bna_rxtx_q_mem *q_mem;
+ struct bna_txq_mem txq_cfg, *txq_mem;
+ const struct bna_qpt *qpt = &cfg_ptr->qpt;
+ struct bna_dma_addr cur_q_addr;
+ struct bna_doorbell_qset *qset;
+ u32 pg_num;
+
+ BNA_ASSERT(txq_id < BNA_TXQ_ID_MAX);
+ /* Check if the depth is a power of 2 */
+ BNA_ASSERT(BNA_POWER_OF_2(q_ptr->q.q_depth));
+
+
+ cur_q_addr = *((struct bna_dma_addr *)(qpt->kv_qpt_ptr));
+
+ /*
+ * Fill out structure, to be subsequently written
+ * to hardware
+ */
+ txq_cfg.pg_tbl_addr_lo = qpt->hw_qpt_ptr.lsb;
+ txq_cfg.pg_tbl_addr_hi = qpt->hw_qpt_ptr.msb;
+
+ /* FIXME */
+ txq_cfg.cur_q_entry_lo = cur_q_addr.lsb;
+ txq_cfg.cur_q_entry_hi = cur_q_addr.msb;
+
+ txq_cfg.pg_cnt_n_prd_ptr = (qpt->page_count << 16) | 0x0;
+
+ /* Is the entry size in words ? Check */
+ txq_cfg.entry_n_pg_size = ((BNA_TXQ_ENTRY_SIZE >> 2) << 16) |
+ (qpt->page_size >> 2);
+ txq_cfg.int_blk_n_cns_ptr =
+ ((((u8)cfg_ptr->ib_seg_index) << 24) |
+ (((u8)cfg_ptr->ib_id) << 16) | 0x0);
+ txq_cfg.cns_ptr2_n_q_state = BNA_Q_IDLE_STATE;
+ txq_cfg.nxt_qid_n_fid_n_pri = (((cfg_ptr->txf_id
+ & 0x3f) << 3) | (cfg_ptr->priority & 0x3));
+ txq_cfg.wvc_n_cquota_n_rquota = (((cfg_ptr->wrr_quota & 0xfff) << 12) |
+ (cfg_ptr->wrr_quota & 0xfff));
+
+ pg_num = BNA_GET_PAGE_NUM(HQM0_BLK_PG_NUM + dev->port,
+ HQM_RXTX_Q_RAM_BASE_OFFSET);
+
+ bna_reg_write(dev->regs.page_addr, pg_num);
+ /* Write to h/w */
+ q_mem = (struct bna_rxtx_q_mem *)
+ BNA_GET_MEM_BASE_ADDR(dev->bar0, HQM_RXTX_Q_RAM_BASE_OFFSET);
+
+ txq_mem = &q_mem[txq_id].txq;
+
+ /*
+ * The following 4 lines, is a hack b'cos the H/W needs to read
+ * these DMA addresses as little endian
+ */
+ bna_mem_writew(&txq_mem->pg_tbl_addr_lo,
+ bna_os_htonl(txq_cfg.pg_tbl_addr_lo));
+ bna_mem_writew(&txq_mem->pg_tbl_addr_hi,
+ bna_os_htonl(txq_cfg.pg_tbl_addr_hi));
+ bna_mem_writew(&txq_mem->cur_q_entry_lo,
+ bna_os_htonl(txq_cfg.cur_q_entry_lo));
+ bna_mem_writew(&txq_mem->cur_q_entry_hi,
+ bna_os_htonl(txq_cfg.cur_q_entry_hi));
+
+ bna_mem_writew(&txq_mem->pg_cnt_n_prd_ptr, txq_cfg.pg_cnt_n_prd_ptr);
+ bna_mem_writew(&txq_mem->entry_n_pg_size, txq_cfg.entry_n_pg_size);
+ bna_mem_writew(&txq_mem->int_blk_n_cns_ptr,
+ txq_cfg.int_blk_n_cns_ptr);
+ bna_mem_writew(&txq_mem->cns_ptr2_n_q_state,
+ txq_cfg.cns_ptr2_n_q_state);
+ bna_mem_writew(&txq_mem->nxt_qid_n_fid_n_pri,
+ txq_cfg.nxt_qid_n_fid_n_pri);
+ bna_mem_writew(&txq_mem->wvc_n_cquota_n_rquota,
+ txq_cfg.wvc_n_cquota_n_rquota);
+
+ DPRINTK(DEBUG, "TxQ %u\n", txq_id);
+ DPRINTK(DEBUG, "TxQ pg_tbl_addr_lo 0x%x\n",
+ bna_os_ntohl(txq_cfg.pg_tbl_addr_lo));
+ DPRINTK(DEBUG, "TxQ cur_q_entry_lo 0x%x\n",
+ bna_os_ntohl(txq_cfg.cur_q_entry_lo));
+ DPRINTK(DEBUG, "TxQ pg_cnt_n_prd_ptr 0x%x\n",
+ txq_cfg.pg_cnt_n_prd_ptr);
+ DPRINTK(DEBUG, "TxQ entry_n_pg_size 0x%x\n",
+ txq_cfg.entry_n_pg_size);
+ DPRINTK(DEBUG, "TxQ int_blk_n_cns_ptr 0x%x\n",
+ txq_cfg.int_blk_n_cns_ptr);
+ DPRINTK(DEBUG, "TxQ cns_ptr2_n_q_state 0x%x\n",
+ txq_cfg.cns_ptr2_n_q_state);
+ DPRINTK(DEBUG, "TxQ nxt_qid_n_fid_n_pri 0x%x\n",
+ txq_cfg.nxt_qid_n_fid_n_pri);
+ DPRINTK(DEBUG, "TxQ wvc_n_cquota_n_rquota 0x%x\n",
+ txq_cfg.wvc_n_cquota_n_rquota);
+
+ qset = (struct bna_doorbell_qset *)
+ BNA_GET_DOORBELL_BASE_ADDR(dev->bar0);
+ q_ptr->doorbell = &qset[txq_id].txq[0];
+
+ q_ptr->q.producer_index = 0;
+ q_ptr->q.consumer_index = 0;
+}
+
+
+/**
+ * bna_txq_stop()
+ *
+ * Stops the TxQ identified by the TxQ Id.
+ * Should be called with a lock held
+ * The driver should wait for the response to
+ * conclude if the Q stop is successful or not.
+ *
+ * @param[in] q_id - Id of the TxQ
+ *
+ * @return BNA_OK in case of success, else BNA_FAIL
+ */
+enum bna_status_e
+bna_txq_stop(struct bna_dev_s *dev, u32 txq_id)
+{
+ struct bfi_ll_q_stop_req ll_req;
+ u64 bit_mask = 1 << txq_id;
+
+ ll_req.mh.msg_class = BFI_MC_LL;
+ ll_req.mh.msg_id = BFI_LL_H2I_TXQ_STOP_REQ;
+ ll_req.mh.mtag.i2htok = 0;
+
+ ll_req.q_id_mask[0] = bna_os_htonl((u32)bit_mask);
+ ll_req.q_id_mask[1] = bna_os_htonl((u32)(bit_mask >> 32));
+
+ /* send to f/w */
+ return bna_mbox_send(dev, &ll_req, sizeof(ll_req), dev->cbarg);
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * bna_rxq_config()
+ *
+ * For RxQ "rxq_id", it configures the Rx-Queue as specified by "cfg_ptr".
+ *-----------------------------------------------------------------------------
+ */
+void
+bna_rxq_config(struct bna_dev_s *dev, struct bna_rxq *q_ptr,
+ unsigned int rxq_id, const struct bna_rxq_config *cfg_ptr)
+{
+ struct bna_rxtx_q_mem *q_mem;
+ struct bna_rxq_mem rxq_cfg, *rxq_mem;
+ const struct bna_qpt *qpt = &cfg_ptr->qpt;
+ struct bna_dma_addr cur_q_addr;
+ struct bna_doorbell_qset *qset;
+ u32 pg_num;
+
+ BNA_ASSERT(rxq_id < BNA_RXQ_ID_MAX);
+
+ /* Check if the depth is a power of 2 */
+ BNA_ASSERT(BNA_POWER_OF_2(q_ptr->q.q_depth));
+
+
+ cur_q_addr = *((struct bna_dma_addr *)(qpt->kv_qpt_ptr));
+ /*
+ * Fill out structure, to be subsequently written
+ * to hardware
+ */
+ rxq_cfg.pg_tbl_addr_lo = qpt->hw_qpt_ptr.lsb;
+ rxq_cfg.pg_tbl_addr_hi = qpt->hw_qpt_ptr.msb;
+ rxq_cfg.cur_q_entry_lo = cur_q_addr.lsb;
+ rxq_cfg.cur_q_entry_hi = cur_q_addr.msb;
+
+ rxq_cfg.pg_cnt_n_prd_ptr = (qpt->page_count << 16) | 0x0;
+ rxq_cfg.entry_n_pg_size = ((BNA_RXQ_ENTRY_SIZE >> 2) << 16) |
+ (qpt->page_size >> 2);
+ rxq_cfg.sg_n_cq_n_cns_ptr = (((u8)cfg_ptr->cq_id) << 16) | 0x0;
+ rxq_cfg.buf_sz_n_q_state =
+ (cfg_ptr->buffer_size << 16) | BNA_Q_IDLE_STATE;
+ rxq_cfg.next_qid = 0x0 | (0x3 << 8);
+
+ /* Write the page number register */
+ pg_num = BNA_GET_PAGE_NUM(HQM0_BLK_PG_NUM + dev->port,
+ HQM_RXTX_Q_RAM_BASE_OFFSET);
+ bna_reg_write(dev->regs.page_addr, pg_num);
+
+ /* Write to h/w */
+ q_mem = (struct bna_rxtx_q_mem *)
+ BNA_GET_MEM_BASE_ADDR(dev->bar0,
+ HQM_RXTX_Q_RAM_BASE_OFFSET);
+ rxq_mem = &q_mem[rxq_id].rxq;
+
+ bna_mem_writew(&rxq_mem->pg_tbl_addr_lo,
+ bna_os_htonl(rxq_cfg.pg_tbl_addr_lo));
+ bna_mem_writew(&rxq_mem->pg_tbl_addr_hi,
+ bna_os_htonl(rxq_cfg.pg_tbl_addr_hi));
+ bna_mem_writew(&rxq_mem->cur_q_entry_lo,
+ bna_os_htonl(rxq_cfg.cur_q_entry_lo));
+ bna_mem_writew(&rxq_mem->cur_q_entry_hi,
+ bna_os_htonl(rxq_cfg.cur_q_entry_hi));
+
+ bna_mem_writew(&rxq_mem->pg_cnt_n_prd_ptr, rxq_cfg.pg_cnt_n_prd_ptr);
+ bna_mem_writew(&rxq_mem->entry_n_pg_size, rxq_cfg.entry_n_pg_size);
+ bna_mem_writew(&rxq_mem->sg_n_cq_n_cns_ptr,
+ rxq_cfg.sg_n_cq_n_cns_ptr);
+ bna_mem_writew(&rxq_mem->buf_sz_n_q_state,
+ rxq_cfg.buf_sz_n_q_state);
+ bna_mem_writew(&rxq_mem->next_qid, rxq_cfg.next_qid);
+
+ DPRINTK(DEBUG, "RxQ %u\n", rxq_id);
+ DPRINTK(DEBUG, "RxQ pg_tbl_addr_lo 0x%x\n",
+ bna_os_ntohl(rxq_cfg.pg_tbl_addr_lo));
+ DPRINTK(DEBUG, "RxQ cur_q_entry_lo 0x%x\n",
+ bna_os_ntohl(rxq_cfg.cur_q_entry_lo));
+ DPRINTK(DEBUG, "RxQ pg_cnt_n_prd_ptr 0x%x\n", rxq_cfg.pg_cnt_n_prd_ptr);
+ DPRINTK(DEBUG, "RxQ entry_n_pg_size 0x%x\n", rxq_cfg.entry_n_pg_size);
+ DPRINTK(DEBUG, "RxQ sg_n_cq_n_cns_ptr 0x%x\n",
+ rxq_cfg.sg_n_cq_n_cns_ptr);
+ DPRINTK(DEBUG, "RxQ buf_sz_n_q_state 0x%x\n", rxq_cfg.buf_sz_n_q_state);
+ DPRINTK(DEBUG, "RxQ next_qid %u\n", rxq_cfg.next_qid);
+
+ qset = (struct bna_doorbell_qset *)
+ BNA_GET_DOORBELL_BASE_ADDR(dev->bar0);
+ q_ptr->doorbell = &qset[rxq_id].rxq[0];
+
+ q_ptr->q.producer_index = 0;
+ q_ptr->q.consumer_index = 0;
+}
+
+
+/**
+ * bna_rxq_stop()
+ *
+ * Stops the RxQ identified by the RxQ Id.
+ * Should be called with a lock held
+ * The driver should wait for the response to
+ * conclude if the Q stop is successful or not.
+ *
+ * @param[in] q_id - Id of the RxQ
+ *
+ * @return BNA_OK in case of success, else BNA_FAIL
+ */
+enum bna_status_e
+bna_rxq_stop(struct bna_dev_s *dev, u32 rxq_id)
+{
+ struct bfi_ll_q_stop_req ll_req;
+ u64 bit_mask = 1 << rxq_id;
+
+ ll_req.mh.msg_class = BFI_MC_LL;
+ ll_req.mh.msg_id = BFI_LL_H2I_RXQ_STOP_REQ;
+ ll_req.mh.mtag.i2htok = 0;
+
+ ll_req.q_id_mask[0] = bna_os_htonl((u32)bit_mask);
+ ll_req.q_id_mask[1] = bna_os_htonl((u32)(bit_mask >> 32));
+
+ /* send to f/w */
+ return bna_mbox_send(dev, &ll_req, sizeof(ll_req), dev->cbarg);
+}
+
+enum bna_status_e
+bna_multi_rxq_stop(struct bna_dev_s *dev, u64 rxq_id_mask)
+{
+ struct bfi_ll_q_stop_req ll_req;
+
+ bfi_h2i_set(ll_req.mh, BFI_MC_LL, BFI_LL_H2I_RXQ_STOP_REQ, 0);
+
+ ll_req.q_id_mask[0] = bna_os_htonl((u32)rxq_id_mask);
+ ll_req.q_id_mask[1] = bna_os_htonl((u32)(rxq_id_mask >> 32));
+
+ /* send to f/w */
+ return bna_mbox_send(dev, &ll_req, sizeof(ll_req), dev->cbarg);
+}
+
+/*
+ *-----------------------------------------------------------------------------
+ * bna_cq_config()
+ *
+ * For CQ "cq_id", it configures the Rx-Completion Queue as specified by
+ * "cfg_ptr".
+ *-----------------------------------------------------------------------------
+ */
+void
+bna_cq_config(struct bna_dev_s *dev, struct bna_cq *q_ptr,
+ unsigned int cq_id, const struct bna_cq_config *cfg_ptr)
+{
+ struct bna_cq_mem cq_cfg, *cq_mem;
+ const struct bna_qpt *qpt = &cfg_ptr->qpt;
+ struct bna_dma_addr cur_q_addr;
+ u32 pg_num;
+
+ BNA_ASSERT(cq_id < BNA_CQ_ID_MAX);
+
+ /* Check if the depth is a power of 2 */
+ /* How do we ensure this ? */
+ BNA_ASSERT(BNA_POWER_OF_2(q_ptr->q.q_depth));
+
+
+ cur_q_addr = *((struct bna_dma_addr *)(qpt->kv_qpt_ptr));
+
+ /*
+ * Fill out structure, to be subsequently written
+ * to hardware
+ */
+ cq_cfg.pg_tbl_addr_lo = qpt->hw_qpt_ptr.lsb;
+ cq_cfg.pg_tbl_addr_hi = qpt->hw_qpt_ptr.msb;
+ cq_cfg.cur_q_entry_lo = cur_q_addr.lsb;
+ cq_cfg.cur_q_entry_hi = cur_q_addr.msb;
+
+ cq_cfg.pg_cnt_n_prd_ptr = (qpt->page_count << 16) | 0x0;
+ cq_cfg.entry_n_pg_size = ((BNA_CQ_ENTRY_SIZE >> 2) << 16) |
+ (qpt->page_size >> 2);
+ cq_cfg.int_blk_n_cns_ptr = ((((u8)cfg_ptr->ib_seg_index) << 24) |
+ (((u8)cfg_ptr->ib_id) << 16) | 0x0);
+ cq_cfg.q_state = BNA_Q_IDLE_STATE;
+
+ /* Write the page number register */
+ pg_num = BNA_GET_PAGE_NUM(HQM0_BLK_PG_NUM + dev->port,
+ HQM_CQ_RAM_BASE_OFFSET);
+
+ bna_reg_write(dev->regs.page_addr, pg_num);
+ /* H/W write */
+ cq_mem = (struct bna_cq_mem *)
+ BNA_GET_MEM_BASE_ADDR(dev->bar0, HQM_CQ_RAM_BASE_OFFSET);
+ bna_mem_writew(&cq_mem[cq_id].pg_tbl_addr_lo,
+ bna_os_htonl(cq_cfg.pg_tbl_addr_lo));
+ bna_mem_writew(&cq_mem[cq_id].pg_tbl_addr_hi,
+ bna_os_htonl(cq_cfg.pg_tbl_addr_hi));
+ bna_mem_writew(&cq_mem[cq_id].cur_q_entry_lo,
+ bna_os_htonl(cq_cfg.cur_q_entry_lo));
+ bna_mem_writew(&cq_mem[cq_id].cur_q_entry_hi,
+ bna_os_htonl(cq_cfg.cur_q_entry_hi));
+
+ bna_mem_writew(&cq_mem[cq_id].pg_cnt_n_prd_ptr,
+ cq_cfg.pg_cnt_n_prd_ptr);
+ bna_mem_writew(&cq_mem[cq_id].entry_n_pg_size, cq_cfg.entry_n_pg_size);
+ bna_mem_writew(&cq_mem[cq_id].int_blk_n_cns_ptr,
+ cq_cfg.int_blk_n_cns_ptr);
+ bna_mem_writew(&cq_mem[cq_id].q_state, cq_cfg.q_state);
+
+ DPRINTK(DEBUG, "CQ %u\n", cq_id);
+ DPRINTK(DEBUG, "CQ pg_tbl_addr_lo 0x%x\n",
+ bna_os_ntohl(cq_cfg.pg_tbl_addr_lo));
+ DPRINTK(DEBUG, "CQ cur_q_entry_lo 0x%x\n",
+ bna_os_ntohl(cq_cfg.cur_q_entry_lo));
+ DPRINTK(DEBUG, "CQ pg_cnt_n_prd_ptr 0x%x\n", cq_cfg.pg_cnt_n_prd_ptr);
+ DPRINTK(DEBUG, "CQ entry_n_pg_size 0x%x\n", cq_cfg.entry_n_pg_size);
+ DPRINTK(DEBUG, "CQ int_blk_n_cns_ptr 0x%x\n", cq_cfg.int_blk_n_cns_ptr);
+ DPRINTK(DEBUG, "CQ q_state 0x%x\n", cq_cfg.q_state);
+
+ q_ptr->q.producer_index = 0;
+ q_ptr->q.consumer_index = 0;
+
+}
+
+/*
+ * bna_ib_idx_reset()
+ *
+ * For the specified IB, it clears the IB index
+ *
+ * @param[in] cfg_ptr - pointer to IB Configuration Structure.
+ *
+ * @return none
+ */
+void
+bna_ib_idx_reset(struct bna_dev_s *dev, const struct bna_ib_config *cfg_ptr)
+{
+ u32 i, pg_num, *ib_idx;
+
+ pg_num = BNA_GET_PAGE_NUM(HQM0_BLK_PG_NUM + dev->port,
+ HQM_INDX_TBL_RAM_BASE_OFFSET);
+ bna_reg_write(dev->regs.page_addr, pg_num);
+
+ ib_idx = (u32 *)
+ BNA_GET_MEM_BASE_ADDR(dev->bar0, HQM_INDX_TBL_RAM_BASE_OFFSET);
+ ib_idx += cfg_ptr->index_table_offset;
+ for (i = 0; i < cfg_ptr->seg_size; i++)
+ *ib_idx++ = 0;
+}
+
+/*
+ * bna_ib_config_set()
+ *
+ * For IB "ib_id", it configures the Interrupt Block specified by "cfg_ptr".
+ *
+ * @param[in] ib_ptr - pointer to IB Data Structure.
+ * @param[in] ib_id - interrupt-block ID
+ * @param[in] cfg_ptr - pointer to IB Configuration Structure.
+ *
+ * @return BNA_OK or BNA_FAIL
+ */
+void
+bna_ib_config_set(struct bna_dev_s *dev, struct bna_ib *ib_ptr,
+ unsigned int ib_id, const struct bna_ib_config *cfg_ptr)
+{
+ struct bna_ib_blk_mem ib_cfg, *ib_mem;
+ u32 pg_num;
+ struct bna_doorbell_qset *qset;
+
+ BNA_ASSERT(ib_id < BNA_IB_ID_MAX);
+
+
+ ib_cfg.host_addr_lo =
+ (u32)(cfg_ptr->ib_seg_addr.lsb);
+ ib_cfg.host_addr_hi =
+ (u32)(cfg_ptr->ib_seg_addr.msb);
+
+ ib_cfg.clsc_n_ctrl_n_msix = ((cfg_ptr->coalescing_timer << 16) |
+ (cfg_ptr->control_flags << 8) | (cfg_ptr->msix_vector));
+ ib_cfg.ipkt_n_ent_n_idxof = ((cfg_ptr->interpkt_timer & 0xf) << 16) |
+ (cfg_ptr->seg_size << 8) |
+ (cfg_ptr->index_table_offset);
+ ib_cfg.ipkt_cnt_cfg_n_unacked = (cfg_ptr->interpkt_count << 24);
+
+ /* Write the page number register */
+ pg_num = BNA_GET_PAGE_NUM(HQM0_BLK_PG_NUM + dev->port,
+ HQM_IB_RAM_BASE_OFFSET);
+ bna_reg_write(dev->regs.page_addr, pg_num);
+
+ ib_mem = (struct bna_ib_blk_mem *)
+ BNA_GET_MEM_BASE_ADDR(dev->bar0,
+ HQM_IB_RAM_BASE_OFFSET);
+
+ bna_mem_writew(&ib_mem[ib_id].host_addr_lo,
+ bna_os_htonl(ib_cfg.host_addr_lo));
+ bna_mem_writew(&ib_mem[ib_id].host_addr_hi,
+ bna_os_htonl(ib_cfg.host_addr_hi));
+
+ bna_mem_writew(&ib_mem[ib_id].clsc_n_ctrl_n_msix,
+ ib_cfg.clsc_n_ctrl_n_msix);
+ bna_mem_writew(&ib_mem[ib_id].ipkt_n_ent_n_idxof,
+ ib_cfg.ipkt_n_ent_n_idxof);
+ bna_mem_writew(&ib_mem[ib_id].ipkt_cnt_cfg_n_unacked,
+ ib_cfg.ipkt_cnt_cfg_n_unacked);
+
+ DPRINTK(DEBUG, "IB %d: host addr 0x%x clsc_n_ctrl_n_msix 0x%x\n",
+ ib_id, bna_os_htonl(ib_cfg.host_addr_lo),
+ ib_cfg.clsc_n_ctrl_n_msix);
+ DPRINTK(DEBUG, "ipkt_n_ent_n_idxof 0x%x ipkt_cnt_cfg_n_unacked 0x%x\n",
+ ib_cfg.ipkt_n_ent_n_idxof, ib_cfg.ipkt_cnt_cfg_n_unacked);
+
+ qset = (struct bna_doorbell_qset *)
+ BNA_GET_DOORBELL_BASE_ADDR(dev->bar0);
+ ib_ptr->doorbell_addr =
+ (&qset[ib_id >> 1].ib0[(ib_id & 0x1) * (0x20 >> 2)]);
+
+ ib_ptr->doorbell_ack = BNA_DOORBELL_IB_INT_ACK(
+ cfg_ptr->coalescing_timer, 0);
+
+ bna_ib_idx_reset(dev, cfg_ptr);
+}
+
+/*
+ * bna_ib_disable()
+ *
+ * Disables the Interrupt Block "ib_id".
+ *
+ * @param[in] ib_ptr - pointer to IB Data Structure.
+ *
+ * @return None
+ */
+void
+bna_ib_disable(struct bna_dev_s *bna_dev, const struct bna_ib *ib_ptr)
+{
+ bna_reg_write(ib_ptr->doorbell_addr, BNA_DOORBELL_IB_INT_DISABLE);
+}
diff -ruP net-next-2.6-orig/drivers/net/bna/bnad_ethtool.c net-next-2.6-mod/drivers/net/bna/bnad_ethtool.c
--- net-next-2.6-orig/drivers/net/bna/bnad_ethtool.c 1969-12-31 16:00:00.000000000 -0800
+++ net-next-2.6-mod/drivers/net/bna/bnad_ethtool.c 2009-10-31 21:34:47.690539000 -0700
@@ -0,0 +1,1094 @@
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved
+ * www.brocade.com
+ *
+ * Linux network driver for Brocade Converged Network Adapter.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License (GPL) Version 2 as
+ * published by the Free Software Foundation
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+/*
+ * Copyright (c) 2005-2009 Brocade Communications Systems, Inc.
+ * All rights reserved.
+ */
+
+/**
+ * bna_ethtool.c Brocade 10G PCIe Ethernet driver.
+ */
+
+#include <linux/types.h>
+#include <linux/ethtool.h>
+#include <linux/netdevice.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/skbuff.h>
+#include <linux/if_ether.h>
+#include <linux/rtnetlink.h>
+
+#include "bnad.h"
+#include "bna_os.h"
+#include "bna_hwreg.h"
+#include "bna_iocll.h"
+#include "bnad_defs.h"
+#include "phyport_defs.h"
+
+#define BNAD_ETHTOOL_STATS_NUM \
+ (sizeof(struct net_device_stats) / sizeof(unsigned long) + \
+ sizeof(struct bnad_drv_stats) / sizeof(u64) + \
+ (offsetof(struct bna_stats, rxf_stats[0]) + \
+ sizeof(struct bna_stats_txf)) / sizeof(u64))
+
+static char *bnad_net_stats_strings[BNAD_ETHTOOL_STATS_NUM] = {
+ "rx_packets",
+ "tx_packets",
+ "rx_bytes",
+ "tx_bytes",
+ "rx_errors",
+ "tx_errors",
+ "rx_dropped",
+ "tx_dropped",
+ "multicast",
+ "collisions",
+
+ "rx_length_errors",
+ "rx_over_errors",
+ "rx_crc_errors",
+ "rx_frame_errors",
+ "rx_fifo_errors",
+ "rx_missed_errors",
+
+ "tx_aborted_errors",
+ "tx_carrier_errors",
+ "tx_fifo_errors",
+ "tx_heartbeat_errors",
+ "tx_window_errors",
+
+ "rx_compressed",
+ "tx_compressed",
+
+ "netif_queue_stop",
+ "netif_queue_wakeup",
+ "tso4",
+ "tso6",
+ "tso_err",
+ "tcpcsum_offload",
+ "udpcsum_offload",
+ "csum_help",
+ "csum_help_err",
+ "hw_stats_updates",
+ "netif_rx_schedule",
+ "netif_rx_complete",
+ "netif_rx_dropped",
+
+ "mac_frame_64",
+ "mac_frame_65_127",
+ "mac_frame_128_255",
+ "mac_frame_256_511",
+ "mac_frame_512_1023",
+ "mac_frame_1024_1518",
+ "mac_frame_1518_1522",
+ "mac_rx_bytes",
+ "mac_rx_packets",
+ "mac_rx_fcs_error",
+ "mac_rx_multicast",
+ "mac_rx_broadcast",
+ "mac_rx_control_frames",
+ "mac_rx_pause",
+ "mac_rx_unknown_opcode",
+ "mac_rx_alignment_error",
+ "mac_rx_frame_length_error",
+ "mac_rx_code_error",
+ "mac_rx_carrier_sense_error",
+ "mac_rx_undersize",
+ "mac_rx_oversize",
+ "mac_rx_fragments",
+ "mac_rx_jabber",
+ "mac_rx_drop",
+
+ "bpc_rx_pause_0",
+ "bpc_rx_pause_1",
+ "bpc_rx_pause_2",
+ "bpc_rx_pause_3",
+ "bpc_rx_pause_4",
+ "bpc_rx_pause_5",
+ "bpc_rx_pause_6",
+ "bpc_rx_pause_7",
+ "bpc_rx_zero_pause_0",
+ "bpc_rx_zero_pause_1",
+ "bpc_rx_zero_pause_2",
+ "bpc_rx_zero_pause_3",
+ "bpc_rx_zero_pause_4",
+ "bpc_rx_zero_pause_5",
+ "bpc_rx_zero_pause_6",
+ "bpc_rx_zero_pause_7",
+ "bpc_rx_first_pause_0",
+ "bpc_rx_first_pause_1",
+ "bpc_rx_first_pause_2",
+ "bpc_rx_first_pause_3",
+ "bpc_rx_first_pause_4",
+ "bpc_rx_first_pause_5",
+ "bpc_rx_first_pause_6",
+ "bpc_rx_first_pause_7",
+
+ "rad_rx_frames",
+ "rad_rx_octets",
+ "rad_rx_vlan_frames",
+ "rad_rx_ucast",
+ "rad_rx_ucast_octets",
+ "rad_rx_ucast_vlan",
+ "rad_rx_mcast",
+ "rad_rx_mcast_octets",
+ "rad_rx_mcast_vlan",
+ "rad_rx_bcast",
+ "rad_rx_bcast_octets",
+ "rad_rx_bcast_vlan",
+ "rad_rx_drops",
+
+ "fc_rx_ucast_octets",
+ "fc_rx_ucast",
+ "fc_rx_ucast_vlan",
+ "fc_rx_mcast_octets",
+ "fc_rx_mcast",
+ "fc_rx_mcast_vlan",
+ "fc_rx_bcast_octets",
+ "fc_rx_bcast",
+ "fc_rx_bcast_vlan",
+
+ "mac_tx_bytes",
+ "mac_tx_packets",
+ "mac_tx_multicast",
+ "mac_tx_broadcast",
+ "mac_tx_pause",
+ "mac_tx_deferral",
+ "mac_tx_excessive_deferral",
+ "mac_tx_single_collision",
+ "mac_tx_muliple_collision",
+ "mac_tx_late_collision",
+ "mac_tx_excessive_collision",
+ "mac_tx_total_collision",
+ "mac_tx_pause_honored",
+ "mac_tx_drop",
+ "mac_tx_jabber",
+ "mac_tx_fcs_error",
+ "mac_tx_control_frame",
+ "mac_tx_oversize",
+ "mac_tx_undersize",
+ "mac_tx_fragments",
+
+ "bpc_tx_pause_0",
+ "bpc_tx_pause_1",
+ "bpc_tx_pause_2",
+ "bpc_tx_pause_3",
+ "bpc_tx_pause_4",
+ "bpc_tx_pause_5",
+ "bpc_tx_pause_6",
+ "bpc_tx_pause_7",
+ "bpc_tx_zero_pause_0",
+ "bpc_tx_zero_pause_1",
+ "bpc_tx_zero_pause_2",
+ "bpc_tx_zero_pause_3",
+ "bpc_tx_zero_pause_4",
+ "bpc_tx_zero_pause_5",
+ "bpc_tx_zero_pause_6",
+ "bpc_tx_zero_pause_7",
+ "bpc_tx_first_pause_0",
+ "bpc_tx_first_pause_1",
+ "bpc_tx_first_pause_2",
+ "bpc_tx_first_pause_3",
+ "bpc_tx_first_pause_4",
+ "bpc_tx_first_pause_5",
+ "bpc_tx_first_pause_6",
+ "bpc_tx_first_pause_7",
+
+ "fc_tx_ucast_octets",
+ "fc_tx_ucast",
+ "fc_tx_ucast_vlan",
+ "fc_tx_mcast_octets",
+ "fc_tx_mcast",
+ "fc_tx_mcast_vlan",
+ "fc_tx_bcast_octets",
+ "fc_tx_bcast",
+ "fc_tx_bcast_vlan",
+ "fc_tx_parity_errors",
+ "fc_tx_timeout",
+ "fc_tx_fid_parity_errors",
+
+ "txf0_ucast_octets",
+ "txf0_ucast",
+ "txf0_ucast_vlan",
+ "txf0_mcast_octets",
+ "txf0_mcast",
+ "txf0_mcast_vlan",
+ "txf0_bcast_octets",
+ "txf0_bcast",
+ "txf0_bcast_vlan",
+ "txf0_errors",
+ "txf0_filter_vlan",
+ "txf0_filter_mac_sa"
+};
+
+static int bnad_get_regs_len(struct net_device *netdev);
+
+static int bnad_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
+{
+ struct bnad *bnad = netdev_priv(netdev);
+ struct bna_port_param port_param;
+
+ bnad_lock();
+ spin_lock_irq(&bnad->priv_lock);
+ bna_port_param_get(bnad->priv, &port_param);
+ spin_unlock_irq(&bnad->priv_lock);
+
+ if (port_param.speed == BNA_LINK_SPEED_10Gbps) {
+ cmd->supported = SUPPORTED_10000baseT_Full;
+ cmd->advertising = ADVERTISED_10000baseT_Full;
+ }
+
+ /* In future we may support autoneg, currently we don't */
+ if (port_param.autoneg) {
+ cmd->supported |= SUPPORTED_Autoneg;
+ cmd->advertising |= ADVERTISED_Autoneg;
+ cmd->autoneg = AUTONEG_ENABLE;
+ } else
+ cmd->autoneg = AUTONEG_DISABLE;
+ cmd->supported |= SUPPORTED_FIBRE;
+ cmd->advertising |= ADVERTISED_FIBRE;
+ cmd->port = PORT_FIBRE;
+ cmd->phy_address = 0;
+
+ if (netif_carrier_ok(netdev)) {
+ cmd->speed = SPEED_10000;
+ cmd->duplex = DUPLEX_FULL;
+ } else {
+ cmd->speed = -1;
+ cmd->duplex = -1;
+ }
+ cmd->transceiver = XCVR_EXTERNAL;
+ cmd->maxtxpkt = 0;
+ cmd->maxrxpkt = 0;
+ bnad_unlock();
+ return 0;
+}
+
+static int bnad_set_settings(struct net_device *netdev, struct ethtool_cmd *cmd)
+{
+ /* 10G full duplex setting supported only */
+ if (cmd->autoneg == AUTONEG_ENABLE) {
+ return -EOPNOTSUPP;
+ } else {
+ if ((cmd->speed == SPEED_10000) && (cmd->duplex == DUPLEX_FULL))
+ return 0;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+static void
+bnad_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
+{
+ struct bnad *bnad = netdev_priv(netdev);
+ struct bfa_ioc_attr_s *ioc_attr;
+
+ strcpy(drvinfo->driver, BNAD_NAME);
+ strcpy(drvinfo->version, BNAD_VERSION);
+
+ ioc_attr = kzalloc(sizeof(*ioc_attr), GFP_KERNEL);
+ if (ioc_attr) {
+ memset(ioc_attr, 0, sizeof(*ioc_attr));
+ spin_lock_irq(&bnad->priv_lock);
+ bna_iocll_getattr(bnad->priv, ioc_attr);
+ spin_unlock_irq(&bnad->priv_lock);
+
+ strncpy(drvinfo->fw_version, ioc_attr->adapter_attr.fw_ver,
+ sizeof(drvinfo->fw_version) - 1);
+ kfree(ioc_attr);
+ }
+
+ strncpy(drvinfo->bus_info, pci_name(bnad->pcidev),
+ ETHTOOL_BUSINFO_LEN);
+}
+
+static int get_regs(struct bnad *bnad, u32 *regs)
+{
+ int num = 0, i;
+ u32 reg_addr;
+
+#define BNAD_GET_REG(addr) \
+do { \
+ if (regs) \
+ regs[num++] = readl(bnad->bar0 + (addr)); \
+ else \
+ num++; \
+} while (0)
+
+ /* DMA Block Internal Registers */
+ BNAD_GET_REG(DMA_CTRL_REG0);
+ BNAD_GET_REG(DMA_CTRL_REG1);
+ BNAD_GET_REG(DMA_ERR_INT_STATUS);
+ BNAD_GET_REG(DMA_ERR_INT_ENABLE);
+ BNAD_GET_REG(DMA_ERR_INT_STATUS_SET);
+
+ /* APP Block Register Address Offset from BAR0 */
+ BNAD_GET_REG(HOSTFN0_INT_STATUS);
+ BNAD_GET_REG(HOSTFN0_INT_MASK);
+ BNAD_GET_REG(HOST_PAGE_NUM_FN0);
+ BNAD_GET_REG(HOST_MSIX_ERR_INDEX_FN0);
+ BNAD_GET_REG(FN0_PCIE_ERR_REG);
+ BNAD_GET_REG(FN0_ERR_TYPE_STATUS_REG);
+ BNAD_GET_REG(FN0_ERR_TYPE_MSK_STATUS_REG);
+
+ BNAD_GET_REG(HOSTFN1_INT_STATUS);
+ BNAD_GET_REG(HOSTFN1_INT_MASK);
+ BNAD_GET_REG(HOST_PAGE_NUM_FN1);
+ BNAD_GET_REG(HOST_MSIX_ERR_INDEX_FN1);
+ BNAD_GET_REG(FN1_PCIE_ERR_REG);
+ BNAD_GET_REG(FN1_ERR_TYPE_STATUS_REG);
+ BNAD_GET_REG(FN1_ERR_TYPE_MSK_STATUS_REG);
+
+ BNAD_GET_REG(PCIE_MISC_REG);
+
+ BNAD_GET_REG(HOST_SEM0_REG);
+ BNAD_GET_REG(HOST_SEM1_REG);
+ BNAD_GET_REG(HOST_SEM2_REG);
+ BNAD_GET_REG(HOST_SEM3_REG);
+ BNAD_GET_REG(HOST_SEM0_INFO_REG);
+ BNAD_GET_REG(HOST_SEM1_INFO_REG);
+ BNAD_GET_REG(HOST_SEM2_INFO_REG);
+ BNAD_GET_REG(HOST_SEM3_INFO_REG);
+
+ BNAD_GET_REG(TEMPSENSE_CNTL_REG);
+ BNAD_GET_REG(TEMPSENSE_STAT_REG);
+
+ BNAD_GET_REG(APP_LOCAL_ERR_STAT);
+ BNAD_GET_REG(APP_LOCAL_ERR_MSK);
+
+ BNAD_GET_REG(PCIE_LNK_ERR_STAT);
+ BNAD_GET_REG(PCIE_LNK_ERR_MSK);
+
+ BNAD_GET_REG(FCOE_FIP_ETH_TYPE);
+ BNAD_GET_REG(RESV_ETH_TYPE);
+
+ BNAD_GET_REG(HOSTFN2_INT_STATUS);
+ BNAD_GET_REG(HOSTFN2_INT_MASK);
+ BNAD_GET_REG(HOST_PAGE_NUM_FN2);
+ BNAD_GET_REG(HOST_MSIX_ERR_INDEX_FN2);
+ BNAD_GET_REG(FN2_PCIE_ERR_REG);
+ BNAD_GET_REG(FN2_ERR_TYPE_STATUS_REG);
+ BNAD_GET_REG(FN2_ERR_TYPE_MSK_STATUS_REG);
+
+ BNAD_GET_REG(HOSTFN3_INT_STATUS);
+ BNAD_GET_REG(HOSTFN3_INT_MASK);
+ BNAD_GET_REG(HOST_PAGE_NUM_FN3);
+ BNAD_GET_REG(HOST_MSIX_ERR_INDEX_FN3);
+ BNAD_GET_REG(FN3_PCIE_ERR_REG);
+ BNAD_GET_REG(FN3_ERR_TYPE_STATUS_REG);
+ BNAD_GET_REG(FN3_ERR_TYPE_MSK_STATUS_REG);
+
+ /* Host Command Status Registers */
+ reg_addr = HOST_CMDSTS0_CLR_REG;
+ for (i = 0; i < 16; i++) {
+ BNAD_GET_REG(reg_addr);
+ BNAD_GET_REG(reg_addr + 4);
+ BNAD_GET_REG(reg_addr + 8);
+ reg_addr += 0x10;
+ }
+
+ /* Function ID register */
+ BNAD_GET_REG(FNC_ID_REG);
+
+ /* Function personality register */
+ BNAD_GET_REG(FNC_PERS_REG);
+
+ /* Operation mode register */
+ BNAD_GET_REG(OP_MODE);
+
+ /* LPU0 Registers */
+ BNAD_GET_REG(LPU0_MBOX_CTL_REG);
+ BNAD_GET_REG(LPU0_MBOX_CMD_REG);
+ BNAD_GET_REG(LPU0_MBOX_LINK_0REG);
+ BNAD_GET_REG(LPU1_MBOX_LINK_0REG);
+ BNAD_GET_REG(LPU0_MBOX_STATUS_0REG);
+ BNAD_GET_REG(LPU1_MBOX_STATUS_0REG);
+ BNAD_GET_REG(LPU0_ERR_STATUS_REG);
+ BNAD_GET_REG(LPU0_ERR_SET_REG);
+
+ /* LPU1 Registers */
+ BNAD_GET_REG(LPU1_MBOX_CTL_REG);
+ BNAD_GET_REG(LPU1_MBOX_CMD_REG);
+ BNAD_GET_REG(LPU0_MBOX_LINK_1REG);
+ BNAD_GET_REG(LPU1_MBOX_LINK_1REG);
+ BNAD_GET_REG(LPU0_MBOX_STATUS_1REG);
+ BNAD_GET_REG(LPU1_MBOX_STATUS_1REG);
+ BNAD_GET_REG(LPU1_ERR_STATUS_REG);
+ BNAD_GET_REG(LPU1_ERR_SET_REG);
+
+ /* PSS Registers */
+ BNAD_GET_REG(PSS_CTL_REG);
+ BNAD_GET_REG(PSS_ERR_STATUS_REG);
+ BNAD_GET_REG(ERR_STATUS_SET);
+ BNAD_GET_REG(PSS_RAM_ERR_STATUS_REG);
+
+ /* Catapult CPQ Registers */
+ BNAD_GET_REG(HOSTFN0_LPU0_MBOX0_CMD_STAT);
+ BNAD_GET_REG(HOSTFN0_LPU1_MBOX0_CMD_STAT);
+ BNAD_GET_REG(LPU0_HOSTFN0_MBOX0_CMD_STAT);
+ BNAD_GET_REG(LPU1_HOSTFN0_MBOX0_CMD_STAT);
+
+ BNAD_GET_REG(HOSTFN0_LPU0_MBOX1_CMD_STAT);
+ BNAD_GET_REG(HOSTFN0_LPU1_MBOX1_CMD_STAT);
+ BNAD_GET_REG(LPU0_HOSTFN0_MBOX1_CMD_STAT);
+ BNAD_GET_REG(LPU1_HOSTFN0_MBOX1_CMD_STAT);
+
+ BNAD_GET_REG(HOSTFN1_LPU0_MBOX0_CMD_STAT);
+ BNAD_GET_REG(HOSTFN1_LPU1_MBOX0_CMD_STAT);
+ BNAD_GET_REG(LPU0_HOSTFN1_MBOX0_CMD_STAT);
+ BNAD_GET_REG(LPU1_HOSTFN1_MBOX0_CMD_STAT);
+
+ BNAD_GET_REG(HOSTFN1_LPU0_MBOX1_CMD_STAT);
+ BNAD_GET_REG(HOSTFN1_LPU1_MBOX1_CMD_STAT);
+ BNAD_GET_REG(LPU0_HOSTFN1_MBOX1_CMD_STAT);
+ BNAD_GET_REG(LPU1_HOSTFN1_MBOX1_CMD_STAT);
+
+ BNAD_GET_REG(HOSTFN2_LPU0_MBOX0_CMD_STAT);
+ BNAD_GET_REG(HOSTFN2_LPU1_MBOX0_CMD_STAT);
+ BNAD_GET_REG(LPU0_HOSTFN2_MBOX0_CMD_STAT);
+ BNAD_GET_REG(LPU1_HOSTFN2_MBOX0_CMD_STAT);
+
+ BNAD_GET_REG(HOSTFN2_LPU0_MBOX1_CMD_STAT);
+ BNAD_GET_REG(HOSTFN2_LPU1_MBOX1_CMD_STAT);
+ BNAD_GET_REG(LPU0_HOSTFN2_MBOX1_CMD_STAT);
+ BNAD_GET_REG(LPU1_HOSTFN2_MBOX1_CMD_STAT);
+
+ BNAD_GET_REG(HOSTFN3_LPU0_MBOX0_CMD_STAT);
+ BNAD_GET_REG(HOSTFN3_LPU1_MBOX0_CMD_STAT);
+ BNAD_GET_REG(LPU0_HOSTFN3_MBOX0_CMD_STAT);
+ BNAD_GET_REG(LPU1_HOSTFN3_MBOX0_CMD_STAT);
+
+ BNAD_GET_REG(HOSTFN3_LPU0_MBOX1_CMD_STAT);
+ BNAD_GET_REG(HOSTFN3_LPU1_MBOX1_CMD_STAT);
+ BNAD_GET_REG(LPU0_HOSTFN3_MBOX1_CMD_STAT);
+ BNAD_GET_REG(LPU1_HOSTFN3_MBOX1_CMD_STAT);
+
+ /* Host Function Force Parity Error Registers */
+ BNAD_GET_REG(HOSTFN0_LPU_FORCE_PERR);
+ BNAD_GET_REG(HOSTFN1_LPU_FORCE_PERR);
+ BNAD_GET_REG(HOSTFN2_LPU_FORCE_PERR);
+ BNAD_GET_REG(HOSTFN3_LPU_FORCE_PERR);
+
+ /* LL Port[0|1] Halt Mask Registers */
+ BNAD_GET_REG(LL_HALT_MSK_P0);
+ BNAD_GET_REG(LL_HALT_MSK_P1);
+
+ /* LL Port[0|1] Error Mask Registers */
+ BNAD_GET_REG(LL_ERR_MSK_P0);
+ BNAD_GET_REG(LL_ERR_MSK_P1);
+
+ /* EMC FLI Registers */
+ BNAD_GET_REG(FLI_CMD_REG);
+ BNAD_GET_REG(FLI_ADDR_REG);
+ BNAD_GET_REG(FLI_CTL_REG);
+ BNAD_GET_REG(FLI_WRDATA_REG);
+ BNAD_GET_REG(FLI_RDDATA_REG);
+ BNAD_GET_REG(FLI_DEV_STATUS_REG);
+ BNAD_GET_REG(FLI_SIG_WD_REG);
+
+ BNAD_GET_REG(FLI_DEV_VENDOR_REG);
+ BNAD_GET_REG(FLI_ERR_STATUS_REG);
+
+ /* RxAdm 0 Registers */
+ BNAD_GET_REG(RAD0_CTL_REG);
+ BNAD_GET_REG(RAD0_PE_PARM_REG);
+ BNAD_GET_REG(RAD0_BCN_REG);
+ BNAD_GET_REG(RAD0_DEFAULT_REG);
+ BNAD_GET_REG(RAD0_PROMISC_REG);
+ BNAD_GET_REG(RAD0_BCNQ_REG);
+ BNAD_GET_REG(RAD0_DEFAULTQ_REG);
+
+ BNAD_GET_REG(RAD0_ERR_STS);
+ BNAD_GET_REG(RAD0_SET_ERR_STS);
+ BNAD_GET_REG(RAD0_ERR_INT_EN);
+ BNAD_GET_REG(RAD0_FIRST_ERR);
+ BNAD_GET_REG(RAD0_FORCE_ERR);
+
+ BNAD_GET_REG(RAD0_MAC_MAN_1H);
+ BNAD_GET_REG(RAD0_MAC_MAN_1L);
+ BNAD_GET_REG(RAD0_MAC_MAN_2H);
+ BNAD_GET_REG(RAD0_MAC_MAN_2L);
+ BNAD_GET_REG(RAD0_MAC_MAN_3H);
+ BNAD_GET_REG(RAD0_MAC_MAN_3L);
+ BNAD_GET_REG(RAD0_MAC_MAN_4H);
+ BNAD_GET_REG(RAD0_MAC_MAN_4L);
+
+ BNAD_GET_REG(RAD0_LAST4_IP);
+
+ /* RxAdm 1 Registers */
+ BNAD_GET_REG(RAD1_CTL_REG);
+ BNAD_GET_REG(RAD1_PE_PARM_REG);
+ BNAD_GET_REG(RAD1_BCN_REG);
+ BNAD_GET_REG(RAD1_DEFAULT_REG);
+ BNAD_GET_REG(RAD1_PROMISC_REG);
+ BNAD_GET_REG(RAD1_BCNQ_REG);
+ BNAD_GET_REG(RAD1_DEFAULTQ_REG);
+
+ BNAD_GET_REG(RAD1_ERR_STS);
+ BNAD_GET_REG(RAD1_SET_ERR_STS);
+ BNAD_GET_REG(RAD1_ERR_INT_EN);
+
+ /* TxA0 Registers */
+ BNAD_GET_REG(TXA0_CTRL_REG);
+ /* TxA0 TSO Sequence # Registers (RO) */
+ for (i = 0; i < 8; i++) {
+ BNAD_GET_REG(TXA0_TSO_TCP_SEQ_REG(i));
+ BNAD_GET_REG(TXA0_TSO_IP_INFO_REG(i));
+ }
+
+ /* TxA1 Registers */
+ BNAD_GET_REG(TXA1_CTRL_REG);
+ /* TxA1 TSO Sequence # Registers (RO) */
+ for (i = 0; i < 8; i++) {
+ BNAD_GET_REG(TXA1_TSO_TCP_SEQ_REG(i));
+ BNAD_GET_REG(TXA1_TSO_IP_INFO_REG(i));
+ }
+
+ /* RxA Registers */
+ BNAD_GET_REG(RXA0_CTL_REG);
+ BNAD_GET_REG(RXA1_CTL_REG);
+
+ /* PLB0 Registers */
+ BNAD_GET_REG(PLB0_ECM_TIMER_REG);
+ BNAD_GET_REG(PLB0_RL_CTL);
+ for (i = 0; i < 8; i++)
+ BNAD_GET_REG(PLB0_RL_MAX_BC(i));
+ BNAD_GET_REG(PLB0_RL_TU_PRIO);
+ for (i = 0; i < 8; i++)
+ BNAD_GET_REG(PLB0_RL_BYTE_CNT(i));
+ BNAD_GET_REG(PLB0_RL_MIN_REG);
+ BNAD_GET_REG(PLB0_RL_MAX_REG);
+ BNAD_GET_REG(PLB0_EMS_ADD_REG);
+
+ /* PLB1 Registers */
+ BNAD_GET_REG(PLB1_ECM_TIMER_REG);
+ BNAD_GET_REG(PLB1_RL_CTL);
+ for (i = 0; i < 8; i++)
+ BNAD_GET_REG(PLB1_RL_MAX_BC(i));
+ BNAD_GET_REG(PLB1_RL_TU_PRIO);
+ for (i = 0; i < 8; i++)
+ BNAD_GET_REG(PLB1_RL_BYTE_CNT(i));
+ BNAD_GET_REG(PLB1_RL_MIN_REG);
+ BNAD_GET_REG(PLB1_RL_MAX_REG);
+ BNAD_GET_REG(PLB1_EMS_ADD_REG);
+
+ /* HQM Control Register */
+ BNAD_GET_REG(HQM0_CTL_REG);
+ BNAD_GET_REG(HQM0_RXQ_STOP_SEM);
+ BNAD_GET_REG(HQM0_TXQ_STOP_SEM);
+ BNAD_GET_REG(HQM1_CTL_REG);
+ BNAD_GET_REG(HQM1_RXQ_STOP_SEM);
+ BNAD_GET_REG(HQM1_TXQ_STOP_SEM);
+
+ /* LUT Registers */
+ BNAD_GET_REG(LUT0_ERR_STS);
+ BNAD_GET_REG(LUT0_SET_ERR_STS);
+ BNAD_GET_REG(LUT1_ERR_STS);
+ BNAD_GET_REG(LUT1_SET_ERR_STS); \
+
+ /* TRC Registers */
+ BNAD_GET_REG(TRC_CTL_REG);
+ BNAD_GET_REG(TRC_MODS_REG);
+ BNAD_GET_REG(TRC_TRGC_REG);
+ BNAD_GET_REG(TRC_CNT1_REG);
+ BNAD_GET_REG(TRC_CNT2_REG);
+ BNAD_GET_REG(TRC_NXTS_REG);
+ BNAD_GET_REG(TRC_DIRR_REG);
+ for (i = 0; i < 10; i++)
+ BNAD_GET_REG(TRC_TRGM_REG(i));
+ for (i = 0; i < 10; i++)
+ BNAD_GET_REG(TRC_NXTM_REG(i));
+ for (i = 0; i < 10; i++)
+ BNAD_GET_REG(TRC_STRM_REG(i));
+
+#undef BNAD_GET_REG
+ return num;
+}
+
+static int bnad_get_regs_len(struct net_device *netdev)
+{
+ return get_regs(netdev_priv(netdev), NULL) * sizeof(u32);
+}
+
+static void
+bnad_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *buf)
+{
+ memset(buf, 0, bnad_get_regs_len(netdev));
+ get_regs(netdev_priv(netdev), buf);
+}
+
+static void
+bnad_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wolinfo)
+{
+ wolinfo->supported = 0;
+ wolinfo->wolopts = 0;
+}
+
+
+static int
+bnad_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
+{
+ struct bnad *bnad = netdev_priv(netdev);
+
+ bnad_lock();
+ coalesce->rx_coalesce_usecs = bnad->rx_coalescing_timeo *
+ BNAD_COALESCING_TIMER_UNIT;
+ coalesce->rx_max_coalesced_frames = bnad->rx_interpkt_count;
+ coalesce->rx_coalesce_usecs_irq = bnad->rx_interpkt_timeo;
+ coalesce->tx_coalesce_usecs = bnad->tx_coalescing_timeo *
+ BNAD_COALESCING_TIMER_UNIT;
+ coalesce->tx_max_coalesced_frames = bnad->tx_interpkt_count;
+
+ coalesce->use_adaptive_rx_coalesce = bnad->rx_dyn_coalesce_on;
+ bnad_unlock();
+ return 0;
+}
+
+static int
+bnad_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
+{
+ struct bnad *bnad = netdev_priv(netdev);
+ int i, err = 0, reset = 0;
+ u16 ib_id;
+
+ if (coalesce->rx_coalesce_usecs == 0 || coalesce->rx_coalesce_usecs >
+ BNAD_MAX_COALESCING_TIMEO * BNAD_COALESCING_TIMER_UNIT)
+ return -EINVAL;
+ if (coalesce->rx_max_coalesced_frames > BNAD_MAX_INTERPKT_COUNT)
+ return -EINVAL;
+ if (coalesce->rx_coalesce_usecs_irq == 0 ||
+ coalesce->rx_coalesce_usecs_irq > BNAD_MAX_INTERPKT_TIMEO)
+ return -EINVAL;
+
+ if (coalesce->tx_coalesce_usecs == 0 || coalesce->tx_coalesce_usecs >
+ BNAD_MAX_COALESCING_TIMEO * BNAD_COALESCING_TIMER_UNIT)
+ return -EINVAL;
+ if (coalesce->tx_max_coalesced_frames > BNAD_MAX_INTERPKT_COUNT)
+ return -EINVAL;
+
+ bnad_lock();
+
+ bnad->rx_dyn_coalesce_on = coalesce->use_adaptive_rx_coalesce;
+
+ bnad->rx_coalescing_timeo = coalesce->rx_coalesce_usecs /
+ BNAD_COALESCING_TIMER_UNIT;
+ if (bnad->rx_coalescing_timeo == 0)
+ bnad->rx_coalescing_timeo = 1;
+ if (!test_bit(BNAD_DISABLED, &bnad->state)) {
+ for (i = 0; i < bnad->cq_num; i++) {
+ ib_id = bnad->cq_table[i].cq_config.ib_id;
+ bnad->ib_table[ib_id].ib_config.coalescing_timer =
+ bnad->rx_coalescing_timeo;
+ if (!bnad->rx_dyn_coalesce_on) {
+ bnad->cq_table[i].rx_coalescing_timeo =
+ bnad->rx_coalescing_timeo;
+ }
+ }
+ }
+ if (coalesce->rx_max_coalesced_frames != bnad->rx_interpkt_count) {
+ bnad->rx_interpkt_count = coalesce->rx_max_coalesced_frames;
+ reset++;
+ }
+ if (coalesce->rx_coalesce_usecs_irq != bnad->rx_interpkt_timeo) {
+ bnad->rx_interpkt_timeo = coalesce->rx_coalesce_usecs_irq;
+ reset++;
+ }
+
+ bnad->tx_coalescing_timeo = coalesce->tx_coalesce_usecs /
+ BNAD_COALESCING_TIMER_UNIT;
+ if (bnad->tx_coalescing_timeo == 0)
+ bnad->tx_coalescing_timeo = 1;
+ if (!test_bit(BNAD_DISABLED, &bnad->state)) {
+ for (i = 0; i < bnad->txq_num; i++) {
+ ib_id = bnad->txq_table[i].txq_config.ib_id;
+ bnad->ib_table[ib_id].ib_config.coalescing_timer =
+ bnad->tx_coalescing_timeo;
+ }
+ }
+ if (coalesce->tx_max_coalesced_frames != bnad->tx_interpkt_count) {
+ bnad->tx_interpkt_count = coalesce->tx_max_coalesced_frames;
+ reset++;
+ }
+
+ if (reset)
+ err = bnad_sw_reset(netdev);
+
+ bnad_unlock();
+
+ return err;
+}
+
+static void bnad_get_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ringparam)
+{
+ struct bnad *bnad = netdev_priv(netdev);
+
+ bnad_lock();
+ ringparam->rx_max_pending = BNAD_MAX_Q_DEPTH / bnad_rxqs_per_cq;
+ ringparam->rx_mini_max_pending = 0;
+ ringparam->rx_jumbo_max_pending = 0;
+ ringparam->tx_max_pending = BNAD_MAX_Q_DEPTH;
+
+ ringparam->rx_pending = bnad->rxq_depth;
+ ringparam->rx_mini_max_pending = 0;
+ ringparam->rx_jumbo_max_pending = 0;
+ ringparam->tx_pending = bnad->txq_depth;
+ bnad_unlock();
+}
+
+static int bnad_set_ringparam(struct net_device *netdev,
+ struct ethtool_ringparam *ringparam)
+{
+ int err = 0;
+ struct bnad *bnad = netdev_priv(netdev);
+ bnad_lock();
+ if (ringparam->rx_pending == bnad->rxq_depth &&
+ ringparam->tx_pending == bnad->txq_depth) {
+ bnad_unlock();
+ return 0;
+ }
+
+ if (ringparam->rx_pending < BNAD_MIN_Q_DEPTH ||
+ ringparam->rx_pending > BNAD_MAX_Q_DEPTH / bnad_rxqs_per_cq ||
+ !BNA_POWER_OF_2(ringparam->rx_pending)) {
+ bnad_unlock();
+ return -EINVAL;
+ }
+ if (ringparam->tx_pending < BNAD_MIN_Q_DEPTH ||
+ ringparam->tx_pending > BNAD_MAX_Q_DEPTH ||
+ !BNA_POWER_OF_2(ringparam->tx_pending)) {
+ bnad_unlock();
+ return -EINVAL;
+ }
+
+ if (ringparam->rx_pending != bnad->rxq_depth) {
+ bnad->rxq_depth = ringparam->rx_pending;
+ bnad->flags |= BNAD_F_RXQ_DEPTH;
+ }
+ if (ringparam->tx_pending != bnad->txq_depth) {
+ bnad->txq_depth = ringparam->tx_pending;
+ bnad->flags |= BNAD_F_TXQ_DEPTH;
+ }
+
+ err = bnad_sw_reset(netdev);
+ bnad_unlock();
+ return err;
+}
+
+static void bnad_get_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pauseparam)
+{
+ struct bnad *bnad = netdev_priv(netdev);
+ bnad_lock();
+ pauseparam->autoneg = 0;
+ pauseparam->rx_pause = bnad->pause_config.rx_pause;
+ pauseparam->tx_pause = bnad->pause_config.tx_pause;
+ bnad_unlock();
+}
+
+static int bnad_set_pauseparam(struct net_device *netdev,
+ struct ethtool_pauseparam *pauseparam)
+{
+ struct bnad *bnad = netdev_priv(netdev);
+ int err;
+
+ if (pauseparam->autoneg == AUTONEG_ENABLE)
+ return -EINVAL;
+ bnad_lock();
+ if (pauseparam->rx_pause != bnad->pause_config.rx_pause ||
+ pauseparam->tx_pause != bnad->pause_config.tx_pause) {
+ bnad->pause_config.rx_pause = pauseparam->rx_pause;
+ bnad->pause_config.tx_pause = pauseparam->tx_pause;
+ spin_lock_irq(&bnad->priv_lock);
+ err = bna_set_pause_config(bnad->priv,
+ &bnad->pause_config, bnad);
+ BNA_ASSERT(!err);
+ spin_unlock_irq(&bnad->priv_lock);
+ }
+ bnad_unlock();
+ return 0;
+}
+
+static u32 bnad_get_rx_csum(struct net_device *netdev)
+{
+ u32 rx_csum;
+ struct bnad *bnad = netdev_priv(netdev);
+
+ bnad_lock();
+ rx_csum = bnad->rx_csum;
+ bnad_unlock();
+ return rx_csum;
+}
+
+static int bnad_set_rx_csum(struct net_device *netdev, u32 rx_csum)
+{
+ struct bnad *bnad = netdev_priv(netdev);
+
+ bnad_lock();
+ bnad->rx_csum = rx_csum;
+ bnad_unlock();
+ return 0;
+}
+
+static int bnad_set_tx_csum(struct net_device *netdev, u32 tx_csum)
+{
+ if (tx_csum) {
+ netdev->features |= NETIF_F_IP_CSUM;
+#ifdef NETIF_F_IPV6_CSUM
+ netdev->features |= NETIF_F_IPV6_CSUM;
+#endif
+ } else {
+ netdev->features &= ~NETIF_F_IP_CSUM;
+#ifdef NETIF_F_IPV6_CSUM
+ netdev->features &= ~NETIF_F_IPV6_CSUM;
+#endif
+ }
+ return 0;
+}
+
+static int bnad_set_tso(struct net_device *netdev, u32 tso)
+{
+ if (tso) {
+ netdev->features |= NETIF_F_TSO;
+ netdev->features |= NETIF_F_TSO6;
+ } else {
+ netdev->features &= ~NETIF_F_TSO;
+ netdev->features &= ~NETIF_F_TSO6;
+ }
+ return 0;
+}
+
+
+static void bnad_get_strings(struct net_device *netdev, u32 stringset,
+ u8 *string)
+{
+ struct bnad *bnad = netdev_priv(netdev);
+ int i;
+ bnad_lock();
+ switch (stringset) {
+ case ETH_SS_STATS:
+ for (i = 0; i < BNAD_ETHTOOL_STATS_NUM; i++) {
+ BNA_ASSERT(strlen(bnad_net_stats_strings[i]) <
+ ETH_GSTRING_LEN);
+ memcpy(string, bnad_net_stats_strings[i],
+ ETH_GSTRING_LEN);
+ string += ETH_GSTRING_LEN;
+ }
+
+ i = 0;
+ sprintf(string, "rxf%d_ucast_octets", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "rxf%d_ucast", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "rxf%d_ucast_vlan", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "rxf%d_mcast_octets", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "rxf%d_mcast", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "rxf%d_mcast_vlan", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "rxf%d_bcast_octets", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "rxf%d_bcast", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "rxf%d_bcast_vlan", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "rxf%d_frame_drops", i);
+ string += ETH_GSTRING_LEN;
+
+ sprintf(string, "netif_queue_stopped");
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "bna_state");
+ string += ETH_GSTRING_LEN;
+
+ for (i = 0; i < bnad->cq_num; i++) {
+ sprintf(string, "cq%d_producer_index", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "cq%d_consumer_index", i);
+ string += ETH_GSTRING_LEN;
+ }
+
+ for (i = 0; i < bnad->rxq_num; i++) {
+ sprintf(string, "rxq%d_packets", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "rxq%d_bytes", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "rxq%d_packets_with_error", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "rxq%d_allocbuf_failed", i);
+ string += ETH_GSTRING_LEN;
+
+ sprintf(string, "rxq%d_producer_index", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "rxq%d_consumer_index", i);
+ string += ETH_GSTRING_LEN;
+
+ }
+
+ for (i = 0; i < bnad->txq_num; i++) {
+ sprintf(string, "txq%d_packets", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "txq%d_bytes", i);
+ string += ETH_GSTRING_LEN;
+
+ sprintf(string, "txq%d_producer_index", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "txq%d_consumer_index", i);
+ string += ETH_GSTRING_LEN;
+ sprintf(string, "txq%d_hw_consumer_index", i);
+ string += ETH_GSTRING_LEN;
+ }
+ break;
+
+ default:
+ break;
+ }
+ bnad_unlock();
+}
+
+
+static void bnad_get_ethtool_stats(struct net_device *netdev,
+ struct ethtool_stats *stats, u64 *buf)
+{
+ struct bnad *bnad = netdev_priv(netdev);
+ int i, bi, j;
+ unsigned long *net_stats;
+ u64 *stats64;
+
+ bi = 0;
+ bnad_get_stats(netdev);
+
+ net_stats = (unsigned long *)&bnad->net_stats;
+ for (i = 0; i < sizeof(struct net_device_stats) /
+ sizeof(unsigned long); i++)
+ buf[bi++] = net_stats[i];
+
+ stats64 = (u64 *)&bnad->stats;
+ for (i = 0; i < sizeof(struct bnad_drv_stats) / sizeof(u64);
+ i++)
+ buf[bi++] = stats64[i];
+
+ stats64 = (u64 *)bnad->hw_stats;
+ for (i = 0; i < offsetof(struct bna_stats, rxf_stats[0]) /
+ sizeof(u64); i++)
+ buf[bi++] = stats64[i];
+
+ stats64 = (u64 *)&bnad->hw_stats->txf_stats[0];
+ for (i = 0; i < sizeof(struct bna_stats_txf) / sizeof(u64); i++)
+ buf[bi++] = stats64[i];
+
+ j = 0;
+ stats64 = (u64 *)&bnad->hw_stats->rxf_stats[j];
+ for (i = 0; i < sizeof(struct bna_stats_rxf) /
+ sizeof(u64); i++)
+ buf[bi++] = stats64[i];
+
+ buf[bi++] = netif_queue_stopped(netdev);
+ buf[bi++] = bnad->state;
+
+ if (bnad->cq_table && bnad->rxq_table && bnad->txq_table) {
+ for (i = 0; i < bnad->cq_num; i++) {
+ buf[bi++] = bnad->cq_table[i].cq.q.producer_index;
+ buf[bi++] = bnad->cq_table[i].cq.q.consumer_index;
+ }
+
+ for (i = 0; i < bnad->rxq_num; i++) {
+ buf[bi++] = bnad->rxq_table[i].rx_packets;
+ buf[bi++] = bnad->rxq_table[i].rx_bytes;
+ buf[bi++] = bnad->rxq_table[i].rx_packets_with_error;
+ buf[bi++] = bnad->rxq_table[i].rxbuf_alloc_failed;
+
+ buf[bi++] = bnad->rxq_table[i].rxq.q.producer_index;
+ buf[bi++] = bnad->rxq_table[i].rxq.q.consumer_index;
+ }
+ for (i = 0; i < bnad->txq_num; i++) {
+ buf[bi++] = bnad->txq_table[i].tx_packets;
+ buf[bi++] = bnad->txq_table[i].tx_bytes;
+
+ buf[bi++] = bnad->txq_table[i].txq.q.producer_index;
+ buf[bi++] = bnad->txq_table[i].txq.q.consumer_index;
+ buf[bi++] = *(bnad->txq_table[i].hw_consumer_index);
+ }
+ }
+}
+
+
+
+static int
+bnad_get_sset_count(struct net_device *netdev, int stringset)
+{
+ struct bnad *bnad = netdev_priv(netdev);
+ int count;
+
+ switch (stringset) {
+ case ETH_SS_STATS:
+ bnad_lock();
+ count = BNAD_ETHTOOL_STATS_NUM + 10 + bnad->rxq_num * 4
+ + bnad->txq_num * 2;
+ count += 2;
+
+ /* CQ producer_index, consumer_index */
+ count += bnad->cq_num * 2;
+
+ /* RxQ producer_index, consumer_index */
+ count += bnad->rxq_num * 2;
+
+ /* TxQ producer_index, consumer_index, hw_consumer_index */
+ count += bnad->txq_num * 3;
+ bnad_unlock();
+ return count;
+ default:
+ return -EINVAL;
+ }
+}
+
+static struct ethtool_ops bnad_ethtool_ops = {
+ .get_settings = bnad_get_settings,
+ .set_settings = bnad_set_settings,
+ .get_drvinfo = bnad_get_drvinfo,
+ .get_regs_len = bnad_get_regs_len,
+ .get_regs = bnad_get_regs,
+ .get_wol = bnad_get_wol,
+ .get_msglevel = bnad_get_msglevel,
+ .set_msglevel = bnad_set_msglevel,
+ .get_link = ethtool_op_get_link,
+ .get_coalesce = bnad_get_coalesce,
+ .set_coalesce = bnad_set_coalesce,
+ .get_ringparam = bnad_get_ringparam,
+ .set_ringparam = bnad_set_ringparam,
+ .get_pauseparam = bnad_get_pauseparam,
+ .set_pauseparam = bnad_set_pauseparam,
+ .get_rx_csum = bnad_get_rx_csum,
+ .set_rx_csum = bnad_set_rx_csum,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = bnad_set_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = ethtool_op_set_sg,
+ .get_tso = ethtool_op_get_tso,
+ .set_tso = bnad_set_tso,
+ .get_flags = ethtool_op_get_flags,
+ .set_flags = ethtool_op_set_flags,
+ .get_strings = bnad_get_strings,
+ .get_ethtool_stats = bnad_get_ethtool_stats,
+ .get_sset_count = bnad_get_sset_count
+};
+
+void bnad_set_ethtool_ops(struct net_device *netdev)
+{
+ SET_ETHTOOL_OPS(netdev, &bnad_ethtool_ops);
+}
+
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists