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