svn commit: r216910 - in projects/ofed/base/sys/ofed/drivers/infiniband/hw: cxgb3 nes

Jeff Roberson jeff at FreeBSD.org
Mon Jan 3 05:36:16 UTC 2011


Author: jeff
Date: Mon Jan  3 05:36:16 2011
New Revision: 216910
URL: http://svn.freebsd.org/changeset/base/216910

Log:
   - Add files missing from the last merge.
  
  Sponsored by:	Isilon Systems, iX Systems, and Panasas.

Added:
  projects/ofed/base/sys/ofed/drivers/infiniband/hw/cxgb3/genalloc.c
  projects/ofed/base/sys/ofed/drivers/infiniband/hw/nes/nes_ud.c
  projects/ofed/base/sys/ofed/drivers/infiniband/hw/nes/nes_ud.h

Added: projects/ofed/base/sys/ofed/drivers/infiniband/hw/cxgb3/genalloc.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/ofed/base/sys/ofed/drivers/infiniband/hw/cxgb3/genalloc.c	Mon Jan  3 05:36:16 2011	(r216910)
@@ -0,0 +1,209 @@
+/*
+ * Basic general purpose allocator for managing special purpose memory
+ * not managed by the regular kmalloc/kfree interface.
+ * Uses for this includes on-device special memory, uncached memory
+ * etc.
+ *
+ * Copyright 2005 (C) Jes Sorensen <jes at trained-monkey.org>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2.  See the file COPYING for more details.
+ */
+
+/*
+ *  General purpose special memory pool descriptor.
+ */
+struct gen_pool {
+	rwlock_t lock;
+	struct list_head chunks;	/* list of chunks in this pool */
+	int min_alloc_order;		/* minimum allocation order */
+};
+
+/*
+ *  General purpose special memory pool chunk descriptor.
+ */
+struct gen_pool_chunk {
+	spinlock_t lock;
+	struct list_head next_chunk;	/* next chunk in pool */
+	unsigned long start_addr;	/* starting address of memory chunk */
+	unsigned long end_addr;		/* ending address of memory chunk */
+	unsigned long bits[0];		/* bitmap for allocating memory chunk */
+};
+
+/**
+ * gen_pool_create - create a new special memory pool
+ * @min_alloc_order: log base 2 of number of bytes each bitmap bit represents
+ * @nid: node id of the node the pool structure should be allocated on, or -1
+ *
+ * Create a new special memory pool that can be used to manage special purpose
+ * memory not managed by the regular kmalloc/kfree interface.
+ */
+static struct gen_pool *gen_pool_create(int min_alloc_order, int nid)
+{
+	struct gen_pool *pool;
+
+	pool = kmalloc_node(sizeof(struct gen_pool), GFP_KERNEL, nid);
+	if (pool != NULL) {
+		rwlock_init(&pool->lock);
+		INIT_LIST_HEAD(&pool->chunks);
+		pool->min_alloc_order = min_alloc_order;
+	}
+	return pool;
+}
+
+/**
+ * gen_pool_add - add a new chunk of special memory to the pool
+ * @pool: pool to add new memory chunk to
+ * @addr: starting address of memory chunk to add to pool
+ * @size: size in bytes of the memory chunk to add to pool
+ * @nid: node id of the node the chunk structure and bitmap should be
+ *       allocated on, or -1
+ *
+ * Add a new chunk of special memory to the specified pool.
+ */
+static int gen_pool_add(struct gen_pool *pool, unsigned long addr, size_t size,
+		 int nid)
+{
+	struct gen_pool_chunk *chunk;
+	int nbits = size >> pool->min_alloc_order;
+	int nbytes = sizeof(struct gen_pool_chunk) +
+				(nbits + BITS_PER_BYTE - 1) / BITS_PER_BYTE;
+
+	chunk = kmalloc_node(nbytes, GFP_KERNEL, nid);
+	if (unlikely(chunk == NULL))
+		return -1;
+
+	memset(chunk, 0, nbytes);
+	spin_lock_init(&chunk->lock);
+	chunk->start_addr = addr;
+	chunk->end_addr = addr + size;
+
+	write_lock(&pool->lock);
+	list_add(&chunk->next_chunk, &pool->chunks);
+	write_unlock(&pool->lock);
+
+	return 0;
+}
+
+/**
+ * gen_pool_destroy - destroy a special memory pool
+ * @pool: pool to destroy
+ *
+ * Destroy the specified special memory pool. Verifies that there are no
+ * outstanding allocations.
+ */
+static void gen_pool_destroy(struct gen_pool *pool)
+{
+	struct list_head *_chunk, *_next_chunk;
+	struct gen_pool_chunk *chunk;
+	int order = pool->min_alloc_order;
+	int bit, end_bit;
+
+
+	write_lock(&pool->lock);
+	list_for_each_safe(_chunk, _next_chunk, &pool->chunks) {
+		chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk);
+		list_del(&chunk->next_chunk);
+
+		end_bit = (chunk->end_addr - chunk->start_addr) >> order;
+		bit = find_next_bit(chunk->bits, end_bit, 0);
+		BUG_ON(bit < end_bit);
+
+		kfree(chunk);
+	}
+	kfree(pool);
+	return;
+}
+
+/**
+ * gen_pool_alloc - allocate special memory from the pool
+ * @pool: pool to allocate from
+ * @size: number of bytes to allocate from the pool
+ *
+ * Allocate the requested number of bytes from the specified pool.
+ * Uses a first-fit algorithm.
+ */
+static unsigned long gen_pool_alloc(struct gen_pool *pool, size_t size)
+{
+	struct list_head *_chunk;
+	struct gen_pool_chunk *chunk;
+	unsigned long addr, flags;
+	int order = pool->min_alloc_order;
+	int nbits, bit, start_bit, end_bit;
+
+	if (size == 0)
+		return 0;
+
+	nbits = (size + (1UL << order) - 1) >> order;
+
+	read_lock(&pool->lock);
+	list_for_each(_chunk, &pool->chunks) {
+		chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk);
+
+		end_bit = (chunk->end_addr - chunk->start_addr) >> order;
+		end_bit -= nbits + 1;
+
+		spin_lock_irqsave(&chunk->lock, flags);
+		bit = -1;
+		while (bit + 1 < end_bit) {
+			bit = find_next_zero_bit(chunk->bits, end_bit, bit + 1);
+			if (bit >= end_bit)
+				break;
+
+			start_bit = bit;
+			if (nbits > 1) {
+				bit = find_next_bit(chunk->bits, bit + nbits,
+							bit + 1);
+				if (bit - start_bit < nbits)
+					continue;
+			}
+
+			addr = chunk->start_addr +
+					    ((unsigned long)start_bit << order);
+			while (nbits--)
+				__set_bit(start_bit++, chunk->bits);
+			spin_unlock_irqrestore(&chunk->lock, flags);
+			read_unlock(&pool->lock);
+			return addr;
+		}
+		spin_unlock_irqrestore(&chunk->lock, flags);
+	}
+	read_unlock(&pool->lock);
+	return 0;
+}
+
+/**
+ * gen_pool_free - free allocated special memory back to the pool
+ * @pool: pool to free to
+ * @addr: starting address of memory to free back to pool
+ * @size: size in bytes of memory to free
+ *
+ * Free previously allocated special memory back to the specified pool.
+ */
+static void gen_pool_free(struct gen_pool *pool, unsigned long addr, size_t size)
+{
+	struct list_head *_chunk;
+	struct gen_pool_chunk *chunk;
+	unsigned long flags;
+	int order = pool->min_alloc_order;
+	int bit, nbits;
+
+	nbits = (size + (1UL << order) - 1) >> order;
+
+	read_lock(&pool->lock);
+	list_for_each(_chunk, &pool->chunks) {
+		chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk);
+
+		if (addr >= chunk->start_addr && addr < chunk->end_addr) {
+			BUG_ON(addr + size > chunk->end_addr);
+			spin_lock_irqsave(&chunk->lock, flags);
+			bit = (addr - chunk->start_addr) >> order;
+			while (nbits--)
+				__clear_bit(bit++, chunk->bits);
+			spin_unlock_irqrestore(&chunk->lock, flags);
+			break;
+		}
+	}
+	BUG_ON(nbits > 0);
+	read_unlock(&pool->lock);
+}

