Subject: Re: [PATCH 1/12] BE NIC driver - Header files and initialization functions

From: Stephen Hemminger <[email-masked]>
Date: Tue, 3 Jun 2008 10:16:56 -0700

Overall this part looks pretty good.

> Thanks to everyone who reviewed the previous two submissions of the NIC driver
> for BladeEngine (ServerEngines' 10Gb NIC) driver. I am submitting the driver
> with changes suggested in the last review.
> 
> BladeEngine is a dual function device with network and storage functions.
> This patch includes the network driver and beclib.
> beclib is a library of function that the driver uses to access the
> hardware.  It is common to both storage and network drivers and
> hence organized under the directory drivers/message/beclib. The
> storage driver is not part of this patch and will be submitted after
> this review.
> 
> This patch is made against the current git tree.
> 
> Thank you.
> Signed-off-by: Subbu Seetharaman <[email-masked]>
> ---
>  drivers/net/benet/be_init.c | 1135 +++++++++++++++++++++++++++++++++++++++++++
>  drivers/net/benet/benet.h   |  301 ++++++++++++
>  drivers/net/benet/bni.h     |  327 +++++++++++++
>  3 files changed, 1763 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/net/benet/be_init.c
>  create mode 100644 drivers/net/benet/benet.h
>  create mode 100644 drivers/net/benet/bni.h
> 
> diff --git a/drivers/net/benet/be_init.c b/drivers/net/benet/be_init.c
> new file mode 100644
> index 0000000..2eb9ce7
> --- /dev/null
> +++ b/drivers/net/benet/be_init.c
> @@ -0,0 +1,1135 @@
> +/*
> + * Copyright (C) 2005 - 2008 ServerEngines
> + * All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License version 2
> + * as published by the Free Software Foundation.  The full GNU General
> + * Public License is included in this distribution in the file called COPYING.
> + *
> + * Contact Information:
> + * [email-masked]
> + *
> + * ServerEngines
> + * 209 N. Fair Oaks Ave
> + * Sunnyvale, CA 94085
> + */
> +
> +#include <linux/pci.h>
> +#include <linux/etherdevice.h>
> +
> +#include "benet.h"
> +
> +#define  DRVR_VERSION  "1.0.688"
> +
> +static struct pci_device_id be_device_id_table[] = {
> +	{PCI_DEVICE(0x19a2, 0x0201)},
> +	{0}
> +};
> +
> +MODULE_DEVICE_TABLE(pci, be_device_id_table);
> +
> +MODULE_VERSION(DRVR_VERSION);
> +
> +#define DRV_DESCRIPTION "ServerEngines BladeEngine Network Driver Version "
> +
> +MODULE_DESCRIPTION(DRV_DESCRIPTION DRVR_VERSION);
> +MODULE_AUTHOR("ServerEngines");
> +MODULE_LICENSE("GPL");
> +
> +static unsigned int msix;	/* default - msix disabled */
> +module_param(msix, uint, S_IRUGO);
> +MODULE_PARM_DESC(msix, "Use MSI-x interrupts");

Why is msix off by default? hardware problem?

> +static unsigned int rxbuf_size = 2048;	/* Size of RX buffers */
> +module_param(rxbuf_size, uint, S_IRUGO);
> +MODULE_PARM_DESC(rxbuf_size, "Size of buffers to hold Rx data");
> +
> +const char be_drvr_ver[] = DRVR_VERSION;
> +char be_fw_ver[32];		/* F/W version filled in by be_probe */
> +char be_driver_name[] = "benet";
> +
> +/*
> + * Number of entries in each queue.
> + */
> +#define EVENT_Q_LEN		1024
> +#define ETH_TXQ_LEN		2048
> +#define ETH_TXCQ_LEN		1024
> +#define ETH_RXQ_LEN		1024	/* Does not support any other value */
> +#define ETH_UC_RXCQ_LEN		1024
> +#define ETH_BC_RXCQ_LEN		256
> +#define MCC_Q_LEN               64	/* total size not to exceed 8 pages */
> +#define MCC_CQ_LEN              256
> +
> +/*
> + * Intialize and register a network device for the pnob. Initialize to No Link.
> + * Link will be enabled during benet_open() or when physical Link is up
> + */
> +static int
> +be_netdev_init(struct be_adapter *adapter, struct bni_net_object *pnob)
> +{
> +	struct net_device *netdev = OSM_NOB(pnob)->netdev;
> +	int ret = 0;
> +
> +	bni_get_uc_mac_adrr(pnob, 0, 0, OSM_NOB(pnob)->devno,
> +		(u8 *)netdev->dev_addr, NULL, NULL);
> +
> +	netdev->init = &benet_probe;
> +	netif_carrier_off(netdev);
> +	netif_stop_queue(netdev);
> +
> +	SET_NETDEV_DEV(netdev, &(adapter->pdev->dev));
> +	ret = register_netdev(netdev);
> +	return ret;
> +}

Why not?
  return register_netdev(netdev);

> +/* Initialize the pci_info structure for this function */
> +static int
> +init_pci_be_function(struct be_adapter *adapter, struct pci_dev *pdev)
> +{
> +	adapter->num_bars = 3;
> +	/* CSR */
> +	adapter->pci_bars[0].base_pa = pci_resource_start(pdev, 2);
> +	adapter->pci_bars[0].base_va =
> +	    ioremap_nocache(adapter->pci_bars[0].base_pa,
> +			    pci_resource_len(pdev, 2));
> +	if (adapter->pci_bars[0].base_va == NULL)
> +		return -ENOMEM;
> +	adapter->pci_bars[0].length = sizeof(struct BLADE_ENGINE_CSRMAP_AMAP);
> +
> +	/* Door Bell */
> +	adapter->pci_bars[1].base_pa = pci_resource_start(pdev, 4);
> +	adapter->pci_bars[1].base_va =
> +	    ioremap_nocache(adapter->pci_bars[1].base_pa, (128 * 1024));
> +	if (adapter->pci_bars[1].base_va == NULL) {
> +		iounmap(adapter->pci_bars[0].base_va);
> +		return -ENOMEM;
> +	}
> +	adapter->pci_bars[1].length =
> +	    sizeof(struct PROTECTION_DOMAIN_DBMAP_AMAP);
> +
> +	/* PCI */
> +	adapter->pci_bars[2].base_pa = pci_resource_start(pdev, 1);
> +	adapter->pci_bars[2].length = pci_resource_len(pdev, 1);
> +	adapter->pci_bars[2].base_va =
> +	    ioremap_nocache(adapter->pci_bars[2].base_pa,
> +			    adapter->pci_bars[2].length);
> +	if (adapter->pci_bars[2].base_va == NULL) {
> +		iounmap(adapter->pci_bars[0].base_va);
> +		iounmap(adapter->pci_bars[1].base_va);
> +		return -ENOMEM;
> +	}
> +
> +
> +	return 0;
> +}
> +
> +/*
> + * Enable MSIx and return 1 if successful. Else return 0
> + */
> +static int be_enable_msix(struct be_adapter *adapter)
> +{
> +	unsigned int i, ret;
> +
> +	if (!msix)
> +		return 0;
> +
> +	adapter->msix_enabled = 1;
> +
> +	for (i = 0; i < BE_MAX_REQ_MSIX_VECTORS; i++)
> +		adapter->msix_entries[i].entry = i;
> +
> +	ret = pci_enable_msix(adapter->pdev,
> +			      adapter->msix_entries, BE_MAX_REQ_MSIX_VECTORS);
> +
> +	if (ret) {
> +		adapter->msix_enabled = 0;
> +		return 0;
> +	}
> +
> +	return 1;
> +}
> +
> +/*
> + * Registers ISR for BE. Uses MSIx interrupt if configured and requested.
> + * If not, uses INTx interrupt. Returns 0 for success and -1 for filure.
> + */
> +static int
> +be_register_isr(struct be_adapter *adapter, struct bni_net_object *pnob)
> +{
> +	int msix_intr, r;
> +	struct net_device *netdev = OSM_NOB(pnob)->netdev;
> +	u32 msix_ret = 0;
> +
> +	netdev->irq = adapter->pdev->irq;
> +
> +	msix_intr = 0;
> +	msix_ret = be_enable_msix(adapter);
> +	if (msix_ret) {
> +		r = request_irq(adapter->msix_entries[0].vector,
> +				be_int, IRQF_SHARED, netdev->name, netdev);
> +		if (r) {
> +			printk(KERN_WARNING
> +			       "MSIX Request IRQ failed - Errno %d\n", r);
> +		} else {
> +			msix_intr = 1;
> +		}
> +	}
> +	if (msix_intr == 0) {
> +		/* request legacy INTx interrupt */
> +		r = request_irq(netdev->irq, be_int, IRQF_SHARED,
> +				netdev->name, netdev);
> +		if (r) {
> +			printk(KERN_ERR
> +			       "INTx Request IRQ failed - Errno %d\n", r);
> +			return (-1);
> +		}
> +	}
> +	return (0);
> +}
> +
> +/*
> + * free all resources associated with a pnob
> + * Called at the time of module cleanup as well a any error during
> + * module init.  Some resources may be partially allocated in a NetObj.
> + */
> +static void netobject_cleanup(struct be_adapter *adapter,
> +			struct bni_net_object *pnob)
> +{
> +	struct net_device *netdev;
> +	struct sk_buff *skb;
> +	int i;
> +
> +	netdev = adapter->netdevp;
> +
> +	if (netif_running(netdev)) {
> +		netif_stop_queue(netdev);
> +		be_wait_nic_tx_cmplx_cmpl(pnob);
> +		bni_disable_eq_intr(pnob);
> +	}
> +
> +	if (adapter->isr_registered && adapter->msix_enabled)
> +		free_irq(adapter->msix_entries[0].vector, netdev);
> +	else if (adapter->isr_registered && !adapter->msix_enabled)
> +		free_irq(netdev->irq, netdev);
> +
> +	adapter->isr_registered = 0;
> +	if (adapter->msix_enabled) {
> +		pci_disable_msix(adapter->pdev);
> +		adapter->msix_enabled = 0;
> +	}
> +	if (adapter->tasklet_started) {
> +		tasklet_kill(&(adapter->sts_handler));
> +		adapter->tasklet_started = 0;
> +	}
> +	if (pnob->fn_obj_created)
> +		bni_disable_intr(pnob);
> +
> +	/* In cases of partial initialization, it's OK to call unregister
> +	 * even if netdev is not registered: handled in unregister_netdev()
> +	 */
> +	unregister_netdev(netdev);
> +
> +	if (pnob->fn_obj_created)
> +		bni_destroy_netobj(pnob, &adapter->sa_device);
> +
> +	adapter->net_obj = NULL;
> +	adapter->netdevp = NULL;
> +
> +	if (pnob->mcc_q)
> +		pci_free_consistent(adapter->pdev, pnob->mcc_q_size,
> +			pnob->mcc_q, pnob->mcc_q_bus);
> +
> +	if (pnob->mcc_wrb_ctxt)
> +		free_pages((unsigned long)pnob->mcc_wrb_ctxt,
> +			   get_order(pnob->mcc_wrb_ctxt_size));
> +
> +	if (pnob->mcc_cq)
> +		pci_free_consistent(adapter->pdev, pnob->mcc_cq_size,
> +			pnob->mcc_cq, pnob->mcc_cq_bus);
> +
> +	if (pnob->event_q)
> +		pci_free_consistent(adapter->pdev, pnob->event_q_size,
> +			pnob->event_q, pnob->event_q_bus);
> +
> +	if (pnob->tx_cq)
> +		pci_free_consistent(adapter->pdev, pnob->tx_cq_size,
> +			pnob->tx_cq, pnob->tx_cq_bus);
> +
> +	if (pnob->tx_q)
> +		pci_free_consistent(adapter->pdev, pnob->tx_q_size,
> +			pnob->tx_q, pnob->tx_q_bus);
> +
> +	if (pnob->bcrx_cq)
> +		pci_free_consistent(adapter->pdev, pnob->bcrx_cq_size,
> +			pnob->bcrx_cq, pnob->bcrx_cq_bus);
> +
> +	if (pnob->rx_q)
> +		pci_free_consistent(adapter->pdev, pnob->rx_q_size,
> +			pnob->rx_q, pnob->rx_q_bus);
> +
> +	if (pnob->ucrx_cq)
> +		pci_free_consistent(adapter->pdev, pnob->ucrx_cq_size,
> +			pnob->ucrx_cq, pnob->ucrx_cq_bus);
> +
> +	if (pnob->rx_ctxt) {
> +		struct be_rx_page_info *rx_page_info;
> +		for (i = 0; i < pnob->rx_q_len; i++) {
> +			rx_page_info = &(OSM_NOB(pnob)->rx_page_info[i]);
> +			if ((OSM_NOB(pnob)->rx_pg_shared == FALSE) ||
> +			    (rx_page_info->page_offset)) {
> +				pci_unmap_page(adapter->pdev,
> +					       pci_unmap_addr(rx_page_info,
> +							      bus),
> +					       pnob->rx_buf_size,
> +					       PCI_DMA_FROMDEVICE);
> +			}
> +			if (rx_page_info->page)
> +				put_page(rx_page_info->page);
> +			memset(rx_page_info, 0, sizeof(struct be_rx_page_info));
> +		}
> +		OSM_NOB(pnob)->rx_pg_info_hd = 0;
> +		kfree(OSM_NOB(pnob)->rx_page_info);
> +		kfree(pnob->rx_ctxt);
> +	}
> +
> +	if (pnob->tx_ctxt) {
> +		for (i = 0; i < pnob->tx_q_len; i++) {
> +			skb = (struct sk_buff *)pnob->tx_ctxt[i];
> +			if (skb)
> +				kfree_skb(skb);
> +		}
> +		kfree(pnob->tx_ctxt);
> +	}
> +
> +	if (pnob->mb_ptr)
> +		pci_free_consistent(adapter->pdev, pnob->mb_size, pnob->mb_ptr,
> +			pnob->mb_bus);
> +
> +	if (OSM_NOB(pnob))
> +		kfree(OSM_NOB(pnob));

Check for null not needed, kfree() handles it.

> +	free_netdev(netdev);
> +}
> +
> +static int be_nob_ring_create(struct be_adapter *adapter)
> +{
> +	struct bni_net_object *pnob = NULL;
> +	u32 size;
> +	struct net_device *netdev;
> +
> +	/* Allocate nob as a part of netdev */
> +	netdev = alloc_etherdev(sizeof(struct bni_net_object));
> +	if (netdev == NULL)
> +		return -ENOMEM;
> +	pnob = netdev->priv;
> +	memset(pnob, 0, sizeof(struct bni_net_object));

This memset is unnecessary, alloc_etherdev returns zeroed memory.

> +	adapter->net_obj = pnob;
> +	adapter->netdevp = netdev;
> +
> +	pnob->osm_netobj = (struct linux_net_object *)
> +	    kzalloc(sizeof(struct linux_net_object), GFP_KERNEL);
> +	if (pnob->osm_netobj == NULL)
> +		return -1;
> +	OSM_NOB(pnob)->devno = 0;
> +	OSM_NOB(pnob)->adapter = adapter;
> +	OSM_NOB(pnob)->netdev = netdev;
> +
> +	/* Mail box sgl; mailbox pointer needs to be 16 byte aligned */
> +	pnob->mb_size = sizeof(struct MCC_MAILBOX_AMAP) + 16;
> +	pnob->mb_ptr = pci_alloc_consistent(adapter->pdev, pnob->mb_size,
> +				&pnob->mb_bus);
> +	if (!pnob->mb_bus)
> +		return -1;
> +	memset(pnob->mb_ptr, 0, pnob->mb_size);
> +	sa_sgl_create_contiguous(PTR_ALIGN(pnob->mb_ptr, 16),
> +		PTR_ALIGN(pnob->mb_bus, 16), sizeof(struct MCC_MAILBOX_AMAP),
> +		&pnob->mb_sgl);
> +
> +	/*
> +	 * Event queue
> +	 */
> +	pnob->event_q_len = EVENT_Q_LEN;
> +	pnob->event_q_size = pnob->event_q_len * sizeof(struct EQ_ENTRY_AMAP);
> +	pnob->event_q = pci_alloc_consistent(adapter->pdev, pnob->event_q_size,
> +				&pnob->event_q_bus);
> +	if (!pnob->event_q_bus)
> +		return -1;
> +	/*
> +	 * Eth TX queue
> +	 */
> +	pnob->tx_q_len = ETH_TXQ_LEN;
> +	pnob->tx_q_port = 0;
> +	pnob->tx_q_size =  pnob->tx_q_len * sizeof(struct ETH_WRB_AMAP);
> +	pnob->tx_q = pci_alloc_consistent(adapter->pdev, pnob->tx_q_size,
> +				&pnob->tx_q_bus);
> +	if (!pnob->tx_q_bus)
> +		return -1;
> +	/*
> +	 * Eth TX Compl queue
> +	 */
> +	pnob->txcq_len = ETH_TXCQ_LEN;
> +	pnob->tx_cq_size = pnob->txcq_len * sizeof(struct ETH_TX_COMPL_AMAP);
> +	pnob->tx_cq = pci_alloc_consistent(adapter->pdev, pnob->tx_cq_size,
> +				&pnob->tx_cq_bus);
> +	if (!pnob->tx_cq_bus)
> +		return -1;
> +	/*
> +	 * Eth RX queue
> +	 */
> +	pnob->rx_q_len = ETH_RXQ_LEN;
> +	pnob->rx_q_size =  pnob->rx_q_len * sizeof(struct ETH_RX_D_AMAP);
> +	pnob->rx_q = pci_alloc_consistent(adapter->pdev, pnob->rx_q_size,
> +				&pnob->rx_q_bus);
> +	if (!pnob->rx_q_bus)
> +		return -1;
> +	/*
> +	 * Eth Unicast RX Compl queue
> +	 */
> +	pnob->ucrx_cq_len = ETH_UC_RXCQ_LEN;
> +	pnob->ucrx_cq_size =  pnob->ucrx_cq_len *
> +			sizeof(struct ETH_RX_COMPL_AMAP);
> +	pnob->ucrx_cq = pci_alloc_consistent(adapter->pdev, pnob->ucrx_cq_size,
> +				&pnob->ucrx_cq_bus);
> +	if (!pnob->ucrx_cq_bus)
> +		return -1;
> +	/*
> +	 * Eth Broadcast RX Compl queue
> +	 */
> +	pnob->bcrx_cq_len = ETH_BC_RXCQ_LEN;
> +	pnob->bcrx_cq_size = pnob->bcrx_cq_len *
> +			sizeof(struct ETH_RX_COMPL_AMAP);
> +	pnob->bcrx_cq = pci_alloc_consistent(adapter->pdev, pnob->bcrx_cq_size,
> +				&pnob->bcrx_cq_bus);
> +	if (!pnob->bcrx_cq_bus)
> +		return -1;
> +
> +	/* TX resources */
> +	size = pnob->tx_q_len * sizeof(void **);
> +	pnob->tx_ctxt = kmalloc(size, GFP_KERNEL);
> +	if (pnob->tx_ctxt == NULL)
> +		return -1;
> +
> +	/* RX resources */
> +	size = pnob->rx_q_len * sizeof(void *);
> +	pnob->rx_ctxt = kmalloc(size, GFP_KERNEL);
> +	if (pnob->rx_ctxt == NULL)
> +		return -1;
> +
> +	size = (pnob->rx_q_len * sizeof(struct be_rx_page_info));
> +	OSM_NOB(pnob)->rx_page_info = kzalloc(size, GFP_KERNEL);
> +	if (OSM_NOB(pnob)->rx_page_info == NULL)
> +		return -1;
> +
> +	adapter->eth_statsp = (struct FWCMD_ETH_GET_STATISTICS *)
> +	    kmalloc(sizeof(struct FWCMD_ETH_GET_STATISTICS), GFP_KERNEL);
> +	if (adapter->eth_statsp == NULL)
> +		return -1;
> +	pnob->rx_buf_size = rxbuf_size;
> +	adapter->dev_state = BE_DEV_STATE_NONE;
> +	return 0;
> +}
> +
> +static int be_nob_ring_init(struct be_adapter *adapter,
> +				struct bni_net_object *pnob)
> +{
> +	struct sa_dev_bar_locations pci_bars[3];
> +	int status;
> +
> +	memset(pnob->event_q, 0, pnob->event_q_size);
> +	pnob->event_q_tl = 0;
> +
> +	memset(pnob->tx_q, 0, pnob->tx_q_size);
> +	pnob->tx_q_hd = 0;
> +	pnob->tx_q_tl = 0;
> +
> +	memset(pnob->tx_cq, 0, pnob->tx_cq_size);
> +	pnob->tx_cq_tl = 0;
> +
> +	memset(pnob->rx_q, 0, pnob->rx_q_size);
> +
> +	memset(pnob->ucrx_cq, 0, pnob->ucrx_cq_size);
> +	pnob->ucrx_cq_tl = 0;
> +
> +	memset(pnob->bcrx_cq, 0, pnob->bcrx_cq_size);
> +	pnob->bcrx_cq_tl = 0;
> +
> +	memset(pnob->tx_ctxt, 0, pnob->tx_q_len * sizeof(void **));
> +	memset(pnob->rx_ctxt, 0, pnob->rx_q_len * sizeof(void *));
> +	memset(OSM_NOB(pnob)->rx_page_info, 0,
> +	       pnob->rx_q_len * sizeof(struct be_rx_page_info));
> +	OSM_NOB(pnob)->rx_pg_info_hd = 0;
> +	pnob->rx_q_hd = 0;
> +	atomic_set(&pnob->rx_q_posted, 0);
> +
> +	memcpy(pci_bars, adapter->pci_bars, sizeof(adapter->pci_bars));
> +	status = bni_create_netobj(pnob, pci_bars, adapter->num_bars,
> +				   &adapter->sa_device, &adapter->chip_object);
> +	if (status != BE_SUCCESS)
> +		return -1;
> +
> +	be_post_eth_rx_buffs(pnob);
> +	return 0;
> +}
> +
> +/* This function handles async callback for link status */
> +static void
> +be_link_status_async_callback(void *context, u32 event_code, void *event)
> +{
> +	struct ASYNC_EVENT_LINK_STATE_AMAP *link_status = event;
> +	struct be_adapter *adapter = context;
> +	bool link_enable = FALSE;
> +	struct bni_net_object *pnob;
> +	struct ASYNC_EVENT_TRAILER_AMAP *async_trailer;
> +	struct net_device *netdev;
> +	u32 async_event_code, async_event_type, active_port;
> +	u32 port0_link_status, port1_link_status, port0_duplex, port1_duplex;
> +	u32 port0_speed, port1_speed;
> +
> +	if (event_code != ASYNC_EVENT_CODE_LINK_STATE) {
> +		/* Not our event to handle */
> +		return;
> +	}
> +	async_trailer = (struct ASYNC_EVENT_TRAILER_AMAP *)
> +	    ((u8 *) event + sizeof(struct MCC_CQ_ENTRY_AMAP) -
> +	     sizeof(struct ASYNC_EVENT_TRAILER_AMAP));
> +
> +	async_event_code = AMAP_GET_BITS_PTR(ASYNC_EVENT_TRAILER, event_code,
> +					     async_trailer);
> +	BUG_ON(async_event_code != ASYNC_EVENT_CODE_LINK_STATE);
> +
> +	pnob = adapter->net_obj;
> +	netdev = OSM_NOB(pnob)->netdev;
> +
> +	/* Determine if this event is a switch VLD or a physical link event */
> +	async_event_type = AMAP_GET_BITS_PTR(ASYNC_EVENT_TRAILER, event_type,
> +					     async_trailer);
> +	active_port = AMAP_GET_BITS_PTR(ASYNC_EVENT_LINK_STATE,
> +					active_port, link_status);
> +	port0_link_status = AMAP_GET_BITS_PTR(ASYNC_EVENT_LINK_STATE,
> +					      port0_link_status, link_status);
> +	port1_link_status = AMAP_GET_BITS_PTR(ASYNC_EVENT_LINK_STATE,
> +					      port1_link_status, link_status);
> +	port0_duplex = AMAP_GET_BITS_PTR(ASYNC_EVENT_LINK_STATE,
> +					 port0_duplex, link_status);
> +	port1_duplex = AMAP_GET_BITS_PTR(ASYNC_EVENT_LINK_STATE,
> +					 port1_duplex, link_status);
> +	port0_speed = AMAP_GET_BITS_PTR(ASYNC_EVENT_LINK_STATE,
> +					port0_speed, link_status);
> +	port1_speed = AMAP_GET_BITS_PTR(ASYNC_EVENT_LINK_STATE,
> +					port1_speed, link_status);
> +	if (async_event_type == NTWK_LINK_TYPE_VIRTUAL) {
> +		adapter->be_stat.bes_link_change_virtual++;
> +		if (adapter->be_link_sts->active_port != active_port) {
> +			dev_notice(&netdev->dev,
> +			       "Active port changed due to VLD on switch\n");
> +		} else {
> +			dev_notice(&netdev->dev, "Link status update\n");
> +		}
> +
> +	} else {
> +		adapter->be_stat.bes_link_change_physical++;
> +		if (adapter->be_link_sts->active_port != active_port) {
> +			dev_notice(&netdev->dev,
> +			       "Active port changed due to port link"
> +			       " status change\n");
> +		} else {
> +			dev_notice(&netdev->dev, "Link status update\n");
> +		}
> +	}
> +
> +	memset(adapter->be_link_sts, 0, sizeof(adapter->be_link_sts));
> +
> +	if ((port0_link_status == ASYNC_EVENT_LINK_UP) ||
> +	    (port1_link_status == ASYNC_EVENT_LINK_UP)) {
> +		if ((adapter->port0_link_sts == BE_PORT_LINK_DOWN) &&
> +		    (adapter->port1_link_sts == BE_PORT_LINK_DOWN)) {
> +			/* Earlier both the ports are down So link is up */
> +			link_enable = TRUE;
> +		}
> +
> +		if (port0_link_status == ASYNC_EVENT_LINK_UP) {
> +			adapter->port0_link_sts = BE_PORT_LINK_UP;
> +			adapter->be_link_sts->mac0_duplex = port0_duplex;
> +			adapter->be_link_sts->mac0_speed = port0_speed;
> +			if (active_port == NTWK_PORT_A)
> +				adapter->be_link_sts->active_port = 0;
> +		} else
> +			adapter->port0_link_sts = BE_PORT_LINK_DOWN;
> +
> +		if (port1_link_status == ASYNC_EVENT_LINK_UP) {
> +			adapter->port1_link_sts = BE_PORT_LINK_UP;
> +			adapter->be_link_sts->mac1_duplex = port1_duplex;
> +			adapter->be_link_sts->mac1_speed = port1_speed;
> +			if (active_port == NTWK_PORT_B)
> +				adapter->be_link_sts->active_port = 1;
> +		} else
> +			adapter->port1_link_sts = BE_PORT_LINK_DOWN;
> +
> +		printk(KERN_INFO "Link Properties for %s:\n", netdev->name);
> +		be_print_link_info(adapter->be_link_sts);
> +
> +		if (!link_enable)
> +			return;
> +		/*
> +		 * Both ports were down previously, but atleast one of
> +		 * them has come up if this netdevice's carrier is not up,
> +		 * then indicate to stack
> +		 */
> +		if (!netif_carrier_ok(netdev)) {
> +			netif_start_queue(netdev);
> +			netif_carrier_on(netdev);
> +		}
> +		return;
> +	}
> +
> +	/* Now both the ports are down. Tell the stack about it */
> +	dev_info(&netdev->dev, "Both ports are down\n");
> +	adapter->port0_link_sts = BE_PORT_LINK_DOWN;
> +	adapter->port1_link_sts = BE_PORT_LINK_DOWN;
> +	if (netif_carrier_ok(netdev)) {
> +		netif_carrier_off(netdev);
> +		netif_stop_queue(netdev);
> +	}
> +	return;
> +}
> +
> +static int be_mcc_create(struct be_adapter *adapter)
> +{
> +	struct bni_net_object *pnob;
> +
> +	pnob = adapter->net_obj;
> +	/*
> +	 * Create the MCC ring so that all further communication with
> +	 * MCC can go thru the ring. we do this at the end since
> +	 * we do not want to be dealing with interrupts until the
> +	 * initialization is complete.
> +	 */
> +	pnob->mcc_q_len = MCC_Q_LEN;
> +	pnob->mcc_q_size = pnob->mcc_q_len * sizeof(struct MCC_WRB_AMAP);
> +	pnob->mcc_q =  pci_alloc_consistent(adapter->pdev, pnob->mcc_q_size,
> +				&pnob->mcc_q_bus);
> +	if (!pnob->mcc_q_bus)
> +		return -1;
> +	/*
> +	 * space for MCC WRB context
> +	 */
> +	pnob->mcc_wrb_ctxtLen = MCC_Q_LEN;
> +	pnob->mcc_wrb_ctxt_size =  pnob->mcc_wrb_ctxtLen *
> +		sizeof(struct be_mcc_wrb_context);
> +	pnob->mcc_wrb_ctxt = (void *)__get_free_pages(GFP_KERNEL,
> +		get_order(pnob->mcc_wrb_ctxt_size));
> +	if (pnob->mcc_wrb_ctxt == NULL)
> +		return -1;
> +	/*
> +	 * Space for MCC compl. ring
> +	 */
> +	pnob->mcc_cq_len = MCC_CQ_LEN;
> +	pnob->mcc_cq_size = pnob->mcc_cq_len * sizeof(struct MCC_CQ_ENTRY_AMAP);
> +	pnob->mcc_cq = pci_alloc_consistent(adapter->pdev, pnob->mcc_cq_size,
> +				&pnob->mcc_cq_bus);
> +	if (!pnob->mcc_cq_bus)
> +		return -1;
> +	return 0;
> +}
> +
> +static int be_mcc_init(struct be_adapter *adapter)
> +{
> +	u32 r;
> +	struct bni_net_object *pnob;
> +
> +	pnob = adapter->net_obj;
> +	memset(pnob->mcc_q, 0, pnob->mcc_q_size);
> +	pnob->mcc_q_hd = 0;
> +
> +	memset(pnob->mcc_wrb_ctxt, 0, pnob->mcc_wrb_ctxt_size);
> +
> +	memset(pnob->mcc_cq, 0, pnob->mcc_cq_size);
> +	pnob->mcc_cq_tl = 0;
> +
> +	r = bni_create_mcc_rings(adapter->net_obj);
> +	if (r != BE_SUCCESS)
> +		return -1;
> +
> +	return 0;
> +}
> +
> +static void be_remove(struct pci_dev *pdev)
> +{
> +	struct bni_net_object *pnob;
> +	struct be_adapter *adapter;
> +	int i;
> +
> +	adapter = pci_get_drvdata(pdev);
> +	if (!adapter)
> +		return;
> +
> +	pci_set_drvdata(pdev, 0);
> +	pnob = (struct bni_net_object *)adapter->net_obj;
> +
> +	flush_scheduled_work();
> +
> +	if (pnob) {
> +		/* Unregister async callback function for link status updates */
> +		if (pnob->mcc_q_created)
> +			be_mcc_add_async_event_callback(
> +					&pnob->mcc_q_obj, NULL, NULL);
> +
> +		netobject_cleanup(adapter, pnob);
> +	}
> +
> +	bni_cleanup(&adapter->chip_object);
> +
> +	for (i = 0; i < adapter->num_bars; i++) {
> +		if (adapter->pci_bars[i].base_va)
> +			iounmap(adapter->pci_bars[i].base_va);
> +	}
> +	pci_release_regions(adapter->pdev);
> +	pci_disable_device(adapter->pdev);
> +
> +	if (adapter->be_link_sts)
> +		kfree(adapter->be_link_sts);

Another case where if() check is unneeded for kfree.

> +	if (adapter->eth_statsp)
> +		kfree(adapter->eth_statsp);
> +
> +	if (adapter->timer_ctxt.get_stats_timer.function)
> +		del_timer_sync(&adapter->timer_ctxt.get_stats_timer);
> +	kfree(adapter);
> +}
> +
> +/*
> + * This function is called by the PCI sub-system when it finds a PCI
> + * device with dev/vendor IDs that match with one of our devices.
> + * All of the driver initialization is done in this function.
> + */
> +static int be_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id)
> +{
> +	int status = 0;
> +	struct be_adapter *adapter = NULL;
> +	struct FWCMD_COMMON_GET_FW_VERSION_RESPONSE_PAYLOAD get_fwv;
> +	struct bni_net_object *pnob = NULL;
> +	struct linux_net_object *lno;
> +
> +	status = pci_enable_device(pdev);
> +	if (status) {
> +		dev_err(&pdev->dev, "pci_enable_device() failed");
> +		goto error;
> +	}
> +
> +	status = pci_request_regions(pdev, be_driver_name);
> +	if (status) {
> +		pci_disable_device(pdev);
> +		goto error;
> +	}
> +
> +	pci_set_master(pdev);
> +	adapter = kzalloc(sizeof(struct be_adapter), GFP_KERNEL);
> +	if (adapter == NULL) {
> +		pci_release_regions(pdev);
> +		pci_disable_device(pdev);
> +		status = -ENOMEM;
> +		goto error;
> +	}
> +
> +	pci_set_drvdata(pdev, adapter);
> +	adapter->pdev = pdev;
> +
> +	/* Adapative interrupt coalescing limits in usecs.
> +	 * should be a multiple of 8.
> +	 */
> +	adapter->enable_aic = 1;
> +	adapter->max_eqd = MAX_EQD;
> +	adapter->min_eqd = 0;
> +	adapter->cur_eqd = 0;
> +	status = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
> +	if (!status) {
> +		/* Device is DAC Capable.  */
> +		adapter->dma_64bit_cap = TRUE;
> +	} else {
> +		adapter->dma_64bit_cap = FALSE;
> +		status = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
> +		if (status != 0) {
> +			printk(KERN_ERR "Could not set PCI DMA Mask\n");
> +			goto cleanup;
> +		}
> +	}
> +
> +	status = init_pci_be_function(adapter, pdev);
> +	if (status != 0) {
> +		printk(KERN_ERR "Failed to map PCI BARS\n");
> +		status = -ENOMEM;
> +		goto cleanup;
> +	}
> +
> +	sa_trace_set_level(DL_ALWAYS | DL_ERR);
> +
> +	status = bni_init(&adapter->chip_object);
> +	if (status != 0) {
> +		printk(KERN_ERR "bni_init() failed - Error %d\n", status);
> +		goto cleanup;
> +	}
> +
> +	adapter->be_link_sts = (struct BE_LINK_STATUS *)
> +	    kmalloc(sizeof(struct BE_LINK_STATUS), GFP_KERNEL);
> +	if (adapter->be_link_sts == NULL) {
> +		printk(KERN_ERR "Memory allocation for link status "
> +		       "buffer failed\n");
> +		goto cleanup;
> +	}
> +	spin_lock_init(&adapter->txq_lock);
> +
> +	status = be_nob_ring_create(adapter);
> +	if (status != 0)
> +		goto cleanup;
> +	pnob = adapter->net_obj;
> +	lno = OSM_NOB(pnob);
> +
> +	status = be_nob_ring_init(adapter, pnob);
> +	if (status != 0)
> +		goto cleanup;
> +
> +	status = be_netdev_init(adapter, pnob);
> +	if (status != 0)
> +		goto cleanup;
> +
> +#ifdef CONFIG_BENET_NAPI

Just do NAPI, having a configuration option means more possible
test cases and distributions only ship one binary anyway.

> +	netif_napi_add(lno->netdev, &lno->napi, be_poll, 64);
> +	lno->rx_sched = FALSE;
> +	spin_lock_init(&lno->rx_lock);

You should not need this lock, if:
  1) you use NAPI properly,
  2) you get rid of the unnecessary state flags like rx_sched etc..

