aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/staging/benet
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/benet')
-rw-r--r--drivers/staging/benet/Kconfig7
-rw-r--r--drivers/staging/benet/MAINTAINERS6
-rw-r--r--drivers/staging/benet/Makefile14
-rw-r--r--drivers/staging/benet/TODO6
-rw-r--r--drivers/staging/benet/asyncmesg.h82
-rw-r--r--drivers/staging/benet/be_cm.h134
-rw-r--r--drivers/staging/benet/be_common.h53
-rw-r--r--drivers/staging/benet/be_ethtool.c348
-rw-r--r--drivers/staging/benet/be_init.c1382
-rw-r--r--drivers/staging/benet/be_int.c863
-rw-r--r--drivers/staging/benet/be_netif.c705
-rw-r--r--drivers/staging/benet/benet.h429
-rw-r--r--drivers/staging/benet/bestatus.h103
-rw-r--r--drivers/staging/benet/cev.h243
-rw-r--r--drivers/staging/benet/cq.c211
-rw-r--r--drivers/staging/benet/descriptors.h71
-rw-r--r--drivers/staging/benet/doorbells.h179
-rw-r--r--drivers/staging/benet/ep.h66
-rw-r--r--drivers/staging/benet/eq.c299
-rw-r--r--drivers/staging/benet/eth.c1273
-rw-r--r--drivers/staging/benet/etx_context.h55
-rw-r--r--drivers/staging/benet/funcobj.c565
-rw-r--r--drivers/staging/benet/fwcmd_common.h222
-rw-r--r--drivers/staging/benet/fwcmd_common_bmap.h717
-rw-r--r--drivers/staging/benet/fwcmd_eth_bmap.h280
-rw-r--r--drivers/staging/benet/fwcmd_hdr_bmap.h54
-rw-r--r--drivers/staging/benet/fwcmd_mcc.h94
-rw-r--r--drivers/staging/benet/fwcmd_opcodes.h244
-rw-r--r--drivers/staging/benet/fwcmd_types_bmap.h29
-rw-r--r--drivers/staging/benet/host_struct.h182
-rw-r--r--drivers/staging/benet/hwlib.h830
-rw-r--r--drivers/staging/benet/mpu.c1364
-rw-r--r--drivers/staging/benet/mpu.h74
-rw-r--r--drivers/staging/benet/mpu_context.h46
-rw-r--r--drivers/staging/benet/pcicfg.h825
-rw-r--r--drivers/staging/benet/post_codes.h111
-rw-r--r--drivers/staging/benet/regmap.h68
37 files changed, 12234 insertions, 0 deletions
diff --git a/drivers/staging/benet/Kconfig b/drivers/staging/benet/Kconfig
new file mode 100644
index 000000000000..f6806074f998
--- /dev/null
+++ b/drivers/staging/benet/Kconfig
@@ -0,0 +1,7 @@
+config BENET
+ tristate "ServerEngines 10Gb NIC - BladeEngine"
+ depends on PCI && INET
+ select INET_LRO
+ help
+ This driver implements the NIC functionality for ServerEngines
+ 10Gb network adapter BladeEngine (EC 3210).
diff --git a/drivers/staging/benet/MAINTAINERS b/drivers/staging/benet/MAINTAINERS
new file mode 100644
index 000000000000..d5ce340218b3
--- /dev/null
+++ b/drivers/staging/benet/MAINTAINERS
@@ -0,0 +1,6 @@
+SERVER ENGINES 10Gbe NIC - BLADE-ENGINE
+P: Subbu Seetharaman
+M: subbus@serverengines.com
+L: netdev@vger.kernel.org
+W: http://www.serverengines.com
+S: Supported
diff --git a/drivers/staging/benet/Makefile b/drivers/staging/benet/Makefile
new file mode 100644
index 000000000000..460b923b99bd
--- /dev/null
+++ b/drivers/staging/benet/Makefile
@@ -0,0 +1,14 @@
+#
+# Makefile to build the network driver for ServerEngine's BladeEngine
+#
+obj-$(CONFIG_BENET) += benet.o
+
+benet-y := be_init.o \
+ be_int.o \
+ be_netif.o \
+ be_ethtool.o \
+ funcobj.o \
+ cq.o \
+ eq.o \
+ mpu.o \
+ eth.o
diff --git a/drivers/staging/benet/TODO b/drivers/staging/benet/TODO
new file mode 100644
index 000000000000..a51dfb59a62f
--- /dev/null
+++ b/drivers/staging/benet/TODO
@@ -0,0 +1,6 @@
+TODO:
+ - remove wrappers around common iowrite functions
+ - full netdev audit of common problems/issues
+
+Please send all patches and questions to Subbu Seetharaman
+<subbus@serverengines.com> and Greg Kroah-Hartman <greg@kroah.com>
diff --git a/drivers/staging/benet/asyncmesg.h b/drivers/staging/benet/asyncmesg.h
new file mode 100644
index 000000000000..d1e779adb848
--- /dev/null
+++ b/drivers/staging/benet/asyncmesg.h
@@ -0,0 +1,82 @@
+/*
+ * 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:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+/*
+ * Autogenerated by srcgen version: 0127
+ */
+#ifndef __asyncmesg_amap_h__
+#define __asyncmesg_amap_h__
+#include "fwcmd_common.h"
+
+/* --- ASYNC_EVENT_CODES --- */
+#define ASYNC_EVENT_CODE_LINK_STATE (1)
+#define ASYNC_EVENT_CODE_ISCSI (2)
+
+/* --- ASYNC_LINK_STATES --- */
+#define ASYNC_EVENT_LINK_DOWN (0) /* Link Down on a port */
+#define ASYNC_EVENT_LINK_UP (1) /* Link Up on a port */
+
+/*
+ * The last 4 bytes of the async events have this common format. It allows
+ * the driver to distinguish [link]MCC_CQ_ENTRY[/link] structs from
+ * asynchronous events. Both arrive on the same completion queue. This
+ * structure also contains the common fields used to decode the async event.
+ */
+struct BE_ASYNC_EVENT_TRAILER_AMAP {
+ u8 rsvd0[8]; /* DWORD 0 */
+ u8 event_code[8]; /* DWORD 0 */
+ u8 event_type[8]; /* DWORD 0 */
+ u8 rsvd1[6]; /* DWORD 0 */
+ u8 async_event; /* DWORD 0 */
+ u8 valid; /* DWORD 0 */
+} __packed;
+struct ASYNC_EVENT_TRAILER_AMAP {
+ u32 dw[1];
+};
+
+/*
+ * Applicable in Initiator, Target and NIC modes.
+ * A link state async event is seen by all device drivers as soon they
+ * create an MCC ring. Thereafter, anytime the link status changes the
+ * drivers will receive a link state async event. Notifications continue to
+ * be sent until a driver destroys its MCC ring. A link down event is
+ * reported when either port loses link. A link up event is reported
+ * when either port regains link. When BE's failover mechanism is enabled, a
+ * link down on the active port causes traffic to be diverted to the standby
+ * port by the BE's ARM firmware (assuming the standby port has link). In
+ * this case, the standy port assumes the active status. Note: when link is
+ * restored on the failed port, traffic continues on the currently active
+ * port. The ARM firmware does not attempt to 'fail back' traffic to
+ * the restored port.
+ */
+struct BE_ASYNC_EVENT_LINK_STATE_AMAP {
+ u8 port0_link_status[8];
+ u8 port1_link_status[8];
+ u8 active_port[8];
+ u8 rsvd0[8]; /* DWORD 0 */
+ u8 port0_duplex[8];
+ u8 port0_speed[8];
+ u8 port1_duplex[8];
+ u8 port1_speed[8];
+ u8 port0_fault[8];
+ u8 port1_fault[8];
+ u8 rsvd1[2][8]; /* DWORD 2 */
+ struct BE_ASYNC_EVENT_TRAILER_AMAP trailer;
+} __packed;
+struct ASYNC_EVENT_LINK_STATE_AMAP {
+ u32 dw[4];
+};
+#endif /* __asyncmesg_amap_h__ */
diff --git a/drivers/staging/benet/be_cm.h b/drivers/staging/benet/be_cm.h
new file mode 100644
index 000000000000..b7a1dfd20c36
--- /dev/null
+++ b/drivers/staging/benet/be_cm.h
@@ -0,0 +1,134 @@
+/*
+ * 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:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+/*
+ * Autogenerated by srcgen version: 0127
+ */
+#ifndef __be_cm_amap_h__
+#define __be_cm_amap_h__
+#include "be_common.h"
+#include "etx_context.h"
+#include "mpu_context.h"
+
+/*
+ * --- CEV_WATERMARK_ENUM ---
+ * CQ/EQ Watermark Encodings. Encoded as number of free entries in
+ * Queue when Watermark is reached.
+ */
+#define CEV_WMARK_0 (0) /* Watermark when Queue full */
+#define CEV_WMARK_16 (1) /* Watermark at 16 free entries */
+#define CEV_WMARK_32 (2) /* Watermark at 32 free entries */
+#define CEV_WMARK_48 (3) /* Watermark at 48 free entries */
+#define CEV_WMARK_64 (4) /* Watermark at 64 free entries */
+#define CEV_WMARK_80 (5) /* Watermark at 80 free entries */
+#define CEV_WMARK_96 (6) /* Watermark at 96 free entries */
+#define CEV_WMARK_112 (7) /* Watermark at 112 free entries */
+#define CEV_WMARK_128 (8) /* Watermark at 128 free entries */
+#define CEV_WMARK_144 (9) /* Watermark at 144 free entries */
+#define CEV_WMARK_160 (10) /* Watermark at 160 free entries */
+#define CEV_WMARK_176 (11) /* Watermark at 176 free entries */
+#define CEV_WMARK_192 (12) /* Watermark at 192 free entries */
+#define CEV_WMARK_208 (13) /* Watermark at 208 free entries */
+#define CEV_WMARK_224 (14) /* Watermark at 224 free entries */
+#define CEV_WMARK_240 (15) /* Watermark at 240 free entries */
+
+/*
+ * --- CQ_CNT_ENUM ---
+ * Completion Queue Count Encodings.
+ */
+#define CEV_CQ_CNT_256 (0) /* CQ has 256 entries */
+#define CEV_CQ_CNT_512 (1) /* CQ has 512 entries */
+#define CEV_CQ_CNT_1024 (2) /* CQ has 1024 entries */
+
+/*
+ * --- EQ_CNT_ENUM ---
+ * Event Queue Count Encodings.
+ */
+#define CEV_EQ_CNT_256 (0) /* EQ has 256 entries (16-byte EQEs only) */
+#define CEV_EQ_CNT_512 (1) /* EQ has 512 entries (16-byte EQEs only) */
+#define CEV_EQ_CNT_1024 (2) /* EQ has 1024 entries (4-byte or */
+ /* 16-byte EQEs only) */
+#define CEV_EQ_CNT_2048 (3) /* EQ has 2048 entries (4-byte or */
+ /* 16-byte EQEs only) */
+#define CEV_EQ_CNT_4096 (4) /* EQ has 4096 entries (4-byte EQEs only) */
+
+/*
+ * --- EQ_SIZE_ENUM ---
+ * Event Queue Entry Size Encoding.
+ */
+#define CEV_EQ_SIZE_4 (0) /* EQE is 4 bytes */
+#define CEV_EQ_SIZE_16 (1) /* EQE is 16 bytes */
+
+/*
+ * Completion Queue Context Table Entry. Contains the state of a CQ.
+ * Located in RAM within the CEV block.
+ */
+struct BE_CQ_CONTEXT_AMAP {
+ u8 Cidx[11]; /* DWORD 0 */
+ u8 Watermark[4]; /* DWORD 0 */
+ u8 NoDelay; /* DWORD 0 */
+ u8 EPIdx[11]; /* DWORD 0 */
+ u8 Count[2]; /* DWORD 0 */
+ u8 valid; /* DWORD 0 */
+ u8 SolEvent; /* DWORD 0 */
+ u8 Eventable; /* DWORD 0 */
+ u8 Pidx[11]; /* DWORD 1 */
+ u8 PD[10]; /* DWORD 1 */
+ u8 EQID[7]; /* DWORD 1 */
+ u8 Func; /* DWORD 1 */
+ u8 WME; /* DWORD 1 */
+ u8 Stalled; /* DWORD 1 */
+ u8 Armed; /* DWORD 1 */
+} __packed;
+struct CQ_CONTEXT_AMAP {
+ u32 dw[2];
+};
+
+/*
+ * Event Queue Context Table Entry. Contains the state of an EQ.
+ * Located in RAM in the CEV block.
+ */
+struct BE_EQ_CONTEXT_AMAP {
+ u8 Cidx[13]; /* DWORD 0 */
+ u8 rsvd0[2]; /* DWORD 0 */
+ u8 Func; /* DWORD 0 */
+ u8 EPIdx[13]; /* DWORD 0 */
+ u8 valid; /* DWORD 0 */
+ u8 rsvd1; /* DWORD 0 */
+ u8 Size; /* DWORD 0 */
+ u8 Pidx[13]; /* DWORD 1 */
+ u8 rsvd2[3]; /* DWORD 1 */
+ u8 PD[10]; /* DWORD 1 */
+ u8 Count[3]; /* DWORD 1 */
+ u8 SolEvent; /* DWORD 1 */
+ u8 Stalled; /* DWORD 1 */
+ u8 Armed; /* DWORD 1 */
+ u8 Watermark[4]; /* DWORD 2 */
+ u8 WME; /* DWORD 2 */
+ u8 rsvd3[3]; /* DWORD 2 */
+ u8 EventVect[6]; /* DWORD 2 */
+ u8 rsvd4[2]; /* DWORD 2 */
+ u8 Delay[8]; /* DWORD 2 */
+ u8 rsvd5[6]; /* DWORD 2 */
+ u8 TMR; /* DWORD 2 */
+ u8 rsvd6; /* DWORD 2 */
+ u8 rsvd7[32]; /* DWORD 3 */
+} __packed;
+struct EQ_CONTEXT_AMAP {
+ u32 dw[4];
+};
+
+#endif /* __be_cm_amap_h__ */
diff --git a/drivers/staging/benet/be_common.h b/drivers/staging/benet/be_common.h
new file mode 100644
index 000000000000..7e63dc5e3348
--- /dev/null
+++ b/drivers/staging/benet/be_common.h
@@ -0,0 +1,53 @@
+/*
+ * 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:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+/*
+ * Autogenerated by srcgen version: 0127
+ */
+#ifndef __be_common_amap_h__
+#define __be_common_amap_h__
+
+/* Physical Address. */
+struct BE_PHYS_ADDR_AMAP {
+ u8 lo[32]; /* DWORD 0 */
+ u8 hi[32]; /* DWORD 1 */
+} __packed;
+struct PHYS_ADDR_AMAP {
+ u32 dw[2];
+};
+
+/* Virtual Address. */
+struct BE_VIRT_ADDR_AMAP {
+ u8 lo[32]; /* DWORD 0 */
+ u8 hi[32]; /* DWORD 1 */
+} __packed;
+struct VIRT_ADDR_AMAP {
+ u32 dw[2];
+};
+
+/* Scatter gather element. */
+struct BE_SGE_AMAP {
+ u8 addr_hi[32]; /* DWORD 0 */
+ u8 addr_lo[32]; /* DWORD 1 */
+ u8 rsvd0[32]; /* DWORD 2 */
+ u8 len[16]; /* DWORD 3 */
+ u8 rsvd1[16]; /* DWORD 3 */
+} __packed;
+struct SGE_AMAP {
+ u32 dw[4];
+};
+
+#endif /* __be_common_amap_h__ */
diff --git a/drivers/staging/benet/be_ethtool.c b/drivers/staging/benet/be_ethtool.c
new file mode 100644
index 000000000000..027af85707aa
--- /dev/null
+++ b/drivers/staging/benet/be_ethtool.c
@@ -0,0 +1,348 @@
+/*
+ * 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:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+/*
+ * be_ethtool.c
+ *
+ * This file contains various functions that ethtool can use
+ * to talk to the driver and the BE H/W.
+ */
+
+#include "benet.h"
+
+#include <linux/ethtool.h>
+
+static const char benet_gstrings_stats[][ETH_GSTRING_LEN] = {
+/* net_device_stats */
+ "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",
+ "tc_compressed",
+/* BE driver Stats */
+ "bes_tx_reqs",
+ "bes_tx_fails",
+ "bes_fwd_reqs",
+ "bes_tx_wrbs",
+ "bes_interrupts",
+ "bes_events",
+ "bes_tx_events",
+ "bes_rx_events",
+ "bes_tx_compl",
+ "bes_rx_compl",
+ "bes_ethrx_post_fail",
+ "bes_802_3_dropped_frames",
+ "bes_802_3_malformed_frames",
+ "bes_rx_misc_pkts",
+ "bes_eth_tx_rate",
+ "bes_eth_rx_rate",
+ "Num Packets collected",
+ "Num Times Flushed",
+};
+
+#define NET_DEV_STATS_LEN \
+ (sizeof(struct net_device_stats)/sizeof(unsigned long))
+
+#define BENET_STATS_LEN ARRAY_SIZE(benet_gstrings_stats)
+
+static void
+be_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
+{
+ struct be_net_object *pnob = netdev_priv(netdev);
+ struct be_adapter *adapter = pnob->adapter;
+
+ strncpy(drvinfo->driver, be_driver_name, 32);
+ strncpy(drvinfo->version, be_drvr_ver, 32);
+ strncpy(drvinfo->fw_version, be_fw_ver, 32);
+ strcpy(drvinfo->bus_info, pci_name(adapter->pdev));
+ drvinfo->testinfo_len = 0;
+ drvinfo->regdump_len = 0;
+ drvinfo->eedump_len = 0;
+}
+
+static int
+be_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
+{
+ struct be_net_object *pnob = netdev_priv(netdev);
+ struct be_adapter *adapter = pnob->adapter;
+
+ coalesce->rx_max_coalesced_frames = adapter->max_rx_coal;
+
+ coalesce->rx_coalesce_usecs = adapter->cur_eqd;
+ coalesce->rx_coalesce_usecs_high = adapter->max_eqd;
+ coalesce->rx_coalesce_usecs_low = adapter->min_eqd;
+
+ coalesce->tx_coalesce_usecs = adapter->cur_eqd;
+ coalesce->tx_coalesce_usecs_high = adapter->max_eqd;
+ coalesce->tx_coalesce_usecs_low = adapter->min_eqd;
+
+ coalesce->use_adaptive_rx_coalesce = adapter->enable_aic;
+ coalesce->use_adaptive_tx_coalesce = adapter->enable_aic;
+
+ return 0;
+}
+
+/*
+ * This routine is used to set interrup coalescing delay *as well as*
+ * the number of pkts to coalesce for LRO.
+ */
+static int
+be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
+{
+ struct be_net_object *pnob = netdev_priv(netdev);
+ struct be_adapter *adapter = pnob->adapter;
+ struct be_eq_object *eq_objectp;
+ u32 max, min, cur;
+ int status;
+
+ adapter->max_rx_coal = coalesce->rx_max_coalesced_frames;
+ if (adapter->max_rx_coal >= BE_LRO_MAX_PKTS)
+ adapter->max_rx_coal = BE_LRO_MAX_PKTS;
+
+ if (adapter->enable_aic == 0 &&
+ coalesce->use_adaptive_rx_coalesce == 1) {
+ /* if AIC is being turned on now, start with an EQD of 0 */
+ adapter->cur_eqd = 0;
+ }
+ adapter->enable_aic = coalesce->use_adaptive_rx_coalesce;
+
+ /* round off to nearest multiple of 8 */
+ max = (((coalesce->rx_coalesce_usecs_high + 4) >> 3) << 3);
+ min = (((coalesce->rx_coalesce_usecs_low + 4) >> 3) << 3);
+ cur = (((coalesce->rx_coalesce_usecs + 4) >> 3) << 3);
+
+ if (adapter->enable_aic) {
+ /* accept low and high if AIC is enabled */
+ if (max > MAX_EQD)
+ max = MAX_EQD;
+ if (min > max)
+ min = max;
+ adapter->max_eqd = max;
+ adapter->min_eqd = min;
+ if (adapter->cur_eqd > max)
+ adapter->cur_eqd = max;
+ if (adapter->cur_eqd < min)
+ adapter->cur_eqd = min;
+ } else {
+ /* accept specified coalesce_usecs only if AIC is disabled */
+ if (cur > MAX_EQD)
+ cur = MAX_EQD;
+ eq_objectp = &pnob->event_q_obj;
+ status =
+ be_eq_modify_delay(&pnob->fn_obj, 1, &eq_objectp, &cur,
+ NULL, NULL, NULL);
+ if (status == BE_SUCCESS)
+ adapter->cur_eqd = cur;
+ }
+ return 0;
+}
+
+static u32 be_get_rx_csum(struct net_device *netdev)
+{
+ struct be_net_object *pnob = netdev_priv(netdev);
+ struct be_adapter *adapter = pnob->adapter;
+ return adapter->rx_csum;
+}
+
+static int be_set_rx_csum(struct net_device *netdev, uint32_t data)
+{
+ struct be_net_object *pnob = netdev_priv(netdev);
+ struct be_adapter *adapter = pnob->adapter;
+
+ if (data)
+ adapter->rx_csum = 1;
+ else
+ adapter->rx_csum = 0;
+
+ return 0;
+}
+
+static void
+be_get_strings(struct net_device *netdev, uint32_t stringset, uint8_t *data)
+{
+ switch (stringset) {
+ case ETH_SS_STATS:
+ memcpy(data, *benet_gstrings_stats,
+ sizeof(benet_gstrings_stats));
+ break;
+ }
+}
+
+static int be_get_stats_count(struct net_device *netdev)
+{
+ return BENET_STATS_LEN;
+}
+
+static void
+be_get_ethtool_stats(struct net_device *netdev,
+ struct ethtool_stats *stats, uint64_t *data)
+{
+ struct be_net_object *pnob = netdev_priv(netdev);
+ struct be_adapter *adapter = pnob->adapter;
+ int i;
+
+ benet_get_stats(netdev);
+
+ for (i = 0; i <= NET_DEV_STATS_LEN; i++)
+ data[i] = ((unsigned long *)&adapter->benet_stats)[i];
+
+ data[i] = adapter->be_stat.bes_tx_reqs;
+ data[i++] = adapter->be_stat.bes_tx_fails;
+ data[i++] = adapter->be_stat.bes_fwd_reqs;
+ data[i++] = adapter->be_stat.bes_tx_wrbs;
+
+ data[i++] = adapter->be_stat.bes_ints;
+ data[i++] = adapter->be_stat.bes_events;
+ data[i++] = adapter->be_stat.bes_tx_events;
+ data[i++] = adapter->be_stat.bes_rx_events;
+ data[i++] = adapter->be_stat.bes_tx_compl;
+ data[i++] = adapter->be_stat.bes_rx_compl;
+ data[i++] = adapter->be_stat.bes_ethrx_post_fail;
+ data[i++] = adapter->be_stat.bes_802_3_dropped_frames;
+ data[i++] = adapter->be_stat.bes_802_3_malformed_frames;
+ data[i++] = adapter->be_stat.bes_rx_misc_pkts;
+ data[i++] = adapter->be_stat.bes_eth_tx_rate;
+ data[i++] = adapter->be_stat.bes_eth_rx_rate;
+ data[i++] = adapter->be_stat.bes_rx_coal;
+ data[i++] = adapter->be_stat.bes_rx_flush;
+
+}
+
+static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
+{
+ ecmd->speed = SPEED_10000;
+ ecmd->duplex = DUPLEX_FULL;
+ ecmd->autoneg = AUTONEG_DISABLE;
+ return 0;
+}
+
+/* Get the Ring parameters from the pnob */
+static void
+be_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring)
+{
+ struct be_net_object *pnob = netdev_priv(netdev);
+
+ /* Pre Set Maxims */
+ ring->rx_max_pending = pnob->rx_q_len;
+ ring->rx_mini_max_pending = ring->rx_mini_max_pending;
+ ring->rx_jumbo_max_pending = ring->rx_jumbo_max_pending;
+ ring->tx_max_pending = pnob->tx_q_len;
+
+ /* Current hardware Settings */
+ ring->rx_pending = atomic_read(&pnob->rx_q_posted);
+ ring->rx_mini_pending = ring->rx_mini_pending;
+ ring->rx_jumbo_pending = ring->rx_jumbo_pending;
+ ring->tx_pending = atomic_read(&pnob->tx_q_used);
+
+}
+
+static void
+be_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd)
+{
+ struct be_net_object *pnob = netdev_priv(netdev);
+ bool rxfc, txfc;
+ int status;
+
+ status = be_eth_get_flow_control(&pnob->fn_obj, &txfc, &rxfc);
+ if (status != BE_SUCCESS) {
+ dev_info(&netdev->dev, "Unable to get pause frame settings\n");
+ /* return defaults */
+ ecmd->rx_pause = 1;
+ ecmd->tx_pause = 0;
+ ecmd->autoneg = AUTONEG_ENABLE;
+ return;
+ }
+
+ if (txfc == true)
+ ecmd->tx_pause = 1;
+ else
+ ecmd->tx_pause = 0;
+
+ if (rxfc == true)
+ ecmd->rx_pause = 1;
+ else
+ ecmd->rx_pause = 0;
+
+ ecmd->autoneg = AUTONEG_ENABLE;
+}
+
+static int
+be_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd)
+{
+ struct be_net_object *pnob = netdev_priv(netdev);
+ bool txfc, rxfc;
+ int status;
+
+ if (ecmd->autoneg != AUTONEG_ENABLE)
+ return -EINVAL;
+
+ if (ecmd->tx_pause)
+ txfc = true;
+ else
+ txfc = false;
+
+ if (ecmd->rx_pause)
+ rxfc = true;
+ else
+ rxfc = false;
+
+ status = be_eth_set_flow_control(&pnob->fn_obj, txfc, rxfc);
+ if (status != BE_SUCCESS) {
+ dev_info(&netdev->dev, "Unable to set pause frame settings\n");
+ return -1;
+ }
+ return 0;
+}
+
+struct ethtool_ops be_ethtool_ops = {
+ .get_settings = be_get_settings,
+ .get_drvinfo = be_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ .get_coalesce = be_get_coalesce,
+ .set_coalesce = be_set_coalesce,
+ .get_ringparam = be_get_ringparam,
+ .get_pauseparam = be_get_pauseparam,
+ .set_pauseparam = be_set_pauseparam,
+ .get_rx_csum = be_get_rx_csum,
+ .set_rx_csum = be_set_rx_csum,
+ .get_tx_csum = ethtool_op_get_tx_csum,
+ .set_tx_csum = ethtool_op_set_tx_csum,
+ .get_sg = ethtool_op_get_sg,
+ .set_sg = ethtool_op_set_sg,
+ .get_tso = ethtool_op_get_tso,
+ .set_tso = ethtool_op_set_tso,
+ .get_strings = be_get_strings,
+ .get_stats_count = be_get_stats_count,
+ .get_ethtool_stats = be_get_ethtool_stats,
+};
diff --git a/drivers/staging/benet/be_init.c b/drivers/staging/benet/be_init.c
new file mode 100644
index 000000000000..12a026c3f9e1
--- /dev/null
+++ b/drivers/staging/benet/be_init.c
@@ -0,0 +1,1382 @@
+/*
+ * 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:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+#include <linux/etherdevice.h>
+#include "benet.h"
+
+#define DRVR_VERSION "1.0.728"
+
+static const 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 = 1;
+module_param(msix, uint, S_IRUGO);
+MODULE_PARM_DESC(msix, "Use MSI-x interrupts");
+
+static unsigned int rxbuf_size = 2048; /* Default RX frag size */
+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
+
+/* Bit mask describing events of interest to be traced */
+unsigned int trace_level;
+
+static int
+init_pci_be_function(struct be_adapter *adapter, struct pci_dev *pdev)
+{
+ u64 pa;
+
+ /* CSR */
+ pa = pci_resource_start(pdev, 2);
+ adapter->csr_va = ioremap_nocache(pa, pci_resource_len(pdev, 2));
+ if (adapter->csr_va == NULL)
+ return -ENOMEM;
+
+ /* Door Bell */
+ pa = pci_resource_start(pdev, 4);
+ adapter->db_va = ioremap_nocache(pa, (128 * 1024));
+ if (adapter->db_va == NULL) {
+ iounmap(adapter->csr_va);
+ return -ENOMEM;
+ }
+
+ /* PCI */
+ pa = pci_resource_start(pdev, 1);
+ adapter->pci_va = ioremap_nocache(pa, pci_resource_len(pdev, 1));
+ if (adapter->pci_va == NULL) {
+ iounmap(adapter->csr_va);
+ iounmap(adapter->db_va);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+/*
+ This function enables the interrupt corresponding to the Event
+ queue ID for the given NetObject
+*/
+void be_enable_eq_intr(struct be_net_object *pnob)
+{
+ struct CQ_DB_AMAP cqdb;
+ cqdb.dw[0] = 0;
+ AMAP_SET_BITS_PTR(CQ_DB, event, &cqdb, 1);
+ AMAP_SET_BITS_PTR(CQ_DB, rearm, &cqdb, 1);
+ AMAP_SET_BITS_PTR(CQ_DB, num_popped, &cqdb, 0);
+ AMAP_SET_BITS_PTR(CQ_DB, qid, &cqdb, pnob->event_q_id);
+ PD_WRITE(&pnob->fn_obj, cq_db, cqdb.dw[0]);
+}
+
+/*
+ This function disables the interrupt corresponding to the Event
+ queue ID for the given NetObject
+*/
+void be_disable_eq_intr(struct be_net_object *pnob)
+{
+ struct CQ_DB_AMAP cqdb;
+ cqdb.dw[0] = 0;
+ AMAP_SET_BITS_PTR(CQ_DB, event, &cqdb, 1);
+ AMAP_SET_BITS_PTR(CQ_DB, rearm, &cqdb, 0);
+ AMAP_SET_BITS_PTR(CQ_DB, num_popped, &cqdb, 0);
+ AMAP_SET_BITS_PTR(CQ_DB, qid, &cqdb, pnob->event_q_id);
+ PD_WRITE(&pnob->fn_obj, cq_db, cqdb.dw[0]);
+}
+
+/*
+ This function enables the interrupt from the network function
+ of the BladeEngine. Use the function be_disable_eq_intr()
+ to enable the interrupt from the event queue of only one specific
+ NetObject
+*/
+void be_enable_intr(struct be_net_object *pnob)
+{
+ struct PCICFG_HOST_TIMER_INT_CTRL_CSR_AMAP ctrl;
+ u32 host_intr;
+
+ ctrl.dw[0] = PCICFG1_READ(&pnob->fn_obj, host_timer_int_ctrl);
+ host_intr = AMAP_GET_BITS_PTR(PCICFG_HOST_TIMER_INT_CTRL_CSR,
+ hostintr, ctrl.dw);
+ if (!host_intr) {
+ AMAP_SET_BITS_PTR(PCICFG_HOST_TIMER_INT_CTRL_CSR,
+ hostintr, ctrl.dw, 1);
+ PCICFG1_WRITE(&pnob->fn_obj, host_timer_int_ctrl,
+ ctrl.dw[0]);
+ }
+}
+
+/*
+ This function disables the interrupt from the network function of
+ the BladeEngine. Use the function be_disable_eq_intr() to
+ disable the interrupt from the event queue of only one specific NetObject
+*/
+void be_disable_intr(struct be_net_object *pnob)
+{
+
+ struct PCICFG_HOST_TIMER_INT_CTRL_CSR_AMAP ctrl;
+ u32 host_intr;
+ ctrl.dw[0] = PCICFG1_READ(&pnob->fn_obj, host_timer_int_ctrl);
+ host_intr = AMAP_GET_BITS_PTR(PCICFG_HOST_TIMER_INT_CTRL_CSR,
+ hostintr, ctrl.dw);
+ if (host_intr) {
+ AMAP_SET_BITS_PTR(PCICFG_HOST_TIMER_INT_CTRL_CSR, hostintr,
+ ctrl.dw, 0);
+ PCICFG1_WRITE(&pnob->fn_obj, host_timer_int_ctrl,
+ ctrl.dw[0]);
+ }
+}
+
+static int be_enable_msix(struct be_adapter *adapter)
+{
+ int i, ret;
+
+ if (!msix)
+ return -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 == 0)
+ adapter->msix_enabled = 1;
+ return ret;
+}
+
+static int be_register_isr(struct be_adapter *adapter,
+ struct be_net_object *pnob)
+{
+ struct net_device *netdev = pnob->netdev;
+ int intx = 0, r;
+
+ netdev->irq = adapter->pdev->irq;
+ r = be_enable_msix(adapter);
+
+ if (r == 0) {
+ 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);
+ intx = 1;
+ pci_disable_msix(adapter->pdev);
+ adapter->msix_enabled = 0;
+ }
+ } else {
+ intx = 1;
+ }
+
+ if (intx) {
+ r = request_irq(netdev->irq, be_int, IRQF_SHARED,
+ netdev->name, netdev);
+ if (r) {
+ printk(KERN_WARNING
+ "INTx Request IRQ failed - Errno %d\n", r);
+ return -1;
+ }
+ }
+ adapter->isr_registered = 1;
+ return 0;
+}
+
+static void be_unregister_isr(struct be_adapter *adapter)
+{
+ struct net_device *netdev = adapter->netdevp;
+ if (adapter->isr_registered) {
+ if (adapter->msix_enabled) {
+ free_irq(adapter->msix_entries[0].vector, netdev);
+ pci_disable_msix(adapter->pdev);
+ adapter->msix_enabled = 0;
+ } else {
+ free_irq(netdev->irq, netdev);
+ }
+ adapter->isr_registered = 0;
+ }
+}
+
+/*
+ This function processes the Flush Completions that are issued by the
+ ARM F/W, when a Recv Ring is destroyed. A flush completion is
+ identified when a Rx COmpl descriptor has the tcpcksum and udpcksum
+ set and the pktsize is 32. These completions are received on the
+ Rx Completion Queue.
+*/
+static u32 be_process_rx_flush_cmpl(struct be_net_object *pnob)
+{
+ struct ETH_RX_COMPL_AMAP *rxcp;
+ unsigned int i = 0;
+ while ((rxcp = be_get_rx_cmpl(pnob)) != NULL) {
+ be_notify_cmpl(pnob, 1, pnob->rx_cq_id, 1);
+ i++;
+ }
+ return i;
+}
+
+static void be_tx_q_clean(struct be_net_object *pnob)
+{
+ while (atomic_read(&pnob->tx_q_used))
+ process_one_tx_compl(pnob, tx_compl_lastwrb_idx_get(pnob));
+}
+
+static void be_rx_q_clean(struct be_net_object *pnob)
+{
+ if (pnob->rx_ctxt) {
+ int i;
+ struct be_rx_page_info *rx_page_info;
+ for (i = 0; i < pnob->rx_q_len; i++) {
+ rx_page_info = &(pnob->rx_page_info[i]);
+ if (!pnob->rx_pg_shared || rx_page_info->page_offset) {
+ pci_unmap_page(pnob->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));
+ }
+ pnob->rx_pg_info_hd = 0;
+ }
+}
+
+static void be_destroy_netobj(struct be_net_object *pnob)
+{
+ int status;
+
+ if (pnob->tx_q_created) {
+ status = be_eth_sq_destroy(&pnob->tx_q_obj);
+ pnob->tx_q_created = 0;
+ }
+
+ if (pnob->rx_q_created) {
+ status = be_eth_rq_destroy(&pnob->rx_q_obj);
+ if (status != 0) {
+ status = be_eth_rq_destroy_options(&pnob->rx_q_obj, 0,
+ NULL, NULL);
+ BUG_ON(status);
+ }
+ pnob->rx_q_created = 0;
+ }
+
+ be_process_rx_flush_cmpl(pnob);
+
+ if (pnob->tx_cq_created) {
+ status = be_cq_destroy(&pnob->tx_cq_obj);
+ pnob->tx_cq_created = 0;
+ }
+
+ if (pnob->rx_cq_created) {
+ status = be_cq_destroy(&pnob->rx_cq_obj);
+ pnob->rx_cq_created = 0;
+ }
+
+ if (pnob->mcc_q_created) {
+ status = be_mcc_ring_destroy(&pnob->mcc_q_obj);
+ pnob->mcc_q_created = 0;
+ }
+ if (pnob->mcc_cq_created) {
+ status = be_cq_destroy(&pnob->mcc_cq_obj);
+ pnob->mcc_cq_created = 0;
+ }
+
+ if (pnob->event_q_created) {
+ status = be_eq_destroy(&pnob->event_q_obj);
+ pnob->event_q_created = 0;
+ }
+ be_function_cleanup(&pnob->fn_obj);
+}
+
+/*
+ * 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 be_net_object *pnob)
+{
+ struct net_device *netdev = adapter->netdevp;
+
+ if (netif_running(netdev)) {
+ netif_stop_queue(netdev);
+ be_wait_nic_tx_cmplx_cmpl(pnob);
+ be_disable_eq_intr(pnob);
+ }
+
+ be_unregister_isr(adapter);
+
+ if (adapter->tasklet_started) {
+ tasklet_kill(&(adapter->sts_handler));
+ adapter->tasklet_started = 0;
+ }
+ if (pnob->fn_obj_created)
+ be_disable_intr(pnob);
+
+ if (adapter->dev_state != BE_DEV_STATE_NONE)
+ unregister_netdev(netdev);
+
+ if (pnob->fn_obj_created)
+ be_destroy_netobj(pnob);
+
+ adapter->net_obj = NULL;
+ adapter->netdevp = NULL;
+
+ be_rx_q_clean(pnob);
+ if (pnob->rx_ctxt) {
+ kfree(pnob->rx_page_info);
+ kfree(pnob->rx_ctxt);
+ }
+
+ be_tx_q_clean(pnob);
+ kfree(pnob->tx_ctxt);
+
+ 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->rx_q)
+ pci_free_consistent(adapter->pdev, pnob->rx_q_size,
+ pnob->rx_q, pnob->rx_q_bus);
+
+ if (pnob->rx_cq)
+ pci_free_consistent(adapter->pdev, pnob->rx_cq_size,
+ pnob->rx_cq, pnob->rx_cq_bus);
+
+
+ if (pnob->mb_ptr)
+ pci_free_consistent(adapter->pdev, pnob->mb_size, pnob->mb_ptr,
+ pnob->mb_bus);
+
+ free_netdev(netdev);
+}
+
+
+static int be_nob_ring_alloc(struct be_adapter *adapter,
+ struct be_net_object *pnob)
+{
+ u32 size;
+
+ /* Mail box rd; 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);
+ pnob->mb_rd.va = PTR_ALIGN(pnob->mb_ptr, 16);
+ pnob->mb_rd.pa = PTR_ALIGN(pnob->mb_bus, 16);
+ pnob->mb_rd.length = sizeof(struct MCC_MAILBOX_AMAP);
+ /*
+ * 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;
+ memset(pnob->event_q, 0, pnob->event_q_size);
+ /*
+ * 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;
+ memset(pnob->tx_q, 0, pnob->tx_q_size);
+ /*
+ * 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;
+ memset(pnob->tx_cq, 0, pnob->tx_cq_size);
+ /*
+ * 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;
+ memset(pnob->rx_q, 0, pnob->rx_q_size);
+ /*
+ * Eth Unicast RX Compl queue
+ */
+ pnob->rx_cq_len = ETH_UC_RXCQ_LEN;
+ pnob->rx_cq_size = pnob->rx_cq_len *
+ sizeof(struct ETH_RX_COMPL_AMAP);
+ pnob->rx_cq = pci_alloc_consistent(adapter->pdev, pnob->rx_cq_size,
+ &pnob->rx_cq_bus);
+ if (!pnob->rx_cq_bus)
+ return -1;
+ memset(pnob->rx_cq, 0, pnob->rx_cq_size);
+
+ /* TX resources */
+ size = pnob->tx_q_len * sizeof(void **);
+ pnob->tx_ctxt = kzalloc(size, GFP_KERNEL);
+ if (pnob->tx_ctxt == NULL)
+ return -1;
+
+ /* RX resources */
+ size = pnob->rx_q_len * sizeof(void *);
+ pnob->rx_ctxt = kzalloc(size, GFP_KERNEL);
+ if (pnob->rx_ctxt == NULL)
+ return -1;
+
+ size = (pnob->rx_q_len * sizeof(struct be_rx_page_info));
+ pnob->rx_page_info = kzalloc(size, GFP_KERNEL);
+ if (pnob->rx_page_info == NULL)
+ return -1;
+
+ adapter->eth_statsp = kzalloc(sizeof(struct FWCMD_ETH_GET_STATISTICS),
+ GFP_KERNEL);
+ if (adapter->eth_statsp == NULL)
+ return -1;
+ pnob->rx_buf_size = rxbuf_size;
+ return 0;
+}
+
+/*
+ This function initializes the be_net_object for subsequent
+ network operations.
+
+ Before calling this function, the driver must have allocated
+ space for the NetObject structure, initialized the structure,
+ allocated DMAable memory for all the network queues that form
+ part of the NetObject and populated the start address (virtual)
+ and number of entries allocated for each queue in the NetObject structure.
+
+ The driver must also have allocated memory to hold the
+ mailbox structure (MCC_MAILBOX) and post the physical address,
+ virtual addresses and the size of the mailbox memory in the
+ NetObj.mb_rd. This structure is used by BECLIB for
+ initial communication with the embedded MCC processor. BECLIB
+ uses the mailbox until MCC rings are created for more efficient
+ communication with the MCC processor.
+
+ If the driver wants to create multiple network interface for more
+ than one protection domain, it can call be_create_netobj()
+ multiple times once for each protection domain. A Maximum of
+ 32 protection domains are supported.
+
+*/
+static int
+be_create_netobj(struct be_net_object *pnob, u8 __iomem *csr_va,
+ u8 __iomem *db_va, u8 __iomem *pci_va)
+{
+ int status = 0;
+ bool eventable = false, tx_no_delay = false, rx_no_delay = false;
+ struct be_eq_object *eq_objectp = NULL;
+ struct be_function_object *pfob = &pnob->fn_obj;
+ struct ring_desc rd;
+ u32 set_rxbuf_size;
+ u32 tx_cmpl_wm = CEV_WMARK_96; /* 0xffffffff to disable */
+ u32 rx_cmpl_wm = CEV_WMARK_160; /* 0xffffffff to disable */
+ u32 eq_delay = 0; /* delay in 8usec units. 0xffffffff to disable */
+
+ memset(&rd, 0, sizeof(struct ring_desc));
+
+ status = be_function_object_create(csr_va, db_va, pci_va,
+ BE_FUNCTION_TYPE_NETWORK, &pnob->mb_rd, pfob);
+ if (status != BE_SUCCESS)
+ return status;
+ pnob->fn_obj_created = true;
+
+ if (tx_cmpl_wm == 0xffffffff)
+ tx_no_delay = true;
+ if (rx_cmpl_wm == 0xffffffff)
+ rx_no_delay = true;
+ /*
+ * now create the necessary rings
+ * Event Queue first.
+ */
+ if (pnob->event_q_len) {
+ rd.va = pnob->event_q;
+ rd.pa = pnob->event_q_bus;
+ rd.length = pnob->event_q_size;
+
+ status = be_eq_create(pfob, &rd, 4, pnob->event_q_len,
+ (u32) -1, /* CEV_WMARK_* or -1 */
+ eq_delay, /* in 8us units, or -1 */
+ &pnob->event_q_obj);
+ if (status != BE_SUCCESS)
+ goto error_ret;
+ pnob->event_q_id = pnob->event_q_obj.eq_id;
+ pnob->event_q_created = 1;
+ eventable = true;
+ eq_objectp = &pnob->event_q_obj;
+ }
+ /*
+ * Now Eth Tx Compl. queue.
+ */
+ if (pnob->txcq_len) {
+ rd.va = pnob->tx_cq;
+ rd.pa = pnob->tx_cq_bus;
+ rd.length = pnob->tx_cq_size;
+
+ status = be_cq_create(pfob, &rd,
+ pnob->txcq_len * sizeof(struct ETH_TX_COMPL_AMAP),
+ false, /* solicted events, */
+ tx_no_delay, /* nodelay */
+ tx_cmpl_wm, /* Watermark encodings */
+ eq_objectp, &pnob->tx_cq_obj);
+ if (status != BE_SUCCESS)
+ goto error_ret;
+
+ pnob->tx_cq_id = pnob->tx_cq_obj.cq_id;
+ pnob->tx_cq_created = 1;
+ }
+ /*
+ * Eth Tx queue
+ */
+ if (pnob->tx_q_len) {
+ struct be_eth_sq_parameters ex_params = { 0 };
+ u32 type;
+
+ if (pnob->tx_q_port) {
+ /* TXQ to be bound to a specific port */
+ type = BE_ETH_TX_RING_TYPE_BOUND;
+ ex_params.port = pnob->tx_q_port - 1;
+ } else
+ type = BE_ETH_TX_RING_TYPE_STANDARD;
+
+ rd.va = pnob->tx_q;
+ rd.pa = pnob->tx_q_bus;
+ rd.length = pnob->tx_q_size;
+
+ status = be_eth_sq_create_ex(pfob, &rd,
+ pnob->tx_q_len * sizeof(struct ETH_WRB_AMAP),
+ type, 2, &pnob->tx_cq_obj,
+ &ex_params, &pnob->tx_q_obj);
+
+ if (status != BE_SUCCESS)
+ goto error_ret;
+
+ pnob->tx_q_id = pnob->tx_q_obj.bid;
+ pnob->tx_q_created = 1;
+ }
+ /*
+ * Now Eth Rx compl. queue. Always needed.
+ */
+ rd.va = pnob->rx_cq;
+ rd.pa = pnob->rx_cq_bus;
+ rd.length = pnob->rx_cq_size;
+
+ status = be_cq_create(pfob, &rd,
+ pnob->rx_cq_len * sizeof(struct ETH_RX_COMPL_AMAP),
+ false, /* solicted events, */
+ rx_no_delay, /* nodelay */
+ rx_cmpl_wm, /* Watermark encodings */
+ eq_objectp, &pnob->rx_cq_obj);
+ if (status != BE_SUCCESS)
+ goto error_ret;
+
+ pnob->rx_cq_id = pnob->rx_cq_obj.cq_id;
+ pnob->rx_cq_created = 1;
+
+ status = be_eth_rq_set_frag_size(pfob, pnob->rx_buf_size,
+ (u32 *) &set_rxbuf_size);
+ if (status != BE_SUCCESS) {
+ be_eth_rq_get_frag_size(pfob, (u32 *) &pnob->rx_buf_size);
+ if ((pnob->rx_buf_size != 2048) && (pnob->rx_buf_size != 4096)
+ && (pnob->rx_buf_size != 8192))
+ goto error_ret;
+ } else {
+ if (pnob->rx_buf_size != set_rxbuf_size)
+ pnob->rx_buf_size = set_rxbuf_size;
+ }
+ /*
+ * Eth RX queue. be_eth_rq_create() always assumes 2 pages size
+ */
+ rd.va = pnob->rx_q;
+ rd.pa = pnob->rx_q_bus;
+ rd.length = pnob->rx_q_size;
+
+ status = be_eth_rq_create(pfob, &rd, &pnob->rx_cq_obj,
+ &pnob->rx_cq_obj, &pnob->rx_q_obj);
+
+ if (status != BE_SUCCESS)
+ goto error_ret;
+
+ pnob->rx_q_id = pnob->rx_q_obj.rid;
+ pnob->rx_q_created = 1;
+
+ return BE_SUCCESS; /* All required queues created. */
+
+error_ret:
+ be_destroy_netobj(pnob);
+ return status;
+}
+
+static int be_nob_ring_init(struct be_adapter *adapter,
+ struct be_net_object *pnob)
+{
+ int status;
+
+ pnob->event_q_tl = 0;
+
+ pnob->tx_q_hd = 0;
+ pnob->tx_q_tl = 0;
+
+ pnob->tx_cq_tl = 0;
+
+ pnob->rx_cq_tl = 0;
+
+ memset(pnob->event_q, 0, pnob->event_q_size);
+ memset(pnob->tx_cq, 0, pnob->tx_cq_size);
+ memset(pnob->tx_ctxt, 0, pnob->tx_q_len * sizeof(void **));
+ memset(pnob->rx_ctxt, 0, pnob->rx_q_len * sizeof(void *));
+ pnob->rx_pg_info_hd = 0;
+ pnob->rx_q_hd = 0;
+ atomic_set(&pnob->rx_q_posted, 0);
+
+ status = be_create_netobj(pnob, adapter->csr_va, adapter->db_va,
+ adapter->pci_va);
+ 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 be_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 = 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);
+ dev_info(&netdev->dev, "Link Properties:\n");
+ 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 be_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;
+}
+
+/*
+ This function creates the MCC request and completion ring required
+ for communicating with the ARM processor. The caller must have
+ allocated required amount of memory for the MCC ring and MCC
+ completion ring and posted the virtual address and number of
+ entries in the corresponding members (mcc_q and mcc_cq) in the
+ NetObject struture.
+
+ When this call is completed, all further communication with
+ ARM will switch from mailbox to this ring.
+
+ pnob - Pointer to the NetObject structure. This NetObject should
+ have been created using a previous call to be_create_netobj()
+*/
+int be_create_mcc_rings(struct be_net_object *pnob)
+{
+ int status = 0;
+ struct ring_desc rd;
+ struct be_function_object *pfob = &pnob->fn_obj;
+
+ memset(&rd, 0, sizeof(struct ring_desc));
+ if (pnob->mcc_cq_len) {
+ rd.va = pnob->mcc_cq;
+ rd.pa = pnob->mcc_cq_bus;
+ rd.length = pnob->mcc_cq_size;
+
+ status = be_cq_create(pfob, &rd,
+ pnob->mcc_cq_len * sizeof(struct MCC_CQ_ENTRY_AMAP),
+ false, /* solicted events, */
+ true, /* nodelay */
+ 0, /* 0 Watermark since Nodelay is true */
+ &pnob->event_q_obj,
+ &pnob->mcc_cq_obj);
+
+ if (status != BE_SUCCESS)
+ return status;
+
+ pnob->mcc_cq_id = pnob->mcc_cq_obj.cq_id;
+ pnob->mcc_cq_created = 1;
+ }
+ if (pnob->mcc_q_len) {
+ rd.va = pnob->mcc_q;
+ rd.pa = pnob->mcc_q_bus;
+ rd.length = pnob->mcc_q_size;
+
+ status = be_mcc_ring_create(pfob, &rd,
+ pnob->mcc_q_len * sizeof(struct MCC_WRB_AMAP),
+ pnob->mcc_wrb_ctxt, pnob->mcc_wrb_ctxtLen,
+ &pnob->mcc_cq_obj, &pnob->mcc_q_obj);
+
+ if (status != BE_SUCCESS)
+ return status;
+
+ pnob->mcc_q_created = 1;
+ }
+ return BE_SUCCESS;
+}
+
+static int be_mcc_init(struct be_adapter *adapter)
+{
+ u32 r;
+ struct be_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 = be_create_mcc_rings(adapter->net_obj);
+ if (r != BE_SUCCESS)
+ return -1;
+
+ return 0;
+}
+
+static void be_remove(struct pci_dev *pdev)
+{
+ struct be_net_object *pnob;
+ struct be_adapter *adapter;
+
+ adapter = pci_get_drvdata(pdev);
+ if (!adapter)
+ return;
+
+ pci_set_drvdata(pdev, NULL);
+ pnob = (struct be_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);
+ }
+
+ if (adapter->csr_va)
+ iounmap(adapter->csr_va);
+ if (adapter->db_va)
+ iounmap(adapter->db_va);
+ if (adapter->pci_va)
+ iounmap(adapter->pci_va);
+
+ pci_release_regions(adapter->pdev);
+ pci_disable_device(adapter->pdev);
+
+ kfree(adapter->be_link_sts);
+ 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;
+ struct FWCMD_COMMON_GET_FW_VERSION_RESPONSE_PAYLOAD get_fwv;
+ struct be_net_object *pnob;
+ struct net_device *netdev;
+
+ status = pci_enable_device(pdev);
+ if (status)
+ goto error;
+
+ status = pci_request_regions(pdev, be_driver_name);
+ if (status)
+ goto error_pci_req;
+
+ pci_set_master(pdev);
+ adapter = kzalloc(sizeof(struct be_adapter), GFP_KERNEL);
+ if (adapter == NULL) {
+ status = -ENOMEM;
+ goto error_adapter;
+ }
+ adapter->dev_state = BE_DEV_STATE_NONE;
+ adapter->pdev = pdev;
+ pci_set_drvdata(pdev, adapter);
+
+ 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) {
+ 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;
+ }
+
+ be_trace_set_level(DL_ALWAYS | DL_ERR);
+
+ adapter->be_link_sts = 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);
+
+ netdev = alloc_etherdev(sizeof(struct be_net_object));
+ if (netdev == NULL) {
+ status = -ENOMEM;
+ goto cleanup;
+ }
+ pnob = netdev_priv(netdev);
+ adapter->net_obj = pnob;
+ adapter->netdevp = netdev;
+ pnob->adapter = adapter;
+ pnob->netdev = netdev;
+
+ status = be_nob_ring_alloc(adapter, pnob);
+ if (status != 0)
+ goto cleanup;
+
+ status = be_nob_ring_init(adapter, pnob);
+ if (status != 0)
+ goto cleanup;
+
+ be_rxf_mac_address_read_write(&pnob->fn_obj, false, false, false,
+ false, false, netdev->dev_addr, NULL, NULL);
+
+ netdev->init = &benet_init;
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+
+ SET_NETDEV_DEV(netdev, &(adapter->pdev->dev));
+
+ netif_napi_add(netdev, &pnob->napi, be_poll, 64);
+
+ /* if the rx_frag size if 2K, one page is shared as two RX frags */
+ pnob->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;
+ spin_lock_init(&(adapter->int_lock));
+
+ status = be_register_isr(adapter, pnob);
+ if (status != 0)
+ goto cleanup;
+
+ 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;
+
+
+ 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");
+ }
+
+ status = register_netdev(netdev);
+ if (status != 0)
+ goto cleanup;
+ be_update_link_status(adapter);
+ adapter->dev_state = BE_DEV_STATE_INIT;
+ return 0;
+
+cleanup:
+ be_remove(pdev);
+ return status;
+error_adapter:
+ pci_release_regions(pdev);
+error_pci_req:
+ pci_disable_device(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 be_net_object *pnob = adapter->net_obj;
+
+ status = be_rxf_link_status(&pnob->fn_obj, adapter->be_link_sts, NULL,
+ 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;
+
+ dev_info(&pnob->netdev->dev, "Link Properties:\n");
+ be_print_link_info(adapter->be_link_sts);
+ return;
+ }
+ dev_info(&pnob->netdev->dev, "Could not get link status\n");
+ return;
+}
+
+
+#ifdef CONFIG_PM
+static void
+be_pm_cleanup(struct be_adapter *adapter,
+ struct be_net_object *pnob, struct net_device *netdev)
+{
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+
+ be_wait_nic_tx_cmplx_cmpl(pnob);
+ be_disable_eq_intr(pnob);
+
+ if (adapter->tasklet_started) {
+ tasklet_kill(&adapter->sts_handler);
+ adapter->tasklet_started = 0;
+ }
+
+ be_unregister_isr(adapter);
+ be_disable_intr(pnob);
+
+ be_tx_q_clean(pnob);
+ be_rx_q_clean(pnob);
+
+ be_destroy_netobj(pnob);
+}
+
+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 be_net_object *pnob = netdev_priv(netdev);
+
+ adapter->dev_pm_state = adapter->dev_state;
+ adapter->dev_state = BE_DEV_STATE_SUSPEND;
+
+ 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 be_net_object *pnob = adapter->net_obj;
+
+ if (pnob->num_vlans != 0)
+ be_rxf_vlan_config(&pnob->fn_obj, false, pnob->num_vlans,
+ pnob->vlan_tag, NULL, NULL, NULL);
+
+}
+
+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 be_net_object *pnob = netdev_priv(netdev);
+
+ 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)) {
+ be_rxf_mac_address_read_write(&pnob->fn_obj, false, false,
+ false, true, false, netdev->dev_addr, NULL, NULL);
+
+ status = be_nob_ring_init(adapter, pnob);
+ if (status < 0)
+ return status;
+
+ tasklet_init(&(adapter->sts_handler), be_process_intr,
+ (unsigned long)adapter);
+ adapter->tasklet_started = 1;
+
+ if (be_register_isr(adapter, pnob) != 0) {
+ printk(KERN_ERR "be_register_isr failed\n");
+ return status;
+ }
+
+
+ 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");
+ }
+ be_enable_intr(pnob);
+ be_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 be_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/staging/benet/be_int.c b/drivers/staging/benet/be_int.c
new file mode 100644
index 000000000000..cba95d09a8b6
--- /dev/null
+++ b/drivers/staging/benet/be_int.c
@@ -0,0 +1,863 @@
+/*
+ * 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:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+#include <linux/if_vlan.h>
+#include <linux/inet_lro.h>
+
+#include "benet.h"
+
+/* number of bytes of RX frame that are copied to skb->data */
+#define BE_HDR_LEN 64
+
+#define NETIF_RX(skb) netif_receive_skb(skb)
+#define VLAN_ACCEL_RX(skb, pnob, vt) \
+ vlan_hwaccel_rx(skb, pnob->vlan_grp, vt)
+
+/*
+ This function notifies BladeEngine of the number of completion
+ entries processed from the specified completion queue by writing
+ the number of popped entries to the door bell.
+
+ pnob - Pointer to the NetObject structure
+ n - Number of completion entries processed
+ cq_id - Queue ID of the completion queue for which notification
+ is being done.
+ re_arm - 1 - rearm the completion ring to generate an event.
+ - 0 - dont rearm the completion ring to generate an event
+*/
+void be_notify_cmpl(struct be_net_object *pnob, int n, int cq_id, int re_arm)
+{
+ struct CQ_DB_AMAP cqdb;
+
+ cqdb.dw[0] = 0;
+ AMAP_SET_BITS_PTR(CQ_DB, qid, &cqdb, cq_id);
+ AMAP_SET_BITS_PTR(CQ_DB, rearm, &cqdb, re_arm);
+ AMAP_SET_BITS_PTR(CQ_DB, num_popped, &cqdb, n);
+ PD_WRITE(&pnob->fn_obj, cq_db, cqdb.dw[0]);
+}
+
+/*
+ * adds additional receive frags indicated by BE starting from given
+ * frag index (fi) to specified skb's frag list
+ */
+static void
+add_skb_frags(struct be_net_object *pnob, struct sk_buff *skb,
+ u32 nresid, u32 fi)
+{
+ struct be_adapter *adapter = pnob->adapter;
+ u32 sk_frag_idx, n;
+ struct be_rx_page_info *rx_page_info;
+ u32 frag_sz = pnob->rx_buf_size;
+
+ sk_frag_idx = skb_shinfo(skb)->nr_frags;
+ while (nresid) {
+ index_inc(&fi, pnob->rx_q_len);
+
+ rx_page_info = (struct be_rx_page_info *)pnob->rx_ctxt[fi];
+ pnob->rx_ctxt[fi] = NULL;
+ if ((rx_page_info->page_offset) ||
+ (pnob->rx_pg_shared == false)) {
+ pci_unmap_page(adapter->pdev,
+ pci_unmap_addr(rx_page_info, bus),
+ frag_sz, PCI_DMA_FROMDEVICE);
+ }
+
+ n = min(nresid, frag_sz);
+ skb_shinfo(skb)->frags[sk_frag_idx].page = rx_page_info->page;
+ skb_shinfo(skb)->frags[sk_frag_idx].page_offset
+ = rx_page_info->page_offset;
+ skb_shinfo(skb)->frags[sk_frag_idx].size = n;
+
+ sk_frag_idx++;
+ skb->len += n;
+ skb->data_len += n;
+ skb_shinfo(skb)->nr_frags++;
+ nresid -= n;
+
+ memset(rx_page_info, 0, sizeof(struct be_rx_page_info));
+ atomic_dec(&pnob->rx_q_posted);
+ }
+}
+
+/*
+ * This function processes incoming nic packets over various Rx queues.
+ * This function takes the adapter, the current Rx status descriptor
+ * entry and the Rx completion queue ID as argument.
+ */
+static inline int process_nic_rx_completion(struct be_net_object *pnob,
+ struct ETH_RX_COMPL_AMAP *rxcp)
+{
+ struct be_adapter *adapter = pnob->adapter;
+ struct sk_buff *skb;
+ int udpcksm, tcpcksm;
+ int n;
+ u32 nresid, fi;
+ u32 frag_sz = pnob->rx_buf_size;
+ u8 *va;
+ struct be_rx_page_info *rx_page_info;
+ u32 numfrags, vtp, vtm, vlan_tag, pktsize;
+
+ fi = AMAP_GET_BITS_PTR(ETH_RX_COMPL, fragndx, rxcp);
+ BUG_ON(fi >= (int)pnob->rx_q_len);
+ BUG_ON(fi < 0);
+
+ rx_page_info = (struct be_rx_page_info *)pnob->rx_ctxt[fi];
+ BUG_ON(!rx_page_info->page);
+ pnob->rx_ctxt[fi] = NULL;
+
+ /*
+ * If one page is used per fragment or if this is the second half of
+ * of the page, unmap the page here
+ */
+ if ((rx_page_info->page_offset) || (pnob->rx_pg_shared == false)) {
+ pci_unmap_page(adapter->pdev,
+ pci_unmap_addr(rx_page_info, bus), frag_sz,
+ PCI_DMA_FROMDEVICE);
+ }
+
+ atomic_dec(&pnob->rx_q_posted);
+ udpcksm = AMAP_GET_BITS_PTR(ETH_RX_COMPL, udpcksm, rxcp);
+ tcpcksm = AMAP_GET_BITS_PTR(ETH_RX_COMPL, tcpcksm, rxcp);
+ pktsize = AMAP_GET_BITS_PTR(ETH_RX_COMPL, pktsize, rxcp);
+ /*
+ * get rid of RX flush completions first.
+ */
+ if ((tcpcksm) && (udpcksm) && (pktsize == 32)) {
+ put_page(rx_page_info->page);
+ memset(rx_page_info, 0, sizeof(struct be_rx_page_info));
+ return 0;
+ }
+ skb = netdev_alloc_skb(pnob->netdev, BE_HDR_LEN + NET_IP_ALIGN);
+ if (skb == NULL) {
+ dev_info(&pnob->netdev->dev, "alloc_skb() failed\n");
+ put_page(rx_page_info->page);
+ memset(rx_page_info, 0, sizeof(struct be_rx_page_info));
+ goto free_frags;
+ }
+ skb_reserve(skb, NET_IP_ALIGN);
+
+ skb->dev = pnob->netdev;
+
+ n = min(pktsize, frag_sz);
+
+ va = page_address(rx_page_info->page) + rx_page_info->page_offset;
+ prefetch(va);
+
+ skb->len = n;
+ skb->data_len = n;
+ if (n <= BE_HDR_LEN) {
+ memcpy(skb->data, va, n);
+ put_page(rx_page_info->page);
+ skb->data_len -= n;
+ skb->tail += n;
+ } else {
+
+ /* Setup the SKB with page buffer information */
+ skb_shinfo(skb)->frags[0].page = rx_page_info->page;
+ skb_shinfo(skb)->nr_frags++;
+
+ /* Copy the header into the skb_data */
+ memcpy(skb->data, va, BE_HDR_LEN);
+ skb_shinfo(skb)->frags[0].page_offset =
+ rx_page_info->page_offset + BE_HDR_LEN;
+ skb_shinfo(skb)->frags[0].size = n - BE_HDR_LEN;
+ skb->data_len -= BE_HDR_LEN;
+ skb->tail += BE_HDR_LEN;
+ }
+ memset(rx_page_info, 0, sizeof(struct be_rx_page_info));
+ nresid = pktsize - n;
+
+ skb->protocol = eth_type_trans(skb, pnob->netdev);
+
+ if ((tcpcksm || udpcksm) && adapter->rx_csum)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ else
+ skb->ip_summed = CHECKSUM_NONE;
+ /*
+ * if we have more bytes left, the frame has been
+ * given to us in multiple fragments. This happens
+ * with Jumbo frames. Add the remaining fragments to
+ * skb->frags[] array.
+ */
+ if (nresid)
+ add_skb_frags(pnob, skb, nresid, fi);
+
+ /* update the the true size of the skb. */
+ skb->truesize = skb->len + sizeof(struct sk_buff);
+
+ /*
+ * If a 802.3 frame or 802.2 LLC frame
+ * (i.e) contains length field in MAC Hdr
+ * and frame len is greater than 64 bytes
+ */
+ if (((skb->protocol == ntohs(ETH_P_802_2)) ||
+ (skb->protocol == ntohs(ETH_P_802_3)))
+ && (pktsize > BE_HDR_LEN)) {
+ /*
+ * If the length given in Mac Hdr is less than frame size
+ * Erraneous frame, Drop it
+ */
+ if ((ntohs(*(u16 *) (va + 12)) + ETH_HLEN) < pktsize) {
+ /* Increment Non Ether type II frames dropped */
+ adapter->be_stat.bes_802_3_dropped_frames++;
+
+ kfree_skb(skb);
+ return 0;
+ }
+ /*
+ * else if the length given in Mac Hdr is greater than
+ * frame size, should not be seeing this sort of frames
+ * dump the pkt and pass to stack
+ */
+ else if ((ntohs(*(u16 *) (va + 12)) + ETH_HLEN) > pktsize) {
+ /* Increment Non Ether type II frames malformed */
+ adapter->be_stat.bes_802_3_malformed_frames++;
+ }
+ }
+
+ vtp = AMAP_GET_BITS_PTR(ETH_RX_COMPL, vtp, rxcp);
+ vtm = AMAP_GET_BITS_PTR(ETH_RX_COMPL, vtm, rxcp);
+ if (vtp && vtm) {
+ /* Vlan tag present in pkt and BE found
+ * that the tag matched an entry in VLAN table
+ */
+ if (!pnob->vlan_grp || pnob->num_vlans == 0) {
+ /* But we have no VLANs configured.
+ * This should never happen. Drop the packet.
+ */
+ dev_info(&pnob->netdev->dev,
+ "BladeEngine: Unexpected vlan tagged packet\n");
+ kfree_skb(skb);
+ return 0;
+ }
+ /* pass the VLAN packet to stack */
+ vlan_tag = AMAP_GET_BITS_PTR(ETH_RX_COMPL, vlan_tag, rxcp);
+ VLAN_ACCEL_RX(skb, pnob, be16_to_cpu(vlan_tag));
+
+ } else {
+ NETIF_RX(skb);
+ }
+ return 0;
+
+free_frags:
+ /* free all frags associated with the current rxcp */
+ numfrags = AMAP_GET_BITS_PTR(ETH_RX_COMPL, numfrags, rxcp);
+ while (numfrags-- > 1) {
+ index_inc(&fi, pnob->rx_q_len);
+
+ rx_page_info = (struct be_rx_page_info *)
+ pnob->rx_ctxt[fi];
+ pnob->rx_ctxt[fi] = (void *)NULL;
+ if (rx_page_info->page_offset || !pnob->rx_pg_shared) {
+ pci_unmap_page(adapter->pdev,
+ pci_unmap_addr(rx_page_info, bus),
+ frag_sz, PCI_DMA_FROMDEVICE);
+ }
+
+ put_page(rx_page_info->page);
+ memset(rx_page_info, 0, sizeof(struct be_rx_page_info));
+ atomic_dec(&pnob->rx_q_posted);
+ }
+ return -ENOMEM;
+}
+
+static void process_nic_rx_completion_lro(struct be_net_object *pnob,
+ struct ETH_RX_COMPL_AMAP *rxcp)
+{
+ struct be_adapter *adapter = pnob->adapter;
+ struct skb_frag_struct rx_frags[BE_MAX_FRAGS_PER_FRAME];
+ unsigned int udpcksm, tcpcksm;
+ u32 numfrags, vlanf, vtm, vlan_tag, nresid;
+ u16 vlant;
+ unsigned int fi, idx, n;
+ struct be_rx_page_info *rx_page_info;
+ u32 frag_sz = pnob->rx_buf_size, pktsize;
+ bool rx_coal = (adapter->max_rx_coal <= 1) ? 0 : 1;
+ u8 err, *va;
+ __wsum csum = 0;
+
+ if (AMAP_GET_BITS_PTR(ETH_RX_COMPL, ipsec, rxcp)) {
+ /* Drop the pkt and move to the next completion. */
+ adapter->be_stat.bes_rx_misc_pkts++;
+ return;
+ }
+ err = AMAP_GET_BITS_PTR(ETH_RX_COMPL, err, rxcp);
+ if (err || !rx_coal) {
+ /* We won't coalesce Rx pkts if the err bit set.
+ * take the path of normal completion processing */
+ process_nic_rx_completion(pnob, rxcp);
+ return;
+ }
+
+ fi = AMAP_GET_BITS_PTR(ETH_RX_COMPL, fragndx, rxcp);
+ BUG_ON(fi >= (int)pnob->rx_q_len);
+ BUG_ON(fi < 0);
+ rx_page_info = (struct be_rx_page_info *)pnob->rx_ctxt[fi];
+ BUG_ON(!rx_page_info->page);
+ pnob->rx_ctxt[fi] = (void *)NULL;
+ /* If one page is used per fragment or if this is the
+ * second half of the page, unmap the page here
+ */
+ if (rx_page_info->page_offset || !pnob->rx_pg_shared) {
+ pci_unmap_page(adapter->pdev,
+ pci_unmap_addr(rx_page_info, bus),
+ frag_sz, PCI_DMA_FROMDEVICE);
+ }
+
+ numfrags = AMAP_GET_BITS_PTR(ETH_RX_COMPL, numfrags, rxcp);
+ udpcksm = AMAP_GET_BITS_PTR(ETH_RX_COMPL, udpcksm, rxcp);
+ tcpcksm = AMAP_GET_BITS_PTR(ETH_RX_COMPL, tcpcksm, rxcp);
+ vlan_tag = AMAP_GET_BITS_PTR(ETH_RX_COMPL, vlan_tag, rxcp);
+ vlant = be16_to_cpu(vlan_tag);
+ vlanf = AMAP_GET_BITS_PTR(ETH_RX_COMPL, vtp, rxcp);
+ vtm = AMAP_GET_BITS_PTR(ETH_RX_COMPL, vtm, rxcp);
+ pktsize = AMAP_GET_BITS_PTR(ETH_RX_COMPL, pktsize, rxcp);
+
+ atomic_dec(&pnob->rx_q_posted);
+
+ if (tcpcksm && udpcksm && pktsize == 32) {
+ /* flush completion entries */
+ put_page(rx_page_info->page);
+ memset(rx_page_info, 0, sizeof(struct be_rx_page_info));
+ return;
+ }
+ /* Only one of udpcksum and tcpcksum can be set */
+ BUG_ON(udpcksm && tcpcksm);
+
+ /* jumbo frames could come in multiple fragments */
+ BUG_ON(numfrags != ((pktsize + (frag_sz - 1)) / frag_sz));
+ n = min(pktsize, frag_sz);
+ nresid = pktsize - n; /* will be useful for jumbo pkts */
+ idx = 0;
+
+ va = page_address(rx_page_info->page) + rx_page_info->page_offset;
+ prefetch(va);
+ rx_frags[idx].page = rx_page_info->page;
+ rx_frags[idx].page_offset = (rx_page_info->page_offset);
+ rx_frags[idx].size = n;
+ memset(rx_page_info, 0, sizeof(struct be_rx_page_info));
+
+ /* If we got multiple fragments, we have more data. */
+ while (nresid) {
+ idx++;
+ index_inc(&fi, pnob->rx_q_len);
+
+ rx_page_info = (struct be_rx_page_info *)pnob->rx_ctxt[fi];
+ pnob->rx_ctxt[fi] = (void *)NULL;
+ if (rx_page_info->page_offset || !pnob->rx_pg_shared) {
+ pci_unmap_page(adapter->pdev,
+ pci_unmap_addr(rx_page_info, bus),
+ frag_sz, PCI_DMA_FROMDEVICE);
+ }
+
+ n = min(nresid, frag_sz);
+ rx_frags[idx].page = rx_page_info->page;
+ rx_frags[idx].page_offset = (rx_page_info->page_offset);
+ rx_frags[idx].size = n;
+
+ nresid -= n;
+ memset(rx_page_info, 0, sizeof(struct be_rx_page_info));
+ atomic_dec(&pnob->rx_q_posted);
+ }
+
+ if (likely(!(vlanf && vtm))) {
+ lro_receive_frags(&pnob->lro_mgr, rx_frags,
+ pktsize, pktsize,
+ (void *)(unsigned long)csum, csum);
+ } else {
+ /* Vlan tag present in pkt and BE found
+ * that the tag matched an entry in VLAN table
+ */
+ if (unlikely(!pnob->vlan_grp || pnob->num_vlans == 0)) {
+ /* But we have no VLANs configured.
+ * This should never happen. Drop the packet.
+ */
+ dev_info(&pnob->netdev->dev,
+ "BladeEngine: Unexpected vlan tagged packet\n");
+ return;
+ }
+ /* pass the VLAN packet to stack */
+ lro_vlan_hwaccel_receive_frags(&pnob->lro_mgr,
+ rx_frags, pktsize, pktsize,
+ pnob->vlan_grp, vlant,
+ (void *)(unsigned long)csum,
+ csum);
+ }
+
+ adapter->be_stat.bes_rx_coal++;
+}
+
+struct ETH_RX_COMPL_AMAP *be_get_rx_cmpl(struct be_net_object *pnob)
+{
+ struct ETH_RX_COMPL_AMAP *rxcp = &pnob->rx_cq[pnob->rx_cq_tl];
+ u32 valid, ct;
+
+ valid = AMAP_GET_BITS_PTR(ETH_RX_COMPL, valid, rxcp);
+ if (valid == 0)
+ return NULL;
+
+ ct = AMAP_GET_BITS_PTR(ETH_RX_COMPL, ct, rxcp);
+ if (ct != 0) {
+ /* Invalid chute #. treat as error */
+ AMAP_SET_BITS_PTR(ETH_RX_COMPL, err, rxcp, 1);
+ }
+
+ be_adv_rxcq_tl(pnob);
+ AMAP_SET_BITS_PTR(ETH_RX_COMPL, valid, rxcp, 0);
+ return rxcp;
+}
+
+static 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 */
+
+ /* Mega Bits/Sec */
+ adapter->be_stat.bes_eth_rx_rate = (r * 8);
+ adapter->eth_rx_jiffies = jiffies;
+ adapter->eth_rx_bytes = 0;
+ }
+}
+
+static int process_rx_completions(struct be_net_object *pnob, int max_work)
+{
+ struct be_adapter *adapter = pnob->adapter;
+ struct ETH_RX_COMPL_AMAP *rxcp;
+ u32 nc = 0;
+ unsigned int pktsize;
+
+ while (max_work && (rxcp = be_get_rx_cmpl(pnob))) {
+ prefetch(rxcp);
+ pktsize = AMAP_GET_BITS_PTR(ETH_RX_COMPL, pktsize, rxcp);
+ process_nic_rx_completion_lro(pnob, rxcp);
+ adapter->eth_rx_bytes += pktsize;
+ update_rx_rate(adapter);
+ nc++;
+ max_work--;
+ adapter->be_stat.bes_rx_compl++;
+ }
+ if (likely(adapter->max_rx_coal > 1)) {
+ adapter->be_stat.bes_rx_flush++;
+ lro_flush_all(&pnob->lro_mgr);
+ }
+
+ /* Refill the queue */
+ if (atomic_read(&pnob->rx_q_posted) < 900)
+ be_post_eth_rx_buffs(pnob);
+
+ return nc;
+}
+
+static struct ETH_TX_COMPL_AMAP *be_get_tx_cmpl(struct be_net_object *pnob)
+{
+ struct ETH_TX_COMPL_AMAP *txcp = &pnob->tx_cq[pnob->tx_cq_tl];
+ u32 valid;
+
+ valid = AMAP_GET_BITS_PTR(ETH_TX_COMPL, valid, txcp);
+ if (valid == 0)
+ return NULL;
+
+ AMAP_SET_BITS_PTR(ETH_TX_COMPL, valid, txcp, 0);
+ be_adv_txcq_tl(pnob);
+ return txcp;
+
+}
+
+void process_one_tx_compl(struct be_net_object *pnob, u32 end_idx)
+{
+ struct be_adapter *adapter = pnob->adapter;
+ int cur_index, tx_wrbs_completed = 0;
+ struct sk_buff *skb;
+ u64 busaddr, pa, pa_lo, pa_hi;
+ struct ETH_WRB_AMAP *wrb;
+ u32 frag_len, last_index, j;
+
+ last_index = tx_compl_lastwrb_idx_get(pnob);
+ BUG_ON(last_index != end_idx);
+ pnob->tx_ctxt[pnob->tx_q_tl] = NULL;
+ do {
+ cur_index = pnob->tx_q_tl;
+ wrb = &pnob->tx_q[cur_index];
+ pa_hi = AMAP_GET_BITS_PTR(ETH_WRB, frag_pa_hi, wrb);
+ pa_lo = AMAP_GET_BITS_PTR(ETH_WRB, frag_pa_lo, wrb);
+ frag_len = AMAP_GET_BITS_PTR(ETH_WRB, frag_len, wrb);
+ busaddr = (pa_hi << 32) | pa_lo;
+ if (busaddr != 0) {
+ pa = le64_to_cpu(busaddr);
+ pci_unmap_single(adapter->pdev, pa,
+ frag_len, PCI_DMA_TODEVICE);
+ }
+ if (cur_index == last_index) {
+ skb = (struct sk_buff *)pnob->tx_ctxt[cur_index];
+ BUG_ON(!skb);
+ for (j = 0; j < skb_shinfo(skb)->nr_frags; j++) {
+ struct skb_frag_struct *frag;
+ frag = &skb_shinfo(skb)->frags[j];
+ pci_unmap_page(adapter->pdev,
+ (ulong) frag->page, frag->size,
+ PCI_DMA_TODEVICE);
+ }
+ kfree_skb(skb);
+ pnob->tx_ctxt[cur_index] = NULL;
+ } else {
+ BUG_ON(pnob->tx_ctxt[cur_index]);
+ }
+ tx_wrbs_completed++;
+ be_adv_txq_tl(pnob);
+ } while (cur_index != last_index);
+ atomic_sub(tx_wrbs_completed, &pnob->tx_q_used);
+}
+
+/* there is no need to take an SMP lock here since currently
+ * we have only one instance of the tasklet that does completion
+ * processing.
+ */
+static void process_nic_tx_completions(struct be_net_object *pnob)
+{
+ struct be_adapter *adapter = pnob->adapter;
+ struct ETH_TX_COMPL_AMAP *txcp;
+ struct net_device *netdev = pnob->netdev;
+ u32 end_idx, num_processed = 0;
+
+ adapter->be_stat.bes_tx_events++;
+
+ while ((txcp = be_get_tx_cmpl(pnob))) {
+ end_idx = AMAP_GET_BITS_PTR(ETH_TX_COMPL, wrb_index, txcp);
+ process_one_tx_compl(pnob, end_idx);
+ num_processed++;
+ adapter->be_stat.bes_tx_compl++;
+ }
+ be_notify_cmpl(pnob, num_processed, pnob->tx_cq_id, 1);
+ /*
+ * We got Tx completions and have usable WRBs.
+ * If the netdev's queue has been stopped
+ * because we had run out of WRBs, wake it now.
+ */
+ spin_lock(&adapter->txq_lock);
+ if (netif_queue_stopped(netdev)
+ && atomic_read(&pnob->tx_q_used) < pnob->tx_q_len / 2) {
+ netif_wake_queue(netdev);
+ }
+ spin_unlock(&adapter->txq_lock);
+}
+
+static u32 post_rx_buffs(struct be_net_object *pnob, struct list_head *rxbl)
+{
+ u32 nposted = 0;
+ struct ETH_RX_D_AMAP *rxd = NULL;
+ struct be_recv_buffer *rxbp;
+ void **rx_ctxp;
+ struct RQ_DB_AMAP rqdb;
+
+ rx_ctxp = pnob->rx_ctxt;
+
+ while (!list_empty(rxbl) &&
+ (rx_ctxp[pnob->rx_q_hd] == NULL) && nposted < 255) {
+
+ rxbp = list_first_entry(rxbl, struct be_recv_buffer, rxb_list);
+ list_del(&rxbp->rxb_list);
+ rxd = pnob->rx_q + pnob->rx_q_hd;
+ AMAP_SET_BITS_PTR(ETH_RX_D, fragpa_lo, rxd, rxbp->rxb_pa_lo);
+ AMAP_SET_BITS_PTR(ETH_RX_D, fragpa_hi, rxd, rxbp->rxb_pa_hi);
+
+ rx_ctxp[pnob->rx_q_hd] = rxbp->rxb_ctxt;
+ be_adv_rxq_hd(pnob);
+ nposted++;
+ }
+
+ if (nposted) {
+ /* Now press the door bell to notify BladeEngine. */
+ rqdb.dw[0] = 0;
+ AMAP_SET_BITS_PTR(RQ_DB, numPosted, &rqdb, nposted);
+ AMAP_SET_BITS_PTR(RQ_DB, rq, &rqdb, pnob->rx_q_id);
+ PD_WRITE(&pnob->fn_obj, erx_rq_db, rqdb.dw[0]);
+ }
+ atomic_add(nposted, &pnob->rx_q_posted);
+ return nposted;
+}
+
+void be_post_eth_rx_buffs(struct be_net_object *pnob)
+{
+ struct be_adapter *adapter = pnob->adapter;
+ u32 num_bufs, r;
+ u64 busaddr = 0, tmp_pa;
+ u32 max_bufs, pg_hd;
+ u32 frag_size;
+ struct be_recv_buffer *rxbp;
+ struct list_head rxbl;
+ struct be_rx_page_info *rx_page_info;
+ struct page *page = NULL;
+ u32 page_order = 0;
+ gfp_t alloc_flags = GFP_ATOMIC;
+
+ BUG_ON(!adapter);
+
+ max_bufs = 64; /* should be even # <= 255. */
+
+ frag_size = pnob->rx_buf_size;
+ page_order = get_order(frag_size);
+
+ if (frag_size == 8192)
+ alloc_flags |= (gfp_t) __GFP_COMP;
+ /*
+ * Form a linked list of RECV_BUFFFER structure to be be posted.
+ * We will post even number of buffer so that pages can be
+ * shared.
+ */
+ INIT_LIST_HEAD(&rxbl);
+
+ for (num_bufs = 0; num_bufs < max_bufs &&
+ !pnob->rx_page_info[pnob->rx_pg_info_hd].page; ++num_bufs) {
+
+ rxbp = &pnob->eth_rx_bufs[num_bufs];
+ pg_hd = pnob->rx_pg_info_hd;
+ rx_page_info = &pnob->rx_page_info[pg_hd];
+
+ if (!page) {
+ page = alloc_pages(alloc_flags, page_order);
+ if (unlikely(page == NULL)) {
+ adapter->be_stat.bes_ethrx_post_fail++;
+ pnob->rxbuf_post_fail++;
+ break;
+ }
+ pnob->rxbuf_post_fail = 0;
+ busaddr = pci_map_page(adapter->pdev, page, 0,
+ frag_size, PCI_DMA_FROMDEVICE);
+ rx_page_info->page_offset = 0;
+ rx_page_info->page = page;
+ /*
+ * If we are sharing a page among two skbs,
+ * alloc a new one on the next iteration
+ */
+ if (pnob->rx_pg_shared == false)
+ page = NULL;
+ } else {
+ get_page(page);
+ rx_page_info->page_offset += frag_size;
+ rx_page_info->page = page;
+ /*
+ * We are finished with the alloced page,
+ * Alloc a new one on the next iteration
+ */
+ page = NULL;
+ }
+ rxbp->rxb_ctxt = (void *)rx_page_info;
+ index_inc(&pnob->rx_pg_info_hd, pnob->rx_q_len);
+
+ pci_unmap_addr_set(rx_page_info, bus, busaddr);
+ tmp_pa = busaddr + rx_page_info->page_offset;
+ rxbp->rxb_pa_lo = (tmp_pa & 0xFFFFFFFF);
+ rxbp->rxb_pa_hi = (tmp_pa >> 32);
+ rxbp->rxb_len = frag_size;
+ list_add_tail(&rxbp->rxb_list, &rxbl);
+ } /* End of for */
+
+ r = post_rx_buffs(pnob, &rxbl);
+ BUG_ON(r != num_bufs);
+ return;
+}
+
+/*
+ * Interrupt service for network function. We just schedule the
+ * tasklet which does all completion processing.
+ */
+irqreturn_t be_int(int irq, void *dev)
+{
+ struct net_device *netdev = dev;
+ struct be_net_object *pnob = netdev_priv(netdev);
+ struct be_adapter *adapter = pnob->adapter;
+ u32 isr;
+
+ isr = CSR_READ(&pnob->fn_obj, cev.isr1);
+ if (unlikely(!isr))
+ return IRQ_NONE;
+
+ spin_lock(&adapter->int_lock);
+ adapter->isr |= isr;
+ spin_unlock(&adapter->int_lock);
+
+ adapter->be_stat.bes_ints++;
+
+ tasklet_schedule(&adapter->sts_handler);
+ return IRQ_HANDLED;
+}
+
+/*
+ * Poll function called by NAPI with a work budget.
+ * We process as many UC. BC and MC receive completions
+ * as the budget allows and return the actual number of
+ * RX ststutses processed.
+ */
+int be_poll(struct napi_struct *napi, int budget)
+{
+ struct be_net_object *pnob =
+ container_of(napi, struct be_net_object, napi);
+ u32 work_done;
+
+ pnob->adapter->be_stat.bes_polls++;
+ work_done = process_rx_completions(pnob, budget);
+ BUG_ON(work_done > budget);
+
+ /* All consumed */
+ if (work_done < budget) {
+ netif_rx_complete(napi);
+ /* enable intr */
+ be_notify_cmpl(pnob, work_done, pnob->rx_cq_id, 1);
+ } else {
+ /* More to be consumed; continue with interrupts disabled */
+ be_notify_cmpl(pnob, work_done, pnob->rx_cq_id, 0);
+ }
+ return work_done;
+}
+
+static struct EQ_ENTRY_AMAP *get_event(struct be_net_object *pnob)
+{
+ struct EQ_ENTRY_AMAP *eqp = &(pnob->event_q[pnob->event_q_tl]);
+ if (!AMAP_GET_BITS_PTR(EQ_ENTRY, Valid, eqp))
+ return NULL;
+ be_adv_eq_tl(pnob);
+ return eqp;
+}
+
+/*
+ * Processes all valid events in the event ring associated with given
+ * NetObject. Also, notifies BE the number of events processed.
+ */
+static inline u32 process_events(struct be_net_object *pnob)
+{
+ struct be_adapter *adapter = pnob->adapter;
+ struct EQ_ENTRY_AMAP *eqp;
+ u32 rid, num_events = 0;
+ struct net_device *netdev = pnob->netdev;
+
+ while ((eqp = get_event(pnob)) != NULL) {
+ adapter->be_stat.bes_events++;
+ rid = AMAP_GET_BITS_PTR(EQ_ENTRY, ResourceID, eqp);
+ if (rid == pnob->rx_cq_id) {
+ adapter->be_stat.bes_rx_events++;
+ netif_rx_schedule(&pnob->napi);
+ } else if (rid == pnob->tx_cq_id) {
+ process_nic_tx_completions(pnob);
+ } else if (rid == pnob->mcc_cq_id) {
+ be_mcc_process_cq(&pnob->mcc_q_obj, 1);
+ } else {
+ dev_info(&netdev->dev,
+ "Invalid EQ ResourceID %d\n", rid);
+ }
+ AMAP_SET_BITS_PTR(EQ_ENTRY, Valid, eqp, 0);
+ AMAP_SET_BITS_PTR(EQ_ENTRY, ResourceID, eqp, 0);
+ num_events++;
+ }
+ return num_events;
+}
+
+static void update_eqd(struct be_adapter *adapter, struct be_net_object *pnob)
+{
+ int status;
+ struct be_eq_object *eq_objectp;
+
+ /* 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)
+ new_eqd = (adapter->cur_eqd + 8);
+ if (r < IPS_LO_WM && adapter->cur_eqd > adapter->min_eqd)
+ new_eqd = (adapter->cur_eqd - 8);
+ if (adapter->enable_aic && new_eqd != -1) {
+ eq_objectp = &pnob->event_q_obj;
+ status = be_eq_modify_delay(&pnob->fn_obj, 1,
+ &eq_objectp, &new_eqd, NULL,
+ NULL, NULL);
+ if (status == BE_SUCCESS)
+ adapter->cur_eqd = new_eqd;
+ }
+ }
+}
+
+/*
+ This function notifies BladeEngine of how many events were processed
+ from the event queue by ringing the corresponding door bell and
+ optionally re-arms the event queue.
+ n - number of events processed
+ re_arm - 1 - re-arm the EQ, 0 - do not re-arm the EQ
+
+*/
+static void be_notify_event(struct be_net_object *pnob, int n, int re_arm)
+{
+ struct CQ_DB_AMAP eqdb;
+ eqdb.dw[0] = 0;
+
+ AMAP_SET_BITS_PTR(CQ_DB, qid, &eqdb, pnob->event_q_id);
+ AMAP_SET_BITS_PTR(CQ_DB, rearm, &eqdb, re_arm);
+ AMAP_SET_BITS_PTR(CQ_DB, event, &eqdb, 1);
+ AMAP_SET_BITS_PTR(CQ_DB, num_popped, &eqdb, n);
+ /*
+ * Under some situations we see an interrupt and no valid
+ * EQ entry. To keep going, we need to ring the DB even if
+ * numPOsted is 0.
+ */
+ PD_WRITE(&pnob->fn_obj, cq_db, eqdb.dw[0]);
+ return;
+}
+
+/*
+ * Called from the tasklet scheduled by ISR. All real interrupt processing
+ * is done here.
+ */
+void be_process_intr(unsigned long context)
+{
+ struct be_adapter *adapter = (struct be_adapter *)context;
+ struct be_net_object *pnob = adapter->net_obj;
+ u32 isr, n;
+ ulong flags = 0;
+
+ isr = adapter->isr;
+
+ /*
+ * we create only one NIC event queue in Linux. Event is
+ * expected only in the first event queue
+ */
+ BUG_ON(isr & 0xfffffffe);
+ if ((isr & 1) == 0)
+ return; /* not our interrupt */
+ n = process_events(pnob);
+ /*
+ * Clear the event bit. adapter->isr is set by
+ * hard interrupt. Prevent race with lock.
+ */
+ spin_lock_irqsave(&adapter->int_lock, flags);
+ adapter->isr &= ~1;
+ spin_unlock_irqrestore(&adapter->int_lock, flags);
+ be_notify_event(pnob, n, 1);
+ /*
+ * If previous allocation attempts had failed and
+ * BE has used up all posted buffers, post RX buffers here
+ */
+ if (pnob->rxbuf_post_fail && atomic_read(&pnob->rx_q_posted) == 0)
+ be_post_eth_rx_buffs(pnob);
+ update_eqd(adapter, pnob);
+ return;
+}
diff --git a/drivers/staging/benet/be_netif.c b/drivers/staging/benet/be_netif.c
new file mode 100644
index 000000000000..2b8daf63dc7d
--- /dev/null
+++ b/drivers/staging/benet/be_netif.c
@@ -0,0 +1,705 @@
+/*
+ * 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:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+/*
+ * be_netif.c
+ *
+ * This file contains various entry points of drivers seen by tcp/ip stack.
+ */
+
+#include <linux/if_vlan.h>
+#include <linux/in.h>
+#include "benet.h"
+#include <linux/ip.h>
+#include <linux/inet_lro.h>
+
+/* Strings to print Link properties */
+static const char *link_speed[] = {
+ "Invalid link Speed Value",
+ "10 Mbps",
+ "100 Mbps",
+ "1 Gbps",
+ "10 Gbps"
+};
+
+static const char *link_duplex[] = {
+ "Invalid Duplex Value",
+ "Half Duplex",
+ "Full Duplex"
+};
+
+static const char *link_state[] = {
+ "",
+ "(active)"
+};
+
+void be_print_link_info(struct BE_LINK_STATUS *lnk_status)
+{
+ u16 si, di, ai;
+
+ /* Port 0 */
+ if (lnk_status->mac0_speed && lnk_status->mac0_duplex) {
+ /* Port is up and running */
+ si = (lnk_status->mac0_speed < 5) ? lnk_status->mac0_speed : 0;
+ di = (lnk_status->mac0_duplex < 3) ?
+ lnk_status->mac0_duplex : 0;
+ ai = (lnk_status->active_port == 0) ? 1 : 0;
+ printk(KERN_INFO "PortNo. 0: Speed - %s %s %s\n",
+ link_speed[si], link_duplex[di], link_state[ai]);
+ } else
+ printk(KERN_INFO "PortNo. 0: Down\n");
+
+ /* Port 1 */
+ if (lnk_status->mac1_speed && lnk_status->mac1_duplex) {
+ /* Port is up and running */
+ si = (lnk_status->mac1_speed < 5) ? lnk_status->mac1_speed : 0;
+ di = (lnk_status->mac1_duplex < 3) ?
+ lnk_status->mac1_duplex : 0;
+ ai = (lnk_status->active_port == 0) ? 1 : 0;
+ printk(KERN_INFO "PortNo. 1: Speed - %s %s %s\n",
+ link_speed[si], link_duplex[di], link_state[ai]);
+ } else
+ printk(KERN_INFO "PortNo. 1: Down\n");
+
+ return;
+}
+
+static int
+be_get_frag_header(struct skb_frag_struct *frag, void **mac_hdr,
+ void **ip_hdr, void **tcpudp_hdr,
+ u64 *hdr_flags, void *priv)
+{
+ struct ethhdr *eh;
+ struct vlan_ethhdr *veh;
+ struct iphdr *iph;
+ u8 *va = page_address(frag->page) + frag->page_offset;
+ unsigned long ll_hlen;
+
+ /* find the mac header, abort if not IPv4 */
+
+ prefetch(va);
+ eh = (struct ethhdr *)va;
+ *mac_hdr = eh;
+ ll_hlen = ETH_HLEN;
+ if (eh->h_proto != htons(ETH_P_IP)) {
+ if (eh->h_proto == htons(ETH_P_8021Q)) {
+ veh = (struct vlan_ethhdr *)va;
+ if (veh->h_vlan_encapsulated_proto != htons(ETH_P_IP))
+ return -1;
+
+ ll_hlen += VLAN_HLEN;
+
+ } else {
+ return -1;
+ }
+ }
+ *hdr_flags = LRO_IPV4;
+
+ iph = (struct iphdr *)(va + ll_hlen);
+ *ip_hdr = iph;
+ if (iph->protocol != IPPROTO_TCP)
+ return -1;
+ *hdr_flags |= LRO_TCP;
+ *tcpudp_hdr = (u8 *) (*ip_hdr) + (iph->ihl << 2);
+
+ return 0;
+}
+
+static int benet_open(struct net_device *netdev)
+{
+ struct be_net_object *pnob = netdev_priv(netdev);
+ struct be_adapter *adapter = pnob->adapter;
+ struct net_lro_mgr *lro_mgr;
+
+ if (adapter->dev_state < BE_DEV_STATE_INIT)
+ return -EAGAIN;
+
+ lro_mgr = &pnob->lro_mgr;
+ lro_mgr->dev = netdev;
+
+ lro_mgr->features = LRO_F_NAPI;
+ lro_mgr->ip_summed = CHECKSUM_UNNECESSARY;
+ lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY;
+ lro_mgr->max_desc = BE_MAX_LRO_DESCRIPTORS;
+ lro_mgr->lro_arr = pnob->lro_desc;
+ lro_mgr->get_frag_header = be_get_frag_header;
+ lro_mgr->max_aggr = adapter->max_rx_coal;
+ lro_mgr->frag_align_pad = 2;
+ if (lro_mgr->max_aggr > MAX_SKB_FRAGS)
+ lro_mgr->max_aggr = MAX_SKB_FRAGS;
+
+ adapter->max_rx_coal = BE_LRO_MAX_PKTS;
+
+ be_update_link_status(adapter);
+
+ /*
+ * Set carrier on only if Physical Link up
+ * Either of the port link status up signifies this
+ */
+ if ((adapter->port0_link_sts == BE_PORT_LINK_UP) ||
+ (adapter->port1_link_sts == BE_PORT_LINK_UP)) {
+ netif_start_queue(netdev);
+ netif_carrier_on(netdev);
+ }
+
+ adapter->dev_state = BE_DEV_STATE_OPEN;
+ napi_enable(&pnob->napi);
+ be_enable_intr(pnob);
+ be_enable_eq_intr(pnob);
+ /*
+ * RX completion queue may be in dis-armed state. Arm it.
+ */
+ be_notify_cmpl(pnob, 0, pnob->rx_cq_id, 1);
+
+ return 0;
+}
+
+static int benet_close(struct net_device *netdev)
+{
+ struct be_net_object *pnob = netdev_priv(netdev);
+ struct be_adapter *adapter = pnob->adapter;
+
+ netif_stop_queue(netdev);
+ synchronize_irq(netdev->irq);
+
+ be_wait_nic_tx_cmplx_cmpl(pnob);
+ adapter->dev_state = BE_DEV_STATE_INIT;
+ netif_carrier_off(netdev);
+
+ adapter->port0_link_sts = BE_PORT_LINK_DOWN;
+ adapter->port1_link_sts = BE_PORT_LINK_DOWN;
+ be_disable_intr(pnob);
+ be_disable_eq_intr(pnob);
+ napi_disable(&pnob->napi);
+
+ return 0;
+}
+
+/*
+ * Setting a Mac Address for BE
+ * Takes netdev and a void pointer as arguments.
+ * The pointer holds the new addres to be used.
+ */
+static int benet_set_mac_addr(struct net_device *netdev, void *p)
+{
+ struct sockaddr *addr = p;
+ struct be_net_object *pnob = netdev_priv(netdev);
+
+ memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+ be_rxf_mac_address_read_write(&pnob->fn_obj, 0, 0, false, true, false,
+ netdev->dev_addr, NULL, NULL);
+ /*
+ * Since we are doing Active-Passive failover, both
+ * ports should have matching MAC addresses everytime.
+ */
+ be_rxf_mac_address_read_write(&pnob->fn_obj, 1, 0, false, true, false,
+ netdev->dev_addr, NULL, NULL);
+
+ return 0;
+}
+
+void be_get_stats_timer_handler(unsigned long context)
+{
+ struct be_timer_ctxt *ctxt = (struct be_timer_ctxt *)context;
+
+ if (atomic_read(&ctxt->get_stat_flag)) {
+ atomic_dec(&ctxt->get_stat_flag);
+ up((void *)ctxt->get_stat_sem_addr);
+ }
+ del_timer(&ctxt->get_stats_timer);
+ return;
+}
+
+void be_get_stat_cb(void *context, int status,
+ struct MCC_WRB_AMAP *optional_wrb)
+{
+ struct be_timer_ctxt *ctxt = (struct be_timer_ctxt *)context;
+ /*
+ * just up the semaphore if the get_stat_flag
+ * reads 1. so that the waiter can continue.
+ * If it is 0, then it was handled by the timer handler.
+ */
+ del_timer(&ctxt->get_stats_timer);
+ if (atomic_read(&ctxt->get_stat_flag)) {
+ atomic_dec(&ctxt->get_stat_flag);
+ up((void *)ctxt->get_stat_sem_addr);
+ }
+}
+
+struct net_device_stats *benet_get_stats(struct net_device *dev)
+{
+ struct be_net_object *pnob = netdev_priv(dev);
+ struct be_adapter *adapter = pnob->adapter;
+ u64 pa;
+ struct be_timer_ctxt *ctxt = &adapter->timer_ctxt;
+
+ if (adapter->dev_state != BE_DEV_STATE_OPEN) {
+ /* Return previously read stats */
+ return &(adapter->benet_stats);
+ }
+ /* Get Physical Addr */
+ pa = pci_map_single(adapter->pdev, adapter->eth_statsp,
+ sizeof(struct FWCMD_ETH_GET_STATISTICS),
+ PCI_DMA_FROMDEVICE);
+ ctxt->get_stat_sem_addr = (unsigned long)&adapter->get_eth_stat_sem;
+ atomic_inc(&ctxt->get_stat_flag);
+
+ be_rxf_query_eth_statistics(&pnob->fn_obj, adapter->eth_statsp,
+ cpu_to_le64(pa), be_get_stat_cb, ctxt,
+ NULL);
+
+ ctxt->get_stats_timer.data = (unsigned long)ctxt;
+ mod_timer(&ctxt->get_stats_timer, (jiffies + (HZ * 2)));
+ down((void *)ctxt->get_stat_sem_addr); /* callback will unblock us */
+
+ /* Adding port0 and port1 stats. */
+ adapter->benet_stats.rx_packets =
+ adapter->eth_statsp->params.response.p0recvdtotalframes +
+ adapter->eth_statsp->params.response.p1recvdtotalframes;
+ adapter->benet_stats.tx_packets =
+ adapter->eth_statsp->params.response.p0xmitunicastframes +
+ adapter->eth_statsp->params.response.p1xmitunicastframes;
+ adapter->benet_stats.tx_bytes =
+ adapter->eth_statsp->params.response.p0xmitbyteslsd +
+ adapter->eth_statsp->params.response.p1xmitbyteslsd;
+ adapter->benet_stats.rx_errors =
+ adapter->eth_statsp->params.response.p0crcerrors +
+ adapter->eth_statsp->params.response.p1crcerrors;
+ adapter->benet_stats.rx_errors +=
+ adapter->eth_statsp->params.response.p0alignmentsymerrs +
+ adapter->eth_statsp->params.response.p1alignmentsymerrs;
+ adapter->benet_stats.rx_errors +=
+ adapter->eth_statsp->params.response.p0inrangelenerrors +
+ adapter->eth_statsp->params.response.p1inrangelenerrors;
+ adapter->benet_stats.rx_bytes =
+ adapter->eth_statsp->params.response.p0recvdtotalbytesLSD +
+ adapter->eth_statsp->params.response.p1recvdtotalbytesLSD;
+ adapter->benet_stats.rx_crc_errors =
+ adapter->eth_statsp->params.response.p0crcerrors +
+ adapter->eth_statsp->params.response.p1crcerrors;
+
+ adapter->benet_stats.tx_packets +=
+ adapter->eth_statsp->params.response.p0xmitmulticastframes +
+ adapter->eth_statsp->params.response.p1xmitmulticastframes;
+ adapter->benet_stats.tx_packets +=
+ adapter->eth_statsp->params.response.p0xmitbroadcastframes +
+ adapter->eth_statsp->params.response.p1xmitbroadcastframes;
+ adapter->benet_stats.tx_errors = 0;
+
+ adapter->benet_stats.multicast =
+ adapter->eth_statsp->params.response.p0xmitmulticastframes +
+ adapter->eth_statsp->params.response.p1xmitmulticastframes;
+
+ adapter->benet_stats.rx_fifo_errors =
+ adapter->eth_statsp->params.response.p0rxfifooverflowdropped +
+ adapter->eth_statsp->params.response.p1rxfifooverflowdropped;
+ adapter->benet_stats.rx_frame_errors =
+ adapter->eth_statsp->params.response.p0alignmentsymerrs +
+ adapter->eth_statsp->params.response.p1alignmentsymerrs;
+ adapter->benet_stats.rx_length_errors =
+ adapter->eth_statsp->params.response.p0inrangelenerrors +
+ adapter->eth_statsp->params.response.p1inrangelenerrors;
+ adapter->benet_stats.rx_length_errors +=
+ adapter->eth_statsp->params.response.p0outrangeerrors +
+ adapter->eth_statsp->params.response.p1outrangeerrors;
+ adapter->benet_stats.rx_length_errors +=
+ adapter->eth_statsp->params.response.p0frametoolongerrors +
+ adapter->eth_statsp->params.response.p1frametoolongerrors;
+
+ pci_unmap_single(adapter->pdev, (ulong) adapter->eth_statsp,
+ sizeof(struct FWCMD_ETH_GET_STATISTICS),
+ PCI_DMA_FROMDEVICE);
+ return &(adapter->benet_stats);
+
+}
+
+static void be_start_tx(struct be_net_object *pnob, u32 nposted)
+{
+#define CSR_ETH_MAX_SQPOSTS 255
+ struct SQ_DB_AMAP sqdb;
+
+ sqdb.dw[0] = 0;
+
+ AMAP_SET_BITS_PTR(SQ_DB, cid, &sqdb, pnob->tx_q_id);
+ while (nposted) {
+ if (nposted > CSR_ETH_MAX_SQPOSTS) {
+ AMAP_SET_BITS_PTR(SQ_DB, numPosted, &sqdb,
+ CSR_ETH_MAX_SQPOSTS);
+ nposted -= CSR_ETH_MAX_SQPOSTS;
+ } else {
+ AMAP_SET_BITS_PTR(SQ_DB, numPosted, &sqdb, nposted);
+ nposted = 0;
+ }
+ PD_WRITE(&pnob->fn_obj, etx_sq_db, sqdb.dw[0]);
+ }
+
+ return;
+}
+
+static 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); /* M bytes/s */
+ adapter->be_stat.bes_eth_tx_rate = (r * 8); /* M bits/s */
+ adapter->eth_tx_jiffies = jiffies;
+ adapter->eth_tx_bytes = 0;
+ }
+}
+
+static int wrb_cnt_in_skb(struct sk_buff *skb)
+{
+ int cnt = 0;
+ while (skb) {
+ if (skb->len > skb->data_len)
+ cnt++;
+ cnt += skb_shinfo(skb)->nr_frags;
+ skb = skb_shinfo(skb)->frag_list;
+ }
+ BUG_ON(cnt > BE_MAX_TX_FRAG_COUNT);
+ return cnt;
+}
+
+static void wrb_fill(struct ETH_WRB_AMAP *wrb, u64 addr, int len)
+{
+ AMAP_SET_BITS_PTR(ETH_WRB, frag_pa_hi, wrb, addr >> 32);
+ AMAP_SET_BITS_PTR(ETH_WRB, frag_pa_lo, wrb, addr & 0xFFFFFFFF);
+ AMAP_SET_BITS_PTR(ETH_WRB, frag_len, wrb, len);
+}
+
+static void wrb_fill_extra(struct ETH_WRB_AMAP *wrb, struct sk_buff *skb,
+ struct be_net_object *pnob)
+{
+ wrb->dw[2] = 0;
+ wrb->dw[3] = 0;
+ AMAP_SET_BITS_PTR(ETH_WRB, crc, wrb, 1);
+ if (skb_shinfo(skb)->gso_segs > 1 && skb_shinfo(skb)->gso_size) {
+ AMAP_SET_BITS_PTR(ETH_WRB, lso, wrb, 1);
+ AMAP_SET_BITS_PTR(ETH_WRB, lso_mss, wrb,
+ skb_shinfo(skb)->gso_size);
+ } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ u8 proto = ((struct iphdr *)ip_hdr(skb))->protocol;
+ if (proto == IPPROTO_TCP)
+ AMAP_SET_BITS_PTR(ETH_WRB, tcpcs, wrb, 1);
+ else if (proto == IPPROTO_UDP)
+ AMAP_SET_BITS_PTR(ETH_WRB, udpcs, wrb, 1);
+ }
+ if (pnob->vlan_grp && vlan_tx_tag_present(skb)) {
+ AMAP_SET_BITS_PTR(ETH_WRB, vlan, wrb, 1);
+ AMAP_SET_BITS_PTR(ETH_WRB, vlan_tag, wrb, vlan_tx_tag_get(skb));
+ }
+}
+
+static inline void wrb_copy_extra(struct ETH_WRB_AMAP *to,
+ struct ETH_WRB_AMAP *from)
+{
+
+ to->dw[2] = from->dw[2];
+ to->dw[3] = from->dw[3];
+}
+
+/* Returns the actual count of wrbs used including a possible dummy */
+static int copy_skb_to_txq(struct be_net_object *pnob, struct sk_buff *skb,
+ u32 wrb_cnt, u32 *copied)
+{
+ u64 busaddr;
+ struct ETH_WRB_AMAP *wrb = NULL, *first = NULL;
+ u32 i;
+ bool dummy = true;
+ struct pci_dev *pdev = pnob->adapter->pdev;
+
+ if (wrb_cnt & 1)
+ wrb_cnt++;
+ else
+ dummy = false;
+
+ atomic_add(wrb_cnt, &pnob->tx_q_used);
+
+ while (skb) {
+ if (skb->len > skb->data_len) {
+ int len = skb->len - skb->data_len;
+ busaddr = pci_map_single(pdev, skb->data, len,
+ PCI_DMA_TODEVICE);
+ busaddr = cpu_to_le64(busaddr);
+ wrb = &pnob->tx_q[pnob->tx_q_hd];
+ if (first == NULL) {
+ wrb_fill_extra(wrb, skb, pnob);
+ first = wrb;
+ } else {
+ wrb_copy_extra(wrb, first);
+ }
+ wrb_fill(wrb, busaddr, len);
+ be_adv_txq_hd(pnob);
+ *copied += len;
+ }
+
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ struct skb_frag_struct *frag =
+ &skb_shinfo(skb)->frags[i];
+ busaddr = pci_map_page(pdev, frag->page,
+ frag->page_offset, frag->size,
+ PCI_DMA_TODEVICE);
+ busaddr = cpu_to_le64(busaddr);
+ wrb = &pnob->tx_q[pnob->tx_q_hd];
+ if (first == NULL) {
+ wrb_fill_extra(wrb, skb, pnob);
+ first = wrb;
+ } else {
+ wrb_copy_extra(wrb, first);
+ }
+ wrb_fill(wrb, busaddr, frag->size);
+ be_adv_txq_hd(pnob);
+ *copied += frag->size;
+ }
+ skb = skb_shinfo(skb)->frag_list;
+ }
+
+ if (dummy) {
+ wrb = &pnob->tx_q[pnob->tx_q_hd];
+ BUG_ON(first == NULL);
+ wrb_copy_extra(wrb, first);
+ wrb_fill(wrb, 0, 0);
+ be_adv_txq_hd(pnob);
+ }
+ AMAP_SET_BITS_PTR(ETH_WRB, complete, wrb, 1);
+ AMAP_SET_BITS_PTR(ETH_WRB, last, wrb, 1);
+ return wrb_cnt;
+}
+
+/* For each skb transmitted, tx_ctxt stores the num of wrbs in the
+ * start index and skb pointer in the end index
+ */
+static inline void be_tx_wrb_info_remember(struct be_net_object *pnob,
+ struct sk_buff *skb, int wrb_cnt,
+ u32 start)
+{
+ *(u32 *) (&pnob->tx_ctxt[start]) = wrb_cnt;
+ index_adv(&start, wrb_cnt - 1, pnob->tx_q_len);
+ pnob->tx_ctxt[start] = skb;
+}
+
+static int benet_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct be_net_object *pnob = netdev_priv(netdev);
+ struct be_adapter *adapter = pnob->adapter;
+ u32 wrb_cnt, copied = 0;
+ u32 start = pnob->tx_q_hd;
+
+ adapter->be_stat.bes_tx_reqs++;
+
+ wrb_cnt = wrb_cnt_in_skb(skb);
+ spin_lock_bh(&adapter->txq_lock);
+ if ((pnob->tx_q_len - 2 - atomic_read(&pnob->tx_q_used)) <= wrb_cnt) {
+ netif_stop_queue(pnob->netdev);
+ spin_unlock_bh(&adapter->txq_lock);
+ adapter->be_stat.bes_tx_fails++;
+ return NETDEV_TX_BUSY;
+ }
+ spin_unlock_bh(&adapter->txq_lock);
+
+ wrb_cnt = copy_skb_to_txq(pnob, skb, wrb_cnt, &copied);
+ be_tx_wrb_info_remember(pnob, skb, wrb_cnt, start);
+
+ be_start_tx(pnob, wrb_cnt);
+
+ adapter->eth_tx_bytes += copied;
+ adapter->be_stat.bes_tx_wrbs += wrb_cnt;
+ update_tx_rate(adapter);
+ netdev->trans_start = jiffies;
+
+ return NETDEV_TX_OK;
+}
+
+/*
+ * This is the driver entry point to change the mtu of the device
+ * Returns 0 for success and errno for failure.
+ */
+static int benet_change_mtu(struct net_device *netdev, int new_mtu)
+{
+ /*
+ * BE supports jumbo frame size upto 9000 bytes including the link layer
+ * header. Considering the different variants of frame formats possible
+ * like VLAN, SNAP/LLC, the maximum possible value for MTU is 8974 bytes
+ */
+
+ if (new_mtu < (ETH_ZLEN + ETH_FCS_LEN) || (new_mtu > BE_MAX_MTU)) {
+ dev_info(&netdev->dev, "Invalid MTU requested. "
+ "Must be between %d and %d bytes\n",
+ (ETH_ZLEN + ETH_FCS_LEN), BE_MAX_MTU);
+ return -EINVAL;
+ }
+ dev_info(&netdev->dev, "MTU changed from %d to %d\n",
+ netdev->mtu, new_mtu);
+ netdev->mtu = new_mtu;
+ return 0;
+}
+
+/*
+ * This is the driver entry point to register a vlan with the device
+ */
+static void benet_vlan_register(struct net_device *netdev,
+ struct vlan_group *grp)
+{
+ struct be_net_object *pnob = netdev_priv(netdev);
+
+ be_disable_eq_intr(pnob);
+ pnob->vlan_grp = grp;
+ pnob->num_vlans = 0;
+ be_enable_eq_intr(pnob);
+}
+
+/*
+ * This is the driver entry point to add a vlan vlan_id
+ * with the device netdev
+ */
+static void benet_vlan_add_vid(struct net_device *netdev, u16 vlan_id)
+{
+ struct be_net_object *pnob = netdev_priv(netdev);
+
+ if (pnob->num_vlans == (BE_NUM_VLAN_SUPPORTED - 1)) {
+ /* no way to return an error */
+ dev_info(&netdev->dev,
+ "BladeEngine: Cannot configure more than %d Vlans\n",
+ BE_NUM_VLAN_SUPPORTED);
+ return;
+ }
+ /* The new vlan tag will be in the slot indicated by num_vlans. */
+ pnob->vlan_tag[pnob->num_vlans++] = vlan_id;
+ be_rxf_vlan_config(&pnob->fn_obj, false, pnob->num_vlans,
+ pnob->vlan_tag, NULL, NULL, NULL);
+}
+
+/*
+ * This is the driver entry point to remove a vlan vlan_id
+ * with the device netdev
+ */
+static void benet_vlan_rem_vid(struct net_device *netdev, u16 vlan_id)
+{
+ struct be_net_object *pnob = netdev_priv(netdev);
+
+ u32 i, value;
+
+ /*
+ * In Blade Engine, we support 32 vlan tag filters across both ports.
+ * To program a vlan tag, the RXF_RTPR_CSR register is used.
+ * Each 32-bit value of RXF_RTDR_CSR can address 2 vlan tag entries.
+ * The Vlan table is of depth 16. thus we support 32 tags.
+ */
+
+ value = vlan_id | VLAN_VALID_BIT;
+ for (i = 0; i < BE_NUM_VLAN_SUPPORTED; i++) {
+ if (pnob->vlan_tag[i] == vlan_id)
+ break;
+ }
+
+ if (i == BE_NUM_VLAN_SUPPORTED)
+ return;
+ /* Now compact the vlan tag array by removing hole created. */
+ while ((i + 1) < BE_NUM_VLAN_SUPPORTED) {
+ pnob->vlan_tag[i] = pnob->vlan_tag[i + 1];
+ i++;
+ }
+ if ((i + 1) == BE_NUM_VLAN_SUPPORTED)
+ pnob->vlan_tag[i] = (u16) 0x0;
+ pnob->num_vlans--;
+ be_rxf_vlan_config(&pnob->fn_obj, false, pnob->num_vlans,
+ pnob->vlan_tag, NULL, NULL, NULL);
+}
+
+/*
+ * This function is called to program multicast
+ * address in the multicast filter of the ASIC.
+ */
+static void be_set_multicast_filter(struct net_device *netdev)
+{
+ struct be_net_object *pnob = netdev_priv(netdev);
+ struct dev_mc_list *mc_ptr;
+ u8 mac_addr[32][ETH_ALEN];
+ int i;
+
+ if (netdev->flags & IFF_ALLMULTI) {
+ /* set BE in Multicast promiscuous */
+ be_rxf_multicast_config(&pnob->fn_obj, true, 0, NULL, NULL,
+ NULL, NULL);
+ return;
+ }
+
+ for (mc_ptr = netdev->mc_list, i = 0; mc_ptr;
+ mc_ptr = mc_ptr->next, i++) {
+ memcpy(&mac_addr[i][0], mc_ptr->dmi_addr, ETH_ALEN);
+ }
+
+ /* reset the promiscuous mode also. */
+ be_rxf_multicast_config(&pnob->fn_obj, false, i,
+ &mac_addr[0][0], NULL, NULL, NULL);
+}
+
+/*
+ * This is the driver entry point to set multicast list
+ * with the device netdev. This function will be used to
+ * set promiscuous mode or multicast promiscuous mode
+ * or multicast mode....
+ */
+static void benet_set_multicast_list(struct net_device *netdev)
+{
+ struct be_net_object *pnob = netdev_priv(netdev);
+
+ if (netdev->flags & IFF_PROMISC) {
+ be_rxf_promiscuous(&pnob->fn_obj, 1, 1, NULL, NULL, NULL);
+ } else {
+ be_rxf_promiscuous(&pnob->fn_obj, 0, 0, NULL, NULL, NULL);
+ be_set_multicast_filter(netdev);
+ }
+}
+
+int benet_init(struct net_device *netdev)
+{
+ struct be_net_object *pnob = netdev_priv(netdev);
+ struct be_adapter *adapter = pnob->adapter;
+
+ ether_setup(netdev);
+
+ netdev->open = &benet_open;
+ netdev->stop = &benet_close;
+ netdev->hard_start_xmit = &benet_xmit;
+
+ netdev->get_stats = &benet_get_stats;
+
+ netdev->set_multicast_list = &benet_set_multicast_list;
+
+ netdev->change_mtu = &benet_change_mtu;
+ netdev->set_mac_address = &benet_set_mac_addr;
+
+ netdev->vlan_rx_register = benet_vlan_register;
+ netdev->vlan_rx_add_vid = benet_vlan_add_vid;
+ netdev->vlan_rx_kill_vid = benet_vlan_rem_vid;
+
+ netdev->features =
+ NETIF_F_SG | NETIF_F_HIGHDMA | NETIF_F_HW_VLAN_RX | NETIF_F_TSO |
+ NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | NETIF_F_IP_CSUM;
+
+ netdev->flags |= IFF_MULTICAST;
+
+ /* If device is DAC Capable, set the HIGHDMA flag for netdevice. */
+ if (adapter->dma_64bit_cap)
+ netdev->features |= NETIF_F_HIGHDMA;
+
+ SET_ETHTOOL_OPS(netdev, &be_ethtool_ops);
+ return 0;
+}
diff --git a/drivers/staging/benet/benet.h b/drivers/staging/benet/benet.h
new file mode 100644
index 000000000000..09a1f0817722
--- /dev/null
+++ b/drivers/staging/benet/benet.h
@@ -0,0 +1,429 @@
+/*
+ * 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:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+#ifndef _BENET_H_
+#define _BENET_H_
+
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/inet_lro.h>
+#include "hwlib.h"
+
+#define _SA_MODULE_NAME "net-driver"
+
+#define VLAN_VALID_BIT 0x8000
+#define BE_NUM_VLAN_SUPPORTED 32
+#define BE_PORT_LINK_DOWN 0000
+#define BE_PORT_LINK_UP 0001
+#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 */
+
+#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
+
+/* This structure is used to describe physical fragments to use
+ * for DMAing data from NIC.
+ */
+struct be_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 be_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 */
+};
+
+struct be_rx_page_info {
+ struct page *page;
+ dma_addr_t bus;
+ u16 page_offset;
+};
+
+/*
+ * This structure is the main tracking structure for a NIC interface.
+ */
+struct be_net_object {
+ /* MCC Ring - used to send fwcmds 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 - FW responses to fwcmds 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 */
+
+ struct ring_desc mb_rd; /* RD for MCC_MAIL_BOX */
+ void *mb_ptr; /* mailbox ptr to be freed */
+ dma_addr_t mb_bus; /* DMA'ble bus address */
+ u32 mb_size;
+
+ /* 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 *rx_cq; /* VA of start of the queue */
+ u32 rx_cq_len; /* # of entries */
+ u32 rx_cq_size;
+ u32 rx_cq_tl; /* Tail of the queue */
+ u32 rx_cq_id; /* queue ID */
+ u8 rx_cq_created; /* flag to help cleanup */
+ struct be_cq_object rx_cq_obj; /* queue handle */
+ dma_addr_t rx_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 */
+
+ struct net_device *netdev;
+ struct be_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 */
+ struct napi_struct napi;
+ struct net_lro_mgr lro_mgr;
+ struct net_lro_desc lro_desc[BE_MAX_LRO_DESCRIPTORS];
+};
+
+#define NET_FH(np) (&(np)->fn_obj)
+
+/*
+ * 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_rx_events; /* number of ucast rx completion events */
+ u32 bes_tx_compl; /* number of tx completion entries processed */
+ u32 bes_rx_compl; /* number of rx 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;
+
+ /* PCI BAR mapped addresses */
+ u8 __iomem *csr_va; /* CSR */
+ u8 __iomem *db_va; /* Door Bell */
+ u8 __iomem *pci_va; /* PCI Config */
+
+ struct tasklet_struct sts_handler;
+ struct timer_list cq_timer;
+ spinlock_t int_lock; /* to protect the isr field in adapter */
+
+ 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; /* to stop/wake queue based on tx_q_used */
+
+ 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 be_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 */
+};
+
+/*
+ * 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 index_adv(u32 *index, u32 val, u32 limit)
+{
+ BUG_ON(limit & (limit-1));
+ *index = (*index + val) & (limit - 1);
+}
+
+static inline void index_inc(u32 *index, u32 limit)
+{
+ BUG_ON(limit & (limit-1));
+ *index = (*index + 1) & (limit - 1);
+}
+
+static inline void be_adv_eq_tl(struct be_net_object *pnob)
+{
+ index_inc(&pnob->event_q_tl, pnob->event_q_len);
+}
+
+static inline void be_adv_txq_hd(struct be_net_object *pnob)
+{
+ index_inc(&pnob->tx_q_hd, pnob->tx_q_len);
+}
+
+static inline void be_adv_txq_tl(struct be_net_object *pnob)
+{
+ index_inc(&pnob->tx_q_tl, pnob->tx_q_len);
+}
+
+static inline void be_adv_txcq_tl(struct be_net_object *pnob)
+{
+ index_inc(&pnob->tx_cq_tl, pnob->txcq_len);
+}
+
+static inline void be_adv_rxq_hd(struct be_net_object *pnob)
+{
+ index_inc(&pnob->rx_q_hd, pnob->rx_q_len);
+}
+
+static inline void be_adv_rxcq_tl(struct be_net_object *pnob)
+{
+ index_inc(&pnob->rx_cq_tl, pnob->rx_cq_len);
+}
+
+static inline u32 tx_compl_lastwrb_idx_get(struct be_net_object *pnob)
+{
+ return (pnob->tx_q_tl + *(u32 *)&pnob->tx_ctxt[pnob->tx_q_tl] - 1)
+ & (pnob->tx_q_len - 1);
+}
+
+int benet_init(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 be_net_object *);
+void be_get_stat_cb(void *, int, struct MCC_WRB_AMAP *);
+void be_get_stats_timer_handler(unsigned long);
+void be_wait_nic_tx_cmplx_cmpl(struct be_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 *);
+int be_poll(struct napi_struct *, int);
+struct ETH_RX_COMPL_AMAP *be_get_rx_cmpl(struct be_net_object *);
+void be_notify_cmpl(struct be_net_object *, int, int, int);
+void be_enable_intr(struct be_net_object *);
+void be_enable_eq_intr(struct be_net_object *);
+void be_disable_intr(struct be_net_object *);
+void be_disable_eq_intr(struct be_net_object *);
+int be_set_uc_mac_adr(struct be_net_object *, u8, u8, u8,
+ u8 *, mcc_wrb_cqe_callback, void *);
+int be_get_flow_ctl(struct be_function_object *pFnObj, bool *, bool *);
+void process_one_tx_compl(struct be_net_object *pnob, u32 end_idx);
+
+#endif /* _BENET_H_ */
diff --git a/drivers/staging/benet/bestatus.h b/drivers/staging/benet/bestatus.h
new file mode 100644
index 000000000000..59c7a4b62223
--- /dev/null
+++ b/drivers/staging/benet/bestatus.h
@@ -0,0 +1,103 @@
+/*
+ * 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:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+#ifndef _BESTATUS_H_
+#define _BESTATUS_H_
+
+#define BE_SUCCESS (0x00000000L)
+/*
+ * MessageId: BE_PENDING
+ * The BladeEngine Driver call succeeded, and pended operation.
+ */
+#define BE_PENDING (0x20070001L)
+#define BE_STATUS_PENDING (BE_PENDING)
+/*
+ * MessageId: BE_NOT_OK
+ * An error occurred.
+ */
+#define BE_NOT_OK (0xE0070002L)
+/*
+ * MessageId: BE_STATUS_SYSTEM_RESOURCES
+ * Insufficient host system resources exist to complete the API.
+ */
+#define BE_STATUS_SYSTEM_RESOURCES (0xE0070003L)
+/*
+ * MessageId: BE_STATUS_CHIP_RESOURCES
+ * Insufficient chip resources exist to complete the API.
+ */
+#define BE_STATUS_CHIP_RESOURCES (0xE0070004L)
+/*
+ * MessageId: BE_STATUS_NO_RESOURCE
+ * Insufficient resources to complete request.
+ */
+#define BE_STATUS_NO_RESOURCE (0xE0070005L)
+/*
+ * MessageId: BE_STATUS_BUSY
+ * Resource is currently busy.
+ */
+#define BE_STATUS_BUSY (0xE0070006L)
+/*
+ * MessageId: BE_STATUS_INVALID_PARAMETER
+ * Invalid Parameter in request.
+ */
+#define BE_STATUS_INVALID_PARAMETER (0xE0000007L)
+/*
+ * MessageId: BE_STATUS_NOT_SUPPORTED
+ * Requested operation is not supported.
+ */
+#define BE_STATUS_NOT_SUPPORTED (0xE000000DL)
+
+/*
+ * ***************************************************************************
+ * E T H E R N E T S T A T U S
+ * ***************************************************************************
+ */
+
+/*
+ * MessageId: BE_ETH_TX_ERROR
+ * The Ethernet device driver failed to transmit a packet.
+ */
+#define BE_ETH_TX_ERROR (0xE0070101L)
+
+/*
+ * ***************************************************************************
+ * S H A R E D S T A T U S
+ * ***************************************************************************
+ */
+
+/*
+ * MessageId: BE_STATUS_VBD_INVALID_VERSION
+ * The device driver is not compatible with this version of the VBD.
+ */
+#define BE_STATUS_INVALID_VERSION (0xE0070402L)
+/*
+ * MessageId: BE_STATUS_DOMAIN_DENIED
+ * The operation failed to complete due to insufficient access
+ * rights for the requesting domain.
+ */
+#define BE_STATUS_DOMAIN_DENIED (0xE0070403L)
+/*
+ * MessageId: BE_STATUS_TCP_NOT_STARTED
+ * The embedded TCP/IP stack has not been started.
+ */
+#define BE_STATUS_TCP_NOT_STARTED (0xE0070409L)
+/*
+ * MessageId: BE_STATUS_NO_MCC_WRB
+ * No free MCC WRB are available for posting the request.
+ */
+#define BE_STATUS_NO_MCC_WRB (0xE0070414L)
+
+#endif /* _BESTATUS_ */
diff --git a/drivers/staging/benet/cev.h b/drivers/staging/benet/cev.h
new file mode 100644
index 000000000000..30996920a544
--- /dev/null
+++ b/drivers/staging/benet/cev.h
@@ -0,0 +1,243 @@
+/*
+ * 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:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+/*
+ * Autogenerated by srcgen version: 0127
+ */
+#ifndef __cev_amap_h__
+#define __cev_amap_h__
+#include "ep.h"
+
+/*
+ * Host Interrupt Status Register 0. The first of four application
+ * interrupt status registers. This register contains the interrupts
+ * for Event Queues EQ0 through EQ31.
+ */
+struct BE_CEV_ISR0_CSR_AMAP {
+ u8 interrupt0; /* DWORD 0 */
+ u8 interrupt1; /* DWORD 0 */
+ u8 interrupt2; /* DWORD 0 */
+ u8 interrupt3; /* DWORD 0 */
+ u8 interrupt4; /* DWORD 0 */
+ u8 interrupt5; /* DWORD 0 */
+ u8 interrupt6; /* DWORD 0 */
+ u8 interrupt7; /* DWORD 0 */
+ u8 interrupt8; /* DWORD 0 */
+ u8 interrupt9; /* DWORD 0 */
+ u8 interrupt10; /* DWORD 0 */
+ u8 interrupt11; /* DWORD 0 */
+ u8 interrupt12; /* DWORD 0 */
+ u8 interrupt13; /* DWORD 0 */
+ u8 interrupt14; /* DWORD 0 */
+ u8 interrupt15; /* DWORD 0 */
+ u8 interrupt16; /* DWORD 0 */
+ u8 interrupt17; /* DWORD 0 */
+ u8 interrupt18; /* DWORD 0 */
+ u8 interrupt19; /* DWORD 0 */
+ u8 interrupt20; /* DWORD 0 */
+ u8 interrupt21; /* DWORD 0 */
+ u8 interrupt22; /* DWORD 0 */
+ u8 interrupt23; /* DWORD 0 */
+ u8 interrupt24; /* DWORD 0 */
+ u8 interrupt25; /* DWORD 0 */
+ u8 interrupt26; /* DWORD 0 */
+ u8 interrupt27; /* DWORD 0 */
+ u8 interrupt28; /* DWORD 0 */
+ u8 interrupt29; /* DWORD 0 */
+ u8 interrupt30; /* DWORD 0 */
+ u8 interrupt31; /* DWORD 0 */
+} __packed;
+struct CEV_ISR0_CSR_AMAP {
+ u32 dw[1];
+};
+
+/*
+ * Host Interrupt Status Register 1. The second of four application
+ * interrupt status registers. This register contains the interrupts
+ * for Event Queues EQ32 through EQ63.
+ */
+struct BE_CEV_ISR1_CSR_AMAP {
+ u8 interrupt32; /* DWORD 0 */
+ u8 interrupt33; /* DWORD 0 */
+ u8 interrupt34; /* DWORD 0 */
+ u8 interrupt35; /* DWORD 0 */
+ u8 interrupt36; /* DWORD 0 */
+ u8 interrupt37; /* DWORD 0 */
+ u8 interrupt38; /* DWORD 0 */
+ u8 interrupt39; /* DWORD 0 */
+ u8 interrupt40; /* DWORD 0 */
+ u8 interrupt41; /* DWORD 0 */
+ u8 interrupt42; /* DWORD 0 */
+ u8 interrupt43; /* DWORD 0 */
+ u8 interrupt44; /* DWORD 0 */
+ u8 interrupt45; /* DWORD 0 */
+ u8 interrupt46; /* DWORD 0 */
+ u8 interrupt47; /* DWORD 0 */
+ u8 interrupt48; /* DWORD 0 */
+ u8 interrupt49; /* DWORD 0 */
+ u8 interrupt50; /* DWORD 0 */
+ u8 interrupt51; /* DWORD 0 */
+ u8 interrupt52; /* DWORD 0 */
+ u8 interrupt53; /* DWORD 0 */
+ u8 interrupt54; /* DWORD 0 */
+ u8 interrupt55; /* DWORD 0 */
+ u8 interrupt56; /* DWORD 0 */
+ u8 interrupt57; /* DWORD 0 */
+ u8 interrupt58; /* DWORD 0 */
+ u8 interrupt59; /* DWORD 0 */
+ u8 interrupt60; /* DWORD 0 */
+ u8 interrupt61; /* DWORD 0 */
+ u8 interrupt62; /* DWORD 0 */
+ u8 interrupt63; /* DWORD 0 */
+} __packed;
+struct CEV_ISR1_CSR_AMAP {
+ u32 dw[1];
+};
+/*
+ * Host Interrupt Status Register 2. The third of four application
+ * interrupt status registers. This register contains the interrupts
+ * for Event Queues EQ64 through EQ95.
+ */
+struct BE_CEV_ISR2_CSR_AMAP {
+ u8 interrupt64; /* DWORD 0 */
+ u8 interrupt65; /* DWORD 0 */
+ u8 interrupt66; /* DWORD 0 */
+ u8 interrupt67; /* DWORD 0 */
+ u8 interrupt68; /* DWORD 0 */
+ u8 interrupt69; /* DWORD 0 */
+ u8 interrupt70; /* DWORD 0 */
+ u8 interrupt71; /* DWORD 0 */
+ u8 interrupt72; /* DWORD 0 */
+ u8 interrupt73; /* DWORD 0 */
+ u8 interrupt74; /* DWORD 0 */
+ u8 interrupt75; /* DWORD 0 */
+ u8 interrupt76; /* DWORD 0 */
+ u8 interrupt77; /* DWORD 0 */
+ u8 interrupt78; /* DWORD 0 */
+ u8 interrupt79; /* DWORD 0 */
+ u8 interrupt80; /* DWORD 0 */
+ u8 interrupt81; /* DWORD 0 */
+ u8 interrupt82; /* DWORD 0 */
+ u8 interrupt83; /* DWORD 0 */
+ u8 interrupt84; /* DWORD 0 */
+ u8 interrupt85; /* DWORD 0 */
+ u8 interrupt86; /* DWORD 0 */
+ u8 interrupt87; /* DWORD 0 */
+ u8 interrupt88; /* DWORD 0 */
+ u8 interrupt89; /* DWORD 0 */
+ u8 interrupt90; /* DWORD 0 */
+ u8 interrupt91; /* DWORD 0 */
+ u8 interrupt92; /* DWORD 0 */
+ u8 interrupt93; /* DWORD 0 */
+ u8 interrupt94; /* DWORD 0 */
+ u8 interrupt95; /* DWORD 0 */
+} __packed;
+struct CEV_ISR2_CSR_AMAP {
+ u32 dw[1];
+};
+
+/*
+ * Host Interrupt Status Register 3. The fourth of four application
+ * interrupt status registers. This register contains the interrupts
+ * for Event Queues EQ96 through EQ127.
+ */
+struct BE_CEV_ISR3_CSR_AMAP {
+ u8 interrupt96; /* DWORD 0 */
+ u8 interrupt97; /* DWORD 0 */
+ u8 interrupt98; /* DWORD 0 */
+ u8 interrupt99; /* DWORD 0 */
+ u8 interrupt100; /* DWORD 0 */
+ u8 interrupt101; /* DWORD 0 */
+ u8 interrupt102; /* DWORD 0 */
+ u8 interrupt103; /* DWORD 0 */
+ u8 interrupt104; /* DWORD 0 */
+ u8 interrupt105; /* DWORD 0 */
+ u8 interrupt106; /* DWORD 0 */
+ u8 interrupt107; /* DWORD 0 */
+ u8 interrupt108; /* DWORD 0 */
+ u8 interrupt109; /* DWORD 0 */
+ u8 interrupt110; /* DWORD 0 */
+ u8 interrupt111; /* DWORD 0 */
+ u8 interrupt112; /* DWORD 0 */
+ u8 interrupt113; /* DWORD 0 */
+ u8 interrupt114; /* DWORD 0 */
+ u8 interrupt115; /* DWORD 0 */
+ u8 interrupt116; /* DWORD 0 */
+ u8 interrupt117; /* DWORD 0 */
+ u8 interrupt118; /* DWORD 0 */
+ u8 interrupt119; /* DWORD 0 */
+ u8 interrupt120; /* DWORD 0 */
+ u8 interrupt121; /* DWORD 0 */
+ u8 interrupt122; /* DWORD 0 */
+ u8 interrupt123; /* DWORD 0 */
+ u8 interrupt124; /* DWORD 0 */
+ u8 interrupt125; /* DWORD 0 */
+ u8 interrupt126; /* DWORD 0 */
+ u8 interrupt127; /* DWORD 0 */
+} __packed;
+struct CEV_ISR3_CSR_AMAP {
+ u32 dw[1];
+};
+
+/* Completions and Events block Registers. */
+struct BE_CEV_CSRMAP_AMAP {
+ u8 rsvd0[32]; /* DWORD 0 */
+ u8 rsvd1[32]; /* DWORD 1 */
+ u8 rsvd2[32]; /* DWORD 2 */
+ u8 rsvd3[32]; /* DWORD 3 */
+ struct BE_CEV_ISR0_CSR_AMAP isr0;
+ struct BE_CEV_ISR1_CSR_AMAP isr1;
+ struct BE_CEV_ISR2_CSR_AMAP isr2;
+ struct BE_CEV_ISR3_CSR_AMAP isr3;
+ u8 rsvd4[32]; /* DWORD 8 */
+ u8 rsvd5[32]; /* DWORD 9 */
+ u8 rsvd6[32]; /* DWORD 10 */
+ u8 rsvd7[32]; /* DWORD 11 */
+ u8 rsvd8[32]; /* DWORD 12 */
+ u8 rsvd9[32]; /* DWORD 13 */
+ u8 rsvd10[32]; /* DWORD 14 */
+ u8 rsvd11[32]; /* DWORD 15 */
+ u8 rsvd12[32]; /* DWORD 16 */
+ u8 rsvd13[32]; /* DWORD 17 */
+ u8 rsvd14[32]; /* DWORD 18 */
+ u8 rsvd15[32]; /* DWORD 19 */
+ u8 rsvd16[32]; /* DWORD 20 */
+ u8 rsvd17[32]; /* DWORD 21 */
+ u8 rsvd18[32]; /* DWORD 22 */
+ u8 rsvd19[32]; /* DWORD 23 */
+ u8 rsvd20[32]; /* DWORD 24 */
+ u8 rsvd21[32]; /* DWORD 25 */
+ u8 rsvd22[32]; /* DWORD 26 */
+ u8 rsvd23[32]; /* DWORD 27 */
+ u8 rsvd24[32]; /* DWORD 28 */
+ u8 rsvd25[32]; /* DWORD 29 */
+ u8 rsvd26[32]; /* DWORD 30 */
+ u8 rsvd27[32]; /* DWORD 31 */
+ u8 rsvd28[32]; /* DWORD 32 */
+ u8 rsvd29[32]; /* DWORD 33 */
+ u8 rsvd30[192]; /* DWORD 34 */
+ u8 rsvd31[192]; /* DWORD 40 */
+ u8 rsvd32[160]; /* DWORD 46 */
+ u8 rsvd33[160]; /* DWORD 51 */
+ u8 rsvd34[160]; /* DWORD 56 */
+ u8 rsvd35[96]; /* DWORD 61 */
+ u8 rsvd36[192][32]; /* DWORD 64 */
+} __packed;
+struct CEV_CSRMAP_AMAP {
+ u32 dw[256];
+};
+
+#endif /* __cev_amap_h__ */
diff --git a/drivers/staging/benet/cq.c b/drivers/staging/benet/cq.c
new file mode 100644
index 000000000000..650458645433
--- /dev/null
+++ b/drivers/staging/benet/cq.c
@@ -0,0 +1,211 @@
+/*
+ * 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:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+#include "hwlib.h"
+#include "bestatus.h"
+
+/*
+ * Completion Queue Objects
+ */
+/*
+ *============================================================================
+ * P U B L I C R O U T I N E S
+ *============================================================================
+ */
+
+/*
+ This routine creates a completion queue based on the client completion
+ queue configuration information.
+
+
+ FunctionObject - Handle to a function object
+ CqBaseVa - Base VA for a the CQ ring
+ NumEntries - CEV_CQ_CNT_* values
+ solEventEnable - 0 = All CQEs can generate Events if CQ is eventable
+ 1 = only CQEs with solicited bit set are eventable
+ eventable - Eventable CQ, generates interrupts.
+ nodelay - 1 = Force interrupt, relevent if CQ eventable.
+ Interrupt is asserted immediately after EQE
+ write is confirmed, regardless of EQ Timer
+ or watermark settings.
+ wme - Enable watermark based coalescing
+ wmThresh - High watermark(CQ fullness at which event
+ or interrupt should be asserted). These are the
+ CEV_WATERMARK encoded values.
+ EqObject - EQ Handle to assign to this CQ
+ ppCqObject - Internal CQ Handle returned.
+
+ Returns BE_SUCCESS if successfull, otherwise a useful error code is
+ returned.
+
+ IRQL < DISPATCH_LEVEL
+
+*/
+int be_cq_create(struct be_function_object *pfob,
+ struct ring_desc *rd, u32 length, bool solicited_eventable,
+ bool no_delay, u32 wm_thresh,
+ struct be_eq_object *eq_object, struct be_cq_object *cq_object)
+{
+ int status = BE_SUCCESS;
+ u32 num_entries_encoding;
+ u32 num_entries = length / sizeof(struct MCC_CQ_ENTRY_AMAP);
+ struct FWCMD_COMMON_CQ_CREATE *fwcmd = NULL;
+ struct MCC_WRB_AMAP *wrb = NULL;
+ u32 n;
+ unsigned long irql;
+
+ ASSERT(rd);
+ ASSERT(cq_object);
+ ASSERT(length % sizeof(struct MCC_CQ_ENTRY_AMAP) == 0);
+
+ switch (num_entries) {
+ case 256:
+ num_entries_encoding = CEV_CQ_CNT_256;
+ break;
+ case 512:
+ num_entries_encoding = CEV_CQ_CNT_512;
+ break;
+ case 1024:
+ num_entries_encoding = CEV_CQ_CNT_1024;
+ break;
+ default:
+ ASSERT(0);
+ return BE_STATUS_INVALID_PARAMETER;
+ }
+
+ /*
+ * All cq entries all the same size. Use iSCSI version
+ * as a test for the proper rd length.
+ */
+ memset(cq_object, 0, sizeof(*cq_object));
+
+ atomic_set(&cq_object->ref_count, 0);
+ cq_object->parent_function = pfob;
+ cq_object->eq_object = eq_object;
+ cq_object->num_entries = num_entries;
+ /* save for MCC cq processing */
+ cq_object->va = rd->va;
+
+ /* map into UT. */
+ length = num_entries * sizeof(struct MCC_CQ_ENTRY_AMAP);
+
+ spin_lock_irqsave(&pfob->post_lock, irql);
+
+ wrb = be_function_peek_mcc_wrb(pfob);
+ if (!wrb) {
+ ASSERT(wrb);
+ TRACE(DL_ERR, "No free MCC WRBs in create EQ.");
+ status = BE_STATUS_NO_MCC_WRB;
+ goto Error;
+ }
+ /* Prepares an embedded fwcmd, including request/response sizes. */
+ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_CQ_CREATE);
+
+ fwcmd->params.request.num_pages = PAGES_SPANNED(OFFSET_IN_PAGE(rd->va),
+ length);
+
+ AMAP_SET_BITS_PTR(CQ_CONTEXT, valid, &fwcmd->params.request.context, 1);
+ n = pfob->pci_function_number;
+ AMAP_SET_BITS_PTR(CQ_CONTEXT, Func, &fwcmd->params.request.context, n);
+
+ n = (eq_object != NULL);
+ AMAP_SET_BITS_PTR(CQ_CONTEXT, Eventable,
+ &fwcmd->params.request.context, n);
+ AMAP_SET_BITS_PTR(CQ_CONTEXT, Armed, &fwcmd->params.request.context, 1);
+
+ n = eq_object ? eq_object->eq_id : 0;
+ AMAP_SET_BITS_PTR(CQ_CONTEXT, EQID, &fwcmd->params.request.context, n);
+ AMAP_SET_BITS_PTR(CQ_CONTEXT, Count,
+ &fwcmd->params.request.context, num_entries_encoding);
+
+ n = 0; /* Protection Domain is always 0 in Linux driver */
+ AMAP_SET_BITS_PTR(CQ_CONTEXT, PD, &fwcmd->params.request.context, n);
+ AMAP_SET_BITS_PTR(CQ_CONTEXT, NoDelay,
+ &fwcmd->params.request.context, no_delay);
+ AMAP_SET_BITS_PTR(CQ_CONTEXT, SolEvent,
+ &fwcmd->params.request.context, solicited_eventable);
+
+ n = (wm_thresh != 0xFFFFFFFF);
+ AMAP_SET_BITS_PTR(CQ_CONTEXT, WME, &fwcmd->params.request.context, n);
+
+ n = (n ? wm_thresh : 0);
+ AMAP_SET_BITS_PTR(CQ_CONTEXT, Watermark,
+ &fwcmd->params.request.context, n);
+ /* Create a page list for the FWCMD. */
+ be_rd_to_pa_list(rd, fwcmd->params.request.pages,
+ ARRAY_SIZE(fwcmd->params.request.pages));
+
+ /* Post the f/w command */
+ status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL,
+ NULL, NULL, fwcmd, NULL);
+ if (status != BE_SUCCESS) {
+ TRACE(DL_ERR, "MCC to create CQ failed.");
+ goto Error;
+ }
+ /* Remember the CQ id. */
+ cq_object->cq_id = fwcmd->params.response.cq_id;
+
+ /* insert this cq into eq_object reference */
+ if (eq_object) {
+ atomic_inc(&eq_object->ref_count);
+ list_add_tail(&cq_object->cqlist_for_eq,
+ &eq_object->cq_list_head);
+ }
+
+Error:
+ spin_unlock_irqrestore(&pfob->post_lock, irql);
+
+ if (pfob->pend_queue_driving && pfob->mcc) {
+ pfob->pend_queue_driving = 0;
+ be_drive_mcc_wrb_queue(pfob->mcc);
+ }
+ return status;
+}
+
+/*
+
+ Deferences the given object. Once the object's reference count drops to
+ zero, the object is destroyed and all resources that are held by this object
+ are released. The on-chip context is also destroyed along with the queue
+ ID, and any mappings made into the UT.
+
+ cq_object - CQ handle returned from cq_object_create.
+
+ returns the current reference count on the object
+
+ IRQL: IRQL < DISPATCH_LEVEL
+*/
+int be_cq_destroy(struct be_cq_object *cq_object)
+{
+ int status = 0;
+
+ /* Nothing should reference this CQ at this point. */
+ ASSERT(atomic_read(&cq_object->ref_count) == 0);
+
+ /* Send fwcmd to destroy the CQ. */
+ status = be_function_ring_destroy(cq_object->parent_function,
+ cq_object->cq_id, FWCMD_RING_TYPE_CQ,
+ NULL, NULL, NULL, NULL);
+ ASSERT(status == 0);
+
+ /* Remove reference if this is an eventable CQ. */
+ if (cq_object->eq_object) {
+ atomic_dec(&cq_object->eq_object->ref_count);
+ list_del(&cq_object->cqlist_for_eq);
+ }
+ return BE_SUCCESS;
+}
+
diff --git a/drivers/staging/benet/descriptors.h b/drivers/staging/benet/descriptors.h
new file mode 100644
index 000000000000..8da438c407d2
--- /dev/null
+++ b/drivers/staging/benet/descriptors.h
@@ -0,0 +1,71 @@
+/*
+ * 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:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+/*
+ * Autogenerated by srcgen version: 0127
+ */
+#ifndef __descriptors_amap_h__
+#define __descriptors_amap_h__
+
+/*
+ * --- IPC_NODE_ID_ENUM ---
+ * IPC processor id values
+ */
+#define TPOST_NODE_ID (0) /* TPOST ID */
+#define TPRE_NODE_ID (1) /* TPRE ID */
+#define TXULP0_NODE_ID (2) /* TXULP0 ID */
+#define TXULP1_NODE_ID (3) /* TXULP1 ID */
+#define TXULP2_NODE_ID (4) /* TXULP2 ID */
+#define RXULP0_NODE_ID (5) /* RXULP0 ID */
+#define RXULP1_NODE_ID (6) /* RXULP1 ID */
+#define RXULP2_NODE_ID (7) /* RXULP2 ID */
+#define MPU_NODE_ID (15) /* MPU ID */
+
+/*
+ * --- MAC_ID_ENUM ---
+ * Meaning of the mac_id field in rxpp_eth_d
+ */
+#define PORT0_HOST_MAC0 (0) /* PD 0, Port 0, host networking, MAC 0. */
+#define PORT0_HOST_MAC1 (1) /* PD 0, Port 0, host networking, MAC 1. */
+#define PORT0_STORAGE_MAC0 (2) /* PD 0, Port 0, host storage, MAC 0. */
+#define PORT0_STORAGE_MAC1 (3) /* PD 0, Port 0, host storage, MAC 1. */
+#define PORT1_HOST_MAC0 (4) /* PD 0, Port 1 host networking, MAC 0. */
+#define PORT1_HOST_MAC1 (5) /* PD 0, Port 1 host networking, MAC 1. */
+#define PORT1_STORAGE_MAC0 (6) /* PD 0, Port 1 host storage, MAC 0. */
+#define PORT1_STORAGE_MAC1 (7) /* PD 0, Port 1 host storage, MAC 1. */
+#define FIRST_VM_MAC (8) /* PD 1 MAC. Protection domains have IDs */
+ /* from 0x8-0x26, one per PD. */
+#define LAST_VM_MAC (38) /* PD 31 MAC. */
+#define MGMT_MAC (39) /* Management port MAC. */
+#define MARBLE_MAC0 (59) /* Used for flushing function 0 receive */
+ /*
+ * queues before re-using a torn-down
+ * receive ring. the DA =
+ * 00-00-00-00-00-00, and the MSB of the
+ * SA = 00
+ */
+#define MARBLE_MAC1 (60) /* Used for flushing function 1 receive */
+ /*
+ * queues before re-using a torn-down
+ * receive ring. the DA =
+ * 00-00-00-00-00-00, and the MSB of the
+ * SA != 00
+ */
+#define NULL_MAC (61) /* Promiscuous mode, indicates no match */
+#define MCAST_MAC (62) /* Multicast match. */
+#define BCAST_MATCH (63) /* Broadcast match. */
+
+#endif /* __descriptors_amap_h__ */
diff --git a/drivers/staging/benet/doorbells.h b/drivers/staging/benet/doorbells.h
new file mode 100644
index 000000000000..550cc4d5d6f7
--- /dev/null
+++ b/drivers/staging/benet/doorbells.h
@@ -0,0 +1,179 @@
+/*
+ * 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:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+/*
+ * Autogenerated by srcgen version: 0127
+ */
+#ifndef __doorbells_amap_h__
+#define __doorbells_amap_h__
+
+/* The TX/RDMA send queue doorbell. */
+struct BE_SQ_DB_AMAP {
+ u8 cid[11]; /* DWORD 0 */
+ u8 rsvd0[5]; /* DWORD 0 */
+ u8 numPosted[14]; /* DWORD 0 */
+ u8 rsvd1[2]; /* DWORD 0 */
+} __packed;
+struct SQ_DB_AMAP {
+ u32 dw[1];
+};
+
+/* The receive queue doorbell. */
+struct BE_RQ_DB_AMAP {
+ u8 rq[10]; /* DWORD 0 */
+ u8 rsvd0[13]; /* DWORD 0 */
+ u8 Invalidate; /* DWORD 0 */
+ u8 numPosted[8]; /* DWORD 0 */
+} __packed;
+struct RQ_DB_AMAP {
+ u32 dw[1];
+};
+
+/*
+ * The CQ/EQ doorbell. Software MUST set reserved fields in this
+ * descriptor to zero, otherwise (CEV) hardware will not execute the
+ * doorbell (flagging a bad_db_qid error instead).
+ */
+struct BE_CQ_DB_AMAP {
+ u8 qid[10]; /* DWORD 0 */
+ u8 rsvd0[4]; /* DWORD 0 */
+ u8 rearm; /* DWORD 0 */
+ u8 event; /* DWORD 0 */
+ u8 num_popped[13]; /* DWORD 0 */
+ u8 rsvd1[3]; /* DWORD 0 */
+} __packed;
+struct CQ_DB_AMAP {
+ u32 dw[1];
+};
+
+struct BE_TPM_RQ_DB_AMAP {
+ u8 qid[10]; /* DWORD 0 */
+ u8 rsvd0[6]; /* DWORD 0 */
+ u8 numPosted[11]; /* DWORD 0 */
+ u8 mss_cnt[5]; /* DWORD 0 */
+} __packed;
+struct TPM_RQ_DB_AMAP {
+ u32 dw[1];
+};
+
+/*
+ * Post WRB Queue Doorbell Register used by the host Storage stack
+ * to notify the controller of a posted Work Request Block
+ */
+struct BE_WRB_POST_DB_AMAP {
+ u8 wrb_cid[10]; /* DWORD 0 */
+ u8 rsvd0[6]; /* DWORD 0 */
+ u8 wrb_index[8]; /* DWORD 0 */
+ u8 numberPosted[8]; /* DWORD 0 */
+} __packed;
+struct WRB_POST_DB_AMAP {
+ u32 dw[1];
+};
+
+/*
+ * Update Default PDU Queue Doorbell Register used to communicate
+ * to the controller that the driver has stopped processing the queue
+ * and where in the queue it stopped, this is
+ * a CQ Entry Type. Used by storage driver.
+ */
+struct BE_DEFAULT_PDU_DB_AMAP {
+ u8 qid[10]; /* DWORD 0 */
+ u8 rsvd0[4]; /* DWORD 0 */
+ u8 rearm; /* DWORD 0 */
+ u8 event; /* DWORD 0 */
+ u8 cqproc[14]; /* DWORD 0 */
+ u8 rsvd1[2]; /* DWORD 0 */
+} __packed;
+struct DEFAULT_PDU_DB_AMAP {
+ u32 dw[1];
+};
+
+/* Management Command and Controller default fragment ring */
+struct BE_MCC_DB_AMAP {
+ u8 rid[11]; /* DWORD 0 */
+ u8 rsvd0[5]; /* DWORD 0 */
+ u8 numPosted[14]; /* DWORD 0 */
+ u8 rsvd1[2]; /* DWORD 0 */
+} __packed;
+struct MCC_DB_AMAP {
+ u32 dw[1];
+};
+
+/*
+ * Used for bootstrapping the Host interface. This register is
+ * used for driver communication with the MPU when no MCC Rings exist.
+ * The software must write this register twice to post any MCC
+ * command. First, it writes the register with hi=1 and the upper bits of
+ * the physical address for the MCC_MAILBOX structure. Software must poll
+ * the ready bit until this is acknowledged. Then, sotware writes the
+ * register with hi=0 with the lower bits in the address. It must
+ * poll the ready bit until the MCC command is complete. Upon completion,
+ * the MCC_MAILBOX will contain a valid completion queue entry.
+ */
+struct BE_MPU_MAILBOX_DB_AMAP {
+ u8 ready; /* DWORD 0 */
+ u8 hi; /* DWORD 0 */
+ u8 address[30]; /* DWORD 0 */
+} __packed;
+struct MPU_MAILBOX_DB_AMAP {
+ u32 dw[1];
+};
+
+/*
+ * This is the protection domain doorbell register map. Note that
+ * while this map shows doorbells for all Blade Engine supported
+ * protocols, not all of these may be valid in a given function or
+ * protection domain. It is the responsibility of the application
+ * accessing the doorbells to know which are valid. Each doorbell
+ * occupies 32 bytes of space, but unless otherwise specified,
+ * only the first 4 bytes should be written. There are 32 instances
+ * of these doorbells for the host and 31 virtual machines respectively.
+ * The host and VMs will only map the doorbell pages belonging to its
+ * protection domain. It will not be able to touch the doorbells for
+ * another VM. The doorbells are the only registers directly accessible
+ * by a virtual machine. Similarly, there are 511 additional
+ * doorbells for RDMA protection domains. PD 0 for RDMA shares
+ * the same physical protection domain doorbell page as ETH/iSCSI.
+ *
+ */
+struct BE_PROTECTION_DOMAIN_DBMAP_AMAP {
+ u8 rsvd0[512]; /* DWORD 0 */
+ struct BE_SQ_DB_AMAP rdma_sq_db;
+ u8 rsvd1[7][32]; /* DWORD 17 */
+ struct BE_WRB_POST_DB_AMAP iscsi_wrb_post_db;
+ u8 rsvd2[7][32]; /* DWORD 25 */
+ struct BE_SQ_DB_AMAP etx_sq_db;
+ u8 rsvd3[7][32]; /* DWORD 33 */
+ struct BE_RQ_DB_AMAP rdma_rq_db;
+ u8 rsvd4[7][32]; /* DWORD 41 */
+ struct BE_DEFAULT_PDU_DB_AMAP iscsi_default_pdu_db;
+ u8 rsvd5[7][32]; /* DWORD 49 */
+ struct BE_TPM_RQ_DB_AMAP tpm_rq_db;
+ u8 rsvd6[7][32]; /* DWORD 57 */
+ struct BE_RQ_DB_AMAP erx_rq_db;
+ u8 rsvd7[7][32]; /* DWORD 65 */
+ struct BE_CQ_DB_AMAP cq_db;
+ u8 rsvd8[7][32]; /* DWORD 73 */
+ struct BE_MCC_DB_AMAP mpu_mcc_db;
+ u8 rsvd9[7][32]; /* DWORD 81 */
+ struct BE_MPU_MAILBOX_DB_AMAP mcc_bootstrap_db;
+ u8 rsvd10[935][32]; /* DWORD 89 */
+} __packed;
+struct PROTECTION_DOMAIN_DBMAP_AMAP {
+ u32 dw[1024];
+};
+
+#endif /* __doorbells_amap_h__ */
diff --git a/drivers/staging/benet/ep.h b/drivers/staging/benet/ep.h
new file mode 100644
index 000000000000..72fcf64a9ffb
--- /dev/null
+++ b/drivers/staging/benet/ep.h
@@ -0,0 +1,66 @@
+/*
+ * 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:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+/*
+ * Autogenerated by srcgen version: 0127
+ */
+#ifndef __ep_amap_h__
+#define __ep_amap_h__
+
+/* General Control and Status Register. */
+struct BE_EP_CONTROL_CSR_AMAP {
+ u8 m0_RxPbuf; /* DWORD 0 */
+ u8 m1_RxPbuf; /* DWORD 0 */
+ u8 m2_RxPbuf; /* DWORD 0 */
+ u8 ff_en; /* DWORD 0 */
+ u8 rsvd0[27]; /* DWORD 0 */
+ u8 CPU_reset; /* DWORD 0 */
+} __packed;
+struct EP_CONTROL_CSR_AMAP {
+ u32 dw[1];
+};
+
+/* Semaphore Register. */
+struct BE_EP_SEMAPHORE_CSR_AMAP {
+ u8 value[32]; /* DWORD 0 */
+} __packed;
+struct EP_SEMAPHORE_CSR_AMAP {
+ u32 dw[1];
+};
+
+/* Embedded Processor Specific Registers. */
+struct BE_EP_CSRMAP_AMAP {
+ struct BE_EP_CONTROL_CSR_AMAP ep_control;
+ u8 rsvd0[32]; /* DWORD 1 */
+ u8 rsvd1[32]; /* DWORD 2 */
+ u8 rsvd2[32]; /* DWORD 3 */
+ u8 rsvd3[32]; /* DWORD 4 */
+ u8 rsvd4[32]; /* DWORD 5 */
+ u8 rsvd5[8][128]; /* DWORD 6 */
+ u8 rsvd6[32]; /* DWORD 38 */
+ u8 rsvd7[32]; /* DWORD 39 */
+ u8 rsvd8[32]; /* DWORD 40 */
+ u8 rsvd9[32]; /* DWORD 41 */
+ u8 rsvd10[32]; /* DWORD 42 */
+ struct BE_EP_SEMAPHORE_CSR_AMAP ep_semaphore;
+ u8 rsvd11[32]; /* DWORD 44 */
+ u8 rsvd12[19][32]; /* DWORD 45 */
+} __packed;
+struct EP_CSRMAP_AMAP {
+ u32 dw[64];
+};
+
+#endif /* __ep_amap_h__ */
diff --git a/drivers/staging/benet/eq.c b/drivers/staging/benet/eq.c
new file mode 100644
index 000000000000..db92ccd8fed8
--- /dev/null
+++ b/drivers/staging/benet/eq.c
@@ -0,0 +1,299 @@
+/*
+ * 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:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+#include "hwlib.h"
+#include "bestatus.h"
+/*
+ This routine creates an event queue based on the client completion
+ queue configuration information.
+
+ FunctionObject - Handle to a function object
+ EqBaseVa - Base VA for a the EQ ring
+ SizeEncoding - The encoded size for the EQ entries. This value is
+ either CEV_EQ_SIZE_4 or CEV_EQ_SIZE_16
+ NumEntries - CEV_CQ_CNT_* values.
+ Watermark - Enables watermark based coalescing. This parameter
+ must be of the type CEV_WMARK_* if watermarks
+ are enabled. If watermarks to to be disabled
+ this value should be-1.
+ TimerDelay - If a timer delay is enabled this value should be the
+ time of the delay in 8 microsecond units. If
+ delays are not used this parameter should be
+ set to -1.
+ ppEqObject - Internal EQ Handle returned.
+
+ Returns BE_SUCCESS if successfull,, otherwise a useful error code
+ is returned.
+
+ IRQL < DISPATCH_LEVEL
+*/
+int
+be_eq_create(struct be_function_object *pfob,
+ struct ring_desc *rd, u32 eqe_size, u32 num_entries,
+ u32 watermark, /* CEV_WMARK_* or -1 */
+ u32 timer_delay, /* in 8us units, or -1 */
+ struct be_eq_object *eq_object)
+{
+ int status = BE_SUCCESS;
+ u32 num_entries_encoding, eqe_size_encoding, length;
+ struct FWCMD_COMMON_EQ_CREATE *fwcmd = NULL;
+ struct MCC_WRB_AMAP *wrb = NULL;
+ u32 n;
+ unsigned long irql;
+
+ ASSERT(rd);
+ ASSERT(eq_object);
+
+ switch (num_entries) {
+ case 256:
+ num_entries_encoding = CEV_EQ_CNT_256;
+ break;
+ case 512:
+ num_entries_encoding = CEV_EQ_CNT_512;
+ break;
+ case 1024:
+ num_entries_encoding = CEV_EQ_CNT_1024;
+ break;
+ case 2048:
+ num_entries_encoding = CEV_EQ_CNT_2048;
+ break;
+ case 4096:
+ num_entries_encoding = CEV_EQ_CNT_4096;
+ break;
+ default:
+ ASSERT(0);
+ return BE_STATUS_INVALID_PARAMETER;
+ }
+
+ switch (eqe_size) {
+ case 4:
+ eqe_size_encoding = CEV_EQ_SIZE_4;
+ break;
+ case 16:
+ eqe_size_encoding = CEV_EQ_SIZE_16;
+ break;
+ default:
+ ASSERT(0);
+ return BE_STATUS_INVALID_PARAMETER;
+ }
+
+ if ((eqe_size == 4 && num_entries < 1024) ||
+ (eqe_size == 16 && num_entries == 4096)) {
+ TRACE(DL_ERR, "Bad EQ size. eqe_size:%d num_entries:%d",
+ eqe_size, num_entries);
+ ASSERT(0);
+ return BE_STATUS_INVALID_PARAMETER;
+ }
+
+ memset(eq_object, 0, sizeof(*eq_object));
+
+ atomic_set(&eq_object->ref_count, 0);
+ eq_object->parent_function = pfob;
+ eq_object->eq_id = 0xFFFFFFFF;
+
+ INIT_LIST_HEAD(&eq_object->cq_list_head);
+
+ length = num_entries * eqe_size;
+
+ spin_lock_irqsave(&pfob->post_lock, irql);
+
+ wrb = be_function_peek_mcc_wrb(pfob);
+ if (!wrb) {
+ ASSERT(wrb);
+ TRACE(DL_ERR, "No free MCC WRBs in create EQ.");
+ status = BE_STATUS_NO_MCC_WRB;
+ goto Error;
+ }
+ /* Prepares an embedded fwcmd, including request/response sizes. */
+ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_EQ_CREATE);
+
+ fwcmd->params.request.num_pages = PAGES_SPANNED(OFFSET_IN_PAGE(rd->va),
+ length);
+ n = pfob->pci_function_number;
+ AMAP_SET_BITS_PTR(EQ_CONTEXT, Func, &fwcmd->params.request.context, n);
+
+ AMAP_SET_BITS_PTR(EQ_CONTEXT, valid, &fwcmd->params.request.context, 1);
+
+ AMAP_SET_BITS_PTR(EQ_CONTEXT, Size,
+ &fwcmd->params.request.context, eqe_size_encoding);
+
+ n = 0; /* Protection Domain is always 0 in Linux driver */
+ AMAP_SET_BITS_PTR(EQ_CONTEXT, PD, &fwcmd->params.request.context, n);
+
+ /* Let the caller ARM the EQ with the doorbell. */
+ AMAP_SET_BITS_PTR(EQ_CONTEXT, Armed, &fwcmd->params.request.context, 0);
+
+ AMAP_SET_BITS_PTR(EQ_CONTEXT, Count, &fwcmd->params.request.context,
+ num_entries_encoding);
+
+ n = pfob->pci_function_number * 32;
+ AMAP_SET_BITS_PTR(EQ_CONTEXT, EventVect,
+ &fwcmd->params.request.context, n);
+ if (watermark != -1) {
+ AMAP_SET_BITS_PTR(EQ_CONTEXT, WME,
+ &fwcmd->params.request.context, 1);
+ AMAP_SET_BITS_PTR(EQ_CONTEXT, Watermark,
+ &fwcmd->params.request.context, watermark);
+ ASSERT(watermark <= CEV_WMARK_240);
+ } else
+ AMAP_SET_BITS_PTR(EQ_CONTEXT, WME,
+ &fwcmd->params.request.context, 0);
+ if (timer_delay != -1) {
+ AMAP_SET_BITS_PTR(EQ_CONTEXT, TMR,
+ &fwcmd->params.request.context, 1);
+
+ ASSERT(timer_delay <= 250); /* max value according to EAS */
+ timer_delay = min(timer_delay, (u32)250);
+
+ AMAP_SET_BITS_PTR(EQ_CONTEXT, Delay,
+ &fwcmd->params.request.context, timer_delay);
+ } else {
+ AMAP_SET_BITS_PTR(EQ_CONTEXT, TMR,
+ &fwcmd->params.request.context, 0);
+ }
+ /* Create a page list for the FWCMD. */
+ be_rd_to_pa_list(rd, fwcmd->params.request.pages,
+ ARRAY_SIZE(fwcmd->params.request.pages));
+
+ status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL,
+ NULL, NULL, fwcmd, NULL);
+ if (status != BE_SUCCESS) {
+ TRACE(DL_ERR, "MCC to create EQ failed.");
+ goto Error;
+ }
+ /* Get the EQ id. The MPU allocates the IDs. */
+ eq_object->eq_id = fwcmd->params.response.eq_id;
+
+Error:
+ spin_unlock_irqrestore(&pfob->post_lock, irql);
+
+ if (pfob->pend_queue_driving && pfob->mcc) {
+ pfob->pend_queue_driving = 0;
+ be_drive_mcc_wrb_queue(pfob->mcc);
+ }
+ return status;
+}
+
+/*
+ Deferences the given object. Once the object's reference count drops to
+ zero, the object is destroyed and all resources that are held by this
+ object are released. The on-chip context is also destroyed along with
+ the queue ID, and any mappings made into the UT.
+
+ eq_object - EQ handle returned from eq_object_create.
+
+ Returns BE_SUCCESS if successfull, otherwise a useful error code
+ is returned.
+
+ IRQL: IRQL < DISPATCH_LEVEL
+*/
+int be_eq_destroy(struct be_eq_object *eq_object)
+{
+ int status = 0;
+
+ ASSERT(atomic_read(&eq_object->ref_count) == 0);
+ /* no CQs should reference this EQ now */
+ ASSERT(list_empty(&eq_object->cq_list_head));
+
+ /* Send fwcmd to destroy the EQ. */
+ status = be_function_ring_destroy(eq_object->parent_function,
+ eq_object->eq_id, FWCMD_RING_TYPE_EQ,
+ NULL, NULL, NULL, NULL);
+ ASSERT(status == 0);
+
+ return BE_SUCCESS;
+}
+/*
+ *---------------------------------------------------------------------------
+ * Function: be_eq_modify_delay
+ * Changes the EQ delay for a group of EQs.
+ * num_eq - The number of EQs in the eq_array to adjust.
+ * This also is the number of delay values in
+ * the eq_delay_array.
+ * eq_array - Array of struct be_eq_object pointers to adjust.
+ * eq_delay_array - Array of "num_eq" timer delays in units
+ * of microseconds. The be_eq_query_delay_range
+ * fwcmd returns the resolution and range of
+ * legal EQ delays.
+ * cb -
+ * cb_context -
+ * q_ctxt - Optional. Pointer to a previously allocated
+ * struct. If the MCC WRB ring is full, this
+ * structure is used to queue the operation. It
+ * will be posted to the MCC ring when space
+ * becomes available. All queued commands will
+ * be posted to the ring in the order they are
+ * received. It is always valid to pass a pointer to
+ * a generic be_generic_q_cntxt. However,
+ * the specific context structs
+ * are generally smaller than the generic struct.
+ * return pend_status - BE_SUCCESS (0) on success.
+ * BE_PENDING (postive value) if the FWCMD
+ * completion is pending. Negative error code on failure.
+ *-------------------------------------------------------------------------
+ */
+int
+be_eq_modify_delay(struct be_function_object *pfob,
+ u32 num_eq, struct be_eq_object **eq_array,
+ u32 *eq_delay_array, mcc_wrb_cqe_callback cb,
+ void *cb_context, struct be_eq_modify_delay_q_ctxt *q_ctxt)
+{
+ struct FWCMD_COMMON_MODIFY_EQ_DELAY *fwcmd = NULL;
+ struct MCC_WRB_AMAP *wrb = NULL;
+ int status = 0;
+ struct be_generic_q_ctxt *gen_ctxt = NULL;
+ u32 i;
+ unsigned long irql;
+
+ spin_lock_irqsave(&pfob->post_lock, irql);
+
+ wrb = be_function_peek_mcc_wrb(pfob);
+ if (!wrb) {
+ if (q_ctxt && cb) {
+ wrb = (struct MCC_WRB_AMAP *) &q_ctxt->wrb_header;
+ gen_ctxt = (struct be_generic_q_ctxt *) q_ctxt;
+ gen_ctxt->context.bytes = sizeof(*q_ctxt);
+ } else {
+ status = BE_STATUS_NO_MCC_WRB;
+ goto Error;
+ }
+ }
+ /* Prepares an embedded fwcmd, including request/response sizes. */
+ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_MODIFY_EQ_DELAY);
+
+ ASSERT(num_eq > 0);
+ ASSERT(num_eq <= ARRAY_SIZE(fwcmd->params.request.delay));
+ fwcmd->params.request.num_eq = num_eq;
+ for (i = 0; i < num_eq; i++) {
+ fwcmd->params.request.delay[i].eq_id = eq_array[i]->eq_id;
+ fwcmd->params.request.delay[i].delay_in_microseconds =
+ eq_delay_array[i];
+ }
+
+ /* Post the f/w command */
+ status = be_function_post_mcc_wrb(pfob, wrb, gen_ctxt,
+ cb, cb_context, NULL, NULL, fwcmd, NULL);
+
+Error:
+ spin_unlock_irqrestore(&pfob->post_lock, irql);
+
+ if (pfob->pend_queue_driving && pfob->mcc) {
+ pfob->pend_queue_driving = 0;
+ be_drive_mcc_wrb_queue(pfob->mcc);
+ }
+ return status;
+}
+
diff --git a/drivers/staging/benet/eth.c b/drivers/staging/benet/eth.c
new file mode 100644
index 000000000000..f641b6260d07
--- /dev/null
+++ b/drivers/staging/benet/eth.c
@@ -0,0 +1,1273 @@
+/*
+ * 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:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+#include <linux/if_ether.h>
+#include "hwlib.h"
+#include "bestatus.h"
+
+/*
+ *---------------------------------------------------------
+ * Function: be_eth_sq_create_ex
+ * Creates an ethernet send ring - extended version with
+ * additional parameters.
+ * pfob -
+ * rd - ring address
+ * length_in_bytes -
+ * type - The type of ring to create.
+ * ulp - The requested ULP number for the ring.
+ * This should be zero based, i.e. 0,1,2. This must
+ * be valid NIC ULP based on the firmware config.
+ * All doorbells for this ring must be sent to
+ * this ULP. The first network ring allocated for
+ * each ULP are higher performance than subsequent rings.
+ * cq_object - cq object for completions
+ * ex_parameters - Additional parameters (that may increase in
+ * future revisions). These parameters are only used
+ * for certain ring types -- see
+ * struct be_eth_sq_parameters for details.
+ * eth_sq -
+ * return status - BE_SUCCESS (0) on success. Negative error code on failure.
+ *---------------------------------------------------------
+ */
+int
+be_eth_sq_create_ex(struct be_function_object *pfob, struct ring_desc *rd,
+ u32 length, u32 type, u32 ulp, struct be_cq_object *cq_object,
+ struct be_eth_sq_parameters *ex_parameters,
+ struct be_ethsq_object *eth_sq)
+{
+ struct FWCMD_COMMON_ETH_TX_CREATE *fwcmd = NULL;
+ struct MCC_WRB_AMAP *wrb = NULL;
+ int status = 0;
+ u32 n;
+ unsigned long irql;
+
+ ASSERT(rd);
+ ASSERT(eth_sq);
+ ASSERT(ex_parameters);
+
+ spin_lock_irqsave(&pfob->post_lock, irql);
+
+ memset(eth_sq, 0, sizeof(*eth_sq));
+
+ eth_sq->parent_function = pfob;
+ eth_sq->bid = 0xFFFFFFFF;
+ eth_sq->cq_object = cq_object;
+
+ /* Translate hwlib interface to arm interface. */
+ switch (type) {
+ case BE_ETH_TX_RING_TYPE_FORWARDING:
+ type = ETH_TX_RING_TYPE_FORWARDING;
+ break;
+ case BE_ETH_TX_RING_TYPE_STANDARD:
+ type = ETH_TX_RING_TYPE_STANDARD;
+ break;
+ case BE_ETH_TX_RING_TYPE_BOUND:
+ ASSERT(ex_parameters->port < 2);
+ type = ETH_TX_RING_TYPE_BOUND;
+ break;
+ default:
+ TRACE(DL_ERR, "Invalid eth tx ring type:%d", type);
+ return BE_NOT_OK;
+ break;
+ }
+
+ wrb = be_function_peek_mcc_wrb(pfob);
+ if (!wrb) {
+ ASSERT(wrb);
+ TRACE(DL_ERR, "No free MCC WRBs in create EQ.");
+ status = BE_STATUS_NO_MCC_WRB;
+ goto Error;
+ }
+ /* NIC must be supported by the current config. */
+ ASSERT(pfob->fw_config.nic_ulp_mask);
+
+ /*
+ * The ulp parameter must select a valid NIC ULP
+ * for the current config.
+ */
+ ASSERT((1 << ulp) & pfob->fw_config.nic_ulp_mask);
+
+ /* Prepares an embedded fwcmd, including request/response sizes. */
+ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_ETH_TX_CREATE);
+ fwcmd->header.request.port_number = ex_parameters->port;
+
+ AMAP_SET_BITS_PTR(ETX_CONTEXT, pd_id,
+ &fwcmd->params.request.context, 0);
+
+ n = be_ring_length_to_encoding(length, sizeof(struct ETH_WRB_AMAP));
+ AMAP_SET_BITS_PTR(ETX_CONTEXT, tx_ring_size,
+ &fwcmd->params.request.context, n);
+
+ AMAP_SET_BITS_PTR(ETX_CONTEXT, cq_id_send,
+ &fwcmd->params.request.context, cq_object->cq_id);
+
+ n = pfob->pci_function_number;
+ AMAP_SET_BITS_PTR(ETX_CONTEXT, func, &fwcmd->params.request.context, n);
+
+ fwcmd->params.request.type = type;
+ fwcmd->params.request.ulp_num = (1 << ulp);
+ fwcmd->params.request.num_pages = DIV_ROUND_UP(length, PAGE_SIZE);
+ ASSERT(PAGES_SPANNED(rd->va, rd->length) >=
+ fwcmd->params.request.num_pages);
+
+ /* Create a page list for the FWCMD. */
+ be_rd_to_pa_list(rd, fwcmd->params.request.pages,
+ ARRAY_SIZE(fwcmd->params.request.pages));
+
+ status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL,
+ NULL, NULL, fwcmd, NULL);
+ if (status != BE_SUCCESS) {
+ TRACE(DL_ERR, "MCC to create etx queue failed.");
+ goto Error;
+ }
+ /* save the butler ID */
+ eth_sq->bid = fwcmd->params.response.cid;
+
+ /* add a reference to the corresponding CQ */
+ atomic_inc(&cq_object->ref_count);
+
+Error:
+ spin_unlock_irqrestore(&pfob->post_lock, irql);
+
+ if (pfob->pend_queue_driving && pfob->mcc) {
+ pfob->pend_queue_driving = 0;
+ be_drive_mcc_wrb_queue(pfob->mcc);
+ }
+ return status;
+}
+
+
+/*
+ This routine destroys an ethernet send queue
+
+ EthSq - EthSq Handle returned from EthSqCreate
+
+ This function always return BE_SUCCESS.
+
+ This function frees memory allocated by EthSqCreate for the EthSq Object.
+
+*/
+int be_eth_sq_destroy(struct be_ethsq_object *eth_sq)
+{
+ int status = 0;
+
+ /* Send fwcmd to destroy the queue. */
+ status = be_function_ring_destroy(eth_sq->parent_function, eth_sq->bid,
+ FWCMD_RING_TYPE_ETH_TX, NULL, NULL, NULL, NULL);
+ ASSERT(status == 0);
+
+ /* Derefence any associated CQs. */
+ atomic_dec(&eth_sq->cq_object->ref_count);
+ return status;
+}
+/*
+ This routine attempts to set the transmit flow control parameters.
+
+ FunctionObject - Handle to a function object
+
+ txfc_enable - transmit flow control enable - true for
+ enable, false for disable
+
+ rxfc_enable - receive flow control enable - true for
+ enable, false for disable
+
+ Returns BE_SUCCESS if successfull, otherwise a useful int error
+ code is returned.
+
+ IRQL: < DISPATCH_LEVEL
+
+ This function always fails in non-privileged machine context.
+*/
+int
+be_eth_set_flow_control(struct be_function_object *pfob,
+ bool txfc_enable, bool rxfc_enable)
+{
+ struct FWCMD_COMMON_SET_FLOW_CONTROL *fwcmd = NULL;
+ struct MCC_WRB_AMAP *wrb = NULL;
+ int status = 0;
+ unsigned long irql;
+
+ spin_lock_irqsave(&pfob->post_lock, irql);
+
+ wrb = be_function_peek_mcc_wrb(pfob);
+ if (!wrb) {
+ TRACE(DL_ERR, "MCC wrb peek failed.");
+ status = BE_STATUS_NO_MCC_WRB;
+ goto error;
+ }
+ /* Prepares an embedded fwcmd, including request/response sizes. */
+ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_SET_FLOW_CONTROL);
+
+ fwcmd->params.request.rx_flow_control = rxfc_enable;
+ fwcmd->params.request.tx_flow_control = txfc_enable;
+
+ /* Post the f/w command */
+ status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL,
+ NULL, NULL, fwcmd, NULL);
+
+ if (status != 0) {
+ TRACE(DL_ERR, "set flow control fwcmd failed.");
+ goto error;
+ }
+
+error:
+ spin_unlock_irqrestore(&pfob->post_lock, irql);
+
+ if (pfob->pend_queue_driving && pfob->mcc) {
+ pfob->pend_queue_driving = 0;
+ be_drive_mcc_wrb_queue(pfob->mcc);
+ }
+ return status;
+}
+
+/*
+ This routine attempts to get the transmit flow control parameters.
+
+ pfob - Handle to a function object
+
+ txfc_enable - transmit flow control enable - true for
+ enable, false for disable
+
+ rxfc_enable - receive flow control enable - true for enable,
+ false for disable
+
+ Returns BE_SUCCESS if successfull, otherwise a useful int error code
+ is returned.
+
+ IRQL: < DISPATCH_LEVEL
+
+ This function always fails in non-privileged machine context.
+*/
+int
+be_eth_get_flow_control(struct be_function_object *pfob,
+ bool *txfc_enable, bool *rxfc_enable)
+{
+ struct FWCMD_COMMON_GET_FLOW_CONTROL *fwcmd = NULL;
+ struct MCC_WRB_AMAP *wrb = NULL;
+ int status = 0;
+ unsigned long irql;
+
+ spin_lock_irqsave(&pfob->post_lock, irql);
+
+ wrb = be_function_peek_mcc_wrb(pfob);
+ if (!wrb) {
+ TRACE(DL_ERR, "MCC wrb peek failed.");
+ status = BE_STATUS_NO_MCC_WRB;
+ goto error;
+ }
+ /* Prepares an embedded fwcmd, including request/response sizes. */
+ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_GET_FLOW_CONTROL);
+
+ /* Post the f/w command */
+ status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL,
+ NULL, NULL, fwcmd, NULL);
+
+ if (status != 0) {
+ TRACE(DL_ERR, "get flow control fwcmd failed.");
+ goto error;
+ }
+
+ *txfc_enable = fwcmd->params.response.tx_flow_control;
+ *rxfc_enable = fwcmd->params.response.rx_flow_control;
+
+error:
+ spin_unlock_irqrestore(&pfob->post_lock, irql);
+
+ if (pfob->pend_queue_driving && pfob->mcc) {
+ pfob->pend_queue_driving = 0;
+ be_drive_mcc_wrb_queue(pfob->mcc);
+ }
+ return status;
+}
+
+/*
+ *---------------------------------------------------------
+ * Function: be_eth_set_qos
+ * This function sets the ethernet transmit Quality of Service (QoS)
+ * characteristics of BladeEngine for the domain. All ethernet
+ * transmit rings of the domain will evenly share the bandwidth.
+ * The exeception to sharing is the host primary (super) ethernet
+ * transmit ring as well as the host ethernet forwarding ring
+ * for missed offload data.
+ * pfob -
+ * max_bps - the maximum bits per second in units of
+ * 10 Mbps (valid 0-100)
+ * max_pps - the maximum packets per second in units
+ * of 1 Kpps (0 indicates no limit)
+ * return status - BE_SUCCESS (0) on success. Negative error code on failure.
+ *---------------------------------------------------------
+ */
+int
+be_eth_set_qos(struct be_function_object *pfob, u32 max_bps, u32 max_pps)
+{
+ struct FWCMD_COMMON_SET_QOS *fwcmd = NULL;
+ struct MCC_WRB_AMAP *wrb = NULL;
+ int status = 0;
+ unsigned long irql;
+
+ spin_lock_irqsave(&pfob->post_lock, irql);
+
+ wrb = be_function_peek_mcc_wrb(pfob);
+ if (!wrb) {
+ TRACE(DL_ERR, "MCC wrb peek failed.");
+ status = BE_STATUS_NO_MCC_WRB;
+ goto error;
+ }
+ /* Prepares an embedded fwcmd, including request/response sizes. */
+ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_SET_QOS);
+
+ /* Set fields in fwcmd */
+ fwcmd->params.request.max_bits_per_second_NIC = max_bps;
+ fwcmd->params.request.max_packets_per_second_NIC = max_pps;
+ fwcmd->params.request.valid_flags = QOS_BITS_NIC | QOS_PKTS_NIC;
+
+ /* Post the f/w command */
+ status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL,
+ NULL, NULL, fwcmd, NULL);
+
+ if (status != 0)
+ TRACE(DL_ERR, "network set qos fwcmd failed.");
+
+error:
+ spin_unlock_irqrestore(&pfob->post_lock, irql);
+ if (pfob->pend_queue_driving && pfob->mcc) {
+ pfob->pend_queue_driving = 0;
+ be_drive_mcc_wrb_queue(pfob->mcc);
+ }
+ return status;
+}
+
+/*
+ *---------------------------------------------------------
+ * Function: be_eth_get_qos
+ * This function retrieves the ethernet transmit Quality of Service (QoS)
+ * characteristics for the domain.
+ * max_bps - the maximum bits per second in units of
+ * 10 Mbps (valid 0-100)
+ * max_pps - the maximum packets per second in units of
+ * 1 Kpps (0 indicates no limit)
+ * return status - BE_SUCCESS (0) on success. Negative error code on failure.
+ *---------------------------------------------------------
+ */
+int
+be_eth_get_qos(struct be_function_object *pfob, u32 *max_bps, u32 *max_pps)
+{
+ struct FWCMD_COMMON_GET_QOS *fwcmd = NULL;
+ struct MCC_WRB_AMAP *wrb = NULL;
+ int status = 0;
+ unsigned long irql;
+
+ spin_lock_irqsave(&pfob->post_lock, irql);
+
+ wrb = be_function_peek_mcc_wrb(pfob);
+ if (!wrb) {
+ TRACE(DL_ERR, "MCC wrb peek failed.");
+ status = BE_STATUS_NO_MCC_WRB;
+ goto error;
+ }
+ /* Prepares an embedded fwcmd, including request/response sizes. */
+ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_GET_QOS);
+
+ /* Post the f/w command */
+ status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL,
+ NULL, NULL, fwcmd, NULL);
+
+ if (status != 0) {
+ TRACE(DL_ERR, "network get qos fwcmd failed.");
+ goto error;
+ }
+
+ *max_bps = fwcmd->params.response.max_bits_per_second_NIC;
+ *max_pps = fwcmd->params.response.max_packets_per_second_NIC;
+
+error:
+ spin_unlock_irqrestore(&pfob->post_lock, irql);
+ if (pfob->pend_queue_driving && pfob->mcc) {
+ pfob->pend_queue_driving = 0;
+ be_drive_mcc_wrb_queue(pfob->mcc);
+ }
+ return status;
+}
+
+/*
+ *---------------------------------------------------------
+ * Function: be_eth_set_frame_size
+ * This function sets the ethernet maximum frame size. The previous
+ * values are returned.
+ * pfob -
+ * tx_frame_size - maximum transmit frame size in bytes
+ * rx_frame_size - maximum receive frame size in bytes
+ * return status - BE_SUCCESS (0) on success. Negative error code on failure.
+ *---------------------------------------------------------
+ */
+int
+be_eth_set_frame_size(struct be_function_object *pfob,
+ u32 *tx_frame_size, u32 *rx_frame_size)
+{
+ struct FWCMD_COMMON_SET_FRAME_SIZE *fwcmd = NULL;
+ struct MCC_WRB_AMAP *wrb = NULL;
+ int status = 0;
+ unsigned long irql;
+
+ spin_lock_irqsave(&pfob->post_lock, irql);
+
+ wrb = be_function_peek_mcc_wrb(pfob);
+ if (!wrb) {
+ TRACE(DL_ERR, "MCC wrb peek failed.");
+ status = BE_STATUS_NO_MCC_WRB;
+ goto error;
+ }
+ /* Prepares an embedded fwcmd, including request/response sizes. */
+ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_SET_FRAME_SIZE);
+ fwcmd->params.request.max_tx_frame_size = *tx_frame_size;
+ fwcmd->params.request.max_rx_frame_size = *rx_frame_size;
+
+ /* Post the f/w command */
+ status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL,
+ NULL, NULL, fwcmd, NULL);
+
+ if (status != 0) {
+ TRACE(DL_ERR, "network set frame size fwcmd failed.");
+ goto error;
+ }
+
+ *tx_frame_size = fwcmd->params.response.chip_max_tx_frame_size;
+ *rx_frame_size = fwcmd->params.response.chip_max_rx_frame_size;
+
+error:
+ spin_unlock_irqrestore(&pfob->post_lock, irql);
+ if (pfob->pend_queue_driving && pfob->mcc) {
+ pfob->pend_queue_driving = 0;
+ be_drive_mcc_wrb_queue(pfob->mcc);
+ }
+ return status;
+}
+
+
+/*
+ This routine creates a Ethernet receive ring.
+
+ pfob - handle to a function object
+ rq_base_va - base VA for the default receive ring. this must be
+ exactly 8K in length and continguous physical memory.
+ cq_object - handle to a previously created CQ to be associated
+ with the RQ.
+ pp_eth_rq - pointer to an opqaue handle where an eth
+ receive object is returned.
+ Returns BE_SUCCESS if successfull, , otherwise a useful
+ int error code is returned.
+
+ IRQL: < DISPATCH_LEVEL
+ this function allocates a struct be_ethrq_object *object.
+ there must be no more than 1 of these per function object, unless the
+ function object supports RSS (is networking and on the host).
+ the rq_base_va must point to a buffer of exactly 8K.
+ the erx::host_cqid (or host_stor_cqid) register and erx::ring_page registers
+ will be updated as appropriate on return
+*/
+int
+be_eth_rq_create(struct be_function_object *pfob,
+ struct ring_desc *rd, struct be_cq_object *cq_object,
+ struct be_cq_object *bcmc_cq_object,
+ struct be_ethrq_object *eth_rq)
+{
+ int status = 0;
+ struct MCC_WRB_AMAP *wrb = NULL;
+ struct FWCMD_COMMON_ETH_RX_CREATE *fwcmd = NULL;
+ unsigned long irql;
+
+ /* MPU will set the */
+ ASSERT(rd);
+ ASSERT(eth_rq);
+
+ spin_lock_irqsave(&pfob->post_lock, irql);
+
+ eth_rq->parent_function = pfob;
+ eth_rq->cq_object = cq_object;
+
+ wrb = be_function_peek_mcc_wrb(pfob);
+ if (!wrb) {
+ TRACE(DL_ERR, "MCC wrb peek failed.");
+ status = BE_STATUS_NO_MCC_WRB;
+ goto Error;
+ }
+ /* Prepares an embedded fwcmd, including request/response sizes. */
+ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_ETH_RX_CREATE);
+
+ fwcmd->params.request.num_pages = 2; /* required length */
+ fwcmd->params.request.cq_id = cq_object->cq_id;
+
+ if (bcmc_cq_object)
+ fwcmd->params.request.bcmc_cq_id = bcmc_cq_object->cq_id;
+ else
+ fwcmd->params.request.bcmc_cq_id = 0xFFFF;
+
+ /* Create a page list for the FWCMD. */
+ be_rd_to_pa_list(rd, fwcmd->params.request.pages,
+ ARRAY_SIZE(fwcmd->params.request.pages));
+
+ /* Post the f/w command */
+ status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL,
+ NULL, NULL, fwcmd, NULL);
+ if (status != BE_SUCCESS) {
+ TRACE(DL_ERR, "fwcmd to map eth rxq frags failed.");
+ goto Error;
+ }
+ /* Save the ring ID for cleanup. */
+ eth_rq->rid = fwcmd->params.response.id;
+
+ atomic_inc(&cq_object->ref_count);
+
+Error:
+ spin_unlock_irqrestore(&pfob->post_lock, irql);
+
+ if (pfob->pend_queue_driving && pfob->mcc) {
+ pfob->pend_queue_driving = 0;
+ be_drive_mcc_wrb_queue(pfob->mcc);
+ }
+ return status;
+}
+
+/*
+ This routine destroys an Ethernet receive queue
+
+ eth_rq - ethernet receive queue handle returned from eth_rq_create
+
+ Returns BE_SUCCESS on success and an appropriate int on failure.
+
+ This function frees resourcs allocated by EthRqCreate.
+ The erx::host_cqid (or host_stor_cqid) register and erx::ring_page
+ registers will be updated as appropriate on return
+ IRQL: < DISPATCH_LEVEL
+*/
+
+static void be_eth_rq_destroy_internal_cb(void *context, int status,
+ struct MCC_WRB_AMAP *wrb)
+{
+ struct be_ethrq_object *eth_rq = (struct be_ethrq_object *) context;
+
+ if (status != BE_SUCCESS) {
+ TRACE(DL_ERR, "Destroy eth rq failed in internal callback.\n");
+ } else {
+ /* Dereference any CQs associated with this queue. */
+ atomic_dec(&eth_rq->cq_object->ref_count);
+ }
+
+ return;
+}
+
+int be_eth_rq_destroy(struct be_ethrq_object *eth_rq)
+{
+ int status = BE_SUCCESS;
+
+ /* Send fwcmd to destroy the RQ. */
+ status = be_function_ring_destroy(eth_rq->parent_function,
+ eth_rq->rid, FWCMD_RING_TYPE_ETH_RX, NULL, NULL,
+ be_eth_rq_destroy_internal_cb, eth_rq);
+
+ return status;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ * Function: be_eth_rq_destroy_options
+ * Destroys an ethernet receive ring with finer granularity options
+ * than the standard be_eth_rq_destroy() API function.
+ * eth_rq -
+ * flush - Set to 1 to flush the ring, set to 0 to bypass the flush
+ * cb - Callback function on completion
+ * cb_context - Callback context
+ * return status - BE_SUCCESS (0) on success. Negative error code on failure.
+ *----------------------------------------------------------------------------
+ */
+int
+be_eth_rq_destroy_options(struct be_ethrq_object *eth_rq, bool flush,
+ mcc_wrb_cqe_callback cb, void *cb_context)
+{
+ struct FWCMD_COMMON_RING_DESTROY *fwcmd = NULL;
+ struct MCC_WRB_AMAP *wrb = NULL;
+ int status = BE_SUCCESS;
+ struct be_function_object *pfob = NULL;
+ unsigned long irql;
+
+ pfob = eth_rq->parent_function;
+
+ spin_lock_irqsave(&pfob->post_lock, irql);
+
+ TRACE(DL_INFO, "Destroy eth_rq ring id:%d, flush:%d", eth_rq->rid,
+ flush);
+
+ wrb = be_function_peek_mcc_wrb(pfob);
+ if (!wrb) {
+ ASSERT(wrb);
+ TRACE(DL_ERR, "No free MCC WRBs in destroy eth_rq ring.");
+ status = BE_STATUS_NO_MCC_WRB;
+ goto Error;
+ }
+ /* Prepares an embedded fwcmd, including request/response sizes. */
+ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_RING_DESTROY);
+
+ fwcmd->params.request.id = eth_rq->rid;
+ fwcmd->params.request.ring_type = FWCMD_RING_TYPE_ETH_RX;
+ fwcmd->params.request.bypass_flush = ((0 == flush) ? 1 : 0);
+
+ /* Post the f/w command */
+ status = be_function_post_mcc_wrb(pfob, wrb, NULL, cb, cb_context,
+ be_eth_rq_destroy_internal_cb, eth_rq, fwcmd, NULL);
+
+ if (status != BE_SUCCESS && status != BE_PENDING) {
+ TRACE(DL_ERR, "eth_rq ring destroy failed. id:%d, flush:%d",
+ eth_rq->rid, flush);
+ goto Error;
+ }
+
+Error:
+ spin_unlock_irqrestore(&pfob->post_lock, irql);
+
+ if (pfob->pend_queue_driving && pfob->mcc) {
+ pfob->pend_queue_driving = 0;
+ be_drive_mcc_wrb_queue(pfob->mcc);
+ }
+ return status;
+}
+
+/*
+ This routine queries the frag size for erx.
+
+ pfob - handle to a function object
+
+ frag_size_bytes - erx frag size in bytes that is/was set.
+
+ Returns BE_SUCCESS if successfull, otherwise a useful int error
+ code is returned.
+
+ IRQL: < DISPATCH_LEVEL
+
+*/
+int
+be_eth_rq_get_frag_size(struct be_function_object *pfob, u32 *frag_size_bytes)
+{
+ struct FWCMD_ETH_GET_RX_FRAG_SIZE *fwcmd = NULL;
+ struct MCC_WRB_AMAP *wrb = NULL;
+ int status = 0;
+ unsigned long irql;
+
+ ASSERT(frag_size_bytes);
+
+ spin_lock_irqsave(&pfob->post_lock, irql);
+
+ wrb = be_function_peek_mcc_wrb(pfob);
+ if (!wrb) {
+ TRACE(DL_ERR, "MCC wrb peek failed.");
+ return BE_STATUS_NO_MCC_WRB;
+ }
+ /* Prepares an embedded fwcmd, including request/response sizes. */
+ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, ETH_GET_RX_FRAG_SIZE);
+
+ /* Post the f/w command */
+ status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL,
+ NULL, NULL, fwcmd, NULL);
+
+ if (status != 0) {
+ TRACE(DL_ERR, "get frag size fwcmd failed.");
+ goto error;
+ }
+
+ *frag_size_bytes = 1 << fwcmd->params.response.actual_fragsize_log2;
+
+error:
+ spin_unlock_irqrestore(&pfob->post_lock, irql);
+
+ if (pfob->pend_queue_driving && pfob->mcc) {
+ pfob->pend_queue_driving = 0;
+ be_drive_mcc_wrb_queue(pfob->mcc);
+ }
+ return status;
+}
+
+/*
+ This routine attempts to set the frag size for erx. If the frag size is
+ already set, the attempt fails and the current frag size is returned.
+
+ pfob - Handle to a function object
+
+ frag_size - Erx frag size in bytes that is/was set.
+
+ current_frag_size_bytes - Pointer to location where currrent frag
+ is to be rturned
+
+ Returns BE_SUCCESS if successfull, otherwise a useful int error
+ code is returned.
+
+ IRQL: < DISPATCH_LEVEL
+
+ This function always fails in non-privileged machine context.
+*/
+int
+be_eth_rq_set_frag_size(struct be_function_object *pfob,
+ u32 frag_size, u32 *frag_size_bytes)
+{
+ struct FWCMD_ETH_SET_RX_FRAG_SIZE *fwcmd = NULL;
+ struct MCC_WRB_AMAP *wrb = NULL;
+ int status = 0;
+ unsigned long irql;
+
+ ASSERT(frag_size_bytes);
+
+ spin_lock_irqsave(&pfob->post_lock, irql);
+
+ wrb = be_function_peek_mcc_wrb(pfob);
+ if (!wrb) {
+ TRACE(DL_ERR, "MCC wrb peek failed.");
+ status = BE_STATUS_NO_MCC_WRB;
+ goto error;
+ }
+ /* Prepares an embedded fwcmd, including request/response sizes. */
+ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, ETH_SET_RX_FRAG_SIZE);
+
+ ASSERT(frag_size >= 128 && frag_size <= 16 * 1024);
+
+ /* This is the log2 of the fragsize. This is not the exact
+ * ERX encoding. */
+ fwcmd->params.request.new_fragsize_log2 = __ilog2_u32(frag_size);
+
+ /* Post the f/w command */
+ status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL,
+ NULL, NULL, fwcmd, NULL);
+
+ if (status != 0) {
+ TRACE(DL_ERR, "set frag size fwcmd failed.");
+ goto error;
+ }
+
+ *frag_size_bytes = 1 << fwcmd->params.response.actual_fragsize_log2;
+error:
+ spin_unlock_irqrestore(&pfob->post_lock, irql);
+
+ if (pfob->pend_queue_driving && pfob->mcc) {
+ pfob->pend_queue_driving = 0;
+ be_drive_mcc_wrb_queue(pfob->mcc);
+ }
+ return status;
+}
+
+
+/*
+ This routine gets or sets a mac address for a domain
+ given the port and mac.
+
+ FunctionObject - Function object handle.
+ port1 - Set to TRUE if this function will set/get the Port 1
+ address. Only the host may set this to TRUE.
+ mac1 - Set to TRUE if this function will set/get the
+ MAC 1 address. Only the host may set this to TRUE.
+ write - Set to TRUE if this function should write the mac address.
+ mac_address - Buffer of the mac address to read or write.
+
+ Returns BE_SUCCESS if successfull, otherwise a useful int is returned.
+
+ IRQL: < DISPATCH_LEVEL
+*/
+int be_rxf_mac_address_read_write(struct be_function_object *pfob,
+ bool port1, /* VM must always set to false */
+ bool mac1, /* VM must always set to false */
+ bool mgmt, bool write,
+ bool permanent, u8 *mac_address,
+ mcc_wrb_cqe_callback cb, /* optional */
+ void *cb_context) /* optional */
+{
+ int status = BE_SUCCESS;
+ union {
+ struct FWCMD_COMMON_NTWK_MAC_QUERY *query;
+ struct FWCMD_COMMON_NTWK_MAC_SET *set;
+ } fwcmd = {NULL};
+ struct MCC_WRB_AMAP *wrb = NULL;
+ u32 type = 0;
+ unsigned long irql;
+ struct be_mcc_wrb_response_copy rc;
+
+ spin_lock_irqsave(&pfob->post_lock, irql);
+
+ ASSERT(mac_address);
+
+ ASSERT(port1 == false);
+ ASSERT(mac1 == false);
+
+ wrb = be_function_peek_mcc_wrb(pfob);
+ if (!wrb) {
+ TRACE(DL_ERR, "MCC wrb peek failed.");
+ status = BE_STATUS_NO_MCC_WRB;
+ goto Error;
+ }
+
+ if (mgmt) {
+ type = MAC_ADDRESS_TYPE_MANAGEMENT;
+ } else {
+ if (pfob->type == BE_FUNCTION_TYPE_NETWORK)
+ type = MAC_ADDRESS_TYPE_NETWORK;
+ else
+ type = MAC_ADDRESS_TYPE_STORAGE;
+ }
+
+ if (write) {
+ /* Prepares an embedded fwcmd, including
+ * request/response sizes.
+ */
+ fwcmd.set = BE_PREPARE_EMBEDDED_FWCMD(pfob,
+ wrb, COMMON_NTWK_MAC_SET);
+
+ fwcmd.set->params.request.invalidate = 0;
+ fwcmd.set->params.request.mac1 = (mac1 ? 1 : 0);
+ fwcmd.set->params.request.port = (port1 ? 1 : 0);
+ fwcmd.set->params.request.type = type;
+
+ /* Copy the mac address to set. */
+ fwcmd.set->params.request.mac.SizeOfStructure =
+ sizeof(fwcmd.set->params.request.mac);
+ memcpy(fwcmd.set->params.request.mac.MACAddress,
+ mac_address, ETH_ALEN);
+
+ /* Post the f/w command */
+ status = be_function_post_mcc_wrb(pfob, wrb, NULL,
+ cb, cb_context, NULL, NULL, fwcmd.set, NULL);
+
+ } else {
+
+ /*
+ * Prepares an embedded fwcmd, including
+ * request/response sizes.
+ */
+ fwcmd.query = BE_PREPARE_EMBEDDED_FWCMD(pfob,
+ wrb, COMMON_NTWK_MAC_QUERY);
+
+ fwcmd.query->params.request.mac1 = (mac1 ? 1 : 0);
+ fwcmd.query->params.request.port = (port1 ? 1 : 0);
+ fwcmd.query->params.request.type = type;
+ fwcmd.query->params.request.permanent = permanent;
+
+ rc.length = FIELD_SIZEOF(struct FWCMD_COMMON_NTWK_MAC_QUERY,
+ params.response.mac.MACAddress);
+ rc.fwcmd_offset = offsetof(struct FWCMD_COMMON_NTWK_MAC_QUERY,
+ params.response.mac.MACAddress);
+ rc.va = mac_address;
+ /* Post the f/w command (with a copy for the response) */
+ status = be_function_post_mcc_wrb(pfob, wrb, NULL, cb,
+ cb_context, NULL, NULL, fwcmd.query, &rc);
+ }
+
+ if (status < 0) {
+ TRACE(DL_ERR, "mac set/query failed.");
+ goto Error;
+ }
+
+Error:
+ spin_unlock_irqrestore(&pfob->post_lock, irql);
+ if (pfob->pend_queue_driving && pfob->mcc) {
+ pfob->pend_queue_driving = 0;
+ be_drive_mcc_wrb_queue(pfob->mcc);
+ }
+ return status;
+}
+
+/*
+ This routine writes data to context memory.
+
+ pfob - Function object handle.
+ mac_table - Set to the 128-bit multicast address hash table.
+
+ Returns BE_SUCCESS if successfull, otherwise a useful int is returned.
+
+ IRQL: < DISPATCH_LEVEL
+*/
+
+int be_rxf_multicast_config(struct be_function_object *pfob,
+ bool promiscuous, u32 num, u8 *mac_table,
+ mcc_wrb_cqe_callback cb, /* optional */
+ void *cb_context,
+ struct be_multicast_q_ctxt *q_ctxt)
+{
+ int status = BE_SUCCESS;
+ struct FWCMD_COMMON_NTWK_MULTICAST_SET *fwcmd = NULL;
+ struct MCC_WRB_AMAP *wrb = NULL;
+ struct be_generic_q_ctxt *generic_ctxt = NULL;
+ unsigned long irql;
+
+ ASSERT(num <= ARRAY_SIZE(fwcmd->params.request.mac));
+
+ if (num > ARRAY_SIZE(fwcmd->params.request.mac)) {
+ TRACE(DL_ERR, "Too many multicast addresses. BE supports %d.",
+ (int) ARRAY_SIZE(fwcmd->params.request.mac));
+ return BE_NOT_OK;
+ }
+
+ spin_lock_irqsave(&pfob->post_lock, irql);
+
+ wrb = be_function_peek_mcc_wrb(pfob);
+ if (!wrb) {
+ if (q_ctxt && cb) {
+ wrb = (struct MCC_WRB_AMAP *) &q_ctxt->wrb_header;
+ generic_ctxt = (struct be_generic_q_ctxt *) q_ctxt;
+ generic_ctxt->context.bytes = sizeof(*q_ctxt);
+ } else {
+ status = BE_STATUS_NO_MCC_WRB;
+ goto Error;
+ }
+ }
+ /* Prepares an embedded fwcmd, including request/response sizes. */
+ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_NTWK_MULTICAST_SET);
+
+ fwcmd->params.request.promiscuous = promiscuous;
+ if (!promiscuous) {
+ fwcmd->params.request.num_mac = num;
+ if (num > 0) {
+ ASSERT(mac_table);
+ memcpy(fwcmd->params.request.mac,
+ mac_table, ETH_ALEN * num);
+ }
+ }
+
+ /* Post the f/w command */
+ status = be_function_post_mcc_wrb(pfob, wrb, generic_ctxt,
+ cb, cb_context, NULL, NULL, fwcmd, NULL);
+ if (status < 0) {
+ TRACE(DL_ERR, "multicast fwcmd failed.");
+ goto Error;
+ }
+
+Error:
+ spin_unlock_irqrestore(&pfob->post_lock, irql);
+ if (pfob->pend_queue_driving && pfob->mcc) {
+ pfob->pend_queue_driving = 0;
+ be_drive_mcc_wrb_queue(pfob->mcc);
+ }
+ return status;
+}
+
+/*
+ This routine adds or removes a vlan tag from the rxf table.
+
+ FunctionObject - Function object handle.
+ VLanTag - VLan tag to add or remove.
+ Add - Set to TRUE if this will add a vlan tag
+
+ Returns BE_SUCCESS if successfull, otherwise a useful int is returned.
+
+ IRQL: < DISPATCH_LEVEL
+*/
+int be_rxf_vlan_config(struct be_function_object *pfob,
+ bool promiscuous, u32 num, u16 *vlan_tag_array,
+ mcc_wrb_cqe_callback cb, /* optional */
+ void *cb_context,
+ struct be_vlan_q_ctxt *q_ctxt) /* optional */
+{
+ int status = BE_SUCCESS;
+ struct FWCMD_COMMON_NTWK_VLAN_CONFIG *fwcmd = NULL;
+ struct MCC_WRB_AMAP *wrb = NULL;
+ struct be_generic_q_ctxt *generic_ctxt = NULL;
+ unsigned long irql;
+
+ if (num > ARRAY_SIZE(fwcmd->params.request.vlan_tag)) {
+ TRACE(DL_ERR, "Too many VLAN tags.");
+ return BE_NOT_OK;
+ }
+
+ spin_lock_irqsave(&pfob->post_lock, irql);
+
+ wrb = be_function_peek_mcc_wrb(pfob);
+ if (!wrb) {
+ if (q_ctxt && cb) {
+ wrb = (struct MCC_WRB_AMAP *) &q_ctxt->wrb_header;
+ generic_ctxt = (struct be_generic_q_ctxt *) q_ctxt;
+ generic_ctxt->context.bytes = sizeof(*q_ctxt);
+ } else {
+ status = BE_STATUS_NO_MCC_WRB;
+ goto Error;
+ }
+ }
+ /* Prepares an embedded fwcmd, including request/response sizes. */
+ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_NTWK_VLAN_CONFIG);
+
+ fwcmd->params.request.promiscuous = promiscuous;
+ if (!promiscuous) {
+ fwcmd->params.request.num_vlan = num;
+
+ if (num > 0) {
+ ASSERT(vlan_tag_array);
+ memcpy(fwcmd->params.request.vlan_tag, vlan_tag_array,
+ num * sizeof(vlan_tag_array[0]));
+ }
+ }
+
+ /* Post the commadn */
+ status = be_function_post_mcc_wrb(pfob, wrb, generic_ctxt,
+ cb, cb_context, NULL, NULL, fwcmd, NULL);
+ if (status < 0) {
+ TRACE(DL_ERR, "vlan fwcmd failed.");
+ goto Error;
+ }
+
+Error:
+ spin_unlock_irqrestore(&pfob->post_lock, irql);
+ if (pfob->pend_queue_driving && pfob->mcc) {
+ pfob->pend_queue_driving = 0;
+ be_drive_mcc_wrb_queue(pfob->mcc);
+ }
+ return status;
+}
+
+
+int be_rxf_link_status(struct be_function_object *pfob,
+ struct BE_LINK_STATUS *link_status,
+ mcc_wrb_cqe_callback cb,
+ void *cb_context,
+ struct be_link_status_q_ctxt *q_ctxt)
+{
+ struct FWCMD_COMMON_NTWK_LINK_STATUS_QUERY *fwcmd = NULL;
+ struct MCC_WRB_AMAP *wrb = NULL;
+ int status = 0;
+ struct be_generic_q_ctxt *generic_ctxt = NULL;
+ unsigned long irql;
+ struct be_mcc_wrb_response_copy rc;
+
+ ASSERT(link_status);
+
+ spin_lock_irqsave(&pfob->post_lock, irql);
+
+ wrb = be_function_peek_mcc_wrb(pfob);
+
+ if (!wrb) {
+ if (q_ctxt && cb) {
+ wrb = (struct MCC_WRB_AMAP *) &q_ctxt->wrb_header;
+ generic_ctxt = (struct be_generic_q_ctxt *) q_ctxt;
+ generic_ctxt->context.bytes = sizeof(*q_ctxt);
+ } else {
+ status = BE_STATUS_NO_MCC_WRB;
+ goto Error;
+ }
+ }
+ /* Prepares an embedded fwcmd, including request/response sizes. */
+ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb,
+ COMMON_NTWK_LINK_STATUS_QUERY);
+
+ rc.length = FIELD_SIZEOF(struct FWCMD_COMMON_NTWK_LINK_STATUS_QUERY,
+ params.response);
+ rc.fwcmd_offset = offsetof(struct FWCMD_COMMON_NTWK_LINK_STATUS_QUERY,
+ params.response);
+ rc.va = link_status;
+ /* Post or queue the f/w command */
+ status = be_function_post_mcc_wrb(pfob, wrb, generic_ctxt,
+ cb, cb_context, NULL, NULL, fwcmd, &rc);
+
+ if (status < 0) {
+ TRACE(DL_ERR, "link status fwcmd failed.");
+ goto Error;
+ }
+
+Error:
+ spin_unlock_irqrestore(&pfob->post_lock, irql);
+ if (pfob->pend_queue_driving && pfob->mcc) {
+ pfob->pend_queue_driving = 0;
+ be_drive_mcc_wrb_queue(pfob->mcc);
+ }
+ return status;
+}
+
+int
+be_rxf_query_eth_statistics(struct be_function_object *pfob,
+ struct FWCMD_ETH_GET_STATISTICS *va_for_fwcmd,
+ u64 pa_for_fwcmd, mcc_wrb_cqe_callback cb,
+ void *cb_context,
+ struct be_nonembedded_q_ctxt *q_ctxt)
+{
+ struct MCC_WRB_AMAP *wrb = NULL;
+ int status = 0;
+ struct be_generic_q_ctxt *generic_ctxt = NULL;
+ unsigned long irql;
+
+ ASSERT(va_for_fwcmd);
+ ASSERT(pa_for_fwcmd);
+
+ spin_lock_irqsave(&pfob->post_lock, irql);
+
+ wrb = be_function_peek_mcc_wrb(pfob);
+
+ if (!wrb) {
+ if (q_ctxt && cb) {
+ wrb = (struct MCC_WRB_AMAP *) &q_ctxt->wrb_header;
+ generic_ctxt = (struct be_generic_q_ctxt *) q_ctxt;
+ generic_ctxt->context.bytes = sizeof(*q_ctxt);
+ } else {
+ status = BE_STATUS_NO_MCC_WRB;
+ goto Error;
+ }
+ }
+
+ TRACE(DL_INFO, "Query eth stats. fwcmd va:%p pa:0x%08x_%08x",
+ va_for_fwcmd, upper_32_bits(pa_for_fwcmd), (u32)pa_for_fwcmd);
+
+ /* Prepares an embedded fwcmd, including request/response sizes. */
+ va_for_fwcmd = BE_PREPARE_NONEMBEDDED_FWCMD(pfob, wrb,
+ va_for_fwcmd, pa_for_fwcmd, ETH_GET_STATISTICS);
+
+ /* Post the f/w command */
+ status = be_function_post_mcc_wrb(pfob, wrb, generic_ctxt,
+ cb, cb_context, NULL, NULL, va_for_fwcmd, NULL);
+ if (status < 0) {
+ TRACE(DL_ERR, "eth stats fwcmd failed.");
+ goto Error;
+ }
+
+Error:
+ spin_unlock_irqrestore(&pfob->post_lock, irql);
+ if (pfob->pend_queue_driving && pfob->mcc) {
+ pfob->pend_queue_driving = 0;
+ be_drive_mcc_wrb_queue(pfob->mcc);
+ }
+ return status;
+}
+
+int
+be_rxf_promiscuous(struct be_function_object *pfob,
+ bool enable_port0, bool enable_port1,
+ mcc_wrb_cqe_callback cb, void *cb_context,
+ struct be_promiscuous_q_ctxt *q_ctxt)
+{
+ struct FWCMD_ETH_PROMISCUOUS *fwcmd = NULL;
+ struct MCC_WRB_AMAP *wrb = NULL;
+ int status = 0;
+ struct be_generic_q_ctxt *generic_ctxt = NULL;
+ unsigned long irql;
+
+
+ spin_lock_irqsave(&pfob->post_lock, irql);
+
+ wrb = be_function_peek_mcc_wrb(pfob);
+
+ if (!wrb) {
+ if (q_ctxt && cb) {
+ wrb = (struct MCC_WRB_AMAP *) &q_ctxt->wrb_header;
+ generic_ctxt = (struct be_generic_q_ctxt *) q_ctxt;
+ generic_ctxt->context.bytes = sizeof(*q_ctxt);
+ } else {
+ status = BE_STATUS_NO_MCC_WRB;
+ goto Error;
+ }
+ }
+ /* Prepares an embedded fwcmd, including request/response sizes. */
+ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, ETH_PROMISCUOUS);
+
+ fwcmd->params.request.port0_promiscuous = enable_port0;
+ fwcmd->params.request.port1_promiscuous = enable_port1;
+
+ /* Post the f/w command */
+ status = be_function_post_mcc_wrb(pfob, wrb, generic_ctxt,
+ cb, cb_context, NULL, NULL, fwcmd, NULL);
+
+ if (status < 0) {
+ TRACE(DL_ERR, "promiscuous fwcmd failed.");
+ goto Error;
+ }
+
+Error:
+ spin_unlock_irqrestore(&pfob->post_lock, irql);
+ if (pfob->pend_queue_driving && pfob->mcc) {
+ pfob->pend_queue_driving = 0;
+ be_drive_mcc_wrb_queue(pfob->mcc);
+ }
+ return status;
+}
+
+
+/*
+ *-------------------------------------------------------------------------
+ * Function: be_rxf_filter_config
+ * Configures BladeEngine ethernet receive filter settings.
+ * pfob -
+ * settings - Pointer to the requested filter settings.
+ * The response from BladeEngine will be placed back
+ * in this structure.
+ * cb - optional
+ * cb_context - optional
+ * q_ctxt - Optional. Pointer to a previously allocated struct.
+ * If the MCC WRB ring is full, this structure is
+ * used to queue the operation. It will be posted
+ * to the MCC ring when space becomes available. All
+ * queued commands will be posted to the ring in
+ * the order they are received. It is always valid
+ * to pass a pointer to a generic
+ * be_generic_q_ctxt. However, the specific
+ * context structs are generally smaller than
+ * the generic struct.
+ * return pend_status - BE_SUCCESS (0) on success.
+ * BE_PENDING (postive value) if the FWCMD
+ * completion is pending. Negative error code on failure.
+ *---------------------------------------------------------------------------
+ */
+int
+be_rxf_filter_config(struct be_function_object *pfob,
+ struct NTWK_RX_FILTER_SETTINGS *settings,
+ mcc_wrb_cqe_callback cb, void *cb_context,
+ struct be_rxf_filter_q_ctxt *q_ctxt)
+{
+ struct FWCMD_COMMON_NTWK_RX_FILTER *fwcmd = NULL;
+ struct MCC_WRB_AMAP *wrb = NULL;
+ int status = 0;
+ struct be_generic_q_ctxt *generic_ctxt = NULL;
+ unsigned long irql;
+ struct be_mcc_wrb_response_copy rc;
+
+ ASSERT(settings);
+
+ spin_lock_irqsave(&pfob->post_lock, irql);
+
+ wrb = be_function_peek_mcc_wrb(pfob);
+
+ if (!wrb) {
+ if (q_ctxt && cb) {
+ wrb = (struct MCC_WRB_AMAP *) &q_ctxt->wrb_header;
+ generic_ctxt = (struct be_generic_q_ctxt *) q_ctxt;
+ generic_ctxt->context.bytes = sizeof(*q_ctxt);
+ } else {
+ status = BE_STATUS_NO_MCC_WRB;
+ goto Error;
+ }
+ }
+ /* Prepares an embedded fwcmd, including request/response sizes. */
+ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_NTWK_RX_FILTER);
+ memcpy(&fwcmd->params.request, settings, sizeof(*settings));
+
+ rc.length = FIELD_SIZEOF(struct FWCMD_COMMON_NTWK_RX_FILTER,
+ params.response);
+ rc.fwcmd_offset = offsetof(struct FWCMD_COMMON_NTWK_RX_FILTER,
+ params.response);
+ rc.va = settings;
+ /* Post or queue the f/w command */
+ status = be_function_post_mcc_wrb(pfob, wrb, generic_ctxt,
+ cb, cb_context, NULL, NULL, fwcmd, &rc);
+
+ if (status < 0) {
+ TRACE(DL_ERR, "RXF/ERX filter config fwcmd failed.");
+ goto Error;
+ }
+
+Error:
+ spin_unlock_irqrestore(&pfob->post_lock, irql);
+ if (pfob->pend_queue_driving && pfob->mcc) {
+ pfob->pend_queue_driving = 0;
+ be_drive_mcc_wrb_queue(pfob->mcc);
+ }
+ return status;
+}
diff --git a/drivers/staging/benet/etx_context.h b/drivers/staging/benet/etx_context.h
new file mode 100644
index 000000000000..554fbe5d127b
--- /dev/null
+++ b/drivers/staging/benet/etx_context.h
@@ -0,0 +1,55 @@
+/*
+ * 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:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+/*
+ * Autogenerated by srcgen version: 0127
+ */
+#ifndef __etx_context_amap_h__
+#define __etx_context_amap_h__
+
+/* ETX ring context structure. */
+struct BE_ETX_CONTEXT_AMAP {
+ u8 tx_cidx[11]; /* DWORD 0 */
+ u8 rsvd0[5]; /* DWORD 0 */
+ u8 rsvd1[16]; /* DWORD 0 */
+ u8 tx_pidx[11]; /* DWORD 1 */
+ u8 rsvd2; /* DWORD 1 */
+ u8 tx_ring_size[4]; /* DWORD 1 */
+ u8 pd_id[5]; /* DWORD 1 */
+ u8 pd_id_not_valid; /* DWORD 1 */
+ u8 cq_id_send[10]; /* DWORD 1 */
+ u8 rsvd3[32]; /* DWORD 2 */
+ u8 rsvd4[32]; /* DWORD 3 */
+ u8 cur_bytes[32]; /* DWORD 4 */
+ u8 max_bytes[32]; /* DWORD 5 */
+ u8 time_stamp[32]; /* DWORD 6 */
+ u8 rsvd5[11]; /* DWORD 7 */
+ u8 func; /* DWORD 7 */
+ u8 rsvd6[20]; /* DWORD 7 */
+ u8 cur_txd_count[32]; /* DWORD 8 */
+ u8 max_txd_count[32]; /* DWORD 9 */
+ u8 rsvd7[32]; /* DWORD 10 */
+ u8 rsvd8[32]; /* DWORD 11 */
+ u8 rsvd9[32]; /* DWORD 12 */
+ u8 rsvd10[32]; /* DWORD 13 */
+ u8 rsvd11[32]; /* DWORD 14 */
+ u8 rsvd12[32]; /* DWORD 15 */
+} __packed;
+struct ETX_CONTEXT_AMAP {
+ u32 dw[16];
+};
+
+#endif /* __etx_context_amap_h__ */
diff --git a/drivers/staging/benet/funcobj.c b/drivers/staging/benet/funcobj.c
new file mode 100644
index 000000000000..0f57eb58daef
--- /dev/null
+++ b/drivers/staging/benet/funcobj.c
@@ -0,0 +1,565 @@
+/*
+ * 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:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+#include "hwlib.h"
+#include "bestatus.h"
+
+
+int
+be_function_internal_query_firmware_config(struct be_function_object *pfob,
+ struct BE_FIRMWARE_CONFIG *config)
+{
+ struct FWCMD_COMMON_FIRMWARE_CONFIG *fwcmd = NULL;
+ struct MCC_WRB_AMAP *wrb = NULL;
+ int status = 0;
+ unsigned long irql;
+ struct be_mcc_wrb_response_copy rc;
+
+ spin_lock_irqsave(&pfob->post_lock, irql);
+
+ wrb = be_function_peek_mcc_wrb(pfob);
+ if (!wrb) {
+ TRACE(DL_ERR, "MCC wrb peek failed.");
+ status = BE_STATUS_NO_MCC_WRB;
+ goto error;
+ }
+ /* Prepares an embedded fwcmd, including request/response sizes. */
+ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_FIRMWARE_CONFIG);
+
+ rc.length = FIELD_SIZEOF(struct FWCMD_COMMON_FIRMWARE_CONFIG,
+ params.response);
+ rc.fwcmd_offset = offsetof(struct FWCMD_COMMON_FIRMWARE_CONFIG,
+ params.response);
+ rc.va = config;
+
+ /* Post the f/w command */
+ status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL,
+ NULL, NULL, NULL, fwcmd, &rc);
+error:
+ spin_unlock_irqrestore(&pfob->post_lock, irql);
+ if (pfob->pend_queue_driving && pfob->mcc) {
+ pfob->pend_queue_driving = 0;
+ be_drive_mcc_wrb_queue(pfob->mcc);
+ }
+ return status;
+}
+
+/*
+ This allocates and initializes a function object based on the information
+ provided by upper layer drivers.
+
+ Returns BE_SUCCESS on success and an appropriate int on failure.
+
+ A function object represents a single BladeEngine (logical) PCI function.
+ That is a function object either represents
+ the networking side of BladeEngine or the iSCSI side of BladeEngine.
+
+ This routine will also detect and create an appropriate PD object for the
+ PCI function as needed.
+*/
+int
+be_function_object_create(u8 __iomem *csr_va, u8 __iomem *db_va,
+ u8 __iomem *pci_va, u32 function_type,
+ struct ring_desc *mailbox, struct be_function_object *pfob)
+{
+ int status;
+
+ ASSERT(pfob); /* not a magic assert */
+ ASSERT(function_type <= 2);
+
+ TRACE(DL_INFO, "Create function object. type:%s object:0x%p",
+ (function_type == BE_FUNCTION_TYPE_ISCSI ? "iSCSI" :
+ (function_type == BE_FUNCTION_TYPE_NETWORK ? "Network" :
+ "Arm")), pfob);
+
+ memset(pfob, 0, sizeof(*pfob));
+
+ pfob->type = function_type;
+ pfob->csr_va = csr_va;
+ pfob->db_va = db_va;
+ pfob->pci_va = pci_va;
+
+ spin_lock_init(&pfob->cq_lock);
+ spin_lock_init(&pfob->post_lock);
+ spin_lock_init(&pfob->mcc_context_lock);
+
+
+ pfob->pci_function_number = 1;
+
+
+ pfob->emulate = false;
+ TRACE(DL_NOTE, "Non-emulation mode");
+ status = be_drive_POST(pfob);
+ if (status != BE_SUCCESS) {
+ TRACE(DL_ERR, "BladeEngine POST failed.");
+ goto error;
+ }
+
+ /* Initialize the mailbox */
+ status = be_mpu_init_mailbox(pfob, mailbox);
+ if (status != BE_SUCCESS) {
+ TRACE(DL_ERR, "Failed to initialize mailbox.");
+ goto error;
+ }
+ /*
+ * Cache the firmware config for ASSERTs in hwclib and later
+ * driver queries.
+ */
+ status = be_function_internal_query_firmware_config(pfob,
+ &pfob->fw_config);
+ if (status != BE_SUCCESS) {
+ TRACE(DL_ERR, "Failed to query firmware config.");
+ goto error;
+ }
+
+error:
+ if (status != BE_SUCCESS) {
+ /* No cleanup necessary */
+ TRACE(DL_ERR, "Failed to create function.");
+ memset(pfob, 0, sizeof(*pfob));
+ }
+ return status;
+}
+
+/*
+ This routine drops the reference count on a given function object. Once
+ the reference count falls to zero, the function object is destroyed and all
+ resources held are freed.
+
+ FunctionObject - The function object to drop the reference to.
+*/
+int be_function_object_destroy(struct be_function_object *pfob)
+{
+ TRACE(DL_INFO, "Destroy pfob. Object:0x%p",
+ pfob);
+
+
+ ASSERT(pfob->mcc == NULL);
+
+ return BE_SUCCESS;
+}
+
+int be_function_cleanup(struct be_function_object *pfob)
+{
+ int status = 0;
+ u32 isr;
+ u32 host_intr;
+ struct PCICFG_HOST_TIMER_INT_CTRL_CSR_AMAP ctrl;
+
+
+ if (pfob->type == BE_FUNCTION_TYPE_NETWORK) {
+ status = be_rxf_multicast_config(pfob, false, 0,
+ NULL, NULL, NULL, NULL);
+ ASSERT(status == BE_SUCCESS);
+ }
+ /* VLAN */
+ status = be_rxf_vlan_config(pfob, false, 0, NULL, NULL, NULL, NULL);
+ ASSERT(status == BE_SUCCESS);
+ /*
+ * MCC Queue -- Switches to mailbox mode. May want to destroy
+ * all but the MCC CQ before this call if polling CQ is much better
+ * performance than polling mailbox register.
+ */
+ if (pfob->mcc)
+ status = be_mcc_ring_destroy(pfob->mcc);
+ /*
+ * If interrupts are disabled, clear any CEV interrupt assertions that
+ * fired after we stopped processing EQs.
+ */
+ ctrl.dw[0] = PCICFG1_READ(pfob, host_timer_int_ctrl);
+ host_intr = AMAP_GET_BITS_PTR(PCICFG_HOST_TIMER_INT_CTRL_CSR,
+ hostintr, ctrl.dw);
+ if (!host_intr)
+ if (pfob->type == BE_FUNCTION_TYPE_NETWORK)
+ isr = CSR_READ(pfob, cev.isr1);
+ else
+ isr = CSR_READ(pfob, cev.isr0);
+ else
+ /* This should never happen... */
+ TRACE(DL_ERR, "function_cleanup called with interrupt enabled");
+ /* Function object destroy */
+ status = be_function_object_destroy(pfob);
+ ASSERT(status == BE_SUCCESS);
+
+ return status;
+}
+
+
+void *
+be_function_prepare_embedded_fwcmd(struct be_function_object *pfob,
+ struct MCC_WRB_AMAP *wrb, u32 payld_len, u32 request_length,
+ u32 response_length, u32 opcode, u32 subsystem)
+{
+ struct FWCMD_REQUEST_HEADER *header = NULL;
+ u32 n;
+
+ ASSERT(wrb);
+
+ n = offsetof(struct BE_MCC_WRB_AMAP, payload)/8;
+ AMAP_SET_BITS_PTR(MCC_WRB, embedded, wrb, 1);
+ AMAP_SET_BITS_PTR(MCC_WRB, payload_length, wrb, min(payld_len, n));
+ header = (struct FWCMD_REQUEST_HEADER *)((u8 *)wrb + n);
+
+ header->timeout = 0;
+ header->domain = 0;
+ header->request_length = max(request_length, response_length);
+ header->opcode = opcode;
+ header->subsystem = subsystem;
+
+ return header;
+}
+
+void *
+be_function_prepare_nonembedded_fwcmd(struct be_function_object *pfob,
+ struct MCC_WRB_AMAP *wrb,
+ void *fwcmd_va, u64 fwcmd_pa,
+ u32 payld_len,
+ u32 request_length,
+ u32 response_length,
+ u32 opcode, u32 subsystem)
+{
+ struct FWCMD_REQUEST_HEADER *header = NULL;
+ u32 n;
+ struct MCC_WRB_PAYLOAD_AMAP *plp;
+
+ ASSERT(wrb);
+ ASSERT(fwcmd_va);
+
+ header = (struct FWCMD_REQUEST_HEADER *) fwcmd_va;
+
+ AMAP_SET_BITS_PTR(MCC_WRB, embedded, wrb, 0);
+ AMAP_SET_BITS_PTR(MCC_WRB, payload_length, wrb, payld_len);
+
+ /*
+ * Assume one fragment. The caller may override the SGL by
+ * rewriting the 0th length and adding more entries. They
+ * will also need to update the sge_count.
+ */
+ AMAP_SET_BITS_PTR(MCC_WRB, sge_count, wrb, 1);
+
+ n = offsetof(struct BE_MCC_WRB_AMAP, payload)/8;
+ plp = (struct MCC_WRB_PAYLOAD_AMAP *)((u8 *)wrb + n);
+ AMAP_SET_BITS_PTR(MCC_WRB_PAYLOAD, sgl[0].length, plp, payld_len);
+ AMAP_SET_BITS_PTR(MCC_WRB_PAYLOAD, sgl[0].pa_lo, plp, (u32)fwcmd_pa);
+ AMAP_SET_BITS_PTR(MCC_WRB_PAYLOAD, sgl[0].pa_hi, plp,
+ upper_32_bits(fwcmd_pa));
+
+ header->timeout = 0;
+ header->domain = 0;
+ header->request_length = max(request_length, response_length);
+ header->opcode = opcode;
+ header->subsystem = subsystem;
+
+ return header;
+}
+
+struct MCC_WRB_AMAP *
+be_function_peek_mcc_wrb(struct be_function_object *pfob)
+{
+ struct MCC_WRB_AMAP *wrb = NULL;
+ u32 offset;
+
+ if (pfob->mcc)
+ wrb = _be_mpu_peek_ring_wrb(pfob->mcc, false);
+ else {
+ offset = offsetof(struct BE_MCC_MAILBOX_AMAP, wrb)/8;
+ wrb = (struct MCC_WRB_AMAP *) ((u8 *) pfob->mailbox.va +
+ offset);
+ }
+
+ if (wrb)
+ memset(wrb, 0, sizeof(struct MCC_WRB_AMAP));
+
+ return wrb;
+}
+
+#if defined(BE_DEBUG)
+void be_function_debug_print_wrb(struct be_function_object *pfob,
+ struct MCC_WRB_AMAP *wrb, void *optional_fwcmd_va,
+ struct be_mcc_wrb_context *wrb_context)
+{
+
+ struct FWCMD_REQUEST_HEADER *header = NULL;
+ u8 embedded;
+ u32 n;
+
+ embedded = AMAP_GET_BITS_PTR(MCC_WRB, embedded, wrb);
+
+ if (embedded) {
+ n = offsetof(struct BE_MCC_WRB_AMAP, payload)/8;
+ header = (struct FWCMD_REQUEST_HEADER *)((u8 *)wrb + n);
+ } else {
+ header = (struct FWCMD_REQUEST_HEADER *) optional_fwcmd_va;
+ }
+
+ /* Save the completed count before posting for a debug assert. */
+
+ if (header) {
+ wrb_context->opcode = header->opcode;
+ wrb_context->subsystem = header->subsystem;
+
+ } else {
+ wrb_context->opcode = 0;
+ wrb_context->subsystem = 0;
+ }
+}
+#else
+#define be_function_debug_print_wrb(a_, b_, c_, d_)
+#endif
+
+int
+be_function_post_mcc_wrb(struct be_function_object *pfob,
+ struct MCC_WRB_AMAP *wrb,
+ struct be_generic_q_ctxt *q_ctxt,
+ mcc_wrb_cqe_callback cb, void *cb_context,
+ mcc_wrb_cqe_callback internal_cb,
+ void *internal_cb_context, void *optional_fwcmd_va,
+ struct be_mcc_wrb_response_copy *rc)
+{
+ int status;
+ struct be_mcc_wrb_context *wrb_context = NULL;
+ u64 *p;
+
+ if (q_ctxt) {
+ /* Initialize context. */
+ q_ctxt->context.internal_cb = internal_cb;
+ q_ctxt->context.internal_cb_context = internal_cb_context;
+ q_ctxt->context.cb = cb;
+ q_ctxt->context.cb_context = cb_context;
+ if (rc) {
+ q_ctxt->context.copy.length = rc->length;
+ q_ctxt->context.copy.fwcmd_offset = rc->fwcmd_offset;
+ q_ctxt->context.copy.va = rc->va;
+ } else
+ q_ctxt->context.copy.length = 0;
+
+ q_ctxt->context.optional_fwcmd_va = optional_fwcmd_va;
+
+ /* Queue this request */
+ status = be_function_queue_mcc_wrb(pfob, q_ctxt);
+
+ goto Error;
+ }
+ /*
+ * Allocate a WRB context struct to hold the callback pointers,
+ * status, etc. This is required if commands complete out of order.
+ */
+ wrb_context = _be_mcc_allocate_wrb_context(pfob);
+ if (!wrb_context) {
+ TRACE(DL_WARN, "Failed to allocate MCC WRB context.");
+ status = BE_STATUS_SYSTEM_RESOURCES;
+ goto Error;
+ }
+ /* Initialize context. */
+ memset(wrb_context, 0, sizeof(*wrb_context));
+ wrb_context->internal_cb = internal_cb;
+ wrb_context->internal_cb_context = internal_cb_context;
+ wrb_context->cb = cb;
+ wrb_context->cb_context = cb_context;
+ if (rc) {
+ wrb_context->copy.length = rc->length;
+ wrb_context->copy.fwcmd_offset = rc->fwcmd_offset;
+ wrb_context->copy.va = rc->va;
+ } else
+ wrb_context->copy.length = 0;
+ wrb_context->wrb = wrb;
+
+ /*
+ * Copy the context pointer into the WRB opaque tag field.
+ * Verify assumption of 64-bit tag with a compile time assert.
+ */
+ p = (u64 *) ((u8 *)wrb + offsetof(struct BE_MCC_WRB_AMAP, tag)/8);
+ *p = (u64)(size_t)wrb_context;
+
+ /* Print info about this FWCMD for debug builds. */
+ be_function_debug_print_wrb(pfob, wrb, optional_fwcmd_va, wrb_context);
+
+ /*
+ * issue the WRB to the MPU as appropriate
+ */
+ if (pfob->mcc) {
+ /*
+ * we're in WRB mode, pass to the mcc layer
+ */
+ status = _be_mpu_post_wrb_ring(pfob->mcc, wrb, wrb_context);
+ } else {
+ /*
+ * we're in mailbox mode
+ */
+ status = _be_mpu_post_wrb_mailbox(pfob, wrb, wrb_context);
+
+ /* mailbox mode always completes synchronously */
+ ASSERT(status != BE_STATUS_PENDING);
+ }
+
+Error:
+
+ return status;
+}
+
+int
+be_function_ring_destroy(struct be_function_object *pfob,
+ u32 id, u32 ring_type, mcc_wrb_cqe_callback cb,
+ void *cb_context, mcc_wrb_cqe_callback internal_cb,
+ void *internal_cb_context)
+{
+
+ struct FWCMD_COMMON_RING_DESTROY *fwcmd = NULL;
+ struct MCC_WRB_AMAP *wrb = NULL;
+ int status = 0;
+ unsigned long irql;
+
+ spin_lock_irqsave(&pfob->post_lock, irql);
+
+ TRACE(DL_INFO, "Destroy ring id:%d type:%d", id, ring_type);
+
+ wrb = be_function_peek_mcc_wrb(pfob);
+ if (!wrb) {
+ ASSERT(wrb);
+ TRACE(DL_ERR, "No free MCC WRBs in destroy ring.");
+ status = BE_STATUS_NO_MCC_WRB;
+ goto Error;
+ }
+ /* Prepares an embedded fwcmd, including request/response sizes. */
+ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_RING_DESTROY);
+
+ fwcmd->params.request.id = id;
+ fwcmd->params.request.ring_type = ring_type;
+
+ /* Post the f/w command */
+ status = be_function_post_mcc_wrb(pfob, wrb, NULL, cb, cb_context,
+ internal_cb, internal_cb_context, fwcmd, NULL);
+ if (status != BE_SUCCESS && status != BE_PENDING) {
+ TRACE(DL_ERR, "Ring destroy fwcmd failed. id:%d ring_type:%d",
+ id, ring_type);
+ goto Error;
+ }
+
+Error:
+ spin_unlock_irqrestore(&pfob->post_lock, irql);
+ if (pfob->pend_queue_driving && pfob->mcc) {
+ pfob->pend_queue_driving = 0;
+ be_drive_mcc_wrb_queue(pfob->mcc);
+ }
+ return status;
+}
+
+void
+be_rd_to_pa_list(struct ring_desc *rd, struct PHYS_ADDR *pa_list, u32 max_num)
+{
+ u32 num_pages = PAGES_SPANNED(rd->va, rd->length);
+ u32 i = 0;
+ u64 pa = rd->pa;
+ __le64 lepa;
+
+ ASSERT(pa_list);
+ ASSERT(pa);
+
+ for (i = 0; i < min(num_pages, max_num); i++) {
+ lepa = cpu_to_le64(pa);
+ pa_list[i].lo = (u32)lepa;
+ pa_list[i].hi = upper_32_bits(lepa);
+ pa += PAGE_SIZE;
+ }
+}
+
+
+
+/*-----------------------------------------------------------------------------
+ * Function: be_function_get_fw_version
+ * Retrieves the firmware version on the adpater. If the callback is
+ * NULL this call executes synchronously. If the callback is not NULL,
+ * the returned status will be BE_PENDING if the command was issued
+ * successfully.
+ * pfob -
+ * fwv - Pointer to response buffer if callback is NULL.
+ * cb - Callback function invoked when the FWCMD completes.
+ * cb_context - Passed to the callback function.
+ * return pend_status - BE_SUCCESS (0) on success.
+ * BE_PENDING (postive value) if the FWCMD
+ * completion is pending. Negative error code on failure.
+ *---------------------------------------------------------------------------
+ */
+int
+be_function_get_fw_version(struct be_function_object *pfob,
+ struct FWCMD_COMMON_GET_FW_VERSION_RESPONSE_PAYLOAD *fwv,
+ mcc_wrb_cqe_callback cb, void *cb_context)
+{
+ int status = BE_SUCCESS;
+ struct MCC_WRB_AMAP *wrb = NULL;
+ struct FWCMD_COMMON_GET_FW_VERSION *fwcmd = NULL;
+ unsigned long irql;
+ struct be_mcc_wrb_response_copy rc;
+
+ spin_lock_irqsave(&pfob->post_lock, irql);
+
+ wrb = be_function_peek_mcc_wrb(pfob);
+ if (!wrb) {
+ TRACE(DL_ERR, "MCC wrb peek failed.");
+ status = BE_STATUS_NO_MCC_WRB;
+ goto Error;
+ }
+
+ if (!cb && !fwv) {
+ TRACE(DL_ERR, "callback and response buffer NULL!");
+ status = BE_NOT_OK;
+ goto Error;
+ }
+ /* Prepares an embedded fwcmd, including request/response sizes. */
+ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_GET_FW_VERSION);
+
+ rc.length = FIELD_SIZEOF(struct FWCMD_COMMON_GET_FW_VERSION,
+ params.response);
+ rc.fwcmd_offset = offsetof(struct FWCMD_COMMON_GET_FW_VERSION,
+ params.response);
+ rc.va = fwv;
+
+ /* Post the f/w command */
+ status = be_function_post_mcc_wrb(pfob, wrb, NULL, cb,
+ cb_context, NULL, NULL, fwcmd, &rc);
+
+Error:
+ spin_unlock_irqrestore(&pfob->post_lock, irql);
+ if (pfob->pend_queue_driving && pfob->mcc) {
+ pfob->pend_queue_driving = 0;
+ be_drive_mcc_wrb_queue(pfob->mcc);
+ }
+ return status;
+}
+
+int
+be_function_queue_mcc_wrb(struct be_function_object *pfob,
+ struct be_generic_q_ctxt *q_ctxt)
+{
+ int status;
+
+ ASSERT(q_ctxt);
+
+ /*
+ * issue the WRB to the MPU as appropriate
+ */
+ if (pfob->mcc) {
+
+ /* We're in ring mode. Queue this item. */
+ pfob->mcc->backlog_length++;
+ list_add_tail(&q_ctxt->context.list, &pfob->mcc->backlog);
+ status = BE_PENDING;
+ } else {
+ status = BE_NOT_OK;
+ }
+ return status;
+}
+
diff --git a/drivers/staging/benet/fwcmd_common.h b/drivers/staging/benet/fwcmd_common.h
new file mode 100644
index 000000000000..406e0d6fa985
--- /dev/null
+++ b/drivers/staging/benet/fwcmd_common.h
@@ -0,0 +1,222 @@
+/*
+ * 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:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+/*
+ * Autogenerated by srcgen version: 0127
+ */
+#ifndef __fwcmd_common_amap_h__
+#define __fwcmd_common_amap_h__
+#include "host_struct.h"
+
+/* --- PHY_LINK_DUPLEX_ENUM --- */
+#define PHY_LINK_DUPLEX_NONE (0)
+#define PHY_LINK_DUPLEX_HALF (1)
+#define PHY_LINK_DUPLEX_FULL (2)
+
+/* --- PHY_LINK_SPEED_ENUM --- */
+#define PHY_LINK_SPEED_ZERO (0) /* No link. */
+#define PHY_LINK_SPEED_10MBPS (1) /* 10 Mbps */
+#define PHY_LINK_SPEED_100MBPS (2) /* 100 Mbps */
+#define PHY_LINK_SPEED_1GBPS (3) /* 1 Gbps */
+#define PHY_LINK_SPEED_10GBPS (4) /* 10 Gbps */
+
+/* --- PHY_LINK_FAULT_ENUM --- */
+#define PHY_LINK_FAULT_NONE (0) /* No fault status
+ available or detected */
+#define PHY_LINK_FAULT_LOCAL (1) /* Local fault detected */
+#define PHY_LINK_FAULT_REMOTE (2) /* Remote fault detected */
+
+/* --- BE_ULP_MASK --- */
+#define BE_ULP0_MASK (1)
+#define BE_ULP1_MASK (2)
+#define BE_ULP2_MASK (4)
+
+/* --- NTWK_ACTIVE_PORT --- */
+#define NTWK_PORT_A (0) /* Port A is currently active */
+#define NTWK_PORT_B (1) /* Port B is currently active */
+#define NTWK_NO_ACTIVE_PORT (15) /* Both ports have lost link */
+
+/* --- NTWK_LINK_TYPE --- */
+#define NTWK_LINK_TYPE_PHYSICAL (0) /* link up/down event
+ applies to BladeEngine's
+ Physical Ports
+ */
+#define NTWK_LINK_TYPE_VIRTUAL (1) /* Virtual link up/down event
+ reported by BladeExchange.
+ This applies only when the
+ VLD feature is enabled
+ */
+
+/*
+ * --- FWCMD_MAC_TYPE_ENUM ---
+ * This enum defines the types of MAC addresses in the RXF MAC Address Table.
+ */
+#define MAC_ADDRESS_TYPE_STORAGE (0) /* Storage MAC Address */
+#define MAC_ADDRESS_TYPE_NETWORK (1) /* Network MAC Address */
+#define MAC_ADDRESS_TYPE_PD (2) /* Protection Domain MAC Addr */
+#define MAC_ADDRESS_TYPE_MANAGEMENT (3) /* Managment MAC Address */
+
+
+/* --- FWCMD_RING_TYPE_ENUM --- */
+#define FWCMD_RING_TYPE_ETH_RX (1) /* Ring created with */
+ /* FWCMD_COMMON_ETH_RX_CREATE. */
+#define FWCMD_RING_TYPE_ETH_TX (2) /* Ring created with */
+ /* FWCMD_COMMON_ETH_TX_CREATE. */
+#define FWCMD_RING_TYPE_ISCSI_WRBQ (3) /* Ring created with */
+ /* FWCMD_COMMON_ISCSI_WRBQ_CREATE. */
+#define FWCMD_RING_TYPE_ISCSI_DEFQ (4) /* Ring created with */
+ /* FWCMD_COMMON_ISCSI_DEFQ_CREATE. */
+#define FWCMD_RING_TYPE_TPM_WRBQ (5) /* Ring created with */
+ /* FWCMD_COMMON_TPM_WRBQ_CREATE. */
+#define FWCMD_RING_TYPE_TPM_DEFQ (6) /* Ring created with */
+ /* FWCMD_COMMONTPM_TDEFQ_CREATE. */
+#define FWCMD_RING_TYPE_TPM_RQ (7) /* Ring created with */
+ /* FWCMD_COMMON_TPM_RQ_CREATE. */
+#define FWCMD_RING_TYPE_MCC (8) /* Ring created with */
+ /* FWCMD_COMMON_MCC_CREATE. */
+#define FWCMD_RING_TYPE_CQ (9) /* Ring created with */
+ /* FWCMD_COMMON_CQ_CREATE. */
+#define FWCMD_RING_TYPE_EQ (10) /* Ring created with */
+ /* FWCMD_COMMON_EQ_CREATE. */
+#define FWCMD_RING_TYPE_QP (11) /* Ring created with */
+ /* FWCMD_RDMA_QP_CREATE. */
+
+
+/* --- ETH_TX_RING_TYPE_ENUM --- */
+#define ETH_TX_RING_TYPE_FORWARDING (1) /* Ethernet ring for
+ forwarding packets */
+#define ETH_TX_RING_TYPE_STANDARD (2) /* Ethernet ring for sending
+ network packets. */
+#define ETH_TX_RING_TYPE_BOUND (3) /* Ethernet ring bound to the
+ port specified in the command
+ header.port_number field.
+ Rings of this type are
+ NOT subject to the
+ failover logic implemented
+ in the BladeEngine.
+ */
+
+/* --- FWCMD_COMMON_QOS_TYPE_ENUM --- */
+#define QOS_BITS_NIC (1) /* max_bits_per_second_NIC */
+ /* field is valid. */
+#define QOS_PKTS_NIC (2) /* max_packets_per_second_NIC */
+ /* field is valid. */
+#define QOS_IOPS_ISCSI (4) /* max_ios_per_second_iSCSI */
+ /*field is valid. */
+#define QOS_VLAN_TAG (8) /* domain_VLAN_tag field
+ is valid. */
+#define QOS_FABRIC_ID (16) /* fabric_domain_ID field
+ is valid. */
+#define QOS_OEM_PARAMS (32) /* qos_params_oem field
+ is valid. */
+#define QOS_TPUT_ISCSI (64) /* max_bytes_per_second_iSCSI
+ field is valid. */
+
+
+/*
+ * --- FAILOVER_CONFIG_ENUM ---
+ * Failover configuration setting used in FWCMD_COMMON_FORCE_FAILOVER
+ */
+#define FAILOVER_CONFIG_NO_CHANGE (0) /* No change to automatic */
+ /* port failover setting. */
+#define FAILOVER_CONFIG_ON (1) /* Automatic port failover
+ on link down is enabled. */
+#define FAILOVER_CONFIG_OFF (2) /* Automatic port failover
+ on link down is disabled. */
+
+/*
+ * --- FAILOVER_PORT_ENUM ---
+ * Failover port setting used in FWCMD_COMMON_FORCE_FAILOVER
+ */
+#define FAILOVER_PORT_A (0) /* Selects port A. */
+#define FAILOVER_PORT_B (1) /* Selects port B. */
+#define FAILOVER_PORT_NONE (15) /* No port change requested. */
+
+
+/*
+ * --- MGMT_FLASHROM_OPCODE ---
+ * Flash ROM operation code
+ */
+#define MGMT_FLASHROM_OPCODE_FLASH (1) /* Commit downloaded data
+ to Flash ROM */
+#define MGMT_FLASHROM_OPCODE_SAVE (2) /* Save downloaded data to
+ ARM's DDR - do not flash */
+#define MGMT_FLASHROM_OPCODE_CLEAR (3) /* Erase specified component
+ from FlashROM */
+#define MGMT_FLASHROM_OPCODE_REPORT (4) /* Read specified component
+ from Flash ROM */
+#define MGMT_FLASHROM_OPCODE_IMAGE_INFO (5) /* Returns size of a
+ component */
+
+/*
+ * --- MGMT_FLASHROM_OPTYPE ---
+ * Flash ROM operation type
+ */
+#define MGMT_FLASHROM_OPTYPE_CODE_FIRMWARE (0) /* Includes ARM firmware,
+ IPSec (optional) and EP
+ firmware */
+#define MGMT_FLASHROM_OPTYPE_CODE_REDBOOT (1)
+#define MGMT_FLASHROM_OPTYPE_CODE_BIOS (2)
+#define MGMT_FLASHROM_OPTYPE_CODE_PXE_BIOS (3)
+#define MGMT_FLASHROM_OPTYPE_CODE_CTRLS (4)
+#define MGMT_FLASHROM_OPTYPE_CFG_IPSEC (5)
+#define MGMT_FLASHROM_OPTYPE_CFG_INI (6)
+#define MGMT_FLASHROM_OPTYPE_ROM_OFFSET_SPECIFIED (7)
+
+/*
+ * --- FLASHROM_TYPE ---
+ * Flash ROM manufacturers supported in the f/w
+ */
+#define INTEL (0)
+#define SPANSION (1)
+#define MICRON (2)
+
+/* --- DDR_CAS_TYPE --- */
+#define CAS_3 (0)
+#define CAS_4 (1)
+#define CAS_5 (2)
+
+/* --- DDR_SIZE_TYPE --- */
+#define SIZE_256MB (0)
+#define SIZE_512MB (1)
+
+/* --- DDR_MODE_TYPE --- */
+#define DDR_NO_ECC (0)
+#define DDR_ECC (1)
+
+/* --- INTERFACE_10GB_TYPE --- */
+#define CX4_TYPE (0)
+#define XFP_TYPE (1)
+
+/* --- BE_CHIP_MAX_MTU --- */
+#define CHIP_MAX_MTU (9000)
+
+/* --- XAUI_STATE_ENUM --- */
+#define XAUI_STATE_ENABLE (0) /* This MUST be the default
+ value for all requests
+ which set/change
+ equalization parameter. */
+#define XAUI_STATE_DISABLE (255) /* The XAUI for both ports
+ may be disabled for EMI
+ tests. There is no
+ provision for turning off
+ individual ports.
+ */
+/* --- BE_ASIC_REVISION --- */
+#define BE_ASIC_REV_A0 (1)
+#define BE_ASIC_REV_A1 (2)
+
+#endif /* __fwcmd_common_amap_h__ */
diff --git a/drivers/staging/benet/fwcmd_common_bmap.h b/drivers/staging/benet/fwcmd_common_bmap.h
new file mode 100644
index 000000000000..a007cf276500
--- /dev/null
+++ b/drivers/staging/benet/fwcmd_common_bmap.h
@@ -0,0 +1,717 @@
+/*
+ * 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:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+/*
+ * Autogenerated by srcgen version: 0127
+ */
+#ifndef __fwcmd_common_bmap_h__
+#define __fwcmd_common_bmap_h__
+#include "fwcmd_types_bmap.h"
+#include "fwcmd_hdr_bmap.h"
+
+#if defined(__BIG_ENDIAN)
+ /* Physical Address. */
+struct PHYS_ADDR {
+ union {
+ struct {
+ u32 lo; /* DWORD 0 */
+ u32 hi; /* DWORD 1 */
+ } __packed; /* unnamed struct */
+ u32 dw[2]; /* dword union */
+ }; /* unnamed union */
+} __packed ;
+
+
+#else
+ /* Physical Address. */
+struct PHYS_ADDR {
+ union {
+ struct {
+ u32 lo; /* DWORD 0 */
+ u32 hi; /* DWORD 1 */
+ } __packed; /* unnamed struct */
+ u32 dw[2]; /* dword union */
+ }; /* unnamed union */
+} __packed ;
+
+struct BE_LINK_STATUS {
+ u8 mac0_duplex;
+ u8 mac0_speed;
+ u8 mac1_duplex;
+ u8 mac1_speed;
+ u8 mgmt_mac_duplex;
+ u8 mgmt_mac_speed;
+ u8 active_port;
+ u8 rsvd0;
+ u8 mac0_fault;
+ u8 mac1_fault;
+ u16 rsvd1;
+} __packed;
+#endif
+
+struct FWCMD_COMMON_ANON_170_REQUEST {
+ u32 rsvd0;
+} __packed;
+
+union LINK_STATUS_QUERY_PARAMS {
+ struct BE_LINK_STATUS response;
+ struct FWCMD_COMMON_ANON_170_REQUEST request;
+} __packed;
+
+/*
+ * Queries the the link status for all ports. The valid values below
+ * DO NOT indicate that a particular duplex or speed is supported by
+ * BladeEngine. These enumerations simply list all possible duplexes
+ * and speeds for any port. Consult BladeEngine product documentation
+ * for the supported parameters.
+ */
+struct FWCMD_COMMON_NTWK_LINK_STATUS_QUERY {
+ union FWCMD_HEADER header;
+ union LINK_STATUS_QUERY_PARAMS params;
+} __packed;
+
+struct FWCMD_COMMON_ANON_171_REQUEST {
+ u8 type;
+ u8 port;
+ u8 mac1;
+ u8 permanent;
+} __packed;
+
+struct FWCMD_COMMON_ANON_172_RESPONSE {
+ struct MAC_ADDRESS_FORMAT mac;
+} __packed;
+
+union NTWK_MAC_QUERY_PARAMS {
+ struct FWCMD_COMMON_ANON_171_REQUEST request;
+ struct FWCMD_COMMON_ANON_172_RESPONSE response;
+} __packed;
+
+/* Queries one MAC address. */
+struct FWCMD_COMMON_NTWK_MAC_QUERY {
+ union FWCMD_HEADER header;
+ union NTWK_MAC_QUERY_PARAMS params;
+} __packed;
+
+struct MAC_SET_PARAMS_IN {
+ u8 type;
+ u8 port;
+ u8 mac1;
+ u8 invalidate;
+ struct MAC_ADDRESS_FORMAT mac;
+} __packed;
+
+struct MAC_SET_PARAMS_OUT {
+ u32 rsvd0;
+} __packed;
+
+union MAC_SET_PARAMS {
+ struct MAC_SET_PARAMS_IN request;
+ struct MAC_SET_PARAMS_OUT response;
+} __packed;
+
+/* Sets a MAC address. */
+struct FWCMD_COMMON_NTWK_MAC_SET {
+ union FWCMD_HEADER header;
+ union MAC_SET_PARAMS params;
+} __packed;
+
+/* MAC address list. */
+struct NTWK_MULTICAST_MAC_LIST {
+ u8 byte[6];
+} __packed;
+
+struct FWCMD_COMMON_NTWK_MULTICAST_SET_REQUEST_PAYLOAD {
+ u16 num_mac;
+ u8 promiscuous;
+ u8 rsvd0;
+ struct NTWK_MULTICAST_MAC_LIST mac[32];
+} __packed;
+
+struct FWCMD_COMMON_ANON_174_RESPONSE {
+ u32 rsvd0;
+} __packed;
+
+union FWCMD_COMMON_ANON_173_PARAMS {
+ struct FWCMD_COMMON_NTWK_MULTICAST_SET_REQUEST_PAYLOAD request;
+ struct FWCMD_COMMON_ANON_174_RESPONSE response;
+} __packed;
+
+/*
+ * Sets multicast address hash. The MPU will merge the MAC address lists
+ * from all clients, including the networking and storage functions.
+ * This command may fail if the final merged list of MAC addresses exceeds
+ * 32 entries.
+ */
+struct FWCMD_COMMON_NTWK_MULTICAST_SET {
+ union FWCMD_HEADER header;
+ union FWCMD_COMMON_ANON_173_PARAMS params;
+} __packed;
+
+struct FWCMD_COMMON_NTWK_VLAN_CONFIG_REQUEST_PAYLOAD {
+ u16 num_vlan;
+ u8 promiscuous;
+ u8 rsvd0;
+ u16 vlan_tag[32];
+} __packed;
+
+struct FWCMD_COMMON_ANON_176_RESPONSE {
+ u32 rsvd0;
+} __packed;
+
+union FWCMD_COMMON_ANON_175_PARAMS {
+ struct FWCMD_COMMON_NTWK_VLAN_CONFIG_REQUEST_PAYLOAD request;
+ struct FWCMD_COMMON_ANON_176_RESPONSE response;
+} __packed;
+
+/*
+ * Sets VLAN tag filter. The MPU will merge the VLAN tag list from all
+ * clients, including the networking and storage functions. This command
+ * may fail if the final vlan_tag array (from all functions) is longer
+ * than 32 entries.
+ */
+struct FWCMD_COMMON_NTWK_VLAN_CONFIG {
+ union FWCMD_HEADER header;
+ union FWCMD_COMMON_ANON_175_PARAMS params;
+} __packed;
+
+struct RING_DESTROY_REQUEST {
+ u16 ring_type;
+ u16 id;
+ u8 bypass_flush;
+ u8 rsvd0;
+ u16 rsvd1;
+} __packed;
+
+struct FWCMD_COMMON_ANON_190_RESPONSE {
+ u32 rsvd0;
+} __packed;
+
+union FWCMD_COMMON_ANON_189_PARAMS {
+ struct RING_DESTROY_REQUEST request;
+ struct FWCMD_COMMON_ANON_190_RESPONSE response;
+} __packed;
+/*
+ * Command for destroying any ring. The connection(s) using the ring should
+ * be quiesced before destroying the ring.
+ */
+struct FWCMD_COMMON_RING_DESTROY {
+ union FWCMD_HEADER header;
+ union FWCMD_COMMON_ANON_189_PARAMS params;
+} __packed;
+
+struct FWCMD_COMMON_ANON_192_REQUEST {
+ u16 num_pages;
+ u16 rsvd0;
+ struct CQ_CONTEXT_AMAP context;
+ struct PHYS_ADDR pages[4];
+} __packed ;
+
+struct FWCMD_COMMON_ANON_193_RESPONSE {
+ u16 cq_id;
+} __packed ;
+
+union FWCMD_COMMON_ANON_191_PARAMS {
+ struct FWCMD_COMMON_ANON_192_REQUEST request;
+ struct FWCMD_COMMON_ANON_193_RESPONSE response;
+} __packed ;
+
+/*
+ * Command for creating a completion queue. A Completion Queue must span
+ * at least 1 page and at most 4 pages. Each completion queue entry
+ * is 16 bytes regardless of CQ entry format. Thus the ring must be
+ * at least 256 entries deep (corresponding to 1 page) and can be at
+ * most 1024 entries deep (corresponding to 4 pages). The number of
+ * pages posted must contain the CQ ring size as encoded in the context.
+ *
+ */
+struct FWCMD_COMMON_CQ_CREATE {
+ union FWCMD_HEADER header;
+ union FWCMD_COMMON_ANON_191_PARAMS params;
+} __packed ;
+
+struct FWCMD_COMMON_ANON_198_REQUEST {
+ u16 num_pages;
+ u16 rsvd0;
+ struct EQ_CONTEXT_AMAP context;
+ struct PHYS_ADDR pages[8];
+} __packed ;
+
+struct FWCMD_COMMON_ANON_199_RESPONSE {
+ u16 eq_id;
+} __packed ;
+
+union FWCMD_COMMON_ANON_197_PARAMS {
+ struct FWCMD_COMMON_ANON_198_REQUEST request;
+ struct FWCMD_COMMON_ANON_199_RESPONSE response;
+} __packed ;
+
+/*
+ * Command for creating a event queue. An Event Queue must span at least
+ * 1 page and at most 8 pages. The number of pages posted must contain
+ * the EQ ring. The ring is defined by the size of the EQ entries (encoded
+ * in the context) and the number of EQ entries (also encoded in the
+ * context).
+ */
+struct FWCMD_COMMON_EQ_CREATE {
+ union FWCMD_HEADER header;
+ union FWCMD_COMMON_ANON_197_PARAMS params;
+} __packed ;
+
+struct FWCMD_COMMON_ANON_201_REQUEST {
+ u16 cq_id;
+ u16 bcmc_cq_id;
+ u16 num_pages;
+ u16 rsvd0;
+ struct PHYS_ADDR pages[2];
+} __packed;
+
+struct FWCMD_COMMON_ANON_202_RESPONSE {
+ u16 id;
+} __packed;
+
+union FWCMD_COMMON_ANON_200_PARAMS {
+ struct FWCMD_COMMON_ANON_201_REQUEST request;
+ struct FWCMD_COMMON_ANON_202_RESPONSE response;
+} __packed;
+
+/*
+ * Command for creating Ethernet receive ring. An ERX ring contains ETH_RX_D
+ * entries (8 bytes each). An ERX ring must be 1024 entries deep
+ * (corresponding to 2 pages).
+ */
+struct FWCMD_COMMON_ETH_RX_CREATE {
+ union FWCMD_HEADER header;
+ union FWCMD_COMMON_ANON_200_PARAMS params;
+} __packed;
+
+struct FWCMD_COMMON_ANON_204_REQUEST {
+ u16 num_pages;
+ u8 ulp_num;
+ u8 type;
+ struct ETX_CONTEXT_AMAP context;
+ struct PHYS_ADDR pages[8];
+} __packed ;
+
+struct FWCMD_COMMON_ANON_205_RESPONSE {
+ u16 cid;
+ u8 ulp_num;
+ u8 rsvd0;
+} __packed ;
+
+union FWCMD_COMMON_ANON_203_PARAMS {
+ struct FWCMD_COMMON_ANON_204_REQUEST request;
+ struct FWCMD_COMMON_ANON_205_RESPONSE response;
+} __packed ;
+
+/*
+ * Command for creating an Ethernet transmit ring. An ETX ring contains
+ * ETH_WRB entries (16 bytes each). An ETX ring must be at least 256
+ * entries deep (corresponding to 1 page) and at most 2k entries deep
+ * (corresponding to 8 pages).
+ */
+struct FWCMD_COMMON_ETH_TX_CREATE {
+ union FWCMD_HEADER header;
+ union FWCMD_COMMON_ANON_203_PARAMS params;
+} __packed ;
+
+struct FWCMD_COMMON_ANON_222_REQUEST {
+ u16 num_pages;
+ u16 rsvd0;
+ struct MCC_RING_CONTEXT_AMAP context;
+ struct PHYS_ADDR pages[8];
+} __packed ;
+
+struct FWCMD_COMMON_ANON_223_RESPONSE {
+ u16 id;
+} __packed ;
+
+union FWCMD_COMMON_ANON_221_PARAMS {
+ struct FWCMD_COMMON_ANON_222_REQUEST request;
+ struct FWCMD_COMMON_ANON_223_RESPONSE response;
+} __packed ;
+
+/*
+ * Command for creating the MCC ring. An MCC ring must be at least 16
+ * entries deep (corresponding to 1 page) and at most 128 entries deep
+ * (corresponding to 8 pages).
+ */
+struct FWCMD_COMMON_MCC_CREATE {
+ union FWCMD_HEADER header;
+ union FWCMD_COMMON_ANON_221_PARAMS params;
+} __packed ;
+
+struct GET_QOS_IN {
+ u32 qos_params_rsvd;
+} __packed;
+
+struct GET_QOS_OUT {
+ u32 max_bits_per_second_NIC;
+ u32 max_packets_per_second_NIC;
+ u32 max_ios_per_second_iSCSI;
+ u32 max_bytes_per_second_iSCSI;
+ u16 domain_VLAN_tag;
+ u16 fabric_domain_ID;
+ u32 qos_params_oem[4];
+} __packed;
+
+union GET_QOS_PARAMS {
+ struct GET_QOS_IN request;
+ struct GET_QOS_OUT response;
+} __packed;
+
+/* QOS/Bandwidth settings per domain. Applicable only in VMs. */
+struct FWCMD_COMMON_GET_QOS {
+ union FWCMD_HEADER header;
+ union GET_QOS_PARAMS params;
+} __packed;
+
+struct SET_QOS_IN {
+ u32 valid_flags;
+ u32 max_bits_per_second_NIC;
+ u32 max_packets_per_second_NIC;
+ u32 max_ios_per_second_iSCSI;
+ u32 max_bytes_per_second_iSCSI;
+ u16 domain_VLAN_tag;
+ u16 fabric_domain_ID;
+ u32 qos_params_oem[4];
+} __packed;
+
+struct SET_QOS_OUT {
+ u32 qos_params_rsvd;
+} __packed;
+
+union SET_QOS_PARAMS {
+ struct SET_QOS_IN request;
+ struct SET_QOS_OUT response;
+} __packed;
+
+/* QOS/Bandwidth settings per domain. Applicable only in VMs. */
+struct FWCMD_COMMON_SET_QOS {
+ union FWCMD_HEADER header;
+ union SET_QOS_PARAMS params;
+} __packed;
+
+struct SET_FRAME_SIZE_IN {
+ u32 max_tx_frame_size;
+ u32 max_rx_frame_size;
+} __packed;
+
+struct SET_FRAME_SIZE_OUT {
+ u32 chip_max_tx_frame_size;
+ u32 chip_max_rx_frame_size;
+} __packed;
+
+union SET_FRAME_SIZE_PARAMS {
+ struct SET_FRAME_SIZE_IN request;
+ struct SET_FRAME_SIZE_OUT response;
+} __packed;
+
+/* Set frame size command. Only host domain may issue this command. */
+struct FWCMD_COMMON_SET_FRAME_SIZE {
+ union FWCMD_HEADER header;
+ union SET_FRAME_SIZE_PARAMS params;
+} __packed;
+
+struct FORCE_FAILOVER_IN {
+ u32 move_to_port;
+ u32 failover_config;
+} __packed;
+
+struct FWCMD_COMMON_ANON_231_RESPONSE {
+ u32 rsvd0;
+} __packed;
+
+union FWCMD_COMMON_ANON_230_PARAMS {
+ struct FORCE_FAILOVER_IN request;
+ struct FWCMD_COMMON_ANON_231_RESPONSE response;
+} __packed;
+
+/*
+ * Use this command to control failover in BladeEngine. It may be used
+ * to failback to a restored port or to forcibly move traffic from
+ * one port to another. It may also be used to enable or disable the
+ * automatic failover feature. This command can only be issued by domain
+ * 0.
+ */
+struct FWCMD_COMMON_FORCE_FAILOVER {
+ union FWCMD_HEADER header;
+ union FWCMD_COMMON_ANON_230_PARAMS params;
+} __packed;
+
+struct FWCMD_COMMON_ANON_240_REQUEST {
+ u64 context;
+} __packed;
+
+struct FWCMD_COMMON_ANON_241_RESPONSE {
+ u64 context;
+} __packed;
+
+union FWCMD_COMMON_ANON_239_PARAMS {
+ struct FWCMD_COMMON_ANON_240_REQUEST request;
+ struct FWCMD_COMMON_ANON_241_RESPONSE response;
+} __packed;
+
+/*
+ * This command can be used by clients as a no-operation request. Typical
+ * uses for drivers are as a heartbeat mechanism, or deferred processing
+ * catalyst. The ARM will always complete this command with a good completion.
+ * The 64-bit parameter is not touched by the ARM processor.
+ */
+struct FWCMD_COMMON_NOP {
+ union FWCMD_HEADER header;
+ union FWCMD_COMMON_ANON_239_PARAMS params;
+} __packed;
+
+struct NTWK_RX_FILTER_SETTINGS {
+ u8 promiscuous;
+ u8 ip_cksum;
+ u8 tcp_cksum;
+ u8 udp_cksum;
+ u8 pass_err;
+ u8 pass_ckerr;
+ u8 strip_crc;
+ u8 mcast_en;
+ u8 bcast_en;
+ u8 mcast_promiscuous_en;
+ u8 unicast_en;
+ u8 vlan_promiscuous;
+} __packed;
+
+union FWCMD_COMMON_ANON_242_PARAMS {
+ struct NTWK_RX_FILTER_SETTINGS request;
+ struct NTWK_RX_FILTER_SETTINGS response;
+} __packed;
+
+/*
+ * This command is used to modify the ethernet receive filter configuration.
+ * Only domain 0 network function drivers may issue this command. The
+ * applied configuration is returned in the response payload. Note:
+ * Some receive packet filter settings are global on BladeEngine and
+ * can affect both the storage and network function clients that the
+ * BladeEngine hardware and firmware serve. Additionaly, depending
+ * on the revision of BladeEngine, some ethernet receive filter settings
+ * are dependent on others. If a dependency exists between settings
+ * for the BladeEngine revision, and the command request settings do
+ * not meet the dependency requirement, the invalid settings will not
+ * be applied despite the comand succeeding. For example: a driver may
+ * request to enable broadcast packets, but not enable multicast packets.
+ * On early revisions of BladeEngine, there may be no distinction between
+ * broadcast and multicast filters, so broadcast could not be enabled
+ * without enabling multicast. In this scenario, the comand would still
+ * succeed, but the response payload would indicate the previously
+ * configured broadcast and multicast setting.
+ */
+struct FWCMD_COMMON_NTWK_RX_FILTER {
+ union FWCMD_HEADER header;
+ union FWCMD_COMMON_ANON_242_PARAMS params;
+} __packed;
+
+
+struct FWCMD_COMMON_ANON_244_REQUEST {
+ u32 rsvd0;
+} __packed;
+
+struct FWCMD_COMMON_GET_FW_VERSION_RESPONSE_PAYLOAD {
+ u8 firmware_version_string[32];
+ u8 fw_on_flash_version_string[32];
+} __packed;
+
+union FWCMD_COMMON_ANON_243_PARAMS {
+ struct FWCMD_COMMON_ANON_244_REQUEST request;
+ struct FWCMD_COMMON_GET_FW_VERSION_RESPONSE_PAYLOAD response;
+} __packed;
+
+/* This comand retrieves the firmware version. */
+struct FWCMD_COMMON_GET_FW_VERSION {
+ union FWCMD_HEADER header;
+ union FWCMD_COMMON_ANON_243_PARAMS params;
+} __packed;
+
+struct FWCMD_COMMON_ANON_246_REQUEST {
+ u16 tx_flow_control;
+ u16 rx_flow_control;
+} __packed;
+
+struct FWCMD_COMMON_ANON_247_RESPONSE {
+ u32 rsvd0;
+} __packed;
+
+union FWCMD_COMMON_ANON_245_PARAMS {
+ struct FWCMD_COMMON_ANON_246_REQUEST request;
+ struct FWCMD_COMMON_ANON_247_RESPONSE response;
+} __packed;
+
+/*
+ * This comand is used to program BladeEngine flow control behavior.
+ * Only the host networking driver is allowed to use this comand.
+ */
+struct FWCMD_COMMON_SET_FLOW_CONTROL {
+ union FWCMD_HEADER header;
+ union FWCMD_COMMON_ANON_245_PARAMS params;
+} __packed;
+
+struct FWCMD_COMMON_ANON_249_REQUEST {
+ u32 rsvd0;
+} __packed;
+
+struct FWCMD_COMMON_ANON_250_RESPONSE {
+ u16 tx_flow_control;
+ u16 rx_flow_control;
+} __packed;
+
+union FWCMD_COMMON_ANON_248_PARAMS {
+ struct FWCMD_COMMON_ANON_249_REQUEST request;
+ struct FWCMD_COMMON_ANON_250_RESPONSE response;
+} __packed;
+
+/* This comand is used to read BladeEngine flow control settings. */
+struct FWCMD_COMMON_GET_FLOW_CONTROL {
+ union FWCMD_HEADER header;
+ union FWCMD_COMMON_ANON_248_PARAMS params;
+} __packed;
+
+struct EQ_DELAY_PARAMS {
+ u32 eq_id;
+ u32 delay_in_microseconds;
+} __packed;
+
+struct FWCMD_COMMON_ANON_257_REQUEST {
+ u32 num_eq;
+ u32 rsvd0;
+ struct EQ_DELAY_PARAMS delay[16];
+} __packed;
+
+struct FWCMD_COMMON_ANON_258_RESPONSE {
+ u32 delay_resolution_in_microseconds;
+ u32 delay_max_in_microseconds;
+} __packed;
+
+union MODIFY_EQ_DELAY_PARAMS {
+ struct FWCMD_COMMON_ANON_257_REQUEST request;
+ struct FWCMD_COMMON_ANON_258_RESPONSE response;
+} __packed;
+
+/* This comand changes the EQ delay for a given set of EQs. */
+struct FWCMD_COMMON_MODIFY_EQ_DELAY {
+ union FWCMD_HEADER header;
+ union MODIFY_EQ_DELAY_PARAMS params;
+} __packed;
+
+struct FWCMD_COMMON_ANON_260_REQUEST {
+ u32 rsvd0;
+} __packed;
+
+struct BE_FIRMWARE_CONFIG {
+ u16 be_config_number;
+ u16 asic_revision;
+ u32 nic_ulp_mask;
+ u32 tulp_mask;
+ u32 iscsi_ulp_mask;
+ u32 rdma_ulp_mask;
+ u32 rsvd0[4];
+ u32 eth_tx_id_start;
+ u32 eth_tx_id_count;
+ u32 eth_rx_id_start;
+ u32 eth_rx_id_count;
+ u32 tpm_wrbq_id_start;
+ u32 tpm_wrbq_id_count;
+ u32 tpm_defq_id_start;
+ u32 tpm_defq_id_count;
+ u32 iscsi_wrbq_id_start;
+ u32 iscsi_wrbq_id_count;
+ u32 iscsi_defq_id_start;
+ u32 iscsi_defq_id_count;
+ u32 rdma_qp_id_start;
+ u32 rdma_qp_id_count;
+ u32 rsvd1[8];
+} __packed;
+
+union FWCMD_COMMON_ANON_259_PARAMS {
+ struct FWCMD_COMMON_ANON_260_REQUEST request;
+ struct BE_FIRMWARE_CONFIG response;
+} __packed;
+
+/*
+ * This comand queries the current firmware configuration parameters.
+ * The static configuration type is defined by be_config_number. This
+ * differentiates different BladeEngine builds, such as iSCSI Initiator
+ * versus iSCSI Target. For a given static configuration, the Upper
+ * Layer Protocol (ULP) processors may be reconfigured to support different
+ * protocols. Each ULP processor supports one or more protocols. The
+ * masks indicate which processors are configured for each protocol.
+ * For a given static configuration, the number of TCP connections
+ * supported for each protocol may vary. The *_id_start and *_id_count
+ * variables define a linear range of IDs that are available for each
+ * supported protocol. The *_id_count may be used by the driver to allocate
+ * the appropriate number of connection resources. The *_id_start may
+ * be used to map the arbitrary range of IDs to a zero-based range
+ * of indices.
+ */
+struct FWCMD_COMMON_FIRMWARE_CONFIG {
+ union FWCMD_HEADER header;
+ union FWCMD_COMMON_ANON_259_PARAMS params;
+} __packed;
+
+struct FWCMD_COMMON_PORT_EQUALIZATION_PARAMS {
+ u32 emph_lev_sel_port0;
+ u32 emph_lev_sel_port1;
+ u8 xaui_vo_sel;
+ u8 xaui_state;
+ u16 rsvd0;
+ u32 xaui_eq_vector;
+} __packed;
+
+struct FWCMD_COMMON_ANON_262_REQUEST {
+ u32 rsvd0;
+} __packed;
+
+union FWCMD_COMMON_ANON_261_PARAMS {
+ struct FWCMD_COMMON_ANON_262_REQUEST request;
+ struct FWCMD_COMMON_PORT_EQUALIZATION_PARAMS response;
+} __packed;
+
+/*
+ * This comand can be used to read XAUI equalization parameters. The
+ * ARM firmware applies default equalization parameters during initialization.
+ * These parameters may be customer-specific when derived from the
+ * SEEPROM. See SEEPROM_DATA for equalization specific fields.
+ */
+struct FWCMD_COMMON_GET_PORT_EQUALIZATION {
+ union FWCMD_HEADER header;
+ union FWCMD_COMMON_ANON_261_PARAMS params;
+} __packed;
+
+struct FWCMD_COMMON_ANON_264_RESPONSE {
+ u32 rsvd0;
+} __packed;
+
+union FWCMD_COMMON_ANON_263_PARAMS {
+ struct FWCMD_COMMON_PORT_EQUALIZATION_PARAMS request;
+ struct FWCMD_COMMON_ANON_264_RESPONSE response;
+} __packed;
+
+/*
+ * This comand can be used to set XAUI equalization parameters. The ARM
+ * firmware applies default equalization parameters during initialization.
+ * These parameters may be customer-specific when derived from the
+ * SEEPROM. See SEEPROM_DATA for equalization specific fields.
+ */
+struct FWCMD_COMMON_SET_PORT_EQUALIZATION {
+ union FWCMD_HEADER header;
+ union FWCMD_COMMON_ANON_263_PARAMS params;
+} __packed;
+
+#endif /* __fwcmd_common_bmap_h__ */
diff --git a/drivers/staging/benet/fwcmd_eth_bmap.h b/drivers/staging/benet/fwcmd_eth_bmap.h
new file mode 100644
index 000000000000..234b179eace6
--- /dev/null
+++ b/drivers/staging/benet/fwcmd_eth_bmap.h
@@ -0,0 +1,280 @@
+/*
+ * 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:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+/*
+ * Autogenerated by srcgen version: 0127
+ */
+#ifndef __fwcmd_eth_bmap_h__
+#define __fwcmd_eth_bmap_h__
+#include "fwcmd_hdr_bmap.h"
+#include "fwcmd_types_bmap.h"
+
+struct MIB_ETH_STATISTICS_PARAMS_IN {
+ u32 rsvd0;
+} __packed;
+
+struct BE_RXF_STATS {
+ u32 p0recvdtotalbytesLSD; /* DWORD 0 */
+ u32 p0recvdtotalbytesMSD; /* DWORD 1 */
+ u32 p0recvdtotalframes; /* DWORD 2 */
+ u32 p0recvdunicastframes; /* DWORD 3 */
+ u32 p0recvdmulticastframes; /* DWORD 4 */
+ u32 p0recvdbroadcastframes; /* DWORD 5 */
+ u32 p0crcerrors; /* DWORD 6 */
+ u32 p0alignmentsymerrs; /* DWORD 7 */
+ u32 p0pauseframesrecvd; /* DWORD 8 */
+ u32 p0controlframesrecvd; /* DWORD 9 */
+ u32 p0inrangelenerrors; /* DWORD 10 */
+ u32 p0outrangeerrors; /* DWORD 11 */
+ u32 p0frametoolongerrors; /* DWORD 12 */
+ u32 p0droppedaddressmatch; /* DWORD 13 */
+ u32 p0droppedvlanmismatch; /* DWORD 14 */
+ u32 p0ipdroppedtoosmall; /* DWORD 15 */
+ u32 p0ipdroppedtooshort; /* DWORD 16 */
+ u32 p0ipdroppedhdrtoosmall; /* DWORD 17 */
+ u32 p0tcpdroppedlen; /* DWORD 18 */
+ u32 p0droppedrunt; /* DWORD 19 */
+ u32 p0recvd64; /* DWORD 20 */
+ u32 p0recvd65_127; /* DWORD 21 */
+ u32 p0recvd128_256; /* DWORD 22 */
+ u32 p0recvd256_511; /* DWORD 23 */
+ u32 p0recvd512_1023; /* DWORD 24 */
+ u32 p0recvd1518_1522; /* DWORD 25 */
+ u32 p0recvd1522_2047; /* DWORD 26 */
+ u32 p0recvd2048_4095; /* DWORD 27 */
+ u32 p0recvd4096_8191; /* DWORD 28 */
+ u32 p0recvd8192_9216; /* DWORD 29 */
+ u32 p0rcvdipcksmerrs; /* DWORD 30 */
+ u32 p0recvdtcpcksmerrs; /* DWORD 31 */
+ u32 p0recvdudpcksmerrs; /* DWORD 32 */
+ u32 p0recvdnonrsspackets; /* DWORD 33 */
+ u32 p0recvdippackets; /* DWORD 34 */
+ u32 p0recvdchute1packets; /* DWORD 35 */
+ u32 p0recvdchute2packets; /* DWORD 36 */
+ u32 p0recvdchute3packets; /* DWORD 37 */
+ u32 p0recvdipsecpackets; /* DWORD 38 */
+ u32 p0recvdmanagementpackets; /* DWORD 39 */
+ u32 p0xmitbyteslsd; /* DWORD 40 */
+ u32 p0xmitbytesmsd; /* DWORD 41 */
+ u32 p0xmitunicastframes; /* DWORD 42 */
+ u32 p0xmitmulticastframes; /* DWORD 43 */
+ u32 p0xmitbroadcastframes; /* DWORD 44 */
+ u32 p0xmitpauseframes; /* DWORD 45 */
+ u32 p0xmitcontrolframes; /* DWORD 46 */
+ u32 p0xmit64; /* DWORD 47 */
+ u32 p0xmit65_127; /* DWORD 48 */
+ u32 p0xmit128_256; /* DWORD 49 */
+ u32 p0xmit256_511; /* DWORD 50 */
+ u32 p0xmit512_1023; /* DWORD 51 */
+ u32 p0xmit1518_1522; /* DWORD 52 */
+ u32 p0xmit1522_2047; /* DWORD 53 */
+ u32 p0xmit2048_4095; /* DWORD 54 */
+ u32 p0xmit4096_8191; /* DWORD 55 */
+ u32 p0xmit8192_9216; /* DWORD 56 */
+ u32 p0rxfifooverflowdropped; /* DWORD 57 */
+ u32 p0ipseclookupfaileddropped; /* DWORD 58 */
+ u32 p1recvdtotalbytesLSD; /* DWORD 59 */
+ u32 p1recvdtotalbytesMSD; /* DWORD 60 */
+ u32 p1recvdtotalframes; /* DWORD 61 */
+ u32 p1recvdunicastframes; /* DWORD 62 */
+ u32 p1recvdmulticastframes; /* DWORD 63 */
+ u32 p1recvdbroadcastframes; /* DWORD 64 */
+ u32 p1crcerrors; /* DWORD 65 */
+ u32 p1alignmentsymerrs; /* DWORD 66 */
+ u32 p1pauseframesrecvd; /* DWORD 67 */
+ u32 p1controlframesrecvd; /* DWORD 68 */
+ u32 p1inrangelenerrors; /* DWORD 69 */
+ u32 p1outrangeerrors; /* DWORD 70 */
+ u32 p1frametoolongerrors; /* DWORD 71 */
+ u32 p1droppedaddressmatch; /* DWORD 72 */
+ u32 p1droppedvlanmismatch; /* DWORD 73 */
+ u32 p1ipdroppedtoosmall; /* DWORD 74 */
+ u32 p1ipdroppedtooshort; /* DWORD 75 */
+ u32 p1ipdroppedhdrtoosmall; /* DWORD 76 */
+ u32 p1tcpdroppedlen; /* DWORD 77 */
+ u32 p1droppedrunt; /* DWORD 78 */
+ u32 p1recvd64; /* DWORD 79 */
+ u32 p1recvd65_127; /* DWORD 80 */
+ u32 p1recvd128_256; /* DWORD 81 */
+ u32 p1recvd256_511; /* DWORD 82 */
+ u32 p1recvd512_1023; /* DWORD 83 */
+ u32 p1recvd1518_1522; /* DWORD 84 */
+ u32 p1recvd1522_2047; /* DWORD 85 */
+ u32 p1recvd2048_4095; /* DWORD 86 */
+ u32 p1recvd4096_8191; /* DWORD 87 */
+ u32 p1recvd8192_9216; /* DWORD 88 */
+ u32 p1rcvdipcksmerrs; /* DWORD 89 */
+ u32 p1recvdtcpcksmerrs; /* DWORD 90 */
+ u32 p1recvdudpcksmerrs; /* DWORD 91 */
+ u32 p1recvdnonrsspackets; /* DWORD 92 */
+ u32 p1recvdippackets; /* DWORD 93 */
+ u32 p1recvdchute1packets; /* DWORD 94 */
+ u32 p1recvdchute2packets; /* DWORD 95 */
+ u32 p1recvdchute3packets; /* DWORD 96 */
+ u32 p1recvdipsecpackets; /* DWORD 97 */
+ u32 p1recvdmanagementpackets; /* DWORD 98 */
+ u32 p1xmitbyteslsd; /* DWORD 99 */
+ u32 p1xmitbytesmsd; /* DWORD 100 */
+ u32 p1xmitunicastframes; /* DWORD 101 */
+ u32 p1xmitmulticastframes; /* DWORD 102 */
+ u32 p1xmitbroadcastframes; /* DWORD 103 */
+ u32 p1xmitpauseframes; /* DWORD 104 */
+ u32 p1xmitcontrolframes; /* DWORD 105 */
+ u32 p1xmit64; /* DWORD 106 */
+ u32 p1xmit65_127; /* DWORD 107 */
+ u32 p1xmit128_256; /* DWORD 108 */
+ u32 p1xmit256_511; /* DWORD 109 */
+ u32 p1xmit512_1023; /* DWORD 110 */
+ u32 p1xmit1518_1522; /* DWORD 111 */
+ u32 p1xmit1522_2047; /* DWORD 112 */
+ u32 p1xmit2048_4095; /* DWORD 113 */
+ u32 p1xmit4096_8191; /* DWORD 114 */
+ u32 p1xmit8192_9216; /* DWORD 115 */
+ u32 p1rxfifooverflowdropped; /* DWORD 116 */
+ u32 p1ipseclookupfaileddropped; /* DWORD 117 */
+ u32 pxdroppednopbuf; /* DWORD 118 */
+ u32 pxdroppednotxpb; /* DWORD 119 */
+ u32 pxdroppednoipsecbuf; /* DWORD 120 */
+ u32 pxdroppednoerxdescr; /* DWORD 121 */
+ u32 pxdroppednotpredescr; /* DWORD 122 */
+ u32 pxrecvdmanagementportpackets; /* DWORD 123 */
+ u32 pxrecvdmanagementportbytes; /* DWORD 124 */
+ u32 pxrecvdmanagementportpauseframes; /* DWORD 125 */
+ u32 pxrecvdmanagementporterrors; /* DWORD 126 */
+ u32 pxxmitmanagementportpackets; /* DWORD 127 */
+ u32 pxxmitmanagementportbytes; /* DWORD 128 */
+ u32 pxxmitmanagementportpause; /* DWORD 129 */
+ u32 pxxmitmanagementportrxfifooverflow; /* DWORD 130 */
+ u32 pxrecvdipsecipcksmerrs; /* DWORD 131 */
+ u32 pxrecvdtcpsecipcksmerrs; /* DWORD 132 */
+ u32 pxrecvdudpsecipcksmerrs; /* DWORD 133 */
+ u32 pxipsecrunt; /* DWORD 134 */
+ u32 pxipsecaddressmismatchdropped; /* DWORD 135 */
+ u32 pxipsecrxfifooverflowdropped; /* DWORD 136 */
+ u32 pxipsecframestoolong; /* DWORD 137 */
+ u32 pxipsectotalipframes; /* DWORD 138 */
+ u32 pxipseciptoosmall; /* DWORD 139 */
+ u32 pxipseciptooshort; /* DWORD 140 */
+ u32 pxipseciphdrtoosmall; /* DWORD 141 */
+ u32 pxipsectcphdrbad; /* DWORD 142 */
+ u32 pxrecvdipsecchute1; /* DWORD 143 */
+ u32 pxrecvdipsecchute2; /* DWORD 144 */
+ u32 pxrecvdipsecchute3; /* DWORD 145 */
+ u32 pxdropped7frags; /* DWORD 146 */
+ u32 pxdroppedfrags; /* DWORD 147 */
+ u32 pxdroppedinvalidfragring; /* DWORD 148 */
+ u32 pxnumforwardedpackets; /* DWORD 149 */
+} __packed;
+
+union MIB_ETH_STATISTICS_PARAMS {
+ struct MIB_ETH_STATISTICS_PARAMS_IN request;
+ struct BE_RXF_STATS response;
+} __packed;
+
+/*
+ * Query ethernet statistics. All domains may issue this command. The
+ * host domain drivers may optionally reset internal statistic counters
+ * with a query.
+ */
+struct FWCMD_ETH_GET_STATISTICS {
+ union FWCMD_HEADER header;
+ union MIB_ETH_STATISTICS_PARAMS params;
+} __packed;
+
+
+struct FWCMD_ETH_ANON_175_REQUEST {
+ u8 port0_promiscuous;
+ u8 port1_promiscuous;
+ u16 rsvd0;
+} __packed;
+
+struct FWCMD_ETH_ANON_176_RESPONSE {
+ u32 rsvd0;
+} __packed;
+
+union FWCMD_ETH_ANON_174_PARAMS {
+ struct FWCMD_ETH_ANON_175_REQUEST request;
+ struct FWCMD_ETH_ANON_176_RESPONSE response;
+} __packed;
+
+/* Enables/Disables promiscuous ethernet receive mode. */
+struct FWCMD_ETH_PROMISCUOUS {
+ union FWCMD_HEADER header;
+ union FWCMD_ETH_ANON_174_PARAMS params;
+} __packed;
+
+struct FWCMD_ETH_ANON_178_REQUEST {
+ u32 new_fragsize_log2;
+} __packed;
+
+struct FWCMD_ETH_ANON_179_RESPONSE {
+ u32 actual_fragsize_log2;
+} __packed;
+
+union FWCMD_ETH_ANON_177_PARAMS {
+ struct FWCMD_ETH_ANON_178_REQUEST request;
+ struct FWCMD_ETH_ANON_179_RESPONSE response;
+} __packed;
+
+/*
+ * Sets the Ethernet RX fragment size. Only host (domain 0) networking
+ * drivers may issue this command. This call will fail for non-host
+ * protection domains. In this situation the MCC CQ status will indicate
+ * a failure due to insufficient priviledges. The response should be
+ * ignored, and the driver should use the FWCMD_ETH_GET_FRAG_SIZE to
+ * query the existing ethernet receive fragment size. It must use this
+ * fragment size for all fragments in the ethernet receive ring. If
+ * the command succeeds, the driver must use the frag size indicated
+ * in the command response since the requested frag size may not be applied
+ * until the next reboot. When the requested fragsize matches the response
+ * fragsize, this indicates the request was applied immediately.
+ */
+struct FWCMD_ETH_SET_RX_FRAG_SIZE {
+ union FWCMD_HEADER header;
+ union FWCMD_ETH_ANON_177_PARAMS params;
+} __packed;
+
+struct FWCMD_ETH_ANON_181_REQUEST {
+ u32 rsvd0;
+} __packed;
+
+struct FWCMD_ETH_ANON_182_RESPONSE {
+ u32 actual_fragsize_log2;
+} __packed;
+
+union FWCMD_ETH_ANON_180_PARAMS {
+ struct FWCMD_ETH_ANON_181_REQUEST request;
+ struct FWCMD_ETH_ANON_182_RESPONSE response;
+} __packed;
+
+/*
+ * Queries the Ethernet RX fragment size. All domains may issue this
+ * command. The driver should call this command to determine the minimum
+ * required fragment size for the ethernet RX ring buffers. Drivers
+ * may choose to use a larger size for each fragment buffer, but BladeEngine
+ * will use up to the configured minimum required fragsize in each ethernet
+ * receive fragment buffer. For example, if the ethernet receive fragment
+ * size is configured to 4kB, and a driver uses 8kB fragments, a 6kB
+ * ethernet packet received by BladeEngine will be split accross two
+ * of the driver's receive framgents (4kB in one fragment buffer, and
+ * 2kB in the subsequent fragment buffer).
+ */
+struct FWCMD_ETH_GET_RX_FRAG_SIZE {
+ union FWCMD_HEADER header;
+ union FWCMD_ETH_ANON_180_PARAMS params;
+} __packed;
+
+#endif /* __fwcmd_eth_bmap_h__ */
diff --git a/drivers/staging/benet/fwcmd_hdr_bmap.h b/drivers/staging/benet/fwcmd_hdr_bmap.h
new file mode 100644
index 000000000000..28b45328fe7b
--- /dev/null
+++ b/drivers/staging/benet/fwcmd_hdr_bmap.h
@@ -0,0 +1,54 @@
+/*
+ * 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:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+/*
+ * Autogenerated by srcgen version: 0127
+ */
+#ifndef __fwcmd_hdr_bmap_h__
+#define __fwcmd_hdr_bmap_h__
+
+struct FWCMD_REQUEST_HEADER {
+ u8 opcode;
+ u8 subsystem;
+ u8 port_number;
+ u8 domain;
+ u32 timeout;
+ u32 request_length;
+ u32 rsvd0;
+} __packed;
+
+struct FWCMD_RESPONSE_HEADER {
+ u8 opcode;
+ u8 subsystem;
+ u8 rsvd0;
+ u8 domain;
+ u8 status;
+ u8 additional_status;
+ u16 rsvd1;
+ u32 response_length;
+ u32 actual_response_length;
+} __packed;
+
+/*
+ * The firmware/driver overwrites the input FWCMD_REQUEST_HEADER with
+ * the output FWCMD_RESPONSE_HEADER.
+ */
+union FWCMD_HEADER {
+ struct FWCMD_REQUEST_HEADER request;
+ struct FWCMD_RESPONSE_HEADER response;
+} __packed;
+
+#endif /* __fwcmd_hdr_bmap_h__ */
diff --git a/drivers/staging/benet/fwcmd_mcc.h b/drivers/staging/benet/fwcmd_mcc.h
new file mode 100644
index 000000000000..9eeca878c1fb
--- /dev/null
+++ b/drivers/staging/benet/fwcmd_mcc.h
@@ -0,0 +1,94 @@
+/*
+ * 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:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+/*
+ * Autogenerated by srcgen version: 0127
+ */
+#ifndef __fwcmd_mcc_amap_h__
+#define __fwcmd_mcc_amap_h__
+#include "fwcmd_opcodes.h"
+/*
+ * Where applicable, a WRB, may contain a list of Scatter-gather elements.
+ * Each element supports a 64 bit address and a 32bit length field.
+ */
+struct BE_MCC_SGE_AMAP {
+ u8 pa_lo[32]; /* DWORD 0 */
+ u8 pa_hi[32]; /* DWORD 1 */
+ u8 length[32]; /* DWORD 2 */
+} __packed;
+struct MCC_SGE_AMAP {
+ u32 dw[3];
+};
+/*
+ * The design of an MCC_SGE allows up to 19 elements to be embedded
+ * in a WRB, supporting 64KB data transfers (assuming a 4KB page size).
+ */
+struct BE_MCC_WRB_PAYLOAD_AMAP {
+ union {
+ struct BE_MCC_SGE_AMAP sgl[19];
+ u8 embedded[59][32]; /* DWORD 0 */
+ };
+} __packed;
+struct MCC_WRB_PAYLOAD_AMAP {
+ u32 dw[59];
+};
+
+/*
+ * This is the structure of the MCC Command WRB for commands
+ * sent to the Management Processing Unit (MPU). See section
+ * for usage in embedded and non-embedded modes.
+ */
+struct BE_MCC_WRB_AMAP {
+ u8 embedded; /* DWORD 0 */
+ u8 rsvd0[2]; /* DWORD 0 */
+ u8 sge_count[5]; /* DWORD 0 */
+ u8 rsvd1[16]; /* DWORD 0 */
+ u8 special[8]; /* DWORD 0 */
+ u8 payload_length[32]; /* DWORD 1 */
+ u8 tag[2][32]; /* DWORD 2 */
+ u8 rsvd2[32]; /* DWORD 4 */
+ struct BE_MCC_WRB_PAYLOAD_AMAP payload;
+} __packed;
+struct MCC_WRB_AMAP {
+ u32 dw[64];
+};
+
+/* This is the structure of the MCC Completion queue entry */
+struct BE_MCC_CQ_ENTRY_AMAP {
+ u8 completion_status[16]; /* DWORD 0 */
+ u8 extended_status[16]; /* DWORD 0 */
+ u8 mcc_tag[2][32]; /* DWORD 1 */
+ u8 rsvd0[27]; /* DWORD 3 */
+ u8 consumed; /* DWORD 3 */
+ u8 completed; /* DWORD 3 */
+ u8 hpi_buffer_completion; /* DWORD 3 */
+ u8 async_event; /* DWORD 3 */
+ u8 valid; /* DWORD 3 */
+} __packed;
+struct MCC_CQ_ENTRY_AMAP {
+ u32 dw[4];
+};
+
+/* Mailbox structures used by the MPU during bootstrap */
+struct BE_MCC_MAILBOX_AMAP {
+ struct BE_MCC_WRB_AMAP wrb;
+ struct BE_MCC_CQ_ENTRY_AMAP cq;
+} __packed;
+struct MCC_MAILBOX_AMAP {
+ u32 dw[68];
+};
+
+#endif /* __fwcmd_mcc_amap_h__ */
diff --git a/drivers/staging/benet/fwcmd_opcodes.h b/drivers/staging/benet/fwcmd_opcodes.h
new file mode 100644
index 000000000000..23d569386b46
--- /dev/null
+++ b/drivers/staging/benet/fwcmd_opcodes.h
@@ -0,0 +1,244 @@
+/*
+ * 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:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+/*
+ * Autogenerated by srcgen version: 0127
+ */
+#ifndef __fwcmd_opcodes_amap_h__
+#define __fwcmd_opcodes_amap_h__
+
+/*
+ * --- FWCMD_SUBSYSTEMS ---
+ * The commands are grouped into the following subsystems. The subsystem
+ * code along with the opcode uniquely identify a particular fwcmd.
+ */
+#define FWCMD_SUBSYSTEM_RSVD (0) /* This subsystem is reserved. It is */
+ /* never used. */
+#define FWCMD_SUBSYSTEM_COMMON (1) /* CMDs in this group are common to
+ * all subsystems. See
+ * COMMON_SUBSYSTEM_OPCODES for opcodes
+ * and Common Host Configuration CMDs
+ * for the FWCMD descriptions.
+ */
+#define FWCMD_SUBSYSTEM_COMMON_ISCSI (2) /* CMDs in this group are */
+ /*
+ * common to Initiator and Target. See
+ * COMMON_ISCSI_SUBSYSTEM_OPCODES and
+ * Common iSCSI Initiator and Target
+ * CMDs for the command descriptions.
+ */
+#define FWCMD_SUBSYSTEM_ETH (3) /* This subsystem is used to
+ execute Ethernet commands. */
+
+#define FWCMD_SUBSYSTEM_TPM (4) /* This subsystem is used
+ to execute TPM commands. */
+#define FWCMD_SUBSYSTEM_PXE_UNDI (5) /* This subsystem is used
+ * to execute PXE
+ * and UNDI specific commands.
+ */
+
+#define FWCMD_SUBSYSTEM_ISCSI_INI (6) /* This subsystem is used to
+ execute ISCSI Initiator
+ specific commands.
+ */
+#define FWCMD_SUBSYSTEM_ISCSI_TGT (7) /* This subsystem is used
+ to execute iSCSI Target
+ specific commands.between
+ PTL and ARM firmware.
+ */
+#define FWCMD_SUBSYSTEM_MILI_PTL (8) /* This subsystem is used to
+ execute iSCSI Target specific
+ commands.between MILI
+ and PTL. */
+#define FWCMD_SUBSYSTEM_MILI_TMD (9) /* This subsystem is used to
+ execute iSCSI Target specific
+ commands between MILI
+ and TMD. */
+#define FWCMD_SUBSYSTEM_PROXY (11) /* This subsystem is used
+ to execute proxied commands
+ within the host at the
+ explicit request of a
+ non priviledged domain.
+ This 'subsystem' is entirely
+ virtual from the controller
+ and firmware perspective as
+ it is implemented in host
+ drivers.
+ */
+
+/*
+ * --- COMMON_SUBSYSTEM_OPCODES ---
+ * These opcodes are common to both networking and storage PCI
+ * functions. They are used to reserve resources and configure
+ * BladeEngine. These opcodes all use the FWCMD_SUBSYSTEM_COMMON
+ * subsystem code.
+ */
+#define OPCODE_COMMON_NTWK_MAC_QUERY (1)
+#define SUBSYSTEM_COMMON_NTWK_MAC_QUERY (1)
+#define SUBSYSTEM_COMMON_NTWK_MAC_SET (1)
+#define SUBSYSTEM_COMMON_NTWK_MULTICAST_SET (1)
+#define SUBSYSTEM_COMMON_NTWK_VLAN_CONFIG (1)
+#define SUBSYSTEM_COMMON_NTWK_LINK_STATUS_QUERY (1)
+#define SUBSYSTEM_COMMON_READ_FLASHROM (1)
+#define SUBSYSTEM_COMMON_WRITE_FLASHROM (1)
+#define SUBSYSTEM_COMMON_QUERY_MAX_FWCMD_BUFFER_SIZE (1)
+#define SUBSYSTEM_COMMON_ADD_PAGE_TABLES (1)
+#define SUBSYSTEM_COMMON_REMOVE_PAGE_TABLES (1)
+#define SUBSYSTEM_COMMON_RING_DESTROY (1)
+#define SUBSYSTEM_COMMON_CQ_CREATE (1)
+#define SUBSYSTEM_COMMON_EQ_CREATE (1)
+#define SUBSYSTEM_COMMON_ETH_RX_CREATE (1)
+#define SUBSYSTEM_COMMON_ETH_TX_CREATE (1)
+#define SUBSYSTEM_COMMON_ISCSI_DEFQ_CREATE (1)
+#define SUBSYSTEM_COMMON_ISCSI_WRBQ_CREATE (1)
+#define SUBSYSTEM_COMMON_MCC_CREATE (1)
+#define SUBSYSTEM_COMMON_JELL_CONFIG (1)
+#define SUBSYSTEM_COMMON_FORCE_FAILOVER (1)
+#define SUBSYSTEM_COMMON_ADD_TEMPLATE_HEADER_BUFFERS (1)
+#define SUBSYSTEM_COMMON_REMOVE_TEMPLATE_HEADER_BUFFERS (1)
+#define SUBSYSTEM_COMMON_POST_ZERO_BUFFER (1)
+#define SUBSYSTEM_COMMON_GET_QOS (1)
+#define SUBSYSTEM_COMMON_SET_QOS (1)
+#define SUBSYSTEM_COMMON_TCP_GET_STATISTICS (1)
+#define SUBSYSTEM_COMMON_SEEPROM_READ (1)
+#define SUBSYSTEM_COMMON_TCP_STATE_QUERY (1)
+#define SUBSYSTEM_COMMON_GET_CNTL_ATTRIBUTES (1)
+#define SUBSYSTEM_COMMON_NOP (1)
+#define SUBSYSTEM_COMMON_NTWK_RX_FILTER (1)
+#define SUBSYSTEM_COMMON_GET_FW_VERSION (1)
+#define SUBSYSTEM_COMMON_SET_FLOW_CONTROL (1)
+#define SUBSYSTEM_COMMON_GET_FLOW_CONTROL (1)
+#define SUBSYSTEM_COMMON_SET_TCP_PARAMETERS (1)
+#define SUBSYSTEM_COMMON_SET_FRAME_SIZE (1)
+#define SUBSYSTEM_COMMON_GET_FAT (1)
+#define SUBSYSTEM_COMMON_MODIFY_EQ_DELAY (1)
+#define SUBSYSTEM_COMMON_FIRMWARE_CONFIG (1)
+#define SUBSYSTEM_COMMON_ENABLE_DISABLE_DOMAINS (1)
+#define SUBSYSTEM_COMMON_GET_DOMAIN_CONFIG (1)
+#define SUBSYSTEM_COMMON_SET_VLD_CONFIG (1)
+#define SUBSYSTEM_COMMON_GET_VLD_CONFIG (1)
+#define SUBSYSTEM_COMMON_GET_PORT_EQUALIZATION (1)
+#define SUBSYSTEM_COMMON_SET_PORT_EQUALIZATION (1)
+#define SUBSYSTEM_COMMON_RED_CONFIG (1)
+#define OPCODE_COMMON_NTWK_MAC_SET (2)
+#define OPCODE_COMMON_NTWK_MULTICAST_SET (3)
+#define OPCODE_COMMON_NTWK_VLAN_CONFIG (4)
+#define OPCODE_COMMON_NTWK_LINK_STATUS_QUERY (5)
+#define OPCODE_COMMON_READ_FLASHROM (6)
+#define OPCODE_COMMON_WRITE_FLASHROM (7)
+#define OPCODE_COMMON_QUERY_MAX_FWCMD_BUFFER_SIZE (8)
+#define OPCODE_COMMON_ADD_PAGE_TABLES (9)
+#define OPCODE_COMMON_REMOVE_PAGE_TABLES (10)
+#define OPCODE_COMMON_RING_DESTROY (11)
+#define OPCODE_COMMON_CQ_CREATE (12)
+#define OPCODE_COMMON_EQ_CREATE (13)
+#define OPCODE_COMMON_ETH_RX_CREATE (14)
+#define OPCODE_COMMON_ETH_TX_CREATE (15)
+#define OPCODE_COMMON_NET_RESERVED0 (16) /* Reserved */
+#define OPCODE_COMMON_NET_RESERVED1 (17) /* Reserved */
+#define OPCODE_COMMON_NET_RESERVED2 (18) /* Reserved */
+#define OPCODE_COMMON_ISCSI_DEFQ_CREATE (19)
+#define OPCODE_COMMON_ISCSI_WRBQ_CREATE (20)
+#define OPCODE_COMMON_MCC_CREATE (21)
+#define OPCODE_COMMON_JELL_CONFIG (22)
+#define OPCODE_COMMON_FORCE_FAILOVER (23)
+#define OPCODE_COMMON_ADD_TEMPLATE_HEADER_BUFFERS (24)
+#define OPCODE_COMMON_REMOVE_TEMPLATE_HEADER_BUFFERS (25)
+#define OPCODE_COMMON_POST_ZERO_BUFFER (26)
+#define OPCODE_COMMON_GET_QOS (27)
+#define OPCODE_COMMON_SET_QOS (28)
+#define OPCODE_COMMON_TCP_GET_STATISTICS (29)
+#define OPCODE_COMMON_SEEPROM_READ (30)
+#define OPCODE_COMMON_TCP_STATE_QUERY (31)
+#define OPCODE_COMMON_GET_CNTL_ATTRIBUTES (32)
+#define OPCODE_COMMON_NOP (33)
+#define OPCODE_COMMON_NTWK_RX_FILTER (34)
+#define OPCODE_COMMON_GET_FW_VERSION (35)
+#define OPCODE_COMMON_SET_FLOW_CONTROL (36)
+#define OPCODE_COMMON_GET_FLOW_CONTROL (37)
+#define OPCODE_COMMON_SET_TCP_PARAMETERS (38)
+#define OPCODE_COMMON_SET_FRAME_SIZE (39)
+#define OPCODE_COMMON_GET_FAT (40)
+#define OPCODE_COMMON_MODIFY_EQ_DELAY (41)
+#define OPCODE_COMMON_FIRMWARE_CONFIG (42)
+#define OPCODE_COMMON_ENABLE_DISABLE_DOMAINS (43)
+#define OPCODE_COMMON_GET_DOMAIN_CONFIG (44)
+#define OPCODE_COMMON_SET_VLD_CONFIG (45)
+#define OPCODE_COMMON_GET_VLD_CONFIG (46)
+#define OPCODE_COMMON_GET_PORT_EQUALIZATION (47)
+#define OPCODE_COMMON_SET_PORT_EQUALIZATION (48)
+#define OPCODE_COMMON_RED_CONFIG (49)
+
+
+
+/*
+ * --- ETH_SUBSYSTEM_OPCODES ---
+ * These opcodes are used for configuring the Ethernet interfaces. These
+ * opcodes all use the FWCMD_SUBSYSTEM_ETH subsystem code.
+ */
+#define OPCODE_ETH_RSS_CONFIG (1)
+#define OPCODE_ETH_ACPI_CONFIG (2)
+#define SUBSYSTEM_ETH_RSS_CONFIG (3)
+#define SUBSYSTEM_ETH_ACPI_CONFIG (3)
+#define OPCODE_ETH_PROMISCUOUS (3)
+#define SUBSYSTEM_ETH_PROMISCUOUS (3)
+#define SUBSYSTEM_ETH_GET_STATISTICS (3)
+#define SUBSYSTEM_ETH_GET_RX_FRAG_SIZE (3)
+#define SUBSYSTEM_ETH_SET_RX_FRAG_SIZE (3)
+#define OPCODE_ETH_GET_STATISTICS (4)
+#define OPCODE_ETH_GET_RX_FRAG_SIZE (5)
+#define OPCODE_ETH_SET_RX_FRAG_SIZE (6)
+
+
+
+
+
+/*
+ * --- MCC_STATUS_CODE ---
+ * These are the global status codes used by all subsystems
+ */
+#define MCC_STATUS_SUCCESS (0) /* Indicates a successful
+ completion of the command */
+#define MCC_STATUS_INSUFFICIENT_PRIVILEGES (1) /* The client does not have
+ sufficient privileges to
+ execute the command */
+#define MCC_STATUS_INVALID_PARAMETER (2) /* A parameter in the command
+ was invalid. The extended
+ status contains the index
+ of the parameter */
+#define MCC_STATUS_INSUFFICIENT_RESOURCES (3) /* There are insufficient
+ chip resources to execute
+ the command */
+#define MCC_STATUS_QUEUE_FLUSHING (4) /* The command is completing
+ because the queue was
+ getting flushed */
+#define MCC_STATUS_DMA_FAILED (5) /* The command is completing
+ with a DMA error */
+
+/*
+ * --- MGMT_ERROR_CODES ---
+ * Error Codes returned in the status field of the FWCMD response header
+ */
+#define MGMT_STATUS_SUCCESS (0) /* The FWCMD completed
+ without errors */
+#define MGMT_STATUS_FAILED (1) /* Error status in the Status
+ field of the
+ struct FWCMD_RESPONSE_HEADER */
+#define MGMT_STATUS_ILLEGAL_REQUEST (2) /* Invalid FWCMD opcode */
+#define MGMT_STATUS_ILLEGAL_FIELD (3) /* Invalid parameter in
+ the FWCMD payload */
+
+#endif /* __fwcmd_opcodes_amap_h__ */
diff --git a/drivers/staging/benet/fwcmd_types_bmap.h b/drivers/staging/benet/fwcmd_types_bmap.h
new file mode 100644
index 000000000000..92217aff3a16
--- /dev/null
+++ b/drivers/staging/benet/fwcmd_types_bmap.h
@@ -0,0 +1,29 @@
+/*
+ * 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:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+/*
+ * Autogenerated by srcgen version: 0127
+ */
+#ifndef __fwcmd_types_bmap_h__
+#define __fwcmd_types_bmap_h__
+
+/* MAC address format */
+struct MAC_ADDRESS_FORMAT {
+ u16 SizeOfStructure;
+ u8 MACAddress[6];
+} __packed;
+
+#endif /* __fwcmd_types_bmap_h__ */
diff --git a/drivers/staging/benet/host_struct.h b/drivers/staging/benet/host_struct.h
new file mode 100644
index 000000000000..3de6722b980f
--- /dev/null
+++ b/drivers/staging/benet/host_struct.h
@@ -0,0 +1,182 @@
+/*
+ * 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:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+/*
+ * Autogenerated by srcgen version: 0127
+ */
+#ifndef __host_struct_amap_h__
+#define __host_struct_amap_h__
+#include "be_cm.h"
+#include "be_common.h"
+#include "descriptors.h"
+
+/* --- EQ_COMPLETION_MAJOR_CODE_ENUM --- */
+#define EQ_MAJOR_CODE_COMPLETION (0) /* Completion event on a */
+ /* qcompletion ueue. */
+#define EQ_MAJOR_CODE_ETH (1) /* Affiliated Ethernet Event. */
+#define EQ_MAJOR_CODE_RESERVED (2) /* Reserved */
+#define EQ_MAJOR_CODE_RDMA (3) /* Affiliated RDMA Event. */
+#define EQ_MAJOR_CODE_ISCSI (4) /* Affiliated ISCSI Event */
+#define EQ_MAJOR_CODE_UNAFFILIATED (5) /* Unaffiliated Event */
+
+/* --- EQ_COMPLETION_MINOR_CODE_ENUM --- */
+#define EQ_MINOR_CODE_COMPLETION (0) /* Completion event on a */
+ /* completion queue. */
+#define EQ_MINOR_CODE_OTHER (1) /* Other Event (TBD). */
+
+/* Queue Entry Definition for all 4 byte event queue types. */
+struct BE_EQ_ENTRY_AMAP {
+ u8 Valid; /* DWORD 0 */
+ u8 MajorCode[3]; /* DWORD 0 */
+ u8 MinorCode[12]; /* DWORD 0 */
+ u8 ResourceID[16]; /* DWORD 0 */
+} __packed;
+struct EQ_ENTRY_AMAP {
+ u32 dw[1];
+};
+
+/*
+ * --- ETH_EVENT_CODE ---
+ * These codes are returned by the MPU when one of these events has occurred,
+ * and the event is configured to report to an Event Queue when an event
+ * is detected.
+ */
+#define ETH_EQ_LINK_STATUS (0) /* Link status change event */
+ /* detected. */
+#define ETH_EQ_WATERMARK (1) /* watermark event detected. */
+#define ETH_EQ_MAGIC_PKT (2) /* magic pkt event detected. */
+#define ETH_EQ_ACPI_PKT0 (3) /* ACPI interesting packet */
+ /* detected. */
+#define ETH_EQ_ACPI_PKT1 (3) /* ACPI interesting packet */
+ /* detected. */
+#define ETH_EQ_ACPI_PKT2 (3) /* ACPI interesting packet */
+ /* detected. */
+#define ETH_EQ_ACPI_PKT3 (3) /* ACPI interesting packet */
+ /* detected. */
+
+/*
+ * --- ETH_TX_COMPL_STATUS_ENUM ---
+ * Status codes contained in Ethernet TX completion descriptors.
+ */
+#define ETH_COMP_VALID (0)
+#define ETH_COMP_ERROR (1)
+#define ETH_COMP_INVALID (15)
+
+/*
+ * --- ETH_TX_COMPL_PORT_ENUM ---
+ * Port indicator contained in Ethernet TX completion descriptors.
+ */
+#define ETH_COMP_PORT0 (0)
+#define ETH_COMP_PORT1 (1)
+#define ETH_COMP_MGMT (2)
+
+/*
+ * --- ETH_TX_COMPL_CT_ENUM ---
+ * Completion type indicator contained in Ethernet TX completion descriptors.
+ */
+#define ETH_COMP_ETH (0)
+
+/*
+ * Work request block that the driver issues to the chip for
+ * Ethernet transmissions. All control fields must be valid in each WRB for
+ * a message. The controller, as specified by the flags, optionally writes
+ * an entry to the Completion Ring and generate an event.
+ */
+struct BE_ETH_WRB_AMAP {
+ u8 frag_pa_hi[32]; /* DWORD 0 */
+ u8 frag_pa_lo[32]; /* DWORD 1 */
+ u8 complete; /* DWORD 2 */
+ u8 event; /* DWORD 2 */
+ u8 crc; /* DWORD 2 */
+ u8 forward; /* DWORD 2 */
+ u8 ipsec; /* DWORD 2 */
+ u8 mgmt; /* DWORD 2 */
+ u8 ipcs; /* DWORD 2 */
+ u8 udpcs; /* DWORD 2 */
+ u8 tcpcs; /* DWORD 2 */
+ u8 lso; /* DWORD 2 */
+ u8 last; /* DWORD 2 */
+ u8 vlan; /* DWORD 2 */
+ u8 dbg[3]; /* DWORD 2 */
+ u8 hash_val[3]; /* DWORD 2 */
+ u8 lso_mss[14]; /* DWORD 2 */
+ u8 frag_len[16]; /* DWORD 3 */
+ u8 vlan_tag[16]; /* DWORD 3 */
+} __packed;
+struct ETH_WRB_AMAP {
+ u32 dw[4];
+};
+
+/* This is an Ethernet transmit completion descriptor */
+struct BE_ETH_TX_COMPL_AMAP {
+ u8 user_bytes[16]; /* DWORD 0 */
+ u8 nwh_bytes[8]; /* DWORD 0 */
+ u8 lso; /* DWORD 0 */
+ u8 rsvd0[7]; /* DWORD 0 */
+ u8 wrb_index[16]; /* DWORD 1 */
+ u8 ct[2]; /* DWORD 1 */
+ u8 port[2]; /* DWORD 1 */
+ u8 rsvd1[8]; /* DWORD 1 */
+ u8 status[4]; /* DWORD 1 */
+ u8 rsvd2[16]; /* DWORD 2 */
+ u8 ringid[11]; /* DWORD 2 */
+ u8 hash_val[4]; /* DWORD 2 */
+ u8 valid; /* DWORD 2 */
+ u8 rsvd3[32]; /* DWORD 3 */
+} __packed;
+struct ETH_TX_COMPL_AMAP {
+ u32 dw[4];
+};
+
+/* Ethernet Receive Buffer descriptor */
+struct BE_ETH_RX_D_AMAP {
+ u8 fragpa_hi[32]; /* DWORD 0 */
+ u8 fragpa_lo[32]; /* DWORD 1 */
+} __packed;
+struct ETH_RX_D_AMAP {
+ u32 dw[2];
+};
+
+/* This is an Ethernet Receive Completion Descriptor */
+struct BE_ETH_RX_COMPL_AMAP {
+ u8 vlan_tag[16]; /* DWORD 0 */
+ u8 pktsize[14]; /* DWORD 0 */
+ u8 port; /* DWORD 0 */
+ u8 rsvd0; /* DWORD 0 */
+ u8 err; /* DWORD 1 */
+ u8 rsshp; /* DWORD 1 */
+ u8 ipf; /* DWORD 1 */
+ u8 tcpf; /* DWORD 1 */
+ u8 udpf; /* DWORD 1 */
+ u8 ipcksm; /* DWORD 1 */
+ u8 tcpcksm; /* DWORD 1 */
+ u8 udpcksm; /* DWORD 1 */
+ u8 macdst[6]; /* DWORD 1 */
+ u8 vtp; /* DWORD 1 */
+ u8 vtm; /* DWORD 1 */
+ u8 fragndx[10]; /* DWORD 1 */
+ u8 ct[2]; /* DWORD 1 */
+ u8 ipsec; /* DWORD 1 */
+ u8 numfrags[3]; /* DWORD 1 */
+ u8 rsvd1[31]; /* DWORD 2 */
+ u8 valid; /* DWORD 2 */
+ u8 rsshash[32]; /* DWORD 3 */
+} __packed;
+struct ETH_RX_COMPL_AMAP {
+ u32 dw[4];
+};
+
+#endif /* __host_struct_amap_h__ */
diff --git a/drivers/staging/benet/hwlib.h b/drivers/staging/benet/hwlib.h
new file mode 100644
index 000000000000..afedf4dc5903
--- /dev/null
+++ b/drivers/staging/benet/hwlib.h
@@ -0,0 +1,830 @@
+/*
+ * 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:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+#ifndef __hwlib_h__
+#define __hwlib_h__
+
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+
+#include "regmap.h" /* srcgen array map output */
+
+#include "asyncmesg.h"
+#include "fwcmd_opcodes.h"
+#include "post_codes.h"
+#include "fwcmd_mcc.h"
+
+#include "fwcmd_types_bmap.h"
+#include "fwcmd_common_bmap.h"
+#include "fwcmd_eth_bmap.h"
+#include "bestatus.h"
+/*
+ *
+ * Macros for reading/writing a protection domain or CSR registers
+ * in BladeEngine.
+ */
+#define PD_READ(fo, field) ioread32((fo)->db_va + \
+ offsetof(struct BE_PROTECTION_DOMAIN_DBMAP_AMAP, field)/8)
+
+#define PD_WRITE(fo, field, val) iowrite32(val, (fo)->db_va + \
+ offsetof(struct BE_PROTECTION_DOMAIN_DBMAP_AMAP, field)/8)
+
+#define CSR_READ(fo, field) ioread32((fo)->csr_va + \
+ offsetof(struct BE_BLADE_ENGINE_CSRMAP_AMAP, field)/8)
+
+#define CSR_WRITE(fo, field, val) iowrite32(val, (fo)->csr_va + \
+ offsetof(struct BE_BLADE_ENGINE_CSRMAP_AMAP, field)/8)
+
+#define PCICFG0_READ(fo, field) ioread32((fo)->pci_va + \
+ offsetof(struct BE_PCICFG0_CSRMAP_AMAP, field)/8)
+
+#define PCICFG0_WRITE(fo, field, val) iowrite32(val, (fo)->pci_va + \
+ offsetof(struct BE_PCICFG0_CSRMAP_AMAP, field)/8)
+
+#define PCICFG1_READ(fo, field) ioread32((fo)->pci_va + \
+ offsetof(struct BE_PCICFG1_CSRMAP_AMAP, field)/8)
+
+#define PCICFG1_WRITE(fo, field, val) iowrite32(val, (fo)->pci_va + \
+ offsetof(struct BE_PCICFG1_CSRMAP_AMAP, field)/8)
+
+#ifdef BE_DEBUG
+#define ASSERT(c) BUG_ON(!(c));
+#else
+#define ASSERT(c)
+#endif
+
+/* debug levels */
+enum BE_DEBUG_LEVELS {
+ DL_ALWAYS = 0, /* cannot be masked */
+ DL_ERR = 0x1, /* errors that should never happen */
+ DL_WARN = 0x2, /* something questionable.
+ recoverable errors */
+ DL_NOTE = 0x4, /* infrequent, important debug info */
+ DL_INFO = 0x8, /* debug information */
+ DL_VERBOSE = 0x10, /* detailed info, such as buffer traces */
+ BE_DL_MIN_VALUE = 0x1, /* this is the min value used */
+ BE_DL_MAX_VALUE = 0x80 /* this is the higheset value used */
+} ;
+
+extern unsigned int trace_level;
+
+#define TRACE(lm, fmt, args...) { \
+ if (trace_level & lm) { \
+ printk(KERN_NOTICE "BE: %s:%d \n" fmt, \
+ __FILE__ , __LINE__ , ## args); \
+ } \
+ }
+
+static inline unsigned int be_trace_set_level(unsigned int level)
+{
+ unsigned int old_level = trace_level;
+ trace_level = level;
+ return old_level;
+}
+
+#define be_trace_get_level() trace_level
+/*
+ * Returns number of pages spanned by the size of data
+ * starting at the given address.
+ */
+#define PAGES_SPANNED(_address, _size) \
+ ((u32)((((size_t)(_address) & (PAGE_SIZE - 1)) + \
+ (_size) + (PAGE_SIZE - 1)) >> PAGE_SHIFT))
+/* Byte offset into the page corresponding to given address */
+#define OFFSET_IN_PAGE(_addr_) ((size_t)(_addr_) & (PAGE_SIZE-1))
+
+/*
+ * circular subtract.
+ * Returns a - b assuming a circular number system, where a and b are
+ * in range (0, maxValue-1). If a==b, zero is returned so the
+ * highest value possible with this subtraction is maxValue-1.
+ */
+static inline u32 be_subc(u32 a, u32 b, u32 max)
+{
+ ASSERT(a <= max && b <= max);
+ ASSERT(max > 0);
+ return a >= b ? (a - b) : (max - b + a);
+}
+
+static inline u32 be_addc(u32 a, u32 b, u32 max)
+{
+ ASSERT(a < max);
+ ASSERT(max > 0);
+ return (max - a > b) ? (a + b) : (b + a - max);
+}
+
+/* descriptor for a physically contiguous memory used for ring */
+struct ring_desc {
+ u32 length; /* length in bytes */
+ void *va; /* virtual address */
+ u64 pa; /* bus address */
+} ;
+
+/*
+ * This structure stores information about a ring shared between hardware
+ * and software. Each ring is allocated by the driver in the uncached
+ * extension and mapped into BladeEngine's unified table.
+ */
+struct mp_ring {
+ u32 pages; /* queue size in pages */
+ u32 id; /* queue id assigned by beklib */
+ u32 num; /* number of elements in queue */
+ u32 cidx; /* consumer index */
+ u32 pidx; /* producer index -- not used by most rings */
+ u32 itemSize; /* size in bytes of one object */
+
+ void *va; /* The virtual address of the ring.
+ This should be last to allow 32 & 64
+ bit debugger extensions to work. */
+} ;
+
+/*----------- amap bit filed get / set macros and functions -----*/
+/*
+ * Structures defined in the map header files (under fw/amap/) with names
+ * in the format BE_<name>_AMAP are pseudo structures with members
+ * of type u8. These structures are templates that are used in
+ * conjuntion with the structures with names in the format
+ * <name>_AMAP to calculate the bit masks and bit offsets to get or set
+ * bit fields in structures. The structures <name>_AMAP are arrays
+ * of 32 bits words and have the correct size. The following macros
+ * provide convenient ways to get and set the various members
+ * in the structures without using strucctures with bit fields.
+ * Always use the macros AMAP_GET_BITS_PTR and AMAP_SET_BITS_PTR
+ * macros to extract and set various members.
+ */
+
+/*
+ * Returns the a bit mask for the register that is NOT shifted into location.
+ * That means return values always look like: 0x1, 0xFF, 0x7FF, etc...
+ */
+static inline u32 amap_mask(u32 bit_size)
+{
+ return bit_size == 32 ? 0xFFFFFFFF : (1 << bit_size) - 1;
+}
+
+#define AMAP_BIT_MASK(_struct_, field) \
+ amap_mask(AMAP_BIT_SIZE(_struct_, field))
+
+/*
+ * non-optimized set bits function. First clears the bits and then assigns them.
+ * This does not require knowledge of the particular DWORD you are setting.
+ * e.g. AMAP_SET_BITS_PTR (struct, field1, &contextMemory, 123);
+ */
+static inline void
+amap_set(void *ptr, u32 dw_offset, u32 mask, u32 offset, u32 value)
+{
+ u32 *dw = (u32 *)ptr;
+ *(dw + dw_offset) &= ~(mask << offset);
+ *(dw + dw_offset) |= (mask & value) << offset;
+}
+
+#define AMAP_SET_BITS_PTR(_struct_, field, _structPtr_, val) \
+ amap_set(_structPtr_, AMAP_WORD_OFFSET(_struct_, field),\
+ AMAP_BIT_MASK(_struct_, field), \
+ AMAP_BIT_OFFSET(_struct_, field), val)
+/*
+ * Non-optimized routine that gets the bits without knowing the correct DWORD.
+ * e.g. fieldValue = AMAP_GET_BITS_PTR (struct, field1, &contextMemory);
+ */
+static inline u32
+amap_get(void *ptr, u32 dw_offset, u32 mask, u32 offset)
+{
+ u32 *dw = (u32 *)ptr;
+ return mask & (*(dw + dw_offset) >> offset);
+}
+#define AMAP_GET_BITS_PTR(_struct_, field, _structPtr_) \
+ amap_get(_structPtr_, AMAP_WORD_OFFSET(_struct_, field), \
+ AMAP_BIT_MASK(_struct_, field), \
+ AMAP_BIT_OFFSET(_struct_, field))
+
+/* Returns 0-31 representing bit offset within a DWORD of a bitfield. */
+#define AMAP_BIT_OFFSET(_struct_, field) \
+ (offsetof(struct BE_ ## _struct_ ## _AMAP, field) % 32)
+
+/* Returns 0-n representing DWORD offset of bitfield within the structure. */
+#define AMAP_WORD_OFFSET(_struct_, field) \
+ (offsetof(struct BE_ ## _struct_ ## _AMAP, field)/32)
+
+/* Returns size of bitfield in bits. */
+#define AMAP_BIT_SIZE(_struct_, field) \
+ sizeof(((struct BE_ ## _struct_ ## _AMAP*)0)->field)
+
+struct be_mcc_wrb_response_copy {
+ u16 length; /* bytes in response */
+ u16 fwcmd_offset; /* offset within the wrb of the response */
+ void *va; /* user's va to copy response into */
+
+} ;
+typedef void (*mcc_wrb_cqe_callback) (void *context, int status,
+ struct MCC_WRB_AMAP *optional_wrb);
+struct be_mcc_wrb_context {
+
+ mcc_wrb_cqe_callback internal_cb; /* Function to call on
+ completion */
+ void *internal_cb_context; /* Parameter to pass
+ to completion function */
+
+ mcc_wrb_cqe_callback cb; /* Function to call on completion */
+ void *cb_context; /* Parameter to pass to completion function */
+
+ int *users_final_status; /* pointer to a local
+ variable for synchronous
+ commands */
+ struct MCC_WRB_AMAP *wrb; /* pointer to original wrb for embedded
+ commands only */
+ struct list_head next; /* links context structs together in
+ free list */
+
+ struct be_mcc_wrb_response_copy copy; /* Optional parameters to copy
+ embedded response to user's va */
+
+#if defined(BE_DEBUG)
+ u16 subsystem, opcode; /* Track this FWCMD for debug builds. */
+ struct MCC_WRB_AMAP *ring_wrb;
+ u32 consumed_count;
+#endif
+} ;
+
+/*
+ Represents a function object for network or storage. This
+ is used to manage per-function resources like MCC CQs, etc.
+*/
+struct be_function_object {
+
+ u32 magic; /*!< magic for detecting memory corruption. */
+
+ /* PCI BAR mapped addresses */
+ u8 __iomem *csr_va; /* CSR */
+ u8 __iomem *db_va; /* Door Bell */
+ u8 __iomem *pci_va; /* PCI config space */
+ u32 emulate; /* if set, MPU is not available.
+ Emulate everything. */
+ u32 pend_queue_driving; /* if set, drive the queued WRBs
+ after releasing the WRB lock */
+
+ spinlock_t post_lock; /* lock for verifying one thread posting wrbs */
+ spinlock_t cq_lock; /* lock for verifying one thread
+ processing cq */
+ spinlock_t mcc_context_lock; /* lock for protecting mcc
+ context free list */
+ unsigned long post_irq;
+ unsigned long cq_irq;
+
+ u32 type;
+ u32 pci_function_number;
+
+ struct be_mcc_object *mcc; /* mcc rings. */
+
+ struct {
+ struct MCC_MAILBOX_AMAP *va; /* VA to the mailbox */
+ u64 pa; /* PA to the mailbox */
+ u32 length; /* byte length of mailbox */
+
+ /* One default context struct used for posting at
+ * least one MCC_WRB
+ */
+ struct be_mcc_wrb_context default_context;
+ bool default_context_allocated;
+ } mailbox;
+
+ struct {
+
+ /* Wake on lans configured. */
+ u32 wol_bitmask; /* bits 0,1,2,3 are set if
+ corresponding index is enabled */
+ } config;
+
+
+ struct BE_FIRMWARE_CONFIG fw_config;
+} ;
+
+/*
+ Represents an Event Queue
+*/
+struct be_eq_object {
+ u32 magic;
+ atomic_t ref_count;
+
+ struct be_function_object *parent_function;
+
+ struct list_head eq_list;
+ struct list_head cq_list_head;
+
+ u32 eq_id;
+ void *cb_context;
+
+} ;
+
+/*
+ Manages a completion queue
+*/
+struct be_cq_object {
+ u32 magic;
+ atomic_t ref_count;
+
+ struct be_function_object *parent_function;
+ struct be_eq_object *eq_object;
+
+ struct list_head cq_list;
+ struct list_head cqlist_for_eq;
+
+ void *va;
+ u32 num_entries;
+
+ void *cb_context;
+
+ u32 cq_id;
+
+} ;
+
+/*
+ Manages an ethernet send queue
+*/
+struct be_ethsq_object {
+ u32 magic;
+
+ struct list_head list;
+
+ struct be_function_object *parent_function;
+ struct be_cq_object *cq_object;
+ u32 bid;
+
+} ;
+
+/*
+@brief
+ Manages an ethernet receive queue
+*/
+struct be_ethrq_object {
+ u32 magic;
+ struct list_head list;
+ struct be_function_object *parent_function;
+ u32 rid;
+ struct be_cq_object *cq_object;
+ struct be_cq_object *rss_cq_object[4];
+
+} ;
+
+/*
+ Manages an MCC
+*/
+typedef void (*mcc_async_event_callback) (void *context, u32 event_code,
+ void *event);
+struct be_mcc_object {
+ u32 magic;
+
+ struct be_function_object *parent_function;
+ struct list_head mcc_list;
+
+ struct be_cq_object *cq_object;
+
+ /* Async event callback for MCC CQ. */
+ mcc_async_event_callback async_cb;
+ void *async_context;
+
+ struct {
+ struct be_mcc_wrb_context *base;
+ u32 num;
+ struct list_head list_head;
+ } wrb_context;
+
+ struct {
+ struct ring_desc *rd;
+ struct mp_ring ring;
+ } sq;
+
+ struct {
+ struct mp_ring ring;
+ } cq;
+
+ u32 processing; /* flag indicating that one thread
+ is processing CQ */
+ u32 rearm; /* doorbell rearm setting to make
+ sure the active processing thread */
+ /* rearms the CQ if any of the threads requested it. */
+
+ struct list_head backlog;
+ u32 backlog_length;
+ u32 driving_backlog;
+ u32 consumed_index;
+
+} ;
+
+
+/* Queue context header -- the required software information for
+ * queueing a WRB.
+ */
+struct be_queue_driver_context {
+ mcc_wrb_cqe_callback internal_cb; /* Function to call on
+ completion */
+ void *internal_cb_context; /* Parameter to pass
+ to completion function */
+
+ mcc_wrb_cqe_callback cb; /* Function to call on completion */
+ void *cb_context; /* Parameter to pass to completion function */
+
+ struct be_mcc_wrb_response_copy copy; /* Optional parameters to copy
+ embedded response to user's va */
+ void *optional_fwcmd_va;
+ struct list_head list;
+ u32 bytes;
+} ;
+
+/*
+ * Common MCC WRB header that all commands require.
+ */
+struct be_mcc_wrb_header {
+ u8 rsvd[offsetof(struct BE_MCC_WRB_AMAP, payload)/8];
+} ;
+
+/*
+ * All non embedded commands supported by hwlib functions only allow
+ * 1 SGE. This queue context handles them all.
+ */
+struct be_nonembedded_q_ctxt {
+ struct be_queue_driver_context context;
+ struct be_mcc_wrb_header wrb_header;
+ struct MCC_SGE_AMAP sge[1];
+} ;
+
+/*
+ * ------------------------------------------------------------------------
+ * This section contains the specific queue struct for each command.
+ * The user could always provide a be_generic_q_ctxt but this is a
+ * rather large struct. By using the specific struct, memory consumption
+ * can be reduced.
+ * ------------------------------------------------------------------------
+ */
+
+struct be_link_status_q_ctxt {
+ struct be_queue_driver_context context;
+ struct be_mcc_wrb_header wrb_header;
+ struct FWCMD_COMMON_NTWK_LINK_STATUS_QUERY fwcmd;
+} ;
+
+struct be_multicast_q_ctxt {
+ struct be_queue_driver_context context;
+ struct be_mcc_wrb_header wrb_header;
+ struct FWCMD_COMMON_NTWK_MULTICAST_SET fwcmd;
+} ;
+
+
+struct be_vlan_q_ctxt {
+ struct be_queue_driver_context context;
+ struct be_mcc_wrb_header wrb_header;
+ struct FWCMD_COMMON_NTWK_VLAN_CONFIG fwcmd;
+} ;
+
+struct be_promiscuous_q_ctxt {
+ struct be_queue_driver_context context;
+ struct be_mcc_wrb_header wrb_header;
+ struct FWCMD_ETH_PROMISCUOUS fwcmd;
+} ;
+
+struct be_force_failover_q_ctxt {
+ struct be_queue_driver_context context;
+ struct be_mcc_wrb_header wrb_header;
+ struct FWCMD_COMMON_FORCE_FAILOVER fwcmd;
+} ;
+
+
+struct be_rxf_filter_q_ctxt {
+ struct be_queue_driver_context context;
+ struct be_mcc_wrb_header wrb_header;
+ struct FWCMD_COMMON_NTWK_RX_FILTER fwcmd;
+} ;
+
+struct be_eq_modify_delay_q_ctxt {
+ struct be_queue_driver_context context;
+ struct be_mcc_wrb_header wrb_header;
+ struct FWCMD_COMMON_MODIFY_EQ_DELAY fwcmd;
+} ;
+
+/*
+ * The generic context is the largest size that would be required.
+ * It is the software context plus an entire WRB.
+ */
+struct be_generic_q_ctxt {
+ struct be_queue_driver_context context;
+ struct be_mcc_wrb_header wrb_header;
+ struct MCC_WRB_PAYLOAD_AMAP payload;
+} ;
+
+/*
+ * Types for the BE_QUEUE_CONTEXT object.
+ */
+#define BE_QUEUE_INVALID (0)
+#define BE_QUEUE_LINK_STATUS (0xA006)
+#define BE_QUEUE_ETH_STATS (0xA007)
+#define BE_QUEUE_TPM_STATS (0xA008)
+#define BE_QUEUE_TCP_STATS (0xA009)
+#define BE_QUEUE_MULTICAST (0xA00A)
+#define BE_QUEUE_VLAN (0xA00B)
+#define BE_QUEUE_RSS (0xA00C)
+#define BE_QUEUE_FORCE_FAILOVER (0xA00D)
+#define BE_QUEUE_PROMISCUOUS (0xA00E)
+#define BE_QUEUE_WAKE_ON_LAN (0xA00F)
+#define BE_QUEUE_NOP (0xA010)
+
+/* --- BE_FUNCTION_ENUM --- */
+#define BE_FUNCTION_TYPE_ISCSI (0)
+#define BE_FUNCTION_TYPE_NETWORK (1)
+#define BE_FUNCTION_TYPE_ARM (2)
+
+/* --- BE_ETH_TX_RING_TYPE_ENUM --- */
+#define BE_ETH_TX_RING_TYPE_FORWARDING (1) /* Ether ring for forwarding */
+#define BE_ETH_TX_RING_TYPE_STANDARD (2) /* Ether ring for sending */
+ /* network packets. */
+#define BE_ETH_TX_RING_TYPE_BOUND (3) /* Ethernet ring for sending */
+ /* network packets, bound */
+ /* to a physical port. */
+/*
+ * ----------------------------------------------------------------------
+ * API MACROS
+ * ----------------------------------------------------------------------
+ */
+#define BE_FWCMD_NAME(_short_name_) struct FWCMD_##_short_name_
+#define BE_OPCODE_NAME(_short_name_) OPCODE_##_short_name_
+#define BE_SUBSYSTEM_NAME(_short_name_) SUBSYSTEM_##_short_name_
+
+
+#define BE_PREPARE_EMBEDDED_FWCMD(_pfob_, _wrb_, _short_name_) \
+ ((BE_FWCMD_NAME(_short_name_) *) \
+ be_function_prepare_embedded_fwcmd(_pfob_, _wrb_, \
+ sizeof(BE_FWCMD_NAME(_short_name_)), \
+ FIELD_SIZEOF(BE_FWCMD_NAME(_short_name_), params.request), \
+ FIELD_SIZEOF(BE_FWCMD_NAME(_short_name_), params.response), \
+ BE_OPCODE_NAME(_short_name_), \
+ BE_SUBSYSTEM_NAME(_short_name_)));
+
+#define BE_PREPARE_NONEMBEDDED_FWCMD(_pfob_, _wrb_, _iva_, _ipa_, _short_name_)\
+ ((BE_FWCMD_NAME(_short_name_) *) \
+ be_function_prepare_nonembedded_fwcmd(_pfob_, _wrb_, (_iva_), (_ipa_), \
+ sizeof(BE_FWCMD_NAME(_short_name_)), \
+ FIELD_SIZEOF(BE_FWCMD_NAME(_short_name_), params.request), \
+ FIELD_SIZEOF(BE_FWCMD_NAME(_short_name_), params.response), \
+ BE_OPCODE_NAME(_short_name_), \
+ BE_SUBSYSTEM_NAME(_short_name_)));
+
+int be_function_object_create(u8 __iomem *csr_va, u8 __iomem *db_va,
+ u8 __iomem *pci_va, u32 function_type, struct ring_desc *mailbox_rd,
+ struct be_function_object *pfob);
+
+int be_function_object_destroy(struct be_function_object *pfob);
+int be_function_cleanup(struct be_function_object *pfob);
+
+
+int be_function_get_fw_version(struct be_function_object *pfob,
+ struct FWCMD_COMMON_GET_FW_VERSION_RESPONSE_PAYLOAD *fw_version,
+ mcc_wrb_cqe_callback cb, void *cb_context);
+
+
+int be_eq_modify_delay(struct be_function_object *pfob,
+ u32 num_eq, struct be_eq_object **eq_array,
+ u32 *eq_delay_array, mcc_wrb_cqe_callback cb,
+ void *cb_context,
+ struct be_eq_modify_delay_q_ctxt *q_ctxt);
+
+
+
+int be_eq_create(struct be_function_object *pfob,
+ struct ring_desc *rd, u32 eqe_size, u32 num_entries,
+ u32 watermark, u32 timer_delay, struct be_eq_object *eq_object);
+
+int be_eq_destroy(struct be_eq_object *eq);
+
+int be_cq_create(struct be_function_object *pfob,
+ struct ring_desc *rd, u32 length,
+ bool solicited_eventable, bool no_delay,
+ u32 wm_thresh, struct be_eq_object *eq_object,
+ struct be_cq_object *cq_object);
+
+int be_cq_destroy(struct be_cq_object *cq);
+
+int be_mcc_ring_create(struct be_function_object *pfob,
+ struct ring_desc *rd, u32 length,
+ struct be_mcc_wrb_context *context_array,
+ u32 num_context_entries,
+ struct be_cq_object *cq, struct be_mcc_object *mcc);
+int be_mcc_ring_destroy(struct be_mcc_object *mcc_object);
+
+int be_mcc_process_cq(struct be_mcc_object *mcc_object, bool rearm);
+
+int be_mcc_add_async_event_callback(struct be_mcc_object *mcc_object,
+ mcc_async_event_callback cb, void *cb_context);
+
+int be_pci_soft_reset(struct be_function_object *pfob);
+
+
+int be_drive_POST(struct be_function_object *pfob);
+
+
+int be_eth_sq_create(struct be_function_object *pfob,
+ struct ring_desc *rd, u32 length_in_bytes,
+ u32 type, u32 ulp, struct be_cq_object *cq_object,
+ struct be_ethsq_object *eth_sq);
+
+struct be_eth_sq_parameters {
+ u32 port;
+ u32 rsvd0[2];
+} ;
+
+int be_eth_sq_create_ex(struct be_function_object *pfob,
+ struct ring_desc *rd, u32 length_in_bytes,
+ u32 type, u32 ulp, struct be_cq_object *cq_object,
+ struct be_eth_sq_parameters *ex_parameters,
+ struct be_ethsq_object *eth_sq);
+int be_eth_sq_destroy(struct be_ethsq_object *eth_sq);
+
+int be_eth_set_flow_control(struct be_function_object *pfob,
+ bool txfc_enable, bool rxfc_enable);
+
+int be_eth_get_flow_control(struct be_function_object *pfob,
+ bool *txfc_enable, bool *rxfc_enable);
+int be_eth_set_qos(struct be_function_object *pfob, u32 max_bps, u32 max_pps);
+
+int be_eth_get_qos(struct be_function_object *pfob, u32 *max_bps, u32 *max_pps);
+
+int be_eth_set_frame_size(struct be_function_object *pfob,
+ u32 *tx_frame_size, u32 *rx_frame_size);
+
+int be_eth_rq_create(struct be_function_object *pfob,
+ struct ring_desc *rd, struct be_cq_object *cq_object,
+ struct be_cq_object *bcmc_cq_object,
+ struct be_ethrq_object *eth_rq);
+
+int be_eth_rq_destroy(struct be_ethrq_object *eth_rq);
+
+int be_eth_rq_destroy_options(struct be_ethrq_object *eth_rq, bool flush,
+ mcc_wrb_cqe_callback cb, void *cb_context);
+int be_eth_rq_set_frag_size(struct be_function_object *pfob,
+ u32 new_frag_size_bytes, u32 *actual_frag_size_bytes);
+int be_eth_rq_get_frag_size(struct be_function_object *pfob,
+ u32 *frag_size_bytes);
+
+void *be_function_prepare_embedded_fwcmd(struct be_function_object *pfob,
+ struct MCC_WRB_AMAP *wrb,
+ u32 payload_length, u32 request_length,
+ u32 response_length, u32 opcode, u32 subsystem);
+void *be_function_prepare_nonembedded_fwcmd(struct be_function_object *pfob,
+ struct MCC_WRB_AMAP *wrb, void *fwcmd_header_va, u64 fwcmd_header_pa,
+ u32 payload_length, u32 request_length, u32 response_length,
+ u32 opcode, u32 subsystem);
+
+
+struct MCC_WRB_AMAP *
+be_function_peek_mcc_wrb(struct be_function_object *pfob);
+
+int be_rxf_mac_address_read_write(struct be_function_object *pfob,
+ bool port1, bool mac1, bool mgmt,
+ bool write, bool permanent, u8 *mac_address,
+ mcc_wrb_cqe_callback cb,
+ void *cb_context);
+
+int be_rxf_multicast_config(struct be_function_object *pfob,
+ bool promiscuous, u32 num, u8 *mac_table,
+ mcc_wrb_cqe_callback cb,
+ void *cb_context,
+ struct be_multicast_q_ctxt *q_ctxt);
+
+int be_rxf_vlan_config(struct be_function_object *pfob,
+ bool promiscuous, u32 num, u16 *vlan_tag_array,
+ mcc_wrb_cqe_callback cb, void *cb_context,
+ struct be_vlan_q_ctxt *q_ctxt);
+
+
+int be_rxf_link_status(struct be_function_object *pfob,
+ struct BE_LINK_STATUS *link_status,
+ mcc_wrb_cqe_callback cb,
+ void *cb_context,
+ struct be_link_status_q_ctxt *q_ctxt);
+
+
+int be_rxf_query_eth_statistics(struct be_function_object *pfob,
+ struct FWCMD_ETH_GET_STATISTICS *va_for_fwcmd,
+ u64 pa_for_fwcmd, mcc_wrb_cqe_callback cb,
+ void *cb_context,
+ struct be_nonembedded_q_ctxt *q_ctxt);
+
+int be_rxf_promiscuous(struct be_function_object *pfob,
+ bool enable_port0, bool enable_port1,
+ mcc_wrb_cqe_callback cb, void *cb_context,
+ struct be_promiscuous_q_ctxt *q_ctxt);
+
+
+int be_rxf_filter_config(struct be_function_object *pfob,
+ struct NTWK_RX_FILTER_SETTINGS *settings,
+ mcc_wrb_cqe_callback cb,
+ void *cb_context,
+ struct be_rxf_filter_q_ctxt *q_ctxt);
+
+/*
+ * ------------------------------------------------------
+ * internal functions used by hwlib
+ * ------------------------------------------------------
+ */
+
+
+int be_function_ring_destroy(struct be_function_object *pfob,
+ u32 id, u32 ring_type, mcc_wrb_cqe_callback cb,
+ void *cb_context,
+ mcc_wrb_cqe_callback internal_cb,
+ void *internal_callback_context);
+
+int be_function_post_mcc_wrb(struct be_function_object *pfob,
+ struct MCC_WRB_AMAP *wrb,
+ struct be_generic_q_ctxt *q_ctxt,
+ mcc_wrb_cqe_callback cb, void *cb_context,
+ mcc_wrb_cqe_callback internal_cb,
+ void *internal_cb_context, void *optional_fwcmd_va,
+ struct be_mcc_wrb_response_copy *response_copy);
+
+int be_function_queue_mcc_wrb(struct be_function_object *pfob,
+ struct be_generic_q_ctxt *q_ctxt);
+
+/*
+ * ------------------------------------------------------
+ * MCC QUEUE
+ * ------------------------------------------------------
+ */
+
+int be_mpu_init_mailbox(struct be_function_object *pfob, struct ring_desc *rd);
+
+
+struct MCC_WRB_AMAP *
+_be_mpu_peek_ring_wrb(struct be_mcc_object *mcc, bool driving_queue);
+
+struct be_mcc_wrb_context *
+_be_mcc_allocate_wrb_context(struct be_function_object *pfob);
+
+void _be_mcc_free_wrb_context(struct be_function_object *pfob,
+ struct be_mcc_wrb_context *context);
+
+int _be_mpu_post_wrb_mailbox(struct be_function_object *pfob,
+ struct MCC_WRB_AMAP *wrb, struct be_mcc_wrb_context *wrb_context);
+
+int _be_mpu_post_wrb_ring(struct be_mcc_object *mcc,
+ struct MCC_WRB_AMAP *wrb, struct be_mcc_wrb_context *wrb_context);
+
+void be_drive_mcc_wrb_queue(struct be_mcc_object *mcc);
+
+
+/*
+ * ------------------------------------------------------
+ * Ring Sizes
+ * ------------------------------------------------------
+ */
+static inline u32 be_ring_encoding_to_length(u32 encoding, u32 object_size)
+{
+
+ ASSERT(encoding != 1); /* 1 is rsvd */
+ ASSERT(encoding < 16);
+ ASSERT(object_size > 0);
+
+ if (encoding == 0) /* 32k deep */
+ encoding = 16;
+
+ return (1 << (encoding - 1)) * object_size;
+}
+
+static inline
+u32 be_ring_length_to_encoding(u32 length_in_bytes, u32 object_size)
+{
+
+ u32 count, encoding;
+
+ ASSERT(object_size > 0);
+ ASSERT(length_in_bytes % object_size == 0);
+
+ count = length_in_bytes / object_size;
+
+ ASSERT(count > 1);
+ ASSERT(count <= 32 * 1024);
+ ASSERT(length_in_bytes <= 8 * PAGE_SIZE); /* max ring size in UT */
+
+ encoding = __ilog2_u32(count) + 1;
+
+ if (encoding == 16)
+ encoding = 0; /* 32k deep */
+
+ return encoding;
+}
+
+void be_rd_to_pa_list(struct ring_desc *rd, struct PHYS_ADDR *pa_list,
+ u32 max_num);
+#endif /* __hwlib_h__ */
diff --git a/drivers/staging/benet/mpu.c b/drivers/staging/benet/mpu.c
new file mode 100644
index 000000000000..269cc11d3055
--- /dev/null
+++ b/drivers/staging/benet/mpu.c
@@ -0,0 +1,1364 @@
+/*
+ * 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:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+#include <linux/delay.h>
+#include "hwlib.h"
+#include "bestatus.h"
+
+static
+inline void mp_ring_create(struct mp_ring *ring, u32 num, u32 size, void *va)
+{
+ ASSERT(ring);
+ memset(ring, 0, sizeof(struct mp_ring));
+ ring->num = num;
+ ring->pages = DIV_ROUND_UP(num * size, PAGE_SIZE);
+ ring->itemSize = size;
+ ring->va = va;
+}
+
+/*
+ * -----------------------------------------------------------------------
+ * Interface for 2 index rings. i.e. consumer/producer rings
+ * --------------------------------------------------------------------------
+ */
+
+/* Returns number items pending on ring. */
+static inline u32 mp_ring_num_pending(struct mp_ring *ring)
+{
+ ASSERT(ring);
+ if (ring->num == 0)
+ return 0;
+ return be_subc(ring->pidx, ring->cidx, ring->num);
+}
+
+/* Returns number items free on ring. */
+static inline u32 mp_ring_num_empty(struct mp_ring *ring)
+{
+ ASSERT(ring);
+ return ring->num - 1 - mp_ring_num_pending(ring);
+}
+
+/* Consume 1 item */
+static inline void mp_ring_consume(struct mp_ring *ring)
+{
+ ASSERT(ring);
+ ASSERT(ring->pidx != ring->cidx);
+
+ ring->cidx = be_addc(ring->cidx, 1, ring->num);
+}
+
+/* Produce 1 item */
+static inline void mp_ring_produce(struct mp_ring *ring)
+{
+ ASSERT(ring);
+ ring->pidx = be_addc(ring->pidx, 1, ring->num);
+}
+
+/* Consume count items */
+static inline void mp_ring_consume_multiple(struct mp_ring *ring, u32 count)
+{
+ ASSERT(ring);
+ ASSERT(mp_ring_num_pending(ring) >= count);
+ ring->cidx = be_addc(ring->cidx, count, ring->num);
+}
+
+static inline void *mp_ring_item(struct mp_ring *ring, u32 index)
+{
+ ASSERT(ring);
+ ASSERT(index < ring->num);
+ ASSERT(ring->itemSize > 0);
+ return (u8 *) ring->va + index * ring->itemSize;
+}
+
+/* Ptr to produce item */
+static inline void *mp_ring_producer_ptr(struct mp_ring *ring)
+{
+ ASSERT(ring);
+ return mp_ring_item(ring, ring->pidx);
+}
+
+/*
+ * Returns a pointer to the current location in the ring.
+ * This is used for rings with 1 index.
+ */
+static inline void *mp_ring_current(struct mp_ring *ring)
+{
+ ASSERT(ring);
+ ASSERT(ring->pidx == 0); /* not used */
+
+ return mp_ring_item(ring, ring->cidx);
+}
+
+/*
+ * Increment index for rings with only 1 index.
+ * This is used for rings with 1 index.
+ */
+static inline void *mp_ring_next(struct mp_ring *ring)
+{
+ ASSERT(ring);
+ ASSERT(ring->num > 0);
+ ASSERT(ring->pidx == 0); /* not used */
+
+ ring->cidx = be_addc(ring->cidx, 1, ring->num);
+ return mp_ring_current(ring);
+}
+
+/*
+ This routine waits for a previously posted mailbox WRB to be completed.
+ Specifically it waits for the mailbox to say that it's ready to accept
+ more data by setting the LSB of the mailbox pd register to 1.
+
+ pcontroller - The function object to post this data to
+
+ IRQL < DISPATCH_LEVEL
+*/
+static void be_mcc_mailbox_wait(struct be_function_object *pfob)
+{
+ struct MPU_MAILBOX_DB_AMAP mailbox_db;
+ u32 i = 0;
+ u32 ready;
+
+ if (pfob->emulate) {
+ /* No waiting for mailbox in emulated mode. */
+ return;
+ }
+
+ mailbox_db.dw[0] = PD_READ(pfob, mcc_bootstrap_db);
+ ready = AMAP_GET_BITS_PTR(MPU_MAILBOX_DB, ready, &mailbox_db);
+
+ while (ready == false) {
+ if ((++i & 0x3FFFF) == 0) {
+ TRACE(DL_WARN, "Waiting for mailbox ready - %dk polls",
+ i / 1000);
+ }
+ udelay(1);
+ mailbox_db.dw[0] = PD_READ(pfob, mcc_bootstrap_db);
+ ready = AMAP_GET_BITS_PTR(MPU_MAILBOX_DB, ready, &mailbox_db);
+ }
+}
+
+/*
+ This routine tells the MCC mailbox that there is data to processed
+ in the mailbox. It does this by setting the physical address for the
+ mailbox location and clearing the LSB. This routine returns immediately
+ and does not wait for the WRB to be processed.
+
+ pcontroller - The function object to post this data to
+
+ IRQL < DISPATCH_LEVEL
+
+*/
+static void be_mcc_mailbox_notify(struct be_function_object *pfob)
+{
+ struct MPU_MAILBOX_DB_AMAP mailbox_db;
+ u32 pa;
+
+ ASSERT(pfob->mailbox.pa);
+ ASSERT(pfob->mailbox.va);
+
+ /* If emulated, do not ring the mailbox */
+ if (pfob->emulate) {
+ TRACE(DL_WARN, "MPU disabled. Skipping mailbox notify.");
+ return;
+ }
+
+ /* form the higher bits in the address */
+ mailbox_db.dw[0] = 0; /* init */
+ AMAP_SET_BITS_PTR(MPU_MAILBOX_DB, hi, &mailbox_db, 1);
+ AMAP_SET_BITS_PTR(MPU_MAILBOX_DB, ready, &mailbox_db, 0);
+
+ /* bits 34 to 63 */
+ pa = (u32) (pfob->mailbox.pa >> 34);
+ AMAP_SET_BITS_PTR(MPU_MAILBOX_DB, address, &mailbox_db, pa);
+
+ /* Wait for the MPU to be ready */
+ be_mcc_mailbox_wait(pfob);
+
+ /* Ring doorbell 1st time */
+ PD_WRITE(pfob, mcc_bootstrap_db, mailbox_db.dw[0]);
+
+ /* Wait for 1st write to be acknowledged. */
+ be_mcc_mailbox_wait(pfob);
+
+ /* lower bits 30 bits from 4th bit (bits 4 to 33)*/
+ pa = (u32) (pfob->mailbox.pa >> 4) & 0x3FFFFFFF;
+
+ AMAP_SET_BITS_PTR(MPU_MAILBOX_DB, hi, &mailbox_db, 0);
+ AMAP_SET_BITS_PTR(MPU_MAILBOX_DB, ready, &mailbox_db, 0);
+ AMAP_SET_BITS_PTR(MPU_MAILBOX_DB, address, &mailbox_db, pa);
+
+ /* Ring doorbell 2nd time */
+ PD_WRITE(pfob, mcc_bootstrap_db, mailbox_db.dw[0]);
+}
+
+/*
+ This routine tells the MCC mailbox that there is data to processed
+ in the mailbox. It does this by setting the physical address for the
+ mailbox location and clearing the LSB. This routine spins until the
+ MPU writes a 1 into the LSB indicating that the data has been received
+ and is ready to be processed.
+
+ pcontroller - The function object to post this data to
+
+ IRQL < DISPATCH_LEVEL
+*/
+static void
+be_mcc_mailbox_notify_and_wait(struct be_function_object *pfob)
+{
+ /*
+ * Notify it
+ */
+ be_mcc_mailbox_notify(pfob);
+ /*
+ * Now wait for completion of WRB
+ */
+ be_mcc_mailbox_wait(pfob);
+}
+
+void
+be_mcc_process_cqe(struct be_function_object *pfob,
+ struct MCC_CQ_ENTRY_AMAP *cqe)
+{
+ struct be_mcc_wrb_context *wrb_context = NULL;
+ u32 offset, status;
+ u8 *p;
+
+ ASSERT(cqe);
+ /*
+ * A command completed. Commands complete out-of-order.
+ * Determine which command completed from the TAG.
+ */
+ offset = offsetof(struct BE_MCC_CQ_ENTRY_AMAP, mcc_tag)/8;
+ p = (u8 *) cqe + offset;
+ wrb_context = (struct be_mcc_wrb_context *)(void *)(size_t)(*(u64 *)p);
+ ASSERT(wrb_context);
+
+ /*
+ * Perform a response copy if requested.
+ * Only copy data if the FWCMD is successful.
+ */
+ status = AMAP_GET_BITS_PTR(MCC_CQ_ENTRY, completion_status, cqe);
+ if (status == MGMT_STATUS_SUCCESS && wrb_context->copy.length > 0) {
+ ASSERT(wrb_context->wrb);
+ ASSERT(wrb_context->copy.va);
+ p = (u8 *)wrb_context->wrb +
+ offsetof(struct BE_MCC_WRB_AMAP, payload)/8;
+ memcpy(wrb_context->copy.va,
+ (u8 *)p + wrb_context->copy.fwcmd_offset,
+ wrb_context->copy.length);
+ }
+
+ if (status)
+ status = BE_NOT_OK;
+ /* internal callback */
+ if (wrb_context->internal_cb) {
+ wrb_context->internal_cb(wrb_context->internal_cb_context,
+ status, wrb_context->wrb);
+ }
+
+ /* callback */
+ if (wrb_context->cb) {
+ wrb_context->cb(wrb_context->cb_context,
+ status, wrb_context->wrb);
+ }
+ /* Free the context structure */
+ _be_mcc_free_wrb_context(pfob, wrb_context);
+}
+
+void be_drive_mcc_wrb_queue(struct be_mcc_object *mcc)
+{
+ struct be_function_object *pfob = NULL;
+ int status = BE_PENDING;
+ struct be_generic_q_ctxt *q_ctxt;
+ struct MCC_WRB_AMAP *wrb;
+ struct MCC_WRB_AMAP *queue_wrb;
+ u32 length, payload_length, sge_count, embedded;
+ unsigned long irql;
+
+ BUILD_BUG_ON((sizeof(struct be_generic_q_ctxt) <
+ sizeof(struct be_queue_driver_context) +
+ sizeof(struct MCC_WRB_AMAP)));
+ pfob = mcc->parent_function;
+
+ spin_lock_irqsave(&pfob->post_lock, irql);
+
+ if (mcc->driving_backlog) {
+ spin_unlock_irqrestore(&pfob->post_lock, irql);
+ if (pfob->pend_queue_driving && pfob->mcc) {
+ pfob->pend_queue_driving = 0;
+ be_drive_mcc_wrb_queue(pfob->mcc);
+ }
+ return;
+ }
+ /* Acquire the flag to limit 1 thread to redrive posts. */
+ mcc->driving_backlog = 1;
+
+ while (!list_empty(&mcc->backlog)) {
+ wrb = _be_mpu_peek_ring_wrb(mcc, true); /* Driving the queue */
+ if (!wrb)
+ break; /* No space in the ring yet. */
+ /* Get the next queued entry to process. */
+ q_ctxt = list_first_entry(&mcc->backlog,
+ struct be_generic_q_ctxt, context.list);
+ list_del(&q_ctxt->context.list);
+ pfob->mcc->backlog_length--;
+ /*
+ * Compute the required length of the WRB.
+ * Since the queue element may be smaller than
+ * the complete WRB, copy only the required number of bytes.
+ */
+ queue_wrb = (struct MCC_WRB_AMAP *) &q_ctxt->wrb_header;
+ embedded = AMAP_GET_BITS_PTR(MCC_WRB, embedded, queue_wrb);
+ if (embedded) {
+ payload_length = AMAP_GET_BITS_PTR(MCC_WRB,
+ payload_length, queue_wrb);
+ length = sizeof(struct be_mcc_wrb_header) +
+ payload_length;
+ } else {
+ sge_count = AMAP_GET_BITS_PTR(MCC_WRB, sge_count,
+ queue_wrb);
+ ASSERT(sge_count == 1); /* only 1 frag. */
+ length = sizeof(struct be_mcc_wrb_header) +
+ sge_count * sizeof(struct MCC_SGE_AMAP);
+ }
+
+ /*
+ * Truncate the length based on the size of the
+ * queue element. Some elements that have output parameters
+ * can be smaller than the payload_length field would
+ * indicate. We really only need to copy the request
+ * parameters, not the response.
+ */
+ length = min(length, (u32) (q_ctxt->context.bytes -
+ offsetof(struct be_generic_q_ctxt, wrb_header)));
+
+ /* Copy the queue element WRB into the ring. */
+ memcpy(wrb, &q_ctxt->wrb_header, length);
+
+ /* Post the wrb. This should not fail assuming we have
+ * enough context structs. */
+ status = be_function_post_mcc_wrb(pfob, wrb, NULL,
+ q_ctxt->context.cb, q_ctxt->context.cb_context,
+ q_ctxt->context.internal_cb,
+ q_ctxt->context.internal_cb_context,
+ q_ctxt->context.optional_fwcmd_va,
+ &q_ctxt->context.copy);
+
+ if (status == BE_SUCCESS) {
+ /*
+ * Synchronous completion. Since it was queued,
+ * we will invoke the callback.
+ * To the user, this is an asynchronous request.
+ */
+ spin_unlock_irqrestore(&pfob->post_lock, irql);
+ if (pfob->pend_queue_driving && pfob->mcc) {
+ pfob->pend_queue_driving = 0;
+ be_drive_mcc_wrb_queue(pfob->mcc);
+ }
+
+ ASSERT(q_ctxt->context.cb);
+
+ q_ctxt->context.cb(
+ q_ctxt->context.cb_context,
+ BE_SUCCESS, NULL);
+
+ spin_lock_irqsave(&pfob->post_lock, irql);
+
+ } else if (status != BE_PENDING) {
+ /*
+ * Another resource failed. Should never happen
+ * if we have sufficient MCC_WRB_CONTEXT structs.
+ * Return to head of the queue.
+ */
+ TRACE(DL_WARN, "Failed to post a queued WRB. 0x%x",
+ status);
+ list_add(&q_ctxt->context.list, &mcc->backlog);
+ pfob->mcc->backlog_length++;
+ break;
+ }
+ }
+
+ /* Free the flag to limit 1 thread to redrive posts. */
+ mcc->driving_backlog = 0;
+ spin_unlock_irqrestore(&pfob->post_lock, irql);
+}
+
+/* This function asserts that the WRB was consumed in order. */
+#ifdef BE_DEBUG
+u32 be_mcc_wrb_consumed_in_order(struct be_mcc_object *mcc,
+ struct MCC_CQ_ENTRY_AMAP *cqe)
+{
+ struct be_mcc_wrb_context *wrb_context = NULL;
+ u32 wrb_index;
+ u32 wrb_consumed_in_order;
+ u32 offset;
+ u8 *p;
+
+ ASSERT(cqe);
+ /*
+ * A command completed. Commands complete out-of-order.
+ * Determine which command completed from the TAG.
+ */
+ offset = offsetof(struct BE_MCC_CQ_ENTRY_AMAP, mcc_tag)/8;
+ p = (u8 *) cqe + offset;
+ wrb_context = (struct be_mcc_wrb_context *)(void *)(size_t)(*(u64 *)p);
+
+ ASSERT(wrb_context);
+
+ wrb_index = (u32) (((u64)(size_t)wrb_context->ring_wrb -
+ (u64)(size_t)mcc->sq.ring.va) / sizeof(struct MCC_WRB_AMAP));
+
+ ASSERT(wrb_index < mcc->sq.ring.num);
+
+ wrb_consumed_in_order = (u32) (wrb_index == mcc->consumed_index);
+ mcc->consumed_index = be_addc(mcc->consumed_index, 1, mcc->sq.ring.num);
+ return wrb_consumed_in_order;
+}
+#endif
+
+int be_mcc_process_cq(struct be_mcc_object *mcc, bool rearm)
+{
+ struct be_function_object *pfob = NULL;
+ struct MCC_CQ_ENTRY_AMAP *cqe;
+ struct CQ_DB_AMAP db;
+ struct mp_ring *cq_ring = &mcc->cq.ring;
+ struct mp_ring *mp_ring = &mcc->sq.ring;
+ u32 num_processed = 0;
+ u32 consumed = 0, valid, completed, cqe_consumed, async_event;
+
+ pfob = mcc->parent_function;
+
+ spin_lock_irqsave(&pfob->cq_lock, pfob->cq_irq);
+
+ /*
+ * Verify that only one thread is processing the CQ at once.
+ * We cannot hold the lock while processing the CQ due to
+ * the callbacks into the OS. Therefore, this flag is used
+ * to control it. If any of the threads want to
+ * rearm the CQ, we need to honor that.
+ */
+ if (mcc->processing != 0) {
+ mcc->rearm = mcc->rearm || rearm;
+ goto Error;
+ } else {
+ mcc->processing = 1; /* lock processing for this thread. */
+ mcc->rearm = rearm; /* set our rearm setting */
+ }
+
+ spin_unlock_irqrestore(&pfob->cq_lock, pfob->cq_irq);
+
+ cqe = mp_ring_current(cq_ring);
+ valid = AMAP_GET_BITS_PTR(MCC_CQ_ENTRY, valid, cqe);
+ while (valid) {
+
+ if (num_processed >= 8) {
+ /* coalesce doorbells, but free space in cq
+ * ring while processing. */
+ db.dw[0] = 0; /* clear */
+ AMAP_SET_BITS_PTR(CQ_DB, qid, &db, cq_ring->id);
+ AMAP_SET_BITS_PTR(CQ_DB, rearm, &db, false);
+ AMAP_SET_BITS_PTR(CQ_DB, event, &db, false);
+ AMAP_SET_BITS_PTR(CQ_DB, num_popped, &db,
+ num_processed);
+ num_processed = 0;
+
+ PD_WRITE(pfob, cq_db, db.dw[0]);
+ }
+
+ async_event = AMAP_GET_BITS_PTR(MCC_CQ_ENTRY, async_event, cqe);
+ if (async_event) {
+ /* This is an asynchronous event. */
+ struct ASYNC_EVENT_TRAILER_AMAP *async_trailer =
+ (struct ASYNC_EVENT_TRAILER_AMAP *)
+ ((u8 *) cqe + sizeof(struct MCC_CQ_ENTRY_AMAP) -
+ sizeof(struct ASYNC_EVENT_TRAILER_AMAP));
+ u32 event_code;
+ async_event = AMAP_GET_BITS_PTR(ASYNC_EVENT_TRAILER,
+ async_event, async_trailer);
+ ASSERT(async_event == 1);
+
+
+ valid = AMAP_GET_BITS_PTR(ASYNC_EVENT_TRAILER,
+ valid, async_trailer);
+ ASSERT(valid == 1);
+
+ /* Call the async event handler if it is installed. */
+ if (mcc->async_cb) {
+ event_code =
+ AMAP_GET_BITS_PTR(ASYNC_EVENT_TRAILER,
+ event_code, async_trailer);
+ mcc->async_cb(mcc->async_context,
+ (u32) event_code, (void *) cqe);
+ }
+
+ } else {
+ /* This is a completion entry. */
+
+ /* No vm forwarding in this driver. */
+
+ cqe_consumed = AMAP_GET_BITS_PTR(MCC_CQ_ENTRY,
+ consumed, cqe);
+ if (cqe_consumed) {
+ /*
+ * A command on the MCC ring was consumed.
+ * Update the consumer index.
+ * These occur in order.
+ */
+ ASSERT(be_mcc_wrb_consumed_in_order(mcc, cqe));
+ consumed++;
+ }
+
+ completed = AMAP_GET_BITS_PTR(MCC_CQ_ENTRY,
+ completed, cqe);
+ if (completed) {
+ /* A command completed. Use tag to
+ * determine which command. */
+ be_mcc_process_cqe(pfob, cqe);
+ }
+ }
+
+ /* Reset the CQE */
+ AMAP_SET_BITS_PTR(MCC_CQ_ENTRY, valid, cqe, false);
+ num_processed++;
+
+ /* Update our tracking for the CQ ring. */
+ cqe = mp_ring_next(cq_ring);
+ valid = AMAP_GET_BITS_PTR(MCC_CQ_ENTRY, valid, cqe);
+ }
+
+ TRACE(DL_INFO, "num_processed:0x%x, and consumed:0x%x",
+ num_processed, consumed);
+ /*
+ * Grab the CQ lock to synchronize the "rearm" setting for
+ * the doorbell, and for clearing the "processing" flag.
+ */
+ spin_lock_irqsave(&pfob->cq_lock, pfob->cq_irq);
+
+ /*
+ * Rearm the cq. This is done based on the global mcc->rearm
+ * flag which combines the rearm parameter from the current
+ * call to process_cq and any other threads
+ * that tried to process the CQ while this one was active.
+ * This handles the situation where a sync. fwcmd was processing
+ * the CQ while the interrupt/dpc tries to process it.
+ * The sync process gets to continue -- but it is now
+ * responsible for the rearming.
+ */
+ if (num_processed > 0 || mcc->rearm == true) {
+ db.dw[0] = 0; /* clear */
+ AMAP_SET_BITS_PTR(CQ_DB, qid, &db, cq_ring->id);
+ AMAP_SET_BITS_PTR(CQ_DB, rearm, &db, mcc->rearm);
+ AMAP_SET_BITS_PTR(CQ_DB, event, &db, false);
+ AMAP_SET_BITS_PTR(CQ_DB, num_popped, &db, num_processed);
+
+ PD_WRITE(pfob, cq_db, db.dw[0]);
+ }
+ /*
+ * Update the consumer index after ringing the CQ doorbell.
+ * We don't want another thread to post more WRBs before we
+ * have CQ space available.
+ */
+ mp_ring_consume_multiple(mp_ring, consumed);
+
+ /* Clear the processing flag. */
+ mcc->processing = 0;
+
+Error:
+ spin_unlock_irqrestore(&pfob->cq_lock, pfob->cq_irq);
+ /*
+ * Use the local variable to detect if the current thread
+ * holds the WRB post lock. If rearm is false, this is
+ * either a synchronous command, or the upper layer driver is polling
+ * from a thread. We do not drive the queue from that
+ * context since the driver may hold the
+ * wrb post lock already.
+ */
+ if (rearm)
+ be_drive_mcc_wrb_queue(mcc);
+ else
+ pfob->pend_queue_driving = 1;
+
+ return BE_SUCCESS;
+}
+
+/*
+ *============================================================================
+ * P U B L I C R O U T I N E S
+ *============================================================================
+ */
+
+/*
+ This routine creates an MCC object. This object contains an MCC send queue
+ and a CQ private to the MCC.
+
+ pcontroller - Handle to a function object
+
+ EqObject - EQ object that will be used to dispatch this MCC
+
+ ppMccObject - Pointer to an internal Mcc Object returned.
+
+ Returns BE_SUCCESS if successfull,, otherwise a useful error code
+ is returned.
+
+ IRQL < DISPATCH_LEVEL
+
+*/
+int
+be_mcc_ring_create(struct be_function_object *pfob,
+ struct ring_desc *rd, u32 length,
+ struct be_mcc_wrb_context *context_array,
+ u32 num_context_entries,
+ struct be_cq_object *cq, struct be_mcc_object *mcc)
+{
+ int status = 0;
+
+ struct FWCMD_COMMON_MCC_CREATE *fwcmd = NULL;
+ struct MCC_WRB_AMAP *wrb = NULL;
+ u32 num_entries_encoded, n, i;
+ void *va = NULL;
+ unsigned long irql;
+
+ if (length < sizeof(struct MCC_WRB_AMAP) * 2) {
+ TRACE(DL_ERR, "Invalid MCC ring length:%d", length);
+ return BE_NOT_OK;
+ }
+ /*
+ * Reduce the actual ring size to be less than the number
+ * of context entries. This ensures that we run out of
+ * ring WRBs first so the queuing works correctly. We never
+ * queue based on context structs.
+ */
+ if (num_context_entries + 1 <
+ length / sizeof(struct MCC_WRB_AMAP) - 1) {
+
+ u32 max_length =
+ (num_context_entries + 2) * sizeof(struct MCC_WRB_AMAP);
+
+ if (is_power_of_2(max_length))
+ length = __roundup_pow_of_two(max_length+1) / 2;
+ else
+ length = __roundup_pow_of_two(max_length) / 2;
+
+ ASSERT(length <= max_length);
+
+ TRACE(DL_WARN,
+ "MCC ring length reduced based on context entries."
+ " length:%d wrbs:%d context_entries:%d", length,
+ (int) (length / sizeof(struct MCC_WRB_AMAP)),
+ num_context_entries);
+ }
+
+ spin_lock_irqsave(&pfob->post_lock, irql);
+
+ num_entries_encoded =
+ be_ring_length_to_encoding(length, sizeof(struct MCC_WRB_AMAP));
+
+ /* Init MCC object. */
+ memset(mcc, 0, sizeof(*mcc));
+ mcc->parent_function = pfob;
+ mcc->cq_object = cq;
+
+ INIT_LIST_HEAD(&mcc->backlog);
+
+ wrb = be_function_peek_mcc_wrb(pfob);
+ if (!wrb) {
+ ASSERT(wrb);
+ TRACE(DL_ERR, "No free MCC WRBs in create EQ.");
+ status = BE_STATUS_NO_MCC_WRB;
+ goto error;
+ }
+ /* Prepares an embedded fwcmd, including request/response sizes. */
+ fwcmd = BE_PREPARE_EMBEDDED_FWCMD(pfob, wrb, COMMON_MCC_CREATE);
+
+ fwcmd->params.request.num_pages = DIV_ROUND_UP(length, PAGE_SIZE);
+ /*
+ * Program MCC ring context
+ */
+ AMAP_SET_BITS_PTR(MCC_RING_CONTEXT, pdid,
+ &fwcmd->params.request.context, 0);
+ AMAP_SET_BITS_PTR(MCC_RING_CONTEXT, invalid,
+ &fwcmd->params.request.context, false);
+ AMAP_SET_BITS_PTR(MCC_RING_CONTEXT, ring_size,
+ &fwcmd->params.request.context, num_entries_encoded);
+
+ n = cq->cq_id;
+ AMAP_SET_BITS_PTR(MCC_RING_CONTEXT,
+ cq_id, &fwcmd->params.request.context, n);
+ be_rd_to_pa_list(rd, fwcmd->params.request.pages,
+ ARRAY_SIZE(fwcmd->params.request.pages));
+ /* Post the f/w command */
+ status = be_function_post_mcc_wrb(pfob, wrb, NULL, NULL, NULL,
+ NULL, NULL, fwcmd, NULL);
+ if (status != BE_SUCCESS) {
+ TRACE(DL_ERR, "MCC to create CQ failed.");
+ goto error;
+ }
+ /*
+ * Create a linked list of context structures
+ */
+ mcc->wrb_context.base = context_array;
+ mcc->wrb_context.num = num_context_entries;
+ INIT_LIST_HEAD(&mcc->wrb_context.list_head);
+ memset(context_array, 0,
+ sizeof(struct be_mcc_wrb_context) * num_context_entries);
+ for (i = 0; i < mcc->wrb_context.num; i++) {
+ list_add_tail(&context_array[i].next,
+ &mcc->wrb_context.list_head);
+ }
+
+ /*
+ *
+ * Create an mcc_ring for tracking WRB hw ring
+ */
+ va = rd->va;
+ ASSERT(va);
+ mp_ring_create(&mcc->sq.ring, length / sizeof(struct MCC_WRB_AMAP),
+ sizeof(struct MCC_WRB_AMAP), va);
+ mcc->sq.ring.id = fwcmd->params.response.id;
+ /*
+ * Init a mcc_ring for tracking the MCC CQ.
+ */
+ ASSERT(cq->va);
+ mp_ring_create(&mcc->cq.ring, cq->num_entries,
+ sizeof(struct MCC_CQ_ENTRY_AMAP), cq->va);
+ mcc->cq.ring.id = cq->cq_id;
+
+ /* Force zeroing of CQ. */
+ memset(cq->va, 0, cq->num_entries * sizeof(struct MCC_CQ_ENTRY_AMAP));
+
+ /* Initialize debug index. */
+ mcc->consumed_index = 0;
+
+ atomic_inc(&cq->ref_count);
+ pfob->mcc = mcc;
+
+ TRACE(DL_INFO, "MCC ring created. id:%d bytes:%d cq_id:%d cq_entries:%d"
+ " num_context:%d", mcc->sq.ring.id, length,
+ cq->cq_id, cq->num_entries, num_context_entries);
+
+error:
+ spin_unlock_irqrestore(&pfob->post_lock, irql);
+ if (pfob->pend_queue_driving && pfob->mcc) {
+ pfob->pend_queue_driving = 0;
+ be_drive_mcc_wrb_queue(pfob->mcc);
+ }
+ return status;
+}
+
+/*
+ This routine destroys an MCC send queue
+
+ MccObject - Internal Mcc Object to be destroyed.
+
+ Returns BE_SUCCESS if successfull, otherwise an error code is returned.
+
+ IRQL < DISPATCH_LEVEL
+
+ The caller of this routine must ensure that no other WRB may be posted
+ until this routine returns.
+
+*/
+int be_mcc_ring_destroy(struct be_mcc_object *mcc)
+{
+ int status = 0;
+ struct be_function_object *pfob = mcc->parent_function;
+
+
+ ASSERT(mcc->processing == 0);
+
+ /*
+ * Remove the ring from the function object.
+ * This transitions back to mailbox mode.
+ */
+ pfob->mcc = NULL;
+
+ /* Send fwcmd to destroy the queue. (Using the mailbox.) */
+ status = be_function_ring_destroy(mcc->parent_function, mcc->sq.ring.id,
+ FWCMD_RING_TYPE_MCC, NULL, NULL, NULL, NULL);
+ ASSERT(status == 0);
+
+ /* Release the SQ reference to the CQ */
+ atomic_dec(&mcc->cq_object->ref_count);
+
+ return status;
+}
+
+static void
+mcc_wrb_sync_cb(void *context, int staus, struct MCC_WRB_AMAP *wrb)
+{
+ struct be_mcc_wrb_context *wrb_context =
+ (struct be_mcc_wrb_context *) context;
+ ASSERT(wrb_context);
+ *wrb_context->users_final_status = staus;
+}
+
+/*
+ This routine posts a command to the MCC send queue
+
+ mcc - Internal Mcc Object to be destroyed.
+
+ wrb - wrb to post.
+
+ Returns BE_SUCCESS if successfull, otherwise an error code is returned.
+
+ IRQL < DISPATCH_LEVEL if CompletionCallback is not NULL
+ IRQL <=DISPATCH_LEVEL if CompletionCallback is NULL
+
+ If this routine is called with CompletionCallback != NULL the
+ call is considered to be asynchronous and will return as soon
+ as the WRB is posted to the MCC with BE_PENDING.
+
+ If CompletionCallback is NULL, then this routine will not return until
+ a completion for this MCC command has been processed.
+ If called at DISPATCH_LEVEL the CompletionCallback must be NULL.
+
+ This routine should only be called if the MPU has been boostraped past
+ mailbox mode.
+
+
+*/
+int
+_be_mpu_post_wrb_ring(struct be_mcc_object *mcc, struct MCC_WRB_AMAP *wrb,
+ struct be_mcc_wrb_context *wrb_context)
+{
+
+ struct MCC_WRB_AMAP *ring_wrb = NULL;
+ int status = BE_PENDING;
+ int final_status = BE_PENDING;
+ mcc_wrb_cqe_callback cb = NULL;
+ struct MCC_DB_AMAP mcc_db;
+ u32 embedded;
+
+ ASSERT(mp_ring_num_empty(&mcc->sq.ring) > 0);
+ /*
+ * Input wrb is most likely the next wrb in the ring, since the client
+ * can peek at the address.
+ */
+ ring_wrb = mp_ring_producer_ptr(&mcc->sq.ring);
+ if (wrb != ring_wrb) {
+ /* If not equal, copy it into the ring. */
+ memcpy(ring_wrb, wrb, sizeof(struct MCC_WRB_AMAP));
+ }
+#ifdef BE_DEBUG
+ wrb_context->ring_wrb = ring_wrb;
+#endif
+ embedded = AMAP_GET_BITS_PTR(MCC_WRB, embedded, ring_wrb);
+ if (embedded) {
+ /* embedded commands will have the response within the WRB. */
+ wrb_context->wrb = ring_wrb;
+ } else {
+ /*
+ * non-embedded commands will not have the response
+ * within the WRB, and they may complete out-of-order.
+ * The WRB will not be valid to inspect
+ * during the completion.
+ */
+ wrb_context->wrb = NULL;
+ }
+ cb = wrb_context->cb;
+
+ if (cb == NULL) {
+ /* Assign our internal callback if this is a
+ * synchronous call. */
+ wrb_context->cb = mcc_wrb_sync_cb;
+ wrb_context->cb_context = wrb_context;
+ wrb_context->users_final_status = &final_status;
+ }
+ /* Increment producer index */
+
+ mcc_db.dw[0] = 0; /* initialize */
+ AMAP_SET_BITS_PTR(MCC_DB, rid, &mcc_db, mcc->sq.ring.id);
+ AMAP_SET_BITS_PTR(MCC_DB, numPosted, &mcc_db, 1);
+
+ mp_ring_produce(&mcc->sq.ring);
+ PD_WRITE(mcc->parent_function, mpu_mcc_db, mcc_db.dw[0]);
+ TRACE(DL_INFO, "pidx: %x and cidx: %x.", mcc->sq.ring.pidx,
+ mcc->sq.ring.cidx);
+
+ if (cb == NULL) {
+ int polls = 0; /* At >= 1 us per poll */
+ /* Wait until this command completes, polling the CQ. */
+ do {
+ TRACE(DL_INFO, "FWCMD submitted in the poll mode.");
+ /* Do not rearm CQ in this context. */
+ be_mcc_process_cq(mcc, false);
+
+ if (final_status == BE_PENDING) {
+ if ((++polls & 0x7FFFF) == 0) {
+ TRACE(DL_WARN,
+ "Warning : polling MCC CQ for %d"
+ "ms.", polls / 1000);
+ }
+
+ udelay(1);
+ }
+
+ /* final_status changed when the command completes */
+ } while (final_status == BE_PENDING);
+
+ status = final_status;
+ }
+
+ return status;
+}
+
+struct MCC_WRB_AMAP *
+_be_mpu_peek_ring_wrb(struct be_mcc_object *mcc, bool driving_queue)
+{
+ /* If we have queued items, do not allow a post to bypass the queue. */
+ if (!driving_queue && !list_empty(&mcc->backlog))
+ return NULL;
+
+ if (mp_ring_num_empty(&mcc->sq.ring) <= 0)
+ return NULL;
+ return (struct MCC_WRB_AMAP *) mp_ring_producer_ptr(&mcc->sq.ring);
+}
+
+int
+be_mpu_init_mailbox(struct be_function_object *pfob, struct ring_desc *mailbox)
+{
+ ASSERT(mailbox);
+ pfob->mailbox.va = mailbox->va;
+ pfob->mailbox.pa = cpu_to_le64(mailbox->pa);
+ pfob->mailbox.length = mailbox->length;
+
+ ASSERT(((u32)(size_t)pfob->mailbox.va & 0xf) == 0);
+ ASSERT(((u32)(size_t)pfob->mailbox.pa & 0xf) == 0);
+ /*
+ * Issue the WRB to set MPU endianness
+ */
+ {
+ u64 *endian_check = (u64 *) (pfob->mailbox.va +
+ offsetof(struct BE_MCC_MAILBOX_AMAP, wrb)/8);
+ *endian_check = 0xFF1234FFFF5678FFULL;
+ }
+
+ be_mcc_mailbox_notify_and_wait(pfob);
+
+ return BE_SUCCESS;
+}
+
+
+/*
+ This routine posts a command to the MCC mailbox.
+
+ FuncObj - Function Object to post the WRB on behalf of.
+ wrb - wrb to post.
+ CompletionCallback - Address of a callback routine to invoke once the WRB
+ is completed.
+ CompletionCallbackContext - Opaque context to be passed during the call to
+ the CompletionCallback.
+ Returns BE_SUCCESS if successfull, otherwise an error code is returned.
+
+ IRQL <=DISPATCH_LEVEL if CompletionCallback is NULL
+
+ This routine will block until a completion for this MCC command has been
+ processed. If called at DISPATCH_LEVEL the CompletionCallback must be NULL.
+
+ This routine should only be called if the MPU has not been boostraped past
+ mailbox mode.
+*/
+int
+_be_mpu_post_wrb_mailbox(struct be_function_object *pfob,
+ struct MCC_WRB_AMAP *wrb, struct be_mcc_wrb_context *wrb_context)
+{
+ struct MCC_MAILBOX_AMAP *mailbox = NULL;
+ struct MCC_WRB_AMAP *mb_wrb;
+ struct MCC_CQ_ENTRY_AMAP *mb_cq;
+ u32 offset, status;
+
+ ASSERT(pfob->mcc == NULL);
+ mailbox = pfob->mailbox.va;
+ ASSERT(mailbox);
+
+ offset = offsetof(struct BE_MCC_MAILBOX_AMAP, wrb)/8;
+ mb_wrb = (struct MCC_WRB_AMAP *) (u8 *)mailbox + offset;
+ if (mb_wrb != wrb) {
+ memset(mailbox, 0, sizeof(*mailbox));
+ memcpy(mb_wrb, wrb, sizeof(struct MCC_WRB_AMAP));
+ }
+ /* The callback can inspect the final WRB to get output parameters. */
+ wrb_context->wrb = mb_wrb;
+
+ be_mcc_mailbox_notify_and_wait(pfob);
+
+ /* A command completed. Use tag to determine which command. */
+ offset = offsetof(struct BE_MCC_MAILBOX_AMAP, cq)/8;
+ mb_cq = (struct MCC_CQ_ENTRY_AMAP *) ((u8 *)mailbox + offset);
+ be_mcc_process_cqe(pfob, mb_cq);
+
+ status = AMAP_GET_BITS_PTR(MCC_CQ_ENTRY, completion_status, mb_cq);
+ if (status)
+ status = BE_NOT_OK;
+ return status;
+}
+
+struct be_mcc_wrb_context *
+_be_mcc_allocate_wrb_context(struct be_function_object *pfob)
+{
+ struct be_mcc_wrb_context *context = NULL;
+ unsigned long irq;
+
+ spin_lock_irqsave(&pfob->mcc_context_lock, irq);
+
+ if (!pfob->mailbox.default_context_allocated) {
+ /* Use the single default context that we
+ * always have allocated. */
+ pfob->mailbox.default_context_allocated = true;
+ context = &pfob->mailbox.default_context;
+ } else if (pfob->mcc) {
+ /* Get a context from the free list. If any are available. */
+ if (!list_empty(&pfob->mcc->wrb_context.list_head)) {
+ context = list_first_entry(
+ &pfob->mcc->wrb_context.list_head,
+ struct be_mcc_wrb_context, next);
+ }
+ }
+
+ spin_unlock_irqrestore(&pfob->mcc_context_lock, irq);
+
+ return context;
+}
+
+void
+_be_mcc_free_wrb_context(struct be_function_object *pfob,
+ struct be_mcc_wrb_context *context)
+{
+ unsigned long irq;
+
+ ASSERT(context);
+ /*
+ * Zero during free to try and catch any bugs where the context
+ * is accessed after a free.
+ */
+ memset(context, 0, sizeof(context));
+
+ spin_lock_irqsave(&pfob->mcc_context_lock, irq);
+
+ if (context == &pfob->mailbox.default_context) {
+ /* Free the default context. */
+ ASSERT(pfob->mailbox.default_context_allocated);
+ pfob->mailbox.default_context_allocated = false;
+ } else {
+ /* Add to free list. */
+ ASSERT(pfob->mcc);
+ list_add_tail(&context->next,
+ &pfob->mcc->wrb_context.list_head);
+ }
+
+ spin_unlock_irqrestore(&pfob->mcc_context_lock, irq);
+}
+
+int
+be_mcc_add_async_event_callback(struct be_mcc_object *mcc_object,
+ mcc_async_event_callback cb, void *cb_context)
+{
+ /* Lock against anyone trying to change the callback/context pointers
+ * while being used. */
+ spin_lock_irqsave(&mcc_object->parent_function->cq_lock,
+ mcc_object->parent_function->cq_irq);
+
+ /* Assign the async callback. */
+ mcc_object->async_context = cb_context;
+ mcc_object->async_cb = cb;
+
+ spin_unlock_irqrestore(&mcc_object->parent_function->cq_lock,
+ mcc_object->parent_function->cq_irq);
+
+ return BE_SUCCESS;
+}
+
+#define MPU_EP_CONTROL 0
+#define MPU_EP_SEMAPHORE 0xac
+
+/*
+ *-------------------------------------------------------------------
+ * Function: be_wait_for_POST_complete
+ * Waits until the BladeEngine POST completes (either in error or success).
+ * pfob -
+ * return status - BE_SUCCESS (0) on success. Negative error code on failure.
+ *-------------------------------------------------------------------
+ */
+static int be_wait_for_POST_complete(struct be_function_object *pfob)
+{
+ struct MGMT_HBA_POST_STATUS_STRUCT_AMAP status;
+ int s;
+ u32 post_error, post_stage;
+
+ const u32 us_per_loop = 1000; /* 1000us */
+ const u32 print_frequency_loops = 1000000 / us_per_loop;
+ const u32 max_loops = 60 * print_frequency_loops;
+ u32 loops = 0;
+
+ /*
+ * Wait for arm fw indicating it is done or a fatal error happened.
+ * Note: POST can take some time to complete depending on configuration
+ * settings (consider ARM attempts to acquire an IP address
+ * over DHCP!!!).
+ *
+ */
+ do {
+ status.dw[0] = ioread32(pfob->csr_va + MPU_EP_SEMAPHORE);
+ post_error = AMAP_GET_BITS_PTR(MGMT_HBA_POST_STATUS_STRUCT,
+ error, &status);
+ post_stage = AMAP_GET_BITS_PTR(MGMT_HBA_POST_STATUS_STRUCT,
+ stage, &status);
+ if (0 == (loops % print_frequency_loops)) {
+ /* Print current status */
+ TRACE(DL_INFO, "POST status = 0x%x (stage = 0x%x)",
+ status.dw[0], post_stage);
+ }
+ udelay(us_per_loop);
+ } while ((post_error != 1) &&
+ (post_stage != POST_STAGE_ARMFW_READY) &&
+ (++loops < max_loops));
+
+ if (post_error == 1) {
+ TRACE(DL_ERR, "POST error! Status = 0x%x (stage = 0x%x)",
+ status.dw[0], post_stage);
+ s = BE_NOT_OK;
+ } else if (post_stage != POST_STAGE_ARMFW_READY) {
+ TRACE(DL_ERR, "POST time-out! Status = 0x%x (stage = 0x%x)",
+ status.dw[0], post_stage);
+ s = BE_NOT_OK;
+ } else {
+ s = BE_SUCCESS;
+ }
+ return s;
+}
+
+/*
+ *-------------------------------------------------------------------
+ * Function: be_kickoff_and_wait_for_POST
+ * Interacts with the BladeEngine management processor to initiate POST, and
+ * subsequently waits until POST completes (either in error or success).
+ * The caller must acquire the reset semaphore before initiating POST
+ * to prevent multiple drivers interacting with the management processor.
+ * Once POST is complete the caller must release the reset semaphore.
+ * Callers who only want to wait for POST complete may call
+ * be_wait_for_POST_complete.
+ * pfob -
+ * return status - BE_SUCCESS (0) on success. Negative error code on failure.
+ *-------------------------------------------------------------------
+ */
+static int
+be_kickoff_and_wait_for_POST(struct be_function_object *pfob)
+{
+ struct MGMT_HBA_POST_STATUS_STRUCT_AMAP status;
+ int s;
+
+ const u32 us_per_loop = 1000; /* 1000us */
+ const u32 print_frequency_loops = 1000000 / us_per_loop;
+ const u32 max_loops = 5 * print_frequency_loops;
+ u32 loops = 0;
+ u32 post_error, post_stage;
+
+ /* Wait for arm fw awaiting host ready or a fatal error happened. */
+ TRACE(DL_INFO, "Wait for BladeEngine ready to POST");
+ do {
+ status.dw[0] = ioread32(pfob->csr_va + MPU_EP_SEMAPHORE);
+ post_error = AMAP_GET_BITS_PTR(MGMT_HBA_POST_STATUS_STRUCT,
+ error, &status);
+ post_stage = AMAP_GET_BITS_PTR(MGMT_HBA_POST_STATUS_STRUCT,
+ stage, &status);
+ if (0 == (loops % print_frequency_loops)) {
+ /* Print current status */
+ TRACE(DL_INFO, "POST status = 0x%x (stage = 0x%x)",
+ status.dw[0], post_stage);
+ }
+ udelay(us_per_loop);
+ } while ((post_error != 1) &&
+ (post_stage < POST_STAGE_AWAITING_HOST_RDY) &&
+ (++loops < max_loops));
+
+ if (post_error == 1) {
+ TRACE(DL_ERR, "Pre-POST error! Status = 0x%x (stage = 0x%x)",
+ status.dw[0], post_stage);
+ s = BE_NOT_OK;
+ } else if (post_stage == POST_STAGE_AWAITING_HOST_RDY) {
+ iowrite32(POST_STAGE_HOST_RDY, pfob->csr_va + MPU_EP_SEMAPHORE);
+
+ /* Wait for POST to complete */
+ s = be_wait_for_POST_complete(pfob);
+ } else {
+ /*
+ * Either a timeout waiting for host ready signal or POST has
+ * moved ahead without requiring a host ready signal.
+ * Might as well give POST a chance to complete
+ * (or timeout again).
+ */
+ s = be_wait_for_POST_complete(pfob);
+ }
+ return s;
+}
+
+/*
+ *-------------------------------------------------------------------
+ * Function: be_pci_soft_reset
+ * This function is called to issue a BladeEngine soft reset.
+ * Callers should acquire the soft reset semaphore before calling this
+ * function. Additionaly, callers should ensure they cannot be pre-empted
+ * while the routine executes. Upon completion of this routine, callers
+ * should release the reset semaphore. This routine implicitly waits
+ * for BladeEngine POST to complete.
+ * pfob -
+ * return status - BE_SUCCESS (0) on success. Negative error code on failure.
+ *-------------------------------------------------------------------
+ */
+int be_pci_soft_reset(struct be_function_object *pfob)
+{
+ struct PCICFG_SOFT_RESET_CSR_AMAP soft_reset;
+ struct PCICFG_ONLINE0_CSR_AMAP pciOnline0;
+ struct PCICFG_ONLINE1_CSR_AMAP pciOnline1;
+ struct EP_CONTROL_CSR_AMAP epControlCsr;
+ int status = BE_SUCCESS;
+ u32 i, soft_reset_bit;
+
+ TRACE(DL_NOTE, "PCI reset...");
+
+ /* Issue soft reset #1 to get BladeEngine into a known state. */
+ soft_reset.dw[0] = PCICFG0_READ(pfob, soft_reset);
+ AMAP_SET_BITS_PTR(PCICFG_SOFT_RESET_CSR, softreset, soft_reset.dw, 1);
+ PCICFG0_WRITE(pfob, host_timer_int_ctrl, soft_reset.dw[0]);
+ /*
+ * wait til soft reset is deasserted - hardware
+ * deasserts after some time.
+ */
+ i = 0;
+ do {
+ udelay(50);
+ soft_reset.dw[0] = PCICFG0_READ(pfob, soft_reset);
+ soft_reset_bit = AMAP_GET_BITS_PTR(PCICFG_SOFT_RESET_CSR,
+ softreset, soft_reset.dw);
+ } while (soft_reset_bit && (i++ < 1024));
+ if (soft_reset_bit != 0) {
+ TRACE(DL_ERR, "Soft-reset #1 did not deassert as expected.");
+ status = BE_NOT_OK;
+ goto Error_label;
+ }
+ /* Mask everything */
+ PCICFG0_WRITE(pfob, ue_status_low_mask, 0xFFFFFFFF);
+ PCICFG0_WRITE(pfob, ue_status_hi_mask, 0xFFFFFFFF);
+ /*
+ * Set everything offline except MPU IRAM (it is offline with
+ * the soft-reset, but soft-reset does not reset the PCICFG registers!)
+ */
+ pciOnline0.dw[0] = 0;
+ pciOnline1.dw[0] = 0;
+ AMAP_SET_BITS_PTR(PCICFG_ONLINE1_CSR, mpu_iram_online,
+ pciOnline1.dw, 1);
+ PCICFG0_WRITE(pfob, online0, pciOnline0.dw[0]);
+ PCICFG0_WRITE(pfob, online1, pciOnline1.dw[0]);
+
+ udelay(20000);
+
+ /* Issue soft reset #2. */
+ AMAP_SET_BITS_PTR(PCICFG_SOFT_RESET_CSR, softreset, soft_reset.dw, 1);
+ PCICFG0_WRITE(pfob, host_timer_int_ctrl, soft_reset.dw[0]);
+ /*
+ * wait til soft reset is deasserted - hardware
+ * deasserts after some time.
+ */
+ i = 0;
+ do {
+ udelay(50);
+ soft_reset.dw[0] = PCICFG0_READ(pfob, soft_reset);
+ soft_reset_bit = AMAP_GET_BITS_PTR(PCICFG_SOFT_RESET_CSR,
+ softreset, soft_reset.dw);
+ } while (soft_reset_bit && (i++ < 1024));
+ if (soft_reset_bit != 0) {
+ TRACE(DL_ERR, "Soft-reset #1 did not deassert as expected.");
+ status = BE_NOT_OK;
+ goto Error_label;
+ }
+
+
+ udelay(20000);
+
+ /* Take MPU out of reset. */
+
+ epControlCsr.dw[0] = ioread32(pfob->csr_va + MPU_EP_CONTROL);
+ AMAP_SET_BITS_PTR(EP_CONTROL_CSR, CPU_reset, &epControlCsr, 0);
+ iowrite32((u32)epControlCsr.dw[0], pfob->csr_va + MPU_EP_CONTROL);
+
+ /* Kickoff BE POST and wait for completion */
+ status = be_kickoff_and_wait_for_POST(pfob);
+
+Error_label:
+ return status;
+}
+
+
+/*
+ *-------------------------------------------------------------------
+ * Function: be_pci_reset_required
+ * This private function is called to detect if a host entity is
+ * required to issue a PCI soft reset and subsequently drive
+ * BladeEngine POST. Scenarios where this is required:
+ * 1) BIOS-less configuration
+ * 2) Hot-swap/plug/power-on
+ * pfob -
+ * return true if a reset is required, false otherwise
+ *-------------------------------------------------------------------
+ */
+static bool be_pci_reset_required(struct be_function_object *pfob)
+{
+ struct MGMT_HBA_POST_STATUS_STRUCT_AMAP status;
+ bool do_reset = false;
+ u32 post_error, post_stage;
+
+ /*
+ * Read the POST status register
+ */
+ status.dw[0] = ioread32(pfob->csr_va + MPU_EP_SEMAPHORE);
+ post_error = AMAP_GET_BITS_PTR(MGMT_HBA_POST_STATUS_STRUCT, error,
+ &status);
+ post_stage = AMAP_GET_BITS_PTR(MGMT_HBA_POST_STATUS_STRUCT, stage,
+ &status);
+ if (post_stage <= POST_STAGE_AWAITING_HOST_RDY) {
+ /*
+ * If BladeEngine is waiting for host ready indication,
+ * we want to do a PCI reset.
+ */
+ do_reset = true;
+ }
+
+ return do_reset;
+}
+
+/*
+ *-------------------------------------------------------------------
+ * Function: be_drive_POST
+ * This function is called to drive BladeEngine POST. The
+ * caller should ensure they cannot be pre-empted while this routine executes.
+ * pfob -
+ * return status - BE_SUCCESS (0) on success. Negative error code on failure.
+ *-------------------------------------------------------------------
+ */
+int be_drive_POST(struct be_function_object *pfob)
+{
+ int status;
+
+ if (false != be_pci_reset_required(pfob)) {
+ /* PCI reset is needed (implicitly starts and waits for POST) */
+ status = be_pci_soft_reset(pfob);
+ } else {
+ /* No PCI reset is needed, start POST */
+ status = be_kickoff_and_wait_for_POST(pfob);
+ }
+
+ return status;
+}
diff --git a/drivers/staging/benet/mpu.h b/drivers/staging/benet/mpu.h
new file mode 100644
index 000000000000..41f3f87516e5
--- /dev/null
+++ b/drivers/staging/benet/mpu.h
@@ -0,0 +1,74 @@
+/*
+ * 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:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+/*
+ * Autogenerated by srcgen version: 0127
+ */
+#ifndef __mpu_amap_h__
+#define __mpu_amap_h__
+#include "ep.h"
+
+/* Provide control parameters for the Managment Processor Unit. */
+struct BE_MPU_CSRMAP_AMAP {
+ struct BE_EP_CSRMAP_AMAP ep;
+ u8 rsvd0[128]; /* DWORD 64 */
+ u8 rsvd1[32]; /* DWORD 68 */
+ u8 rsvd2[192]; /* DWORD 69 */
+ u8 rsvd3[192]; /* DWORD 75 */
+ u8 rsvd4[32]; /* DWORD 81 */
+ u8 rsvd5[32]; /* DWORD 82 */
+ u8 rsvd6[32]; /* DWORD 83 */
+ u8 rsvd7[32]; /* DWORD 84 */
+ u8 rsvd8[32]; /* DWORD 85 */
+ u8 rsvd9[32]; /* DWORD 86 */
+ u8 rsvd10[32]; /* DWORD 87 */
+ u8 rsvd11[32]; /* DWORD 88 */
+ u8 rsvd12[32]; /* DWORD 89 */
+ u8 rsvd13[32]; /* DWORD 90 */
+ u8 rsvd14[32]; /* DWORD 91 */
+ u8 rsvd15[32]; /* DWORD 92 */
+ u8 rsvd16[32]; /* DWORD 93 */
+ u8 rsvd17[32]; /* DWORD 94 */
+ u8 rsvd18[32]; /* DWORD 95 */
+ u8 rsvd19[32]; /* DWORD 96 */
+ u8 rsvd20[32]; /* DWORD 97 */
+ u8 rsvd21[32]; /* DWORD 98 */
+ u8 rsvd22[32]; /* DWORD 99 */
+ u8 rsvd23[32]; /* DWORD 100 */
+ u8 rsvd24[32]; /* DWORD 101 */
+ u8 rsvd25[32]; /* DWORD 102 */
+ u8 rsvd26[32]; /* DWORD 103 */
+ u8 rsvd27[32]; /* DWORD 104 */
+ u8 rsvd28[96]; /* DWORD 105 */
+ u8 rsvd29[32]; /* DWORD 108 */
+ u8 rsvd30[32]; /* DWORD 109 */
+ u8 rsvd31[32]; /* DWORD 110 */
+ u8 rsvd32[32]; /* DWORD 111 */
+ u8 rsvd33[32]; /* DWORD 112 */
+ u8 rsvd34[96]; /* DWORD 113 */
+ u8 rsvd35[32]; /* DWORD 116 */
+ u8 rsvd36[32]; /* DWORD 117 */
+ u8 rsvd37[32]; /* DWORD 118 */
+ u8 rsvd38[32]; /* DWORD 119 */
+ u8 rsvd39[32]; /* DWORD 120 */
+ u8 rsvd40[32]; /* DWORD 121 */
+ u8 rsvd41[134][32]; /* DWORD 122 */
+} __packed;
+struct MPU_CSRMAP_AMAP {
+ u32 dw[256];
+};
+
+#endif /* __mpu_amap_h__ */
diff --git a/drivers/staging/benet/mpu_context.h b/drivers/staging/benet/mpu_context.h
new file mode 100644
index 000000000000..8ce90f9c46c2
--- /dev/null
+++ b/drivers/staging/benet/mpu_context.h
@@ -0,0 +1,46 @@
+/*
+ * 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:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+/*
+ * Autogenerated by srcgen version: 0127
+ */
+#ifndef __mpu_context_amap_h__
+#define __mpu_context_amap_h__
+
+/*
+ * Management command and control ring context. The MPUs BTLR_CTRL1 CSR
+ * controls the writeback behavior of the producer and consumer index values.
+ */
+struct BE_MCC_RING_CONTEXT_AMAP {
+ u8 con_index[16]; /* DWORD 0 */
+ u8 ring_size[4]; /* DWORD 0 */
+ u8 cq_id[11]; /* DWORD 0 */
+ u8 rsvd0; /* DWORD 0 */
+ u8 prod_index[16]; /* DWORD 1 */
+ u8 pdid[15]; /* DWORD 1 */
+ u8 invalid; /* DWORD 1 */
+ u8 cmd_pending_current[7]; /* DWORD 2 */
+ u8 rsvd1[25]; /* DWORD 2 */
+ u8 hpi_port_cq_id[11]; /* DWORD 3 */
+ u8 rsvd2[5]; /* DWORD 3 */
+ u8 cmd_pending_max[7]; /* DWORD 3 */
+ u8 rsvd3[9]; /* DWORD 3 */
+} __packed;
+struct MCC_RING_CONTEXT_AMAP {
+ u32 dw[4];
+};
+
+#endif /* __mpu_context_amap_h__ */
diff --git a/drivers/staging/benet/pcicfg.h b/drivers/staging/benet/pcicfg.h
new file mode 100644
index 000000000000..7c15684adf4a
--- /dev/null
+++ b/drivers/staging/benet/pcicfg.h
@@ -0,0 +1,825 @@
+/*
+ * 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:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+/*
+ * Autogenerated by srcgen version: 0127
+ */
+#ifndef __pcicfg_amap_h__
+#define __pcicfg_amap_h__
+
+/* Vendor and Device ID Register. */
+struct BE_PCICFG_ID_CSR_AMAP {
+ u8 vendorid[16]; /* DWORD 0 */
+ u8 deviceid[16]; /* DWORD 0 */
+} __packed;
+struct PCICFG_ID_CSR_AMAP {
+ u32 dw[1];
+};
+
+/* IO Bar Register. */
+struct BE_PCICFG_IOBAR_CSR_AMAP {
+ u8 iospace; /* DWORD 0 */
+ u8 rsvd0[7]; /* DWORD 0 */
+ u8 iobar[24]; /* DWORD 0 */
+} __packed;
+struct PCICFG_IOBAR_CSR_AMAP {
+ u32 dw[1];
+};
+
+/* Memory BAR 0 Register. */
+struct BE_PCICFG_MEMBAR0_CSR_AMAP {
+ u8 memspace; /* DWORD 0 */
+ u8 type[2]; /* DWORD 0 */
+ u8 pf; /* DWORD 0 */
+ u8 rsvd0[10]; /* DWORD 0 */
+ u8 membar0[18]; /* DWORD 0 */
+} __packed;
+struct PCICFG_MEMBAR0_CSR_AMAP {
+ u32 dw[1];
+};
+
+/* Memory BAR 1 - Low Address Register. */
+struct BE_PCICFG_MEMBAR1_LO_CSR_AMAP {
+ u8 memspace; /* DWORD 0 */
+ u8 type[2]; /* DWORD 0 */
+ u8 pf; /* DWORD 0 */
+ u8 rsvd0[13]; /* DWORD 0 */
+ u8 membar1lo[15]; /* DWORD 0 */
+} __packed;
+struct PCICFG_MEMBAR1_LO_CSR_AMAP {
+ u32 dw[1];
+};
+
+/* Memory BAR 1 - High Address Register. */
+struct BE_PCICFG_MEMBAR1_HI_CSR_AMAP {
+ u8 membar1hi[32]; /* DWORD 0 */
+} __packed;
+struct PCICFG_MEMBAR1_HI_CSR_AMAP {
+ u32 dw[1];
+};
+
+/* Memory BAR 2 - Low Address Register. */
+struct BE_PCICFG_MEMBAR2_LO_CSR_AMAP {
+ u8 memspace; /* DWORD 0 */
+ u8 type[2]; /* DWORD 0 */
+ u8 pf; /* DWORD 0 */
+ u8 rsvd0[17]; /* DWORD 0 */
+ u8 membar2lo[11]; /* DWORD 0 */
+} __packed;
+struct PCICFG_MEMBAR2_LO_CSR_AMAP {
+ u32 dw[1];
+};
+
+/* Memory BAR 2 - High Address Register. */
+struct BE_PCICFG_MEMBAR2_HI_CSR_AMAP {
+ u8 membar2hi[32]; /* DWORD 0 */
+} __packed;
+struct PCICFG_MEMBAR2_HI_CSR_AMAP {
+ u32 dw[1];
+};
+
+/* Subsystem Vendor and ID (Function 0) Register. */
+struct BE_PCICFG_SUBSYSTEM_ID_F0_CSR_AMAP {
+ u8 subsys_vendor_id[16]; /* DWORD 0 */
+ u8 subsys_id[16]; /* DWORD 0 */
+} __packed;
+struct PCICFG_SUBSYSTEM_ID_F0_CSR_AMAP {
+ u32 dw[1];
+};
+
+/* Subsystem Vendor and ID (Function 1) Register. */
+struct BE_PCICFG_SUBSYSTEM_ID_F1_CSR_AMAP {
+ u8 subsys_vendor_id[16]; /* DWORD 0 */
+ u8 subsys_id[16]; /* DWORD 0 */
+} __packed;
+struct PCICFG_SUBSYSTEM_ID_F1_CSR_AMAP {
+ u32 dw[1];
+};
+
+/* Semaphore Register. */
+struct BE_PCICFG_SEMAPHORE_CSR_AMAP {
+ u8 locked; /* DWORD 0 */
+ u8 rsvd0[31]; /* DWORD 0 */
+} __packed;
+struct PCICFG_SEMAPHORE_CSR_AMAP {
+ u32 dw[1];
+};
+
+/* Soft Reset Register. */
+struct BE_PCICFG_SOFT_RESET_CSR_AMAP {
+ u8 rsvd0[7]; /* DWORD 0 */
+ u8 softreset; /* DWORD 0 */
+ u8 rsvd1[16]; /* DWORD 0 */
+ u8 nec_ll_rcvdetect_i[8]; /* DWORD 0 */
+} __packed;
+struct PCICFG_SOFT_RESET_CSR_AMAP {
+ u32 dw[1];
+};
+
+/* Unrecoverable Error Status (Low) Register. Each bit corresponds to
+ * an internal Unrecoverable Error. These are set by hardware and may be
+ * cleared by writing a one to the respective bit(s) to be cleared. Any
+ * bit being set that is also unmasked will result in Unrecoverable Error
+ * interrupt notification to the host CPU and/or Server Management chip
+ * and the transitioning of BladeEngine to an Offline state.
+ */
+struct BE_PCICFG_UE_STATUS_LOW_CSR_AMAP {
+ u8 cev_ue_status; /* DWORD 0 */
+ u8 ctx_ue_status; /* DWORD 0 */
+ u8 dbuf_ue_status; /* DWORD 0 */
+ u8 erx_ue_status; /* DWORD 0 */
+ u8 host_ue_status; /* DWORD 0 */
+ u8 mpu_ue_status; /* DWORD 0 */
+ u8 ndma_ue_status; /* DWORD 0 */
+ u8 ptc_ue_status; /* DWORD 0 */
+ u8 rdma_ue_status; /* DWORD 0 */
+ u8 rxf_ue_status; /* DWORD 0 */
+ u8 rxips_ue_status; /* DWORD 0 */
+ u8 rxulp0_ue_status; /* DWORD 0 */
+ u8 rxulp1_ue_status; /* DWORD 0 */
+ u8 rxulp2_ue_status; /* DWORD 0 */
+ u8 tim_ue_status; /* DWORD 0 */
+ u8 tpost_ue_status; /* DWORD 0 */
+ u8 tpre_ue_status; /* DWORD 0 */
+ u8 txips_ue_status; /* DWORD 0 */
+ u8 txulp0_ue_status; /* DWORD 0 */
+ u8 txulp1_ue_status; /* DWORD 0 */
+ u8 uc_ue_status; /* DWORD 0 */
+ u8 wdma_ue_status; /* DWORD 0 */
+ u8 txulp2_ue_status; /* DWORD 0 */
+ u8 host1_ue_status; /* DWORD 0 */
+ u8 p0_ob_link_ue_status; /* DWORD 0 */
+ u8 p1_ob_link_ue_status; /* DWORD 0 */
+ u8 host_gpio_ue_status; /* DWORD 0 */
+ u8 mbox_netw_ue_status; /* DWORD 0 */
+ u8 mbox_stor_ue_status; /* DWORD 0 */
+ u8 axgmac0_ue_status; /* DWORD 0 */
+ u8 axgmac1_ue_status; /* DWORD 0 */
+ u8 mpu_intpend_ue_status; /* DWORD 0 */
+} __packed;
+struct PCICFG_UE_STATUS_LOW_CSR_AMAP {
+ u32 dw[1];
+};
+
+/* Unrecoverable Error Status (High) Register. Each bit corresponds to
+ * an internal Unrecoverable Error. These are set by hardware and may be
+ * cleared by writing a one to the respective bit(s) to be cleared. Any
+ * bit being set that is also unmasked will result in Unrecoverable Error
+ * interrupt notification to the host CPU and/or Server Management chip;
+ * and the transitioning of BladeEngine to an Offline state.
+ */
+struct BE_PCICFG_UE_STATUS_HI_CSR_AMAP {
+ u8 jtag_ue_status; /* DWORD 0 */
+ u8 lpcmemhost_ue_status; /* DWORD 0 */
+ u8 mgmt_mac_ue_status; /* DWORD 0 */
+ u8 mpu_iram_ue_status; /* DWORD 0 */
+ u8 pcs0online_ue_status; /* DWORD 0 */
+ u8 pcs1online_ue_status; /* DWORD 0 */
+ u8 pctl0_ue_status; /* DWORD 0 */
+ u8 pctl1_ue_status; /* DWORD 0 */
+ u8 pmem_ue_status; /* DWORD 0 */
+ u8 rr_ue_status; /* DWORD 0 */
+ u8 rxpp_ue_status; /* DWORD 0 */
+ u8 txpb_ue_status; /* DWORD 0 */
+ u8 txp_ue_status; /* DWORD 0 */
+ u8 xaui_ue_status; /* DWORD 0 */
+ u8 arm_ue_status; /* DWORD 0 */
+ u8 ipc_ue_status; /* DWORD 0 */
+ u8 rsvd0[16]; /* DWORD 0 */
+} __packed;
+struct PCICFG_UE_STATUS_HI_CSR_AMAP {
+ u32 dw[1];
+};
+
+/* Unrecoverable Error Mask (Low) Register. Each bit, when set to one,
+ * will mask the associated Unrecoverable Error status bit from notification
+ * of Unrecoverable Error to the host CPU and/or Server Managment chip and the
+ * transitioning of all BladeEngine units to an Offline state.
+ */
+struct BE_PCICFG_UE_STATUS_LOW_MASK_CSR_AMAP {
+ u8 cev_ue_mask; /* DWORD 0 */
+ u8 ctx_ue_mask; /* DWORD 0 */
+ u8 dbuf_ue_mask; /* DWORD 0 */
+ u8 erx_ue_mask; /* DWORD 0 */
+ u8 host_ue_mask; /* DWORD 0 */
+ u8 mpu_ue_mask; /* DWORD 0 */
+ u8 ndma_ue_mask; /* DWORD 0 */
+ u8 ptc_ue_mask; /* DWORD 0 */
+ u8 rdma_ue_mask; /* DWORD 0 */
+ u8 rxf_ue_mask; /* DWORD 0 */
+ u8 rxips_ue_mask; /* DWORD 0 */
+ u8 rxulp0_ue_mask; /* DWORD 0 */
+ u8 rxulp1_ue_mask; /* DWORD 0 */
+ u8 rxulp2_ue_mask; /* DWORD 0 */
+ u8 tim_ue_mask; /* DWORD 0 */
+ u8 tpost_ue_mask; /* DWORD 0 */
+ u8 tpre_ue_mask; /* DWORD 0 */
+ u8 txips_ue_mask; /* DWORD 0 */
+ u8 txulp0_ue_mask; /* DWORD 0 */
+ u8 txulp1_ue_mask; /* DWORD 0 */
+ u8 uc_ue_mask; /* DWORD 0 */
+ u8 wdma_ue_mask; /* DWORD 0 */
+ u8 txulp2_ue_mask; /* DWORD 0 */
+ u8 host1_ue_mask; /* DWORD 0 */
+ u8 p0_ob_link_ue_mask; /* DWORD 0 */
+ u8 p1_ob_link_ue_mask; /* DWORD 0 */
+ u8 host_gpio_ue_mask; /* DWORD 0 */
+ u8 mbox_netw_ue_mask; /* DWORD 0 */
+ u8 mbox_stor_ue_mask; /* DWORD 0 */
+ u8 axgmac0_ue_mask; /* DWORD 0 */
+ u8 axgmac1_ue_mask; /* DWORD 0 */
+ u8 mpu_intpend_ue_mask; /* DWORD 0 */
+} __packed;
+struct PCICFG_UE_STATUS_LOW_MASK_CSR_AMAP {
+ u32 dw[1];
+};
+
+/* Unrecoverable Error Mask (High) Register. Each bit, when set to one,
+ * will mask the associated Unrecoverable Error status bit from notification
+ * of Unrecoverable Error to the host CPU and/or Server Managment chip and the
+ * transitioning of all BladeEngine units to an Offline state.
+ */
+struct BE_PCICFG_UE_STATUS_HI_MASK_CSR_AMAP {
+ u8 jtag_ue_mask; /* DWORD 0 */
+ u8 lpcmemhost_ue_mask; /* DWORD 0 */
+ u8 mgmt_mac_ue_mask; /* DWORD 0 */
+ u8 mpu_iram_ue_mask; /* DWORD 0 */
+ u8 pcs0online_ue_mask; /* DWORD 0 */
+ u8 pcs1online_ue_mask; /* DWORD 0 */
+ u8 pctl0_ue_mask; /* DWORD 0 */
+ u8 pctl1_ue_mask; /* DWORD 0 */
+ u8 pmem_ue_mask; /* DWORD 0 */
+ u8 rr_ue_mask; /* DWORD 0 */
+ u8 rxpp_ue_mask; /* DWORD 0 */
+ u8 txpb_ue_mask; /* DWORD 0 */
+ u8 txp_ue_mask; /* DWORD 0 */
+ u8 xaui_ue_mask; /* DWORD 0 */
+ u8 arm_ue_mask; /* DWORD 0 */
+ u8 ipc_ue_mask; /* DWORD 0 */
+ u8 rsvd0[16]; /* DWORD 0 */
+} __packed;
+struct PCICFG_UE_STATUS_HI_MASK_CSR_AMAP {
+ u32 dw[1];
+};
+
+/* Online Control Register 0. This register controls various units within
+ * BladeEngine being in an Online or Offline state.
+ */
+struct BE_PCICFG_ONLINE0_CSR_AMAP {
+ u8 cev_online; /* DWORD 0 */
+ u8 ctx_online; /* DWORD 0 */
+ u8 dbuf_online; /* DWORD 0 */
+ u8 erx_online; /* DWORD 0 */
+ u8 host_online; /* DWORD 0 */
+ u8 mpu_online; /* DWORD 0 */
+ u8 ndma_online; /* DWORD 0 */
+ u8 ptc_online; /* DWORD 0 */
+ u8 rdma_online; /* DWORD 0 */
+ u8 rxf_online; /* DWORD 0 */
+ u8 rxips_online; /* DWORD 0 */
+ u8 rxulp0_online; /* DWORD 0 */
+ u8 rxulp1_online; /* DWORD 0 */
+ u8 rxulp2_online; /* DWORD 0 */
+ u8 tim_online; /* DWORD 0 */
+ u8 tpost_online; /* DWORD 0 */
+ u8 tpre_online; /* DWORD 0 */
+ u8 txips_online; /* DWORD 0 */
+ u8 txulp0_online; /* DWORD 0 */
+ u8 txulp1_online; /* DWORD 0 */
+ u8 uc_online; /* DWORD 0 */
+ u8 wdma_online; /* DWORD 0 */
+ u8 txulp2_online; /* DWORD 0 */
+ u8 host1_online; /* DWORD 0 */
+ u8 p0_ob_link_online; /* DWORD 0 */
+ u8 p1_ob_link_online; /* DWORD 0 */
+ u8 host_gpio_online; /* DWORD 0 */
+ u8 mbox_netw_online; /* DWORD 0 */
+ u8 mbox_stor_online; /* DWORD 0 */
+ u8 axgmac0_online; /* DWORD 0 */
+ u8 axgmac1_online; /* DWORD 0 */
+ u8 mpu_intpend_online; /* DWORD 0 */
+} __packed;
+struct PCICFG_ONLINE0_CSR_AMAP {
+ u32 dw[1];
+};
+
+/* Online Control Register 1. This register controls various units within
+ * BladeEngine being in an Online or Offline state.
+ */
+struct BE_PCICFG_ONLINE1_CSR_AMAP {
+ u8 jtag_online; /* DWORD 0 */
+ u8 lpcmemhost_online; /* DWORD 0 */
+ u8 mgmt_mac_online; /* DWORD 0 */
+ u8 mpu_iram_online; /* DWORD 0 */
+ u8 pcs0online_online; /* DWORD 0 */
+ u8 pcs1online_online; /* DWORD 0 */
+ u8 pctl0_online; /* DWORD 0 */
+ u8 pctl1_online; /* DWORD 0 */
+ u8 pmem_online; /* DWORD 0 */
+ u8 rr_online; /* DWORD 0 */
+ u8 rxpp_online; /* DWORD 0 */
+ u8 txpb_online; /* DWORD 0 */
+ u8 txp_online; /* DWORD 0 */
+ u8 xaui_online; /* DWORD 0 */
+ u8 arm_online; /* DWORD 0 */
+ u8 ipc_online; /* DWORD 0 */
+ u8 rsvd0[16]; /* DWORD 0 */
+} __packed;
+struct PCICFG_ONLINE1_CSR_AMAP {
+ u32 dw[1];
+};
+
+/* Host Timer Register. */
+struct BE_PCICFG_HOST_TIMER_INT_CTRL_CSR_AMAP {
+ u8 hosttimer[24]; /* DWORD 0 */
+ u8 hostintr; /* DWORD 0 */
+ u8 rsvd0[7]; /* DWORD 0 */
+} __packed;
+struct PCICFG_HOST_TIMER_INT_CTRL_CSR_AMAP {
+ u32 dw[1];
+};
+
+/* Scratchpad Register (for software use). */
+struct BE_PCICFG_SCRATCHPAD_CSR_AMAP {
+ u8 scratchpad[32]; /* DWORD 0 */
+} __packed;
+struct PCICFG_SCRATCHPAD_CSR_AMAP {
+ u32 dw[1];
+};
+
+/* PCI Express Capabilities Register. */
+struct BE_PCICFG_PCIE_CAP_CSR_AMAP {
+ u8 capid[8]; /* DWORD 0 */
+ u8 nextcap[8]; /* DWORD 0 */
+ u8 capver[4]; /* DWORD 0 */
+ u8 devport[4]; /* DWORD 0 */
+ u8 rsvd0[6]; /* DWORD 0 */
+ u8 rsvd1[2]; /* DWORD 0 */
+} __packed;
+struct PCICFG_PCIE_CAP_CSR_AMAP {
+ u32 dw[1];
+};
+
+/* PCI Express Device Capabilities Register. */
+struct BE_PCICFG_PCIE_DEVCAP_CSR_AMAP {
+ u8 payload[3]; /* DWORD 0 */
+ u8 rsvd0[3]; /* DWORD 0 */
+ u8 lo_lat[3]; /* DWORD 0 */
+ u8 l1_lat[3]; /* DWORD 0 */
+ u8 rsvd1[3]; /* DWORD 0 */
+ u8 rsvd2[3]; /* DWORD 0 */
+ u8 pwr_value[8]; /* DWORD 0 */
+ u8 pwr_scale[2]; /* DWORD 0 */
+ u8 rsvd3[4]; /* DWORD 0 */
+} __packed;
+struct PCICFG_PCIE_DEVCAP_CSR_AMAP {
+ u32 dw[1];
+};
+
+/* PCI Express Device Control/Status Registers. */
+struct BE_PCICFG_PCIE_CONTROL_STATUS_CSR_AMAP {
+ u8 CorrErrReportEn; /* DWORD 0 */
+ u8 NonFatalErrReportEn; /* DWORD 0 */
+ u8 FatalErrReportEn; /* DWORD 0 */
+ u8 UnsuppReqReportEn; /* DWORD 0 */
+ u8 EnableRelaxOrder; /* DWORD 0 */
+ u8 Max_Payload_Size[3]; /* DWORD 0 */
+ u8 ExtendTagFieldEnable; /* DWORD 0 */
+ u8 PhantomFnEnable; /* DWORD 0 */
+ u8 AuxPwrPMEnable; /* DWORD 0 */
+ u8 EnableNoSnoop; /* DWORD 0 */
+ u8 Max_Read_Req_Size[3]; /* DWORD 0 */
+ u8 rsvd0; /* DWORD 0 */
+ u8 CorrErrDetect; /* DWORD 0 */
+ u8 NonFatalErrDetect; /* DWORD 0 */
+ u8 FatalErrDetect; /* DWORD 0 */
+ u8 UnsuppReqDetect; /* DWORD 0 */
+ u8 AuxPwrDetect; /* DWORD 0 */
+ u8 TransPending; /* DWORD 0 */
+ u8 rsvd1[10]; /* DWORD 0 */
+} __packed;
+struct PCICFG_PCIE_CONTROL_STATUS_CSR_AMAP {
+ u32 dw[1];
+};
+
+/* PCI Express Link Capabilities Register. */
+struct BE_PCICFG_PCIE_LINK_CAP_CSR_AMAP {
+ u8 MaxLinkSpeed[4]; /* DWORD 0 */
+ u8 MaxLinkWidth[6]; /* DWORD 0 */
+ u8 ASPMSupport[2]; /* DWORD 0 */
+ u8 L0sExitLat[3]; /* DWORD 0 */
+ u8 L1ExitLat[3]; /* DWORD 0 */
+ u8 rsvd0[6]; /* DWORD 0 */
+ u8 PortNum[8]; /* DWORD 0 */
+} __packed;
+struct PCICFG_PCIE_LINK_CAP_CSR_AMAP {
+ u32 dw[1];
+};
+
+/* PCI Express Link Status Register. */
+struct BE_PCICFG_PCIE_LINK_STATUS_CSR_AMAP {
+ u8 ASPMCtl[2]; /* DWORD 0 */
+ u8 rsvd0; /* DWORD 0 */
+ u8 ReadCmplBndry; /* DWORD 0 */
+ u8 LinkDisable; /* DWORD 0 */
+ u8 RetrainLink; /* DWORD 0 */
+ u8 CommonClkConfig; /* DWORD 0 */
+ u8 ExtendSync; /* DWORD 0 */
+ u8 rsvd1[8]; /* DWORD 0 */
+ u8 LinkSpeed[4]; /* DWORD 0 */
+ u8 NegLinkWidth[6]; /* DWORD 0 */
+ u8 LinkTrainErr; /* DWORD 0 */
+ u8 LinkTrain; /* DWORD 0 */
+ u8 SlotClkConfig; /* DWORD 0 */
+ u8 rsvd2[3]; /* DWORD 0 */
+} __packed;
+struct PCICFG_PCIE_LINK_STATUS_CSR_AMAP {
+ u32 dw[1];
+};
+
+/* PCI Express MSI Configuration Register. */
+struct BE_PCICFG_MSI_CSR_AMAP {
+ u8 capid[8]; /* DWORD 0 */
+ u8 nextptr[8]; /* DWORD 0 */
+ u8 tablesize[11]; /* DWORD 0 */
+ u8 rsvd0[3]; /* DWORD 0 */
+ u8 funcmask; /* DWORD 0 */
+ u8 en; /* DWORD 0 */
+} __packed;
+struct PCICFG_MSI_CSR_AMAP {
+ u32 dw[1];
+};
+
+/* MSI-X Table Offset Register. */
+struct BE_PCICFG_MSIX_TABLE_CSR_AMAP {
+ u8 tablebir[3]; /* DWORD 0 */
+ u8 offset[29]; /* DWORD 0 */
+} __packed;
+struct PCICFG_MSIX_TABLE_CSR_AMAP {
+ u32 dw[1];
+};
+
+/* MSI-X PBA Offset Register. */
+struct BE_PCICFG_MSIX_PBA_CSR_AMAP {
+ u8 pbabir[3]; /* DWORD 0 */
+ u8 offset[29]; /* DWORD 0 */
+} __packed;
+struct PCICFG_MSIX_PBA_CSR_AMAP {
+ u32 dw[1];
+};
+
+/* PCI Express MSI-X Message Vector Control Register. */
+struct BE_PCICFG_MSIX_VECTOR_CONTROL_CSR_AMAP {
+ u8 vector_control; /* DWORD 0 */
+ u8 rsvd0[31]; /* DWORD 0 */
+} __packed;
+struct PCICFG_MSIX_VECTOR_CONTROL_CSR_AMAP {
+ u32 dw[1];
+};
+
+/* PCI Express MSI-X Message Data Register. */
+struct BE_PCICFG_MSIX_MSG_DATA_CSR_AMAP {
+ u8 data[16]; /* DWORD 0 */
+ u8 rsvd0[16]; /* DWORD 0 */
+} __packed;
+struct PCICFG_MSIX_MSG_DATA_CSR_AMAP {
+ u32 dw[1];
+};
+
+/* PCI Express MSI-X Message Address Register - High Part. */
+struct BE_PCICFG_MSIX_MSG_ADDR_HI_CSR_AMAP {
+ u8 addr[32]; /* DWORD 0 */
+} __packed;
+struct PCICFG_MSIX_MSG_ADDR_HI_CSR_AMAP {
+ u32 dw[1];
+};
+
+/* PCI Express MSI-X Message Address Register - Low Part. */
+struct BE_PCICFG_MSIX_MSG_ADDR_LO_CSR_AMAP {
+ u8 rsvd0[2]; /* DWORD 0 */
+ u8 addr[30]; /* DWORD 0 */
+} __packed;
+struct PCICFG_MSIX_MSG_ADDR_LO_CSR_AMAP {
+ u32 dw[1];
+};
+
+struct BE_PCICFG_ANON_18_RSVD_AMAP {
+ u8 rsvd0[32]; /* DWORD 0 */
+} __packed;
+struct PCICFG_ANON_18_RSVD_AMAP {
+ u32 dw[1];
+};
+
+struct BE_PCICFG_ANON_19_RSVD_AMAP {
+ u8 rsvd0[32]; /* DWORD 0 */
+} __packed;
+struct PCICFG_ANON_19_RSVD_AMAP {
+ u32 dw[1];
+};
+
+struct BE_PCICFG_ANON_20_RSVD_AMAP {
+ u8 rsvd0[32]; /* DWORD 0 */
+ u8 rsvd1[25][32]; /* DWORD 1 */
+} __packed;
+struct PCICFG_ANON_20_RSVD_AMAP {
+ u32 dw[26];
+};
+
+struct BE_PCICFG_ANON_21_RSVD_AMAP {
+ u8 rsvd0[32]; /* DWORD 0 */
+ u8 rsvd1[1919][32]; /* DWORD 1 */
+} __packed;
+struct PCICFG_ANON_21_RSVD_AMAP {
+ u32 dw[1920];
+};
+
+struct BE_PCICFG_ANON_22_MESSAGE_AMAP {
+ struct BE_PCICFG_MSIX_VECTOR_CONTROL_CSR_AMAP vec_ctrl;
+ struct BE_PCICFG_MSIX_MSG_DATA_CSR_AMAP msg_data;
+ struct BE_PCICFG_MSIX_MSG_ADDR_HI_CSR_AMAP addr_hi;
+ struct BE_PCICFG_MSIX_MSG_ADDR_LO_CSR_AMAP addr_low;
+} __packed;
+struct PCICFG_ANON_22_MESSAGE_AMAP {
+ u32 dw[4];
+};
+
+struct BE_PCICFG_ANON_23_RSVD_AMAP {
+ u8 rsvd0[32]; /* DWORD 0 */
+ u8 rsvd1[895][32]; /* DWORD 1 */
+} __packed;
+struct PCICFG_ANON_23_RSVD_AMAP {
+ u32 dw[896];
+};
+
+/* These PCI Configuration Space registers are for the Storage Function of
+ * BladeEngine (Function 0). In the memory map of the registers below their
+ * table,
+ */
+struct BE_PCICFG0_CSRMAP_AMAP {
+ struct BE_PCICFG_ID_CSR_AMAP id;
+ u8 rsvd0[32]; /* DWORD 1 */
+ u8 rsvd1[32]; /* DWORD 2 */
+ u8 rsvd2[32]; /* DWORD 3 */
+ struct BE_PCICFG_IOBAR_CSR_AMAP iobar;
+ struct BE_PCICFG_MEMBAR0_CSR_AMAP membar0;
+ struct BE_PCICFG_MEMBAR1_LO_CSR_AMAP membar1_lo;
+ struct BE_PCICFG_MEMBAR1_HI_CSR_AMAP membar1_hi;
+ struct BE_PCICFG_MEMBAR2_LO_CSR_AMAP membar2_lo;
+ struct BE_PCICFG_MEMBAR2_HI_CSR_AMAP membar2_hi;
+ u8 rsvd3[32]; /* DWORD 10 */
+ struct BE_PCICFG_SUBSYSTEM_ID_F0_CSR_AMAP subsystem_id;
+ u8 rsvd4[32]; /* DWORD 12 */
+ u8 rsvd5[32]; /* DWORD 13 */
+ u8 rsvd6[32]; /* DWORD 14 */
+ u8 rsvd7[32]; /* DWORD 15 */
+ struct BE_PCICFG_SEMAPHORE_CSR_AMAP semaphore[4];
+ struct BE_PCICFG_SOFT_RESET_CSR_AMAP soft_reset;
+ u8 rsvd8[32]; /* DWORD 21 */
+ struct BE_PCICFG_SCRATCHPAD_CSR_AMAP scratchpad;
+ u8 rsvd9[32]; /* DWORD 23 */
+ u8 rsvd10[32]; /* DWORD 24 */
+ u8 rsvd11[32]; /* DWORD 25 */
+ u8 rsvd12[32]; /* DWORD 26 */
+ u8 rsvd13[32]; /* DWORD 27 */
+ u8 rsvd14[2][32]; /* DWORD 28 */
+ u8 rsvd15[32]; /* DWORD 30 */
+ u8 rsvd16[32]; /* DWORD 31 */
+ u8 rsvd17[8][32]; /* DWORD 32 */
+ struct BE_PCICFG_UE_STATUS_LOW_CSR_AMAP ue_status_low;
+ struct BE_PCICFG_UE_STATUS_HI_CSR_AMAP ue_status_hi;
+ struct BE_PCICFG_UE_STATUS_LOW_MASK_CSR_AMAP ue_status_low_mask;
+ struct BE_PCICFG_UE_STATUS_HI_MASK_CSR_AMAP ue_status_hi_mask;
+ struct BE_PCICFG_ONLINE0_CSR_AMAP online0;
+ struct BE_PCICFG_ONLINE1_CSR_AMAP online1;
+ u8 rsvd18[32]; /* DWORD 46 */
+ u8 rsvd19[32]; /* DWORD 47 */
+ u8 rsvd20[32]; /* DWORD 48 */
+ u8 rsvd21[32]; /* DWORD 49 */
+ struct BE_PCICFG_HOST_TIMER_INT_CTRL_CSR_AMAP host_timer_int_ctrl;
+ u8 rsvd22[32]; /* DWORD 51 */
+ struct BE_PCICFG_PCIE_CAP_CSR_AMAP pcie_cap;
+ struct BE_PCICFG_PCIE_DEVCAP_CSR_AMAP pcie_devcap;
+ struct BE_PCICFG_PCIE_CONTROL_STATUS_CSR_AMAP pcie_control_status;
+ struct BE_PCICFG_PCIE_LINK_CAP_CSR_AMAP pcie_link_cap;
+ struct BE_PCICFG_PCIE_LINK_STATUS_CSR_AMAP pcie_link_status;
+ struct BE_PCICFG_MSI_CSR_AMAP msi;
+ struct BE_PCICFG_MSIX_TABLE_CSR_AMAP msix_table_offset;
+ struct BE_PCICFG_MSIX_PBA_CSR_AMAP msix_pba_offset;
+ u8 rsvd23[32]; /* DWORD 60 */
+ u8 rsvd24[32]; /* DWORD 61 */
+ u8 rsvd25[32]; /* DWORD 62 */
+ u8 rsvd26[32]; /* DWORD 63 */
+ u8 rsvd27[32]; /* DWORD 64 */
+ u8 rsvd28[32]; /* DWORD 65 */
+ u8 rsvd29[32]; /* DWORD 66 */
+ u8 rsvd30[32]; /* DWORD 67 */
+ u8 rsvd31[32]; /* DWORD 68 */
+ u8 rsvd32[32]; /* DWORD 69 */
+ u8 rsvd33[32]; /* DWORD 70 */
+ u8 rsvd34[32]; /* DWORD 71 */
+ u8 rsvd35[32]; /* DWORD 72 */
+ u8 rsvd36[32]; /* DWORD 73 */
+ u8 rsvd37[32]; /* DWORD 74 */
+ u8 rsvd38[32]; /* DWORD 75 */
+ u8 rsvd39[32]; /* DWORD 76 */
+ u8 rsvd40[32]; /* DWORD 77 */
+ u8 rsvd41[32]; /* DWORD 78 */
+ u8 rsvd42[32]; /* DWORD 79 */
+ u8 rsvd43[32]; /* DWORD 80 */
+ u8 rsvd44[32]; /* DWORD 81 */
+ u8 rsvd45[32]; /* DWORD 82 */
+ u8 rsvd46[32]; /* DWORD 83 */
+ u8 rsvd47[32]; /* DWORD 84 */
+ u8 rsvd48[32]; /* DWORD 85 */
+ u8 rsvd49[32]; /* DWORD 86 */
+ u8 rsvd50[32]; /* DWORD 87 */
+ u8 rsvd51[32]; /* DWORD 88 */
+ u8 rsvd52[32]; /* DWORD 89 */
+ u8 rsvd53[32]; /* DWORD 90 */
+ u8 rsvd54[32]; /* DWORD 91 */
+ u8 rsvd55[32]; /* DWORD 92 */
+ u8 rsvd56[832]; /* DWORD 93 */
+ u8 rsvd57[32]; /* DWORD 119 */
+ u8 rsvd58[32]; /* DWORD 120 */
+ u8 rsvd59[32]; /* DWORD 121 */
+ u8 rsvd60[32]; /* DWORD 122 */
+ u8 rsvd61[32]; /* DWORD 123 */
+ u8 rsvd62[32]; /* DWORD 124 */
+ u8 rsvd63[32]; /* DWORD 125 */
+ u8 rsvd64[32]; /* DWORD 126 */
+ u8 rsvd65[32]; /* DWORD 127 */
+ u8 rsvd66[61440]; /* DWORD 128 */
+ struct BE_PCICFG_ANON_22_MESSAGE_AMAP message[32];
+ u8 rsvd67[28672]; /* DWORD 2176 */
+ u8 rsvd68[32]; /* DWORD 3072 */
+ u8 rsvd69[1023][32]; /* DWORD 3073 */
+} __packed;
+struct PCICFG0_CSRMAP_AMAP {
+ u32 dw[4096];
+};
+
+struct BE_PCICFG_ANON_24_RSVD_AMAP {
+ u8 rsvd0[32]; /* DWORD 0 */
+} __packed;
+struct PCICFG_ANON_24_RSVD_AMAP {
+ u32 dw[1];
+};
+
+struct BE_PCICFG_ANON_25_RSVD_AMAP {
+ u8 rsvd0[32]; /* DWORD 0 */
+} __packed;
+struct PCICFG_ANON_25_RSVD_AMAP {
+ u32 dw[1];
+};
+
+struct BE_PCICFG_ANON_26_RSVD_AMAP {
+ u8 rsvd0[32]; /* DWORD 0 */
+} __packed;
+struct PCICFG_ANON_26_RSVD_AMAP {
+ u32 dw[1];
+};
+
+struct BE_PCICFG_ANON_27_RSVD_AMAP {
+ u8 rsvd0[32]; /* DWORD 0 */
+ u8 rsvd1[32]; /* DWORD 1 */
+} __packed;
+struct PCICFG_ANON_27_RSVD_AMAP {
+ u32 dw[2];
+};
+
+struct BE_PCICFG_ANON_28_RSVD_AMAP {
+ u8 rsvd0[32]; /* DWORD 0 */
+ u8 rsvd1[3][32]; /* DWORD 1 */
+} __packed;
+struct PCICFG_ANON_28_RSVD_AMAP {
+ u32 dw[4];
+};
+
+struct BE_PCICFG_ANON_29_RSVD_AMAP {
+ u8 rsvd0[32]; /* DWORD 0 */
+ u8 rsvd1[36][32]; /* DWORD 1 */
+} __packed;
+struct PCICFG_ANON_29_RSVD_AMAP {
+ u32 dw[37];
+};
+
+struct BE_PCICFG_ANON_30_RSVD_AMAP {
+ u8 rsvd0[32]; /* DWORD 0 */
+ u8 rsvd1[1930][32]; /* DWORD 1 */
+} __packed;
+struct PCICFG_ANON_30_RSVD_AMAP {
+ u32 dw[1931];
+};
+
+struct BE_PCICFG_ANON_31_MESSAGE_AMAP {
+ struct BE_PCICFG_MSIX_VECTOR_CONTROL_CSR_AMAP vec_ctrl;
+ struct BE_PCICFG_MSIX_MSG_DATA_CSR_AMAP msg_data;
+ struct BE_PCICFG_MSIX_MSG_ADDR_HI_CSR_AMAP addr_hi;
+ struct BE_PCICFG_MSIX_MSG_ADDR_LO_CSR_AMAP addr_low;
+} __packed;
+struct PCICFG_ANON_31_MESSAGE_AMAP {
+ u32 dw[4];
+};
+
+struct BE_PCICFG_ANON_32_RSVD_AMAP {
+ u8 rsvd0[32]; /* DWORD 0 */
+ u8 rsvd1[895][32]; /* DWORD 1 */
+} __packed;
+struct PCICFG_ANON_32_RSVD_AMAP {
+ u32 dw[896];
+};
+
+/* This PCI configuration space register map is for the Networking Function of
+ * BladeEngine (Function 1).
+ */
+struct BE_PCICFG1_CSRMAP_AMAP {
+ struct BE_PCICFG_ID_CSR_AMAP id;
+ u8 rsvd0[32]; /* DWORD 1 */
+ u8 rsvd1[32]; /* DWORD 2 */
+ u8 rsvd2[32]; /* DWORD 3 */
+ struct BE_PCICFG_IOBAR_CSR_AMAP iobar;
+ struct BE_PCICFG_MEMBAR0_CSR_AMAP membar0;
+ struct BE_PCICFG_MEMBAR1_LO_CSR_AMAP membar1_lo;
+ struct BE_PCICFG_MEMBAR1_HI_CSR_AMAP membar1_hi;
+ struct BE_PCICFG_MEMBAR2_LO_CSR_AMAP membar2_lo;
+ struct BE_PCICFG_MEMBAR2_HI_CSR_AMAP membar2_hi;
+ u8 rsvd3[32]; /* DWORD 10 */
+ struct BE_PCICFG_SUBSYSTEM_ID_F1_CSR_AMAP subsystem_id;
+ u8 rsvd4[32]; /* DWORD 12 */
+ u8 rsvd5[32]; /* DWORD 13 */
+ u8 rsvd6[32]; /* DWORD 14 */
+ u8 rsvd7[32]; /* DWORD 15 */
+ struct BE_PCICFG_SEMAPHORE_CSR_AMAP semaphore[4];
+ struct BE_PCICFG_SOFT_RESET_CSR_AMAP soft_reset;
+ u8 rsvd8[32]; /* DWORD 21 */
+ struct BE_PCICFG_SCRATCHPAD_CSR_AMAP scratchpad;
+ u8 rsvd9[32]; /* DWORD 23 */
+ u8 rsvd10[32]; /* DWORD 24 */
+ u8 rsvd11[32]; /* DWORD 25 */
+ u8 rsvd12[32]; /* DWORD 26 */
+ u8 rsvd13[32]; /* DWORD 27 */
+ u8 rsvd14[2][32]; /* DWORD 28 */
+ u8 rsvd15[32]; /* DWORD 30 */
+ u8 rsvd16[32]; /* DWORD 31 */
+ u8 rsvd17[8][32]; /* DWORD 32 */
+ struct BE_PCICFG_UE_STATUS_LOW_CSR_AMAP ue_status_low;
+ struct BE_PCICFG_UE_STATUS_HI_CSR_AMAP ue_status_hi;
+ struct BE_PCICFG_UE_STATUS_LOW_MASK_CSR_AMAP ue_status_low_mask;
+ struct BE_PCICFG_UE_STATUS_HI_MASK_CSR_AMAP ue_status_hi_mask;
+ struct BE_PCICFG_ONLINE0_CSR_AMAP online0;
+ struct BE_PCICFG_ONLINE1_CSR_AMAP online1;
+ u8 rsvd18[32]; /* DWORD 46 */
+ u8 rsvd19[32]; /* DWORD 47 */
+ u8 rsvd20[32]; /* DWORD 48 */
+ u8 rsvd21[32]; /* DWORD 49 */
+ struct BE_PCICFG_HOST_TIMER_INT_CTRL_CSR_AMAP host_timer_int_ctrl;
+ u8 rsvd22[32]; /* DWORD 51 */
+ struct BE_PCICFG_PCIE_CAP_CSR_AMAP pcie_cap;
+ struct BE_PCICFG_PCIE_DEVCAP_CSR_AMAP pcie_devcap;
+ struct BE_PCICFG_PCIE_CONTROL_STATUS_CSR_AMAP pcie_control_status;
+ struct BE_PCICFG_PCIE_LINK_CAP_CSR_AMAP pcie_link_cap;
+ struct BE_PCICFG_PCIE_LINK_STATUS_CSR_AMAP pcie_link_status;
+ struct BE_PCICFG_MSI_CSR_AMAP msi;
+ struct BE_PCICFG_MSIX_TABLE_CSR_AMAP msix_table_offset;
+ struct BE_PCICFG_MSIX_PBA_CSR_AMAP msix_pba_offset;
+ u8 rsvd23[64]; /* DWORD 60 */
+ u8 rsvd24[32]; /* DWORD 62 */
+ u8 rsvd25[32]; /* DWORD 63 */
+ u8 rsvd26[32]; /* DWORD 64 */
+ u8 rsvd27[32]; /* DWORD 65 */
+ u8 rsvd28[32]; /* DWORD 66 */
+ u8 rsvd29[32]; /* DWORD 67 */
+ u8 rsvd30[32]; /* DWORD 68 */
+ u8 rsvd31[32]; /* DWORD 69 */
+ u8 rsvd32[32]; /* DWORD 70 */
+ u8 rsvd33[32]; /* DWORD 71 */
+ u8 rsvd34[32]; /* DWORD 72 */
+ u8 rsvd35[32]; /* DWORD 73 */
+ u8 rsvd36[32]; /* DWORD 74 */
+ u8 rsvd37[128]; /* DWORD 75 */
+ u8 rsvd38[32]; /* DWORD 79 */
+ u8 rsvd39[1184]; /* DWORD 80 */
+ u8 rsvd40[61792]; /* DWORD 117 */
+ struct BE_PCICFG_ANON_31_MESSAGE_AMAP message[32];
+ u8 rsvd41[28672]; /* DWORD 2176 */
+ u8 rsvd42[32]; /* DWORD 3072 */
+ u8 rsvd43[1023][32]; /* DWORD 3073 */
+} __packed;
+struct PCICFG1_CSRMAP_AMAP {
+ u32 dw[4096];
+};
+
+#endif /* __pcicfg_amap_h__ */
diff --git a/drivers/staging/benet/post_codes.h b/drivers/staging/benet/post_codes.h
new file mode 100644
index 000000000000..6d1621f5f5fb
--- /dev/null
+++ b/drivers/staging/benet/post_codes.h
@@ -0,0 +1,111 @@
+/*
+ * 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:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+/*
+ * Autogenerated by srcgen version: 0127
+ */
+#ifndef __post_codes_amap_h__
+#define __post_codes_amap_h__
+
+/* --- MGMT_HBA_POST_STAGE_ENUM --- */
+#define POST_STAGE_POWER_ON_RESET (0) /* State after a cold or warm boot. */
+#define POST_STAGE_AWAITING_HOST_RDY (1) /* ARM boot code awaiting a
+ go-ahed from the host. */
+#define POST_STAGE_HOST_RDY (2) /* Host has given go-ahed to ARM. */
+#define POST_STAGE_BE_RESET (3) /* Host wants to reset chip, this is a chip
+ workaround */
+#define POST_STAGE_SEEPROM_CS_START (256) /* SEEPROM checksum
+ test start. */
+#define POST_STAGE_SEEPROM_CS_DONE (257) /* SEEPROM checksum test
+ done. */
+#define POST_STAGE_DDR_CONFIG_START (512) /* DDR configuration start. */
+#define POST_STAGE_DDR_CONFIG_DONE (513) /* DDR configuration done. */
+#define POST_STAGE_DDR_CALIBRATE_START (768) /* DDR calibration start. */
+#define POST_STAGE_DDR_CALIBRATE_DONE (769) /* DDR calibration done. */
+#define POST_STAGE_DDR_TEST_START (1024) /* DDR memory test start. */
+#define POST_STAGE_DDR_TEST_DONE (1025) /* DDR memory test done. */
+#define POST_STAGE_REDBOOT_INIT_START (1536) /* Redboot starts execution. */
+#define POST_STAGE_REDBOOT_INIT_DONE (1537) /* Redboot done execution. */
+#define POST_STAGE_FW_IMAGE_LOAD_START (1792) /* Firmware image load to
+ DDR start. */
+#define POST_STAGE_FW_IMAGE_LOAD_DONE (1793) /* Firmware image load
+ to DDR done. */
+#define POST_STAGE_ARMFW_START (2048) /* ARMfw runtime code
+ starts execution. */
+#define POST_STAGE_DHCP_QUERY_START (2304) /* DHCP server query start. */
+#define POST_STAGE_DHCP_QUERY_DONE (2305) /* DHCP server query done. */
+#define POST_STAGE_BOOT_TARGET_DISCOVERY_START (2560) /* Boot Target
+ Discovery Start. */
+#define POST_STAGE_BOOT_TARGET_DISCOVERY_DONE (2561) /* Boot Target
+ Discovery Done. */
+#define POST_STAGE_RC_OPTION_SET (2816) /* Remote configuration
+ option is set in SEEPROM */
+#define POST_STAGE_SWITCH_LINK (2817) /* Wait for link up on switch */
+#define POST_STAGE_SEND_ICDS_MESSAGE (2818) /* Send the ICDS message
+ to switch */
+#define POST_STAGE_PERFROM_TFTP (2819) /* Download xml using TFTP */
+#define POST_STAGE_PARSE_XML (2820) /* Parse XML file */
+#define POST_STAGE_DOWNLOAD_IMAGE (2821) /* Download IMAGE from
+ TFTP server */
+#define POST_STAGE_FLASH_IMAGE (2822) /* Flash the IMAGE */
+#define POST_STAGE_RC_DONE (2823) /* Remote configuration
+ complete */
+#define POST_STAGE_REBOOT_SYSTEM (2824) /* Upgrade IMAGE done,
+ reboot required */
+#define POST_STAGE_MAC_ADDRESS (3072) /* MAC Address Check */
+#define POST_STAGE_ARMFW_READY (49152) /* ARMfw is done with POST
+ and ready. */
+#define POST_STAGE_ARMFW_UE (61440) /* ARMfw has asserted an
+ unrecoverable error. The
+ lower 3 hex digits of the
+ stage code identify the
+ unique error code.
+ */
+
+/* This structure defines the format of the MPU semaphore
+ * register when used for POST.
+ */
+struct BE_MGMT_HBA_POST_STATUS_STRUCT_AMAP {
+ u8 stage[16]; /* DWORD 0 */
+ u8 rsvd0[10]; /* DWORD 0 */
+ u8 iscsi_driver_loaded; /* DWORD 0 */
+ u8 option_rom_installed; /* DWORD 0 */
+ u8 iscsi_ip_conflict; /* DWORD 0 */
+ u8 iscsi_no_ip; /* DWORD 0 */
+ u8 backup_fw; /* DWORD 0 */
+ u8 error; /* DWORD 0 */
+} __packed;
+struct MGMT_HBA_POST_STATUS_STRUCT_AMAP {
+ u32 dw[1];
+};
+
+/* --- MGMT_HBA_POST_DUMMY_BITS_ENUM --- */
+#define POST_BIT_ISCSI_LOADED (26)
+#define POST_BIT_OPTROM_INST (27)
+#define POST_BIT_BAD_IP_ADDR (28)
+#define POST_BIT_NO_IP_ADDR (29)
+#define POST_BIT_BACKUP_FW (30)
+#define POST_BIT_ERROR (31)
+
+/* --- MGMT_HBA_POST_DUMMY_VALUES_ENUM --- */
+#define POST_ISCSI_DRIVER_LOADED (67108864)
+#define POST_OPTROM_INSTALLED (134217728)
+#define POST_ISCSI_IP_ADDRESS_CONFLICT (268435456)
+#define POST_ISCSI_NO_IP_ADDRESS (536870912)
+#define POST_BACKUP_FW_LOADED (1073741824)
+#define POST_FATAL_ERROR (2147483648)
+
+#endif /* __post_codes_amap_h__ */
diff --git a/drivers/staging/benet/regmap.h b/drivers/staging/benet/regmap.h
new file mode 100644
index 000000000000..e816ba210e83
--- /dev/null
+++ b/drivers/staging/benet/regmap.h
@@ -0,0 +1,68 @@
+/*
+ * 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:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+/*
+ * Autogenerated by srcgen version: 0127
+ */
+#ifndef __regmap_amap_h__
+#define __regmap_amap_h__
+#include "pcicfg.h"
+#include "ep.h"
+#include "cev.h"
+#include "mpu.h"
+#include "doorbells.h"
+
+/*
+ * This is the control and status register map for BladeEngine, showing
+ * the relative size and offset of each sub-module. The CSR registers
+ * are identical for the network and storage PCI functions. The
+ * CSR map is shown below, followed by details of each block,
+ * in sub-sections. The sub-sections begin with a description
+ * of CSRs that are instantiated in multiple blocks.
+ */
+struct BE_BLADE_ENGINE_CSRMAP_AMAP {
+ struct BE_MPU_CSRMAP_AMAP mpu;
+ u8 rsvd0[8192]; /* DWORD 256 */
+ u8 rsvd1[8192]; /* DWORD 512 */
+ struct BE_CEV_CSRMAP_AMAP cev;
+ u8 rsvd2[8192]; /* DWORD 1024 */
+ u8 rsvd3[8192]; /* DWORD 1280 */
+ u8 rsvd4[8192]; /* DWORD 1536 */
+ u8 rsvd5[8192]; /* DWORD 1792 */
+ u8 rsvd6[8192]; /* DWORD 2048 */
+ u8 rsvd7[8192]; /* DWORD 2304 */
+ u8 rsvd8[8192]; /* DWORD 2560 */
+ u8 rsvd9[8192]; /* DWORD 2816 */
+ u8 rsvd10[8192]; /* DWORD 3072 */
+ u8 rsvd11[8192]; /* DWORD 3328 */
+ u8 rsvd12[8192]; /* DWORD 3584 */
+ u8 rsvd13[8192]; /* DWORD 3840 */
+ u8 rsvd14[8192]; /* DWORD 4096 */
+ u8 rsvd15[8192]; /* DWORD 4352 */
+ u8 rsvd16[8192]; /* DWORD 4608 */
+ u8 rsvd17[8192]; /* DWORD 4864 */
+ u8 rsvd18[8192]; /* DWORD 5120 */
+ u8 rsvd19[8192]; /* DWORD 5376 */
+ u8 rsvd20[8192]; /* DWORD 5632 */
+ u8 rsvd21[8192]; /* DWORD 5888 */
+ u8 rsvd22[8192]; /* DWORD 6144 */
+ u8 rsvd23[17152][32]; /* DWORD 6400 */
+} __packed;
+struct BLADE_ENGINE_CSRMAP_AMAP {
+ u32 dw[23552];
+};
+
+#endif /* __regmap_amap_h__ */