Ammasso 1100 iWARP Driver
Subsystems (3)
v4 cover Ammasso 1100 iWARP Driver
Roland, here is the updated Ammasso 1100 iWARP Driver.
----
This patchset implements the iWARP provider driver for the Ammasso 1100 RNIC. It is dependent on the "iWARP Core Support" patch set. The patchset consists of 7 patches:
1 - Low-level device interface and native stack support 2 - Work request definitions
3 - Provider interface
4 - Memory management
5 - User mode message queue implementation
6 - Verbs queue implementation
7 - Kconfig and Makefile
PATCH v4 1/7 AMSO1100 Low Level Driver.
This is the core of the driver and includes the hardware probe, low-level device interfaces and native Ethernet support.
---
drivers/infiniband/hw/amso1100/c2.c | 1255 ++++++++++++++++++++++++++++++ drivers/infiniband/hw/amso1100/c2.h | 552 +++++++++++++ drivers/infiniband/hw/amso1100/c2_ae.c | 321 ++++++++ drivers/infiniband/hw/amso1100/c2_intr.c | 209 +++++ drivers/infiniband/hw/amso1100/c2_rnic.c | 664 ++++++++++++++++ 5 files changed, 3001 insertions(+), 0 deletions(-)
drivers/infiniband/hw/amso1100/c2.c new file +1255 -0
@@ -0,0 +1,1255 @@ +/* +* Copyright (c) 2005 Ammasso, Inc. All rights reserved. +* Copyright (c) 2005 Open Grid Computing, 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/pci.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/inetdevice.h> +#include <linux/delay.h> +#include <linux/ethtool.h> +#include <linux/mii.h> +#include <linux/if_vlan.h> +#include <linux/crc32.h> +#include <linux/in.h> +#include <linux/ip.h> +#include <linux/tcp.h> +#include <linux/init.h> +#include <linux/dma-mapping.h> + +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/byteorder.h> + +#include <rdma/ib_smi.h> +#include "c2.h" +#include "c2_provider.h" + +MODULE_AUTHOR ("Tom Tucker <[email protected]>" ); +MODULE_DESCRIPTION ("Ammasso AMSO1100 Low-level iWARP Driver" ); +MODULE_LICENSE ("Dual BSD/GPL" ); +MODULE_VERSION (DRV_VERSION ); + +static const u32 default_msg =NETIF_MSG_DRV |NETIF_MSG_PROBE |NETIF_MSG_LINK + |NETIF_MSG_IFUP |NETIF_MSG_IFDOWN ; + +static int debug =-1 ;/* defaults above */ +module_param (debug, int,0 ); +MODULE_PARM_DESC (debug,"Debug level (0=none,...,16=all)" ); + +static int c2_up (struct net_device *netdev); +static int c2_down (struct net_device *netdev); +static int c2_xmit_frame (struct sk_buff *skb,struct net_device *netdev); +static void c2_tx_interrupt (struct net_device *netdev); +static void c2_rx_interrupt (struct net_device *netdev); +static irqreturn_t c2_interrupt (int irq,void *dev_id,struct pt_regs *regs); +static void c2_tx_timeout (struct net_device *netdev); +static int c2_change_mtu (struct net_device *netdev,int new_mtu); +static void c2_reset (struct c2_port *c2_port); +static struct net_device_stats *c2_get_stats (struct net_device *netdev); + +static struct pci_device_id c2_pci_table[] = { + {0x18b8 ,0xb001 ,PCI_ANY_ID ,PCI_ANY_ID }, + {0 } +}; + +MODULE_DEVICE_TABLE (pci, c2_pci_table); + +static void c2_print_macaddr (struct net_device *netdev) +{ +pr_debug ("%s: MAC %02X:%02X:%02X:%02X:%02X:%02X, " +"IRQ %u\n" , netdev->name, + netdev->dev_addr[0 ], netdev->dev_addr[1 ], netdev->dev_addr[2 ], + netdev->dev_addr[3 ], netdev->dev_addr[4 ], netdev->dev_addr[5 ], + netdev->irq); +} + +static void c2_set_rxbufsize (struct c2_port *c2_port) +{ +struct net_device *netdev = c2_port->netdev; + +if (netdev->mtu >RX_BUF_SIZE ) + c2_port->rx_buf_size = + netdev->mtu +ETH_HLEN +sizeof (struct c2_rxp_hdr ) + +NET_IP_ALIGN ; +else + c2_port->rx_buf_size =sizeof (struct c2_rxp_hdr ) +RX_BUF_SIZE ; +} + +/* +* Allocate TX ring elements and chain them together. +* One-to-one association of adapter descriptors with ring elements. +*/ +static int c2_tx_ring_alloc (struct c2_ring *tx_ring,void *vaddr, +dma_addr_t base,void __iomem * mmio_txp_ring) +{ +struct c2_tx_desc *tx_desc; +struct c2_txp_desc __iomem *txp_desc; +struct c2_element *elem; +int i; + + tx_ring->start =kmalloc (sizeof (*elem) * tx_ring->count,GFP_KERNEL ); +if (!tx_ring->start) +return -ENOMEM ; + + elem = tx_ring->start; + tx_desc = vaddr; + txp_desc = mmio_txp_ring; +for (i =0 ; i < tx_ring->count; i++, elem++, tx_desc++, txp_desc++) { + tx_desc->len =0 ; + tx_desc->status =0 ; + +/* Set TXP_HTXD_UNINIT */ +__raw_writeq (cpu_to_be64 (0x1122334455667788ULL ), + (void __iomem *) txp_desc +C2_TXP_ADDR ); +__raw_writew (0 , (void __iomem *) txp_desc +C2_TXP_LEN ); +__raw_writew (cpu_to_be16 (TXP_HTXD_UNINIT ), + (void __iomem *) txp_desc +C2_TXP_FLAGS ); + + elem->skb =NULL ; + elem->ht_desc = tx_desc; + elem->hw_desc = txp_desc; + +if (i == tx_ring->count -1 ) { + elem->next = tx_ring->start; + tx_desc->next_offset = base; + }else { + elem->next = elem +1 ; + tx_desc->next_offset = + base + (i +1 ) *sizeof (*tx_desc); + } + } + + tx_ring->to_use = tx_ring->to_clean = tx_ring->start; + +return 0 ; +} + +/* +* Allocate RX ring elements and chain them together. +* One-to-one association of adapter descriptors with ring elements. +*/ +static int c2_rx_ring_alloc (struct c2_ring *rx_ring,void *vaddr, +dma_addr_t base,void __iomem * mmio_rxp_ring) +{ +struct c2_rx_desc *rx_desc; +struct c2_rxp_desc __iomem *rxp_desc; +struct c2_element *elem; +int i; + + rx_ring->start =kmalloc (sizeof (*elem) * rx_ring->count,GFP_KERNEL ); +if (!rx_ring->start) +return -ENOMEM ; + + elem = rx_ring->start; + rx_desc = vaddr; + rxp_desc = mmio_rxp_ring; +for (i =0 ; i < rx_ring->count; i++, elem++, rx_desc++, rxp_desc++) { + rx_desc->len =0 ; + rx_desc->status =0 ; + +/* Set RXP_HRXD_UNINIT */ +__raw_writew (cpu_to_be16 (RXP_HRXD_OK ), + (void __iomem *) rxp_desc +C2_RXP_STATUS ); +__raw_writew (0 , (void __iomem *) rxp_desc +C2_RXP_COUNT ); +__raw_writew (0 , (void __iomem *) rxp_desc +C2_RXP_LEN ); +__raw_writeq (cpu_to_be64 (0x99aabbccddeeffULL ), + (void __iomem *) rxp_desc +C2_RXP_ADDR ); +__raw_writew (cpu_to_be16 (RXP_HRXD_UNINIT ), + (void __iomem *) rxp_desc +C2_RXP_FLAGS ); + + elem->skb =NULL ; + elem->ht_desc = rx_desc; + elem->hw_desc = rxp_desc; + +if (i == rx_ring->count -1 ) { + elem->next = rx_ring->start; + rx_desc->next_offset = base; + }else { + elem->next = elem +1 ; + rx_desc->next_offset = + base + (i +1 ) *sizeof (*rx_desc); + } + } + + rx_ring->to_use = rx_ring->to_clean = rx_ring->start; + +return 0 ; +} + +/* Setup buffer for receiving */ +static inline int c2_rx_alloc (struct c2_port *c2_port,struct c2_element *elem) +{ +struct c2_dev *c2dev = c2_port->c2dev; +struct c2_rx_desc *rx_desc = elem->ht_desc; +struct sk_buff *skb; +dma_addr_t mapaddr; +u32 maplen; +struct c2_rxp_hdr *rxp_hdr; + + skb =dev_alloc_skb (c2_port->rx_buf_size); +if (unlikely (!skb)) { +pr_debug ("%s: out of memory for receive\n" , + c2_port->netdev->name); +return -ENOMEM ; + } + +/* Zero out the rxp hdr in the sk_buff */ +memset (skb->data,0 ,sizeof (*rxp_hdr)); + + skb->dev = c2_port->netdev; + + maplen = c2_port->rx_buf_size; + mapaddr = +pci_map_single (c2dev->pcidev, skb->data, maplen, +PCI_DMA_FROMDEVICE ); + +/* Set the sk_buff RXP_header to RXP_HRXD_READY */ + rxp_hdr = (struct c2_rxp_hdr *) skb->data; + rxp_hdr->flags =RXP_HRXD_READY ; + +__raw_writew (0 , elem->hw_desc +C2_RXP_STATUS ); +__raw_writew (cpu_to_be16 ((u16 ) maplen -sizeof (*rxp_hdr)), + elem->hw_desc +C2_RXP_LEN ); +__raw_writeq (cpu_to_be64 (mapaddr), elem->hw_desc +C2_RXP_ADDR ); +__raw_writew (cpu_to_be16 (RXP_HRXD_READY ), elem->hw_desc +C2_RXP_FLAGS ); + + elem->skb = skb; + elem->mapaddr = mapaddr; + elem->maplen = maplen; + rx_desc->len = maplen; + +return 0 ; +} + +/* +* Allocate buffers for the Rx ring +* For receive: rx_ring.to_clean is next received frame +*/ +static int c2_rx_fill (struct c2_port *c2_port) +{ +struct c2_ring *rx_ring = &c2_port->rx_ring; +struct c2_element *elem; +int ret =0 ; + + elem = rx_ring->start; +do { +if (c2_rx_alloc (c2_port, elem)) { + ret =1 ; +break ; + } + }while ((elem = elem->next) != rx_ring->start); + + rx_ring->to_clean = rx_ring->start; +return ret; +} + +/* Free all buffers in RX ring, assumes receiver stopped */ +static void c2_rx_clean (struct c2_port *c2_port) +{ +struct c2_dev *c2dev = c2_port->c2dev; +struct c2_ring *rx_ring = &c2_port->rx_ring; +struct c2_element *elem; +struct c2_rx_desc *rx_desc; + + elem = rx_ring->start; +do { + rx_desc = elem->ht_desc; + rx_desc->len =0 ; + +__raw_writew (0 , elem->hw_desc +C2_RXP_STATUS ); +__raw_writew (0 , elem->hw_desc +C2_RXP_COUNT ); +__raw_writew (0 , elem->hw_desc +C2_RXP_LEN ); +__raw_writeq (cpu_to_be64 (0x99aabbccddeeffULL ), + elem->hw_desc +C2_RXP_ADDR ); +__raw_writew (cpu_to_be16 (RXP_HRXD_UNINIT ), + elem->hw_desc +C2_RXP_FLAGS ); + +if (elem->skb) { +pci_unmap_single (c2dev->pcidev, elem->mapaddr, + elem->maplen,PCI_DMA_FROMDEVICE ); +dev_kfree_skb (elem->skb); + elem->skb =NULL ; + } + }while ((elem = elem->next) != rx_ring->start); +} + +static inline int c2_tx_free (struct c2_dev *c2dev,struct c2_element *elem) +{ +struct c2_tx_desc *tx_desc = elem->ht_desc; + + tx_desc->len =0 ; + +pci_unmap_single (c2dev->pcidev, elem->mapaddr, elem->maplen, +PCI_DMA_TODEVICE ); + +if (elem->skb) { +dev_kfree_skb_any (elem->skb); + elem->skb =NULL ; + } + +return 0 ; +} + +/* Free all buffers in TX ring, assumes transmitter stopped */ +static void c2_tx_clean (struct c2_port *c2_port) +{ +struct c2_ring *tx_ring = &c2_port->tx_ring; +struct c2_element *elem; +struct c2_txp_desc txp_htxd; +int retry; +unsigned long flags; + +spin_lock_irqsave (&c2_port->tx_lock, flags); + + elem = tx_ring->start; + +do { + retry =0 ; +do { + txp_htxd.flags = +readw (elem->hw_desc +C2_TXP_FLAGS ); + +if (txp_htxd.flags ==TXP_HTXD_READY ) { + retry =1 ; +__raw_writew (0 , + elem->hw_desc +C2_TXP_LEN ); +__raw_writeq (0 , + elem->hw_desc +C2_TXP_ADDR ); +__raw_writew (cpu_to_be16 (TXP_HTXD_DONE ), + elem->hw_desc +C2_TXP_FLAGS ); + c2_port->netstats.tx_dropped++; +break ; + }else { +__raw_writew (0 , + elem->hw_desc +C2_TXP_LEN ); +__raw_writeq (cpu_to_be64 (0x1122334455667788ULL ), + elem->hw_desc +C2_TXP_ADDR ); +__raw_writew (cpu_to_be16 (TXP_HTXD_UNINIT ), + elem->hw_desc +C2_TXP_FLAGS ); + } + +c2_tx_free (c2_port->c2dev, elem); + + }while ((elem = elem->next) != tx_ring->start); + }while (retry); + + c2_port->tx_avail = c2_port->tx_ring.count -1 ; + c2_port->c2dev->cur_tx = tx_ring->to_use - tx_ring->start; + +if (c2_port->tx_avail >MAX_SKB_FRAGS +1 ) +netif_wake_queue (c2_port->netdev); + +spin_unlock_irqrestore (&c2_port->tx_lock, flags); +} + +/* +* Process transmit descriptors marked 'DONE' by the firmware, +* freeing up their unneeded sk_buffs. +*/ +static void c2_tx_interrupt (struct net_device *netdev) +{ +struct c2_port *c2_port =netdev_priv (netdev); +struct c2_dev *c2dev = c2_port->c2dev; +struct c2_ring *tx_ring = &c2_port->tx_ring; +struct c2_element *elem; +struct c2_txp_desc txp_htxd; + +spin_lock (&c2_port->tx_lock); + +for (elem = tx_ring->to_clean; elem != tx_ring->to_use; + elem = elem->next) { + txp_htxd.flags = +be16_to_cpu (readw (elem->hw_desc +C2_TXP_FLAGS )); + +if (txp_htxd.flags !=TXP_HTXD_DONE ) +break ; + +if (netif_msg_tx_done (c2_port)) { +/* PCI reads are expensive in fast path */ + txp_htxd.len = +be16_to_cpu (readw (elem->hw_desc +C2_TXP_LEN )); +pr_debug ("%s: tx done slot %3Zu status 0x%x len " +"%5u bytes\n" , + netdev->name, elem - tx_ring->start, + txp_htxd.flags, txp_htxd.len); + } + +c2_tx_free (c2dev, elem); + ++(c2_port->tx_avail); + } + + tx_ring->to_clean = elem; + +if (netif_queue_stopped (netdev) + && c2_port->tx_avail >MAX_SKB_FRAGS +1 ) +netif_wake_queue (netdev); + +spin_unlock (&c2_port->tx_lock); +} + +static void c2_rx_error (struct c2_port *c2_port,struct c2_element *elem) +{ +struct c2_rx_desc *rx_desc = elem->ht_desc; +struct c2_rxp_hdr *rxp_hdr = (struct c2_rxp_hdr *) elem->skb->data; + +if (rxp_hdr->status !=RXP_HRXD_OK || + rxp_hdr->len > (rx_desc->len -sizeof (*rxp_hdr))) { +pr_debug ("BAD RXP_HRXD\n" ); +pr_debug (" rx_desc : %p\n" , rx_desc); +pr_debug (" index : %Zu\n" , + elem - c2_port->rx_ring.start); +pr_debug (" len : %u\n" , rx_desc->len); +pr_debug (" rxp_hdr : %p [PA %p]\n" , rxp_hdr, + (void *)__pa ((unsigned long ) rxp_hdr)); +pr_debug (" flags : 0x%x\n" , rxp_hdr->flags); +pr_debug (" status: 0x%x\n" , rxp_hdr->status); +pr_debug (" len : %u\n" , rxp_hdr->len); +pr_debug (" rsvd : 0x%x\n" , rxp_hdr->rsvd); + } + +/* Setup the skb for reuse since we're dropping this pkt */ + elem->skb->tail = elem->skb->data = elem->skb->head; + +/* Zero out the rxp hdr in the sk_buff */ +memset (elem->skb->data,0 ,sizeof (*rxp_hdr)); + +/* Write the descriptor to the adapter's rx ring */ +__raw_writew (0 , elem->hw_desc +C2_RXP_STATUS ); +__raw_writew (0 , elem->hw_desc +C2_RXP_COUNT ); +__raw_writew (cpu_to_be16 ((u16 ) elem->maplen -sizeof (*rxp_hdr)), + elem->hw_desc +C2_RXP_LEN ); +__raw_writeq (cpu_to_be64 (elem->mapaddr), elem->hw_desc +C2_RXP_ADDR ); +__raw_writew (cpu_to_be16 (RXP_HRXD_READY ), elem->hw_desc +C2_RXP_FLAGS ); + +pr_debug ("packet dropped\n" ); + c2_port->netstats.rx_dropped++; +} + +static void c2_rx_interrupt (struct net_device *netdev) +{ +struct c2_port *c2_port =netdev_priv (netdev); +struct c2_dev *c2dev = c2_port->c2dev; +struct c2_ring *rx_ring = &c2_port->rx_ring; +struct c2_element *elem; +struct c2_rx_desc *rx_desc; +struct c2_rxp_hdr *rxp_hdr; +struct sk_buff *skb; +dma_addr_t mapaddr; +u32 maplen, buflen; +unsigned long flags; + +spin_lock_irqsave (&c2dev->lock, flags); + +/* Begin where we left off */ + rx_ring->to_clean = rx_ring->start + c2dev->cur_rx; + +for (elem = rx_ring->to_clean; elem->next != rx_ring->to_clean; + elem = elem->next) { + rx_desc = elem->ht_desc; + mapaddr = elem->mapaddr; + maplen = elem->maplen; + skb = elem->skb; + rxp_hdr = (struct c2_rxp_hdr *) skb->data; + +if (rxp_hdr->flags !=RXP_HRXD_DONE ) +break ; + buflen = rxp_hdr->len; + +/* Sanity check the RXP header */ +if (rxp_hdr->status !=RXP_HRXD_OK || + buflen > (rx_desc->len -sizeof (*rxp_hdr))) { +c2_rx_error (c2_port, elem); +continue ; + } + +/* +* Allocate and map a new skb for replenishing the host +* RX desc +*/ +if (c2_rx_alloc (c2_port, elem)) { +c2_rx_error (c2_port, elem); +continue ; + } + +/* Unmap the old skb */ +pci_unmap_single (c2dev->pcidev, mapaddr, maplen, +PCI_DMA_FROMDEVICE ); + +prefetch (skb->data); + +/* +* Skip past the leading 8 bytes comprising of the +* "struct c2_rxp_hdr", prepended by the adapter +* to the usual Ethernet header ("struct ethhdr"), +* to the start of the raw Ethernet packet. +* +* Fix up the various fields in the sk_buff before +* passing it up to netif_rx(). The transfer size +* (in bytes) specified by the adapter len field of +* the "struct rxp_hdr_t" does NOT include the +* "sizeof(struct c2_rxp_hdr)". +*/ + skb->data +=sizeof (*rxp_hdr); + skb->tail = skb->data + buflen; + skb->len = buflen; + skb->dev = netdev; + skb->protocol =eth_type_trans (skb, netdev); + +netif_rx (skb); + + netdev->last_rx = jiffies; + c2_port->netstats.rx_packets++; + c2_port->netstats.rx_bytes += buflen; + } + +/* Save where we left off */ + rx_ring->to_clean = elem; + c2dev->cur_rx = elem - rx_ring->start; +C2_SET_CUR_RX (c2dev, c2dev->cur_rx); + +spin_unlock_irqrestore (&c2dev->lock, flags); +} + +/* +* Handle netisr0 TX & RX interrupts. +*/ +static irqreturn_t c2_interrupt (int irq,void *dev_id,struct pt_regs *regs) +{ +unsigned int netisr0, dmaisr; +int handled =0 ; +struct c2_dev *c2dev = (struct c2_dev *) dev_id; + +/* Process CCILNET interrupts */ + netisr0 =readl (c2dev->regs +C2_NISR0 ); +if (netisr0) { + +/* +* There is an issue with the firmware that always +* provides the status of RX for both TX & RX +* interrupts. So process both queues here. +*/ +c2_rx_interrupt (c2dev->netdev); +c2_tx_interrupt (c2dev->netdev); + +/* Clear the interrupt */ +writel (netisr0, c2dev->regs +C2_NISR0 ); + handled++; + } + +/* Process RNIC interrupts */ + dmaisr =readl (c2dev->regs +C2_DISR ); +if (dmaisr) { +writel (dmaisr, c2dev->regs +C2_DISR ); +c2_rnic_interrupt (c2dev); + handled++; + } + +if (handled) { +return IRQ_HANDLED ; + }else { +return IRQ_NONE ; + } +} + +static int c2_up (struct net_device *netdev) +{ +struct c2_port *c2_port =netdev_priv (netdev); +struct c2_dev *c2dev = c2_port->c2dev; +struct c2_element *elem; +struct c2_rxp_hdr *rxp_hdr; +struct in_device *in_dev; +size_t rx_size, tx_size; +int ret, i; +unsigned int netimr0; + +if (netif_msg_ifup (c2_port)) +pr_debug ("%s: enabling interface\n" , netdev->name); + +/* Set the Rx buffer size based on MTU */ +c2_set_rxbufsize (c2_port); + +/* Allocate DMA'able memory for Tx/Rx host descriptor rings */ + rx_size = c2_port->rx_ring.count *sizeof (struct c2_rx_desc ); + tx_size = c2_port->tx_ring.count *sizeof (struct c2_tx_desc ); + + c2_port->mem_size = tx_size + rx_size; + c2_port->mem =pci_alloc_consistent (c2dev->pcidev, c2_port->mem_size, + &c2_port->dma); +if (c2_port->mem ==NULL ) { +pr_debug ("Unable to allocate memory for " +"host descriptor rings\n" ); +return -ENOMEM ; + } + +memset (c2_port->mem,0 , c2_port->mem_size); + +/* Create the Rx host descriptor ring */ +if ((ret = +c2_rx_ring_alloc (&c2_port->rx_ring, c2_port->mem, c2_port->dma, + c2dev->mmio_rxp_ring))) { +pr_debug ("Unable to create RX ring\n" ); + goto bail0; + } + +/* Allocate Rx buffers for the host descriptor ring */ +if (c2_rx_fill (c2_port)) { +pr_debug ("Unable to fill RX ring\n" ); + goto bail1; + } + +/* Create the Tx host descriptor ring */ +if ((ret =c2_tx_ring_alloc (&c2_port->tx_ring, c2_port->mem + rx_size, + c2_port->dma + rx_size, + c2dev->mmio_txp_ring))) { +pr_debug ("Unable to create TX ring\n" ); + goto bail1; + } + +/* Set the TX pointer to where we left off */ + c2_port->tx_avail = c2_port->tx_ring.count -1 ; + c2_port->tx_ring.to_use = c2_port->tx_ring.to_clean = + c2_port->tx_ring.start + c2dev->cur_tx; + +/* missing: Initialize MAC */ + +BUG_ON (c2_port->tx_ring.to_use != c2_port->tx_ring.to_clean); + +/* Reset the adapter, ensures the driver is in sync with the RXP */ +c2_reset (c2_port); + +/* Reset the READY bit in the sk_buff RXP headers & adapter HRXDQ */ +for (i =0 , elem = c2_port->rx_ring.start; i < c2_port->rx_ring.count; + i++, elem++) { + rxp_hdr = (struct c2_rxp_hdr *) elem->skb->data; + rxp_hdr->flags =0 ; +__raw_writew (cpu_to_be16 (RXP_HRXD_READY ), + elem->hw_desc +C2_RXP_FLAGS ); + } + +/* Enable network packets */ +netif_start_queue (netdev); + +/* Enable IRQ */ +writel (0 , c2dev->regs +C2_IDIS ); + netimr0 =readl (c2dev->regs +C2_NIMR0 ); + netimr0 &= ~(C2_PCI_HTX_INT |C2_PCI_HRX_INT ); +writel (netimr0, c2dev->regs +C2_NIMR0 ); + +/* Tell the stack to ignore arp requests for ipaddrs bound to +* other interfaces. This is needed to prevent the host stack +* from responding to arp requests to the ipaddr bound on the +* rdma interface. +*/ + in_dev =in_dev_get (netdev); + in_dev->cnf.arp_ignore =1 ; +in_dev_put (in_dev); + +return 0 ; + + bail1: +c2_rx_clean (c2_port); +kfree (c2_port->rx_ring.start); + + bail0: +pci_free_consistent (c2dev->pcidev, c2_port->mem_size, c2_port->mem, + c2_port->dma); + +return ret; +} + +static int c2_down (struct net_device *netdev) +{ +struct c2_port *c2_port =netdev_priv (netdev); +struct c2_dev *c2dev = c2_port->c2dev; + +if (netif_msg_ifdown (c2_port)) +pr_debug ("%s: disabling interface\n" , + netdev->name); + +/* Wait for all the queued packets to get sent */ +c2_tx_interrupt (netdev); + +/* Disable network packets */ +netif_stop_queue (netdev); + +/* Disable IRQs by clearing the interrupt mask */ +writel (1 , c2dev->regs +C2_IDIS ); +writel (0 , c2dev->regs +C2_NIMR0 ); + +/* missing: Stop transmitter */ + +/* missing: Stop receiver */ + +/* Reset the adapter, ensures the driver is in sync with the RXP */ +c2_reset (c2_port); + +/* missing: Turn off LEDs here */ + +/* Free all buffers in the host descriptor rings */ +c2_tx_clean (c2_port); +c2_rx_clean (c2_port); + +/* Free the host descriptor rings */ +kfree (c2_port->rx_ring.start); +kfree (c2_port->tx_ring.start); +pci_free_consistent (c2dev->pcidev, c2_port->mem_size, c2_port->mem, + c2_port->dma); + +return 0 ; +} + +static void c2_reset (struct c2_port *c2_port) +{ +struct c2_dev *c2dev = c2_port->c2dev; +unsigned int cur_rx = c2dev->cur_rx; + +/* Tell the hardware to quiesce */ +C2_SET_CUR_RX (c2dev, cur_rx |C2_PCI_HRX_QUI ); + +/* +* The hardware will reset the C2_PCI_HRX_QUI bit once +* the RXP is quiesced. Wait 2 seconds for this. +*/ +ssleep (2 ); + + cur_rx =C2_GET_CUR_RX (c2dev); + +if (cur_rx &C2_PCI_HRX_QUI ) +pr_debug ("c2_reset: failed to quiesce the hardware!\n" ); + + cur_rx &= ~C2_PCI_HRX_QUI ; + + c2dev->cur_rx = cur_rx; + +pr_debug ("Current RX: %u\n" , c2dev->cur_rx); +} + +static int c2_xmit_frame (struct sk_buff *skb,struct net_device *netdev) +{ +struct c2_port *c2_port =netdev_priv (netdev); +struct c2_dev *c2dev = c2_port->c2dev; +struct c2_ring *tx_ring = &c2_port->tx_ring; +struct c2_element *elem; +dma_addr_t mapaddr; +u32 maplen; +unsigned long flags; +unsigned int i; + +spin_lock_irqsave (&c2_port->tx_lock, flags); + +if (unlikely (c2_port->tx_avail < (skb_shinfo (skb)->nr_frags +1 ))) { +netif_stop_queue (netdev); +spin_unlock_irqrestore (&c2_port->tx_lock, flags); + +pr_debug ("%s: Tx ring full when queue awake!\n" , + netdev->name); +return NETDEV_TX_BUSY ; + } + + maplen =skb_headlen (skb); + mapaddr = +pci_map_single (c2dev->pcidev, skb->data, maplen,PCI_DMA_TODEVICE ); + + elem = tx_ring->to_use; + elem->skb = skb; + elem->mapaddr = mapaddr; + elem->maplen = maplen; + +/* Tell HW to xmit */ +__raw_writeq (cpu_to_be64 (mapaddr), elem->hw_desc +C2_TXP_ADDR ); +__raw_writew (cpu_to_be16 (maplen), elem->hw_desc +C2_TXP_LEN ); +__raw_writew (cpu_to_be16 (TXP_HTXD_READY ), elem->hw_desc +C2_TXP_FLAGS ); + + c2_port->netstats.tx_packets++; + c2_port->netstats.tx_bytes += maplen; + +/* Loop thru additional data fragments and queue them */ +if (skb_shinfo (skb)->nr_frags) { +for (i =0 ; i <skb_shinfo (skb)->nr_frags; i++) { +skb_frag_t *frag = &skb_shinfo (skb)->frags[i]; + maplen = frag->size; + mapaddr = +pci_map_page (c2dev->pcidev, frag->page, + frag->page_offset, maplen, +PCI_DMA_TODEVICE ); + + elem = elem->next; + elem->skb =NULL ; + elem->mapaddr = mapaddr; + elem->maplen = maplen; + +/* Tell HW to xmit */ +__raw_writeq (cpu_to_be64 (mapaddr), + elem->hw_desc +C2_TXP_ADDR ); +__raw_writew (cpu_to_be16 (maplen), + elem->hw_desc +C2_TXP_LEN ); +__raw_writew (cpu_to_be16 (TXP_HTXD_READY ), + elem->hw_desc +C2_TXP_FLAGS ); + + c2_port->netstats.tx_packets++; + c2_port->netstats.tx_bytes += maplen; + } + } + + tx_ring->to_use = elem->next; + c2_port->tx_avail -= (skb_shinfo (skb)->nr_frags +1 ); + +if (c2_port->tx_avail <=MAX_SKB_FRAGS +1 ) { +netif_stop_queue (netdev); +if (netif_msg_tx_queued (c2_port)) +pr_debug ("%s: transmit queue full\n" , + netdev->name); + } + +spin_unlock_irqrestore (&c2_port->tx_lock, flags); + + netdev->trans_start = jiffies; + +return NETDEV_TX_OK ; +} + +static struct net_device_stats *c2_get_stats (struct net_device *netdev) +{ +struct c2_port *c2_port =netdev_priv (netdev); + +return &c2_port->netstats; +} + +static void c2_tx_timeout (struct net_device *netdev) +{ +struct c2_port *c2_port =netdev_priv (netdev); + +if (netif_msg_timer (c2_port)) +pr_debug ("%s: tx timeout\n" , netdev->name); + +c2_tx_clean (c2_port); +} + +static int c2_change_mtu (struct net_device *netdev,int new_mtu) +{ +int ret =0 ; + +if (new_mtu <ETH_ZLEN || new_mtu >ETH_JUMBO_MTU ) +return -EINVAL ; + + netdev->mtu = new_mtu; + +if (netif_running (netdev)) { +c2_down (netdev); + +c2_up (netdev); + } + +return ret; +} + +/* Initialize network device */ +static struct net_device *c2_devinit (struct c2_dev *c2dev, +void __iomem * mmio_addr) +{ +struct c2_port *c2_port =NULL ; +struct net_device *netdev =alloc_etherdev (sizeof (*c2_port)); + +if (!netdev) { +pr_debug ("c2_port etherdev alloc failed" ); +return NULL ; + } + +SET_MODULE_OWNER (netdev); +SET_NETDEV_DEV (netdev, &c2dev->pcidev->dev); + + netdev->open = c2_up; + netdev->stop = c2_down; + netdev->hard_start_xmit = c2_xmit_frame; + netdev->get_stats = c2_get_stats; + netdev->tx_timeout = c2_tx_timeout; + netdev->change_mtu = c2_change_mtu; + netdev->watchdog_timeo =C2_TX_TIMEOUT ; + netdev->irq = c2dev->pcidev->irq; + + c2_port =netdev_priv (netdev); + c2_port->netdev = netdev; + c2_port->c2dev = c2dev; + c2_port->msg_enable =netif_msg_init (debug, default_msg); + c2_port->tx_ring.count =C2_NUM_TX_DESC ; + c2_port->rx_ring.count =C2_NUM_RX_DESC ; + +spin_lock_init (&c2_port->tx_lock); + +/* Copy our 48-bit ethernet hardware address */ +memcpy_fromio (netdev->dev_addr, mmio_addr +C2_REGS_ENADDR ,6 ); + +/* Validate the MAC address */ +if (!is_valid_ether_addr (netdev->dev_addr)) { +pr_debug ("Invalid MAC Address\n" ); +c2_print_macaddr (netdev); +free_netdev (netdev); +return NULL ; + } + + c2dev->netdev = netdev; + +return netdev; +} + +static int __devinit c2_probe (struct pci_dev *pcidev, +const struct pci_device_id *ent) +{ +int ret =0 , i; +unsigned long reg0_start, reg0_flags, reg0_len; +unsigned long reg2_start, reg2_flags, reg2_len; +unsigned long reg4_start, reg4_flags, reg4_len; +unsigned kva_map_size; +struct net_device *netdev =NULL ; +struct c2_dev *c2dev =NULL ; +void __iomem *mmio_regs =NULL ; + + printk(KERN_INFO PFX "AMSO1100 Gigabit Ethernet driver v%s loaded\n", + DRV_VERSION); + +/* Enable PCI device */ + ret =pci_enable_device (pcidev); +if (ret) { + printk(KERN_ERR PFX "%s: Unable to enable PCI device\n", + pci_name(pcidev)); + goto bail0; + } + + reg0_start =pci_resource_start (pcidev,BAR_0 ); + reg0_len =pci_resource_len (pcidev,BAR_0 ); + reg0_flags =pci_resource_flags (pcidev,BAR_0 ); + + reg2_start =pci_resource_start (pcidev,BAR_2 ); + reg2_len =pci_resource_len (pcidev,BAR_2 ); + reg2_flags =pci_resource_flags (pcidev,BAR_2 ); + + reg4_start =pci_resource_start (pcidev,BAR_4 ); + reg4_len =pci_resource_len (pcidev,BAR_4 ); + reg4_flags =pci_resource_flags (pcidev,BAR_4 ); + +pr_debug ("BAR0 size = 0x%lX bytes\n" , reg0_len); +pr_debug ("BAR2 size = 0x%lX bytes\n" , reg2_len); +pr_debug ("BAR4 size = 0x%lX bytes\n" , reg4_len); + +/* Make sure PCI base addr are MMIO */ +if (!(reg0_flags &IORESOURCE_MEM ) || + !(reg2_flags &IORESOURCE_MEM ) || !(reg4_flags &IORESOURCE_MEM )) { + printk(KERN_ERR PFX "PCI regions not an MMIO resource\n"); + ret = -ENODEV ; + goto bail1; + } + +/* Check for weird/broken PCI region reporting */ +if ((reg0_len <C2_REG0_SIZE ) || + (reg2_len <C2_REG2_SIZE ) || (reg4_len <C2_REG4_SIZE )) { + printk(KERN_ERR PFX "Invalid PCI region sizes\n"); + ret = -ENODEV ; + goto bail1; + } + +/* Reserve PCI I/O and memory resources */ + ret =pci_request_regions (pcidev,DRV_NAME ); +if (ret) { + printk(KERN_ERR PFX "%s: Unable to request regions\n", + pci_name(pcidev)); + goto bail1; + } + +if ((sizeof (dma_addr_t) >4 )) { + ret =pci_set_dma_mask (pcidev,DMA_64BIT_MASK ); +if (ret <0 ) { + printk(KERN_ERR PFX "64b DMA configuration failed\n"); + goto bail2; + } + }else { + ret =pci_set_dma_mask (pcidev,DMA_32BIT_MASK ); +if (ret <0 ) { + printk(KERN_ERR PFX "32b DMA configuration failed\n"); + goto bail2; + } + } + +/* Enables bus-mastering on the device */ +pci_set_master (pcidev); + +/* Remap the adapter PCI registers in BAR4 */ + mmio_regs =ioremap_nocache (reg4_start +C2_PCI_REGS_OFFSET , +sizeof (struct c2_adapter_pci_regs )); +if (mmio_regs ==0UL ) { + printk(KERN_ERR PFX + "Unable to remap adapter PCI registers in BAR4\n"); + ret = -EIO ; + goto bail2; + } + +/* Validate PCI regs magic */ +for (i =0 ; i <sizeof (c2_magic); i++) { +if (c2_magic[i] !=readb (mmio_regs +C2_REGS_MAGIC + i)) { + printk(KERN_ERR PFX "Downlevel Firmware boot loader " +"[%d/%Zd: got 0x%x, exp 0x%x]. Use the cc_flash " +"utility to update your boot loader\n" , + i +1 ,sizeof (c2_magic), +readb (mmio_regs +C2_REGS_MAGIC + i), + c2_magic[i]); + printk(KERN_ERR PFX "Adapter not claimed\n"); +iounmap (mmio_regs); + ret = -EIO ; + goto bail2; + } + } + +/* Validate the adapter version */ +if (be32_to_cpu (readl (mmio_regs +C2_REGS_VERS )) !=C2_VERSION ) { + printk(KERN_ERR PFX "Version mismatch " +"[fw=%u, c2=%u], Adapter not claimed\n" , +be32_to_cpu (readl (mmio_regs +C2_REGS_VERS )), + C2_VERSION); + ret = -EINVAL ; +iounmap (mmio_regs); + goto bail2; + } + +/* Validate the adapter IVN */ +if (be32_to_cpu (readl (mmio_regs +C2_REGS_IVN )) !=C2_IVN ) { + printk(KERN_ERR PFX "Downlevel FIrmware level. You should be using " +"the OpenIB device support kit. " +"[fw=0x%x, c2=0x%x], Adapter not claimed\n" , +be32_to_cpu (readl (mmio_regs +C2_REGS_IVN )), + C2_IVN); + ret = -EINVAL ; +iounmap (mmio_regs); + goto bail2; + } + +/* Allocate hardware structure */ + c2dev = (struct c2_dev *)ib_alloc_device (sizeof (*c2dev)); +if (!c2dev) { + printk(KERN_ERR PFX "%s: Unable to alloc hardware struct\n", + pci_name(pcidev)); + ret = -ENOMEM ; +iounmap (mmio_regs); + goto bail2; + } + +memset (c2dev,0 ,sizeof (*c2dev)); +spin_lock_init (&c2dev->lock); + c2dev->pcidev = pcidev; + c2dev->cur_tx =0 ; + +/* Get the last RX index */ + c2dev->cur_rx = + (be32_to_cpu (readl (mmio_regs +C2_REGS_HRX_CUR )) - +0xffffc000 ) /sizeof (struct c2_rxp_desc ); + +/* Request an interrupt line for the driver */ + ret =request_irq (pcidev->irq, c2_interrupt,SA_SHIRQ ,DRV_NAME , c2dev); +if (ret) { + printk(KERN_ERR PFX "%s: requested IRQ %u is busy\n", + pci_name(pcidev), pcidev->irq); +iounmap (mmio_regs); + goto bail3; + } + +/* Set driver specific data */ +pci_set_drvdata (pcidev, c2dev); + +/* Initialize network device */ +if ((netdev =c2_devinit (c2dev, mmio_regs)) ==NULL ) { +iounmap (mmio_regs); + goto bail4; + } + +/* Save off the actual size prior to unmapping mmio_regs */ + kva_map_size =be32_to_cpu (readl (mmio_regs +C2_REGS_PCI_WINSIZE )); + +/* Unmap the adapter PCI registers in BAR4 */ +iounmap (mmio_regs); + +/* Register network device */ + ret =register_netdev (netdev); +if (ret) { + printk(KERN_ERR PFX "Unable to register netdev, ret = %d\n", + ret); + goto bail5; + } + +/* Disable network packets */ +netif_stop_queue (netdev); + +/* Remap the adapter HRXDQ PA space to kernel VA space */ + c2dev->mmio_rxp_ring =ioremap_nocache (reg4_start +C2_RXP_HRXDQ_OFFSET , +C2_RXP_HRXDQ_SIZE ); +if (c2dev->mmio_rxp_ring ==0UL ) { + printk(KERN_ERR PFX "Unable to remap MMIO HRXDQ region\n"); + ret = -EIO ; + goto bail6; + } + +/* Remap the adapter HTXDQ PA space to kernel VA space */ + c2dev->mmio_txp_ring =ioremap_nocache (reg4_start +C2_TXP_HTXDQ_OFFSET , +C2_TXP_HTXDQ_SIZE ); +if (c2dev->mmio_txp_ring ==0UL ) { + printk(KERN_ERR PFX "Unable to remap MMIO HTXDQ region\n"); + ret = -EIO ; + goto bail7; + } + +/* Save off the current RX index in the last 4 bytes of the TXP Ring */ +C2_SET_CUR_RX (c2dev, c2dev->cur_rx); + +/* Remap the PCI registers in adapter BAR0 to kernel VA space */ + c2dev->regs =ioremap_nocache (reg0_start, reg0_len); +if (c2dev->regs ==0UL ) { + printk(KERN_ERR PFX "Unable to remap BAR0\n"); + ret = -EIO ; + goto bail8; + } + +/* Remap the PCI registers in adapter BAR4 to kernel VA space */ + c2dev->pa = reg4_start +C2_PCI_REGS_OFFSET ; + c2dev->kva =ioremap_nocache (reg4_start +C2_PCI_REGS_OFFSET , + kva_map_size); +if (c2dev->kva ==0UL ) { + printk(KERN_ERR PFX "Unable to remap BAR4\n"); + ret = -EIO ; + goto bail9; + } + +/* Print out the MAC address */ +c2_print_macaddr (netdev); + + ret =c2_rnic_init (c2dev); +if (ret) { + printk(KERN_ERR PFX "c2_rnic_init failed: %d\n", ret); + goto bail10; + } + +c2_register_device (c2dev); + +return 0 ; + + bail10: +iounmap (c2dev->kva); + + bail9: +iounmap (c2dev->regs); + + bail8: +iounmap (c2dev->mmio_txp_ring); + + bail7: +iounmap (c2dev->mmio_rxp_ring); + + bail6: +unregister_netdev (netdev); + + bail5: +free_netdev (netdev); + + bail4: +free_irq (pcidev->irq, c2dev); + + bail3: +ib_dealloc_device (&c2dev->ibdev); + + bail2: +pci_release_regions (pcidev); + + bail1: +pci_disable_device (pcidev); + + bail0: +return ret; +} + +static void __devexit c2_remove(struct pci_dev *pcidev) +{ +struct c2_dev *c2dev =pci_get_drvdata (pcidev); +struct net_device *netdev = c2dev->netdev; + +/* Unregister with OpenIB */ +c2_unregister_device (c2dev); + +/* Clean up the RNIC resources */ +c2_rnic_term (c2dev); + +/* Remove network device from the kernel */ +unregister_netdev (netdev); + +/* Free network device */ +free_netdev (netdev); + +/* Free the interrupt line */ +free_irq (pcidev->irq, c2dev); + +/* missing: Turn LEDs off here */ + +/* Unmap adapter PA space */ +iounmap (c2dev->kva); +iounmap (c2dev->regs); +iounmap (c2dev->mmio_txp_ring); +iounmap (c2dev->mmio_rxp_ring); + +/* Free the hardware structure */ +ib_dealloc_device (&c2dev->ibdev); + +/* Release reserved PCI I/O and memory resources */ +pci_release_regions (pcidev); + +/* Disable PCI device */ +pci_disable_device (pcidev); + +/* Clear driver specific data */ +pci_set_drvdata (pcidev,NULL ); +} + +static struct pci_driver c2_pci_driver = { + .name =DRV_NAME , + .id_table = c2_pci_table, + .probe = c2_probe, + .remove =__devexit_p (c2_remove), +}; + +static int __init c2_init_module (void ) +{ +return pci_module_init (&c2_pci_driver); +} + +static void __exit c2_exit_module(void) +{ +pci_unregister_driver (&c2_pci_driver); +} + +module_init (c2_init_module); +module_exit (c2_exit_module);
drivers/infiniband/hw/amso1100/c2.h new file +552 -0
552 lines not on this page · raw message
drivers/infiniband/hw/amso1100/c2_ae.c new file +321 -0
321 lines not on this page · raw message
drivers/infiniband/hw/amso1100/c2_intr.c new file +209 -0
209 lines not on this page · raw message
drivers/infiniband/hw/amso1100/c2_rnic.c new file +664 -0
663 lines not on this page · raw message
The rest of this diff is not shown. View the raw message.
Part of the diff is not shown here. View the raw message.
PATCH v4 2/7 AMSO1100 WR / Event Definitions.
In reply to Steve Wise---
drivers/infiniband/hw/amso1100/c2_ae.h | 108 ++ drivers/infiniband/hw/amso1100/c2_status.h | 158 +++ drivers/infiniband/hw/amso1100/c2_wr.h | 1520 ++++++++++++++++++++++++++++ 3 files changed, 1786 insertions(+), 0 deletions(-)
drivers/infiniband/hw/amso1100/c2_ae.h new file +108 -0
@@ -0,0 +1,108 @@ +/* +* Copyright (c) 2005 Ammasso, Inc. All rights reserved. +* Copyright (c) 2005 Open Grid Computing, 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. +*/ +#ifndef _C2_AE_H_ +#define _C2_AE_H_ + +/* +* WARNING: If you change this file, also bump C2_IVN_BASE +* in common/include/clustercore/c2_ivn.h. +*/ + +/* +* Asynchronous Event Identifiers +* +* These start at 0x80 only so it's obvious from inspection that +* they are not work-request statuses. This isn't critical. +* +* NOTE: these event id's must fit in eight bits. +*/ +enum c2_event_id { +CCAE_REMOTE_SHUTDOWN =0x80 , +CCAE_ACTIVE_CONNECT_RESULTS , +CCAE_CONNECTION_REQUEST , +CCAE_LLP_CLOSE_COMPLETE , +CCAE_TERMINATE_MESSAGE_RECEIVED , +CCAE_LLP_CONNECTION_RESET , +CCAE_LLP_CONNECTION_LOST , +CCAE_LLP_SEGMENT_SIZE_INVALID , +CCAE_LLP_INVALID_CRC , +CCAE_LLP_BAD_FPDU , +CCAE_INVALID_DDP_VERSION , +CCAE_INVALID_RDMA_VERSION , +CCAE_UNEXPECTED_OPCODE , +CCAE_INVALID_DDP_QUEUE_NUMBER , +CCAE_RDMA_READ_NOT_ENABLED , +CCAE_RDMA_WRITE_NOT_ENABLED , +CCAE_RDMA_READ_TOO_SMALL , +CCAE_NO_L_BIT , +CCAE_TAGGED_INVALID_STAG , +CCAE_TAGGED_BASE_BOUNDS_VIOLATION , +CCAE_TAGGED_ACCESS_RIGHTS_VIOLATION , +CCAE_TAGGED_INVALID_PD , +CCAE_WRAP_ERROR , +CCAE_BAD_CLOSE , +CCAE_BAD_LLP_CLOSE , +CCAE_INVALID_MSN_RANGE , +CCAE_INVALID_MSN_GAP , +CCAE_IRRQ_OVERFLOW , +CCAE_IRRQ_MSN_GAP , +CCAE_IRRQ_MSN_RANGE , +CCAE_IRRQ_INVALID_STAG , +CCAE_IRRQ_BASE_BOUNDS_VIOLATION , +CCAE_IRRQ_ACCESS_RIGHTS_VIOLATION , +CCAE_IRRQ_INVALID_PD , +CCAE_IRRQ_WRAP_ERROR , +CCAE_CQ_SQ_COMPLETION_OVERFLOW , +CCAE_CQ_RQ_COMPLETION_ERROR , +CCAE_QP_SRQ_WQE_ERROR , +CCAE_QP_LOCAL_CATASTROPHIC_ERROR , +CCAE_CQ_OVERFLOW , +CCAE_CQ_OPERATION_ERROR , +CCAE_SRQ_LIMIT_REACHED , +CCAE_QP_RQ_LIMIT_REACHED , +CCAE_SRQ_CATASTROPHIC_ERROR , +CCAE_RNIC_CATASTROPHIC_ERROR +/* WARNING If you add more id's, make sure their values fit in eight bits. */ +}; + +/* +* Resource Indicators and Identifiers +*/ +enum c2_resource_indicator { +C2_RES_IND_QP =1 , +C2_RES_IND_EP , +C2_RES_IND_CQ , +C2_RES_IND_SRQ , +}; + +#endif /* _C2_AE_H_ */
drivers/infiniband/hw/amso1100/c2_status.h new file +158 -0
158 lines not on this page · raw message
drivers/infiniband/hw/amso1100/c2_wr.h new file +1520 -0
1,520 lines not on this page · raw message
PATCH v4 3/7 AMSO1100 OpenFabrics Provider.
In reply to Steve Wise---
drivers/infiniband/hw/amso1100/c2_cm.c | 452 ++++++++++++ drivers/infiniband/hw/amso1100/c2_cq.c | 433 ++++++++++++ drivers/infiniband/hw/amso1100/c2_pd.c | 89 ++ drivers/infiniband/hw/amso1100/c2_provider.c | 869 +++++++++++++++++++++++ drivers/infiniband/hw/amso1100/c2_provider.h | 181 +++++ drivers/infiniband/hw/amso1100/c2_qp.c | 975 ++++++++++++++++++++++++++ drivers/infiniband/hw/amso1100/c2_user.h | 82 ++ 7 files changed, 3081 insertions(+), 0 deletions(-)
drivers/infiniband/hw/amso1100/c2_cm.c new file +452 -0
@@ -0,0 +1,452 @@ +/* +* Copyright (c) 2005 Ammasso, Inc. All rights reserved. +* Copyright (c) 2005 Open Grid Computing, 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 "c2.h" +#include "c2_wr.h" +#include "c2_vq.h" +#include <rdma/iw_cm.h> + +int c2_llp_connect (struct iw_cm_id *cm_id,struct iw_cm_conn_param *iw_param) +{ +struct c2_dev *c2dev =to_c2dev (cm_id->device); +struct ib_qp *ibqp; +struct c2_qp *qp; +struct c2wr_qp_connect_req *wr;/* variable size needs a malloc. */ +struct c2_vq_req *vq_req; +int err; + + ibqp =c2_get_qp (cm_id->device, iw_param->qpn); +if (!ibqp) +return -EINVAL ; + qp =to_c2qp (ibqp); + +/* Associate QP <--> CM_ID */ + cm_id->provider_data = qp; + cm_id->add_ref (cm_id); + qp->cm_id = cm_id; + +/* +* only support the max private_data length +*/ +if (iw_param->private_data_len >C2_MAX_PRIVATE_DATA_SIZE ) { + err = -EINVAL ; + goto bail0; + } +/* +* Set the rdma read limits +*/ + err =c2_qp_set_read_limits (c2dev, qp, iw_param->ord, iw_param->ird); +if (err) + goto bail0; + +/* +* Create and send a WR_QP_CONNECT... +*/ + wr =kmalloc (c2dev->req_vq.msg_size,GFP_KERNEL ); +if (!wr) { + err = -ENOMEM ; + goto bail0; + } + + vq_req =vq_req_alloc (c2dev); +if (!vq_req) { + err = -ENOMEM ; + goto bail1; + } + +c2_wr_set_id (wr,CCWR_QP_CONNECT ); + wr->hdr.context =0 ; + wr->rnic_handle = c2dev->adapter_handle; + wr->qp_handle = qp->adapter_handle; + + wr->remote_addr = cm_id->remote_addr.sin_addr.s_addr; + wr->remote_port = cm_id->remote_addr.sin_port; + +/* +* Move any private data from the callers's buf into +* the WR. +*/ +if (iw_param->private_data) { + wr->private_data_length = +cpu_to_be32 (iw_param->private_data_len); +memcpy (&wr->private_data[0 ], iw_param->private_data, + iw_param->private_data_len); + }else + wr->private_data_length =0 ; + +/* +* Send WR to adapter. NOTE: There is no synch reply from +* the adapter. +*/ + err =vq_send_wr (c2dev, (union c2wr *) wr); +vq_req_free (c2dev, vq_req); + + bail1: +kfree (wr); + bail0: +if (err) { +/* +* If we fail, release reference on QP and +* disassociate QP from CM_ID +*/ + cm_id->provider_data =NULL ; + qp->cm_id =NULL ; + cm_id->rem_ref (cm_id); + } +return err; +} + +int c2_llp_service_create (struct iw_cm_id *cm_id,int backlog) +{ +struct c2_dev *c2dev; +struct c2wr_ep_listen_create_req wr; +struct c2wr_ep_listen_create_rep *reply; +struct c2_vq_req *vq_req; +int err; + + c2dev =to_c2dev (cm_id->device); +if (c2dev ==NULL ) +return -EINVAL ; + +/* +* Allocate verbs request. +*/ + vq_req =vq_req_alloc (c2dev); +if (!vq_req) +return -ENOMEM ; + +/* +* Build the WR +*/ +c2_wr_set_id (&wr,CCWR_EP_LISTEN_CREATE ); + wr.hdr.context = (u64 ) (unsigned long ) vq_req; + wr.rnic_handle = c2dev->adapter_handle; + wr.local_addr = cm_id->local_addr.sin_addr.s_addr; + wr.local_port = cm_id->local_addr.sin_port; + wr.backlog =cpu_to_be32 (backlog); + wr.user_context = (u64 ) (unsigned long ) cm_id; + +/* +* Reference the request struct. Dereferenced in the int handler. +*/ +vq_req_get (c2dev, vq_req); + +/* +* Send WR to adapter +*/ + err =vq_send_wr (c2dev, (union c2wr *) & wr); +if (err) { +vq_req_put (c2dev, vq_req); + goto bail0; + } + +/* +* Wait for reply from adapter +*/ + err =vq_wait_for_reply (c2dev, vq_req); +if (err) + goto bail0; + +/* +* Process reply +*/ + reply = + (struct c2wr_ep_listen_create_rep *) (unsigned long ) vq_req->reply_msg; +if (!reply) { + err = -ENOMEM ; + goto bail1; + } + +if ((err =c2_errno (reply)) !=0 ) + goto bail1; + +/* +* Keep the adapter handle. Used in subsequent destroy +*/ + cm_id->provider_data = (void *)(unsigned long ) reply->ep_handle; + +/* +* free vq stuff +*/ +vq_repbuf_free (c2dev, reply); +vq_req_free (c2dev, vq_req); + +return 0 ; + + bail1: +vq_repbuf_free (c2dev, reply); + bail0: +vq_req_free (c2dev, vq_req); +return err; +} + + +int c2_llp_service_destroy (struct iw_cm_id *cm_id) +{ + +struct c2_dev *c2dev; +struct c2wr_ep_listen_destroy_req wr; +struct c2wr_ep_listen_destroy_rep *reply; +struct c2_vq_req *vq_req; +int err; + + c2dev =to_c2dev (cm_id->device); +if (c2dev ==NULL ) +return -EINVAL ; + +/* +* Allocate verbs request. +*/ + vq_req =vq_req_alloc (c2dev); +if (!vq_req) +return -ENOMEM ; + +/* +* Build the WR +*/ +c2_wr_set_id (&wr,CCWR_EP_LISTEN_DESTROY ); + wr.hdr.context = (unsigned long ) vq_req; + wr.rnic_handle = c2dev->adapter_handle; + wr.ep_handle = (u32 )(unsigned long )cm_id->provider_data; + +/* +* reference the request struct. dereferenced in the int handler. +*/ +vq_req_get (c2dev, vq_req); + +/* +* Send WR to adapter +*/ + err =vq_send_wr (c2dev, (union c2wr *) & wr); +if (err) { +vq_req_put (c2dev, vq_req); + goto bail0; + } + +/* +* Wait for reply from adapter +*/ + err =vq_wait_for_reply (c2dev, vq_req); +if (err) + goto bail0; + +/* +* Process reply +*/ + reply=(struct c2wr_ep_listen_destroy_rep *)(unsigned long )vq_req->reply_msg; +if (!reply) { + err = -ENOMEM ; + goto bail0; + } +if ((err =c2_errno (reply)) !=0 ) + goto bail1; + + bail1: +vq_repbuf_free (c2dev, reply); + bail0: +vq_req_free (c2dev, vq_req); +return err; +} + +int c2_llp_accept (struct iw_cm_id *cm_id,struct iw_cm_conn_param *iw_param) +{ +struct c2_dev *c2dev =to_c2dev (cm_id->device); +struct c2_qp *qp; +struct ib_qp *ibqp; +struct c2wr_cr_accept_req *wr;/* variable length WR */ +struct c2_vq_req *vq_req; +struct c2wr_cr_accept_rep *reply;/* VQ Reply msg ptr. */ +int err; + + ibqp =c2_get_qp (cm_id->device, iw_param->qpn); +if (!ibqp) +return -EINVAL ; + qp =to_c2qp (ibqp); + +/* Set the RDMA read limits */ + err =c2_qp_set_read_limits (c2dev, qp, iw_param->ord, iw_param->ird); +if (err) + goto bail0; + +/* Allocate verbs request. */ + vq_req =vq_req_alloc (c2dev); +if (!vq_req) { + err = -ENOMEM ; + goto bail1; + } + vq_req->qp = qp; + vq_req->cm_id = cm_id; + vq_req->event =IW_CM_EVENT_ESTABLISHED ; + + wr =kmalloc (c2dev->req_vq.msg_size,GFP_KERNEL ); +if (!wr) { + err = -ENOMEM ; + goto bail2; + } + +/* Build the WR */ +c2_wr_set_id (wr,CCWR_CR_ACCEPT ); + wr->hdr.context = (unsigned long ) vq_req; + wr->rnic_handle = c2dev->adapter_handle; + wr->ep_handle = (u32 ) (unsigned long ) cm_id->provider_data; + wr->qp_handle = qp->adapter_handle; + +/* Replace the cr_handle with the QP after accept */ + cm_id->provider_data = qp; + cm_id->add_ref (cm_id); + qp->cm_id = cm_id; + + cm_id->provider_data = qp; + +/* Validate private_data length */ +if (iw_param->private_data_len >C2_MAX_PRIVATE_DATA_SIZE ) { + err = -EINVAL ; + goto bail2; + } + +if (iw_param->private_data) { + wr->private_data_length =cpu_to_be32 (iw_param->private_data_len); +memcpy (&wr->private_data[0 ], + iw_param->private_data, iw_param->private_data_len); + }else + wr->private_data_length =0 ; + +/* Reference the request struct. Dereferenced in the int handler. */ +vq_req_get (c2dev, vq_req); + +/* Send WR to adapter */ + err =vq_send_wr (c2dev, (union c2wr *) wr); +if (err) { +vq_req_put (c2dev, vq_req); + goto bail2; + } + +/* Wait for reply from adapter */ + err =vq_wait_for_reply (c2dev, vq_req); +if (err) + goto bail2; + +/* Check that reply is present */ + reply = (struct c2wr_cr_accept_rep *) (unsigned long ) vq_req->reply_msg; +if (!reply) { + err = -ENOMEM ; + goto bail2; + } + + err =c2_errno (reply); +vq_repbuf_free (c2dev, reply); + +if (!err) +c2_set_qp_state (qp,C2_QP_STATE_RTS ); + bail2: +kfree (wr); + bail1: +vq_req_free (c2dev, vq_req); + bail0: +if (err) { +/* +* If we fail, release reference on QP and +* disassociate QP from CM_ID +*/ + cm_id->provider_data =NULL ; + qp->cm_id =NULL ; + cm_id->rem_ref (cm_id); + } +return err; +} + +int c2_llp_reject (struct iw_cm_id *cm_id,const void *pdata,u8 pdata_len) +{ +struct c2_dev *c2dev; +struct c2wr_cr_reject_req wr; +struct c2_vq_req *vq_req; +struct c2wr_cr_reject_rep *reply; +int err; + + c2dev =to_c2dev (cm_id->device); + +/* +* Allocate verbs request. +*/ + vq_req =vq_req_alloc (c2dev); +if (!vq_req) +return -ENOMEM ; + +/* +* Build the WR +*/ +c2_wr_set_id (&wr,CCWR_CR_REJECT ); + wr.hdr.context = (unsigned long ) vq_req; + wr.rnic_handle = c2dev->adapter_handle; + wr.ep_handle = (u32 ) (unsigned long ) cm_id->provider_data; + +/* +* reference the request struct. dereferenced in the int handler. +*/ +vq_req_get (c2dev, vq_req); + +/* +* Send WR to adapter +*/ + err =vq_send_wr (c2dev, (union c2wr *) & wr); +if (err) { +vq_req_put (c2dev, vq_req); + goto bail0; + } + +/* +* Wait for reply from adapter +*/ + err =vq_wait_for_reply (c2dev, vq_req); +if (err) + goto bail0; + +/* +* Process reply +*/ + reply = (struct c2wr_cr_reject_rep *) (unsigned long ) + vq_req->reply_msg; +if (!reply) { + err = -ENOMEM ; + goto bail0; + } + err =c2_errno (reply); +/* +* free vq stuff +*/ +vq_repbuf_free (c2dev, reply); + + bail0: +vq_req_free (c2dev, vq_req); +return err; +}
drivers/infiniband/hw/amso1100/c2_cq.c new file +433 -0
433 lines not on this page · raw message
drivers/infiniband/hw/amso1100/c2_pd.c new file +89 -0
89 lines not on this page · raw message
drivers/infiniband/hw/amso1100/c2_provider.c new file +869 -0
869 lines not on this page · raw message
drivers/infiniband/hw/amso1100/c2_provider.h new file +181 -0
181 lines not on this page · raw message
drivers/infiniband/hw/amso1100/c2_qp.c new file +975 -0
975 lines not on this page · raw message
drivers/infiniband/hw/amso1100/c2_user.h new file +82 -0
1 line not on this page · raw message
The rest of this diff is not shown. View the raw message.
Part of the diff is not shown here. View the raw message.
PATCH v4 4/7 AMSO1100 Memory Management.
In reply to Steve Wise---
drivers/infiniband/hw/amso1100/c2_alloc.c | 144 +++++++++++ drivers/infiniband/hw/amso1100/c2_mm.c | 375 +++++++++++++++++++++++++++++ 2 files changed, 519 insertions(+), 0 deletions(-)
drivers/infiniband/hw/amso1100/c2_alloc.c new file +144 -0
@@ -0,0 +1,144 @@ +/* +* Copyright (c) 2004 Topspin Communications. All rights reserved. +* Copyright (c) 2005 Open Grid Computing, 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/errno.h> +#include <linux/slab.h> +#include <linux/bitmap.h> + +#include "c2.h" + +static int c2_alloc_mqsp_chunk (struct c2_dev *c2dev,gfp_t gfp_mask, +struct sp_chunk **head) +{ +int i; +struct sp_chunk *new_head; + + new_head = (struct sp_chunk *)__get_free_page (gfp_mask); +if (new_head ==NULL ) +return -ENOMEM ; + + new_head->dma_addr =dma_map_single (c2dev->ibdev.dma_device, new_head, +PAGE_SIZE ,DMA_FROM_DEVICE ); +pci_unmap_addr_set (new_head, mapping, new_head->dma_addr); + + new_head->next =NULL ; + new_head->head =0 ; + +/* build list where each index is the next free slot */ +for (i =0 ; + i < (PAGE_SIZE -sizeof (struct sp_chunk ) - +sizeof (u16)) /sizeof (u16) -1 ; + i++) { + new_head->shared_ptr[i] = i +1 ; + } +/* terminate list */ + new_head->shared_ptr[i] =0xFFFF ; + + *head = new_head; +return 0 ; +} + +int c2_init_mqsp_pool (struct c2_dev *c2dev,gfp_t gfp_mask, +struct sp_chunk **root) +{ +return c2_alloc_mqsp_chunk (c2dev, gfp_mask, root); +} + +void c2_free_mqsp_pool (struct c2_dev *c2dev,struct sp_chunk *root) +{ +struct sp_chunk *next; + +while (root) { + next = root->next; +dma_unmap_single (c2dev->ibdev.dma_device, +pci_unmap_addr (root, mapping),PAGE_SIZE , +DMA_FROM_DEVICE ); +__free_page ((struct page *) root); + root = next; + } +} + +u16 *c2_alloc_mqsp (struct c2_dev *c2dev,struct sp_chunk *head, +dma_addr_t *dma_addr,gfp_t gfp_mask) +{ +u16 mqsp; + +while (head) { + mqsp = head->head; +if (mqsp !=0xFFFF ) { + head->head = head->shared_ptr[mqsp]; +break ; + }else if (head->next ==NULL ) { +if (c2_alloc_mqsp_chunk (c2dev, gfp_mask, &head->next) == +0 ) { + head = head->next; + mqsp = head->head; + head->head = head->shared_ptr[mqsp]; +break ; + }else +return NULL ; + }else + head = head->next; + } +if (head) { + *dma_addr = head->dma_addr + + ((unsigned long ) &(head->shared_ptr[mqsp]) - + (unsigned long ) head); +pr_debug ("%s addr %p dma_addr %llx\n" , __FUNCTION__, + &(head->shared_ptr[mqsp]), (u64)*dma_addr); +return &(head->shared_ptr[mqsp]); + } +return NULL ; +} + +void c2_free_mqsp (u16 * mqsp) +{ +struct sp_chunk *head; +u16 idx; + +/* The chunk containing this ptr begins at the page boundary */ + head = (struct sp_chunk *) ((unsigned long ) mqsp &PAGE_MASK ); + +/* Link head to new mqsp */ + *mqsp = head->head; + +/* Compute the shared_ptr index */ + idx = ((unsigned long ) mqsp & ~PAGE_MASK ) >>1 ; + idx -= (unsigned long ) &(((struct sp_chunk *)0 )->shared_ptr[0 ]) >>1 ; + +/* Point this index at the head */ + head->shared_ptr[idx] = head->head; + +/* Point head at this index */ + head->head = idx; +}
drivers/infiniband/hw/amso1100/c2_mm.c new file +375 -0
375 lines not on this page · raw message
PATCH v4 5/7 AMSO1100 Message Queues.
In reply to Steve Wise---
drivers/infiniband/hw/amso1100/c2_mq.c | 175 ++++++++++++++++++++++++++++++++ drivers/infiniband/hw/amso1100/c2_mq.h | 107 ++++++++++++++++++++ 2 files changed, 282 insertions(+), 0 deletions(-)
drivers/infiniband/hw/amso1100/c2_mq.c new file +175 -0
@@ -0,0 +1,175 @@ +/* +* Copyright (c) 2005 Ammasso, Inc. All rights reserved. +* Copyright (c) 2005 Open Grid Computing, 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 "c2.h" +#include "c2_mq.h" + +void *c2_mq_alloc (struct c2_mq *q) +{ +BUG_ON (q->magic !=C2_MQ_MAGIC ); +BUG_ON (q->type !=C2_MQ_ADAPTER_TARGET ); + +if (c2_mq_full (q)) { +return NULL ; + }else { +#ifdef DEBUG +struct c2wr_hdr *m = + (struct c2wr_hdr *) (q->msg_pool.host + q->priv * q->msg_size); +#ifdef CCMSGMAGIC +BUG_ON (m->magic !=be32_to_cpu (~CCWR_MAGIC )); + m->magic =cpu_to_be32 (CCWR_MAGIC ); +#endif +return m; +#else +return q->msg_pool.host + q->priv * q->msg_size; +#endif + } +} + +void c2_mq_produce (struct c2_mq *q) +{ +BUG_ON (q->magic !=C2_MQ_MAGIC ); +BUG_ON (q->type !=C2_MQ_ADAPTER_TARGET ); + +if (!c2_mq_full (q)) { + q->priv = (q->priv +1 ) % q->q_size; + q->hint_count++; +/* Update peer's offset. */ +__raw_writew (cpu_to_be16 (q->priv), &q->peer->shared); + } +} + +void *c2_mq_consume (struct c2_mq *q) +{ +BUG_ON (q->magic !=C2_MQ_MAGIC ); +BUG_ON (q->type !=C2_MQ_HOST_TARGET ); + +if (c2_mq_empty (q)) { +return NULL ; + }else { +#ifdef DEBUG +struct c2wr_hdr *m = (struct c2wr_hdr *) + (q->msg_pool.host + q->priv * q->msg_size); +#ifdef CCMSGMAGIC +BUG_ON (m->magic !=be32_to_cpu (CCWR_MAGIC )); +#endif +return m; +#else +return q->msg_pool.host + q->priv * q->msg_size; +#endif + } +} + +void c2_mq_free (struct c2_mq *q) +{ +BUG_ON (q->magic !=C2_MQ_MAGIC ); +BUG_ON (q->type !=C2_MQ_HOST_TARGET ); + +if (!c2_mq_empty (q)) { + +#ifdef CCMSGMAGIC + { +struct c2wr_hdr __iomem *m = (struct c2wr_hdr __iomem *) + (q->msg_pool.adapter + q->priv * q->msg_size); +__raw_writel (cpu_to_be32 (~CCWR_MAGIC ), &m->magic); + } +#endif + q->priv = (q->priv +1 ) % q->q_size; +/* Update peer's offset. */ +__raw_writew (cpu_to_be16 (q->priv), &q->peer->shared); + } +} + + +void c2_mq_lconsume (struct c2_mq *q,u32 wqe_count) +{ +BUG_ON (q->magic !=C2_MQ_MAGIC ); +BUG_ON (q->type !=C2_MQ_ADAPTER_TARGET ); + +while (wqe_count--) { +BUG_ON (c2_mq_empty (q)); + *q->shared =cpu_to_be16 ((be16_to_cpu (*q->shared)+1 ) % q->q_size); + } +} + + +u32 c2_mq_count (struct c2_mq *q) +{ +s32 count; + +if (q->type ==C2_MQ_HOST_TARGET ) { + count =be16_to_cpu (*q->shared) - q->priv; + }else { + count = q->priv -be16_to_cpu (*q->shared); + } + +if (count <0 ) { + count += q->q_size; + } + +return (u32 ) count; +} + +void c2_mq_req_init (struct c2_mq *q,u32 index,u32 q_size,u32 msg_size, +u8 __iomem *pool_start,u16 __iomem *peer,u32 type) +{ +BUG_ON (!q->shared); + +/* This code assumes the byte swapping has already been done! */ + q->index = index; + q->q_size = q_size; + q->msg_size = msg_size; + q->msg_pool.adapter = pool_start; + q->peer = (struct c2_mq_shared __iomem *) peer; + q->magic =C2_MQ_MAGIC ; + q->type = type; + q->priv =0 ; + q->hint_count =0 ; +return ; +} +void c2_mq_rep_init (struct c2_mq *q,u32 index,u32 q_size,u32 msg_size, +u8 *pool_start,u16 __iomem *peer,u32 type) +{ +BUG_ON (!q->shared); + +/* This code assumes the byte swapping has already been done! */ + q->index = index; + q->q_size = q_size; + q->msg_size = msg_size; + q->msg_pool.host = pool_start; + q->peer = (struct c2_mq_shared __iomem *) peer; + q->magic =C2_MQ_MAGIC ; + q->type = type; + q->priv =0 ; + q->hint_count =0 ; +return ; +}
drivers/infiniband/hw/amso1100/c2_mq.h new file +107 -0
107 lines not on this page · raw message
PATCH v4 6/7 AMSO1100: Privileged Verbs Queues.
In reply to Steve Wise---
drivers/infiniband/hw/amso1100/c2_vq.c | 260 ++++++++++++++++++++++++++++++++ drivers/infiniband/hw/amso1100/c2_vq.h | 63 ++++++++ 2 files changed, 323 insertions(+), 0 deletions(-)
drivers/infiniband/hw/amso1100/c2_vq.c new file +260 -0
@@ -0,0 +1,260 @@ +/* +* Copyright (c) 2005 Ammasso, Inc. All rights reserved. +* Copyright (c) 2005 Open Grid Computing, 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/slab.h> +#include <linux/spinlock.h> + +#include "c2_vq.h" +#include "c2_provider.h" + +/* +* Verbs Request Objects: +* +* VQ Request Objects are allocated by the kernel verbs handlers. +* They contain a wait object, a refcnt, an atomic bool indicating that the +* adapter has replied, and a copy of the verb reply work request. +* A pointer to the VQ Request Object is passed down in the context +* field of the work request message, and reflected back by the adapter +* in the verbs reply message. The function handle_vq() in the interrupt +* path will use this pointer to: +* 1) append a copy of the verbs reply message +* 2) mark that the reply is ready +* 3) wake up the kernel verbs handler blocked awaiting the reply. +* +* +* The kernel verbs handlers do a "get" to put a 2nd reference on the +* VQ Request object. If the kernel verbs handler exits before the adapter +* can respond, this extra reference will keep the VQ Request object around +* until the adapter's reply can be processed. The reason we need this is +* because a pointer to this object is stuffed into the context field of +* the verbs work request message, and reflected back in the reply message. +* It is used in the interrupt handler (handle_vq()) to wake up the appropriate +* kernel verb handler that is blocked awaiting the verb reply. +* So handle_vq() will do a "put" on the object when it's done accessing it. +* NOTE: If we guarantee that the kernel verb handler will never bail before +* getting the reply, then we don't need these refcnts. +* +* +* VQ Request objects are freed by the kernel verbs handlers only +* after the verb has been processed, or when the adapter fails and +* does not reply. +* +* +* Verbs Reply Buffers: +* +* VQ Reply bufs are local host memory copies of a +* outstanding Verb Request reply +* message. The are always allocated by the kernel verbs handlers, and _may_ be +* freed by either the kernel verbs handler -or- the interrupt handler. The +* kernel verbs handler _must_ free the repbuf, then free the vq request object +* in that order. +*/ + +int vq_init (struct c2_dev *c2dev) +{ +sprintf (c2dev->vq_cache_name,"c2-vq:dev%c" , + (char ) ('0' + c2dev->devnum)); + c2dev->host_msg_cache = +kmem_cache_create (c2dev->vq_cache_name, c2dev->rep_vq.msg_size,0 , +SLAB_HWCACHE_ALIGN ,NULL ,NULL ); +if (c2dev->host_msg_cache ==NULL ) { +return -ENOMEM ; + } +return 0 ; +} + +void vq_term (struct c2_dev *c2dev) +{ +kmem_cache_destroy (c2dev->host_msg_cache); +} + +/* vq_req_alloc - allocate a VQ Request Object and initialize it. +* The refcnt is set to 1. +*/ +struct c2_vq_req *vq_req_alloc (struct c2_dev *c2dev) +{ +struct c2_vq_req *r; + + r =kmalloc (sizeof (struct c2_vq_req ),GFP_KERNEL ); +if (r) { +init_waitqueue_head (&r->wait_object); + r->reply_msg = (u64 )NULL ; + r->event =0 ; + r->cm_id =NULL ; + r->qp =NULL ; +atomic_set (&r->refcnt,1 ); +atomic_set (&r->reply_ready,0 ); + } +return r; +} + + +/* vq_req_free - free the VQ Request Object. It is assumed the verbs handler +* has already free the VQ Reply Buffer if it existed. +*/ +void vq_req_free (struct c2_dev *c2dev,struct c2_vq_req *r) +{ + r->reply_msg = (u64 )NULL ; +if (atomic_dec_and_test (&r->refcnt)) { +kfree (r); + } +} + +/* vq_req_get - reference a VQ Request Object. Done +* only in the kernel verbs handlers. +*/ +void vq_req_get (struct c2_dev *c2dev,struct c2_vq_req *r) +{ +atomic_inc (&r->refcnt); +} + + +/* vq_req_put - dereference and potentially free a VQ Request Object. +* +* This is only called by handle_vq() on the +* interrupt when it is done processing +* a verb reply message. If the associated +* kernel verbs handler has already bailed, +* then this put will actually free the VQ +* Request object _and_ the VQ Reply Buffer +* if it exists. +*/ +void vq_req_put (struct c2_dev *c2dev,struct c2_vq_req *r) +{ +if (atomic_dec_and_test (&r->refcnt)) { +if (r->reply_msg != (u64 )NULL ) +vq_repbuf_free (c2dev, + (void *) (unsigned long ) r->reply_msg); +kfree (r); + } +} + + +/* +* vq_repbuf_alloc - allocate a VQ Reply Buffer. +*/ +void *vq_repbuf_alloc (struct c2_dev *c2dev) +{ +return kmem_cache_alloc (c2dev->host_msg_cache,SLAB_ATOMIC ); +} + +/* +* vq_send_wr - post a verbs request message to the Verbs Request Queue. +* If a message is not available in the MQ, then block until one is available. +* NOTE: handle_mq() on the interrupt context will wake up threads blocked here. +* When the adapter drains the Verbs Request Queue, +* it inserts MQ index 0 in to the +* adapter->host activity fifo and interrupts the host. +*/ +int vq_send_wr (struct c2_dev *c2dev,union c2wr *wr) +{ +void *msg; +wait_queue_t __wait; + +/* +* grab adapter vq lock +*/ +spin_lock (&c2dev->vqlock); + +/* +* allocate msg +*/ + msg =c2_mq_alloc (&c2dev->req_vq); + +/* +* If we cannot get a msg, then we'll wait +* When a messages are available, the int handler will wake_up() +* any waiters. +*/ +while (msg ==NULL ) { +pr_debug ("%s:%d no available msg in VQ, waiting...\n" , + __FUNCTION__, __LINE__); +init_waitqueue_entry (&__wait, current); +add_wait_queue (&c2dev->req_vq_wo, &__wait); +spin_unlock (&c2dev->vqlock); +for (;;) { +set_current_state (TASK_INTERRUPTIBLE ); +if (!c2_mq_full (&c2dev->req_vq)) { +break ; + } +if (!signal_pending (current)) { +schedule_timeout (1 *HZ );/* 1 second... */ +continue ; + } +set_current_state (TASK_RUNNING ); +remove_wait_queue (&c2dev->req_vq_wo, &__wait); +return -EINTR ; + } +set_current_state (TASK_RUNNING ); +remove_wait_queue (&c2dev->req_vq_wo, &__wait); +spin_lock (&c2dev->vqlock); + msg =c2_mq_alloc (&c2dev->req_vq); + } + +/* +* copy wr into adapter msg +*/ +memcpy (msg, wr, c2dev->req_vq.msg_size); + +/* +* post msg +*/ +c2_mq_produce (&c2dev->req_vq); + +/* +* release adapter vq lock +*/ +spin_unlock (&c2dev->vqlock); +return 0 ; +} + + +/* +* vq_wait_for_reply - block until the adapter posts a Verb Reply Message. +*/ +int vq_wait_for_reply (struct c2_dev *c2dev,struct c2_vq_req *req) +{ +if (!wait_event_timeout (req->wait_object, +atomic_read (&req->reply_ready), +60 *HZ )) +return -ETIMEDOUT ; + +return 0 ; +} + +/* +* vq_repbuf_free - Free a Verbs Reply Buffer. +*/ +void vq_repbuf_free (struct c2_dev *c2dev,void *reply) +{ +kmem_cache_free (c2dev->host_msg_cache, reply); +}
drivers/infiniband/hw/amso1100/c2_vq.h new file +63 -0
63 lines not on this page · raw message
PATCH v4 7/7 AMSO1100 Makefiles and Kconfig changes.
In reply to Steve Wise---
drivers/infiniband/Kconfig | 1 + drivers/infiniband/Makefile | 1 + drivers/infiniband/hw/amso1100/Kbuild | 10 ++++++++++ drivers/infiniband/hw/amso1100/Kconfig | 15 +++++++++++++++ drivers/infiniband/hw/amso1100/README | 11 +++++++++++ 5 files changed, 38 insertions(+), 0 deletions(-)
drivers/infiniband/Kconfig +1 -0
@@ -36,6 +36,7 @@ config INFINIBAND_ADDR_TRANS source "drivers/infiniband/hw/mthca/Kconfig" source "drivers/infiniband/hw/ipath/Kconfig" +source "drivers/infiniband/hw/amso1100/Kconfig" source "drivers/infiniband/ulp/ipoib/Kconfig"
drivers/infiniband/Makefile +1 -0
@@ -1,6 +1,7 @@ obj-$(CONFIG_INFINIBAND) += core/ obj-$(CONFIG_INFINIBAND_MTHCA) += hw/mthca/ obj-$(CONFIG_IPATH_CORE) += hw/ipath/ +obj-$(CONFIG_INFINIBAND_AMSO1100) += hw/amso1100/ obj-$(CONFIG_INFINIBAND_IPOIB) += ulp/ipoib/ obj-$(CONFIG_INFINIBAND_SRP) += ulp/srp/ obj-$(CONFIG_INFINIBAND_ISER) += ulp/iser/
drivers/infiniband/hw/amso1100/Kbuild new file +10 -0
@@ -0,0 +1,10 @@ +EXTRA_CFLAGS += -Idrivers/infiniband/include + +ifdef CONFIG_INFINIBAND_AMSO1100_DEBUG +EXTRA_CFLAGS += -DDEBUG +endif + +obj-$(CONFIG_INFINIBAND_AMSO1100) += iw_c2.o + +iw_c2-y := c2.o c2_provider.o c2_rnic.o c2_alloc.o c2_mq.o c2_ae.o c2_vq.o \ + c2_intr.o c2_cq.o c2_qp.o c2_cm.o c2_mm.o c2_pd.o
drivers/infiniband/hw/amso1100/Kconfig new file +15 -0
@@ -0,0 +1,15 @@ +config INFINIBAND_AMSO1100 + tristate "Ammasso 1100 HCA support" + depends on PCI && INET && INFINIBAND + ---help--- + This is a low-level driver for the Ammasso 1100 host + channel adapter (HCA). + +config INFINIBAND_AMSO1100_DEBUG + bool "Verbose debugging output" + depends on INFINIBAND_AMSO1100 + default n + ---help--- + This option causes the amso1100 driver to produce a bunch of + debug messages. Select this if you are developing the driver + or trying to diagnose a problem.
drivers/infiniband/hw/amso1100/README new file +11 -0
@@ -0,0 +1,11 @@ +This is the OpenFabrics provider driver for the +AMSO1100 1Gb RNIC adapter. + +This adapter is available in limited quantities +for development purposes from Open Grid Computing. + +This driver requires the IWCM and CMA mods necessary +to support iWARP. + +Contact [email protected] for more information. +
Re: [PATCH v4 7/7] AMSO1100 Makefiles and Kconfig changes.
I'm finally getting around to merging this up, and:
Quoted 4 lines
drivers/infiniband/hw/amso1100/README new file +1
-0@@ -0,0 +1,11 @@ +This is the OpenFabrics provider driver for the
drivers/infiniband/hw/amso1100/README line 11
Quoted 10 lines
drivers/infiniband/hw/amso1100/README new file +10
-0+AMSO1100 1Gb RNIC adapter. + +This adapter is available in limited quantities +for development purposes from Open Grid Computing. + +This driver requires the IWCM and CMA mods necessary +to support iWARP. + +Contact [email protected] for more information. +
I don't think this belongs in the drivers directory. In fact, is it worth having this in the kernel at all?
How about if I just add a MAINTAINERS entry for amso1100 pointing at [email protected] ?
- R.
Re: [PATCH v4 7/7] AMSO1100 Makefiles and Kconfig changes.
Sounds good to me.
----- Original Message ----- From: "Roland Dreier" <[email protected]>
To: "Steve Wise" <[email protected]>
Cc: <[email protected]>; <[email protected]>
Sent: Monday, August 28, 2006 6:07 PM
Subject: Re: [PATCH v4 7/7] AMSO1100 Makefiles and Kconfig changes.
Quoted 25 lines
I'm finally getting around to merging this up, and:
Quoted 4 lines
drivers/infiniband/hw/amso1100/README new file +1
-0@@ -0,0 +1,11 @@ +This is the OpenFabrics provider driver for thedrivers/infiniband/hw/amso1100/README line 11
Quoted 10 lines
drivers/infiniband/hw/amso1100/README new file +10
-0+AMSO1100 1Gb RNIC adapter. + +This adapter is available in limited quantities +for development purposes from Open Grid Computing. + +This driver requires the IWCM and CMA mods necessary +to support iWARP. + +Contact [email protected] for more information. +I don't think this belongs in the drivers directory. In fact, is it worth having this in the kernel at all?
How about if I just add a
MAINTAINERSentry for amso1100 pointing at [email protected] ?- R.