> +#endif

> +
> +	/* if the rx_frag size if 2K, one page is shared as two RX frags */
> +	lno->rx_pg_shared = (pnob->rx_buf_size <= PAGE_SIZE / 2)? TRUE : FALSE;
> +	if (pnob->rx_buf_size != rxbuf_size) {
> +		printk(KERN_WARNING
> +		       "Could not set Rx buffer size to %d. Using %d\n",
> +		       rxbuf_size, pnob->rx_buf_size);
> +		rxbuf_size = pnob->rx_buf_size;
> +	}
> +
> +	tasklet_init(&(adapter->sts_handler), be_process_intr,
> +		     (unsigned long)adapter);
> +	adapter->tasklet_started = 1;

Do you need a tasklet if using NAPI? That would 

> +	spin_lock_init(&(adapter->int_lock));
> +
> +	status = be_register_isr(adapter, pnob);
> +	if (status != 0)
> +		goto cleanup;
> +
> +	adapter->isr_registered = 1;
> +	adapter->rx_csum = 1;
> +	adapter->max_rx_coal = BE_LRO_MAX_PKTS;
> +
> +	memset(&get_fwv, 0,
> +	       sizeof(struct FWCMD_COMMON_GET_FW_VERSION_RESPONSE_PAYLOAD));
> +	printk(KERN_INFO "BladeEngine Driver version:%s. "
> +	       "Copyright ServerEngines, Corporation 2005 - 2008\n",
> +	       be_drvr_ver);
> +	status = be_function_get_fw_version(&pnob->fn_obj, &get_fwv, NULL,
> +					    NULL);
> +	if (status == BE_SUCCESS) {
> +		strncpy(be_fw_ver, get_fwv.firmware_version_string, 32);
> +		printk(KERN_INFO "BladeEngine Firmware Version:%s\n",
> +		       get_fwv.firmware_version_string);
> +	} else {
> +		printk(KERN_WARNING "Unable to get BE Firmware Version\n");
> +	}
> +
> +	sema_init(&adapter->get_eth_stat_sem, 0);
> +
> +	init_timer(&adapter->timer_ctxt.get_stats_timer);
> +	atomic_set(&adapter->timer_ctxt.get_stat_flag, 0);
> +	adapter->timer_ctxt.get_stats_timer.function =
> +	    &be_get_stats_timer_handler;
> +
> +	status = be_mcc_create(adapter);
> +	if (status < 0)
> +		goto cleanup;
> +	status = be_mcc_init(adapter);
> +	if (status < 0)
> +		goto cleanup;
> +
> +	be_update_link_status(adapter);
> +
> +	/* Register async call back function to handle link status updates */
> +	status = be_mcc_add_async_event_callback(&adapter->net_obj->mcc_q_obj,
> +						 be_link_status_async_callback,
> +						 (void *)adapter);
> +	if (status != BE_SUCCESS) {
> +		printk(KERN_WARNING "add_async_event_callback failed");
> +		printk(KERN_WARNING
> +		       "Link status changes may not be reflected\n");
> +	}
> +
> +	bni_enable_intr(adapter->net_obj);
> +	bni_enable_eq_intr(adapter->net_obj);
> +	adapter->dev_state = BE_DEV_STATE_INIT;
> +	return 0;
> +
> +cleanup:
> +	be_remove(pdev);
> +
> +error:
> +	printk(KERN_ERR "BladeEngine initalization failed\n");
> +	return status;
> +}
> +
> +/*
> + * Get the current link status and print the status on console
> + */
> +void be_update_link_status(struct be_adapter *adapter)
> +{
> +	int status;
> +	struct bni_net_object *pnob = adapter->net_obj;
> +
> +	status = bni_get_link_sts(pnob, adapter->be_link_sts, NULL, NULL);
> +
> +	if (status == BE_SUCCESS) {
> +		if (adapter->be_link_sts->mac0_speed &&
> +		    adapter->be_link_sts->mac0_duplex)
> +			adapter->port0_link_sts = BE_PORT_LINK_UP;
> +		else
> +			adapter->port0_link_sts = BE_PORT_LINK_DOWN;
> +
> +		if (adapter->be_link_sts->mac1_speed &&
> +		    adapter->be_link_sts->mac1_duplex)
> +			adapter->port1_link_sts = BE_PORT_LINK_UP;
> +		else
> +			adapter->port1_link_sts = BE_PORT_LINK_DOWN;
> +
> +		printk(KERN_INFO "Link Properties for %s:\n",
> +		       OSM_NOB(pnob)->netdev->name);
> +		be_print_link_info(adapter->be_link_sts);
> +		return;
> +	}
> +	printk(KERN_WARNING "Could not get link status for %s\n",
> +	       OSM_NOB(pnob)->netdev->name);
> +	return;
> +}
> +
> +#ifdef CONFIG_PM
> +static void
> +be_pm_cleanup(struct be_adapter *adapter,
> +	      struct bni_net_object *pnob, struct net_device *netdev)
> +{
> +	u32 i;
> +
> +	netif_carrier_off(netdev);
> +	netif_stop_queue(netdev);
> +
> +	be_wait_nic_tx_cmplx_cmpl(pnob);
> +	bni_disable_eq_intr(pnob);
> +
> +	if (adapter->tasklet_started) {
> +		tasklet_kill(&adapter->sts_handler);
> +		adapter->tasklet_started = 0;
> +	}
> +
> +	if (adapter->msix_enabled) {
> +		if (adapter->isr_registered) {
> +			free_irq(adapter->msix_entries[0].vector, netdev);
> +			adapter->tasklet_started = 0;
> +			adapter->isr_registered = 0;
> +		}
> +	}
> +
> +	if (adapter->isr_registered) {
> +		/* This is an INTX Interrupt */
> +		free_irq(netdev->irq, netdev);
> +		adapter->isr_registered = 0;
> +	}
> +
> +	bni_disable_intr(pnob);
> +	bni_destroy_netobj(pnob, &adapter->sa_device);
> +
> +	if (pnob->rx_ctxt) {
> +		struct be_rx_page_info *rx_page_info;
> +
> +		/*
> +		 * go through RX context array and free
> +		 * data buffs
> +		 */
> +		for (i = 0; i < pnob->rx_q_len; i++) {
> +			rx_page_info = &(OSM_NOB(pnob)->rx_page_info[i]);
> +			if ((OSM_NOB(pnob)->rx_pg_shared == FALSE) ||
> +			    (rx_page_info->page_offset))
> +				pci_unmap_page(adapter->pdev,
> +					       pci_unmap_addr(rx_page_info,
> +							      bus),
> +					       pnob->rx_buf_size,
> +					       PCI_DMA_FROMDEVICE);
> +			if (rx_page_info->page)
> +				put_page(rx_page_info->page);
> +			memset(rx_page_info, 0, sizeof(struct be_rx_page_info));
> +		}
> +		OSM_NOB(pnob)->rx_pg_info_hd = 0;
> +	}
> +
> +}
> +static int be_suspend(struct pci_dev *pdev, pm_message_t state)
> +{
> +	struct be_adapter *adapter = pci_get_drvdata(pdev);
> +	struct net_device *netdev =  adapter->netdevp;
> +	struct bni_net_object *pnob = (struct bni_net_object *)netdev->priv;
> +
> +	adapter->dev_pm_state = adapter->dev_state;
> +	adapter->dev_state = BE_DEV_STATE_SUSPEND;
> +
> +	netif_device_detach(netdev);
> +	netif_device_detach(netdev);
> +	if (netif_running(netdev))
> +		be_pm_cleanup(adapter, pnob, netdev);
> +
> +	pci_enable_wake(pdev, 3, 1);
> +	pci_enable_wake(pdev, 4, 1);	/* D3 Cold = 4 */
> +	pci_save_state(pdev);
> +	pci_disable_device(pdev);
> +	pci_set_power_state(pdev, pci_choose_state(pdev, state));
> +	return 0;
> +}
> +
> +static void be_up(struct be_adapter *adapter)
> +{
> +	struct bni_net_object *pnob = adapter->net_obj;
> +
> +	if (OSM_NOB(pnob)->num_vlans != 0)
> +		bni_config_vlan(pnob, OSM_NOB(pnob)->vlan_tag,
> +				OSM_NOB(pnob)->num_vlans, NULL, NULL, 0);
> +
> +}
> +static int be_resume(struct pci_dev *pdev)
> +{
> +	int status = 0;
> +	struct be_adapter *adapter = pci_get_drvdata(pdev);
> +	struct net_device *netdev =  adapter->netdevp;
> +	struct bni_net_object *pnob = (struct bni_net_object *)netdev->priv;
> +
> +	netif_device_detach(netdev);
> +
> +	status = pci_enable_device(pdev);
> +	if (status)
> +		return status;
> +
> +	pci_set_power_state(pdev, 0);
> +	pci_restore_state(pdev);
> +	pci_enable_wake(pdev, 3, 0);
> +	pci_enable_wake(pdev, 4, 0);	/* 4 is D3 cold */
> +
> +	netif_carrier_on(netdev);
> +	netif_start_queue(netdev);
> +
> +	if (netif_running(netdev)) {
> +		status = be_nob_ring_init(adapter, pnob);
> +		if (status < 0)
> +			return (status);
> +
> +		bni_set_uc_mac_adr(pnob, 0, 0, 0,
> +			(u8 *)netdev->dev_addr, NULL, NULL);
> +
> +		tasklet_init(&(adapter->sts_handler), be_process_intr,
> +			     (unsigned long)adapter);
> +		adapter->tasklet_started = 1;	/* indication to cleanup */
> +
> +		if (be_register_isr(adapter, pnob) != 0) {
> +			printk(KERN_ERR "be_register_isr failed\n");
> +			return (status);
> +		}
> +
> +		adapter->isr_registered = 1;
> +
> +		status = be_mcc_init(adapter);
> +		if (status < 0) {
> +			printk(KERN_ERR "be_mcc_init failed\n");
> +			return (status);
> +		}
> +		be_update_link_status(adapter);
> +		/*
> +		 * Register async call back function to handle link
> +		 * status updates
> +		 */
> +		status = be_mcc_add_async_event_callback(
> +				&adapter->net_obj->mcc_q_obj,
> +				be_link_status_async_callback, (void *)adapter);
> +		if (status != BE_SUCCESS) {
> +			printk(KERN_WARNING "add_async_event_callback failed");
> +			printk(KERN_WARNING
> +			       "Link status changes may not be reflected\n");
> +		}
> +		bni_enable_intr(pnob);
> +		bni_enable_eq_intr(pnob);
> +		be_up(adapter);
> +	}
> +	netif_device_attach(netdev);
> +	adapter->dev_state = adapter->dev_pm_state;
> +	return 0;
> +
> +}
> +
> +#endif
> +
> +/* Wait until no more pending transmits  */
> +void be_wait_nic_tx_cmplx_cmpl(struct bni_net_object *pnob)
> +{
> +	int i;
> +
> +	/* Wait for 20us * 50000 (= 1s) and no more */
> +	i = 0;
> +	while ((pnob->tx_q_tl != pnob->tx_q_hd) && (i < 50000)) {
> +		++i;
> +		udelay(20);
> +	}
> +
> +	/* Check for no more pending transmits */
> +	if (i >= 50000) {
> +		printk(KERN_WARNING
> +		       "Did not receive completions for all TX requests\n");
> +	}
> +}
> +
> +static struct pci_driver be_driver = {
> +	.name = be_driver_name,
> +	.id_table = be_device_id_table,
> +	.probe = be_probe,
> +#ifdef CONFIG_PM
> +	.suspend = be_suspend,
> +	.resume = be_resume,
> +#endif
> +	.remove = be_remove
> +};
> +
> +/*
> + * Module init entry point. Registers our our device and return.
> + * Our probe will be called if the device is found.
> + */
> +
> +static int __init be_init_module(void)
> +{
> +	int ret;
> +
> +	if ((rxbuf_size != 8192) && (rxbuf_size != 4096)
> +	    && (rxbuf_size != 2048)) {
> +		printk(KERN_WARNING
> +		       "Unsupported receive buffer size (%d) requested\n",
> +		       rxbuf_size);
> +		printk(KERN_WARNING
> +		       "Must be 2048, 4096 or 8192. Defaulting to 2048\n");
> +		rxbuf_size = 2048;
> +	}
> +
> +	ret = pci_register_driver(&be_driver);
> +
> +	return ret;
> +}
> +
> +module_init(be_init_module);
> +
> +/*
> + * be_exit_module - Driver Exit Cleanup Routine
> + */
> +static void __exit be_exit_module(void)
> +{
> +	pci_unregister_driver(&be_driver);
> +}
> +
> +module_exit(be_exit_module);
> diff --git a/drivers/net/benet/benet.h b/drivers/net/benet/benet.h
> new file mode 100644
> index 0000000..2174dfa
> --- /dev/null
> +++ b/drivers/net/benet/benet.h
> @@ -0,0 +1,301 @@
> +/*
> + * Copyright (C) 2005 - 2008 ServerEngines
> + * All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License version 2
> + * as published by the Free Software Foundation.  The full GNU General
> + * Public License is included in this distribution in the file called COPYING.
> + *
> + * Contact Information:
> + * [email-masked]
> + *
> + * ServerEngines
> + * 209 N. Fair Oaks Ave
> + * Sunnyvale, CA 94085
> + */
> +#ifndef _BENET_H_
> +#define _BENET_H_
> +
> +#include <linux/netdevice.h>
> +#include <linux/inet_lro.h>
> +#include "bni.h"
> +
> +#define BE_MAX_MTU	8974
> +
> +#define BE_MAX_LRO_DESCRIPTORS			8
> +#define BE_LRO_MAX_PKTS				64
> +#define BE_MAX_FRAGS_PER_FRAME			6
> +
> +extern const char be_drvr_ver[];
> +extern char be_fw_ver[];
> +extern char be_driver_name[];
> +
> +extern struct ethtool_ops be_ethtool_ops;
> +
> +
> +#define BE_DEV_STATE_NONE 0
> +#define BE_DEV_STATE_INIT 1
> +#define BE_DEV_STATE_OPEN 2
> +#define BE_DEV_STATE_SUSPEND 3
> +
> +/*
> + * BE driver statistics.
> + */
> +struct be_drvr_stat {
> +	u32 bes_tx_reqs;	/* number of TX requests initiated */
> +	u32 bes_tx_fails;	/* number of TX requests that failed */
> +	u32 bes_fwd_reqs;	/* number of send reqs through forwarding i/f */
> +	u32 bes_tx_wrbs;	/* number of tx WRBs used */
> +
> +	u32 bes_ints;		/* number of interrupts */
> +	u32 bes_polls;		/* number of times NAPI called poll function */
> +	u32 bes_events;		/* total evet entries processed */
> +	u32 bes_tx_events;	/* number of tx completion events  */
> +	u32 bes_ucrx_events;	/* number of ucast rx completion events  */
> +	u32 bes_bcrx_events;	/* number of bcast rx completion events  */
> +	u32 bes_tx_compl;	/* number of tx completion entries processed */
> +	u32 bes_ucrx_compl;	/* number of ucrx completion entries
> +				   processed */
> +	u32 bes_bcrx_compl;	/* number of bcrx completion entries
> +				   processed */
> +	u32 bes_ethrx_post_fail;	/* number of ethrx buffer alloc
> +					   failures */
> +	/*
> +	 * number of non ether type II frames dropped where
> +	 * frame len > length field of Mac Hdr
> +	 */
> +	u32 bes_802_3_dropped_frames;
> +	/*
> +	 * number of non ether type II frames malformed where
> +	 * in frame len < length field of Mac Hdr
> +	 */
> +	u32 bes_802_3_malformed_frames;
> +	u32 bes_ips;		/*  interrupts / sec */
> +	u32 bes_prev_ints;	/* bes_ints at last IPS calculation  */
> +	u16 bes_eth_tx_rate;	/*  ETH TX rate - Mb/sec */
> +	u16 bes_eth_rx_rate;	/*  ETH RX rate - Mb/sec */
> +	u32 bes_rx_coal;	/* Num pkts coalasced */
> +	u32 bes_rx_flush;	/* Num times coalasced */
> +	u32 bes_link_change_physical;	/*Num of times physical link changed */
> +	u32 bes_link_change_virtual;	/*Num of times virtual link changed */
> +	u32 bes_rx_misc_pkts;	/* Misc pkts received */
> +};
> +
> +/* Maximum interrupt delay (in microseconds) allowed */
> +#define MAX_EQD				120
> +
> +/*
> + * timer to prevent system shutdown hang for ever if h/w stops responding
> + */
> +struct be_timer_ctxt {
> +	atomic_t get_stat_flag;
> +	struct timer_list get_stats_timer;
> +	unsigned long get_stat_sem_addr;
> +} ;
> +
> +/* This structure is the main BladeEngine driver context.  */
> +struct be_adapter {
> +	struct net_device *netdevp;
> +	struct be_drvr_stat be_stat;
> +	struct net_device_stats benet_stats;
> +	u32 num_bars;
> +	struct sa_dev_bar_locations pci_bars[3];	/* PCI BAR details */
> +	struct sa_dev sa_device;	/* device object owned by beclib */
> +	struct be_chip_object chip_object;	/* BEClib chip object  */
> +
> +	struct tasklet_struct sts_handler;
> +	struct timer_list cq_timer;
> +	spinlock_t int_lock;
> +
> +	struct FWCMD_ETH_GET_STATISTICS *eth_statsp;
> +	/*
> +	 * This will enable the use of ethtool to enable or disable
> +	 * Checksum on Rx pkts to be obeyed or disobeyed.
> +	 * If this is TRUE = 1, then whatever is the checksum on the
> +	 * Received pkt as per BE, it will be given to the stack.
> +	 * Else the stack will re calculate it.
> +	 */
> +	bool rx_csum;
> +	/*
> +	 * This will enable the use of ethtool to enable or disable
> +	 * Coalese on Rx pkts to be obeyed or disobeyed.
> +	 * If this is grater than 0 and less than 16 then coalascing
> +	 * is enabled else it is disabled
> +	 */
> +	u32 max_rx_coal;
> +	struct pci_dev *pdev;	/* Pointer to OS's PCI dvice */
> +
> +	spinlock_t txq_lock;
> +
> +	u32 isr;		/* copy of Intr status reg. */
> +
> +	u32 port0_link_sts;	/* Port 0 link status */
> +	u32 port1_link_sts;	/* port 1 list status */
> +	struct BE_LINK_STATUS *be_link_sts;
> +
> +	/* pointer to the first netobject of this adapter */
> +	struct bni_net_object *net_obj;
> +
> +	/*  Flags to indicate what to clean up */
> +	bool tasklet_started;
> +	bool isr_registered;
> +	/*
> +	 * adaptive interrupt coalescing (AIC) related
> +	 */
> +	bool enable_aic;	/* 1 if AIC is enabled */
> +	u16 min_eqd;		/* minimum EQ delay in usec */
> +	u16 max_eqd;		/* minimum EQ delay in usec */
> +	u16 cur_eqd;		/* current EQ delay in usec */
> +	/*
> +	 * book keeping for interrupt / sec and TX/RX rate calculation
> +	 */
> +	ulong ips_jiffies;	/* jiffies at last IPS calc */
> +	u32 eth_tx_bytes;
> +	ulong eth_tx_jiffies;
> +	u32 eth_rx_bytes;
> +	ulong eth_rx_jiffies;
> +
> +	struct semaphore get_eth_stat_sem;
> +
> +	/* timer ctxt to prevent shutdown hanging due to un-responsive BE */
> +	struct be_timer_ctxt timer_ctxt;
> +
> +#define BE_MAX_MSIX_VECTORS             32
> +#define BE_MAX_REQ_MSIX_VECTORS         1 /* only one EQ in Linux driver */
> +	struct msix_entry msix_entries[BE_MAX_MSIX_VECTORS];
> +	bool msix_enabled;
> +	bool dma_64bit_cap;	/* the Device DAC capable  or not */
> +	u8 dev_state;	/* The current state of the device */
> +	u8 dev_pm_state; /* The State of device before going to suspend */
> +};
> +
> +
> +struct be_rx_page_info {
> +	struct page *page;
> +	dma_addr_t bus;
> +	u16 page_offset;
> +} ;
> +
> +/*
> + * linux_net_object is an extension to BNI's NetObject structure.
> + * NetObject has a pointer to this structure
> + */
> +struct linux_net_object {
> +	struct net_device *netdev;
> +	struct bni_recv_buffer eth_rx_bufs[256];	/* to pass Rx buffer
> +							   addresses */
> +	struct be_adapter *adapter;	/* Pointer to OSM adapter */
> +	u32 devno;		/* OSM, network dev no. */
> +	u32 use_port;		/* Current active port */
> +	struct be_rx_page_info *rx_page_info;	/* Array of Rx buf pages */
> +	u32 rx_pg_info_hd;	/* Head of queue */
> +	int rxbuf_post_fail;	/* RxBuff posting fail count */
> +	bool rx_pg_shared;	/* Is an allocsted page shared as two frags ? */
> +	struct vlan_group *vlan_grp;
> +	u32 num_vlans;		/* Number of vlans in BE's filter */
> +	u16 vlan_tag[BE_NUM_VLAN_SUPPORTED]; /* vlans currently configured */
> +#ifdef CONFIG_BENET_NAPI
> +	struct napi_struct napi;
> +	u32 work_quota;		/* Max RX packets to process */
> +	bool rx_sched;
> +	spinlock_t rx_lock;
> +#endif
> +	struct net_lro_mgr lro_mgr;
> +	struct net_lro_desc lro_desc[BE_MAX_LRO_DESCRIPTORS];
> +} ;
> +
> +/* functions to update RX/TX rates */
> +static inline void
> +update_rx_rate(struct be_adapter *adapter)
> +{
> +	/* update the rate once in two seconds */
> +	if ((jiffies - adapter->eth_rx_jiffies) > 2*(HZ)) {
> +		u32 r;
> +		r = adapter->eth_rx_bytes /
> +			((jiffies-adapter->eth_rx_jiffies)/(HZ));
> +		r = (r / 1000000); /* MB/Sec */
> +		adapter->be_stat.bes_eth_rx_rate = (r * 8); /* Mega Bits/Sec */
> +		adapter->eth_rx_jiffies = jiffies;
> +		adapter->eth_rx_bytes = 0;
> +	}
> +}
> +
> +static inline void
> +update_tx_rate(struct be_adapter *adapter)
> +{
> +	/* update the rate once in two seconds */
> +	if ((jiffies - adapter->eth_tx_jiffies) > 2*(HZ)) {
> +		u32 r;
> +		r = adapter->eth_tx_bytes /
> +			((jiffies-adapter->eth_tx_jiffies)/(HZ));
> +		r = (r / 1000000); /* MB/Sec */
> +		adapter->be_stat.bes_eth_tx_rate = (r * 8); /* Mega Bits/Sec */
> +		adapter->eth_tx_jiffies = jiffies;
> +		adapter->eth_tx_bytes = 0;
> +	}
> +}
> +/*
> + * Every second we look at the ints/sec and adjust eq_delay
> + * between adapter->min_eqd and adapter->max_eqd to keep the ints/sec between
> + * IPS_HI_WM and IPS_LO_WM.
> + */
> +#define IPS_HI_WM	18000
> +#define IPS_LO_WM	8000
> +
> +static inline void
> +update_eqd(struct be_adapter *adapter, struct bni_net_object *pnob)
> +{
> +	/* update once a second */
> +	if ((jiffies - adapter->ips_jiffies) > 1*(HZ)) {
> +		/* One second elapsed since last update	 */
> +		u32 r, new_eqd = -1;
> +		r = adapter->be_stat.bes_ints -
> +			adapter->be_stat.bes_prev_ints;
> +		r =  r / ((jiffies - adapter->ips_jiffies)/(HZ));
> +		adapter->be_stat.bes_ips = r;
> +		adapter->ips_jiffies = jiffies;
> +		adapter->be_stat.bes_prev_ints = adapter->be_stat.bes_ints;
> +		if (r > IPS_HI_WM && adapter->cur_eqd < adapter->max_eqd) {
> +			/* increase eqdelay by a notch */
> +			new_eqd = (adapter->cur_eqd + 8);
> +		}
> +		if (r < IPS_LO_WM && adapter->cur_eqd > adapter->min_eqd) {
> +			/* decrease eqdelay by a notch */
> +			new_eqd = (adapter->cur_eqd - 8);
> +		}
> +		if (adapter->enable_aic && new_eqd != -1) {
> +			/* program new delay */
> +			if (bni_change_eqd(pnob, new_eqd) == BE_SUCCESS)
> +				adapter->cur_eqd = new_eqd;
> +		}
> +	}
> +}
> +/* convenience macro to access members in Linux extension of NetObject */
> +#define OSM_NOB(x)	((struct linux_net_object *)((x)->osm_netobj))
> +
> +/* proto declarations */
> +
> +int benet_probe(struct net_device *);
> +int be_ethtool_ioctl(struct net_device *, struct ifreq *);
> +struct net_device_stats *benet_get_stats(struct net_device *);
> +
> +void be_process_intr(unsigned long context);
> +irqreturn_t be_int(int irq, void *dev);
> +
> +void be_post_eth_rx_buffs(struct bni_net_object *);
> +void be_get_stat_cb(void *, BESTATUS, struct MCC_WRB_AMAP *);
> +
> +void be_get_stats_timer_handler(unsigned long);
> +
> +void be_wait_nic_tx_cmplx_cmpl(struct bni_net_object *);
> +void be_print_link_info(struct BE_LINK_STATUS *);
> +void be_update_link_status(struct be_adapter *);
> +
> +void be_init_procfs(struct be_adapter *);
> +void be_cleanup_procfs(struct be_adapter *);
> +
> +#ifdef CONFIG_BENET_NAPI
> +int be_poll(struct napi_struct *, int);
> +#endif
> +#endif /* _BENET_H_ */
> diff --git a/drivers/net/benet/bni.h b/drivers/net/benet/bni.h
> new file mode 100644
> index 0000000..fc9cd86
> --- /dev/null
> +++ b/drivers/net/benet/bni.h
> @@ -0,0 +1,327 @@
> +/*
> + * Copyright (C) 2005 - 2008 ServerEngines
> + * All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License version 2
> + * as published by the Free Software Foundation.  The full GNU General
> + * Public License is included in this distribution in the file called COPYING.
> + *
> + * Contact Information:
> + * [email-masked]
> + *
> + * ServerEngines
> + * 209 N. Fair Oaks Ave
> + * Sunnyvale, CA 94085
> + */
> +/*
> +
> +@file
> +    bni.h
> +
> +@brief
> +    Definitions and macros that are required for all .c files
> +    that use the BNI API and implement the BNI API functions
> +*/
> +#ifndef _BNI_H
> +#define _BNI_H
> +
> +#define _SA_MODULE_NAME "net-driver"
> +#include "beclib_ll.h"
> +
> +#define VLAN_VALID_BIT		0x8000
> +#define BE_NUM_VLAN_SUPPORTED	32
> +#define BE_PORT_LINK_DOWN       0000
> +#define BE_PORT_LINK_UP         0001
> +
> +
> +/*
> +@brief
> +    This structure is used by the OSM driver to give BNI
> +    physical fragments to use for DMAing data from NIC.
> +*/
> +struct bni_recv_buffer {
> +	struct list_head rxb_list;	/* for maintaining a linked list */
> +	void *rxb_va;		/* buffer virtual address */
> +	u32 rxb_pa_lo;		/* low part of physical address */
> +	u32 rxb_pa_hi;		/* high part of physical address */
> +	u32 rxb_len;		/* length of recv buffer */
> +	void *rxb_ctxt;		/* context for OSM driver to use */
> +};
> +
> +/*
> + * fragment list to describe scattered data.
> + */
> +struct bni_tx_frag_list {
> +	u32 txb_len;		/* Size of this fragment */
> +	u32 txb_pa_lo;		/* Lower 32 bits of 64 bit physical addr */
> +	u32 txb_pa_hi;		/* Higher 32 bits of 64 bit physical addr */
> +};
> +/*
> + * maximum fragements in a TX request
> + */
> +#define	BE_MAX_TX_FRAG_COUNT		(30)
> +
> +/*
> + * Flag bits for send operation
> + */
> +#define IPCS            (1 << 0)	/* Enable IP checksum offload */
> +#define UDPCS           (1 << 1)	/* Enable UDP checksum offload */
> +#define TCPCS           (1 << 2)	/* Enable TCP checksum offload */
> +#define LSO             (1 << 3)	/* Enable Large Segment  offload */
> +#define ETHVLAN         (1 << 4)	/* Enable VLAN insert */
> +#define ETHEVENT        (1 << 5)	/* Generate  event on completion */
> +#define ETHCOMPLETE     (1 << 6)	/* Generate completion when done */
> +#define IPSEC           (1 << 7)	/* Enable IPSEC */
> +#define FORWARD         (1 << 8)	/* Send the packet in forwarding path */
> +#define FIN             (1 << 9)	/* Issue FIN segment */
> +
> +/* @brief
> + *  This structure is the main tracking structure for a NIC interface.
> + *  This data structure contains OS agnostic data members for processing
> + *  intialization, sends, receives, and asynchronous events from the
> + *  BladeEngine network function. The OSM driver makes
> + *  calls into functions defined at this layer for initialization,
> + *  eumeration and population of physical fragments with per-packet
> + *  control flags for send and receive operations, population of
> + *  receive buffers for NIC , and handling asynchronous
> + *  events (such as link status change, packet pattern recognition etc.).
> + */
> +struct bni_net_object {
> +
> +	/*
> +	 * MCC Ring - used to send ioctl cmds to embedded ARM processor
> +	 */
> +	struct MCC_WRB_AMAP *mcc_q;	/* VA of the start of the ring */
> +	u32 mcc_q_len;			/* # of WRB entries in this ring */
> +	u32 mcc_q_size;
> +	u32 mcc_q_hd;			/* MCC ring head */
> +	u8 mcc_q_created;		/* flag to help cleanup */
> +	struct be_mcc_object mcc_q_obj;	/* BECLIB's MCC ring Object */
> +	dma_addr_t mcc_q_bus;		/* DMA'ble bus address */
> +	/*
> +	 * MCC Completion Ring - ARM's responses to ioctls sent from MCC ring
> +	 */
> +	struct MCC_CQ_ENTRY_AMAP *mcc_cq; /* VA of the start of the ring */
> +	u32 mcc_cq_len;			/* # of compl. entries in this ring */
> +	u32 mcc_cq_size;
> +	u32 mcc_cq_tl;			/* compl. ring tail */
> +	u8 mcc_cq_created;		/* flag to help cleanup */
> +	struct be_cq_object mcc_cq_obj;	/* BECLIB's MCC compl. ring object */
> +	u32 mcc_cq_id;			/* MCC ring ID */
> +	dma_addr_t mcc_cq_bus;		/* DMA'ble bus address */
> +	/*
> +	 * BEClib uses an array of context objects to track outstanding
> +	 * requests to the MCC.  We need allocate the same number of
> +	 * conext entries as the number of entries in the MCC WRB ring
> +	 */
> +	u32 mcc_wrb_ctxt_size;
> +	void *mcc_wrb_ctxt;		/* pointer to the context area */
> +	u32 mcc_wrb_ctxtLen;		/* Number of entries in the context */
> +	/*
> +	 * NIC send request ring - used for xmitting raw ether frames.
> +	 */
> +	struct ETH_WRB_AMAP *tx_q;	/* VA of the start of the ring */
> +	u32 tx_q_len;			/* # if entries in the send ring */
> +	u32 tx_q_size;
> +	u32 tx_q_hd;			/* Head index. Next req. goes here */
> +	u32 tx_q_tl;			/* Tail indx. oldest outstanding req. */
> +	u8 tx_q_created;		/* flag to help cleanup */
> +	struct be_ethsq_object tx_q_obj;/* BECLIB's send Q handle */
> +	dma_addr_t tx_q_bus;		/* DMA'ble bus address */
> +	u32 tx_q_id;			/* send queue ring ID */
> +	u32 tx_q_port;			/* 0 no binding, 1 port A,  2 port B */
> +	atomic_t tx_q_used;		/* # of WRBs used */
> +	/* ptr to an array in which we store context info for each send req. */
> +	void **tx_ctxt;
> +	/*
> +	 * NIC Send compl. ring - completion status for all NIC frames xmitted.
> +	 */
> +	struct ETH_TX_COMPL_AMAP *tx_cq;/* VA of start of the ring */
> +	u32 txcq_len;			/* # of entries in the ring */
> +	u32 tx_cq_size;
> +	/*
> +	 * index into compl ring where the host expects next completion entry
> +	 */
> +	u32 tx_cq_tl;
> +	u32 tx_cq_id;			/* completion queue id */
> +	u8 tx_cq_created;		/* flag to help cleanup */
> +	struct be_cq_object tx_cq_obj;
> +	dma_addr_t tx_cq_bus;		/* DMA'ble bus address */
> +	/*
> +	 * Event Queue - all completion entries post events here.
> +	 */
> +	struct EQ_ENTRY_AMAP *event_q;	/* VA of start of event queue */
> +	u32 event_q_len;		/* # of entries */
> +	u32 event_q_size;
> +	u32 event_q_tl;			/* Tail of the event queue */
> +	u32 event_q_id;			/* Event queue ID */
> +	u8 event_q_created;		/* flag to help cleanup */
> +	struct be_eq_object event_q_obj; /* Queue handle */
> +	dma_addr_t event_q_bus;		/* DMA'ble bus address */
> +	/*
> +	 * NIC receive queue - Data buffers to be used for receiving unicast,
> +	 * broadcast and multi-cast frames  are posted here.
> +	 */
> +	struct ETH_RX_D_AMAP *rx_q;	/* VA of start of the queue */
> +	u32 rx_q_len;			/* # of entries */
> +	u32 rx_q_size;
> +	u32 rx_q_hd;			/* Head of the queue */
> +	atomic_t rx_q_posted;		/* number of posted buffers */
> +	u32 rx_q_id;			/* queue ID */
> +	u8 rx_q_created;		/* flag to help cleanup */
> +	struct be_ethrq_object rx_q_obj;	/* NIC RX queue handle */
> +	dma_addr_t rx_q_bus;		/* DMA'ble bus address */
> +	/*
> +	 * Pointer to an array of opaque context object for use by OSM driver
> +	 */
> +	void **rx_ctxt;
> +	/*
> +	 * NIC unicast RX completion queue - all unicast ether frame completion
> +	 * statuses from BE come here.
> +	 */
> +	struct ETH_RX_COMPL_AMAP *ucrx_cq;	/* VA of start of the queue */
> +	u32 ucrx_cq_len;		/* # of entries */
> +	u32 ucrx_cq_size;
> +	u32 ucrx_cq_tl;			/* Tail of the queue */
> +	u32 ucrx_cq_id;			/* queue ID */
> +	u8 ucrx_cq_created;		/* flag to help cleanup */
> +	struct be_cq_object ucrx_cq_obj;	/* queue handle */
> +	dma_addr_t ucrx_cq_bus;		/* DMA'ble bus address */
> +	/*
> +	 * Broadcast RX completion queue - all broadcast and multicast ether
> +	 * completion statues from BE come here.
> +	 */
> +	struct ETH_RX_COMPL_AMAP *bcrx_cq;	/* VA of start of queue */
> +	u32 bcrx_cq_len;		/* # of entries */
> +	u32 bcrx_cq_size;
> +	u32 bcrx_cq_tl;			/* Tail of the queue */
> +	u32 bcrx_cq_id;			/* Queue ID */
> +	u8 bcrx_cq_created;		/* flag to help cleanup */
> +	struct be_cq_object bcrx_cq_obj;	/* queue handle */
> +	dma_addr_t bcrx_cq_bus;		/* DMA'ble bus address */
> +
> +	struct be_function_object fn_obj;	/* function object   */
> +	bool	fn_obj_created;
> +	u32 rx_buf_size;		/* Size of the RX buffers */
> +	/*
> +	 * OSM handle. OSM drivers can use this pointer to extend NetObject.
> +	 */
> +	void *osm_netobj;
> +	struct sa_sgl mb_sgl;		/* SGL for MCC_MAIL_BOX */
> +	void *mb_ptr;			/* mailbox ptr to be freed  */
> +	dma_addr_t mb_bus;		/* DMA'ble bus address */
> +	u32 mb_size;
> +};
> +
> +/*
> + * convenience macros to access some NetObject members
> + */
> +#define NET_FH(np)       (&(np)->fn_obj)
> +
> +static inline void index_advance(u32 *index, u32 limit)
> +{
> +	BUG_ON(limit & (limit-1));
> +	*index = (*index + 1) & (limit - 1);
> +}
> +
> +/*
> + * Functions to advance the head and tail in various rings.
> + */
> +static inline void bni_adv_eq_tl(struct bni_net_object *pnob)
> +{
> +	index_advance(&pnob->event_q_tl, pnob->event_q_len);
> +}
> +
> +static inline void bni_adv_txq_hd(struct bni_net_object *pnob)
> +{
> +	index_advance(&pnob->tx_q_hd, pnob->tx_q_len);
> +}
> +
> +static inline void bni_adv_txq_tl(struct bni_net_object *pnob)
> +{
> +	index_advance(&pnob->tx_q_tl, pnob->tx_q_len);
> +}
> +
> +static inline void bni_adv_txcq_tl(struct bni_net_object *pnob)
> +{
> +	index_advance(&pnob->tx_cq_tl, pnob->txcq_len);
> +}
> +
> +static inline void bni_adv_rxq_hd(struct bni_net_object *pnob)
> +{
> +	index_advance(&pnob->rx_q_hd, pnob->rx_q_len);
> +}
> +
> +static inline void bni_adv_ucrxcq_tl(struct bni_net_object *pnob)
> +{
> +	index_advance(&pnob->ucrx_cq_tl, pnob->ucrx_cq_len);
> +}
> +
> +static inline void bni_adv_bcrxcq_tl(struct bni_net_object *pnob)
> +{
> +	index_advance(&pnob->bcrx_cq_tl, pnob->bcrx_cq_len);
> +}
> +
> +static inline BESTATUS bni_process_mcc_cmpl(struct be_mcc_object *pmccob)
> +{
> +	return (be_mcc_process_cq(pmccob, 1));
> +}
> +
> +/* forward declarations of function prototypes */
> +BESTATUS bni_init(struct be_chip_object *);
> +BESTATUS bni_create_mcc_rings(struct bni_net_object *);
> +extern void bni_destroy_netobj(struct bni_net_object *, struct sa_dev *);
> +void bni_cleanup(struct be_chip_object *);
> +
> +BESTATUS bni_create_netobj(struct bni_net_object *,
> +			struct sa_dev_bar_locations *, u32,
> +			struct sa_dev *, struct be_chip_object *);
> +
> +BESTATUS bni_tx_pkt(struct bni_net_object *, struct bni_tx_frag_list *, u32,
> +		    u32, u32, void *, u32);
> +void bni_start_tx(struct bni_net_object *, u32);
> +
> +u32 bni_post_rx_buffs(struct bni_net_object *, struct list_head *);
> +BESTATUS bni_change_eqd(struct bni_net_object *, u32);
> +
> +struct ETH_TX_COMPL_AMAP *bni_get_tx_cmpl(struct bni_net_object *);
> +struct ETH_RX_COMPL_AMAP *bni_get_ucrx_cmpl(struct bni_net_object *);
> +struct ETH_RX_COMPL_AMAP *bni_get_bcrx_cmpl(struct bni_net_object *);
> +void bni_notify_cmpl(struct bni_net_object *, int, int, int);
> +
> +void bni_enable_intr(struct bni_net_object *);
> +void bni_enable_eq_intr(struct bni_net_object *);
> +void bni_disable_intr(struct bni_net_object *);
> +void bni_disable_eq_intr(struct bni_net_object *);
> +
> +u32 bni_get_isr(struct bni_net_object *);
> +
> +struct EQ_ENTRY_AMAP *bni_get_event(struct bni_net_object *);
> +void bni_notify_event(struct bni_net_object *, int, int);
> +
> +BESTATUS bni_get_uc_mac_adrr(struct bni_net_object *, u8, u8, u8,
> +		     u8 *, MCC_WRB_CQE_CALLBACK, void *);
> +
> +BESTATUS bni_set_uc_mac_adr(struct bni_net_object *, u8, u8, u8,
> +		    u8 *, MCC_WRB_CQE_CALLBACK, void *);
> +
> +BESTATUS bni_set_mc_filter(struct bni_net_object *, u32,
> +		   bool, u8 *, MCC_WRB_CQE_CALLBACK, void *);
> +
> +void bni_set_promisc(struct bni_net_object *);
> +void bni_reset_promisc(struct bni_net_object *);
> +BESTATUS bni_config_vlan(struct bni_net_object *, u16 *,
> +			 u32, MCC_WRB_CQE_CALLBACK, void *, bool);
> +
> +BESTATUS bni_get_stats(struct bni_net_object *,
> +		       struct FWCMD_ETH_GET_STATISTICS *,
> +		       u64, MCC_WRB_CQE_CALLBACK, void *);
> +
> +BESTATUS bni_get_link_sts(struct bni_net_object *, struct BE_LINK_STATUS *,
> +			  MCC_WRB_CQE_CALLBACK, void *);
> +BESTATUS bni_set_flow_ctll(struct be_function_object *, bool, bool);
> +BESTATUS bni_get_flow_ctl(struct be_function_object *pFnObj, bool *, bool *);
> +u32 bni_process_rx_flush_cmpl(struct bni_net_object *);
> +
> +#endif /* #ifndef _BNI_H_ */
> -- 
> 1.5.5