Added: projects/ofed/base/sys/ofed/drivers/infiniband/hw/nes/nes_ud.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ projects/ofed/base/sys/ofed/drivers/infiniband/hw/nes/nes_ud.c	Mon Jan  3 05:36:16 2011	(r216910)
@@ -0,0 +1,2174 @@
+/*
+ * Copyright (c) 2009 - 2010 Intel Corporation.  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/version.h>
+#include <linux/vmalloc.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+#include <linux/poll.h>
+#include <linux/idr.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/device.h>
+#include <linux/netdevice.h>
+#include <linux/list.h>
+#include <linux/miscdevice.h>
+#include <linux/device.h>
+
+#include <rdma/ib_umem.h>
+#include <rdma/ib_user_verbs.h>
+
+#include "nes.h"
+#include "nes_ud.h"
+
+#define NES_UD_BASE_XMIT_NIC_QPID  28
+#define NES_UD_BASE_RECV_NIC_IDX   12
+#define NES_UD_BASE_XMIT_NIC_IDX   8
+#define NES_UD_MAX_NIC_CNT 8
+#define NES_UD_CLEANUP_TIMEOUT (HZ)
+#define NES_UD_MCAST_TBL_SZ 128
+#define NES_UD_SINGLE_HDR_SZ 64
+#define NES_UD_CQE_NUM NES_NIC_WQ_SIZE
+#define NES_UD_SKSQ_WAIT_TIMEOUT	100000
+#define NES_UD_MAX_REG_CNT 128
+#define NES_UD_MAX_MCAST_PER_QP 40
+
+#define NES_UD_MAX_ADAPTERS 4 /* number of supported interfaces for  RAW ETH */
+
+#define NES_UD_MAX_REG_HASH_CNT 256 /* last byte of the STAG is hash key */
+
+/*
+ * the same multicast could be allocated up to 2 owners so there could be
+ *  two differentmcast entries allocated for the same mcas address
+ */
+struct nes_ud_file;
+struct nes_ud_mcast {
+	u8 addr[3];
+	u8 in_use;
+	struct nes_ud_file *owner;
+	u8 nic_mask;
+};
+
+struct nes_ud_mem_region {
+	struct list_head list;
+	dma_addr_t *addrs;
+	u64 va;
+	u64 length;
+	u32 pg_cnt;
+	u32 in_use;
+	u32 stag; /* stag related this structure */
+};
+
+struct nic_queue_info {
+	u32 qpn;
+	u32 nic_index;
+	u32 logical_port;
+	enum nes_ud_dev_priority prio;
+	enum nes_ud_queue_type queue_type;
+	struct nes_ud_file *file;
+	struct nes_ud_file file_body;
+};
+
+struct nes_ud_resources {
+	int num_logport_confed;
+	int num_allocated_nics;
+	u8 logport_2_map;
+	u8 logport_3_map;
+	u32 original_6000;
+	u32 original_60b8;
+	struct nic_queue_info nics[NES_UD_MAX_NIC_CNT];
+	struct mutex          mutex;
+	struct nes_ud_mcast mcast[NES_UD_MCAST_TBL_SZ];
+	u32 adapter_no;  /* the allocated adapter no */
+
+	/* the unique ID of the NE020 adapter */
+	/*- it is allocated once per HW */
+	struct nes_adapter *pAdap;
+};
+
+/* memory hash list entry */
+struct nes_ud_hash_mem {
+    struct list_head   list;
+    int                read_stats;
+};
+
+
+
+struct nes_ud_mem {
+	/* hash list of registered STAGs */
+	struct nes_ud_hash_mem mrs[NES_UD_MAX_REG_HASH_CNT];
+	struct mutex          mutex;
+};
+
+/* the QP in format x.y.z where x is adapter no, */
+/* y is ud file idx in adapter, z is a qp no */
+static struct nes_ud_mem ud_mem;
+
+struct nes_ud_send_wr {
+    u32               wr_cnt;
+    u32               qpn;
+    u32               flags;
+    u32               resv[1];
+    struct ib_sge     sg_list[64];
+};
+
+struct nes_ud_recv_wr {
+    u32               wr_cnt;
+    u32               qpn;
+    u32	              resv[2];
+    struct ib_sge     sg_list[64];
+};
+
+static struct nes_ud_resources nes_ud_rsc[NES_UD_MAX_ADAPTERS];
+static struct workqueue_struct *nes_ud_workqueue;
+
+/*
+ * locate_ud_adapter
+ *
+ * the function locates the UD adapter
+*  on base of the adapter unique ID (structure nes_adapter)
+ */
+static inline
+struct nes_ud_resources *locate_ud_adapter(struct nes_adapter *pAdapt)
+{
+	int i;
+	struct nes_ud_resources *pRsc;
+
+	for (i = 0; i < NES_UD_MAX_ADAPTERS; i++) {
+		pRsc = &nes_ud_rsc[i];
+
+		if (pRsc->pAdap == pAdapt)
+			return pRsc;
+
+	}
+	return NULL;
+}
+
+/*
+ * allocate_ud_adapter()
+ *
+ * function allocates a new adapter
+ */
+static inline
+struct nes_ud_resources *allocate_ud_adapter(struct nes_adapter *pAdapt)
+{
+    int i;
+    struct nes_ud_resources *pRsc;
+
+    for (i = 0; i < NES_UD_MAX_ADAPTERS; i++) {
+	pRsc = &nes_ud_rsc[i];
+	if (pRsc->pAdap == NULL) {
+		pRsc->pAdap = pAdapt;
+		nes_debug(NES_DBG_UD, "new UD Adapter allocated %d"
+		" for adapter %p no =%d\n", i, pAdapt, pRsc->adapter_no);
+		return pRsc;
+		}
+	}
+	nes_debug(NES_DBG_UD, "Unable to allocate adapter\n");
+	return NULL;
+}
+
+static inline
+struct nes_ud_file *allocate_nic_queue(struct nes_vnic *nesvnic,
+					enum nes_ud_queue_type queue_type)
+{
+    struct nes_ud_file *file = NULL;
+	int i = 0;
+	u8 select_log_port = 0xf;
+	struct nes_device *nesdev = nesvnic->nesdev;
+	int log_port_2_alloced = 0;
+	int log_port_3_alloced = 0;
+	int ret = 0;
+	struct nes_ud_resources *pRsc;
+
+	/* the first thing that must be done is determine the adapter */
+	/* number max the adapter could have up to 2 interfaces */
+	if (nesvnic->nic_index != 0 && nesvnic->nic_index != 1) {
+		nes_debug(NES_DBG_UD, "nic queue allocation failed"
+		" nesvnic->nic_index = %d\n", nesvnic->nic_index);
+		return NULL;
+	}
+
+	/* locate device on base of nesvnic */
+	/* - when it is an unknown card a new one is allocated */
+	pRsc = locate_ud_adapter(nesdev->nesadapter);
+	if (pRsc == NULL)
+		return NULL;
+
+	for (i = 0; i < NES_UD_MAX_NIC_CNT; i++) {
+		if (pRsc->nics[i].file->active == 0)
+			continue;
+		if (pRsc->nics[i].logical_port == 2 &&
+		    queue_type == pRsc->nics[i].queue_type)
+				log_port_2_alloced++;
+		if (pRsc->nics[i].logical_port == 3 &&
+		    queue_type == pRsc->nics[i].queue_type)
+				log_port_3_alloced++;
+	}
+
+	/* check dual/single card */
+	if (pRsc->logport_2_map != pRsc->logport_3_map) {
+		/* a dual port card */
+		/* allocation is NIC2, NIC2, NIC3, NIC3 */
+		/*- no RX packat replication supported */
+		if (log_port_2_alloced < 2 &&
+		    pRsc->logport_2_map == nesvnic->nic_index)
+				select_log_port = 2;
+		else if (log_port_3_alloced < 2 &&
+			 pRsc->logport_3_map == nesvnic->nic_index)
+				select_log_port = 3;
+	} else {
+		/* single port card */
+		/* change allocation scheme to NIC2,NIC3,NIC2,NIC3 */
+		switch (log_port_2_alloced + log_port_3_alloced) {
+		case 0: /* no QPs allocated - use NIC2 */
+			if (pRsc->logport_2_map == nesvnic->nic_index)
+				select_log_port = 2;
+
+			break;
+		case 1: /* NIC2 or NIC3 allocated */
+			if (log_port_2_alloced > 0) {
+				/* if NIC2 allocated use NIC3 */
+				if (pRsc->logport_3_map == nesvnic->nic_index)
+					select_log_port = 3;
+
+			} else {
+				/* when NIC3 allocated use NIC2 */
+				if (pRsc->logport_2_map == nesvnic->nic_index)
+					select_log_port = 2;
+
+			}
+			break;
+
+		case 2:
+		/* NIC2 and NIC3 allocated or both ports on NIC3 - use NIC2 */
+			if ((log_port_2_alloced == 1) ||
+			    (log_port_3_alloced == 2)) {
+				if (pRsc->logport_2_map == nesvnic->nic_index)
+					select_log_port = 2;
+
+			} else {
+				/* both ports allocated on NIC2 - use NIC3 */
+				if (pRsc->logport_3_map == nesvnic->nic_index)
+					select_log_port = 3;
+
+			}
+				break;
+		case 3:
+			/* when both NIC2 allocated use NIC3 */
+			if (log_port_2_alloced == 2) {
+				if (pRsc->logport_3_map == nesvnic->nic_index)
+					select_log_port = 3;
+
+			} else {
+				/* when both NIC3 alloced use NIC2 */
+				if (pRsc->logport_2_map == nesvnic->nic_index)
+					select_log_port = 2;
+			}
+			break;
+
+		default:
+			break;
+		}
+	}
+	if (select_log_port == 0xf) {
+		ret = -1;
+		nes_debug(NES_DBG_UD, "%s(%d) logport allocation failed "
+		"log_port_2_alloced=%d log_port_3_alloced=%d\n",
+			__func__, __LINE__, log_port_2_alloced,
+			log_port_3_alloced);
+		goto out;
+	}
+
+	nes_debug(NES_DBG_UD, "%s(%d) log_port_2_alloced=%d "
+		"log_port_3_alloced=%d select_log_port=%d\n",
+		__func__, __LINE__, log_port_2_alloced,
+		log_port_3_alloced, select_log_port);
+
+	for (i = 0; i < NES_UD_MAX_NIC_CNT; i++) {
+		if (pRsc->nics[i].file->active == 1)
+			continue;
+		if (pRsc->nics[i].logical_port == select_log_port &&
+		    queue_type == pRsc->nics[i].queue_type) {
+
+			/* file is preallocated during initialization */
+			file = pRsc->nics[i].file;
+			memset(file, 0, sizeof(*file));
+
+			file->nesvnic = nesvnic;
+			file->queue_type = queue_type;
+
+			file->prio = pRsc->nics[i].prio;
+			file->qpn = pRsc->nics[i].qpn;
+			file->nes_ud_nic_index = pRsc->nics[i].nic_index;
+			file->rsc_idx = i;
+			file->adapter_no = pRsc->adapter_no;
+			goto out;
+		}
+	}
+
+out:
+	return file;
+}
+
+static inline int  del_rsc_list(struct nes_ud_file *file)
+{
+	int logport_2_cnt = 0;
+	int logport_3_cnt = 0;
+	struct nes_device *nesdev = file->nesvnic->nesdev;
+	int i = 0;
+	struct nes_ud_resources *pRsc;
+
+	if (file == NULL) {
+		nes_debug(NES_DBG_UD, "%s(%d) file is NULL\n",
+			__func__, __LINE__);
+		return -EFAULT;
+	}
+	if (file->nesvnic == NULL) {
+		nes_debug(NES_DBG_UD, "%s(%d) file->nesvnic is NULL\n",
+			__func__, __LINE__);
+		return -EFAULT;
+	}
+	if (nesdev == NULL) {
+		nes_debug(NES_DBG_UD, "%s(%d) nesdev is NULL\n",
+			__func__, __LINE__);
+		return -EFAULT;
+	}
+
+	/* locate device on base of nesvnic */
+	/*- when it is an unknown card a new one is allocated */
+	pRsc = locate_ud_adapter(nesdev->nesadapter);
+	if (pRsc == NULL) {
+		nes_debug(NES_DBG_UD, "%s(%d) cannot locate an allocated "
+			"adapter  is NULL\n", __func__, __LINE__);
+		return -EFAULT;
+	}
+	if (pRsc->num_allocated_nics == 0)
+		return 0;
+
+	if (--pRsc->num_allocated_nics == 0) {
+		nes_write_indexed(nesdev, 0x60b8, pRsc->original_60b8);
+		nes_write_indexed(nesdev, 0x6000, pRsc->original_6000);
+		pRsc->num_logport_confed = 0;
+	}
+	BUG_ON(file->rsc_idx >= NES_UD_MAX_NIC_CNT);
+
+	for (i = 0; i < NES_UD_MAX_NIC_CNT; i++) {
+		if (pRsc->nics[i].file->active &&
+		    pRsc->nics[i].logical_port == 2)
+			logport_2_cnt++;
+		if (pRsc->nics[i].file->active &&
+		    pRsc->nics[i].logical_port == 3)
+			logport_3_cnt++;
+	}
+
+	if (pRsc->num_logport_confed != 0x3 && logport_2_cnt == 0)
+		pRsc->logport_2_map = 0xf;
+
+	if (pRsc->num_logport_confed != 0x3 && logport_3_cnt == 0)
+		pRsc->logport_3_map = 0xf;
+	return 0;
+}
+
+/*
+* the QPN contains now the number of the RAW ETH
+* adapter and QPN number on the adapter
+* the adapter number is located in the highier
+* 8 bits so QPN is stored as [adapter:qpn]
+*/
+static inline
+struct nes_ud_file *get_file_by_qpn(struct nes_ud_resources *pRsc, int qpn)
+{
+	int i = 0;
+
+	for (i = 0; i < NES_UD_MAX_NIC_CNT; i++) {
+		if (pRsc->nics[i].file->active &&
+		    pRsc->nics[i].qpn == (qpn & 0xff))
+			return pRsc->nics[i].file;
+
+	}
+	return NULL;
+}
+
+/* function counts all ETH RAW entities that have  */
+/* a specific type and relation to specific vnic */
+static inline
+int count_files_by_nic(struct nes_vnic *nesvnic,
+			enum nes_ud_queue_type queue_type)
+{
+	int count = 0;
+	int i = 0;
+	struct nes_ud_resources *pRsc;
+
+	pRsc = locate_ud_adapter(nesvnic->nesdev->nesadapter);
+	if (pRsc == NULL)
+		return 0;
+
+	for (i = 0; i < NES_UD_MAX_NIC_CNT; i++) {
+		if (pRsc->nics[i].file->active &&
+		    pRsc->nics[i].file->nesvnic == nesvnic &&
+		    pRsc->nics[i].queue_type == queue_type)
+				count++;
+	}
+	return count;
+}
+
+/* function counts all RAW ETH  entities the have a specific type */
+static inline
+int count_files(struct nes_vnic *nesvnic, enum nes_ud_queue_type queue_type)
+{
+	int count = 0;
+	int i = 0;
+	struct nes_ud_resources *pRsc;
+
+	pRsc = locate_ud_adapter(nesvnic->nesdev->nesadapter);
+	if (pRsc == NULL)
+		return 0;
+
+	for (i = 0; i < NES_UD_MAX_NIC_CNT; i++) {
+		if (pRsc->nics[i].file->active &&
+		    pRsc->nics[i].queue_type == queue_type)
+			count++;
+	}
+	return count;
+}
+
+/*
+ * the function locates the entry allocated by IGMP and modifies the
+ * PFT entry with the list of the NICs allowed to receive that multicast
+ * the NIC0/NIC1 are removed due to performance issue so tcpdum
+ * like tools cannot receive the accelerated multicasts
+ */
+static void mcast_fix_filter_table_single(struct nes_ud_file *file, u8 *addr)
+{
+  struct nes_device *nesdev = file->nesvnic->nesdev;
+  int i = 0;
+  u32 macaddr_low;
+  u32 orig_low;
+  u32 macaddr_high;
+  u32 prev_high;
+
+  for (i = 0; i < 48; i++) {
+	macaddr_low = nes_read_indexed(nesdev,
+					NES_IDX_PERFECT_FILTER_LOW + i*8);
+	orig_low = macaddr_low;
+	macaddr_high = nes_read_indexed(nesdev,
+					NES_IDX_PERFECT_FILTER_LOW + 4 + i*8);
+	if (!(macaddr_high & NES_MAC_ADDR_VALID))
+		continue;
+	if ((macaddr_high & 0xffff) != 0x0100)
+		continue;
+	if ((macaddr_low & 0xff) != addr[2])
+		continue;
+	macaddr_low >>= 8;
+	if ((macaddr_low & 0xff) != addr[1])
+		continue;
+	macaddr_low >>= 8;
+	if ((macaddr_low & 0xff) != addr[0])
+		continue;
+	macaddr_low >>= 8;
+	if ((macaddr_low & 0xff) != 0x5e)
+		continue;
+	/* hit - that means Linux or other UD set this bit earlier  */
+	prev_high = macaddr_high;
+	nes_write_indexed(nesdev, NES_IDX_PERFECT_FILTER_LOW + 4 + i*8, 0);
+	macaddr_high = (macaddr_high & 0xfffcffff) |
+					((1<<file->nes_ud_nic_index) << 16);
+
+	nes_debug(NES_DBG_UD, "%s(%d) found addr to fix, "
+		 "i=%d, macaddr_high=0x%x  macaddr_low=0x%x "
+		 "nic_idx=%d prev_high=0x%x\n",
+		 __func__, __LINE__, i, macaddr_high, orig_low,
+		file->nes_ud_nic_index, prev_high);
+	nes_write_indexed(nesdev,
+			NES_IDX_PERFECT_FILTER_LOW + 4 + i*8, macaddr_high);
+	break;
+  }
+}
+
+/* this function is implemented that way because the Linux multicast API
+   use the multicast list approach. When a new multicast address is added
+   all PFT table is reinitialized by linux and all entries must be fixed
+   by this procedure
+*/
+static void mcast_fix_filter_table(struct nes_ud_file *file)
+{
+	int i;
+	struct nes_ud_resources *pRsc;
+
+	pRsc = locate_ud_adapter(file->nesvnic->nesdev->nesadapter);
+	if (pRsc == NULL)
+		return;
+
+	for (i = 0; i < NES_UD_MCAST_TBL_SZ; i++) {
+		if (pRsc->mcast[i].in_use != 0)
+			mcast_fix_filter_table_single(pRsc->mcast[i].owner,
+							pRsc->mcast[i].addr);
+	}
+}
+
+/* function invalidates the PFT entry */
+static void remove_mcast_from_pft(struct nes_ud_file *file, u8 *addr)
+{
+  struct nes_device *nesdev = file->nesvnic->nesdev;
+  int i = 0;
+   u32 macaddr_low;
+  u32 orig_low;
+  u32 macaddr_high;
+  u32 prev_high;
+
+  for (i = 0; i < 48; i++) {
+	macaddr_low = nes_read_indexed(nesdev,
+					NES_IDX_PERFECT_FILTER_LOW + i*8);
+	orig_low = macaddr_low;
+	macaddr_high = nes_read_indexed(nesdev,
+					NES_IDX_PERFECT_FILTER_LOW + 4 + i*8);
+	if (!(macaddr_high & NES_MAC_ADDR_VALID))
+		continue;
+
+	if ((macaddr_high & 0xffff) != 0x0100)
+		continue;
+	if ((macaddr_low & 0xff) != addr[2])
+		continue;
+	macaddr_low >>= 8;
+	if ((macaddr_low & 0xff) != addr[1])
+		continue;
+	macaddr_low >>= 8;
+	if ((macaddr_low & 0xff) != addr[0])
+		continue;
+	macaddr_low >>= 8;
+	if ((macaddr_low & 0xff) != 0x5e)
+		continue;
+	/* hit - that means Linux or other UD set this bit earlier */
+	/* so remove the NIC from MAC address reception */
+	prev_high = macaddr_high;
+	macaddr_high = (macaddr_high & 0xfffcffff) &
+					~((1<<file->nes_ud_nic_index) << 16);
+	nes_debug(NES_DBG_UD, "%s(%d) found addr to mcast remove,"
+		"i=%d, macaddr_high=0x%x  macaddr_low=0x%x "
+		"nic_idx=%d prev_high=0x%x\n", __func__, __LINE__, i,
+		macaddr_high, orig_low, file->nes_ud_nic_index, prev_high);
+	nes_write_indexed(nesdev, NES_IDX_PERFECT_FILTER_LOW + 4 + i*8,
+							macaddr_high);
+	break;
+	}
+
+}
+
+/*
+* the function returns a mask of the NICs
+* assotiated with given multicast address
+*/
+static int nes_ud_mcast_filter(struct nes_vnic *nesvnic, __u8 *dmi_addr)
+{
+	int i = 0;
+	int ret = 0;
+	int mask = 0;
+	struct nes_ud_resources *pRsc;
+
+	pRsc = locate_ud_adapter(nesvnic->nesdev->nesadapter);
+	if (pRsc == NULL)
+		return 0;
+
+	for (i = 0; i < NES_UD_MCAST_TBL_SZ; i++) {
+		if (pRsc->mcast[i].in_use &&
+		    pRsc->mcast[i].addr[0] == dmi_addr[3] &&
+		    pRsc->mcast[i].addr[1] == dmi_addr[4] &&
+		    pRsc->mcast[i].addr[2] == dmi_addr[5]) {
+			mask = (pRsc->mcast[i].owner->mcast_mode ==
+				NES_UD_MCAST_PFT_MODE) ?
+				pRsc->mcast[i].owner->nes_ud_nic_index : 0;
+
+			ret = ret | (1 << mask);
+			nes_debug(NES_DBG_UD, "mcast filter, "
+				"fpr=%02X%02X%02X ret=%d\n",
+				dmi_addr[3], dmi_addr[4], dmi_addr[5], ret);
+		}
+	}
+	if (ret == 0)
+		return -1;
+	else
+		return ret;
+
+}
+
+static __u32 mqueue_key[4] = { 0x0, 0x80, 0x0, 0x0 };
+
+static inline __u8 nes_ud_calculate_hash(__u8 dest_addr_lsb)
+{
+  __u8 in[8];
+  __u32 key_arr[4];
+  int i;
+  __u32 result = 0;
+  int j, k;
+  __u8 shift_in, next_shift_in;
+
+  in[0] = 0;
+  in[1] = 0;
+  in[2] = 0;
+  in[3] = 0;
+
+  in[4] = 0;
+
+  in[5] = 0;
+  in[6] = 0;
+  in[7] = dest_addr_lsb;
+
+
+
+	for (i = 0; i < 4; i++)
+		key_arr[3-i] = mqueue_key[i];
+
+
+
+	for (i = 0; i < 8; i++) {
+		for (j = 7; j >= 0; j--) {
+			if (in[i] & (1 << j))
+				result = result ^ key_arr[0];
+
+			shift_in = 0;
+			for (k = 3; k >= 0; k--) {
+				next_shift_in = key_arr[k] >> 31;
+				key_arr[k] = (key_arr[k] << 1) + shift_in;
+				shift_in = next_shift_in;
+			}
+		}
+	}
+	return result & 0x7f;
+}
+
+static inline void nes_ud_enable_mqueue(struct nes_ud_file *file)
+{
+	struct nes_device *nesdev = file->nesvnic->nesdev;
+	int mqueue_config0;
+	int mqueue_config2;
+	int instance = file->nes_ud_nic_index & 0x1;
+
+	mqueue_config0 = nes_read_indexed(nesdev, 0x6400);
+	mqueue_config0 |= (4 | (instance & 0x3)) << (file->nes_ud_nic_index*3);
+	nes_write_indexed(nesdev, 0x6400, mqueue_config0);
+	mqueue_config0 = nes_read_indexed(nesdev, 0x6400);
+
+	mqueue_config2 = nes_read_indexed(nesdev, 0x6408);
+	mqueue_config2 |= (2 << (instance*2)) | (6 << (instance*3+8));
+	nes_write_indexed(nesdev, 0x6408, mqueue_config2);
+	mqueue_config2 = nes_read_indexed(nesdev, 0x6408);
+
+	nes_write_indexed(nesdev, 0x64a0+instance*0x100, mqueue_key[0]);
+	nes_write_indexed(nesdev, 0x64a4+instance*0x100, mqueue_key[1]);
+	nes_write_indexed(nesdev, 0x64a8+instance*0x100, mqueue_key[2]);
+	nes_write_indexed(nesdev, 0x64ac+instance*0x100, mqueue_key[3]);
+
+	nes_debug(NES_DBG_UD, "mq_config0=0x%x mq_config2=0x%x nic_idx= %d\n",
+		  mqueue_config0, mqueue_config2, file->nes_ud_nic_index);
+
+}
+
+
+
+static inline
+void nes_ud_redirect_from_mqueue(struct nes_ud_file *file, int num_queues)
+{
+	struct nes_device *nesdev = file->nesvnic->nesdev;
+	int instance = file->nes_ud_nic_index & 0x1;
+	unsigned addr = 0x6420+instance*0x100;
+	unsigned value;
+	int i;
+
+	value  = (file->prio == NES_UD_DEV_PRIO_LOW || num_queues == 1) ?
+							0x0 : 0x11111111;
+	for (i = 0; i < 16; i++)
+		nes_write_indexed(nesdev, addr+i*4, value);
+}
+
+
+static int nes_ud_create_nic(struct nes_ud_file *file)
+{
+	struct nes_vnic *nesvnic = file->nesvnic;
+	struct nes_device *nesdev = nesvnic->nesdev;
+	struct nes_hw_nic_qp_context *nic_context;
+	struct nes_hw_cqp_wqe *cqp_wqe;
+	struct nes_cqp_request *cqp_request;
+	unsigned long flags;
+	void *vmem;
+	dma_addr_t pmem;
+	u64 u64temp;
+	int ret = 0;
+
+	BUG_ON(file->nic_vbase != NULL);
+
+	file->nic_mem_size = 256 +
+			(NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_sq_wqe)) +
+			sizeof(struct nes_hw_nic_qp_context);
+
+	file->nic_vbase = pci_alloc_consistent(nesdev->pcidev,
+						file->nic_mem_size,
+						&file->nic_pbase);
+	if (!file->nic_vbase) {
+		nes_debug(NES_DBG_UD, "Unable to allocate memory for NIC host "
+			"descriptor rings\n");
+		return -ENOMEM;
+	}
+
+	memset(file->nic_vbase, 0, file->nic_mem_size);
+
+	vmem = (void *)(((unsigned long long)file->nic_vbase + (256 - 1)) &
+			~(unsigned long long)(256 - 1));
+	pmem = (dma_addr_t)(((unsigned long long)file->nic_pbase + (256 - 1)) &
+			~(unsigned long long)(256 - 1));
+
+	file->wq_vbase = vmem;
+	file->wq_pbase = pmem;
+	file->head = 0;
+	file->tail = 0;
+
+	vmem += (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_sq_wqe));
+	pmem += (NES_NIC_WQ_SIZE * sizeof(struct nes_hw_nic_sq_wqe));
+
+	cqp_request = nesvnic->get_cqp_request(nesdev);
+	if (cqp_request == NULL) {
+		nes_debug(NES_DBG_QP, "Failed to get a cqp_request.\n");
+		goto fail_cqp_req_alloc;
+	}
+	cqp_request->waiting = 1;
+	cqp_wqe = &cqp_request->cqp_wqe;
+
+	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(file->qpn);
+	cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_LOW_IDX] =
+			cpu_to_le32((u32)((u64)(&nesdev->cqp)));
+	cqp_wqe->wqe_words[NES_CQP_WQE_COMP_CTX_HIGH_IDX] =
+			cpu_to_le32((u32)(((u64)(&nesdev->cqp))>>32));
+	cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_LOW_IDX] = 0;
+	cqp_wqe->wqe_words[NES_CQP_WQE_COMP_SCRATCH_HIGH_IDX] = 0;
+
+
+	nic_context = vmem;
+
+	nic_context->context_words[NES_NIC_CTX_MISC_IDX] =
+			cpu_to_le32((u32)NES_NIC_CTX_SIZE |
+			((u32)PCI_FUNC(nesdev->pcidev->devfn) << 12) |
+			(1 << 18));
+
+	nic_context->context_words[NES_NIC_CTX_SQ_LOW_IDX] = 0;
+	nic_context->context_words[NES_NIC_CTX_SQ_HIGH_IDX] = 0;
+	nic_context->context_words[NES_NIC_CTX_RQ_LOW_IDX] = 0;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-projects mailing list