Kernel driver patch 5 of 9. Signed-off-by: Glenn Grundstrom <[EMAIL PROTECTED]>
====================================================== 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; + +} + - 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