Kernel driver patch 6 of 9. Signed-off-by: Glenn Grundstrom <[EMAIL PROTECTED]>
====================================================== diff -ruNp old/drivers/infiniband/hw/nes/nes_nic.c new/drivers/infiniband/hw/nes/nes_nic.c --- old/drivers/infiniband/hw/nes/nes_nic.c 1969-12-31 18:00:00.000000000 -0600 +++ new/drivers/infiniband/hw/nes/nes_nic.c 2006-10-25 10:15:50.000000000 -0500 @@ -0,0 +1,567 @@ +/* + * 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 <linux/if_arp.h> + +#include "nes.h" + +static const u32 default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK + | NETIF_MSG_IFUP | NETIF_MSG_IFDOWN; +static int debug = -1; + +static int nes_netdev_open(struct net_device *); +static int nes_netdev_stop(struct net_device *); +static int nes_netdev_start_xmit(struct sk_buff *, struct net_device *); +static struct net_device_stats *nes_netdev_get_stats(struct net_device *); +static void nes_netdev_tx_timeout(struct net_device *); +static int nes_netdev_set_mac_address(struct net_device *, void *); +static int nes_netdev_change_mtu(struct net_device *, int); + + +/** + * nes_netdev_open + * + * @param netdev + * + * @return int + */ +static int nes_netdev_open(struct net_device *netdev) +{ + struct nes_port *nes_port = netdev_priv(netdev); + struct nes_dev *nesdev = nes_port->nesdev; + u32 u32temp; + u32 nic_active_bit; + u32 nic_active; + u16 link_up = 0; + + dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__); + + assert(nesdev != NULL); + + if (netif_msg_ifup(nes_port)) + dprintk(KERN_INFO PFX "%s: enabling interface\n", netdev->name); + + /* clear the MAC interrupt status */ + u32temp = nes_read_indexed(nesdev->index_reg, NES_IDX_MAC_INT_STATUS ); + dprintk("Phy interrupt status = 0x%X.\n", u32temp); + nes_write_indexed(nesdev->index_reg, NES_IDX_MAC_INT_STATUS, u32temp); + + nes_phy_init(nesdev); + + nes_nic_qp_init(nesdev, netdev); + + // Set packet filters + nic_active_bit = 1<<PCI_FUNC(nesdev->pcidev->devfn); + nic_active = nes_read_indexed(nesdev->index_reg, NES_IDX_NIC_ACTIVE); + nic_active |= nic_active_bit; + nic_active |= 2; + nes_write_indexed(nesdev->index_reg, NES_IDX_NIC_ACTIVE, nic_active); + nic_active = nes_read_indexed(nesdev->index_reg, NES_IDX_NIC_MULTICAST_ALL); + nic_active |= nic_active_bit; + nes_write_indexed(nesdev->index_reg, NES_IDX_NIC_MULTICAST_ALL, nic_active); + nic_active = nes_read_indexed(nesdev->index_reg, NES_IDX_NIC_BROADCAST_ON); + nic_active |= nic_active_bit; + nes_write_indexed(nesdev->index_reg, NES_IDX_NIC_BROADCAST_ON, nic_active); + + + nes_write32(nesdev->regs+NES_CQE_ALLOC, NES_CQE_ALLOC_NOTIFY_NEXT | + nesdev->hnic_cq.cq_number ); + + // TODO: add proper way to setup packet filters + // TODO: move some of the code from init_netdev? + + if ( link_up ) { + /* Enable network packets */ + nes_port->linkup = 1; + netif_start_queue(netdev); + } else { + nes_port->linkup = 0; + netif_carrier_off(netdev); + } + + nes_write_indexed(nesdev->index_reg, NES_IDX_MAC_INT_MASK, + ~(NES_MAC_INT_LINK_STAT_CHG | NES_MAC_INT_XGMII_EXT | + NES_MAC_INT_TX_UNDERFLOW | NES_MAC_INT_TX_ERROR) ); + + return 0; +} + + +/** + * nes_netdev_stop + * + * @param netdev + * + * @return int + */ +static int nes_netdev_stop(struct net_device *netdev) +{ + struct nes_port *nes_port = netdev_priv(netdev); + struct nes_dev *nesdev = nes_port->nesdev; + struct nes_hw_cqp_wqe *cqp_wqe; + struct nes_hw_nic_rq_wqe *nic_rqe; + u64 wqe_frag; + u32 cqp_head; + u32 nic_active_mask; + u32 nic_active; + unsigned long flags; + int ret; + + dprintk("%s:%s:%u\n", __FILE__, __FUNCTION__, __LINE__); + + nes_stop_cm(nesdev); + + if (netif_msg_ifdown(nes_port)) + dprintk(KERN_INFO PFX "%s: disabling interface\n", netdev->name); + + nes_write_indexed(nesdev->index_reg, NES_IDX_MAC_INT_MASK, 0xffffffff ); + + nic_active_mask = ~((u32)(1<<PCI_FUNC(nesdev->pcidev->devfn))); + nic_active_mask = ~((u32)(1 << (PCI_FUNC(nesdev->pcidev->devfn) + 1))); + nes_write_indexed(nesdev->index_reg, + NES_IDX_PERFECT_FILTER_HIGH+((PCI_FUNC(nesdev->pcidev->devfn)+1)*8), 0); + nes_write_indexed(nesdev->index_reg, + NES_IDX_PERFECT_FILTER_HIGH+(PCI_FUNC(nesdev->pcidev->devfn)*8), 0); + nic_active = nes_read_indexed(nesdev->index_reg, NES_IDX_NIC_ACTIVE); + nic_active &= nic_active_mask; + nes_write_indexed(nesdev->index_reg, NES_IDX_NIC_ACTIVE, nic_active); + nic_active = nes_read_indexed(nesdev->index_reg, NES_IDX_NIC_MULTICAST_ALL); + nic_active &= nic_active_mask; + nes_write_indexed(nesdev->index_reg, NES_IDX_NIC_MULTICAST_ALL, nic_active); + nic_active = nes_read_indexed(nesdev->index_reg, NES_IDX_NIC_BROADCAST_ON); + nic_active &= nic_active_mask; + nes_write_indexed(nesdev->index_reg, NES_IDX_NIC_BROADCAST_ON, nic_active); + + + /* Disable network packets */ + netif_stop_queue(netdev); + + // Free remaining NIC receive buffers + while (nesdev->hnic.rq_head != nesdev->hnic.rq_tail) { + nic_rqe = &nesdev->hnic.rq_vbase[nesdev->hnic.rq_tail]; + wqe_frag = nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_LOW_IDX]; + wqe_frag += ((u64)nic_rqe->wqe_words[NES_NIC_RQ_WQE_FRAG0_HIGH_IDX])<<32; + pci_unmap_single(nesdev->pcidev, (dma_addr_t)wqe_frag, + max_frame_len, PCI_DMA_FROMDEVICE); + dev_kfree_skb(nesdev->hnic.rx_skb[nesdev->hnic.rq_tail++]); + nesdev->hnic.rq_tail &= nesdev->hnic.rq_size - 1; + } + + // Destroy NIC QP + 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] = cpu_to_le32(NES_CQP_DESTROY_QP | NES_CQP_QP_TYPE_NIC); + cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(nesdev->hnic_cq.cq_number); + 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; + if (++cqp_head >= nesdev->cqp.sq_size) cqp_head = 0; + cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head]; + + // Destroy NIC CQ + cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_CQ | (nesdev->hnic_cq.cq_size<<16)); + cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(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; + 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 destroy 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("Destroy NIC QP completed, wait_event_timeout ret = %u.\n", ret); + + // Free the NIC memory + pci_free_consistent(nesdev->pcidev, nesdev->nic_mem_size, nesdev->hnic.first_frag_vbase, + nesdev->hnic.frag_paddr[0]); + + return 0; +} + + +/** + * nes_netdev_start_xmit + * + * @param skb + * @param netdev + * + * @return int + */ +static int nes_netdev_start_xmit(struct sk_buff *skb, struct net_device *netdev) +{ + struct nes_port *nes_port = netdev_priv(netdev); + struct nes_dev *nesdev = nes_port->nesdev; + struct nes_hw_nic *nesnic = &nesdev->hnic; + struct nes_hw_nic_sq_wqe *nic_sqe; + unsigned long flags; + dma_addr_t bus_address; + +// printk(KERN_ERR PFX "%s: Request to transmit a NIC packet length %u (%u frags), first address = %p...\n", +// pci_name(nesdev->pcidev), skb_headlen(skb), skb_shinfo(skb)->nr_frags, skb->data); + local_irq_save(flags); + if (!spin_trylock(&nesnic->sq_lock)) { + local_irq_restore(flags); + return NETDEV_TX_LOCKED; + } + + /* Check if SQ is full */ + if ((((nesnic->sq_tail+(nesnic->sq_size*2))-nesnic->sq_head) & (nesnic->sq_size - 1)) == 1 ) { + netif_stop_queue(netdev); + spin_unlock_irqrestore(&nesnic->sq_lock, flags); + dprintk(KERN_WARNING PFX "%s: HNIC SQ full when queue awake!\n", netdev->name); + return NETDEV_TX_BUSY; + } + + /* Check if too many fragments */ + if (skb_shinfo(skb)->nr_frags) { + /* TODO: if too many fragments copy the data or enable EFBs */ + spin_unlock_irqrestore(&nesnic->sq_lock, flags); + kfree_skb(skb); + dprintk(KERN_WARNING PFX "%s: HNIC TODO: Need support for more 4 fragments! Packet with %u fragments not sent.\n", + netdev->name, skb_shinfo(skb)->nr_frags+1); + return NETDEV_TX_OK; + } + + memcpy(&nesnic->first_frag_vbase[nesnic->sq_head].buffer, + skb->data, min(((unsigned int)NES_FIRST_FRAG_SIZE), (skb_headlen(skb)))); + + nic_sqe = &nesnic->sq_vbase[nesnic->sq_head]; + + nic_sqe->wqe_words[NES_NIC_SQ_WQE_MISC_IDX] = cpu_to_le32(NES_NIC_SQ_WQE_DISABLE_CHKSUM | NES_NIC_SQ_WQE_COMPLETION); + nic_sqe->wqe_words[NES_NIC_SQ_WQE_TOTAL_LENGTH_IDX] = cpu_to_le32(skb_headlen(skb)); + if (skb_headlen(skb)>NES_FIRST_FRAG_SIZE) { + bus_address = pci_map_single(nesdev->pcidev, skb->data+NES_FIRST_FRAG_SIZE, + skb_headlen(skb)-NES_FIRST_FRAG_SIZE, PCI_DMA_TODEVICE); + nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_2_1_IDX] = cpu_to_le32(skb_headlen(skb)-NES_FIRST_FRAG_SIZE); + nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG1_LOW_IDX] = cpu_to_le32((u32)bus_address); + nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG1_HIGH_IDX] = cpu_to_le32((u32)((u64)bus_address>>32)); +// dprintk("Mapping sq fragment 0x%08X%08X, length = %u.\n", +// nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG1_HIGH_IDX], +// nic_sqe->wqe_words[NES_NIC_SQ_WQE_FRAG1_LOW_IDX], +// nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_2_1_IDX]); + nesnic->tx_skb[nesnic->sq_head] = skb; + } else { + nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_2_1_IDX] = 0; + nesnic->tx_skb[nesnic->sq_head] = 0; + dev_kfree_skb(skb); + } + + nesnic->sq_head++; + nesnic->sq_head &= nesnic->sq_size-1; + + barrier(); + + nes_write32(nesdev->regs+NES_WQE_ALLOC, (1<<24) | (1<<23) | nesdev->hnic.qp_id ); + + netdev->trans_start = jiffies; + nes_port->netstats.tx_packets++; + nes_port->netstats.tx_bytes += skb_headlen(skb); + spin_unlock_irqrestore(&nesnic->sq_lock, flags); + + return NETDEV_TX_OK; +} + + +/** + * nes_netdev_get_stats + * + * @param netdev + * + * @return struct net_device_stats* + */ +static struct net_device_stats *nes_netdev_get_stats(struct net_device *netdev) +{ + struct nes_port *nes_port = netdev_priv(netdev); + + return (&nes_port->netstats); +} + + +/** + * nes_netdev_tx_timeout + * + * @param netdev + */ +static void nes_netdev_tx_timeout(struct net_device *netdev) +{ + struct nes_port *nes_port = netdev_priv(netdev); + + if (netif_msg_timer(nes_port)) + dprintk(KERN_DEBUG PFX "%s: tx timeout\n", netdev->name); +} + + +/** + * nes_netdev_set_mac_address + * + * @param netdev + * @param p + * + * @return int + */ +static int nes_netdev_set_mac_address(struct net_device *netdev, void *p) +{ + return -1; +} + + +/** + * nes_netdev_change_mtu + * + * @param netdev + * @param new_mtu + * + * @return int + */ +static int nes_netdev_change_mtu(struct net_device *netdev, int new_mtu) +{ + int ret = 0; + + if ( (new_mtu < ETH_ZLEN) || (new_mtu > max_mtu) ) + return -EINVAL; + + netdev->mtu = new_mtu; + + if (netif_running(netdev)) { + nes_netdev_stop(netdev); + nes_netdev_open(netdev); + } + + return ret; +} + + +/** + * nes_netdev_init - initialize network device + * + * @param nesdev + * @param mmio_addr + * + * @return struct net_device* + */ +struct net_device *nes_netdev_init(struct nes_dev *nesdev, void __iomem *mmio_addr) +{ + struct nes_port *nes_port = NULL; + struct net_device *netdev = alloc_etherdev(sizeof(*nes_port)); + u32 count=0; + + if (!netdev) { + dprintk(KERN_ERR PFX "nes_port etherdev alloc failed"); + return NULL; + } + + SET_MODULE_OWNER(netdev); + SET_NETDEV_DEV(netdev, &nesdev->pcidev->dev); + + netdev->open = nes_netdev_open; + netdev->stop = nes_netdev_stop; + netdev->hard_start_xmit = nes_netdev_start_xmit; + netdev->get_stats = nes_netdev_get_stats; + netdev->tx_timeout = nes_netdev_tx_timeout; + netdev->set_mac_address = nes_netdev_set_mac_address; + netdev->change_mtu = nes_netdev_change_mtu; + netdev->watchdog_timeo = NES_TX_TIMEOUT; + netdev->irq = nesdev->pcidev->irq; + netdev->mtu = max_mtu; + netdev->hard_header_len = ETH_HLEN; + netdev->addr_len = ETH_ALEN; + netdev->type = ARPHRD_ETHER; + + /* Setup the burned in MAC address */ + netdev->dev_addr[0] = (u8)(nesdev->nesadapter->mac_addr_high>>8); + netdev->dev_addr[1] = (u8)nesdev->nesadapter->mac_addr_high; + netdev->dev_addr[2] = (u8)(nesdev->nesadapter->mac_addr_low>>24); + netdev->dev_addr[3] = (u8)(nesdev->nesadapter->mac_addr_low>>16); + netdev->dev_addr[4] = (u8)(nesdev->nesadapter->mac_addr_low>>8); + netdev->dev_addr[5] = (u8)nesdev->nesadapter->mac_addr_low; + + /* Program the various MAC regs */ + nes_write_indexed(nesdev->index_reg, + NES_IDX_PERFECT_FILTER_LOW+(PCI_FUNC(nesdev->pcidev->devfn)*8), + nesdev->nesadapter->mac_addr_low+PCI_FUNC(nesdev->pcidev->devfn)); + nes_write_indexed(nesdev->index_reg, + NES_IDX_PERFECT_FILTER_HIGH+(PCI_FUNC(nesdev->pcidev->devfn)*8), + (u32)nesdev->nesadapter->mac_addr_high | NES_MAC_ADDR_VALID | + ((((u32)PCI_FUNC(nesdev->pcidev->devfn))<<16))); + nes_write_indexed(nesdev->index_reg, + NES_IDX_PERFECT_FILTER_LOW+((PCI_FUNC(nesdev->pcidev->devfn)+1)*8), + nesdev->nesadapter->mac_addr_low+PCI_FUNC(nesdev->pcidev->devfn)); + nes_write_indexed(nesdev->index_reg, + NES_IDX_PERFECT_FILTER_HIGH+((PCI_FUNC(nesdev->pcidev->devfn)+1)*8), + (u32)nesdev->nesadapter->mac_addr_high | NES_MAC_ADDR_VALID | + ((((u32)PCI_FUNC(nesdev->pcidev->devfn))<<16))); + + /* Fill in the port structure */ + nes_port = netdev_priv(netdev); + nes_port->netdev = netdev; + nes_port->nesdev = nesdev; + nes_port->msg_enable = netif_msg_init(debug, default_msg); + + spin_lock_init(&nes_port->tx_lock); + + nes_cqp_init(nesdev); + + // Arm the CCQ + nes_write32(nesdev->regs+NES_CQE_ALLOC, NES_CQE_ALLOC_NOTIFY_NEXT | + PCI_FUNC(nesdev->pcidev->devfn) ); + + // Enable the interrupts + nesdev->int_req = (1<<PCI_FUNC(nesdev->pcidev->devfn)) | + (1<<(PCI_FUNC(nesdev->pcidev->devfn)+16)) | + (1<<(PCI_FUNC(nesdev->pcidev->devfn)+24)); + nesdev->intf_int_req &= ~NES_INTF_INT_CRITERR; + nes_write32(nesdev->regs+NES_INTF_INT_MASK, ~(nesdev->intf_int_req)); + + nes_write32(nesdev->regs+NES_INT_MASK, ~nesdev->int_req); + dprintk("Waiting for create CQP init to complete.\n"); + do { + if (count++ > 1000) + break; + udelay(10); + } while (!(nesdev->cqp.sq_head == nesdev->cqp.sq_tail)); + + nesdev->netdev = netdev; + + list_add_tail(&nesdev->list, &nes_dev_list); + + return netdev; +} + + +/** + * nes_netdev_exit + * + * @param nesdev + */ +void nes_netdev_exit(struct nes_dev *nesdev) +{ + struct nes_hw_cqp_wqe *cqp_wqe; + u32 count=0; + u32 cqp_head; + unsigned long flags; + int ret; + + dprintk("Waiting for CQP work to complete.\n"); + do { + if (count++ > 1000) break; + udelay(10); + } while ( !(nesdev->cqp.sq_head == nesdev->cqp.sq_tail) ); + + // Reset CCQ + nes_write32(nesdev->regs+NES_CQE_ALLOC, NES_CQE_ALLOC_RESET | + nesdev->ccq.cq_number ); + // Disable device interrupts + nes_write32(nesdev->regs+NES_INT_MASK, 0x7fffffff ); + // Destroy the AEQ + spin_lock_irqsave(&nesdev->cqp.lock, flags); + cqp_head = nesdev->cqp.sq_head++; + nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1; + cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head]; + cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_AEQ + (PCI_FUNC(nesdev->pcidev->devfn)<<8)); + cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] = 0; + // Destroy the CEQ + cqp_head = nesdev->cqp.sq_head++; + nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1; + cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head]; + cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_CEQ + (PCI_FUNC(nesdev->pcidev->devfn)<<8)); + // Destroy the CCQ + cqp_head = nesdev->cqp.sq_head++; + nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1; + cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head]; + cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_CQ); + cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32( PCI_FUNC(nesdev->pcidev->devfn) || (PCI_FUNC(nesdev->pcidev->devfn)<<16)); + // Destroy CQP + cqp_head = nesdev->cqp.sq_head++; + nesdev->cqp.sq_head &= nesdev->cqp.sq_size-1; + cqp_wqe = &nesdev->cqp.sq_vbase[cqp_head]; + cqp_wqe->wqe_words[NES_CQP_WQE_OPCODE_IDX] = cpu_to_le32(NES_CQP_DESTROY_QP | NES_CQP_QP_TYPE_CQP); + cqp_wqe->wqe_words[NES_CQP_WQE_ID_IDX] = cpu_to_le32(nesdev->cqp.qp_id); + + barrier(); + // Ring doorbell (4 WQEs) + nes_write32(nesdev->regs+NES_WQE_ALLOC, 0x04800000 | nesdev->cqp.qp_id); + + // Wait for the destroy to complete + spin_unlock_irqrestore(&nesdev->cqp.lock, flags); + dprintk("%s:Waiting for DestroyQP.\n",__FUNCTION__); + 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("%s:Done waiting for DestroyQP. wait_event_timeout ret = %d.\n",__FUNCTION__, ret); + // Free the control structures + pci_free_consistent(nesdev->pcidev, nesdev->cqp_mem_size, nesdev->cqp.sq_vbase, + nesdev->cqp.sq_pbase); + list_del(&nesdev->list); +} + + +/** + * nes_adapter_free - free network adapter + * + * @param nesadapter + */ +void nes_adapter_free(struct nes_adapter *nesadapter) +{ + struct nes_adapter *tmp_adapter; + list_for_each_entry(tmp_adapter, &nes_adapter_list, list) { + dprintk("%s: Nes Adapter list entry = 0x%p.\n", __FUNCTION__, tmp_adapter); + } + + nesadapter->ref_count--; + if (!nesadapter->ref_count) { + dprintk("nes_adapter_free: Deleting adapter from adapter list.\n" ); + list_del(&nesadapter->list); + /* TODO: free the resources from the resource list */ + dprintk("nes_adapter_free: Freeing adapter structure.\n"); + kfree(nesadapter); + } + dprintk("nes_adapter_free: Done.\n"); +} + + - 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