[openib-general] [PATCH 5/9] NetEffect 10Gb RNIC Driver: hardware interface c file

Glenn Grundstrom ggrundstrom at NetEffect.com
Thu Oct 26 17:09:39 PDT 2006


Kernel driver patch 5 of 9.

Signed-off-by: Glenn Grundstrom <glenng at neteffect.com>

======================================================

diff -ruNp old/drivers/infiniband/hw/nes/nes_hw.c
new/drivers/infiniband/hw/nes/nes_hw.c
--- old/drivers/infiniband/hw/nes/nes_hw.c	1969-12-31
18:00:00.000000000 -0600
+++ new/drivers/infiniband/hw/nes/nes_hw.c	2006-10-25
10:15:50.000000000 -0500
@@ -0,0 +1,1470 @@
+/*
+ * Copyright (c) 2006 NetEffect, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/etherdevice.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+
+#include "nes.h"
+
+
+#if defined(SA1)
+struct nes_init_values init_values[] = 
+{
+	{0x00000600,0x55555555}, 
+	{0x00000604,0x55555555}, 
+	{0x00002000,0x00000001}, 
+	{0x00002004,0x00000001}, 
+	{0x00002008,0x0000FFFF}, 
+	{0x0000200C,0x00000001}, 
+	{0x00002010,0x00000241}, 
+	{0x0000201C,0x75345678}, 
+	{0x00005100,0x00000008}, 
+	{0x00006000,0x000000e0}, 
+	{0x00006008,0x000000e0}, 
+//	{0x00006018,0x00000001}, 
+//	{0x00006028,0x00000001}, 
+	{0x00006038,0x00000003}, 
+	{0x000060B8,0x00000002}, 
+	{0x00006090,0xFFFFFFFF}, 
+	{0x00000900,0x20000001}, 
+//	{0x000001E8,0x000208c2}, 
+	{0x000001E8,0x000208c4}, 
+	{0x000001EC,0x5f1e8480}, 
+	{0x000001FC,0x00050005}, 
+	{0x00000B00,0x00001000}, 
+	{0x000010C8,0x00000003}, 
+	{0x00005008,0x1F1F1F1F}, 
+	{0x00005010,0x1F1F1F1F}, 
+	{0x00005018,0x1F1F1F1F}, 
+	{0x00005020,0x1F1F1F1F}, 
+//	{0x000060B8,0x00000001}, 
+	{0x000060C0,0x00000194}, 
+	{0x000060C8,0x00000020}, 
+	{0x00000000,0x00000000}	 
+};
+#endif
+
+
+/**
+ * nes_adapter_init - initialize adapter
+ *
+ * @param nesdev
+ * @param num_pds
+ * 
+ * @return struct nes_adapter*
+ */
+struct nes_adapter *nes_adapter_init(struct nes_dev *nesdev, unsigned
long num_pds) {
+	struct nes_adapter *nesadapter = NULL;
+	int i=0;
+	int found = 0;
+	u32 u32temp;
+	u16 max_rq_wrs;
+	u16 max_sq_wrs;
+	u32 max_mr;
+	u32 max_256pbl;
+	u32 max_4kpbl;
+	u32 max_qp;
+	u32 max_irrq;
+	u32 max_cq;
+	u32 hte_index_mask;
+	u32 adapter_size;
+	u32 arp_table_size;
+
+	/* search the list of existing adapters */
+	list_for_each_entry(nesadapter, &nes_adapter_list, list) {
+		dprintk("Searching Adapter list for PCI devfn =
0x%X.\n", nesdev->pcidev->devfn);
+		if ((PCI_SLOT(nesadapter->devfn) ==
PCI_SLOT(nesdev->pcidev->devfn)) && 
+			(nesadapter->bus_number ==
nesdev->pcidev->bus->number)) {
+			found = 1;           
+			break;
+		}
+	}
+
+	if (!found) {
+		if (nes_read_indexed(nesdev->index_reg, 
+
NES_IDX_QP_CONTROL+PCI_FUNC(nesdev->pcidev->devfn)*8)) {
+			nes_write32(nesdev->regs+NES_SOFTWARE_RESET,
0xd);
+		}
+		/* enable the ports */
+		nes_write32(nesdev->regs+NES_SOFTWARE_RESET, 0);
+
+		u32temp = 0;
+		while ( nes_read_indexed(nesdev->index_reg, 
+
NES_IDX_INT_CPU_STATUS) != 0x80 ) {
+			if (u32temp++ > 10000) break;
+			mdelay(1);
+		}
+
+		if (nes_read_indexed(nesdev->index_reg,
NES_IDX_INT_CPU_STATUS) != 0x80) {
+			printk(KERN_ERR PFX "Internal CPU not ready,
status = %02X\n",
+
nes_read_indexed(nesdev->index_reg, NES_IDX_INT_CPU_STATUS) );
+			return NULL;
+		}
+
+		while ( init_values[i].index != 0 ) {
+			nes_write_indexed(nesdev->index_reg, 
+
init_values[i].index, init_values[i].data);
+			i++;
+		}
+
+		nes_write_indexed(nesdev->index_reg,
NES_IDX_GPIO_CONTROL, 0x00000070);
+		nes_write_indexed(nesdev->index_reg, NES_IDX_GPIO_DATA,
0);
+
+		u32temp = nes_read_indexed(nesdev->index_reg,
NES_IDX_TCP_TIMER_SIZE0);
+		u32temp &= 0xf0f0f0f0;
+		u32temp |= 0x05050105; 
+		u32temp &= 0xffffff0f;
+		u32temp |= 0x00000090; 
+		nes_write_indexed(nesdev->index_reg,
NES_IDX_TCP_TIMER_SIZE0, u32temp);
+
+		u32temp = nes_read_indexed(nesdev->index_reg,
NES_IDX_TCP_TIMER_SIZE1);
+		u32temp &= 0x0000f0f0;
+		u32temp |= 0x00000505; 
+		u32temp &= 0xffff0f0f;
+		u32temp |= 0x00009090; 
+		nes_write_indexed(nesdev->index_reg,
NES_IDX_TCP_TIMER_SIZE1, u32temp);
+
+		u32temp = nes_read_indexed(nesdev->index_reg,
NES_IDX_TCP_CONFIG0);
+		u32temp |= 0x00000001;
+		nes_write_indexed(nesdev->index_reg,
NES_IDX_TCP_CONFIG0, u32temp);
+
+		nes_write_indexed(nesdev->index_reg,
NES_IDX_DENALI_CTL_22, 0x00FF0000);
+
+		nesadapter->tick_delta = 2000;
+		u32temp = nes_read_indexed(nesdev->index_reg,
NES_IDX_TCP_TIMER_CONFIG);
+		nes_write_indexed(nesdev->index_reg,
NES_IDX_TCP_TIMER_CONFIG, 
+
(u32temp&0xff000000)|((nesadapter->tick_delta*1000)&0x00ffffff)); // set
to 10ms
+
+		max_qp = nes_read_indexed(nesdev->index_reg,
NES_IDX_QP_CTX_SIZE);
+		u32temp = nes_read_indexed(nesdev->index_reg,
NES_IDX_QUAD_HASH_TABLE_SIZE);
+		if (max_qp > ((u32)1 << (u32temp & 0x001f))) {
+			dprintk("Reducing Max QPs to %u due to hash
table size. ht size reg = 0x%08X\n", max_qp, u32temp );
+			max_qp = (u32)1 << (u32temp & 0x001f);
+		}
+
+		hte_index_mask = ((u32)1 << ((u32temp & 0x001f)+1))-1;
+		dprintk("Max QP = %u, hte_index_mask = 0x%08X.\n",
max_qp, hte_index_mask);
+
+		u32temp = nes_read_indexed(nesdev->index_reg,
NES_IDX_IRRQ_COUNT);
+
+		max_irrq = 1<<(u32temp&0x001f);
+
+		if (max_qp > max_irrq) {
+			max_qp = max_irrq;
+			dprintk("Reducing Max QPs to %u due to Available
Q1s.\n", max_qp);
+		}
+
+		/* there should be no reason to allocate more pds than
qps */
+		if (num_pds > max_qp)
+			num_pds = max_qp;
+
+		u32temp = nes_read_indexed(nesdev->index_reg,
NES_IDX_MRT_SIZE);
+		max_mr = (u32)8192 << (u32temp&0x3);
+
+		u32temp = nes_read_indexed(nesdev->index_reg,
NES_IDX_PBL_REGION_SIZE);
+		max_256pbl = (u32)1 << (u32temp & 0x0000001f);
+		max_4kpbl = (u32)1 << ((u32temp>>16) & 0x0000001f);
+		max_cq = nes_read_indexed(nesdev->index_reg,
NES_IDX_CQ_CTX_SIZE);
+
+		arp_table_size = NES_ARP_TABLE_SIZE;
+		max_qp -= 5;
+		arp_table_size -= 5;
+
+		adapter_size = (sizeof(struct
nes_adapter)+(sizeof(unsigned long)-1))&(~(sizeof(unsigned long)-1)); 
+		adapter_size += sizeof(unsigned
long)*BITS_TO_LONGS(max_qp);
+		adapter_size += sizeof(unsigned
long)*BITS_TO_LONGS(max_mr);
+		adapter_size += sizeof(unsigned
long)*BITS_TO_LONGS(max_cq);
+		adapter_size += sizeof(unsigned
long)*BITS_TO_LONGS(num_pds);
+		adapter_size += sizeof(unsigned long) *
BITS_TO_LONGS(NES_ARP_TABLE_SIZE);
+		adapter_size += sizeof(struct nes_qp **)*max_qp;
+
+		nesadapter = kzalloc(adapter_size, GFP_KERNEL);
+		dprintk("Adapter not found, allocating new one @ %p,
size = %u (actual size = %u).\n", nesadapter, (u32)sizeof(struct
nes_adapter), adapter_size);
+		if (nesadapter){
+			nesadapter->devfn = nesdev->pcidev->devfn;
+			nesadapter->bus_number =
nesdev->pcidev->bus->number;
+			nesadapter->ref_count = 1;
+			
+			nesadapter->max_qp = max_qp;
+			nesadapter->hte_index_mask = hte_index_mask;
+			nesadapter->max_irrq = max_irrq;
+			nesadapter->max_mr = max_mr;
+			nesadapter->max_256pbl = max_256pbl - 1;
+			nesadapter->max_4kpbl = max_4kpbl - 1;
+			nesadapter->max_cq = max_cq;
+			nesadapter->free_256pbl = max_256pbl-1;
+			nesadapter->free_4kpbl = max_4kpbl-1;
+			nesadapter->max_pd = num_pds;
+			nesadapter->arp_table_size = arp_table_size;
+			nesadapter->base_pd = 1;
+
+			nesadapter->allocated_qps = (unsigned long
*)&(((unsigned char *)nesadapter)[(sizeof(struct
nes_adapter)+(sizeof(unsigned long)-1))&(~(sizeof(unsigned long)-1))]);
+			nesadapter->allocated_cqs =
&nesadapter->allocated_qps[BITS_TO_LONGS(max_qp)];
+			nesadapter->allocated_mrs =
&nesadapter->allocated_cqs[BITS_TO_LONGS(max_cq)];
+			nesadapter->allocated_pds =
&nesadapter->allocated_mrs[BITS_TO_LONGS(max_mr)];
+			nesadapter->allocated_arps =
&nesadapter->allocated_pds[BITS_TO_LONGS(num_pds)];
+			nesadapter->qp_table = (struct nes_qp
**)(&nesadapter->allocated_arps[BITS_TO_LONGS(NES_ARP_TABLE_SIZE)]);
+
+
+			/* mark the usual suspect QPs and CQs as in use
*/
+			for (u32temp=0; u32temp<NES_FIRST_QPN;
u32temp++) {
+				set_bit(u32temp,
nesadapter->allocated_qps);
+				set_bit(u32temp,
nesadapter->allocated_cqs);
+			}
+			
+			u32temp = nes_read_indexed(nesdev->index_reg,
NES_IDX_QP_MAX_CFG_SIZES);
+			
+			max_rq_wrs = ((u32temp>>8) & 3);
+			switch (max_rq_wrs) {
+				case 0:
+					max_rq_wrs = 4;
+					break;
+				case 1:
+					max_rq_wrs = 16;
+					break;
+				case 2:
+					max_rq_wrs = 32;
+					break;
+				case 3:
+					max_rq_wrs = 512;
+					break;
+			}
+			
+			max_sq_wrs = (u32temp & 3);
+			switch (max_sq_wrs) {
+				case 0:
+					max_sq_wrs = 4;
+					break;
+				case 1:
+					max_sq_wrs = 16;
+					break;
+				case 2:
+					max_sq_wrs = 32;
+					break;
+				case 3:
+					max_sq_wrs = 512;
+					break;
+			}
+			nesadapter->max_qp_wr = min(max_rq_wrs,
max_sq_wrs);
+			dprintk("Max wqes = %u.\n",
nesadapter->max_qp_wr );
+
+			/* Encoded */
+			nesadapter->max_irrq_wr = (u32temp >> 16) & 3;
+//			dprintk("%s: Max IRRQ wqes = %u.\n",
__FUNCTION__, nesadapter->max_irrq_wr );
+			
+			nesadapter->max_sge = 4;
+			nesadapter->max_cqe = 32767;
+
+			dprintk("%s:Initializing adapter resource lock
(%p).\n", 
+					__FUNCTION__,
&nesadapter->resource_lock );
+			spin_lock_init(&nesadapter->resource_lock);
+			
+			list_add_tail(&nesadapter->list,
&nes_adapter_list);
+			i = 0;
+			
+		}
+	}else 
+		nesadapter->ref_count++;
+
+	return nesadapter;
+}
+
+
+/**
+ * nes_cqp_init
+ * 
+ * @param nesdev
+ * 
+ * @return int
+ */
+int nes_cqp_init(struct nes_dev *nesdev)
+{
+	struct nes_port *nes_port = NULL;
+	struct nes_adapter *nesadapter = nesdev->nesadapter;
+	struct net_device *netdev = alloc_etherdev(sizeof(*nes_port));
+	struct nes_hw_cqp_qp_context *cqp_qp_context;
+	struct nes_hw_cqp_wqe *cqp_wqe;
+	struct nes_hw_ceq *ceq;
+	struct nes_hw_aeq *aeq;
+	void *mem;
+	char *lmi_buf;
+	dma_addr_t lmi_dma_handle;
+	u32 count=0;
+	u32 cqp_head;
+	u64 u64temp;
+
+	// Allocate Memory
+	nesdev->cqp_mem_size =  (sizeof(struct
nes_hw_cqp_wqe)*NES_CQP_SQ_SIZE) +	  /* needs 512 byte alignment */
+							(sizeof(struct
nes_hw_cqe)*NES_CCQ_SIZE) +			  /* needs 256 byte
alignment */
+							(sizeof(struct
nes_hw_ceqe)*nesadapter->max_cq) +	  /* needs 256 byte alignment */
+							(sizeof(struct
nes_hw_aeqe)*nesadapter->max_qp) +	  /* needs 256 byte alignment */
+							sizeof(struct
nes_hw_cqp_qp_context) +				  /* needs 8
byte alignment */
+							8192;
/* this is the masq table */
+
+	mem = pci_alloc_consistent(nesdev->pcidev, nesdev->cqp_mem_size,
+
&nesdev->cqp.sq_pbase);
+	if (!mem) {
+		dprintk(KERN_ERR PFX "Unable to allocate memory for "
+				"host descriptor rings\n");
+		free_netdev(netdev);
+		return ERR_PTR(-ENOMEM);
+	}
+	dprintk("Allocated CQP structures at %p (phys = %016lX), size =
%u.\n", mem, 
+			(unsigned long)nesdev->cqp.sq_pbase,
nesdev->cqp_mem_size);
+	if (((u64)((unsigned)mem))&(512-1)) {
+		dprintk("CQP SQ base (%p) not 512 byte aligned.\n",
mem);
+	}
+	memset(mem, 0, nesdev->cqp_mem_size);
+
+	nesdev->mac_index = PCI_FUNC(nesdev->pcidev->devfn);
+	spin_lock_init(&nesdev->cqp.lock);
+	init_waitqueue_head( &nesdev->cqp.waitq );
+
+	// Setup Various Structures
+	nesdev->cqp.sq_vbase = mem;
+	nesdev->cqp.sq_size = NES_CQP_SQ_SIZE;
+	nesdev->cqp.sq_head = 0;
+	nesdev->cqp.sq_tail = 0;
+	nesdev->cqp.qp_id = PCI_FUNC(nesdev->pcidev->devfn);
+	mem += sizeof(struct nes_hw_cqp_wqe)*nesdev->cqp.sq_size;
+
+	nesdev->ccq.cq_vbase = mem;
+	nesdev->ccq.cq_pbase = nesdev->cqp.sq_pbase + (sizeof(struct
nes_hw_cqp_wqe)*nesdev->cqp.sq_size);
+	nesdev->ccq.cq_size = NES_CCQ_SIZE;
+	nesdev->ccq.cq_head = 0;
+	nesdev->ccq.ce_handler = cqp_ce_handler;
+	nesdev->ccq.cq_number = PCI_FUNC(nesdev->pcidev->devfn);
+	mem += sizeof(struct nes_hw_cqe)*nesdev->ccq.cq_size;
+	dprintk("CCQ  at %p (phys = %016lX).\n", nesdev->ccq.cq_vbase,
(unsigned long)nesdev->ccq.cq_pbase);
+
+	ceq = &nesadapter->ceq[PCI_FUNC(nesdev->pcidev->devfn)];
+	ceq->ceq_vbase = mem;
+	ceq->ceq_pbase = nesdev->ccq.cq_pbase + (sizeof(struct
nes_hw_cqe)*nesdev->ccq.cq_size);
+	ceq->ceq_size = nesadapter->max_cq;
+	ceq->ceq_head = 0;
+	mem += sizeof(struct nes_hw_ceqe)*nesadapter->max_cq;
+	dprintk("CEQ  at %p (phys = %016lX).\n", ceq->ceq_vbase,
(unsigned long)ceq->ceq_pbase);
+
+	aeq = &nesadapter->aeq[PCI_FUNC(nesdev->pcidev->devfn)];
+	aeq->aeq_vbase = mem;
+	aeq->aeq_pbase = ceq->ceq_pbase + (sizeof(struct
nes_hw_ceqe)*nesadapter->max_cq);
+	aeq->aeq_size = nesadapter->max_qp;
+	aeq->aeq_head = 0;
+	mem += sizeof(struct nes_hw_aeqe)*nesadapter->max_qp;
+	dprintk("AEQ  at %p (phys = %016lX).\n", aeq->aeq_vbase,
(unsigned long)aeq->aeq_pbase);
+
+	// Setup QP Context
+	cqp_qp_context = mem;
+	cqp_qp_context->context_words[0] =
(PCI_FUNC(nesdev->pcidev->devfn)<<12) + (1<<10);
+	cqp_qp_context->context_words[1] = 0;
+	cqp_qp_context->context_words[2] = (u32)nesdev->cqp.sq_pbase;
+	cqp_qp_context->context_words[3] =
((u64)nesdev->cqp.sq_pbase)>>32;
+	mem += sizeof(struct nes_hw_cqp_qp_context);
+
+	nesdev->apbv_table = mem;
+	memset(nesdev->apbv_table, 0, sizeof(*nesdev->apbv_table));
+
+	dprintk("Address of CQP Context = %p.\n", cqp_qp_context);
+	for (count=0;count<4 ; count++ ) {
+		dprintk("CQP Context, Line %u = %08X.\n", count,
cqp_qp_context->context_words[count]); 
+	}
+
+	// Write the address to Create CQP
+	if ((sizeof(dma_addr_t) > 4)) {
+		nes_write_indexed(nesdev->index_reg, 
+
NES_IDX_CREATE_CQP_HIGH+(PCI_FUNC(nesdev->pcidev->devfn)*8), 
+
((u64)aeq->aeq_pbase+(sizeof(struct nes_hw_aeqe)*aeq->aeq_size))>>32);
+	} else {
+		nes_write_indexed(nesdev->index_reg, 
+
NES_IDX_CREATE_CQP_HIGH+(PCI_FUNC(nesdev->pcidev->devfn)*8), 0);
+	}
+	nes_write_indexed(nesdev->index_reg, 
+
NES_IDX_CREATE_CQP_LOW+(PCI_FUNC(nesdev->pcidev->devfn)*8), 
+
(u32)(aeq->aeq_pbase+(sizeof(struct nes_hw_aeqe)*aeq->aeq_size)));
+
+	dprintk("Address of CQP SQ = %p.\n", nesdev->cqp.sq_vbase);
+
+	lmi_buf = pci_alloc_consistent(nesdev->pcidev, 1024,
&lmi_dma_handle);
+	if (lmi_buf == NULL) {
+		free_netdev(netdev);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	cqp_head = nesdev->cqp.sq_head++;
+	cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+	cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] =
cpu_to_le32(NES_CQP_LMI_ACCESS + 0x20000000);
+	cqp_wqe->wqe_words[NES_CQP_LMI_WQE_LMI_OFFSET_IDX] =  0;
+	cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] =  0;
+	*((struct nes_hw_cqp
**)&cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_LOW_IDX]) =  &nesdev->cqp;
+	cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] =
0x01010101;
+	cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] =
0x02020202;
+	u64temp = (u64)lmi_dma_handle;
+	cqp_wqe->wqe_words[NES_CQP_LMI_WQE_FRAG_LOW_IDX] =
cpu_to_le32((u32)u64temp);
+	cqp_wqe->wqe_words[NES_CQP_LMI_WQE_FRAG_HIGH_IDX] =
cpu_to_le32((u32)(u64temp >> 32));
+	cqp_wqe->wqe_words[NES_CQP_LMI_WQE_FRAG_LEN_IDX] =
cpu_to_le32(1024);
+
+	// Write Create CCQ WQE
+	cqp_head = nesdev->cqp.sq_head++;
+	cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+	cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] =
cpu_to_le32(NES_CQP_CREATE_CQ | NES_CQP_CQ_CEQ_VALID | 
+
NES_CQP_CQ_CHK_OVERFLOW | (nesdev->ccq.cq_size<<16));
+	cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] =
cpu_to_le32(PCI_FUNC(nesdev->pcidev->devfn) || 
+
(PCI_FUNC(nesdev->pcidev->devfn)<<16));
+	cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] =  0;
+	*((struct nes_hw_cqp
**)&cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_LOW_IDX]) =  &nesdev->cqp;
+	cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] =
0x03030303;
+	cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] =
0x04040404;
+	u64temp = (u64)nesdev->ccq.cq_pbase;
+	cqp_wqe->wqe_words[NES_CQP_CQ_WQE_PBL_LOW_IDX] =
cpu_to_le32((u32)u64temp);
+	cqp_wqe->wqe_words[NES_CQP_CQ_WQE_PBL_HIGH_IDX] =
cpu_to_le32((u32)(u64temp>>32));
+	cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] =  0;
+	/* TODO: the following 2 lines likely have endian issues */
+	*((struct nes_hw_cq
**)&cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_LOW_IDX]) =
&nesdev->ccq;
+	*((u64 *)&cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_LOW_IDX])
>>= 1;
+	dprintk("%s: CQ%u context = 0x%08X:0x%08X.\n", __FUNCTION__,
nesdev->ccq.cq_number, 
+		cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX], 
+		cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_LOW_IDX]);
+	
+	cqp_wqe->wqe_words[NES_CQP_CQ_WQE_DOORBELL_INDEX_HIGH_IDX] =  0;
+
+	// Write Create CEQ WQE
+	cqp_head = nesdev->cqp.sq_head++;
+	cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+	cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] =
cpu_to_le32(NES_CQP_CREATE_CEQ + (PCI_FUNC(nesdev->pcidev->devfn)<<8));
+	cqp_wqe->wqe_words[NES_CQP_CEQ_WQE_ELEMENT_COUNT_IDX] =
cpu_to_le32(ceq->ceq_size);
+	cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] =  0;
+	*((struct nes_hw_cqp
**)&cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_LOW_IDX]) =  &nesdev->cqp;
+	cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] =
0x05050505;
+	cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] =
0x06060606;
+	u64temp = (u64)ceq->ceq_pbase;
+	cqp_wqe->wqe_words[NES_CQP_CEQ_WQE_PBL_LOW_IDX] =
cpu_to_le32((u32)u64temp);
+	cqp_wqe->wqe_words[NES_CQP_CEQ_WQE_PBL_HIGH_IDX] =
cpu_to_le32((u32)(u64temp>>32));
+
+	// Write Create AEQ WQE
+	cqp_head = nesdev->cqp.sq_head++;
+	cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+	cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] =
cpu_to_le32(NES_CQP_CREATE_AEQ + (PCI_FUNC(nesdev->pcidev->devfn)<<8));
+	cqp_wqe->wqe_words[NES_CQP_AEQ_WQE_ELEMENT_COUNT_IDX] =
cpu_to_le32(aeq->aeq_size);
+	cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] =  0;
+	*((struct nes_hw_cqp
**)&cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_LOW_IDX]) =  &nesdev->cqp;
+	cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] =
0x07070707;
+	cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] =
0x08080808;
+	u64temp = (u64)aeq->aeq_pbase;
+	cqp_wqe->wqe_words[NES_CQP_AEQ_WQE_PBL_LOW_IDX] =
cpu_to_le32((u32)u64temp);
+	cqp_wqe->wqe_words[NES_CQP_AEQ_WQE_PBL_HIGH_IDX] =
cpu_to_le32((u32)(u64temp>>32));
+
+	// Poll until CCQP done
+	// TODO: Cleanup if CQP does not behave
+	count = 0;
+	do {
+		if (count++ > 1000)	break;
+		udelay(10);
+	} while ( !(nes_read_indexed(nesdev->index_reg, 
+
NES_IDX_QP_CONTROL+
+
(PCI_FUNC(nesdev->pcidev->devfn)*8))&(1<<8)) );
+
+	dprintk("QP Status        = 0x%08X bytes\n", 
+			nes_read_indexed(nesdev->index_reg, 
+
NES_IDX_QP_CONTROL+(PCI_FUNC(nesdev->pcidev->devfn)*8)));
+
+	// Ring doorbell (4 WQEs)
+	nes_write32(nesdev->regs+NES_WQE_ALLOC, 0x04800000 |
nesdev->cqp.qp_id );
+
+	/* wait for the CCQ, CEQ, and AEQ to get created */
+	count = 0;
+	do {
+		if (count++ > 1000)	break;
+		udelay(10);
+	} while ( ((nes_read_indexed(nesdev->index_reg, 
+
NES_IDX_QP_CONTROL+
+
(PCI_FUNC(nesdev->pcidev->devfn)*8)) & (15<<8)) != (15<<8)) );
+
+	/* dump the QP status value */
+	dprintk("QP Status        = 0x%08X bytes\n", 
+			nes_read_indexed(nesdev->index_reg, 
+
NES_IDX_QP_CONTROL+(PCI_FUNC(nesdev->pcidev->devfn)*8)));
+
+	pci_free_consistent(nesdev->pcidev, 1024, lmi_buf,
lmi_dma_handle);
+	/* bump head since create CCQ does not generate a completion */
+	nesdev->cqp.sq_tail++;
+	nesdev->cqp.sq_tail++;
+
+	return 0;
+}
+
+
+/**
+ * nes_phy_init
+ */
+int nes_phy_init(struct nes_dev *nesdev)
+{
+	struct nes_adapter *nesadapter = nesdev->nesadapter;
+	u32 u32temp;
+	u32 counter;
+	u32 mac_index = nesdev->mac_index;
+	u16 phy_data;
+	u16 link_up = 0;
+
+
+	dprintk("10G PHY\n");
+
+	nes_write_indexed(nesdev->index_reg, 0x2004, 0x00000019);
+	udelay(30);				/* do we really need
this? */
+
+	nes_read_10G_phy_reg(nesdev->index_reg, 0,
nesadapter->phy_index[mac_index]);
+	phy_data = (u16)nes_read_indexed(nesdev->index_reg,
NES_IDX_MAC_MDIO_CONTROL );
+	dprintk("Phy data from register 0 = 0x%X.\n", phy_data);
+
+	nes_read_10G_phy_reg(nesdev->index_reg, 1,
nesadapter->phy_index[mac_index]);
+	phy_data = (u16)nes_read_indexed(nesdev->index_reg,
NES_IDX_MAC_MDIO_CONTROL );
+	dprintk("Phy data from register 1 = 0x%X.\n", phy_data);
+
+	// reset the phy
+	nes_write_10G_phy_reg(nesdev->index_reg, 0,
nesadapter->phy_index[mac_index], 0x8000);
+	for (counter = 0; counter < 100; counter++)
+	{
+		mdelay(1);
+		nes_read_10G_phy_reg(nesdev->index_reg, 0,
nesadapter->phy_index[mac_index]);
+		phy_data = (u16)nes_read_indexed(nesdev->index_reg,
NES_IDX_MAC_MDIO_CONTROL );
+		dprintk("Phy data from register 0 after reset =
0x%X.\n", phy_data);
+
+		if (!(phy_data & 0x8000))
+		{
+			break;
+		}
+	}
+
+	// device identifier 1
+	nes_read_10G_phy_reg(nesdev->index_reg, 2,
nesadapter->phy_index[mac_index]);
+	phy_data = (u16)nes_read_indexed(nesdev->index_reg,
NES_IDX_MAC_MDIO_CONTROL );
+	dprintk("Phy data from register 2 = 0x%X.\n", phy_data);
+
+	// device identifier 2
+	nes_read_10G_phy_reg(nesdev->index_reg, 3,
nesadapter->phy_index[mac_index]);
+	phy_data = (u16)nes_read_indexed(nesdev->index_reg,
NES_IDX_MAC_MDIO_CONTROL );
+	dprintk("Phy data from register 3 = 0x%X.\n", phy_data);
+
+	// primary channel lanes (0-3) analog transmit configuration
+	nes_write_10G_phy_reg(nesdev->index_reg, 0xd021,
nesadapter->phy_index[mac_index], 0x160a);
+	nes_write_10G_phy_reg(nesdev->index_reg, 0xd029,
nesadapter->phy_index[mac_index], 0x160a);
+	nes_write_10G_phy_reg(nesdev->index_reg, 0xd031,
nesadapter->phy_index[mac_index], 0x160a);
+	nes_write_10G_phy_reg(nesdev->index_reg, 0xd039,
nesadapter->phy_index[mac_index], 0x160a);
+
+	nes_write_10G_phy_reg(nesdev->index_reg, 0xd041,
nesadapter->phy_index[mac_index], 0x160a);
+	nes_write_10G_phy_reg(nesdev->index_reg, 0xd049,
nesadapter->phy_index[mac_index], 0x160a);
+	nes_write_10G_phy_reg(nesdev->index_reg, 0xd051,
nesadapter->phy_index[mac_index], 0x160a);
+	nes_write_10G_phy_reg(nesdev->index_reg, 0xd059,
nesadapter->phy_index[mac_index], 0x160a);
+
+	// primary channel lanes (0-3) analog receive configuration
+	nes_write_10G_phy_reg(nesdev->index_reg, 0xd025,
nesadapter->phy_index[mac_index], 0x8201);
+	nes_write_10G_phy_reg(nesdev->index_reg, 0xd02d,
nesadapter->phy_index[mac_index], 0x8201);
+	nes_write_10G_phy_reg(nesdev->index_reg, 0xd035,
nesadapter->phy_index[mac_index], 0x8201);
+	nes_write_10G_phy_reg(nesdev->index_reg, 0xd03d,
nesadapter->phy_index[mac_index], 0x8201);
+
+	nes_write_10G_phy_reg(nesdev->index_reg, 0xd045,
nesadapter->phy_index[mac_index], 0x8201);
+	nes_write_10G_phy_reg(nesdev->index_reg, 0xd04d,
nesadapter->phy_index[mac_index], 0x8201);
+	nes_write_10G_phy_reg(nesdev->index_reg, 0xd055,
nesadapter->phy_index[mac_index], 0x8201);
+	nes_write_10G_phy_reg(nesdev->index_reg, 0xd05d,
nesadapter->phy_index[mac_index], 0x8201);
+
+	nes_write_10G_phy_reg(nesdev->index_reg, 0xd023,
nesadapter->phy_index[mac_index], 0x0500);
+	nes_write_10G_phy_reg(nesdev->index_reg, 0xd02b,
nesadapter->phy_index[mac_index], 0x0500);
+	nes_write_10G_phy_reg(nesdev->index_reg, 0xd033,
nesadapter->phy_index[mac_index], 0x0500);
+	nes_write_10G_phy_reg(nesdev->index_reg, 0xd03b,
nesadapter->phy_index[mac_index], 0x0500);
+	nes_write_10G_phy_reg(nesdev->index_reg, 0xd043,
nesadapter->phy_index[mac_index], 0x0500);
+	nes_write_10G_phy_reg(nesdev->index_reg, 0xd04b,
nesadapter->phy_index[mac_index], 0x0500);
+	nes_write_10G_phy_reg(nesdev->index_reg, 0xd053,
nesadapter->phy_index[mac_index], 0x0500);
+	nes_write_10G_phy_reg(nesdev->index_reg, 0xd05b,
nesadapter->phy_index[mac_index], 0x0500);
+
+	nes_write_10G_phy_reg(nesdev->index_reg, 0xd000,
nesadapter->phy_index[mac_index], 0x0800);
+
+	// master register port status
+	nes_write_10G_phy_reg(nesdev->index_reg, 0xd00c,
nesadapter->phy_index[mac_index], 0x8070);
+
+	// try to let the link come up
+	nes_read_10G_phy_reg(nesdev->index_reg, 0x18,
nesadapter->phy_index[mac_index]);
+	phy_data = (u16)nes_read_indexed(nesdev->index_reg,
NES_IDX_MAC_MDIO_CONTROL);
+	dprintk("10G phy data from register 0x18 = 0x%X\n", phy_data);
+	// clear any faults
+	nes_read_10G_phy_reg(nesdev->index_reg, 8,
nesadapter->phy_index[mac_index]);
+	phy_data = (u16)nes_read_indexed(nesdev->index_reg,
NES_IDX_MAC_MDIO_CONTROL);
+	dprintk("10G phy data from register 8 = 0x%X\n", phy_data);
+
+	counter = 0;
+	do {
+		msleep(1);
+		nes_read_10G_phy_reg(nesdev->index_reg, 1,
nesadapter->phy_index[mac_index]);
+		phy_data = (u16)nes_read_indexed(nesdev->index_reg,
NES_IDX_MAC_MDIO_CONTROL );
+	} while ( (!(phy_data & 0x0004)) && (counter++<100) );
+
+	dprintk("10G phy data from register 1 = 0x%X, counter=%d\n",
phy_data, counter);
+
+	return 0;
+}
+
+
+/**
+ * nes_nic_qp_init
+ */
+int nes_nic_qp_init(struct nes_dev *nesdev, struct net_device *netdev)
+{
+	struct nes_hw_cqp_wqe *cqp_wqe;
+	struct nes_hw_nic_sq_wqe *nic_sqe;
+	struct nes_hw_nic_qp_context *nic_context;
+	struct sk_buff *skb;
+	struct nes_hw_nic_rq_wqe *nic_rqe;
+	u8 *virt_address;
+	unsigned long flags;
+	dma_addr_t bus_address;
+	u64 u64temp;
+	int ret;
+	u32 cqp_head;
+	u32 counter;
+	u32 wqe_count;
+
+	/* Allocate SQ, RQ, CQ, Reuse CEQ based on the PCI function */
+	nesdev->nic_mem_size = (NES_NIC_WQ_SIZE * sizeof(struct
nes_hw_nic_sq_wqe)) +
+						   (NES_NIC_WQ_SIZE *
sizeof(struct nes_hw_nic_rq_wqe)) +
+						   (NES_NIC_WQ_SIZE * 2
* sizeof(struct nes_hw_nic_cqe)) +
+						   (NES_NIC_WQ_SIZE *
sizeof(struct nes_first_frag)) +
+						   sizeof(struct
nes_hw_nic_qp_context);
+	dprintk("NIC PCI memory size = %u.\n", nesdev->nic_mem_size);
+
+	/* TODO: check for NULL */
+	virt_address = pci_alloc_consistent(nesdev->pcidev,
nesdev->nic_mem_size, &bus_address);
+
+	/* Setup the first Fragment buffers */
+	nesdev->hnic.first_frag_vbase = (void *)virt_address;
+	virt_address += NES_NIC_WQ_SIZE * sizeof(struct nes_first_frag);
+
+	for (counter=0; counter<NES_NIC_WQ_SIZE; counter++ ) {
+		nesdev->hnic.frag_paddr[counter] = bus_address;
+		bus_address += sizeof(struct nes_first_frag);
+	}
+
+	/* setup the SQ */
+	nesdev->hnic.sq_vbase = (void *)virt_address;
+	nesdev->hnic.sq_pbase = bus_address;
+	virt_address += NES_NIC_WQ_SIZE * sizeof(struct
nes_hw_nic_sq_wqe);
+	bus_address += NES_NIC_WQ_SIZE * sizeof(struct
nes_hw_nic_sq_wqe);
+	nesdev->hnic.sq_head = 0;
+	nesdev->hnic.sq_tail = 0;
+	nesdev->hnic.sq_size = NES_NIC_WQ_SIZE;
+	nesdev->hnic.qp_id = 16+(PCI_FUNC(nesdev->pcidev->devfn)*2);
+	for (counter=0; counter<(NES_NIC_WQ_SIZE); counter++) {
+		nic_sqe = &nesdev->hnic.sq_vbase[counter];
+		nic_sqe->wqe_words[NES_NIC_SQ_WQE_MISC_IDX] =
NES_NIC_SQ_WQE_DISABLE_CHKSUM | NES_NIC_SQ_WQE_COMPLETION;
+		nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_0_TAG_IDX] =
(u32)NES_FIRST_FRAG_SIZE<<16;
+		nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_LOW_IDX] =
(u32)nesdev->hnic.frag_paddr[counter];
+		nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG0_HIGH_IDX] =
(u32)((u64)nesdev->hnic.frag_paddr[counter]>>32);
+	}
+	/* TODO: if first frag is usually un-aligned, setup the first
frag SGEs here */
+	spin_lock_init(&nesdev->hnic.sq_lock);
+
+	/* setup the RQ */
+	nesdev->hnic.rq_vbase = (void
*)(&nesdev->hnic.sq_vbase[NES_NIC_WQ_SIZE]);
+	nesdev->hnic.rq_head = 0;
+	nesdev->hnic.rq_tail = 0;
+	nesdev->hnic.rq_size = NES_NIC_WQ_SIZE;
+	nesdev->hnic.rq_pbase = nesdev->hnic.sq_pbase + (NES_NIC_WQ_SIZE
* sizeof(struct nes_hw_nic_sq_wqe));
+
+	/* setup the CQ */
+	nesdev->hnic_cq.cq_vbase = (void
*)(&nesdev->hnic.rq_vbase[NES_NIC_WQ_SIZE]);
+	nesdev->hnic_cq.cq_head = 0;
+	nesdev->hnic_cq.cq_size = NES_NIC_WQ_SIZE*2;
+	nesdev->hnic_cq.cq_number = nesdev->hnic.qp_id;
+	nesdev->hnic_cq.ce_handler = nes_hnic_ce_handler;
+	nesdev->hnic_cq.cq_pbase = nesdev->hnic.rq_pbase +
(NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_rq_wqe));
+
+	/* Send CreateCQ request to CQP */
+	spin_lock_irqsave(&nesdev->cqp.lock, flags);
+	cqp_head = nesdev->cqp.sq_head;
+	cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+
+	cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = NES_CQP_CREATE_CQ |
NES_CQP_CQ_CEQ_VALID | 
+
(nesdev->hnic_cq.cq_size << 16);
+	cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] =
nesdev->hnic_cq.cq_number | ((u32)PCI_FUNC(nesdev->pcidev->devfn)<<16);
+	cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] = 0;
+	*((struct nes_hw_cqp
**)&cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_LOW_IDX]) = &nesdev->cqp;
+	cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] = cqp_head;
+	cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] = 0;
+	u64temp = (u64)nesdev->hnic_cq.cq_pbase;
+	cqp_wqe->wqe_words[NES_CQP_CQ_WQE_PBL_LOW_IDX] =
cpu_to_le32((u32)u64temp);
+	cqp_wqe->wqe_words[NES_CQP_CQ_WQE_PBL_HIGH_IDX] =
cpu_to_le32((u32)(u64temp>>32));
+	cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX] =  0;
+	/* the following two lines likely have endian issues */
+	*((struct nes_hw_nic_cq
**)&cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_LOW_IDX]) =
&nesdev->hnic_cq;
+	*((u64 *)&cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_LOW_IDX])
>>= 1;
+	dprintk("%s: CQ%u context = 0x%08X:0x%08X.\n", __FUNCTION__,
nesdev->hnic_cq.cq_number, 
+		cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_HIGH_IDX], 
+		cqp_wqe->wqe_words[NES_CQP_CQ_WQE_CQ_CONTEXT_LOW_IDX]);
+	cqp_wqe->wqe_words[NES_CQP_CQ_WQE_DOORBELL_INDEX_HIGH_IDX] =  0;
+	cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] =
cpu_to_le32(cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX]);
+	if (++cqp_head >= nesdev->cqp.sq_size) cqp_head = 0;
+	cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head];
+
+	/* Send CreateQP request to CQP */
+	nic_context = (void
*)(&nesdev->hnic_cq.cq_vbase[nesdev->hnic_cq.cq_size]);
+	nic_context->context_words[NES_NIC_CTX_MISC_IDX] =
cpu_to_le32((u32)NES_NIC_CTX_SIZE |
((u32)PCI_FUNC(nesdev->pcidev->devfn)<<12));
+	dprintk("NES_NIC_CTX_SIZE = %0x, word0 = %u.\n",
NES_NIC_CTX_SIZE, nic_context->context_words[NES_NIC_CTX_MISC_IDX]);
+
+	u64temp = (u64)nesdev->hnic.sq_pbase;
+	nic_context->context_words[NES_NIC_CTX_SQ_LOW_IDX] =
cpu_to_le32((u32)u64temp);
+	nic_context->context_words[NES_NIC_CTX_SQ_HIGH_IDX] =
cpu_to_le32((u32)(u64temp>>32));
+	u64temp = (u64)nesdev->hnic.rq_pbase;
+	nic_context->context_words[NES_NIC_CTX_RQ_LOW_IDX] =
cpu_to_le32((u32)u64temp);
+	nic_context->context_words[NES_NIC_CTX_RQ_HIGH_IDX] =
cpu_to_le32((u32)(u64temp>>32));
+
+	cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] =
cpu_to_le32(NES_CQP_CREATE_QP | NES_CQP_QP_TYPE_NIC);
+	cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] =
cpu_to_le32(nesdev->hnic.qp_id);
+	cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] =  0;
+	*((struct nes_hw_cqp
**)&cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_LOW_IDX]) =  &nesdev->cqp;
+	cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] =
cqp_head;
+	cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] =  0;
+	u64temp = (u64)nesdev->hnic_cq.cq_pbase +
(nesdev->hnic_cq.cq_size * sizeof(struct nes_hw_nic_cqe));
+	cqp_wqe->wqe_words[NES_CQP_QP_WQE_CONTEXT_LOW_IDX] =
cpu_to_le32((u32)u64temp);
+	cqp_wqe->wqe_words[NES_CQP_QP_WQE_CONTEXT_HIGH_IDX] =
cpu_to_le32((u32)(u64temp>>32));
+	if (++cqp_head >= nesdev->cqp.sq_size) cqp_head = 0;
+
+	nesdev->cqp.sq_head = cqp_head;
+	barrier();
+
+	// Ring doorbell (2 WQEs)
+	nes_write32(nesdev->regs+NES_WQE_ALLOC, 0x02800000 |
nesdev->cqp.qp_id );
+
+	spin_unlock_irqrestore(&nesdev->cqp.lock, flags);
+	dprintk("Waiting for create NIC QP to complete.\n");
+	cqp_head = (cqp_head+1)&(nesdev->cqp.sq_size-1);
+	ret =
wait_event_timeout(nesdev->cqp.waitq,(nesdev->cqp.sq_tail==cqp_head),
2);
+	dprintk("Create NIC QP completed, wait_event_timeout ret =
%u.\n", ret);
+
+	/* Populate the RQ */
+	for (counter=0; counter<(NES_NIC_WQ_SIZE-1); counter++) {
+		skb = dev_alloc_skb(max_frame_len);
+		if (!skb) {
+			dprintk(KERN_ERR PFX "%s: out of memory for
receive\n", netdev->name);
+			// TODO: Unwind the NIC
+			return -ENOMEM;
+		}
+
+		skb->dev = netdev;
+
+		bus_address = pci_map_single(nesdev->pcidev, skb->data,
max_frame_len, PCI_DMA_FROMDEVICE);
+
+		nic_rqe = &nesdev->hnic.rq_vbase[counter];
+		nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_1_0_IDX] =
cpu_to_le32(max_frame_len);
+		nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_3_2_IDX] = 0;
+		nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX] =
cpu_to_le32((u32)bus_address);
+		nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX] =
cpu_to_le32((u32)((u64)bus_address>>32));
+		nesdev->hnic.rx_skb[counter] = skb; 
+	}
+
+	wqe_count = NES_NIC_WQ_SIZE-1;
+	nesdev->hnic.rq_head = wqe_count-1;
+	barrier();
+	do {
+		counter = min(wqe_count, ((u32)255));
+		wqe_count -= counter;
+		nes_write32(nesdev->regs+NES_WQE_ALLOC, (counter<<24) |
nesdev->hnic.qp_id );
+	} while (wqe_count);
+
+	return 0;
+}
+
+
+#define MAX_DPC_ITERATIONS 128
+/**
+ * nes_dpc
+ *
+ * @param param
+ */
+void nes_dpc(unsigned long param)
+{
+	struct nes_dev *nesdev = (struct nes_dev *) param;
+	struct nes_adapter *nesadapter = nesdev->nesadapter;
+	u32 counter;
+	u32 loop_counter = 0;
+	u32 int_status_bit;
+	u32 int_stat;
+	u32 temp_int_stat;
+
+//	dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+
+	do {
+		int_stat = nes_read32(nesdev->regs + NES_INT_STAT);
+		/* Mask off bits for interrupts we are not processing */
+		int_stat &= nesdev->int_req;
+		// dprintk("Interrupt Status (postfilter)  = 0x%08X\n",
int_stat );
+
+		if (int_stat) {
+			/* Ack the interrupts */
+			nes_write32(nesdev->regs+NES_INT_STAT, 
+
(int_stat&~(NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0|NES_INT_MAC1|NES_INT
_MAC2|NES_INT_MAC3)));
+
+			temp_int_stat = int_stat;
+			/* Process the CEQs */
+			for (counter=0, int_status_bit=1; counter<16 ;
counter++) {
+				if (int_stat & int_status_bit) {
+					nes_process_ceq(nesdev,
&nesadapter->ceq[counter]);
+					temp_int_stat &=
~int_status_bit;
+				}
+				if (!(temp_int_stat & 0x0000ffff))
+					break;
+				int_status_bit <<= 1;
+			}
+
+			/* Process the AEQ for this pci function */
+			int_status_bit =
1<<(16+PCI_FUNC(nesdev->pcidev->devfn));
+			if (int_stat & int_status_bit) {
+				nes_process_aeq(nesdev,
&nesadapter->aeq[PCI_FUNC(nesdev->pcidev->devfn)]);
+			}
+
+			/* Process the MAC interrupt for this pci
function */
+			int_status_bit = 1<<(24+nesdev->mac_index);
+			if (int_stat & int_status_bit) {
+				nes_process_mac_intr(nesdev,
nesdev->mac_index);
+			}
+
+			if (int_stat & NES_INT_TIMER) {
+
+			}
+
+
+			if (int_stat & NES_INT_TSW) {
+			}
+		}
+		/* Don't use the interface interrupt bit stay in loop */
+		int_stat &=
~NES_INT_INTF|NES_INT_TIMER|NES_INT_MAC0|NES_INT_MAC1|NES_INT_MAC2|NES_I
NT_MAC3;
+	} while ((int_stat != 0) && (loop_counter++ <
MAX_DPC_ITERATIONS));
+
+	// Enable interrupts
+	nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req);
+}
+
+
+/**
+ * nes_process_ceq
+ * 
+ * @param nesdev
+ * @param ceq
+ */
+void nes_process_ceq(struct nes_dev *nesdev, struct nes_hw_ceq *ceq)
+{
+	u64 u64temp;
+	struct nes_hw_cq *cq;
+	u32 head;
+	u32 ceq_size;
+
+//	dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+	head = ceq->ceq_head;
+	ceq_size = ceq->ceq_size;
+
+	do {
+		if
(le32_to_cpu(ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX])
& NES_CEQE_VALID) {
+			u64temp = *((u64
*)&ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_LOW_IDX]);
+			u64temp <<= 1;
+			cq = *((struct nes_hw_cq **)&u64temp);
+			barrier();
+			/* make the CEQE not valid */
+
ceq->ceq_vbase[head].ceqe_words[NES_CEQE_CQ_CTX_HIGH_IDX] = 0;
+
+			/* call the event handler */
+			cq->ce_handler(nesdev, cq);
+
+			if (++head >= ceq_size)
+				head = 0;
+		} else {
+			break;
+		}
+	} while ( 1 );
+	ceq->ceq_head = head;
+}
+
+
+/**
+ * nes_process_aeq
+ * 
+ * @param nesdev
+ * @param aeq
+ */
+void nes_process_aeq(struct nes_dev *nesdev, struct nes_hw_aeq *aeq)
+{
+	u64 u64temp;
+	u32 head;
+	u32 aeq_size;
+	struct nes_hw_aeqe volatile *aeqe;
+
+	dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+
+	head = aeq->aeq_head;
+	aeq_size = aeq->aeq_size;
+
+	do {
+		aeqe = &aeq->aeq_vbase[head];
+		if ((le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]) &
NES_AEQE_VALID) == 0)
+			break;
+		aeqe->aeqe_words[NES_AEQE_MISC_IDX] =
le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]);
+		aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX] =
le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]);
+		if (aeqe->aeqe_words[NES_AEQE_MISC_IDX] &
(NES_AEQE_QP|NES_AEQE_CQ)) {
+			if (aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]
>= NES_FIRST_QPN) {
+				/* dealing with an accelerated QP
related AE */
+				u64temp = *((u64
*)&aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX]);
+				nes_process_iwarp_aeqe(nesdev, (struct
nes_hw_aeqe *)aeqe);
+			} else {
+			}
+		} else if (aeqe->aeqe_words[NES_AEQE_MISC_IDX] &
NES_AEQE_CQ) {
+			/* dealing with a CQ related AE */
+			dprintk("%s: Processing CQ realated AE, misc =
0x%04X\n", __FUNCTION__, 
+
(u16)(aeqe->aeqe_words[NES_AEQE_MISC_IDX]>>16));
+		}
+
+		aeqe->aeqe_words[NES_AEQE_MISC_IDX] = 0;
+
+		head++; 
+		if (head >= aeq_size)
+			head = 0;
+	}
+	while ( 1 );
+	aeq->aeq_head = head;
+}
+
+
+/**
+ * nes_process_mac_intr
+ * 
+ * @param nesdev
+ * @param mac_number
+ */
+void nes_process_mac_intr(struct nes_dev *nesdev, u32 mac_number)
+{
+	struct nes_adapter *nesadapter = nesdev->nesadapter;
+	struct nes_port *nes_port = netdev_priv(nesdev->netdev);
+	u32 mac_status;
+	u32 mac_index = nesdev->mac_index;
+	u16 phy_data;
+
+	// ack the MAC interrupt
+	mac_status = nes_read_indexed(nesdev->index_reg,
NES_IDX_MAC_INT_STATUS );
+	/* Clear the interrupt */
+	nes_write_indexed(nesdev->index_reg, NES_IDX_MAC_INT_STATUS,
mac_status );
+
+	dprintk("MAC interrupt status = 0x%X.\n", mac_status);
+
+	if (mac_status & (NES_MAC_INT_LINK_STAT_CHG |
NES_MAC_INT_XGMII_EXT)) {
+		/* read the PHY interrupt status register */
+		// read status
+		nes_read_10G_phy_reg(nesdev->index_reg, 1,
nesadapter->phy_index[mac_index]);
+		phy_data = (u16)nes_read_indexed(nesdev->index_reg, 
+
NES_IDX_MAC_MDIO_CONTROL );
+		dprintk("10G phy data from register 1 = 0x%X\n",
phy_data);
+
+		if (!(phy_data & 0x0004))
+		{
+			dprintk("link reports down, check faults\n");
+
+//			nes_read_10G_phy_reg(nesdev->index_reg, 0x18,
nesadapter->phy_index[mac_index]);
+//			phy_data =
(u16)nes_read_indexed(nesdev->index_reg, NES_IDX_MAC_MDIO_CONTROL);
+//			dprintk("10G phy data from register 0x18 =
0x%X\n", phy_data);
+			// clear any faults
+			nes_read_10G_phy_reg(nesdev->index_reg, 8,
nesadapter->phy_index[mac_index]);
+			phy_data =
(u16)nes_read_indexed(nesdev->index_reg, NES_IDX_MAC_MDIO_CONTROL);
+			dprintk("10G phy data from register 8 = 0x%X\n",
phy_data);
+
+			// read status, again
+			nes_read_10G_phy_reg(nesdev->index_reg, 1,
nesadapter->phy_index[mac_index]);
+			phy_data =
(u16)nes_read_indexed(nesdev->index_reg, 
+
NES_IDX_MAC_MDIO_CONTROL );
+			dprintk("10G phy data from register 1 = 0x%X\n",
phy_data);
+		}
+
+		if (phy_data & 0x0004)
+		{
+			dprintk("The Link is UP!!.  linkup was %d\n",
nes_port->linkup);
+			if (nes_port->linkup == 0) {
+				printk(PFX "The Link is now up for port
%u.\n", nesdev->mac_index);
+				if (netif_queue_stopped(nesdev->netdev))
+
netif_start_queue(nesdev->netdev);
+				nes_port->linkup = 1;
+				netif_carrier_on(nesdev->netdev);
+			}
+		} else {
+			dprintk("The Link is Down!!. linkup was %d\n",
nes_port->linkup);
+			if (nes_port->linkup == 1) {
+				printk(PFX "The Link is now down for
port %u.\n", nesdev->mac_index);
+				if
(!(netif_queue_stopped(nesdev->netdev)))
+
netif_stop_queue(nesdev->netdev);
+				nes_port->linkup = 0;
+				netif_carrier_off(nesdev->netdev);
+			}
+		}
+	}
+	if (mac_status & NES_MAC_INT_TX_UNDERFLOW) {
+		dprintk("The MAC reported a TX underflow!!.\n");
+	}
+	if (mac_status & NES_MAC_INT_TX_ERROR) {
+		dprintk("The MAC reported a TX Error!!.\n");
+	}
+}
+
+
+/**
+ * nes_hnic_ce_handler
+ * 
+ * @param nesdev
+ * @param cq
+ */
+void nes_hnic_ce_handler(struct nes_dev *nesdev, struct nes_hw_nic_cq
*cq)
+{
+	struct nes_hw_nic *nesnic;
+	struct nes_port *nes_port = netdev_priv(nesdev->netdev);
+	struct nes_hw_nic_rq_wqe *nic_rqe;
+	struct nes_hw_nic_sq_wqe *nic_sqe;
+	struct sk_buff *skb;
+	struct sk_buff *rx_skb;
+	struct sk_buff *dup_rx_skb;
+	struct tcphdr *pTCPHeader;
+	struct iphdr *pIPHeader;
+	unsigned long flags;
+	u64 u64temp;
+	u8 u8temp;
+	dma_addr_t bus_address;
+	u32 head;
+	u32 cq_size;
+	u32 rx_pkt_size;
+	u32 cqe_count=0;
+
+//	dprintk("%s:%s:%u:\n", __FILE__, __FUNCTION__, __LINE__);
+
+	head = cq->cq_head;
+	cq_size = cq->cq_size;
+	do {
+		if
(le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX]) &
NES_NIC_CQE_VALID) {
+			nesnic = &nesdev->hnic;
+
cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX] =
le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX]);
+
+			if
(cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX]&NES_NIC_CQE_SQ) {
+//				dprintk("%s: Processing SQ completion
for QP%u. SQ Tail = %u.\n", __FUNCTION__, 
+//						nesdev->hnic.qp_id,
nesnic->sq_tail);
+				nic_sqe =
&nesnic->sq_vbase[nesnic->sq_tail];
+				skb = nesnic->tx_skb[nesnic->sq_tail];
+//            	dprintk("SQ skb = %p.\n", skb);
+				if
(nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_2_1_IDX] != 0) {
+					u64temp =
le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG1_LOW_IDX]);
+					u64temp +=
((u64)le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG1_HIGH_IDX]))<<3
2;
+					bus_address =
(dma_addr_t)u64temp;
+					pci_unmap_single(nesdev->pcidev,
bus_address,
+
le32_to_cpu(nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_2_1_IDX]),
PCI_DMA_TODEVICE);
+					dev_kfree_skb_any(skb);
+				}
+				spin_lock_irqsave(&nesnic->sq_lock,
flags);
+				nesnic->sq_tail++;
+				nesnic->sq_tail &= nesnic->sq_size-1;
+				/* restart the queue if it had been
stopped */
+				if (netif_queue_stopped(nesdev->netdev))
+
netif_wake_queue(nesdev->netdev);
+				spin_unlock_irqrestore(&nesnic->sq_lock,
flags);
+			} else {
+				rx_pkt_size =
cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX]&0x0000ffff;
+//				dprintk("%s: Processing RQ completion
for QP%u. RQ Tail = %u, size = %u.\n", 
+//							__FUNCTION__,
nesdev->hnic.qp_id, nesnic->rq_tail, rx_pkt_size);
+				nic_rqe =
&nesnic->rq_vbase[nesnic->rq_tail];
+				/* Get the skb */
+				rx_skb =
nesnic->rx_skb[nesnic->rq_tail];
+//            	dprintk("Dequeued RQ skb = %p.\n", rx_skb);
+				/* unmap the buffer */
+				nic_rqe =
&nesnic->rq_vbase[nesdev->hnic.rq_tail];
+				bus_address =
le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX]);
+				bus_address +=
((u64)le32_to_cpu(nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX]))<<3
2;
+//   	      	dprintk("skb %p getting removed from the RQ at index %u
(bus address = %X).\n", 
+//         	   				rx_skb, nesnic->rq_tail,
(u32)bus_address);
+				pci_unmap_single(nesdev->pcidev,
bus_address,
+
max_frame_len, PCI_DMA_FROMDEVICE);
+				/* setup the old skb */
+				rx_skb->tail = rx_skb->data +
rx_pkt_size;
+				rx_skb->len = rx_pkt_size;
+				rx_skb->protocol =
eth_type_trans(rx_skb, nesdev->netdev);
+				nesnic->rq_tail++;
+				nesnic->rq_tail &= nesnic->rq_size - 1;
+				/* get a new skb */
+				skb = dev_alloc_skb(max_frame_len);
+				if (skb) {
+//   	         	dprintk("skb %p added to the RQ at index %u.\n",
skb, nesnic->rq_head);
+					skb->dev = nesdev->netdev;
+
+					/* map put down to the chip */
+					bus_address =
pci_map_single(nesdev->pcidev, 
+
skb->data, max_frame_len, PCI_DMA_FROMDEVICE);
+//   	         	dprintk("skb %p added to the RQ at index %u (bus
address = %X).\n", skb, nesnic->rq_head, bus_address);
+
+					nic_rqe =
&nesnic->rq_vbase[nesdev->hnic.rq_head];
+
nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_1_0_IDX] =
cpu_to_le32(max_frame_len);
+
nic_rqe->wqe_words[NES_NIC_RQ_WQE_LENGTH_3_2_IDX] = 0;
+
nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX] =
cpu_to_le32((u32)bus_address);
+
nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX] =
cpu_to_le32((u32)((u64)bus_address>>32));
+					nesnic->rx_skb[nesnic->rq_head]
= skb; 
+					nesnic->rq_head++;
+					nesnic->rq_head &=
nesnic->rq_size - 1;
+
nes_write32(nesdev->regs+NES_WQE_ALLOC, (1<<24) | nesnic->qp_id );
+				} else {
+					// TODO: Set a timer and/or add
code to rx to allocate more buffers
+				}
+
+				/* indicate the old skb up to the stack
*/
+				/* Need to dup arps, and filter packets
based on ports */
+
+				// if the packet is TCP/IPv4, look it up
+				if
((le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_NIC_CQE_TAG_PKT_TYPE_IDX]
) & 0xF3E)== 0x112) {
+					/* TODO: Assuming DIX for now,
allow for SNAP and VLAN */
+					pIPHeader = (struct iphdr
*)rx_skb->data;
+					pTCPHeader = (struct tcphdr
*)(rx_skb->data+(4*pIPHeader->ihl));
+					u8temp = 1 <<
(ntohs(pTCPHeader->dest)&7);
+					if ((nesdev->local_ipaddr ==
pIPHeader->daddr) && 
+
(nesdev->apbv_table[ntohs(pTCPHeader->dest)>>3] & u8temp)) {
+
stack_ops_p->nesif_rx(rx_skb);
+					} else {
+						netif_rx(rx_skb);
+					}
+				} else {
+					if (ntohs(rx_skb->protocol) ==
ETH_P_ARP) {
+						if
(nesdev->nes_stack_start) {
+							dup_rx_skb =
skb_clone(rx_skb, GFP_ATOMIC);
+							if (dup_rx_skb)
{
+
stack_ops_p->nesif_rx(dup_rx_skb);
+							}
+						}
+					}
+					netif_rx(rx_skb);
+				}
+
+				nesdev->netdev->last_rx = jiffies;
+				nes_port->netstats.rx_packets++;
+				nes_port->netstats.rx_bytes +=
(cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX]&0x0000ffff);
+			}
+
cq->cq_vbase[head].cqe_words[NES_NIC_CQE_MISC_IDX] = 0;
+			// Accounting...
+			cqe_count++;
+			if (++head >= cq_size) head = 0;
+			if (cqe_count == 255) {
+				// Arm the CCQ
+				nes_write32(nesdev->regs+NES_CQE_ALLOC,

+							cq->cq_number |
(cqe_count << 16) );
+				cqe_count = 0;
+			}
+		} else {
+			break;
+		}
+	} while ( 1 );
+	cq->cq_head = head;
+//   dprintk("CQ%u Processed = %u cqes, new head = %u.\n",
cq->cq_number, cqe_count, cq->cq_head);
+	// Arm the CCQ
+	nes_write32(nesdev->regs+NES_CQE_ALLOC,
NES_CQE_ALLOC_NOTIFY_NEXT | 
+				cq->cq_number | (cqe_count << 16) );
+}
+
+
+/**
+ * cqp_ce_handler
+ * 
+ * @param nesdev
+ * @param cq
+ */
+void cqp_ce_handler(struct nes_dev *nesdev, struct nes_hw_cq *cq)
+{
+	struct nes_hw_cqp *cqp;
+	u32 head;
+	u32 cq_size;
+	u32 cqe_count=0;
+
+	dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+	head = cq->cq_head;
+	cq_size = cq->cq_size;
+
+	do {
+		/* process the CQE */
+		if
(le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX]) &
NES_CQE_VALID) {
+			cqp = *((struct nes_hw_cqp
**)&cq->cq_vbase[head].cqe_words[NES_CQE_COMP_COMP_CTX_LOW_IDX]);
+
+			if
(cq->cq_vbase[head].cqe_words[NES_CQE_ERROR_CODE_IDX]) {
+
cq->cq_vbase[head].cqe_words[NES_CQE_ERROR_CODE_IDX] = 
+
le32_to_cpu(cq->cq_vbase[head].cqe_words[NES_CQE_ERROR_CODE_IDX]);
+				dprintk("Bad Completion code from CQP,
Major/Minor codes = 0x%04X:%04X.\n", 
+
(u16)(cq->cq_vbase[head].cqe_words[NES_CQE_ERROR_CODE_IDX]>>16),
+
(u16)cq->cq_vbase[head].cqe_words[NES_CQE_ERROR_CODE_IDX]);
+			}
+
+			if (++cqp->sq_tail >= cqp->sq_size)
+				cqp->sq_tail = 0;
+			wake_up(&nesdev->cqp.waitq);
+
+			cq->cq_vbase[head].cqe_words[NES_CQE_OPCODE_IDX]
= 0;
+			// Accounting...
+			cqe_count++;
+			if (++head >= cq_size)
+				head = 0;
+		} else {
+			break;
+		}
+	} while ( 1 );
+	cq->cq_head = head;
+
+	/* Arm the CCQ */
+	nes_write32(nesdev->regs+NES_CQE_ALLOC,
NES_CQE_ALLOC_NOTIFY_NEXT | 
+				cq->cq_number | (cqe_count << 16) );
+}
+
+
+/**
+ * nes_process_iwarp_aeqe
+ * 
+ * @param nesdev
+ * @param aeqe
+ */
+void nes_process_iwarp_aeqe(struct nes_dev *nesdev, struct nes_hw_aeqe
*aeqe)
+{
+	u64 context;
+    struct nes_qp *nesqp;
+    struct iw_cm_id *cm_id;
+	struct nes_adapter *nesadapter = nesdev->nesadapter;
+    struct ib_event ibevent;
+    struct iw_cm_event cmevent;
+	u32 aeq_info;
+    u16 async_event_id;
+
+    dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+	context = aeqe->aeqe_words[NES_AEQE_COMP_CTXT_LOW_IDX];
+	context +=
((u64)aeqe->aeqe_words[NES_AEQE_COMP_CTXT_HIGH_IDX])<<32;
+	aeq_info = le32_to_cpu(aeqe->aeqe_words[NES_AEQE_MISC_IDX]);
+	async_event_id = (u16)aeq_info;
+
+    switch (async_event_id){
+        case NES_AEQE_AEID_LLP_FIN_RECEIVED:
+            nesqp = *((struct nes_qp **)&context);
+            if (nesqp->cm_id){
+                cm_id = nesqp->cm_id;
+				if (cm_id->event_handler) {
+	                cmevent.event = IW_CM_EVENT_DISCONNECT;
+					cmevent.status =
IW_CM_EVENT_STATUS_OK;
+	                cmevent.local_addr = cm_id->local_addr;
+	                cmevent.remote_addr = cm_id->remote_addr;
+	                cmevent.private_data = NULL;
+	                cmevent.private_data_len = 0;
+	                dprintk("%s:Generating a Disconnect Event
(normal) for QP%u \n", 
+	                        __FUNCTION__, nesqp->hwqp.qp_id);
+	                cm_id->event_handler(nesqp->cm_id, &cmevent);
+					/* TODO: this does not seem
correct, Seems like app should do close */
+					INIT_WORK(&nesqp->ae_work,
nes_disconnect_worker, nesqp);
+					queue_work(nesqp->aewq,
&nesqp->ae_work);
+				}
+            }
+            break;
+		case NES_AEQE_AEID_LLP_CLOSE_COMPLETE:
+			nesqp = *((struct nes_qp **)&context);
+			nesqp->last_aeq =
NES_AEQE_AEID_LLP_CLOSE_COMPLETE;
+			dprintk("%s: Processing an
NES_AEQE_AEID_LLP_CLOSE_COMPLETE event on QP%u \n", 
+					__FUNCTION__,
nesqp->hwqp.qp_id);
+			INIT_WORK(&nesqp->ae_work,
nes_disconnect_worker, nesqp);
+			queue_work(nesqp->aewq, &nesqp->ae_work);
+			break;
+        case NES_AEQE_AEID_LLP_CONNECTION_RESET:
+            nesqp = *((struct nes_qp **)&context);
+            if (nesqp->cm_id){
+                cm_id = nesqp->cm_id;
+				if (cm_id->event_handler) {
+					cmevent.event =
IW_CM_EVENT_DISCONNECT;
+					cmevent.status =
IW_CM_EVENT_STATUS_OK;
+					cmevent.local_addr =
cm_id->local_addr;
+					cmevent.remote_addr =
cm_id->remote_addr;
+					cmevent.private_data = NULL;
+					cmevent.private_data_len = 0;
+					dprintk("%s:Generating a
Disconnect Event (reset) for QP%u \n", 
+							__FUNCTION__,
nesqp->hwqp.qp_id);
+					cm_id->event_handler(cm_id,
&cmevent);
+					/* TODO: this does not seem
correct, Seems like app should do close */
+					dprintk("nesqp->aewq = %p.\n",
nesqp->aewq );
+					INIT_WORK(&nesqp->ae_work,
nes_disconnect_worker, nesqp);
+					queue_work(nesqp->aewq,
&nesqp->ae_work);
+				}
+            }
+            break;
+		case NES_AEQE_AEID_AMP_BAD_STAG_INDEX:
+			if (NES_AEQE_INBOUND_RDMA&aeq_info) {
+				nesqp =
nesadapter->qp_table[le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID
_IDX])-NES_FIRST_QPN];
+			} else {
+				/* TODO: get the actual WQE and mask off
wqe index */
+				context &= ~((u64)511);
+				nesqp = *((struct nes_qp **)&context);
+			}
+			printk("%s: Processing an
NES_AEQE_AEID_AMP_BAD_STAG_INDEX event on QP%u \n", 
+					__FUNCTION__,
nesqp->hwqp.qp_id);
+			if (nesqp->ibqp.event_handler) {
+				ibevent.device = nesqp->ibqp.device;
+				ibevent.element.qp = &nesqp->ibqp;
+				ibevent.event = IB_EVENT_QP_ACCESS_ERR;
+				nesqp->ibqp.event_handler(&ibevent,
nesqp->ibqp.qp_context );
+			}
+			break;
+		case NES_AEQE_AEID_AMP_UNALLOCATED_STAG:
+			nesqp = *((struct nes_qp **)&context);
+			printk("%s: Processing an
NES_AEQE_AEID_AMP_UNALLOCATED_STAG event on QP%u \n", 
+					__FUNCTION__,
nesqp->hwqp.qp_id);
+			if (nesqp->ibqp.event_handler) {
+				ibevent.device = nesqp->ibqp.device;
+				ibevent.element.qp = &nesqp->ibqp;
+				ibevent.event = IB_EVENT_QP_ACCESS_ERR;
+				nesqp->ibqp.event_handler(&ibevent,
nesqp->ibqp.qp_context);
+			}
+			break;
+		case NES_AEQE_AEID_PRIV_OPERATION_DENIED:
+			nesqp =
nesadapter->qp_table[le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID
_IDX])-NES_FIRST_QPN];
+			printk("%s: Processing an
NES_AEQE_AEID_PRIV_OPERATION_DENIED event on QP%u, nesqp = %p, AE
reported %p \n", 
+					__FUNCTION__, nesqp->hwqp.qp_id,
nesqp, *((struct nes_qp **)&context));
+			if (nesqp->ibqp.event_handler) {
+				ibevent.device = nesqp->ibqp.device;
+				ibevent.element.qp = &nesqp->ibqp;
+				ibevent.event = IB_EVENT_QP_ACCESS_ERR;
+				nesqp->ibqp.event_handler(&ibevent,
nesqp->ibqp.qp_context);
+			}
+		case NES_AEQE_AEID_CQ_OPERATION_ERROR:
+			printk("%s: Processing an
NES_AEQE_AEID_CQ_OPERATION_ERROR event on CQ%u \n", 
+					__FUNCTION__,
le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID_IDX]));
+			/* TODO: Need to add code to lookup the CQ
context based on the CQID from the AE
+					and generate an event */
+			break;
+		case
NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER:
+			/* SA1 Errata: completion context not filled in
*/
+			nesqp =
nesadapter->qp_table[le32_to_cpu(aeqe->aeqe_words[NES_AEQE_COMP_QP_CQ_ID
_IDX])-NES_FIRST_QPN];
+			printk("%s: Processing an
NES_AEQE_AEID_DDP_UBE_DDP_MESSAGE_TOO_LONG_FOR_AVAILABLE_BUFFER event on
QP%u \n", 
+					__FUNCTION__,
nesqp->hwqp.qp_id);
+			if (nesqp->ibqp.event_handler) {
+				ibevent.device = nesqp->ibqp.device;
+				ibevent.element.qp = &nesqp->ibqp;
+				ibevent.event = IB_EVENT_QP_ACCESS_ERR;
+				nesqp->ibqp.event_handler(&ibevent,
nesqp->ibqp.qp_context );
+			}
+			/* TODO: this does not seem correct, Seems like
app should do close */
+			INIT_WORK(&nesqp->ae_work,
nes_disconnect_worker, nesqp);
+			queue_work(nesqp->aewq, &nesqp->ae_work);
+			break;
+		case
NES_AEQE_AEID_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE:
+			nesqp = *((struct nes_qp **)&context);
+			printk("%s: Processing an
NES_AEQE_AEID_DDP_UBE_INVALID_MSN_NO_BUFFER_AVAILABLE event on QP%u \n",

+					__FUNCTION__, nesqp->hwqp.qp_id
);
+			if (nesqp->ibqp.event_handler) {
+				ibevent.device = nesqp->ibqp.device;
+				ibevent.element.qp = &nesqp->ibqp;
+				ibevent.event = IB_EVENT_QP_FATAL;
+				nesqp->ibqp.event_handler(&ibevent,
nesqp->ibqp.qp_context );
+			}
+			/* TODO: this does not seem correct, Seems like
app should do close */
+			INIT_WORK(&nesqp->ae_work,
nes_disconnect_worker, nesqp);
+			queue_work(nesqp->aewq, &nesqp->ae_work);
+			break;
+		case NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR:
+			nesqp = *((struct nes_qp **)&context);
+			printk("%s: Processing an
NES_AEQE_AEID_LLP_RECEIVED_MPA_CRC_ERROR event on QP%u \n  Q2 Data: \n",

+					__FUNCTION__, nesqp->hwqp.qp_id
);
+			if (nesqp->ibqp.event_handler) {
+				ibevent.device = nesqp->ibqp.device;
+				ibevent.element.qp = &nesqp->ibqp;
+				ibevent.event = IB_EVENT_QP_FATAL;
+				nesqp->ibqp.event_handler(&ibevent,
nesqp->ibqp.qp_context );
+			}
+			/* TODO: this does not seem correct, Seems like
app should do close */
+			INIT_WORK(&nesqp->ae_work,
nes_disconnect_worker, nesqp);
+			queue_work(nesqp->aewq, &nesqp->ae_work);
+			break;
+		case NES_AEQE_AEID_LLP_TERMINATE_RECEIVED:
+            nesqp = *((struct nes_qp **)&context);
+			printk("%s: Processing an
NES_AEQE_AEID_LLP_TERMINATE_RECEIVED event on QP%u \n  Q2 Data: \n", 
+					__FUNCTION__, nesqp->hwqp.qp_id
);
+			if (nesqp->ibqp.event_handler) {
+				ibevent.device = nesqp->ibqp.device;
+				ibevent.element.qp = &nesqp->ibqp;
+				ibevent.event = IB_EVENT_QP_FATAL;
+				nesqp->ibqp.event_handler(&ibevent,
nesqp->ibqp.qp_context );
+			}
+			nesqp->ibqp_state = IB_QPS_SQE;
+			nesqp->iwarp_state =
NES_CQP_QP_IWARP_STATE_TERMINATE;
+			/* TODO: this does not seem correct, Seems like
app should do close */
+			INIT_WORK(&nesqp->ae_work,
nes_disconnect_worker, nesqp);
+			queue_work(nesqp->aewq, &nesqp->ae_work);
+			break;
+		case NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE:
+            nesqp = *((struct nes_qp **)&context);
+			printk("%s: Processing an
NES_AEQE_AEID_RDMAP_ROE_BAD_LLP_CLOSE event on QP%u \n", 
+					__FUNCTION__, nesqp->hwqp.qp_id
);
+			if (nesqp->ibqp.event_handler) {
+				ibevent.device = nesqp->ibqp.device;
+				ibevent.element.qp = &nesqp->ibqp;
+				ibevent.event = IB_EVENT_QP_FATAL;
+				nesqp->ibqp.event_handler(&ibevent,
nesqp->ibqp.qp_context );
+			}
+			nesqp->ibqp_state = IB_QPS_SQE;
+			nesqp->iwarp_state =
NES_CQP_QP_IWARP_STATE_TERMINATE;
+			/* TODO: this does not seem correct, Seems like
app should do close */
+			INIT_WORK(&nesqp->ae_work,
nes_disconnect_worker, nesqp);
+			queue_work(nesqp->aewq, &nesqp->ae_work);
+			break;
+			/* TODO: additional AEs need to be here */
+        default:
+            printk("%s: Processing an iWARP related AE for QP, misc =
0x%04X\n", __FUNCTION__, 
+							async_event_id);
+            break;
+    }
+}
+
+
+/**
+ * iwarp_ce_handler
+ * 
+ * @param nesdev
+ * @param hw_cq
+ */
+void iwarp_ce_handler(struct nes_dev *nesdev, struct nes_hw_cq *hw_cq)
+{
+	struct nes_cq *nescq = container_of(hw_cq, struct nes_cq,
hw_cq);
+
+//	dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__);
+
+//	dprintk("%s: Processing completion event for iWARP CQ%u.\n",
__FUNCTION__, nescq->hw_cq.cq_number);
+	nes_write32(nesdev->regs+NES_CQ_ACK, nescq->hw_cq.cq_number );
+
+	if (nescq->ibcq.comp_handler)
+		nescq->ibcq.comp_handler(&nescq->ibcq,
nescq->ibcq.cq_context);
+
+	return; 
+
+}
+





More information about the general mailing list