Skip to contentSkip to conversation

Neterion: New driver: Hardware init & configuration

PATCH In review Ramkrishna Vepa 4 participants 7 messages Mar 14, 2009 – Mar 17, 2009

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 6/10 Neterion: New driver: Hardware init & configuration

This patch takes care of Initialization and configuration steps of Neterion Inc's X3100 Series 10GbE PCIe I/O Virtualized Server Adapter.
- Device Initialization.
- Verification and setting of device config parameters.
- Allocation of Tx FIFO and Rx Ring descriptors (DTR).
- APIs to get various type of hw stats
- APIs to configure RTS (Receive Traffic Steering)

---

drivers/net/vxge/vxge-config.c +7576 -0
diff -urpN patch_5/drivers/net/vxge/vxge-config.c patch_6/drivers/net/vxge/vxge-config.c
@@ -0,0 +1,7576 @@
+/******************************************************************************
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License (GPL), incorporated herein by reference.
+ * Drivers based on or derived from this code fall under the GPL and must
+ * retain the authorship, copyright and license notice.  This file is not
+ * a complete program and may only be used when the entire operating
+ * system is licensed under the GPL.
+ * See the file COPYING in this distribution for more information.
+ ******************************************************************************/
+/*******************************************************************************
+ * vxge-config.c: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O
+ *                Virtualized Server Adapter.
+ * Copyright(c) 2002-2009 Neterion Inc.
+ ******************************************************************************/
+#include <linux/version.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "vxge-traffic.h"
+#include "vxge-config.h"
+
+/*
+ * __hw_channel_allocate - Allocate memory for channel
+ * @devh: Handle to the device object
+ * @vph: Handle to Virtual Path
+ * @type: Type of channel
+ * @length: Lengths of arrays
+ * @alloc_work_array: Flag to specify if work array is required
+ * @alloc_free_array: Flag to specify if free array is required
+ * @alloc_reserve_array: Flag to specify if reserve array is required
+ * @per_dtr_space: driver requested per dtr space to be allocated in priv
+ * @userdata: User data to be passed back in the callback
+ *
+ * This function allocates required memory for the channel and various arrays
+ * in the channel
+ */
+struct __hw_channel*
+__hw_channel_allocate(
+	struct __hw_device *hldev,
+	struct __hw_vpath_handle *vph,
+	enum __hw_channel_type type,
+	u32 length,
+	u32 alloc_work_array,
+	u32 alloc_free_array,
+	u32 alloc_reserve_array,
+	u32 per_dtr_space,
+	void *userdata)
+{
+	struct __hw_channel *channel;
+	int size = 0;
+	u32 vp_id;
+
+	vxge_assert((hldev != NULL) && (vph != NULL));
+
+	vp_id = ((struct __hw_vpath_handle *)vph)->vpath->vp_id;
+
+	switch (type) {
+	case VXGE_HW_CHANNEL_TYPE_FIFO:
+		size = sizeof(struct __hw_fifo);
+		break;
+	case VXGE_HW_CHANNEL_TYPE_RING:
+		size = sizeof(struct __hw_ring);
+		break;
+	default:
+		vxge_assert(size);
+		break;
+
+	}
+
+	channel = (struct __hw_channel *) vmalloc(size);
+	if (channel == NULL)
+		goto exit0;
+	memset(channel, 0, size);
+	vxge_list_init(&channel->item);
+
+	channel->common_reg = hldev->common_reg;
+	channel->first_vp_id = hldev->first_vp_id;
+	channel->type		= type;
+	channel->devh		= hldev;
+	channel->vph		= vph;
+
+	channel->userdata = userdata;
+	channel->per_dtr_space = per_dtr_space;
+
+	channel->length = length;
+	channel->vp_id	= vp_id;
+
+	if (alloc_work_array) {
+		channel->work_arr = (void **) vmalloc(sizeof(void *)*length);
+		if (channel->work_arr == NULL)
+			goto exit1;
+		memset(channel->work_arr, 0, sizeof(void *)*length);
+	}
+
+	channel->post_index = 0;
+	channel->compl_index = 0;
+
+	if (alloc_free_array) {
+		channel->free_arr = (void **) vmalloc(sizeof(void *)*length);
+		if (channel->free_arr == NULL)
+			goto exit1;
+		memset(channel->free_arr, 0, sizeof(void *)*length);
+	}
+
+	channel->free_ptr = length;
+
+	if (alloc_reserve_array) {
+		channel->reserve_arr =
+			(void **) vmalloc(sizeof(void *)*length);
+		if (channel->reserve_arr == NULL)
+			goto exit1;
+
+		memset(channel->reserve_arr, 0, sizeof(void *)*length);
+	}
+
+	channel->reserve_ptr = length;
+	channel->reserve_top = 0;
+
+	if (alloc_reserve_array) {
+		channel->orig_arr = (void **) vmalloc(sizeof(void *) * length);
+		if (channel->orig_arr == NULL)
+			goto exit1;
+
+		memset(channel->orig_arr, 0, sizeof(void *)*length);
+	}
+
+	channel->level_err = vxge_hw_device_error_level_get(hldev);
+	channel->level_trace = vxge_hw_device_trace_level_get(hldev);
+
+	return channel;
+exit1:
+	__hw_channel_free(channel);
+
+exit0:
+
+	return NULL;
+}
+
+/*
+ * __hw_channel_free - Free memory allocated for channel
+ * @channel: channel to be freed
+ *
+ * This function deallocates memory from the channel and various arrays
+ * in the channel
+ */
+void
+__hw_channel_free(
+	struct __hw_channel *channel)
+{
+	u32	vp_id = 0;
+	struct __hw_device  *hldev;
+
+	vxge_assert(channel != NULL);
+
+	hldev = (struct __hw_device  *)channel->devh;
+
+	vp_id = ((struct __hw_vpath_handle *)channel->vph)->vpath->vp_id;
+
+	if (channel->work_arr) {
+		vfree(channel->work_arr);
+		channel->work_arr = NULL;
+	}
+
+	if (channel->free_arr) {
+		vfree(channel->free_arr);
+		channel->free_arr = NULL;
+	}
+
+	if (channel->reserve_arr) {
+		vfree(channel->reserve_arr);
+		channel->reserve_arr = NULL;
+	}
+
+	if (channel->orig_arr) {
+		vfree(channel->orig_arr);
+		channel->orig_arr = NULL;
+	}
+
+	vfree(channel);
+
+}
+
+/*
+ * __hw_channel_initialize - Initialize a channel
+ * @channel: channel to be initialized
+ *
+ * This function initializes a channel by properly setting the
+ * various references
+ */
+enum vxge_hw_status
+__hw_channel_initialize(
+	struct __hw_channel *channel)
+{
+	u32 i;
+	struct __hw_virtualpath *vpath;
+
+	vxge_assert(channel != NULL);
+
+	vpath = (struct __hw_virtualpath *)((struct __hw_vpath_handle *) \
+						channel->vph)->vpath;
+	vxge_assert(vpath != NULL);
+
+	if ((channel->reserve_arr != NULL) && (channel->orig_arr != NULL)) {
+		for (i = 0; i < channel->length; i++)
+			channel->orig_arr[i] = channel->reserve_arr[i];
+	}
+
+	switch (channel->type) {
+	case VXGE_HW_CHANNEL_TYPE_FIFO:
+		vpath->fifoh = (struct __hw_fifo *)channel;
+		channel->stats = &((struct __hw_fifo *) \
+				channel)->stats->common_stats;
+		break;
+	case VXGE_HW_CHANNEL_TYPE_RING:
+		vpath->ringh = (struct __hw_ring *)channel;
+		channel->stats = &((struct __hw_ring *) \
+				channel)->stats->common_stats;
+		break;
+	default:
+		break;
+	}
+
+	return VXGE_HW_OK;
+}
+
+/*
+ * __hw_channel_reset - Resets a channel
+ * @channel: channel to be reset
+ *
+ * This function resets a channel by properly setting the various references
+ */
+enum vxge_hw_status
+__hw_channel_reset(
+	struct __hw_channel *channel)
+{
+	u32 i;
+	struct __hw_device *hldev;
+
+	vxge_assert(channel != NULL);
+
+	hldev = (struct __hw_device *)channel->devh;
+
+	for (i = 0; i < channel->length; i++) {
+		if (channel->reserve_arr != NULL)
+			channel->reserve_arr[i] = channel->orig_arr[i];
+		if (channel->free_arr != NULL)
+			channel->free_arr[i] = NULL;
+		if (channel->work_arr != NULL)
+			channel->work_arr[i] = NULL;
+	}
+	channel->free_ptr = channel->length;
+	channel->reserve_ptr = channel->length;
+	channel->reserve_top = 0;
+	channel->post_index = 0;
+	channel->compl_index = 0;
+
+	return VXGE_HW_OK;
+}
+
+/*
+ * __hw_device_pci_caps_list_process
+ * @hldev: HW device handle.
+ *
+ * Process PCI capabilities and initialize the offsets
+ */
+void
+__hw_device_pci_caps_list_process(struct __hw_device *hldev)
+{
+	u8 cap_id;
+	u16 next_ptr;
+	struct vxge_hw_pci_config *pci_config = &hldev->pci_config_space_bios;
+
+	vxge_assert(hldev != NULL);
+
+	next_ptr = pci_config->capabilities_pointer;
+
+	while (next_ptr != 0) {
+
+		cap_id = VXGE_HW_PCI_CAP_ID((((u8 *)pci_config)  +  next_ptr));
+
+		switch (cap_id) {
+
+		case VXGE_HW_PCI_CAP_ID_PM:
+			hldev->pci_caps.pm_cap_offset = next_ptr;
+			break;
+		case VXGE_HW_PCI_CAP_ID_VPD:
+			hldev->pci_caps.vpd_cap_offset = next_ptr;
+			break;
+		case VXGE_HW_PCI_CAP_ID_SLOTID:
+			hldev->pci_caps.sid_cap_offset = next_ptr;
+			break;
+		case VXGE_HW_PCI_CAP_ID_MSI:
+			hldev->pci_caps.msi_cap_offset = next_ptr;
+			break;
+		case VXGE_HW_PCI_CAP_ID_VS:
+			hldev->pci_caps.vs_cap_offset = next_ptr;
+			break;
+		case VXGE_HW_PCI_CAP_ID_SHPC:
+			hldev->pci_caps.shpc_cap_offset = next_ptr;
+			break;
+		case VXGE_HW_PCI_CAP_ID_PCIE:
+			hldev->pci_e_caps = next_ptr;
+			break;
+		case VXGE_HW_PCI_CAP_ID_MSIX:
+			hldev->pci_caps.msix_cap_offset = next_ptr;
+			break;
+		case VXGE_HW_PCI_CAP_ID_AGP:
+		case VXGE_HW_PCI_CAP_ID_CHSWP:
+		case VXGE_HW_PCI_CAP_ID_PCIX:
+		case VXGE_HW_PCI_CAP_ID_HT:
+		case VXGE_HW_PCI_CAP_ID_DBGPORT:
+		case VXGE_HW_PCI_CAP_ID_CPCICSR:
+		case VXGE_HW_PCI_CAP_ID_PCIBSVID:
+		case VXGE_HW_PCI_CAP_ID_AGP8X:
+		case VXGE_HW_PCI_CAP_ID_SECDEV:
+
+			break;
+		default:
+
+			break;
+		}
+
+		next_ptr =
+			VXGE_HW_PCI_CAP_NEXT((((u8 *)pci_config)  +  next_ptr));
+
+	}
+
+	if (VXGE_HW_PCI_CONFIG_SPACE_SIZE <= 0x100)
+		goto exit;
+
+	next_ptr = 0x100;
+
+	while (next_ptr != 0) {
+
+		cap_id = (u8)VXGE_HW_PCI_EXT_CAP_ID(
+				*(u32 *)(((u8 *)pci_config)  +  next_ptr));
+
+		switch (cap_id) {
+
+		case VXGE_HW_PCI_EXT_CAP_ID_ERR:
+			hldev->pci_e_ext_caps.err_cap_offset = next_ptr;
+			break;
+		case VXGE_HW_PCI_EXT_CAP_ID_VC:
+			hldev->pci_e_ext_caps.vc_cap_offset = next_ptr;
+			break;
+		case VXGE_HW_PCI_EXT_CAP_ID_DSN:
+			hldev->pci_e_ext_caps.dsn_cap_offset = next_ptr;
+			break;
+		case VXGE_HW_PCI_EXT_CAP_ID_PWR:
+			hldev->pci_e_ext_caps.pwr_budget_cap_offset = next_ptr;
+			break;
+
+		default:
+
+			break;
+		}
+
+		next_ptr = (u16)VXGE_HW_PCI_EXT_CAP_NEXT(
+				*(u32 *)(((u8 *)pci_config)  +  next_ptr));
+
+	}
+exit:
+
+	return;
+}
+
+/*
+ * __hw_device_pci_e_init
+ * @hldev: HW device handle.
+ *
+ * Initialize certain PCI/PCI-X configuration registers
+ * with recommended values. Save config space for future hw resets.
+ */
+void
+__hw_device_pci_e_init(struct __hw_device *hldev)
+{
+	int i;
+	u16 cmd = 0;
+	u16 device_id;
+	u8  revision;
+
+	vxge_assert(hldev != NULL);
+
+	/* Store PCI device ID and revision for future references where in we
+	 * decide Xena revision using PCI sub system ID */
+	pci_read_config_word(hldev->pdev,
+			vxge_offsetof(struct vxge_hw_pci_config_le, device_id),
+			&device_id);
+
+	pci_read_config_byte(hldev->pdev, vxge_offsetof(
+				struct vxge_hw_pci_config_le, revision),
+				&revision);
+
+	/* save original PCI config space to restore it on device_terminate() */
+	for (i = 0; i < VXGE_HW_PCI_CONFIG_SPACE_SIZE/4; i++) {
+		pci_read_config_dword(hldev->pdev, i * 4,
+				(u32 *)&hldev->pci_config_space_bios  +  i);
+	}
+
+	__hw_device_pci_caps_list_process(hldev);
+
+	/* Set the PErr Repconse bit and SERR in PCI command register. */
+	pci_read_config_word(hldev->pdev,
+			vxge_offsetof(struct vxge_hw_pci_config_le, command),
+			&cmd);
+	cmd |= 0x140;
+	pci_write_config_word(hldev->pdev,
+			vxge_offsetof(struct vxge_hw_pci_config_le, command),
+			cmd);
+
+	/* save PCI config space for future resets */
+	for (i = 0; i < VXGE_HW_PCI_CONFIG_SPACE_SIZE/4; i++) {
+		pci_read_config_dword(hldev->pdev, i * 4,
+					(u32 *)&hldev->pci_config_space  +  i);
+	}
+
+	return;
+}
+
+/*
+ * __hw_device_register_poll
+ * @reg: register to poll for
+ * @op: 0 - bit reset, 1 - bit set
+ * @mask: mask for logical "and" condition based on %op
+ * @max_millis: maximum time to try to poll in milliseconds
+ *
+ * Will poll certain register for specified amount of time.
+ * Will poll until masked bit is not cleared.
+ */
+enum vxge_hw_status
+__hw_device_register_poll(u64		*reg,
+			u32		op,
+			u64		mask,
+			u32		max_millis)
+{
+	u64 val64;
+	u32 i = 0;
+	enum vxge_hw_status ret = VXGE_HW_FAIL;
+
+	vxge_os_udelay(10);
+
+	do {
+		val64 = readq(reg);
+		if (op == 0 && !(val64 & mask))
+			return VXGE_HW_OK;
+		else if (op == 1 && (val64 & mask) == mask)
+			return VXGE_HW_OK;
+		vxge_os_udelay(100);
+	} while (++i <= 9);
+
+	do {
+		val64 = readq(reg);
+		if (op == 0 && !(val64 & mask))
+			return VXGE_HW_OK;
+		else if (op == 1 && (val64 & mask) == mask)
+			return VXGE_HW_OK;
+		vxge_os_udelay(1000);
+	} while (++i < max_millis);
+
+	return ret;
+}
+
+/*
+ * __hw_device_vpath_reset_in_prog_check - Check if vpath reset in progress
+ *
+ * @vpath_rst_in_prog: Address of vpath reset in progress register
+ *
+ * This routine checks the vpath reset in progress register is turned zero
+ */
+enum vxge_hw_status
+__hw_device_vpath_reset_in_prog_check(u64 *vpath_rst_in_prog)
+{
+	enum vxge_hw_status status;
+
+	status = __hw_device_register_poll(vpath_rst_in_prog, 0,
+			VXGE_HW_VPATH_RST_IN_PROG_VPATH_RST_IN_PROG(0x1ffff),
+			VXGE_HW_DEF_DEVICE_POLL_MILLIS);
+
+	return status;
+}
+
+/*
+ * __hw_device_toc_get
+ * @bar0: Address of BAR0 in PCI config
+ *
+ * This routine sets the sapper and reads the toc pointer and returns the
+ * memory mapped address of the toc
+ */
+struct vxge_hw_toc_reg *
+__hw_device_toc_get(u8 *bar0)
+{
+	u64 val64;
+	struct vxge_hw_toc_reg *toc = NULL;
+	enum vxge_hw_status status;
+	struct vxge_hw_legacy_reg *legacy_reg =
+		(struct vxge_hw_legacy_reg *)bar0;
+
+	status = __hw_legacy_swapper_set(legacy_reg);
+	if (status != VXGE_HW_OK)
+		goto exit;
+
+	val64 =	readq(&legacy_reg->toc_first_pointer);
+
+	toc = (struct vxge_hw_toc_reg *)(bar0+val64);
+
+exit:
+
+	return toc;
+}
+
+/*
+ * __hw_device_reg_addr_get
+ * @hldev: HW Device object.
+ *
+ * This routine sets the swapper and reads the toc pointer and initializes the
+ * register location pointers in the device object. It waits until the ric is
+ * completed initializing registers.
+ */
+enum vxge_hw_status
+__hw_device_reg_addr_get(struct __hw_device *hldev)
+{
+	u64 val64;
+	u32 i;
+	enum vxge_hw_status status = VXGE_HW_OK;
+
+	vxge_assert(hldev);
+
+	hldev->legacy_reg = (struct vxge_hw_legacy_reg *)hldev->bar0;
+
+	hldev->toc_reg = __hw_device_toc_get(hldev->bar0);
+	if (hldev->toc_reg  == NULL) {
+		status = VXGE_HW_FAIL;
+		goto exit;
+	}
+
+	val64 = readq(&hldev->toc_reg->toc_common_pointer);
+
+	hldev->common_reg =
+		(struct vxge_hw_common_reg *)(hldev->bar0  +  val64);
+
+	val64 = readq(&hldev->toc_reg->toc_memrepair_pointer);
+
+	hldev->memrepair_reg =
+		(struct vxge_hw_memrepair_reg *)(hldev->bar0  +  val64);
+
+	for (i = 0; i < VXGE_HW_TITAN_PCICFGMGMT_REG_SPACES; i++) {
+
+		val64 = readq(&hldev->toc_reg->toc_pcicfgmgmt_pointer[i]);
+
+		hldev->pcicfgmgmt_reg[i] = (struct vxge_hw_pcicfgmgmt_reg *) \
+						(hldev->bar0  +  val64);
+
+	}
+
+	val64 = readq(&hldev->toc_reg->toc_mrpcim_pointer);
+
+	hldev->mrpcim_reg =
+		(struct vxge_hw_mrpcim_reg *)(hldev->bar0  +  val64);
+
+	for (i = 0; i < VXGE_HW_TITAN_SRPCIM_REG_SPACES; i++) {
+
+		val64 = readq(&hldev->toc_reg->toc_srpcim_pointer[i]);
+
+		hldev->srpcim_reg[i] =
+			(struct vxge_hw_srpcim_reg *)(hldev->bar0  +  val64);
+
+	}
+
+	for (i = 0; i < VXGE_HW_TITAN_VPMGMT_REG_SPACES; i++) {
+
+		val64 = readq(&hldev->toc_reg->toc_vpmgmt_pointer[i]);
+
+		hldev->vpmgmt_reg[i] =
+			(struct vxge_hw_vpmgmt_reg *)(hldev->bar0  +  val64);
+
+	}
+
+	for (i = 0; i < VXGE_HW_TITAN_VPATH_REG_SPACES; i++) {
+
+		val64 = readq(&hldev->toc_reg->toc_vpath_pointer[i]);
+
+		hldev->vpath_reg[i] =
+			(struct vxge_hw_vpath_reg *)(hldev->bar0  +  val64);
+
+	}
+
+	val64 = readq(&hldev->toc_reg->toc_kdfc);
+
+	switch (VXGE_HW_TOC_GET_KDFC_INITIAL_BIR(val64)) {
+	case 0:
+		hldev->kdfc = hldev->bar0  +
+			VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64);
+		break;
+	case 2:
+		hldev->kdfc = hldev->bar1  +
+			VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64);
+		break;
+	case 4:
+		hldev->kdfc = hldev->bar2  +
+			VXGE_HW_TOC_GET_KDFC_INITIAL_OFFSET(val64);
+		break;
+	default:
+
+		break;
+	}
+
+	val64 = readq(&hldev->toc_reg->toc_usdc);
+
+	switch (VXGE_HW_TOC_GET_USDC_INITIAL_BIR(val64)) {
+	case 0:
+		hldev->usdc = hldev->bar0  +
+			VXGE_HW_TOC_GET_USDC_INITIAL_OFFSET(val64);
+		break;
+	case 2:
+		hldev->usdc = hldev->bar1  +
+			VXGE_HW_TOC_GET_USDC_INITIAL_OFFSET(val64);
+		break;
+	case 4:
+		hldev->usdc = hldev->bar2  +
+			VXGE_HW_TOC_GET_USDC_INITIAL_OFFSET(val64);
+		break;
+	default:
+
+		break;
+	}
+
+	status = __hw_device_vpath_reset_in_prog_check(
+			(u64 *)&hldev->common_reg->vpath_rst_in_prog);
+
+exit:
+
+	return status;
+}
+
+/*
+ * __hw_device_id_get
+ * @hldev: HW Device object.
+ *
+ * This routine returns sets the device id and revision numbers into the device
+ * structure
+ */
+void
+__hw_device_id_get(struct __hw_device *hldev)
+{
+	u64 val64;
+
+	vxge_assert(hldev);
+
+	val64 = readq(&hldev->common_reg->titan_asic_id);
+
+	hldev->device_id =
+		(u16)VXGE_HW_TITAN_ASIC_ID_GET_INITIAL_DEVICE_ID(val64);
+
+	hldev->major_revision =
+		(u8)VXGE_HW_TITAN_ASIC_ID_GET_INITIAL_MAJOR_REVISION(val64);
+
+	hldev->minor_revision =
+		(u8)VXGE_HW_TITAN_ASIC_ID_GET_INITIAL_MINOR_REVISION(val64);
+
+	return;
+}
+
+/*
+ * __hw_device_access_rights_get: Get Access Rights of the driver
+ * @host_type: Host type.
+ * @func_id: Function Id
+ *
+ * This routine returns the Access Rights of the driver
+ */
+u32
+__hw_device_access_rights_get(u32 host_type, u32 func_id)
+{
+	u32 access_rights = VXGE_HW_DEVICE_ACCESS_RIGHT_VPATH;
+
+	switch (host_type) {
+	case VXGE_HW_NO_MR_NO_SR_NORMAL_FUNCTION:
+		if (func_id == 0) {
+			access_rights |= VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM |
+					VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM;
+		}
+		break;
+	case VXGE_HW_MR_NO_SR_VH0_BASE_FUNCTION:
+		access_rights |= VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM |
+				VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM;
+		break;
+	case VXGE_HW_NO_MR_SR_VH0_FUNCTION0:
+		access_rights |= VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM |
+				VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM;
+		break;
+	case VXGE_HW_NO_MR_SR_VH0_VIRTUAL_FUNCTION:
+	case VXGE_HW_SR_VH_VIRTUAL_FUNCTION:
+		break;
+	case VXGE_HW_MR_SR_VH0_INVALID_CONFIG:
+		break;
+	case VXGE_HW_SR_VH_FUNCTION0:
+	case VXGE_HW_VH_NORMAL_FUNCTION:
+		access_rights |= VXGE_HW_DEVICE_ACCESS_RIGHT_SRPCIM;
+		break;
+	}
+
+	return access_rights;
+}
+/*
+ * __hw_device_host_info_get
+ * @hldev: HW Device object.
+ *
+ * This routine returns the host type assignments
+ */
+void
+__hw_device_host_info_get(struct __hw_device *hldev)
+{
+	u64 val64;
+	u32 i;
+
+	vxge_assert(hldev);
+
+	val64 = readq(&hldev->common_reg->host_type_assignments);
+
+	hldev->host_type =
+	   (u32)VXGE_HW_HOST_TYPE_ASSIGNMENTS_GET_HOST_TYPE_ASSIGNMENTS(val64);
+
+	hldev->vpath_assignments = readq(&hldev->common_reg->vpath_assignments);
+
+	for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+
+		if (!(hldev->vpath_assignments & vxge_mBIT(i)))
+			continue;
+
+		hldev->func_id = __hw_vpath_func_id_get(i,
+					hldev->vpmgmt_reg[i]);
+
+		hldev->access_rights = __hw_device_access_rights_get(
+			hldev->host_type, hldev->func_id);
+
+		hldev->first_vp_id = i;
+
+		break;
+
+	}
+
+	return;
+}
+
+/*
+ * __hw_device_pci_e_info_get - Get PCI_E bus informations such as link_width
+	*and signalling rate
+ * @hldev: HW device.
+ * @signalling_rate:	pointer to a variable of enumerated type
+	*			enum vxge_hw_pci_e_signalling_rate{}.
+ * @link_width:		pointer to a variable of enumerated type
+	*			enum vxge_hw_pci_e_link_width{}.
+ *
+ * Get pci-e signalling rate and link width.
+ *
+ * Returns: one of the enum vxge_hw_status{} enumerated types.
+ * VXGE_HW_OK- for success.
+ * VXGE_HW_ERR_INVALID_PCI_INFO - for invalid PCI information from the card.
+ * VXGE_HW_ERR_BAD_DEVICE_ID - for invalid card.
+ *
+ */
+static enum vxge_hw_status
+__hw_device_pci_e_info_get(
+	struct __hw_device *hldev,
+	enum vxge_hw_pci_e_signalling_rate *signalling_rate,
+	enum vxge_hw_pci_e_link_width *link_width)
+
+{
+	enum vxge_hw_status status = VXGE_HW_OK;
+	struct vxge_hw_pci_e_capability *pci_e_caps;
+
+	vxge_assert((hldev != NULL) && (signalling_rate != NULL) &&
+		(link_width != NULL));
+
+	pci_e_caps = (struct vxge_hw_pci_e_capability *)
+		(((u8 *)&hldev->pci_config_space_bios)  +  hldev->pci_e_caps);
+
+	switch (pci_e_caps->pci_e_lnkcap & VXGE_HW_PCI_EXP_LNKCAP_LNK_SPEED) {
+	case VXGE_HW_PCI_EXP_LNKCAP_LS_2_5:
+		*signalling_rate = VXGE_HW_PCI_E_SIGNALLING_RATE_2_5GB;
+		break;
+	case VXGE_HW_PCI_EXP_LNKCAP_LS_5:
+		*signalling_rate = VXGE_HW_PCI_E_SIGNALLING_RATE_5GB;
+		break;
+	default:
+		*signalling_rate = VXGE_HW_PCI_E_SIGNALLING_RATE_UNKNOWN;
+		break;
+	}
+
+	switch ((pci_e_caps->pci_e_lnkcap &
+		VXGE_HW_PCI_EXP_LNKCAP_LNK_WIDTH) >> 4) {
+	case VXGE_HW_PCI_EXP_LNKCAP_LW_X1:
+		*link_width = VXGE_HW_PCI_E_LINK_WIDTH_X1;
+		break;
+	case VXGE_HW_PCI_EXP_LNKCAP_LW_X2:
+		*link_width = VXGE_HW_PCI_E_LINK_WIDTH_X2;
+		break;
+	case VXGE_HW_PCI_EXP_LNKCAP_LW_X4:
+		*link_width = VXGE_HW_PCI_E_LINK_WIDTH_X4;
+		break;
+	case VXGE_HW_PCI_EXP_LNKCAP_LW_X8:
+		*link_width = VXGE_HW_PCI_E_LINK_WIDTH_X8;
+		break;
+	case VXGE_HW_PCI_EXP_LNKCAP_LW_X12:
+		*link_width = VXGE_HW_PCI_E_LINK_WIDTH_X12;
+		break;
+	case VXGE_HW_PCI_EXP_LNKCAP_LW_X16:
+		*link_width = VXGE_HW_PCI_E_LINK_WIDTH_X16;
+		break;
+	case VXGE_HW_PCI_EXP_LNKCAP_LW_X32:
+		*link_width = VXGE_HW_PCI_E_LINK_WIDTH_X32;
+		break;
+	case VXGE_HW_PCI_EXP_LNKCAP_LW_RES:
+	default:
+		*link_width = VXGE_HW_PCI_E_LINK_WIDTH_UNKNOWN;
+		break;
+	}
+
+	if ((*signalling_rate == VXGE_HW_PCI_E_SIGNALLING_RATE_UNKNOWN) ||
+		(*link_width == VXGE_HW_PCI_E_LINK_WIDTH_UNKNOWN))
+		status = VXGE_HW_ERR_INVALID_PCI_INFO;
+
+	return status;
+}
+
+/**
+ * __hw_device_get_vpd_data - Getting vpd_data.
+ *
+ *   @hldev: HW device handle.
+ *
+ *   Getting  product name and serial number from vpd capabilites structure
+ *
+ */
+void
+__hw_device_get_vpd_data(struct __hw_device *hldev)
+{
+	u8   *vpd_data;
+	u16  data;
+	u32  data32;
+	u32  index = 0, i, count, fail = 0;
+	u32  addr_offset;
+	u32  data_offset;
+	u32  max_count = hldev->config.device_poll_millis * 10;
+
+	vxge_assert(hldev);
+
+	addr_offset = hldev->pci_caps.vpd_cap_offset  +
+		vxge_offsetof(struct vxge_hw_vpid_capability_le, vpd_address);
+
+	data_offset = hldev->pci_caps.vpd_cap_offset  +
+		vxge_offsetof(struct vxge_hw_vpid_capability_le, vpd_data);
+	strcpy((char *) hldev->vpd_data.product_name,
+		"10 Gigabit Ethernet Adapter");
+
+	strcpy((char *) hldev->vpd_data.serial_num, "not available");
+
+	if ((hldev->host_type != VXGE_HW_NO_MR_NO_SR_NORMAL_FUNCTION) ||
+			(hldev->func_id != 0)) {
+		strcpy((char *) hldev->vpd_data.serial_num,
+				"not supported");
+		strcpy((char *) hldev->vpd_data.product_name,
+				"not supported");
+		return;
+	}
+	vpd_data = (u8 *) vmalloc(VXGE_HW_VPD_BUFFER_SIZE  +  16);
+	if (vpd_data == 0)
+		return;
+	for (index = 0; index < VXGE_HW_VPD_BUFFER_SIZE; index += 4) {
+		pci_write_config_word(hldev->pdev,
+				addr_offset, (u16)index);
+		for (count = 0; count < max_count; count++) {
+			vxge_os_udelay(100);
+			pci_read_config_word(hldev->pdev,
+					addr_offset, &data);
+			if (data & VXGE_HW_PCI_VPID_COMPL_FALG)
+				break;
+		}
+
+		if (count >= max_count) {
+
+			fail = 1;
+			break;
+		}
+
+		pci_read_config_dword(hldev->pdev,
+				data_offset, &data32);
+
+		for (i = 0; i < 4; i++) {
+			vpd_data[index+i] = (u8)(data32 & 0xff);
+			data32 >>= 8;
+		}
+	}
+
+	if (!fail) {
+
+		/* read serial number of adapter */
+		for (count = 0; count < VXGE_HW_VPD_BUFFER_SIZE; count++) {
+			if ((vpd_data[count] == 'S')     &&
+			    (vpd_data[count  +  1] == 'N') &&
+			    (vpd_data[count  +  2] < VXGE_HW_VPD_LENGTH)) {
+				memset(hldev->vpd_data.serial_num, 0,
+					VXGE_HW_VPD_LENGTH);
+				memcpy(hldev->vpd_data.serial_num,
+					&vpd_data[count  +  3],
+					vpd_data[count  +  2]);
+				break;
+			}
+		}
+
+		if (vpd_data[1] < VXGE_HW_VPD_LENGTH) {
+			memset(hldev->vpd_data.product_name, 0, vpd_data[1]);
+			memcpy(hldev->vpd_data.product_name, &vpd_data[3],
+				vpd_data[1]);
+		}
+	}
+
+	vfree(vpd_data);
+
+	return;
+}
+
+/*
+ * vxge_hw_wrr_rebalance - Rebalance the RX_WRR and KDFC_WRR calandars.
+ * @devh: HW device handle.
+ *
+ * Rebalance the RX_WRR and KDFC_WRR calandars.
+ *
+ */
+enum vxge_hw_status vxge_hw_wrr_rebalance(struct __hw_device *hldev)
+{
+	u64 val64;
+	u32 calender[176];
+	u32 i, j, how_often = 1;
+	enum vxge_hw_status status = VXGE_HW_OK;
+
+	vxge_assert(hldev != NULL);
+
+	if ((hldev->host_type != VXGE_HW_NO_MR_NO_SR_NORMAL_FUNCTION) ||
+			(hldev->func_id != 0)) {
+		status = VXGE_HW_ERR_PRIVILAGED_OPEARATION;
+		goto exit;
+	}
+
+	/* Reset the priorities assigned to the WRR arbitration
+	phases for the receive traffic */
+	for (i = 0; i < 22; i++)
+		writeq(0, ((&hldev->mrpcim_reg->rx_w_round_robin_0) + i));
+
+	/* Reset the transmit FIFO servicing calendar for FIFOs */
+	for (i = 0; i < 20; i++) {
+		writeq(0, ((&hldev->mrpcim_reg->
+				kdfc_w_round_robin_0) + i));
+
+		writeq(0, ((&hldev->mrpcim_reg->
+				kdfc_w_round_robin_20) + i));
+	}
+
+	/* Assign WRR priority  0 for all FIFOs */
+	for (i = 1; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+		writeq(VXGE_HW_KDFC_FIFO_0_CTRL_WRR_NUMBER(0),
+				((&hldev->mrpcim_reg->kdfc_fifo_0_ctrl)  + i));
+
+		writeq(VXGE_HW_KDFC_FIFO_17_CTRL_WRR_NUMBER(0),
+			((&hldev->mrpcim_reg->kdfc_fifo_17_ctrl) + i));
+	}
+
+	/* Reset to service non-offload doorbells */
+	writeq(0, &hldev->mrpcim_reg->kdfc_entry_type_sel_0);
+
+	writeq(0, &hldev->mrpcim_reg->kdfc_entry_type_sel_1);
+
+	/* Set priority 0 to all receive queues */
+	writeq(0, &hldev->mrpcim_reg->rx_queue_priority_0);
+
+	writeq(0, &hldev->mrpcim_reg->rx_queue_priority_1);
+
+	writeq(0, &hldev->mrpcim_reg->rx_queue_priority_2);
+
+	/* Initialize all the slots as unused */
+	for (i = 0; i < 176; i++)
+		calender[i] = -1;
+
+	/* Prepare the Fifo service states */
+	for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+
+		if (!hldev->config.vp_config[i].min_bandwidth)
+			continue;
+
+		how_often = 100 / hldev->config.
+				vp_config[i].min_bandwidth;
+		if (how_often) {
+
+			for (j = 0; j < 153;) {
+				if (calender[j] == -1) {
+					calender[j] = i;
+					/* Make sure each fifo is serviced
+					 * atleast once */
+					if (i == j)
+						j += VXGE_HW_MAX_VIRTUAL_PATHS;
+					else
+						j += how_often;
+				} else
+					j++;
+			}
+		}
+	}
+
+	/* Fill the unused slots with 0 */
+	for (j = 0; j < 176; j++) {
+		if (calender[j] == -1)
+			calender[j] = 0;
+	}
+
+	/* Assign WRR priority number for FIFOs */
+	for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+		writeq(VXGE_HW_KDFC_FIFO_0_CTRL_WRR_NUMBER(i),
+				((&hldev->mrpcim_reg->kdfc_fifo_0_ctrl) + i));
+
+		writeq(VXGE_HW_KDFC_FIFO_17_CTRL_WRR_NUMBER(i),
+			((&hldev->mrpcim_reg->kdfc_fifo_17_ctrl) + i));
+	}
+
+	/* Modify the servicing algorithm applied to the 3 types of doorbells.
+	i.e, none-offload, message and offload */
+	writeq(VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_0(0) |
+				VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_1(0) |
+				VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_2(0) |
+				VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_3(0) |
+				VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_4(1) |
+				VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_5(0) |
+				VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_6(0) |
+				VXGE_HW_KDFC_ENTRY_TYPE_SEL_0_NUMBER_7(0),
+				&hldev->mrpcim_reg->kdfc_entry_type_sel_0);
+
+	writeq(VXGE_HW_KDFC_ENTRY_TYPE_SEL_1_NUMBER_8(1),
+				&hldev->mrpcim_reg->kdfc_entry_type_sel_1);
+
+	for (i = 0, j = 0; i < 20; i++) {
+
+		val64 = 0;
+
+		val64 |=  VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_0(calender[j++]);
+		val64 |=  VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_1(calender[j++]);
+		val64 |=  VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_2(calender[j++]);
+		val64 |=  VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_3(calender[j++]);
+		val64 |=  VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_4(calender[j++]);
+		val64 |=  VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_5(calender[j++]);
+		val64 |=  VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_6(calender[j++]);
+		val64 |=  VXGE_HW_KDFC_W_ROUND_ROBIN_0_NUMBER_7(calender[j++]);
+
+		writeq(val64, ((&hldev->mrpcim_reg->
+				kdfc_w_round_robin_0)  +  i));
+
+		writeq(val64, ((&hldev->mrpcim_reg->
+				kdfc_w_round_robin_20)  +  i));
+	}
+
+	/* Set up the priorities assigned to receive queues */
+	writeq(VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_0(0) |
+			VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_1(1) |
+			VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_2(2) |
+			VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_3(3) |
+			VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_4(4) |
+			VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_5(5) |
+			VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_6(6) |
+			VXGE_HW_RX_QUEUE_PRIORITY_0_RX_Q_NUMBER_7(7),
+			&hldev->mrpcim_reg->rx_queue_priority_0);
+
+	writeq(VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_8(8) |
+			VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_9(9) |
+			VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_10(10) |
+			VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_11(11) |
+			VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_12(12) |
+			VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_13(13) |
+			VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_14(14) |
+			VXGE_HW_RX_QUEUE_PRIORITY_1_RX_Q_NUMBER_15(15),
+			&hldev->mrpcim_reg->rx_queue_priority_1);
+
+	writeq(VXGE_HW_RX_QUEUE_PRIORITY_2_RX_Q_NUMBER_16(16),
+				&hldev->mrpcim_reg->rx_queue_priority_2);
+
+	/* Initialize all the slots as unused */
+	for (i = 0; i < 176; i++)
+		calender[i] = -1;
+
+	/* Prepare the Ring service states */
+	for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+
+		if (!hldev->config.vp_config[i].min_bandwidth)
+			continue;
+
+		how_often = 100 / hldev->
+				config.vp_config[i].min_bandwidth;
+		if (how_often) {
+
+			for (j = 0; j < 171;) {
+				if (calender[j] == -1) {
+					calender[j] = i;
+					/* Make sure each ring is
+					 * serviced atleast once */
+					if (i == j)
+						j += VXGE_HW_MAX_VIRTUAL_PATHS;
+					else
+						j += how_often;
+				} else
+					j++;
+			}
+		}
+	}
+
+	/* Fill the unused slots with 0 */
+	for (j = 0; j < 176; j++) {
+		if (calender[j] == -1)
+			calender[j] = 0;
+	}
+
+	for (i = 0, j = 0; i < 22; i++) {
+		val64 = 0;
+		val64 |=  VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_0(
+				calender[j++]);
+		val64 |=  VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_1(
+				calender[j++]);
+		val64 |=  VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_2(
+				calender[j++]);
+		val64 |=  VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_3(
+				calender[j++]);
+		val64 |=  VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_4(
+				calender[j++]);
+		val64 |=  VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_5(
+				calender[j++]);
+		val64 |=  VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_6(
+				calender[j++]);
+		val64 |=  VXGE_HW_RX_W_ROUND_ROBIN_0_RX_W_PRIORITY_SS_7(
+				calender[j++]);
+
+		writeq(val64, ((&hldev->mrpcim_reg->rx_w_round_robin_0)  +  i));
+	}
+exit:
+
+	return status;
+}
+
+/*
+ * __hw_device_initialize
+ * @hldev: HW device handle.
+ *
+ * Initialize Titan-V hardware.
+ */
+enum vxge_hw_status
+__hw_device_initialize(struct __hw_device *hldev)
+{
+	enum vxge_hw_status status = VXGE_HW_OK;
+
+	vxge_assert(hldev);
+
+	/* Get the pci-e link width and speed */
+	status = __hw_device_pci_e_info_get(hldev,
+		&hldev->signalling_rate,
+		&hldev->link_width);
+	if (status != VXGE_HW_OK) {
+		hldev->signalling_rate =
+				VXGE_HW_PCI_E_SIGNALLING_RATE_UNKNOWN;
+		hldev->link_width = VXGE_HW_PCI_E_LINK_WIDTH_UNKNOWN;
+		goto exit;
+	}
+
+	if ((hldev->host_type == VXGE_HW_NO_MR_NO_SR_NORMAL_FUNCTION) &&
+			(hldev->func_id == 0)) {
+
+		hldev->mrpcim_stats_block =
+			__hw_blockpool_block_allocate(hldev,
+			VXGE_HW_BLOCK_SIZE);
+
+		if (hldev->mrpcim_stats_block == NULL) {
+			status = VXGE_HW_ERR_OUT_OF_MEMORY;
+			goto exit;
+		}
+
+		hldev->mrpcim_stats =
+			(struct vxge_hw_device_stats_mrpcim_info *) \
+				hldev->mrpcim_stats_block->memblock;
+
+		memset(hldev->mrpcim_stats, 0,
+			sizeof(struct vxge_hw_device_stats_mrpcim_info));
+
+		hldev->stats.hw_dev_info_stats.mrpcim_info =
+						hldev->mrpcim_stats;
+
+		hldev->mrpcim_stats_sav =
+			&hldev->stats.hw_dev_info_stats.mrpcim_info_sav;
+
+		memset(hldev->mrpcim_stats_sav, 0,
+			sizeof(struct vxge_hw_device_stats_mrpcim_info));
+
+		writeq(hldev->mrpcim_stats_block->dma_addr,
+			&hldev->mrpcim_reg->mrpcim_stats_start_host_addr);
+	}
+
+	vxge_hw_wrr_rebalance(hldev);
+
+exit:
+
+	return status;
+}
+
+/**
+ * vxge_hw_device_hw_info_get - Get the hw information
+ * @bar0: Address of BAR0 in PCI config
+ * @hw_info: Buffer to return struct vxge_hw_device_hw_info{} structure
+ *
+ * Returns the vpath mask that has the bits set for each vpath allocated
+ * for the driver, FW version information and the first mac addresse for
+ * each vpath
+ */
+enum vxge_hw_status vxge_hw_device_hw_info_get(u8 *bar0,
+				struct vxge_hw_device_hw_info *hw_info)
+{
+	u32 i;
+	u64 val64;
+	struct vxge_hw_toc_reg *toc;
+	struct vxge_hw_mrpcim_reg *mrpcim_reg;
+	struct vxge_hw_common_reg *common_reg;
+	struct vxge_hw_vpath_reg *vpath_reg;
+	struct vxge_hw_vpmgmt_reg *vpmgmt_reg;
+	enum vxge_hw_status status;
+
+	vxge_assert((bar0 != NULL) && (hw_info != NULL));
+
+	memset(hw_info, 0, sizeof(struct vxge_hw_device_hw_info));
+
+	toc = __hw_device_toc_get(bar0);
+	if (toc == NULL) {
+		status = VXGE_HW_ERR_CRITICAL;
+		goto exit;
+	}
+
+	val64 = readq(&toc->toc_common_pointer);
+
+	common_reg = (struct vxge_hw_common_reg *)(bar0  +  val64);
+
+	status = __hw_device_vpath_reset_in_prog_check(
+		(u64 *)&common_reg->vpath_rst_in_prog);
+	if (status != VXGE_HW_OK)
+		goto exit;
+
+	hw_info->vpath_mask = readq(&common_reg->vpath_assignments);
+
+	val64 = readq(&common_reg->host_type_assignments);
+
+	hw_info->host_type =
+	   (u32)VXGE_HW_HOST_TYPE_ASSIGNMENTS_GET_HOST_TYPE_ASSIGNMENTS(val64);
+
+	for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+
+		if (!((hw_info->vpath_mask) & vxge_mBIT(i)))
+			continue;
+
+		val64 = readq(&toc->toc_vpmgmt_pointer[i]);
+
+		vpmgmt_reg = (struct vxge_hw_vpmgmt_reg *)(bar0  +  val64);
+
+		hw_info->func_id = __hw_vpath_func_id_get(i, vpmgmt_reg);
+		if (__hw_device_access_rights_get(hw_info->host_type,
+			hw_info->func_id) &
+			VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM) {
+
+			val64 = readq(&toc->toc_mrpcim_pointer);
+
+			mrpcim_reg =
+				(struct vxge_hw_mrpcim_reg *)(bar0 + val64);
+
+			writeq(0, &mrpcim_reg->xgmac_gen_fw_memo_mask);
+			wmb();
+		}
+
+		val64 = readq(&toc->toc_vpath_pointer[i]);
+
+		vpath_reg = (struct vxge_hw_vpath_reg *)(bar0  +  val64);
+
+		hw_info->function_mode =
+			__hw_vpath_pci_func_mode_get(i, vpath_reg);
+
+		__hw_vpath_fw_flash_ver_get(i, vpath_reg,
+			&hw_info->fw_version,
+			&hw_info->fw_date,
+			&hw_info->flash_version,
+			&hw_info->flash_date);
+
+		break;
+	}
+
+	for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+
+		if (!((hw_info->vpath_mask) & vxge_mBIT(i)))
+			continue;
+
+		val64 = readq(&toc->toc_vpath_pointer[i]);
+
+		vpath_reg = (struct vxge_hw_vpath_reg *)(bar0  +  val64);
+
+		status =  __hw_vpath_addr_get(i, vpath_reg,
+				hw_info->mac_addrs[i],
+				hw_info->mac_addr_masks[i]);
+		if (status != VXGE_HW_OK)
+			goto exit;
+	}
+exit:
+
+	return status;
+}
+
+/**
+ * vxge_hw_device_initialize - Initialize Titan device.
+ * @hldev: HW device handle.
+ * @attr: pointer to struct vxge_hw_device_attr structure
+ * @device_config: Configuration to be _applied_ to the device,
+ *                 For the Titan configuration "knobs" please
+ *                 refer to struct vxge_hw_device_config and Titan
+ *                 User Guide.
+ *
+ * Initialize Titan device. Note that all the arguments of this public API
+ * are 'IN', including @hldev. Driver cooperates with
+ * OS to find new Titan device, locate its PCI and memory spaces.
+ *
+ * When done, the driver allocates sizeof(struct __hw_device) bytes for HW
+ * to enable the latter to perform Titan hardware initialization.
+ *
+ * Returns: VXGE_HW_OK - success.
+ * VXGE_HW_ERR_DRIVER_NOT_INITIALIZED - Driver is not initialized.
+ * VXGE_HW_ERR_BAD_DEVICE_CONFIG - Device configuration params are not
+ * valid.
+ * VXGE_HW_ERR_OUT_OF_MEMORY - Memory allocation failed.
+ * VXGE_HW_ERR_BAD_SUBSYSTEM_ID - Device subsystem id is invalid.
+ * VXGE_HW_ERR_INVALID_MAC_ADDRESS - Device mac address in not valid.
+ * VXGE_HW_INF_MEM_STROBE_CMD_EXECUTING - Failed to retrieve the mac
+ * address within the time(timeout) or TTI/RTI initialization failed.
+ * VXGE_HW_ERR_SWAPPER_CTRL - Failed to configure swapper control.
+ *
+ * See also: __hw_device_terminate(), enum vxge_hw_status{}
+ * struct vxge_hw_device_attr{}.
+ */
+enum vxge_hw_status
+vxge_hw_device_initialize(
+	struct __hw_device **devh,
+	struct vxge_hw_device_attr *attr,
+	struct vxge_hw_device_config *device_config)
+{
+	u32 i;
+	u32 nblocks = 0;
+	struct __hw_device *hldev = NULL;
+	enum vxge_hw_status status = VXGE_HW_OK;
+	u64 value = 0;
+
+	vxge_assert((devh != NULL) && (attr != NULL) &&
+		(device_config != NULL));
+
+	status = __hw_device_config_check(device_config);
+	if (status != VXGE_HW_OK)
+		goto exit;
+
+	hldev = (struct __hw_device *)vmalloc(sizeof(struct __hw_device));
+	if (hldev == NULL) {
+		status = VXGE_HW_ERR_OUT_OF_MEMORY;
+		goto exit;
+	}
+
+	memset(hldev, 0, sizeof(struct __hw_device));
+
+	hldev->magic = VXGE_HW_DEVICE_MAGIC;
+
+	vxge_hw_device_debug_set(hldev, VXGE_ERR, VXGE_COMPONENT_ALL);
+
+	/* apply config */
+	memcpy(&hldev->config, device_config,
+		sizeof(struct vxge_hw_device_config));
+
+	hldev->bar0 = attr->bar0;
+	hldev->bar1 = attr->bar1;
+	hldev->bar2 = attr->bar2;
+	hldev->pdev = attr->pdev;
+
+	hldev->uld_callbacks.link_up = attr->uld_callbacks.link_up;
+	hldev->uld_callbacks.link_down = attr->uld_callbacks.link_down;
+	hldev->uld_callbacks.crit_err = attr->uld_callbacks.crit_err;
+	hldev->uld_callbacks.sched_timer =
+		attr->uld_callbacks.sched_timer;
+	hldev->uld_callbacks.xpak_alarm_log =
+		attr->uld_callbacks.xpak_alarm_log;
+
+	__hw_device_pci_e_init(hldev);
+
+	status = __hw_device_reg_addr_get(hldev);
+	if (status != VXGE_HW_OK)
+		goto exit;
+	__hw_device_id_get(hldev);
+
+	__hw_device_host_info_get(hldev);
+
+	/* Incrementing for stats blocks */
+	nblocks++;
+
+	for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+
+		if (!(hldev->vpath_assignments & vxge_mBIT(i)))
+			continue;
+
+		if (device_config->vp_config[i].ring.enable ==
+			VXGE_HW_RING_ENABLE)
+			nblocks += device_config->vp_config[i].ring.ring_blocks;
+
+		if (device_config->vp_config[i].fifo.enable ==
+			VXGE_HW_FIFO_ENABLE)
+			nblocks += device_config->vp_config[i].fifo.fifo_blocks;
+		nblocks++;
+
+	}
+
+	if (__hw_blockpool_create(hldev,
+		&hldev->block_pool,
+		device_config->dma_blockpool_initial  +  nblocks,
+		device_config->dma_blockpool_incr,
+		device_config->dma_blockpool_min,
+		device_config->dma_blockpool_max  +  nblocks) !=
+			VXGE_HW_OK) {
+
+		vxge_hw_device_terminate(hldev);
+		status = VXGE_HW_ERR_OUT_OF_MEMORY;
+		goto exit;
+	}
+
+	status = __hw_device_initialize(hldev);
+
+	if (status != VXGE_HW_OK) {
+
+		vxge_hw_device_terminate(hldev);
+		goto exit;
+	}
+
+	__hw_device_get_vpd_data(hldev);
+
+	/* Redundant as it is already set in __hw_device_hw_initialzie. */
+	hldev->is_initialized = 1;
+
+	*devh = hldev;
+
+	if (hldev->access_rights & VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM) {
+		/* debounce configuration for PORT0 */
+		value = VXGE_HW_XGMAC_DEBOUNCE_PORT_PERIOD_LINK_UP(0xD) |
+			VXGE_HW_XGMAC_DEBOUNCE_PORT_PERIOD_LINK_DOWN(0xD) |
+			VXGE_HW_XGMAC_DEBOUNCE_PORT_PERIOD_PORT_UP(0xD) |
+			VXGE_HW_XGMAC_DEBOUNCE_PORT_PERIOD_PORT_DOWN(0xD);
+
+		writeq(value, &hldev->mrpcim_reg->xgmac_debounce_port[0]);
+
+		/* debounce configuration for PORT1 */
+		writeq(value, &hldev->mrpcim_reg->xgmac_debounce_port[1]);
+	}
+exit:
+
+	return status;
+}
+
+/**
+ * vxge_hw_device_terminate - Terminate Titan device.
+ * @hldev: HW device handle.
+ *
+ * Terminate HW device.
+ *
+ * See also: vxge_hw_device_initialize().
+ */
+void
+vxge_hw_device_terminate(struct __hw_device *hldev)
+{
+	vxge_assert(hldev != NULL);
+	vxge_assert(hldev->magic == VXGE_HW_DEVICE_MAGIC);
+
+	hldev->is_initialized = 0;
+	hldev->magic = VXGE_HW_DEVICE_DEAD;
+
+	if (hldev->mrpcim_stats_block != NULL) {
+		__hw_blockpool_block_free(hldev, hldev->mrpcim_stats_block);
+		hldev->mrpcim_stats_block = NULL;
+	}
+
+	__hw_blockpool_destroy(&hldev->block_pool);
+
+	vfree(hldev);
+
+}
+
+/**
+ * vxge_hw_device_hw_stats_enable - Enable device h/w statistics.
+ * @hldev: HW Device.
+ *
+ * Enable the DMA vpath statistics for the device. The function is to be called
+ * to re-enable the adapter to update stats into the host memory
+ *
+ */
+enum vxge_hw_status vxge_hw_device_hw_stats_enable(struct __hw_device *hldev)
+{
+	u32 i;
+	u64 val64;
+	enum vxge_hw_status status = VXGE_HW_OK;
+
+	vxge_assert(hldev != NULL);
+
+	val64 = readq(&hldev->common_reg->stats_cfg0);
+
+	for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+
+		if (!(hldev->vpaths_deployed & vxge_mBIT(i)) ||
+			(hldev->virtual_paths[i].vp_open ==
+				VXGE_HW_VP_NOT_OPEN))
+			continue;
+
+		memcpy(hldev->virtual_paths[i].hw_stats_sav,
+				hldev->virtual_paths[i].hw_stats,
+				sizeof(struct vxge_hw_vpath_stats_hw_info));
+
+		if (hldev->config.stats_read_method ==
+					VXGE_HW_STATS_READ_METHOD_DMA) {
+			val64 |= VXGE_HW_STATS_CFG0_STATS_ENABLE(
+							(1 << (16 - i)));
+		} else {
+			status = __hw_vpath_stats_get(
+				&hldev->virtual_paths[i],
+				hldev->virtual_paths[i].hw_stats);
+		}
+
+	}
+
+	__hw_pio_mem_write32_upper((u32)bVAL32(val64, 0),
+				&hldev->common_reg->stats_cfg0);
+
+	return status;
+}
+
+/**
+ * vxge_hw_device_stats_get - Get the device hw statistics.
+ * @hldev: HW Device.
+ * @hw_stats: Hardware stats
+ *
+ * Returns the vpath h/w stats for the device.
+ *
+ * See also: vxge_hw_device_hw_stats_enable(),
+ * vxge_hw_device_hw_stats_disable()
+ */
+enum vxge_hw_status vxge_hw_device_stats_get(
+	struct __hw_device *hldev,
+	struct vxge_hw_device_stats_hw_info *hw_stats)
+{
+	u32 i;
+	u64 val64 = 0;
+	enum vxge_hw_status status = VXGE_HW_OK;
+
+	vxge_assert((hldev != NULL) && (hw_stats != NULL));
+
+	if (hldev->config.stats_read_method ==
+			VXGE_HW_STATS_READ_METHOD_DMA) {
+
+		for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+
+			if (!(hldev->vpaths_deployed & vxge_mBIT(i)))
+				continue;
+
+			val64 |= VXGE_HW_STATS_CFG0_STATS_ENABLE(
+							(1 << (16 - i)));
+
+		}
+
+		status = __hw_device_register_poll(
+				(u64 *)&hldev->common_reg->stats_cfg0,
+				0,
+				val64,
+				hldev->config.device_poll_millis);
+
+	}
+
+	if (status == VXGE_HW_OK) {
+		memcpy(hw_stats,
+				&hldev->stats.hw_dev_info_stats,
+				sizeof(struct vxge_hw_device_stats_hw_info));
+	}
+
+	return status;
+}
+
+/**
+ * vxge_hw_driver_stats_get - Get the device sw statistics.
+ * @hldev: HW Device.
+ * @sw_stats: Software stats
+ *
+ * Returns the vpath s/w stats for the device.
+ *
+ * See also: vxge_hw_device_stats_get()
+ */
+enum vxge_hw_status vxge_hw_driver_stats_get(
+			struct __hw_device *hldev,
+			struct vxge_hw_device_stats_sw_info *sw_stats)
+{
+	enum vxge_hw_status status = VXGE_HW_OK;
+
+	vxge_assert((hldev != NULL) && (sw_stats != NULL));
+
+	memcpy(sw_stats,
+		&hldev->stats.sw_dev_info_stats,
+		sizeof(struct vxge_hw_device_stats_sw_info));
+
+	return status;
+}
+
+/**
+ * vxge_hw_mrpcim_stats_access - Access the statistics from the given location
+ *                           and offset and perform an operation
+ * @hldev: HW Device handle.
+ * @operation: Operation to be performed
+ * @location: Location (one of vpath id, aggregate or port)
+ * @offset: Offset with in the location
+ * @stat: Pointer to a buffer to return the value
+ *
+ * Get the statistics from the given location and offset.
+ *
+ */
+enum vxge_hw_status
+vxge_hw_mrpcim_stats_access(
+	struct __hw_device *hldev,
+	u32 operation,
+	u32 location,
+	u32 offset,
+	u64 *stat)
+{
+	u64 val64;
+	enum vxge_hw_status status = VXGE_HW_OK;
+
+	vxge_assert((hldev != NULL) && (stat != NULL));
+
+	if ((hldev->host_type != VXGE_HW_NO_MR_NO_SR_NORMAL_FUNCTION) ||
+	   (hldev->func_id != 0)) {
+		status = VXGE_HW_ERR_PRIVILAGED_OPEARATION;
+		goto exit;
+	}
+
+	val64 = VXGE_HW_XMAC_STATS_SYS_CMD_OP(operation) |
+		VXGE_HW_XMAC_STATS_SYS_CMD_STROBE |
+		VXGE_HW_XMAC_STATS_SYS_CMD_LOC_SEL(location) |
+		VXGE_HW_XMAC_STATS_SYS_CMD_OFFSET_SEL(offset);
+
+	__hw_pio_mem_write32_lower((u32)bVAL32(val64, 32),
+			&hldev->mrpcim_reg->xmac_stats_sys_cmd);
+
+	wmb();
+
+	__hw_pio_mem_write32_upper((u32)bVAL32(val64, 0),
+			&hldev->mrpcim_reg->xmac_stats_sys_cmd);
+
+	wmb();
+
+	status = __hw_device_register_poll(
+			(u64 *)&hldev->mrpcim_reg->xmac_stats_sys_cmd,
+			0,
+			VXGE_HW_XMAC_STATS_SYS_CMD_STROBE,
+			hldev->config.device_poll_millis);
+
+	if ((status == VXGE_HW_OK) && (operation == VXGE_HW_STATS_OP_READ))
+		*stat = readq(&hldev->mrpcim_reg->xmac_stats_sys_data);
+	else
+		*stat = 0;
+exit:
+
+	return status;
+}
+
+/**
+ * vxge_hw_device_xmac_aggr_stats_get - Get the Statistics on aggregate port
+ * @hldev: HW device handle.
+ * @port: Number of the port (0 or 1)
+ * @aggr_stats: Buffer to return Statistics on aggregate port.
+ *
+ * Get the Statistics on aggregate port
+ *
+ */
+enum vxge_hw_status
+vxge_hw_device_xmac_aggr_stats_get(struct __hw_device *hldev,
+				u32 port,
+				struct vxge_hw_xmac_aggr_stats *aggr_stats)
+{
+	u64 *val64;
+	int i;
+	u32 offset = VXGE_HW_STATS_AGGRn_OFFSET;
+	enum vxge_hw_status status = VXGE_HW_OK;
+
+	vxge_assert((hldev != NULL) && (aggr_stats != NULL));
+	val64 = (u64 *)aggr_stats;
+
+	if ((hldev->host_type != VXGE_HW_NO_MR_NO_SR_NORMAL_FUNCTION) ||
+	   (hldev->func_id != 0)) {
+		status = VXGE_HW_ERR_PRIVILAGED_OPEARATION;
+		goto exit;
+	}
+
+	for (i = 0; i < sizeof(struct vxge_hw_xmac_aggr_stats) / 8; i++) {
+		status = vxge_hw_mrpcim_stats_access(hldev,
+					VXGE_HW_STATS_OP_READ,
+					VXGE_HW_STATS_LOC_AGGR,
+					((offset + (104 * port)) >> 3), val64);
+		if (status != VXGE_HW_OK)
+			goto exit;
+
+		offset = offset + 8;
+		val64++;
+	}
+exit:
+
+	return status;
+}
+
+/**
+ * vxge_hw_device_xmac_port_stats_get - Get the Statistics on a port
+ * @hldev: HW device handle.
+ * @port: Number of the port (wire 0, wire 1 or LAG)
+ * @port_stats: Buffer to return Statistics on a port.
+ *
+ * Get the Statistics on port
+ *
+ */
+enum vxge_hw_status
+vxge_hw_device_xmac_port_stats_get(struct __hw_device *hldev,
+				u32 port,
+				struct vxge_hw_xmac_port_stats *port_stats)
+{
+	u64 *val64;
+	enum vxge_hw_status status = VXGE_HW_OK;
+	int i;
+	u32 offset = 0x0;
+	vxge_assert((hldev != NULL) && (port_stats != NULL));
+	val64 = (u64 *) port_stats;
+
+	if ((hldev->host_type != VXGE_HW_NO_MR_NO_SR_NORMAL_FUNCTION) ||
+	   (hldev->func_id != 0)) {
+		status = VXGE_HW_ERR_PRIVILAGED_OPEARATION;
+		goto exit;
+	}
+
+	for (i = 0; i < sizeof(struct vxge_hw_xmac_port_stats) / 8; i++) {
+		status = vxge_hw_mrpcim_stats_access(hldev,
+					VXGE_HW_STATS_OP_READ,
+					VXGE_HW_STATS_LOC_AGGR,
+					((offset + (608 * port)) >> 3), val64);
+		if (status != VXGE_HW_OK)
+			goto exit;
+
+		offset = offset + 8;
+		val64++;
+	}
+
+exit:
+
+	return status;
+}
+
+/**
+ * vxge_hw_device_xmac_stats_get - Get the XMAC Statistics
+ * @hldev: HW device handle.
+ * @xmac_stats: Buffer to return XMAC Statistics.
+ *
+ * Get the XMAC Statistics
+ *
+ */
+enum vxge_hw_status
+vxge_hw_device_xmac_stats_get(struct __hw_device *hldev,
+				struct vxge_hw_xmac_stats *xmac_stats)
+{
+	enum vxge_hw_status status = VXGE_HW_OK;
+	u32 i;
+
+	vxge_assert((hldev != NULL) && (xmac_stats != NULL));
+
+	status = vxge_hw_device_xmac_aggr_stats_get(hldev,
+				      0,
+				      &xmac_stats->aggr_stats[0]);
+
+	if (status != VXGE_HW_OK)
+		goto exit;
+
+	status = vxge_hw_device_xmac_aggr_stats_get(hldev,
+				      1,
+				      &xmac_stats->aggr_stats[1]);
+
+	if (status != VXGE_HW_OK)
+		goto exit;
+
+	for (i = 0; i <= VXGE_HW_MAC_MAX_MAC_PORT_ID; i++) {
+
+		status = vxge_hw_device_xmac_port_stats_get(hldev,
+					i,
+					&xmac_stats->port_stats[i]);
+
+		if (status != VXGE_HW_OK)
+			goto exit;
+
+	}
+
+	for (i = 0; i < VXGE_HW_MAX_VIRTUAL_PATHS; i++) {
+
+		if (!(hldev->vpaths_deployed & vxge_mBIT(i)))
+			continue;
+
+		status = __hw_vpath_xmac_tx_stats_get(&hldev->virtual_paths[i],
+					&xmac_stats->vpath_tx_stats[i]);
+
+		if (status != VXGE_HW_OK)
+			goto exit;
+
+		status = __hw_vpath_xmac_rx_stats_get(&hldev->virtual_paths[i],
+					&xmac_stats->vpath_rx_stats[i]);
+
+		if (status != VXGE_HW_OK)
+			goto exit;
+
+	}
+exit:
+
+	return status;
+}
+
+/**
+ * vxge_hw_device_debug_set - Set the debug module, level and timestamp
+ * @hldev: Hal device object
+ * @level: Debug level as defined in enum enum vxge_debug_level
+ * @module masks: An or value of component masks as defined in vxge_debug.h
+ *
+ * This routine is used to dynamically change the debug output
+ */
+void vxge_hw_device_debug_set(
+	struct __hw_device *hldev,
+	enum vxge_debug_level level,
+	u32 mask)
+{
+
+	if (hldev == NULL)
+		return;
+
+#if defined(VXGE_DEBUG_TRACE_MASK) || \
+	defined(VXGE_DEBUG_ERR_MASK)
+	hldev->debug_module_mask = mask;
+	hldev->debug_level = level;
+#endif
+
+#if defined(VXGE_DEBUG_ERR_MASK)
+	hldev->level_err = level & VXGE_ERR;
+#endif
+
+#if defined(VXGE_DEBUG_TRACE_MASK)
+	hldev->level_trace = level & VXGE_TRACE;
+#endif
+
+}
+
+/**
+ * vxge_hw_device_debug_level_get - Get the debug level
+ * @hldev: Hal device object
+ *
+ * This routine returns the current debug level set
+ */
+u32
+vxge_hw_device_debug_level_get(struct __hw_device *hldev)
+{
+#if defined(VXGE_DEBUG_TRACE_MASK) || defined(VXGE_DEBUG_ERR_MASK)
+	if (hldev == NULL)
+		return 0;
+	return hldev->debug_level;
+#else
+	return 0;
+#endif
+
+}
+
+/**
+ * vxge_hw_device_error_level_get - Get the error level
+ * @hldev: Hal device object
+ *
+ * This routine returns the current error level set
+ */
+u32
+vxge_hw_device_error_level_get(struct __hw_device *hldev)
+{
+#if defined(VXGE_DEBUG_ERR_MASK)
+	if (hldev == NULL)
+		return VXGE_ERR;
+	else
+		return hldev->level_err;
+#else
+	return 0;
+#endif
+
+}
+/**
+ * vxge_hw_device_trace_level_get - Get the trace level
+ * @hldev: Hal device object
+ *
+ * This routine returns the current trace level set
+ */
+u32
+vxge_hw_device_trace_level_get(struct __hw_device *hldev)
+{
+#if defined(VXGE_DEBUG_TRACE_MASK)
+	if (hldev == NULL)
+		return VXGE_TRACE;
+	else
+		return hldev->level_trace;
+#else
+	return 0;
+#endif
+
+}
+/**
+ * vxge_hw_device_debug_mask_get - Get the debug mask
+ * @hldev: Hal device object
+ *
+ * This routine returns the current debug mask set
+ */
+u32
+vxge_hw_device_debug_mask_get(struct __hw_device *hldev)
+{
+#if defined(VXGE_DEBUG_TRACE_MASK) || defined(VXGE_DEBUG_ERR_MASK)
+	if (hldev == NULL)
+		return 0;
+	return hldev->debug_module_mask;
+#else
+	return 0;
+#endif
+
+}
+
+/**
+ * vxge_hw_getpause_data -Pause frame frame generation and reception.
+ * @hldev: HW device handle.
+ * @port : Port number 0, 1, or 2
+ * @tx : A field to return the pause generation capability of the NIC.
+ * @rx : A field to return the pause reception capability of the NIC.
+ *
+ * Returns the Pause frame generation and reception capability of the NIC.
+ * Return value:
+ *  status
+ */
+enum vxge_hw_status vxge_hw_device_getpause_data(
+	 struct __hw_device *hldev,
+	 u32 port,
+	 u32 *tx,
+	 u32 *rx)
+{
+	u64 val64;
+	enum vxge_hw_status status = VXGE_HW_OK;
+	vxge_assert(hldev != NULL);
+
+	if ((hldev == NULL) || (hldev->magic != VXGE_HW_DEVICE_MAGIC)) {
+		status = VXGE_HW_ERR_INVALID_DEVICE;
+		goto exit;
+	}
+
+	if (port > VXGE_HW_MAC_MAX_MAC_PORT_ID) {
+		status = VXGE_HW_ERR_INVALID_PORT;
+		goto exit;
+	}
+
+	if (!(hldev->access_rights & VXGE_HW_DEVICE_ACCESS_RIGHT_MRPCIM)) {
+		status = VXGE_HW_ERR_PRIVILAGED_OPEARATION;
+		goto exit;
+	}
+
+	val64 = readq(&hldev->mrpcim_reg->rxmac_pause_cfg_port[port]);
+
+	if (val64 & VXGE_HW_RXMAC_PAUSE_CFG_PORT_GEN_EN)
+		*tx = 1;
+
+	if (val64 & VXGE_HW_RXMAC_PAUSE_CFG_PORT_RCV_EN)
+		*rx = 1;
+exit:
+
+	return status;
+}
+
+/**
+ * vxge_hw_device_setpause_data -  set/reset pause frame generation.
+ * @hldev: HW device handle.
+ * @port : Port number 0, 1, or 2
+ * @tx: A field that indicates the pause generation capability to be
+ * set on the NIC.
+ * @rx: A field that indicates the pause reception capability to be
+ * set on the NIC.
+ *
+ * It can be used to set or reset Pause frame generation or reception
+ * support of the NIC.
+ * Return value:
+ * int, returns 0 on Success
+ */
+
+enum vxge_hw_status vxge_hw_device_setpause_data(
+				struct __hw_device *hldev,
+				u32 port,
+				u32 tx,
+				u32 rx)
+{
+	u64 val64;
+	enum vxge_hw_status status = VXGE_HW_OK;
+	vxge_assert(hldev != NULL);
+
+	if ((hldev == NULL) || (hldev->magic != VXGE_HW_DEVICE_MAGIC)) {
+		status = VXGE_HW_ERR_INVALID_DEVICE;
+		goto exit;
+	}
+
+	if (port > VXGE_HW_MAC_MAX_MAC_PORT_ID) {
+		status = VXGE_HW_ERR_INVALID_PORT;
+		goto exit;
+	}
+
+	if ((hldev->host_type != VXGE_HW_NO_MR_NO_SR_NORMAL_FUNCTION) ||
+				(hldev->func_id != 0)) {
+		status = VXGE_HW_ERR_PRIVILAGED_OPEARATION;
+		goto exit;
+	}
+
+	val64 = readq(&hldev->mrpcim_reg->rxmac_pause_cfg_port[port]);
+	if (tx)
+		val64 |= VXGE_HW_RXMAC_PAUSE_CFG_PORT_GEN_EN;
+	else
+		val64 &= ~VXGE_HW_RXMAC_PAUSE_CFG_PORT_GEN_EN;
+	if (rx)
+		val64 |= VXGE_HW_RXMAC_PAUSE_CFG_PORT_RCV_EN;
+	else
+		val64 &= ~VXGE_HW_RXMAC_PAUSE_CFG_PORT_RCV_EN;
+
+	writeq(val64, &hldev->mrpcim_reg->rxmac_pause_cfg_port[port]);
+exit:
+
+	return status;
+}
+
+/**
+ * vxge_hw_device_private_set - Set driver context.
+ * @hldev: HW device handle.
+ * @data: pointer to driver context
+ *
+ * Use HW device to set driver context.
+ *
+ * See also: vxge_hw_device_private_get()
+ */
+void vxge_hw_device_private_set(struct __hw_device *hldev, void *data)
+{
+	hldev->upper_layer_data = data;
+}
+
+/**
+ * vxge_hw_device_private_get - Get driver context.
+ * @hldev: HW device handle.
+ *
+ * Use HW device to set driver context.
+ *
+ * See also: vxge_hw_device_private_get()
+ */
+void *vxge_hw_device_private_get(struct __hw_device *hldev)
+{
+	return hldev->upper_layer_data;
+}
+
+/*
+ * vxge_hw_device_serial_number_get - Returns the serial number
+ * @hldev: HW device handle.
+ *
+ * Return the serial number
+ */
+const u8 *
+vxge_hw_device_serial_number_get(struct __hw_device *hldev)
+{
+
+	vxge_assert(hldev);
+
+	return hldev->vpd_data.serial_num;
+}
+
+/*
+ * vxge_hw_device_product_name_get - Returns the product name
+ * @hldev: HW device handle.
+ *
+ * Return the product name
+ */
+const u8 *
+vxge_hw_device_product_name_get(struct __hw_device *hldev)
+{
+
+	vxge_assert(hldev);
+
+	return hldev->vpd_data.product_name;
+}
+
+u8
+vxge_hw_device_link_width_get(struct __hw_device *hldev)
+{
+	struct vxge_hw_pci_e_capability *pci_e_caps;
+
+	vxge_assert(hldev);
+
+	pci_e_caps = (struct vxge_hw_pci_e_capability *)
+		(((u8 *)&hldev->pci_config_space_bios)  +  hldev->pci_e_caps);
+
+	return (pci_e_caps->pci_e_lnksta &
+		VXGE_HW_PCI_EXP_LNKCAP_LNK_WIDTH) >> 4;
+}
+
+#ifdef VXGE_HW_INTERNAL_COMPILER_ERROR
+
+#pragma optimize("", off)
+
+#endif
+
+/*
+ * __hw_ring_block_memblock_idx - Return the memblock index
+ * @block: Virtual address of memory block
+ *
+ * This function returns the index of memory block
+ */
+static inline u32
+__hw_ring_block_memblock_idx(
+	u8 (block)[VXGE_HW_BLOCK_SIZE])
+{
+	return (u32)*((u64 *)((u8 *)block  +
+		VXGE_HW_RING_MEMBLOCK_IDX_OFFSET));
+}
+
+/*
+ * __hw_ring_block_memblock_idx_set - Sets the memblock index
+ * @block: Virtual address of memory block
+ * @memblock_idx: Index of memory block
+ *
+ * This function sets index to a memory block
+ */
+static inline void
+__hw_ring_block_memblock_idx_set(
+	u8 (block)[VXGE_HW_BLOCK_SIZE],
+	u32 memblock_idx)
+{
+	*((u64 *)((u8 *)block  +   VXGE_HW_RING_MEMBLOCK_IDX_OFFSET)) =
+					   memblock_idx;
+}
+
+/*
+ * __hw_ring_block_next_pointer - Returns the dma address of next block
+ * @block: RxD block
+ *
+ * Returns the dma address of next block stored in the RxD block
+ */
+static inline dma_addr_t
+__hw_ring_block_next_pointer(
+	u8 (*block)[VXGE_HW_BLOCK_SIZE])
+{
+	return (dma_addr_t)*((u64 *)((u8 *)block  +
+			VXGE_HW_RING_NEXT_BLOCK_POINTER_OFFSET));
+}
+
+/*
+ * __hw_ring_block_next_pointer_set - Sets the next block pointer in RxD block
+ * @block: RxD block
+ * @dma_next: dma address of next block
+ *
+ * Sets the next block pointer in RxD block
+ */
+static inline void
+__hw_ring_block_next_pointer_set(
+	u8 (*block)[VXGE_HW_BLOCK_SIZE],
+	dma_addr_t dma_next)
+{
+	*((u64 *)((u8 *)block  +  VXGE_HW_RING_NEXT_BLOCK_POINTER_OFFSET)) =
+							dma_next;
+}
+
+/*
+ * __hw_ring_first_block_address_get - Returns the dma address of the
+ *             first block
+ * @ringh: Handle to the ring
+ *
+ * Returns the dma address of the first RxD block
+ */
+u64
+__hw_ring_first_block_address_get(struct __hw_ring *ringh)
+{
+	struct __hw_ring *ring = (struct __hw_ring *)ringh;
+	struct vxge_hw_mempool_dma *dma_object;
+
+	dma_object = __hw_mempool_memblock_dma(ring->mempool, 0);
+
+	vxge_assert(dma_object != NULL);
+
+	return dma_object->addr;
+}
+
+/*
+ * __hw_ring_item_dma_addr - Return the dma address of an item
+ * @mempoolh: Handle to the memory pool of the ring
+ * @item: Item for which to get the dma offset
+ * @dma_handle: dma handle
+ *
+ * This function returns the dma address of a given item
+ */
+static dma_addr_t
+__hw_ring_item_dma_addr(
+	struct vxge_hw_mempool *mempoolh,
+	void *item,
+	struct pci_dev **dma_handle)
+{
+	u32 memblock_idx;
+	void *memblock;
+	struct vxge_hw_mempool_dma *memblock_dma_object;
+#if (VXGE_COMPONENT_HW_POOL & VXGE_DEBUG_MODULE_MASK)
+	struct vxge_hw_mempool *mempool = (struct vxge_hw_mempool *)mempoolh;
+#endif
+
+	ptrdiff_t dma_item_offset;
+
+	vxge_assert((mempoolh != NULL) && (item != NULL) &&
+			(dma_handle != NULL));
+
+	/* get owner memblock index */
+	memblock_idx = __hw_ring_block_memblock_idx(item);
+
+	/* get owner memblock by memblock index */
+	memblock = __hw_mempool_memblock(
+		(struct vxge_hw_mempool *) mempoolh, memblock_idx);
+
+	/* get memblock DMA object by memblock index */
+	memblock_dma_object = __hw_mempool_memblock_dma(
+		(struct vxge_hw_mempool *) mempoolh, memblock_idx);
+
+	/* calculate offset in the memblock of this item */
+	dma_item_offset = (u8 *)item - (u8 *)memblock;
+
+	*dma_handle = memblock_dma_object->handle;
+
+	return memblock_dma_object->addr  +  dma_item_offset;
+}
+
+/*
+ * __hw_ring_rxdblock_link - Link the RxD blocks
+ * @mempoolh: Handle to the memory pool of the ring
+ * @ringh: Handle to the ring object used for receive
+ * @from: RxD block from which to link
+ * @to: RxD block to which to link to
+ *
+ * This function returns the dma address of a given item
+ */
+static void
+__hw_ring_rxdblock_link(
+	struct vxge_hw_mempool *mempoolh,
+	struct __hw_ring *ring,
+	u32 from,
+	u32 to)
+{
+	u8 (*to_item)[VXGE_HW_BLOCK_SIZE], (*from_item)[VXGE_HW_BLOCK_SIZE];
+	dma_addr_t to_dma, from_dma;
+	struct pci_dev *to_dma_handle, *from_dma_handle;
+
+	vxge_assert((mempoolh != NULL) && (ring != NULL));
+
+	/* get "from" RxD block */
+	from_item = __hw_mempool_item(
+			(struct vxge_hw_mempool *) mempoolh, from);
+	vxge_assert(from_item);
+
+	/* get "to" RxD block */
+	to_item = __hw_mempool_item(
+			(struct vxge_hw_mempool *) mempoolh, to);
+	vxge_assert(to_item);
+
+	/* return address of the beginning of previous RxD block */
+	to_dma = __hw_ring_item_dma_addr(mempoolh, to_item, &to_dma_handle);
+
+	/* set next pointer for this RxD block to point on
+	 * previous item's DMA start address */
+	__hw_ring_block_next_pointer_set(from_item, to_dma);
+
+	/* return "from" RxD block's DMA start address */
+	from_dma = __hw_ring_item_dma_addr(
+			mempoolh, from_item, &from_dma_handle);
+
+}
+
+/*
+ * __hw_ring_mempool_item_alloc - Allocate List blocks for RxD block callback
+ * @mempoolh: Handle to memory pool
+ * @memblock: Address of this memory block
+ * @memblock_index: Index of this memory block
+ * @dma_object: dma object for this block
+ * @item: Pointer to this item
+ * @index: Index of this item in memory block
+ * @is_last: If this is last item in the block
+ * @userdata: Specific data of user
+ *
+ * This function is callback passed to __hw_mempool_create to create memory
+ * pool for RxD block
+ */
+static enum vxge_hw_status
+__hw_ring_mempool_item_alloc(
+	struct vxge_hw_mempool *mempoolh,
+	void *memblock,
+	u32 memblock_index,
+	struct vxge_hw_mempool_dma *dma_object,
+	void *item,
+	u32 index,
+	u32 is_last,
+	void *userdata)
+{
+	u32 i;
+	struct __hw_ring *ring = (struct __hw_ring *)userdata;
+
+	vxge_assert((item != NULL) && (ring != NULL));
+
+	/* format rxds array */
+	for (i = 0; i < ring->rxds_per_block; i++) {
+		void *rxdblock_priv;
+		void *uld_priv;
+		struct vxge_hw_ring_rxd_1 *rxdp;
+
+		u32 reserve_index = ring->channel.reserve_ptr -
+				(index * ring->rxds_per_block  +  i  +  1);
+		u32 memblock_item_idx;
+
+		ring->channel.reserve_arr[reserve_index] = ((u8 *)item)  +
+						i * ring->rxd_size;
+
+		/* Note: memblock_item_idx is index of the item within
+		 *       the memblock. For instance, in case of three RxD-blocks
+		 *       per memblock this value can be 0, 1 or 2. */
+		rxdblock_priv = __hw_mempool_item_priv(
+					(struct vxge_hw_mempool *)mempoolh,
+					memblock_index, item,
+					&memblock_item_idx);
+
+		rxdp = (struct vxge_hw_ring_rxd_1 *)
+				ring->channel.reserve_arr[reserve_index];
+
+		uld_priv = ((u8 *)rxdblock_priv  +  ring->rxd_priv_size * i);
+
+		/* pre-format Host_Control */
+		rxdp->host_control = (u64)(ptr_t)uld_priv;
+	}
+
+	__hw_ring_block_memblock_idx_set(item, memblock_index);
+
+	if (is_last) {
+		/* link last one with first one */
+		__hw_ring_rxdblock_link(mempoolh, ring, index, 0);
+	}
+
+	if (index > 0) {
+		/* link this RxD block with previous one */
+		__hw_ring_rxdblock_link(mempoolh, ring, index-1, index);
+	}
+
+	return VXGE_HW_OK;
+}
+
+/*
+ * __hw_ring_initial_replenish - Initial replenish of RxDs
+ * @ringh: Handle to the ring object used for receive
+ * @reopen: Flag to denote if it is open or repopen
+ *
+ * This function replenishes the RxDs from reserve array to work array
+ */
+enum vxge_hw_status
+vxge_hw_ring_replenish(
+	struct __hw_ring *ring,
+	enum vxge_hw_reopen reopen, u16 min_flag)
+{
+	void *rxd;
+	int i = 0;
+	struct __hw_channel *channel;
+	enum vxge_hw_status status = VXGE_HW_OK;
+
+	vxge_assert(ring != NULL);
+
+	channel = &ring->channel;
+
+	while (vxge_hw_channel_dtr_count(channel) > 0) {
+
+		status = vxge_hw_ring_rxd_reserve(ring, &rxd);
+
+		vxge_assert(status == VXGE_HW_OK);
+
+		if (ring->rxd_init) {
+			status = ring->rxd_init(rxd,
+					channel->reserve_ptr,
+					channel->userdata,
+					reopen);
+			if (status != VXGE_HW_OK) {
+				vxge_hw_ring_rxd_free(ring, rxd);
+				goto exit;
+			}
+		}
+
+		vxge_hw_ring_rxd_post(ring, rxd);
+		if (min_flag) {
+			i++;
+			if (i == VXGE_HW_RING_MIN_BUFF_ALLOCATION)
+				break;
+		}
+	}
+	status = VXGE_HW_OK;
+exit:
+
+	return status;
+}
+
+/**
+ * __hw_ring_create - Create a Ring
+ * @vpath_handle: Handle returned by virtual path open
+ * @attr: Ring configuration parameters structure
+ *
+ * This function creates Ring and initializes it.
+ *
+ */
+enum vxge_hw_status
+__hw_ring_create(
+	struct __hw_vpath_handle *vp,
+	struct vxge_hw_ring_attr *attr)
+{
+	enum vxge_hw_status status = VXGE_HW_OK;
+	struct __hw_ring *ring;
+	u32 ring_length;
+	struct vxge_hw_ring_config *config;
+	struct __hw_device *hldev;
+	u32 vp_id;
+	struct vxge_hw_mempool_cbs ring_mp_callback;
+	vxge_assert((vp != NULL) && (attr != NULL));
+
+	hldev = vp->vpath->hldev;
+	vp_id = vp->vpath->vp_id;
+
+	if ((vp == NULL) || (attr == NULL)) {
+
+		status = VXGE_HW_FAIL;
+		goto exit;
+	}
+
+	config = &hldev->config.vp_config[vp_id].ring;
+
+	ring_length = config->ring_blocks *
+			vxge_hw_ring_rxds_per_block_get(config->buffer_mode);
+
+	ring = (struct __hw_ring *)__hw_channel_allocate(
+					(struct __hw_device *)hldev,
+					vp,
+					VXGE_HW_CHANNEL_TYPE_RING,
+					ring_length,
+					TRUE,
+					TRUE,
+					TRUE,
+					attr->per_rxd_space,
+					attr->userdata);
+
+	if (ring == NULL) {
+
+		status = VXGE_HW_ERR_OUT_OF_MEMORY;
+		goto exit;
+	}
+
+	vp->vpath->ringh = (struct __hw_ring *)ring;
+
+	ring->rpa_strip_vlan_tag = vp->vpath->vp_config->rpa_strip_vlan_tag;
+
+	ring->vp_id = vp_id;
+	ring->vp_reg = vp->vpath->vp_reg;
+	ring->common_reg = hldev->common_reg;
+	ring->stats = &vp->vpath->sw_stats->ring_stats;
+	ring->config = config;
+	ring->callback = attr->callback;
+	ring->rxd_init = attr->rxd_init;
+	ring->rxd_term = attr->rxd_term;
+
+	ring->indicate_max_pkts = config->indicate_max_pkts;
+	ring->buffer_mode = config->buffer_mode;
+
+	ring->rxd_size = vxge_hw_ring_rxd_size_get(config->buffer_mode);
+	ring->rxd_priv_size =
+		sizeof(struct __hw_ring_rxd_priv)  +  attr->per_rxd_space;
+	ring->per_rxd_space = attr->per_rxd_space;
+
+	ring->rxd_priv_size =
+		((ring->rxd_priv_size  +  VXGE_CACHE_LINE_SIZE - 1) /
+		VXGE_CACHE_LINE_SIZE) * VXGE_CACHE_LINE_SIZE;
+
+	/* how many RxDs can fit into one block. Depends on configured
+	 * buffer_mode. */
+	ring->rxds_per_block =
+		vxge_hw_ring_rxds_per_block_get(config->buffer_mode);
+
+	/* calculate actual RxD block private size */
+	ring->rxdblock_priv_size = ring->rxd_priv_size * ring->rxds_per_block;
+	ring_mp_callback.item_func_alloc = __hw_ring_mempool_item_alloc;
+	ring_mp_callback.item_func_free = NULL;
+	ring->mempool = __hw_mempool_create(
+				(struct __hw_device *)hldev,
+				VXGE_HW_BLOCK_SIZE,
+				VXGE_HW_BLOCK_SIZE,
+				ring->rxdblock_priv_size,
+				ring->config->ring_blocks,
+				ring->config->ring_blocks,
+				&ring_mp_callback,
+				ring);
+
+	if (ring->mempool == NULL) {
+		__hw_ring_delete(vp);
+
+		return VXGE_HW_ERR_OUT_OF_MEMORY;
+	}
+
+	status = __hw_channel_initialize(&ring->channel);
+	if (status != VXGE_HW_OK) {
+		__hw_ring_delete(vp);
+		goto exit;
+	}
+
+	/* Note:
+	 * Specifying rxd_init callback means two things:
+	 * 1) rxds need to be initialized by driver at channel-open time;
+	 * 2) rxds need to be posted at channel-open time
+	 *    (that's what the initial_replenish() below does)
+	 * Currently we don't have a case when the 1) is done without the 2).
+	 */
+	if (ring->rxd_init) {
+		status = vxge_hw_ring_replenish(ring, VXGE_HW_OPEN_NORMAL, 1);
+		if (status != VXGE_HW_OK) {
+			__hw_ring_delete(vp);
+			goto exit;
+		}
+	}
+
+	/* initial replenish will increment the counter in its post() routine,
+	 * we have to reset it */
+	ring->stats->common_stats.usage_cnt = 0;
+exit:
+
+	return status;
+}
+
+/*
+ * __hw_ring_abort - Returns the RxD
+ * @ringh: Ring to be reset
+ * @reopen: See  enum vxge_hw_reopen{}.
+ *
+ * This function terminates the RxDs of ring
+ */
+enum vxge_hw_status
+__hw_ring_abort(
+	struct __hw_ring *ringh,
+	enum vxge_hw_reopen reopen)
+{
+	struct __hw_ring *ring = (struct __hw_ring *)ringh;
+	void *rxdh;
+	struct __hw_channel *channel;
+
+	vxge_assert(ringh != NULL);
+
+	channel = &ring->channel;
+
+	for (;;) {
+		vxge_hw_channel_dtr_try_complete(channel, &rxdh);
+
+		if (rxdh == NULL)
+			break;
+
+		vxge_hw_channel_dtr_complete(channel);
+
+		if (ring->rxd_term) {
+			ring->rxd_term(rxdh,
+				VXGE_HW_RXD_STATE_POSTED,
+				channel->userdata,
+				reopen);
+		}
+
+		vxge_hw_channel_dtr_free(channel, rxdh);
+
+	}
+
+	return VXGE_HW_OK;
+}
+
+/*
+ * __hw_ring_reset - Resets the ring
+ * @ringh: Ring to be reset
+ *
+ * This function resets the ring during vpath reset operation
+ */
+enum vxge_hw_status
+__hw_ring_reset(
+	struct __hw_ring *ringh)
+{
+	struct __hw_ring *ring = (struct __hw_ring *)ringh;
+	enum vxge_hw_status status = VXGE_HW_OK;
+	struct __hw_channel *channel;
+
+	vxge_assert(ringh != NULL);
+
+	channel = &ring->channel;
+
+	__hw_ring_abort(ringh, VXGE_HW_RESET_ONLY);
+
+	status = __hw_channel_reset(channel);
+
+	if (status != VXGE_HW_OK)
+		goto exit;
+
+	if (ring->rxd_init) {
+		status = vxge_hw_ring_replenish(ring, VXGE_HW_RESET_ONLY, 1);
+		if (status != VXGE_HW_OK)
+			goto exit;
+	}
+exit:
+
+	return status;
+}
+
+/*
+ * __hw_ring_delete - Removes the ring
+ * @vp: Virtual path handle to which this queue belongs
+ *
+ * This function freeup the memory pool and removes the ring
+ */
+enum vxge_hw_status
+__hw_ring_delete(
+	struct __hw_vpath_handle *vp)
+{
+	struct __hw_ring *ring;
+	struct __hw_channel *channel;
+	struct __hw_device *hldev;
+
+	vxge_assert(vp != NULL);
+
+	hldev = vp->vpath->hldev;
+	ring = (struct __hw_ring *)vp->vpath->ringh;
+
+	vxge_assert(ring != NULL);
+
+	channel = &ring->channel;
+
+	__hw_ring_abort(ring, VXGE_HW_OPEN_NORMAL);
+
+	if (ring->mempool)
+		__hw_mempool_destroy(ring->mempool);
+
+	vp->vpath->ringh = NULL;
+
+	__hw_channel_free(channel);
+
+	return VXGE_HW_OK;
+}
+
+/*
+ * __hw_mempool_grow
+ *
+ * Will resize mempool up to %num_allocate value.
+ */
+enum vxge_hw_status
+__hw_mempool_grow(
+	struct vxge_hw_mempool *mempool,
+	u32 num_allocate,
+	u32 *num_allocated)
+{
+	u32 i, first_time = mempool->memblocks_allocated == 0 ? 1 : 0;
+	u32 n_items = mempool->items_per_memblock;
+	u32 start_block_idx = mempool->memblocks_allocated;
+	u32 end_block_idx = mempool->memblocks_allocated  +  num_allocate;
+	enum vxge_hw_status status = VXGE_HW_OK;
+	vxge_assert(mempool != NULL);
+
+	*num_allocated = 0;
+
+	if (end_block_idx > mempool->memblocks_max) {
+
+		status = VXGE_HW_ERR_OUT_OF_MEMORY;
+		goto exit;
+	}
+
+	for (i = start_block_idx; i < end_block_idx; i++) {
+		u32 j;
+		u32 is_last = ((end_block_idx-1) == i);
+		struct vxge_hw_mempool_dma *dma_object =
+			mempool->memblocks_dma_arr  +  i;
+		void *the_memblock;
+
+		/* allocate memblock's private part. Each DMA memblock
+		 * has a space allocated for item's private usage upon
+		 * mempool's user request. Each time mempool grows, it will
+		 * allocate new memblock and its private part at once.
+		 * This helps to minimize memory usage a lot. */
+		mempool->memblocks_priv_arr[i] =
+				vmalloc(mempool->items_priv_size * n_items);
+		if (mempool->memblocks_priv_arr[i] == NULL) {
+
+			status = VXGE_HW_ERR_OUT_OF_MEMORY;
+			goto exit;
+
+		}
+
+		memset(mempool->memblocks_priv_arr[i], 0,
+			     mempool->items_priv_size * n_items);
+
+		/* allocate DMA-capable memblock */
+		mempool->memblocks_arr[i] =
+			__hw_blockpool_malloc(mempool->devh,
+				mempool->memblock_size,
+				&dma_object->addr,
+				&dma_object->handle,
+				&dma_object->acc_handle);
+		if (mempool->memblocks_arr[i] == NULL) {
+			vfree(mempool->memblocks_priv_arr[i]);
+
+			status = VXGE_HW_ERR_OUT_OF_MEMORY;
+			goto exit;
+		}
+
+		(*num_allocated)++;
+		mempool->memblocks_allocated++;
+
+		memset(mempool->memblocks_arr[i], 0,
+				mempool->memblock_size);
+
+		the_memblock = mempool->memblocks_arr[i];
+
+		/* fill the items hash array */
+		for (j = 0; j < n_items; j++) {
+			u32 index = i*n_items  +  j;
+
+			if (first_time && index >= mempool->items_initial)
+				break;
+
+			mempool->items_arr[index] =
+				((char *)the_memblock  +  j*mempool->item_size);
+
+			/* let caller to do more job on each item */
+			if (mempool->item_func_alloc != NULL) {
+				enum vxge_hw_status status;
+
+				status = mempool->item_func_alloc(
+					mempool,
+					the_memblock,
+					i,
+					dma_object,
+					mempool->items_arr[index],
+					index,
+					is_last,
+					mempool->userdata);
+			       if (status != VXGE_HW_OK) {
+
+					if (mempool->item_func_free != NULL) {
+						u32 k;
+
+						for (k = 0; k < j; k++) {
+							index = i * n_items + k;
+							(void)mempool->
+								item_func_free(
+							mempool, the_memblock,
+							i, dma_object,
+							mempool->
+							items_arr[index],
+							index, is_last,
+							mempool->userdata);
+						}
+					}
+
+					vfree(mempool->memblocks_priv_arr[i]);
+
+					__hw_blockpool_free(mempool->devh,
+					     the_memblock,
+					     mempool->memblock_size,
+					     &dma_object->addr,
+					     &dma_object->handle,
+					     &dma_object->acc_handle);
+
+					(*num_allocated)--;
+					mempool->memblocks_allocated--;
+					goto exit;
+				}
+			}
+
+			mempool->items_current = index  +  1;
+		}
+
+		if (first_time && mempool->items_current ==
+					mempool->items_initial)
+			break;
+	}
+exit:
+
+	return status;
+}
+
+/*
+ * vxge_hw_mempool_create
+ * @memblock_size:
+ * @items_initial:
+ * @items_max:
+ * @item_size:
+ * @item_func:
+ *
+ * This function will create memory pool object. Pool may grow but will
+ * never shrink. Pool consists of number of dynamically allocated blocks
+ * with size enough to hold %items_initial number of items. Memory is
+ * DMA-able but client must map/unmap before interoperating with the device.
+ * See also: vxge_os_dma_map(), vxge_hw_dma_unmap(), enum vxge_hw_status{}.
+ */
+struct vxge_hw_mempool*
+__hw_mempool_create(
+	struct __hw_device *devh,
+	u32 memblock_size,
+	u32 item_size,
+	u32 items_priv_size,
+	u32 items_initial,
+	u32 items_max,
+	struct vxge_hw_mempool_cbs *mp_callback,
+	void *userdata)
+{
+	enum vxge_hw_status status = VXGE_HW_OK;
+	u32 memblocks_to_allocate;
+	struct vxge_hw_mempool *mempool = NULL;
+	u32 allocated;
+
+	vxge_assert(devh != NULL);
+
+	if (memblock_size < item_size) {
+
+		status = VXGE_HW_FAIL;
+		goto exit;
+	}
+
+	mempool = (struct vxge_hw_mempool *) \
+			vmalloc(sizeof(struct vxge_hw_mempool));
+	if (mempool == NULL) {
+		status = VXGE_HW_ERR_OUT_OF_MEMORY;
+		goto exit;
+	}
+	memset(mempool, 0, sizeof(struct vxge_hw_mempool));
+
+	mempool->devh			= devh;
+	mempool->memblock_size		= memblock_size;
+	mempool->items_max		= items_max;
+	mempool->items_initial		= items_initial;
+	mempool->item_size		= item_size;
+	mempool->items_priv_size	= items_priv_size;
+	mempool->item_func_alloc	= mp_callback->item_func_alloc;
+	mempool->item_func_free		= mp_callback->item_func_free;
+	mempool->userdata		= userdata;
+
+	mempool->memblocks_allocated = 0;
+
+	if (memblock_size != VXGE_HW_BLOCK_SIZE)
+		mempool->dma_flags = VXGE_OS_DMA_CACHELINE_ALIGNED;
+
+#ifdef VXGE_HW_DMA_CONSISTENT
+	mempool->dma_flags |= VXGE_OS_DMA_CONSISTENT;
+#else
+	mempool->dma_flags |= VXGE_OS_DMA_STREAMING;
+#endif
+
+	mempool->items_per_memblock = memblock_size / item_size;
+
+	mempool->memblocks_max = (items_max + mempool->items_per_memblock - 1) /
+					mempool->items_per_memblock;
+
+	/* allocate array of memblocks */
+	mempool->memblocks_arr =
+		(void **) vmalloc(sizeof(void *) * mempool->memblocks_max);
+	if (mempool->memblocks_arr == NULL) {
+		__hw_mempool_destroy(mempool);
+		status = VXGE_HW_ERR_OUT_OF_MEMORY;
+		mempool = NULL;
+		goto exit;
+	}
+	memset(mempool->memblocks_arr, 0,
+		sizeof(void *) * mempool->memblocks_max);
+
+	/* allocate array of private parts of items per memblocks */
+	mempool->memblocks_priv_arr =
+		(void **) vmalloc(sizeof(void *) * mempool->memblocks_max);
+	if (mempool->memblocks_priv_arr == NULL) {
+		__hw_mempool_destroy(mempool);
+		status = VXGE_HW_ERR_OUT_OF_MEMORY;
+		mempool = NULL;
+		goto exit;
+	}
+	memset(mempool->memblocks_priv_arr, 0,
+		    sizeof(void *) * mempool->memblocks_max);
+
+	/* allocate array of memblocks DMA objects */
+	mempool->memblocks_dma_arr = (struct vxge_hw_mempool_dma *)\
+		vmalloc(sizeof(struct vxge_hw_mempool_dma) *\
+			mempool->memblocks_max);
+
+	if (mempool->memblocks_dma_arr == NULL) {
+		__hw_mempool_destroy(mempool);
+		status = VXGE_HW_ERR_OUT_OF_MEMORY;
+		mempool = NULL;
+		goto exit;
+	}
+	memset(mempool->memblocks_dma_arr, 0,
+			sizeof(struct vxge_hw_mempool_dma) *
+			mempool->memblocks_max);
+
+	/* allocate hash array of items */
+	mempool->items_arr =
+		(void **) vmalloc(sizeof(void *) * mempool->items_max);
+	if (mempool->items_arr == NULL) {
+		__hw_mempool_destroy(mempool);
+		status = VXGE_HW_ERR_OUT_OF_MEMORY;
+		mempool = NULL;
+		goto exit;
+	}
+	memset(mempool->items_arr, 0, sizeof(void *) * mempool->items_max);
+
+	mempool->shadow_items_arr =
+		(void **) vmalloc(sizeof(void *) *  mempool->items_max);
+	if (mempool->shadow_items_arr == NULL) {
+		__hw_mempool_destroy(mempool);
+		status = VXGE_HW_ERR_OUT_OF_MEMORY;
+		mempool = NULL;
+		goto exit;
+	}
+	memset(mempool->shadow_items_arr, 0,
+		     sizeof(void *) * mempool->items_max);
+
+	/* calculate initial number of memblocks */
+	memblocks_to_allocate = (mempool->items_initial  +
+				 mempool->items_per_memblock - 1) /
+						mempool->items_per_memblock;
+
+	/* pre-allocate the mempool */
+	status = __hw_mempool_grow(mempool, memblocks_to_allocate, &allocated);
+	memcpy(mempool->shadow_items_arr, mempool->items_arr,
+		    sizeof(void *) * mempool->items_max);
+	if (status != VXGE_HW_OK) {
+		__hw_mempool_destroy(mempool);
+		status = VXGE_HW_ERR_OUT_OF_MEMORY;
+		mempool = NULL;
+		goto exit;
+	}
+
+exit:
+
+	return mempool;
+}
+
+/*
+ * vxge_hw_mempool_destroy
+ */
+void
+__hw_mempool_destroy(
+	struct vxge_hw_mempool *mempool)
+{
+	u32 i, j;
+	struct __hw_device *devh;
+
+	vxge_assert(mempool != NULL);
+
+	devh = (struct __hw_device *)mempool->devh;
+
+	for (i = 0; i < mempool->memblocks_allocated; i++) {
+		struct vxge_hw_mempool_dma *dma_object;
+
+		vxge_assert(mempool->memblocks_arr[i]);
+		vxge_assert(mempool->memblocks_dma_arr  +  i);
+
+		dma_object = mempool->memblocks_dma_arr  +  i;
+
+		for (j = 0; j < mempool->items_per_memblock; j++) {
+			u32 index = i*mempool->items_per_memblock  +  j;
+
+			/* to skip last partially filled(if any) memblock */
+			if (index >= mempool->items_current)
+				break;
+
+			/* let caller to do more job on each item */
+			if (mempool->item_func_free != NULL) {
+
+				mempool->item_func_free(mempool,
+					mempool->memblocks_arr[i],
+					i, dma_object,
+					mempool->shadow_items_arr[index],
+					index, /* unused */ -1,
+					mempool->userdata);
+			}
+		}
+
+		vfree(mempool->memblocks_priv_arr[i]);
+
+		__hw_blockpool_free(devh,
+				mempool->memblocks_arr[i],
+				mempool->memblock_size,
+				&dma_object->addr,
+				&dma_object->handle,
+				&dma_object->acc_handle);
[… more lines in the raw message]

Lines of this file are not shown. View the raw message.

drivers/net/vxge/vxge-config.h +3323 -0

3,323 lines not on this page · raw message

The rest of this diff is not shown. View the raw message.

Part of the diff is not shown here. View the raw message.

#1 lore raw
Quoted 30 lines · Ramkrishna Vepa

This patch takes care of Initialization and configuration steps of Neterion Inc's X3100 Series 10GbE PCIe I/O Virtualized Server Adapter.
- Device Initialization.
- Verification and setting of device config parameters.
- Allocation of Tx FIFO and Rx Ring descriptors (DTR).
- APIs to get various type of hw stats
- APIs to configure RTS (Receive Traffic Steering)

---
diff -urpN patch_5/drivers/net/vxge/vxge-config.c patch_6/drivers/net/vxge/vxge-config.c

drivers/net/vxge/vxge-config.c +14 -0
@@ -0,0 +1,7576 @@
+/******************************************************************************
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License (GPL), incorporated herein by reference.
+ * Drivers based on or derived from this code fall under the GPL and must
+ * retain the authorship, copyright and license notice.  This file is not
+ * a complete program and may only be used when the entire operating
+ * system is licensed under the GPL.
+ * See the file COPYING in this distribution for more information.
+ ******************************************************************************/
+/*******************************************************************************
+ * vxge-config.c: Driver for Neterion Inc's X3100 Series 10GbE PCIe I/O
+ *                Virtualized Server Adapter.
+ * Copyright(c) 2002-2009 Neterion Inc.
+ ******************************************************************************/

drivers/net/vxge/vxge-config.c line 24

Quoted 10 lines
drivers/net/vxge/vxge-config.c +10 -0
+#include <linux/version.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include "vxge-traffic.h"
+#include "vxge-config.h"
+
+/*

You need to start a comment with "/**" to make it a kernel-doc comment.

Quoted 6 lines
drivers/net/vxge/vxge-config.c +6 -0
+ * __hw_channel_allocate - Allocate memory for channel
+ * @devh: Handle to the device object
+ * @vph: Handle to Virtual Path
+ * @type: Type of channel
+ * @length: Lengths of arrays
+ * @alloc_work_array: Flag to specify if work array is required

drivers/net/vxge/vxge-config.c line 40

Quoted 10 lines
drivers/net/vxge/vxge-config.c +10 -0
+ * @alloc_free_array: Flag to specify if free array is required
+ * @alloc_reserve_array: Flag to specify if reserve array is required
+ * @per_dtr_space: driver requested per dtr space to be allocated in priv
+ * @userdata: User data to be passed back in the callback
+ *
+ * This function allocates required memory for the channel and various arrays
+ * in the channel
+ */
+struct __hw_channel*
+__hw_channel_allocate(

Drivers in the kernel tree are not necessarily compiled as modules, so their external symbols must be globally unique. You should use a driver- specific prefix, presumably "vxge" (possibly with "__" in front of that).

[...]

Quoted 13 lines
drivers/net/vxge/vxge-config.c +13 -0
+/*
+ * __hw_channel_free - Free memory allocated for channel
+ * @channel: channel to be freed
+ *
+ * This function deallocates memory from the channel and various arrays
+ * in the channel
+ */
+void
+__hw_channel_free(
+	struct __hw_channel *channel)
+{
+	u32	vp_id = 0;
+	struct __hw_device  *hldev;

drivers/net/vxge/vxge-config.c line 163

Quoted 10 lines
drivers/net/vxge/vxge-config.c +10 -0
+
+	vxge_assert(channel != NULL);
+
+	hldev = (struct __hw_device  *)channel->devh;
+
+	vp_id = ((struct __hw_vpath_handle *)channel->vph)->vpath->vp_id;
+
+	if (channel->work_arr) {
+		vfree(channel->work_arr);
+		channel->work_arr = NULL;

Why bother clearing members of *channel just before you free it?

[...]

Quoted 8 lines
drivers/net/vxge/vxge-config.c +8 -0
+/*
+ * __hw_channel_initialize - Initialize a channel
+ * @channel: channel to be initialized
+ *
+ * This function initializes a channel by properly setting the
+ * various references
+ */
+enum vxge_hw_status

drivers/net/vxge/vxge-config.c line 202

Quoted 10 lines
drivers/net/vxge/vxge-config.c +10 -0
+__hw_channel_initialize(
+	struct __hw_channel *channel)
+{
+	u32 i;
+	struct __hw_virtualpath *vpath;
+
+	vxge_assert(channel != NULL);
+
+	vpath = (struct __hw_virtualpath *)((struct __hw_vpath_handle *) \
+						channel->vph)->vpath;

Why are you using backslashes in multi-line statements? This is only necessary in macro definitions.

[...]

drivers/net/vxge/vxge-config.c line 269

Quoted 8 lines
drivers/net/vxge/vxge-config.c +8 -0
+/*
+ * __hw_device_pci_caps_list_process
+ * @hldev: HW device handle.
+ *
+ * Process PCI capabilities and initialize the offsets
+ */
+void
+__hw_device_pci_caps_list_process(struct __hw_device *hldev)

This is redundant with pci_find_capability().

[...]

Quoted 16 lines
drivers/net/vxge/vxge-config.c +16 -0
+/*
+ * __hw_device_pci_e_init
+ * @hldev: HW device handle.
+ *
+ * Initialize certain PCI/PCI-X configuration registers
+ * with recommended values. Save config space for future hw resets.
+ */
+void
+__hw_device_pci_e_init(struct __hw_device *hldev)#
+{
+	int i;
+	u16 cmd = 0;
+	u16 device_id;
+	u8  revision;
+
+	vxge_assert(hldev != NULL);

drivers/net/vxge/vxge-config.c line 394

Quoted 10 lines
drivers/net/vxge/vxge-config.c +10 -0
+
+	/* Store PCI device ID and revision for future references where in we
+	 * decide Xena revision using PCI sub system ID */
+	pci_read_config_word(hldev->pdev,
+			vxge_offsetof(struct vxge_hw_pci_config_le, device_id),
+			&device_id);
+
+	pci_read_config_byte(hldev->pdev, vxge_offsetof(
+				struct vxge_hw_pci_config_le, revision),
+				&revision);

This information is in *hldev->pdev already.

drivers/net/vxge/vxge-config.c line 400

Quoted 5 lines
drivers/net/vxge/vxge-config.c +5 -0
+	/* save original PCI config space to restore it on device_terminate() */
+	for (i = 0; i < VXGE_HW_PCI_CONFIG_SPACE_SIZE/4; i++) {
+		pci_read_config_dword(hldev->pdev, i * 4,
+				(u32 *)&hldev->pci_config_space_bios  +  i);
+	}

Since you only change two bits in the command register, maybe you should just save those bits. Or not bother.

Quoted 6 lines
drivers/net/vxge/vxge-config.c +6 -0
+	__hw_device_pci_caps_list_process(hldev);
+
+	/* Set the PErr Repconse bit and SERR in PCI command register. */
+	pci_read_config_word(hldev->pdev,
+			vxge_offsetof(struct vxge_hw_pci_config_le, command),
+			&cmd);

drivers/net/vxge/vxge-config.c line 417

Quoted 10 lines
drivers/net/vxge/vxge-config.c +10 -0
+	cmd |= 0x140;
+	pci_write_config_word(hldev->pdev,
+			vxge_offsetof(struct vxge_hw_pci_config_le, command),
+			cmd);
+
+	/* save PCI config space for future resets */
+	for (i = 0; i < VXGE_HW_PCI_CONFIG_SPACE_SIZE/4; i++) {
+		pci_read_config_dword(hldev->pdev, i * 4,
+					(u32 *)&hldev->pci_config_space  +  i);
+	}


You should use pci_save_state() and pci_restore_state() around resets instead.

Quoted 22 lines
drivers/net/vxge/vxge-config.c +22 -0
+	return;
+}
+
+/*
+ * __hw_device_register_poll
+ * @reg: register to poll for
+ * @op: 0 - bit reset, 1 - bit set
+ * @mask: mask for logical "and" condition based on %op
+ * @max_millis: maximum time to try to poll in milliseconds
+ *
+ * Will poll certain register for specified amount of time.
+ * Will poll until masked bit is not cleared.
+ */
+enum vxge_hw_status
+__hw_device_register_poll(u64		*reg,
+			u32		op,
+			u64		mask,
+			u32		max_millis)
+{
+	u64 val64;
+	u32 i = 0;
+	enum vxge_hw_status ret = VXGE_HW_FAIL;

drivers/net/vxge/vxge-config.c line 450

Quoted 10 lines
drivers/net/vxge/vxge-config.c +10 -0
+
+	vxge_os_udelay(10);
+
+	do {
+		val64 = readq(reg);
+		if (op == 0 && !(val64 & mask))
+			return VXGE_HW_OK;
+		else if (op == 1 && (val64 & mask) == mask)
+			return VXGE_HW_OK;
+		vxge_os_udelay(100);

udelay(100)

drivers/net/vxge/vxge-config.c line 451

Quoted 1 line
drivers/net/vxge/vxge-config.c +1 -0
+	} while (++i <= 9);

You need to reset i to 0 or 1 after this, since you've waited 910 us not 9 ms.

drivers/net/vxge/vxge-config.c line 459

Quoted 7 lines
drivers/net/vxge/vxge-config.c +7 -0
+	do {
+		val64 = readq(reg);
+		if (op == 0 && !(val64 & mask))
+			return VXGE_HW_OK;
+		else if (op == 1 && (val64 & mask) == mask)
+			return VXGE_HW_OK;
+		vxge_os_udelay(1000);

mdelay(1)

drivers/net/vxge/vxge-config.c line 460

Quoted 1 line
drivers/net/vxge/vxge-config.c +1 -0
+	} while (++i < max_millis);

This should probably be a while() not a do...while().

drivers/net/vxge/vxge-config.c line 488

Quoted 8 lines
drivers/net/vxge/vxge-config.c +8 -0
+	return ret;
+}
+
+/*
+ * __hw_device_toc_get
+ * @bar0: Address of BAR0 in PCI config
+ *
+ * This routine sets the sapper and reads the toc pointer and returns the

Based on the function call below I'm guessing "sapper" should be "swapper".

Quoted 57 lines
drivers/net/vxge/vxge-config.c +57 -0
+ * memory mapped address of the toc
+ */
+struct vxge_hw_toc_reg *
+__hw_device_toc_get(u8 *bar0)
+{
+	u64 val64;
+	struct vxge_hw_toc_reg *toc = NULL;
+	enum vxge_hw_status status;
+	struct vxge_hw_legacy_reg *legacy_reg =
+		(struct vxge_hw_legacy_reg *)bar0;
+
+	status = __hw_legacy_swapper_set(legacy_reg);
+	if (status != VXGE_HW_OK)
+		goto exit;
+
+	val64 =	readq(&legacy_reg->toc_first_pointer);
+
+	toc = (struct vxge_hw_toc_reg *)(bar0+val64);
+
+exit:
+
+	return toc;
+}
+
+/*
+ * __hw_device_reg_addr_get
+ * @hldev: HW Device object.
+ *
+ * This routine sets the swapper and reads the toc pointer and initializes the
+ * register location pointers in the device object. It waits until the ric is
+ * completed initializing registers.
+ */
+enum vxge_hw_status
+__hw_device_reg_addr_get(struct __hw_device *hldev)
+{
+	u64 val64;
+	u32 i;
+	enum vxge_hw_status status = VXGE_HW_OK;
+
+	vxge_assert(hldev);
+
+	hldev->legacy_reg = (struct vxge_hw_legacy_reg *)hldev->bar0;
+
+	hldev->toc_reg = __hw_device_toc_get(hldev->bar0);
+	if (hldev->toc_reg  == NULL) {
+		status = VXGE_HW_FAIL;
+		goto exit;
+	}
+
+	val64 = readq(&hldev->toc_reg->toc_common_pointer);
+
+	hldev->common_reg =
+		(struct vxge_hw_common_reg *)(hldev->bar0  +  val64);
+
+	val64 = readq(&hldev->toc_reg->toc_memrepair_pointer);
+
+	hldev->memrepair_reg =

drivers/net/vxge/vxge-config.c line 555

Quoted 10 lines
drivers/net/vxge/vxge-config.c +10 -0
+		(struct vxge_hw_memrepair_reg *)(hldev->bar0  +  val64);
+
+	for (i = 0; i < VXGE_HW_TITAN_PCICFGMGMT_REG_SPACES; i++) {
+
+		val64 = readq(&hldev->toc_reg->toc_pcicfgmgmt_pointer[i]);
+
+		hldev->pcicfgmgmt_reg[i] = (struct vxge_hw_pcicfgmgmt_reg *) \
+						(hldev->bar0  +  val64);
+
+	}

This function

might have

too much

vertical whitespace.

[...]

Quoted 33 lines
drivers/net/vxge/vxge-config.c +33 -0
+/**
+ * __hw_device_get_vpd_data - Getting vpd_data.
+ *
+ *   @hldev: HW device handle.
+ *
+ *   Getting  product name and serial number from vpd capabilites structure
+ *
+ */
+void
+__hw_device_get_vpd_data(struct __hw_device *hldev)
+{
+	u8   *vpd_data;
+	u16  data;
+	u32  data32;
+	u32  index = 0, i, count, fail = 0;
+	u32  addr_offset;
+	u32  data_offset;
+	u32  max_count = hldev->config.device_poll_millis * 10;
+
+	vxge_assert(hldev);
+
+	addr_offset = hldev->pci_caps.vpd_cap_offset  +
+		vxge_offsetof(struct vxge_hw_vpid_capability_le, vpd_address);
+
+	data_offset = hldev->pci_caps.vpd_cap_offset  +
+		vxge_offsetof(struct vxge_hw_vpid_capability_le, vpd_data);
+	strcpy((char *) hldev->vpd_data.product_name,
+		"10 Gigabit Ethernet Adapter");
+
+	strcpy((char *) hldev->vpd_data.serial_num, "not available");
+
+	if ((hldev->host_type != VXGE_HW_NO_MR_NO_SR_NORMAL_FUNCTION) ||
+			(hldev->func_id != 0)) {

drivers/net/vxge/vxge-config.c line 869

Quoted 10 lines
drivers/net/vxge/vxge-config.c +10 -0
+		strcpy((char *) hldev->vpd_data.serial_num,
+				"not supported");
+		strcpy((char *) hldev->vpd_data.product_name,
+				"not supported");
+		return;
+	}
+	vpd_data = (u8 *) vmalloc(VXGE_HW_VPD_BUFFER_SIZE  +  16);
+	if (vpd_data == 0)
+		return;
+	for (index = 0; index < VXGE_HW_VPD_BUFFER_SIZE; index += 4) {

Use pci_read_vpd() instead of this loop.

[...]

drivers/net/vxge/vxge-config.c line 933

Quoted 11 lines
drivers/net/vxge/vxge-config.c +11 -0
+/*
+ * vxge_hw_wrr_rebalance - Rebalance the RX_WRR and KDFC_WRR calandars.
+ * @devh: HW device handle.
+ *
+ * Rebalance the RX_WRR and KDFC_WRR calandars.
+ *
+ */
+enum vxge_hw_status vxge_hw_wrr_rebalance(struct __hw_device *hldev)
+{
+	u64 val64;
+	u32 calender[176];

[...]

Why 176? This value should have at least a comment, but preferably a name or explicit formula.

Also should this variable be called "calendar"?

This is as far as I got.

Ben.

Signature · 3 lines
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
#2 lore raw
In reply to Ramkrishna Vepa

drivers/net/vxge/vxge-config.c line 49

Quoted 11 lines · Ramkrishna Vepa
drivers/net/vxge/vxge-config.c +11 -0
+struct __hw_channel*
+__hw_channel_allocate(
+	struct __hw_device *hldev,
+	struct __hw_vpath_handle *vph,
+	enum __hw_channel_type type,
+	u32 length,
+	u32 alloc_work_array,
+	u32 alloc_free_array,
+	u32 alloc_reserve_array,
+	u32 per_dtr_space,
+	void *userdata)

Having so many arguments in a function is usually a clear sign that it needs to be refactored into smaller functions.

drivers/net/vxge/vxge-config.c line 72

Quoted 1 line
drivers/net/vxge/vxge-config.c +1 -0
+	channel = (struct __hw_channel *) vmalloc(size);

You seem to use vmalloc nearly everywhere. First that has a lot of overhead (rounds up to pages, flushes TLBs) and also will cause more TLB misses. It's better to avoid it when not absolutely needed.

drivers/net/vxge/vxge-config.c line 157

Quoted 3 lines
drivers/net/vxge/vxge-config.c +3 -0
+	vxge_assert(channel != NULL);
+
+	hldev = (struct __hw_device  *)channel->devh;

That assert is pretyt pointless because you'll just get a NULL pointer reference next. Same true all over. asserts (or rather BUG_ON) only make sense when they check for something that's not nearly obvious given a oops.

drivers/net/vxge/vxge-config.c line 286

Quoted 8 lines
drivers/net/vxge/vxge-config.c +8 -0
+	while (next_ptr != 0) {
+
+		cap_id = VXGE_HW_PCI_CAP_ID((((u8 *)pci_config)  +  next_ptr));
+
+		switch (cap_id) {
+
+		case VXGE_HW_PCI_CAP_ID_PM:
+			hldev->pci_caps.pm_cap_offset = next_ptr;

This all could be done much shorter with a table.

drivers/net/vxge/vxge-config.c line 333

Quoted 4 lines
drivers/net/vxge/vxge-config.c +4 -0
+	if (VXGE_HW_PCI_CONFIG_SPACE_SIZE <= 0x100)
+		goto exit;
+
+	next_ptr = 0x100;

Such magic numbers are frowned upon.

Also in general you should use the pci capabilities accessor functions provided by the PCI layer.

Quoted 5 lines
drivers/net/vxge/vxge-config.c +5 -0
+			break;
+		case VXGE_HW_PCI_EXT_CAP_ID_DSN:
+			hldev->pci_e_ext_caps.dsn_cap_offset = next_ptr;
+			break;
+		case VXGE_HW_PCI_EXT_CAP_ID_PWR:

drivers/net/vxge/vxge-config.c line 361

Quoted 10 lines
drivers/net/vxge/vxge-config.c +10 -0
+			hldev->pci_e_ext_caps.pwr_budget_cap_offset = next_ptr;
+			break;
+
+		default:
+
+			break;
+		}
+
+		next_ptr = (u16)VXGE_HW_PCI_EXT_CAP_NEXT(
+				*(u32 *)(((u8 *)pci_config)  +  next_ptr));

Especially the patch orgies are scary. Does that really use readl() et.al. correctly? I doubt it. Again this should use the pci layer code for this.

drivers/net/vxge/vxge-config.c line 2053

Quoted 13 lines
drivers/net/vxge/vxge-config.c +13 -0
+/**
+ * vxge_hw_device_private_set - Set driver context.
+ * @hldev: HW device handle.
+ * @data: pointer to driver context
+ *
+ * Use HW device to set driver context.
+ *
+ * See also: vxge_hw_device_private_get()
+ */
+void vxge_hw_device_private_set(struct __hw_device *hldev, void *data)
+{
+	hldev->upper_layer_data = data;
+}

Such wrappers are not encouraged in Linux code, which aims to do with only necessary abstraction. Lots of occurrences.

drivers/net/vxge/vxge-config.c line 2116

Quoted 6 lines
drivers/net/vxge/vxge-config.c +6 -0
+
+#ifdef VXGE_HW_INTERNAL_COMPILER_ERROR
+
+#pragma optimize("", off)
+
+#endif

That's not for gcc isn't it?

drivers/net/vxge/vxge-config.c line 2129

Quoted 12 lines
drivers/net/vxge/vxge-config.c +12 -0
+/*
+ * __hw_ring_block_memblock_idx - Return the memblock index
+ * @block: Virtual address of memory block
+ *
+ * This function returns the index of memory block
+ */
+static inline u32
+__hw_ring_block_memblock_idx(
+	u8 (block)[VXGE_HW_BLOCK_SIZE])
+{
+	return (u32)*((u64 *)((u8 *)block  +
+		VXGE_HW_RING_MEMBLOCK_IDX_OFFSET));

Is that readl/writel clean again?

In general your driver looks like it could use a pass with sparse's __iomem checking (make V=1)

drivers/net/vxge/vxge-config.c line 2311

Quoted 10 lines
drivers/net/vxge/vxge-config.c +10 -0
+static enum vxge_hw_status
+__hw_ring_mempool_item_alloc(
+	struct vxge_hw_mempool *mempoolh,
+	void *memblock,
+	u32 memblock_index,
+	struct vxge_hw_mempool_dma *dma_object,
+	void *item,
+	u32 index,
+	u32 is_last,
+	void *userdata)

Again far too many arguments.

Stopped reading for now, but that file needs a lot of work in general.

-Andi

#3 lore raw

Andi,

Thanks for the comments. We are looking into them.

Question of the following -

Quoted 2 lines

In general your driver looks like it could use a pass with sparse's __iomem checking (make V=1)

How do I enable this checking?

Ram

Quoted 54 lines

drivers/net/vxge/vxge-config.c line 49

Quoted 11 lines
drivers/net/vxge/vxge-config.c +11 -0
+struct __hw_channel*
+__hw_channel_allocate(
+	struct __hw_device *hldev,
+	struct __hw_vpath_handle *vph,
+	enum __hw_channel_type type,
+	u32 length,
+	u32 alloc_work_array,
+	u32 alloc_free_array,
+	u32 alloc_reserve_array,
+	u32 per_dtr_space,
+	void *userdata)

Having so many arguments in a function is usually a clear sign that it needs
to be refactored into smaller functions.

drivers/net/vxge/vxge-config.c line 72

Quoted 1 line
drivers/net/vxge/vxge-config.c +1 -0
+	channel = (struct __hw_channel *) vmalloc(size);

You seem to use vmalloc nearly everywhere. First that has a lot of overhead (rounds up to pages, flushes TLBs) and also will cause more TLB misses. It's better to avoid it when not absolutely needed.

drivers/net/vxge/vxge-config.c line 157

Quoted 3 lines
drivers/net/vxge/vxge-config.c +3 -0
+	vxge_assert(channel != NULL);
+
+	hldev = (struct __hw_device  *)channel->devh;

That assert is pretyt pointless because you'll just get a NULL pointer reference next. Same true all over. asserts (or rather BUG_ON) only make sense when they check for something that's not nearly obvious given a oops.

drivers/net/vxge/vxge-config.c

Quoted 3 lines
drivers/net/vxge/vxge-config.c +3 -0
+	while (next_ptr != 0) {
+
+		cap_id = VXGE_HW_PCI_CAP_ID((((u8 *)pci_config)  +

next_ptr));

drivers/net/vxge/vxge-config.c line 286

Quoted 5 lines
drivers/net/vxge/vxge-config.c +5 -0
+
+		switch (cap_id) {
+
+		case VXGE_HW_PCI_CAP_ID_PM:
+			hldev->pci_caps.pm_cap_offset = next_ptr;

This all could be done much shorter with a table.

drivers/net/vxge/vxge-config.c line 333

Quoted 4 lines
drivers/net/vxge/vxge-config.c +4 -0
+	if (VXGE_HW_PCI_CONFIG_SPACE_SIZE <= 0x100)
+		goto exit;
+
+	next_ptr = 0x100;

Such magic numbers are frowned upon.

Also in general you should use the pci capabilities accessor functions provided by the PCI layer.

Quoted 6 lines

drivers/net/vxge/vxge-config.c

Quoted 6 lines
drivers/net/vxge/vxge-config.c +6 -0
+			break;
+		case VXGE_HW_PCI_EXT_CAP_ID_DSN:
+			hldev->pci_e_ext_caps.dsn_cap_offset = next_ptr;
+			break;
+		case VXGE_HW_PCI_EXT_CAP_ID_PWR:
+			hldev->pci_e_ext_caps.pwr_budget_cap_offset =

next_ptr;

Quoted 9 lines

drivers/net/vxge/vxge-config.c

Quoted 9 lines
drivers/net/vxge/vxge-config.c +9 -0
+			break;
+
+		default:
+
+			break;
+		}
+
+		next_ptr = (u16)VXGE_HW_PCI_EXT_CAP_NEXT(
+				*(u32 *)(((u8 *)pci_config)  +

next_ptr));

Quoted 2 lines

Especially the patch orgies are scary. Does that really use readl()

et.al.

Quoted 1 line

correctly? I doubt it. Again this should use the pci layer code for

this.

Quoted 11 lines

drivers/net/vxge/vxge-config.c

Quoted 11 lines
drivers/net/vxge/vxge-config.c +10 -0
+/**
+ * vxge_hw_device_private_set - Set driver context.
+ * @hldev: HW device handle.
+ * @data: pointer to driver context
+ *
+ * Use HW device to set driver context.
+ *
+ * See also: vxge_hw_device_private_get()
+ */
+void vxge_hw_device_private_set(struct __hw_device *hldev, void

*data)

Quoted 57 lines

drivers/net/vxge/vxge-config.c line 2053

Quoted 3 lines
drivers/net/vxge/vxge-config.c +3 -0
+{
+	hldev->upper_layer_data = data;
+}

Such wrappers are not encouraged in Linux code, which aims to do with only necessary abstraction. Lots of occurrences.

drivers/net/vxge/vxge-config.c line 2116

Quoted 6 lines
drivers/net/vxge/vxge-config.c +6 -0
+
+#ifdef VXGE_HW_INTERNAL_COMPILER_ERROR
+
+#pragma optimize("", off)
+
+#endif

That's not for gcc isn't it?

drivers/net/vxge/vxge-config.c line 2129

Quoted 12 lines
drivers/net/vxge/vxge-config.c +12 -0
+/*
+ * __hw_ring_block_memblock_idx - Return the memblock index
+ * @block: Virtual address of memory block
+ *
+ * This function returns the index of memory block
+ */
+static inline u32
+__hw_ring_block_memblock_idx(
+	u8 (block)[VXGE_HW_BLOCK_SIZE])
+{
+	return (u32)*((u64 *)((u8 *)block  +
+		VXGE_HW_RING_MEMBLOCK_IDX_OFFSET));

Is that readl/writel clean again?

In general your driver looks like it could use a pass with sparse's __iomem checking (make V=1)

drivers/net/vxge/vxge-config.c line 2311

Quoted 10 lines
drivers/net/vxge/vxge-config.c +10 -0
+static enum vxge_hw_status
+__hw_ring_mempool_item_alloc(
+	struct vxge_hw_mempool *mempoolh,
+	void *memblock,
+	u32 memblock_index,
+	struct vxge_hw_mempool_dma *dma_object,
+	void *item,
+	u32 index,
+	u32 is_last,
+	void *userdata)

Again far too many arguments.

Stopped reading for now, but that file needs a lot of work in general.

-Andi

--
To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#4 lore raw
Quoted 8 lines · Ramkrishna Vepa

Andi,

Thanks for the comments. We are looking into them.

Question of the following -

Quoted 2 lines

In general your driver looks like it could use a pass with sparse's __iomem checking (make V=1)

How do I enable this checking?

What Andi said, only without the typo: run "make C=1 drivers/net/vxge/"

Ben.

Signature · 3 lines
Ben Hutchings, Senior Software Engineer, Solarflare Communications
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
#5 lore raw

RE: [net-2.6 PATCH 6/10] Neterion: New driver: Hardware init &configuration

Ben,
Got it.

Thanks,
Ram

Quoted 8 lines

-----Original Message-----
From: Ben Hutchings [mailto:[email protected]]
Sent: Monday, March 16, 2009 8:35 PM
To: Ramkrishna Vepa
Cc: Andi Kleen; Netdev; David Miller
Subject: RE: [net-2.6 PATCH 6/10] Neterion: New driver: Hardware init &configuration

Quoted 7 lines
Quoted 6 lines · Ramkrishna Vepa

Andi,

Thanks for the comments. We are looking into them.

Question of the following -

Quoted 1 line

In general your driver looks like it could use a pass with

sparse's

Quoted 4 lines
Quoted 2 lines
Quoted 1 line

__iomem checking (make V=1)

How do I enable this checking?

What Andi said, only without the typo: run "make C=1

drivers/net/vxge/"

Quoted 7 lines

Ben.

--
Ben Hutchings, Senior Software Engineer, Solarflare Communications Not speaking for my employer; that's the marketing department's job. They asked us to note that Solarflare product names are trademarked.

#6 lore raw
In reply to Ramkrishna Vepa
Quoted 4 lines · Ramkrishna Vepa

Question of the following -

Quoted 2 lines

In general your driver looks like it could use a pass with sparse's __iomem checking (make V=1)

How do I enable this checking?

Install sparse and then

make V=1

and add __iomem annotations as needed.

There will be a lot of warnings, it's likely enough to concentrate on iomem first pass.

-Andi