15054 lines
488 KiB
Plaintext
15054 lines
488 KiB
Plaintext
From: David Riddoch <driddoch@solarflare.com>
|
|
# replaces http://xenbits.xensource.com/linux-2.6.18-xen.hg c/s 421:
|
|
# HG changeset patch
|
|
# User Keir Fraser <keir.fraser@citrix.com>
|
|
# Date 1203330569 0
|
|
# Node ID e4dd072db2595c420bb21d9e835416f4fd543526
|
|
# Parent fc90e9b2c12b316b5460ece28f013e6de881af1a
|
|
Subject: Solarflare: Resource driver.
|
|
References: FATE#303479
|
|
Patch-mainline: n/a
|
|
Acked-by: jbeulich@novell.com
|
|
|
|
--- head-2009-04-21.orig/drivers/net/sfc/Kconfig 2009-04-21 11:01:52.000000000 +0200
|
|
+++ head-2009-04-21/drivers/net/sfc/Kconfig 2009-04-21 11:02:22.000000000 +0200
|
|
@@ -11,6 +11,13 @@ config SFC
|
|
|
|
To compile this driver as a module, choose M here. The module
|
|
will be called sfc.
|
|
+
|
|
+config SFC_RESOURCE
|
|
+ depends on SFC && X86
|
|
+ tristate "Solarflare Solarstorm SFC4000 resource driver"
|
|
+ help
|
|
+ This module provides the SFC resource manager driver.
|
|
+
|
|
config SFC_MTD
|
|
bool "Solarflare Solarstorm SFC4000 flash MTD support"
|
|
depends on SFC && MTD && !(SFC=y && MTD=m)
|
|
--- head-2009-04-21.orig/drivers/net/sfc/Makefile 2009-04-21 11:01:52.000000000 +0200
|
|
+++ head-2009-04-21/drivers/net/sfc/Makefile 2009-02-06 12:42:18.000000000 +0100
|
|
@@ -5,3 +5,5 @@ sfc-y += efx.o falcon.o tx.o rx.o falc
|
|
sfc-$(CONFIG_SFC_MTD) += mtd.o
|
|
|
|
obj-$(CONFIG_SFC) += sfc.o
|
|
+
|
|
+obj-$(CONFIG_SFC_RESOURCE) += sfc_resource/
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/Makefile 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,14 @@
|
|
+obj-$(CONFIG_SFC_RESOURCE) := sfc_resource.o
|
|
+
|
|
+EXTRA_CFLAGS += -D__CI_HARDWARE_CONFIG_FALCON__
|
|
+EXTRA_CFLAGS += -D__ci_driver__
|
|
+EXTRA_CFLAGS += -Werror
|
|
+EXTRA_CFLAGS += -Idrivers/net/sfc -Idrivers/net/sfc/sfc_resource
|
|
+
|
|
+sfc_resource-objs := resource_driver.o iopage.o efx_vi_shm.o \
|
|
+ driverlink_new.o kernel_proc.o kfifo.o \
|
|
+ nic.o eventq.o falcon.o falcon_hash.o \
|
|
+ assert_valid.o buddy.o buffer_table.o filter_resource.o \
|
|
+ iobufset_resource.o resource_manager.o resources.o \
|
|
+ vi_resource_alloc.o vi_resource_event.o vi_resource_flush.o \
|
|
+ vi_resource_manager.o driver_object.o kernel_compat.o
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/assert_valid.c 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,92 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file contains functions to assert validness of resources and
|
|
+ * resource manager in DEBUG build of the resource driver.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#include <ci/efrm/sysdep.h>
|
|
+
|
|
+#ifndef NDEBUG
|
|
+#include <ci/efrm/resource.h>
|
|
+#include <ci/efrm/driver_private.h>
|
|
+#include <ci/efrm/debug.h>
|
|
+
|
|
+void
|
|
+efrm_resource_manager_assert_valid(struct efrm_resource_manager *rm,
|
|
+ const char *file, int line)
|
|
+{
|
|
+ _EFRM_ASSERT(rm, file, line);
|
|
+ _EFRM_ASSERT(rm->rm_name, file, line);
|
|
+ _EFRM_ASSERT(rm->rm_type < EFRM_RESOURCE_NUM, file, line);
|
|
+ _EFRM_ASSERT(rm->rm_dtor, file, line);
|
|
+}
|
|
+EXPORT_SYMBOL(efrm_resource_manager_assert_valid);
|
|
+
|
|
+/*
|
|
+ * \param rs resource to validate
|
|
+ * \param ref_count_is_zero One of 3 values
|
|
+ * > 0 - check ref count is zero
|
|
+ * = 0 - check ref count is non-zero
|
|
+ * < 0 - ref count could be any value
|
|
+ */
|
|
+void
|
|
+efrm_resource_assert_valid(struct efrm_resource *rs, int ref_count_is_zero,
|
|
+ const char *file, int line)
|
|
+{
|
|
+ struct efrm_resource_manager *rm;
|
|
+
|
|
+ _EFRM_ASSERT(rs, file, line);
|
|
+
|
|
+ if (ref_count_is_zero >= 0) {
|
|
+ if (!(ref_count_is_zero || rs->rs_ref_count > 0)
|
|
+ || !(!ref_count_is_zero || rs->rs_ref_count == 0))
|
|
+ EFRM_WARN("%s: check %szero ref=%d " EFRM_RESOURCE_FMT,
|
|
+ __func__,
|
|
+ ref_count_is_zero == 0 ? "non-" : "",
|
|
+ rs->rs_ref_count,
|
|
+ EFRM_RESOURCE_PRI_ARG(rs->rs_handle));
|
|
+
|
|
+ _EFRM_ASSERT(!(ref_count_is_zero == 0) ||
|
|
+ rs->rs_ref_count != 0, file, line);
|
|
+ _EFRM_ASSERT(!(ref_count_is_zero > 0) ||
|
|
+ rs->rs_ref_count == 0, file, line);
|
|
+ }
|
|
+
|
|
+ rm = efrm_rm_table[EFRM_RESOURCE_TYPE(rs->rs_handle)];
|
|
+ efrm_resource_manager_assert_valid(rm, file, line);
|
|
+}
|
|
+EXPORT_SYMBOL(efrm_resource_assert_valid);
|
|
+
|
|
+#endif
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/buddy.c 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,220 @@
|
|
+
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file contains implementation of a buddy allocator.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#include <ci/efhw/common.h> /* get uintXX types on win32 */
|
|
+#include <ci/efrm/sysdep.h>
|
|
+#include <ci/efrm/buddy.h>
|
|
+#include <ci/efrm/debug.h>
|
|
+
|
|
+#if 1
|
|
+#define DEBUG_ALLOC(x)
|
|
+#else
|
|
+#define DEBUG_ALLOC(x) x
|
|
+
|
|
+static inline void efrm_buddy_dump(struct efrm_buddy_allocator *b)
|
|
+{
|
|
+ unsigned o;
|
|
+
|
|
+ EFRM_NOTICE("%s: dump allocator with order %u",
|
|
+ __func__, b->order);
|
|
+ for (o = 0; o <= b->order; o++) {
|
|
+ struct list_head *l = &b->free_lists[o];
|
|
+ while (l->next != &b->free_lists[o]) {
|
|
+ l = l->next;
|
|
+ EFRM_NOTICE("%s: order %x: %zx", __func__, o,
|
|
+ l - b->links);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+#endif
|
|
+
|
|
+/*
|
|
+ * The purpose of the following inline functions is to give the
|
|
+ * understandable names to the simple actions.
|
|
+ */
|
|
+static inline void
|
|
+efrm_buddy_free_list_add(struct efrm_buddy_allocator *b,
|
|
+ unsigned order, unsigned addr)
|
|
+{
|
|
+ list_add(&b->links[addr], &b->free_lists[order]);
|
|
+ b->orders[addr] = (uint8_t) order;
|
|
+}
|
|
+static inline void
|
|
+efrm_buddy_free_list_del(struct efrm_buddy_allocator *b, unsigned addr)
|
|
+{
|
|
+ list_del(&b->links[addr]);
|
|
+ b->links[addr].next = NULL;
|
|
+}
|
|
+static inline int
|
|
+efrm_buddy_free_list_empty(struct efrm_buddy_allocator *b, unsigned order)
|
|
+{
|
|
+ return list_empty(&b->free_lists[order]);
|
|
+}
|
|
+static inline unsigned
|
|
+efrm_buddy_free_list_pop(struct efrm_buddy_allocator *b, unsigned order)
|
|
+{
|
|
+ struct list_head *l = list_pop(&b->free_lists[order]);
|
|
+ l->next = NULL;
|
|
+ return (unsigned)(l - b->links);
|
|
+}
|
|
+static inline int
|
|
+efrm_buddy_addr_in_free_list(struct efrm_buddy_allocator *b, unsigned addr)
|
|
+{
|
|
+ return b->links[addr].next != NULL;
|
|
+}
|
|
+static inline unsigned
|
|
+efrm_buddy_free_list_first(struct efrm_buddy_allocator *b, unsigned order)
|
|
+{
|
|
+ return (unsigned)(b->free_lists[order].next - b->links);
|
|
+}
|
|
+
|
|
+int efrm_buddy_ctor(struct efrm_buddy_allocator *b, unsigned order)
|
|
+{
|
|
+ unsigned o;
|
|
+ unsigned size = 1 << order;
|
|
+
|
|
+ DEBUG_ALLOC(EFRM_NOTICE("%s(%u)", __func__, order));
|
|
+ EFRM_ASSERT(b);
|
|
+ EFRM_ASSERT(order <= sizeof(unsigned) * 8 - 1);
|
|
+
|
|
+ b->order = order;
|
|
+ b->free_lists = vmalloc((order + 1) * sizeof(struct list_head));
|
|
+ if (b->free_lists == NULL)
|
|
+ goto fail1;
|
|
+
|
|
+ b->links = vmalloc(size * sizeof(struct list_head));
|
|
+ if (b->links == NULL)
|
|
+ goto fail2;
|
|
+
|
|
+ b->orders = vmalloc(size);
|
|
+ if (b->orders == NULL)
|
|
+ goto fail3;
|
|
+
|
|
+ memset(b->links, 0, size * sizeof(struct list_head));
|
|
+
|
|
+ for (o = 0; o <= b->order; ++o)
|
|
+ INIT_LIST_HEAD(b->free_lists + o);
|
|
+
|
|
+ efrm_buddy_free_list_add(b, b->order, 0);
|
|
+
|
|
+ return 0;
|
|
+
|
|
+fail3:
|
|
+ vfree(b->links);
|
|
+fail2:
|
|
+ vfree(b->free_lists);
|
|
+fail1:
|
|
+ return -ENOMEM;
|
|
+}
|
|
+
|
|
+void efrm_buddy_dtor(struct efrm_buddy_allocator *b)
|
|
+{
|
|
+ EFRM_ASSERT(b);
|
|
+
|
|
+ vfree(b->free_lists);
|
|
+ vfree(b->links);
|
|
+ vfree(b->orders);
|
|
+}
|
|
+
|
|
+int efrm_buddy_alloc(struct efrm_buddy_allocator *b, unsigned order)
|
|
+{
|
|
+ unsigned smallest;
|
|
+ unsigned addr;
|
|
+
|
|
+ DEBUG_ALLOC(EFRM_NOTICE("%s(%u)", __func__, order));
|
|
+ EFRM_ASSERT(b);
|
|
+
|
|
+ /* Find smallest chunk that is big enough. ?? Can optimise this by
|
|
+ ** keeping array of pointers to smallest chunk for each order.
|
|
+ */
|
|
+ smallest = order;
|
|
+ while (smallest <= b->order &&
|
|
+ efrm_buddy_free_list_empty(b, smallest))
|
|
+ ++smallest;
|
|
+
|
|
+ if (smallest > b->order) {
|
|
+ DEBUG_ALLOC(EFRM_NOTICE
|
|
+ ("buddy - alloc order %d failed - max order %d",
|
|
+ order, b->order););
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ /* Split blocks until we get one of the correct size. */
|
|
+ addr = efrm_buddy_free_list_pop(b, smallest);
|
|
+
|
|
+ DEBUG_ALLOC(EFRM_NOTICE("buddy - alloc %x order %d cut from order %d",
|
|
+ addr, order, smallest););
|
|
+ while (smallest-- > order)
|
|
+ efrm_buddy_free_list_add(b, smallest, addr + (1 << smallest));
|
|
+
|
|
+ EFRM_DO_DEBUG(b->orders[addr] = (uint8_t) order);
|
|
+
|
|
+ EFRM_ASSERT(addr < 1u << b->order);
|
|
+ return addr;
|
|
+}
|
|
+
|
|
+void
|
|
+efrm_buddy_free(struct efrm_buddy_allocator *b, unsigned addr,
|
|
+ unsigned order)
|
|
+{
|
|
+ unsigned buddy_addr;
|
|
+
|
|
+ DEBUG_ALLOC(EFRM_NOTICE("%s(%u, %u)", __func__, addr, order));
|
|
+ EFRM_ASSERT(b);
|
|
+ EFRM_ASSERT(order <= b->order);
|
|
+ EFRM_ASSERT((unsigned long)addr + ((unsigned long)1 << order) <=
|
|
+ (unsigned long)1 << b->order);
|
|
+ EFRM_ASSERT(!efrm_buddy_addr_in_free_list(b, addr));
|
|
+ EFRM_ASSERT(b->orders[addr] == order);
|
|
+
|
|
+ /* merge free blocks */
|
|
+ while (order < b->order) {
|
|
+ buddy_addr = addr ^ (1 << order);
|
|
+ if (!efrm_buddy_addr_in_free_list(b, buddy_addr) ||
|
|
+ b->orders[buddy_addr] != order)
|
|
+ break;
|
|
+ efrm_buddy_free_list_del(b, buddy_addr);
|
|
+ if (buddy_addr < addr)
|
|
+ addr = buddy_addr;
|
|
+ ++order;
|
|
+ }
|
|
+
|
|
+ DEBUG_ALLOC(EFRM_NOTICE
|
|
+ ("buddy - free %x merged into order %d", addr, order););
|
|
+ efrm_buddy_free_list_add(b, order, addr);
|
|
+}
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/buffer_table.c 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,209 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file contains abstraction of the buffer table on the NIC.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+/*
|
|
+** Might be worth keeping a bitmap of which entries are clear. Then we
|
|
+** wouldn't need to clear them all again when we free an allocation.
|
|
+*/
|
|
+
|
|
+#include <ci/efrm/debug.h>
|
|
+#include <ci/driver/efab/hardware.h>
|
|
+#include <ci/efrm/nic_table.h>
|
|
+#include <ci/efrm/buffer_table.h>
|
|
+#include <ci/efrm/buddy.h>
|
|
+
|
|
+/*! Comment? */
|
|
+struct efrm_buffer_table {
|
|
+ spinlock_t lock;
|
|
+ struct efrm_buddy_allocator buddy;
|
|
+};
|
|
+
|
|
+/* Efab buffer state. */
|
|
+static struct efrm_buffer_table efrm_buffers;
|
|
+
|
|
+int efrm_buffer_table_ctor(unsigned low, unsigned high)
|
|
+{
|
|
+ int log2_n_entries, rc, i;
|
|
+
|
|
+ EFRM_ASSERT(high > 0);
|
|
+ EFRM_ASSERT(low < high);
|
|
+
|
|
+ EFRM_TRACE("%s: low=%u high=%u", __func__, low, high);
|
|
+ EFRM_NOTICE("%s: low=%u high=%u", __func__, low, high);
|
|
+
|
|
+ log2_n_entries = fls(high - 1);
|
|
+
|
|
+ rc = efrm_buddy_ctor(&efrm_buffers.buddy, log2_n_entries);
|
|
+ if (rc < 0) {
|
|
+ EFRM_ERR("efrm_buffer_table_ctor: efrm_buddy_ctor(%d) "
|
|
+ "failed (%d)", log2_n_entries, rc);
|
|
+ return rc;
|
|
+ }
|
|
+ for (i = 0; i < (1 << log2_n_entries); ++i) {
|
|
+ rc = efrm_buddy_alloc(&efrm_buffers.buddy, 0);
|
|
+ EFRM_ASSERT(rc >= 0);
|
|
+ EFRM_ASSERT(rc < (1 << log2_n_entries));
|
|
+ }
|
|
+ for (i = low; i < (int) high; ++i)
|
|
+ efrm_buddy_free(&efrm_buffers.buddy, i, 0);
|
|
+
|
|
+ spin_lock_init(&efrm_buffers.lock);
|
|
+
|
|
+ EFRM_TRACE("%s: done", __func__);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void efrm_buffer_table_dtor(void)
|
|
+{
|
|
+ /* ?? debug check that all allocations have been freed? */
|
|
+
|
|
+ spin_lock_destroy(&efrm_buffers.lock);
|
|
+ efrm_buddy_dtor(&efrm_buffers.buddy);
|
|
+
|
|
+ EFRM_TRACE("%s: done", __func__);
|
|
+}
|
|
+
|
|
+/**********************************************************************/
|
|
+
|
|
+int
|
|
+efrm_buffer_table_alloc(unsigned order,
|
|
+ struct efhw_buffer_table_allocation *a)
|
|
+{
|
|
+ irq_flags_t lock_flags;
|
|
+ int rc;
|
|
+
|
|
+ EFRM_ASSERT(&efrm_buffers.buddy);
|
|
+ EFRM_ASSERT(a);
|
|
+
|
|
+ /* Round up to multiple of two, as the buffer clear logic works in
|
|
+ * pairs when not in "full" mode. */
|
|
+ order = max_t(unsigned, order, 1);
|
|
+
|
|
+ spin_lock_irqsave(&efrm_buffers.lock, lock_flags);
|
|
+ rc = efrm_buddy_alloc(&efrm_buffers.buddy, order);
|
|
+ spin_unlock_irqrestore(&efrm_buffers.lock, lock_flags);
|
|
+
|
|
+ if (rc < 0) {
|
|
+ EFRM_ERR("efrm_buffer_table_alloc: failed (n=%ld) rc %d",
|
|
+ 1ul << order, rc);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ EFRM_TRACE("efrm_buffer_table_alloc: base=%d n=%ld",
|
|
+ rc, 1ul << order);
|
|
+ a->order = order;
|
|
+ a->base = (unsigned)rc;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void efrm_buffer_table_free(struct efhw_buffer_table_allocation *a)
|
|
+{
|
|
+ irq_flags_t lock_flags;
|
|
+ struct efhw_nic *nic;
|
|
+ int nic_i;
|
|
+
|
|
+ EFRM_ASSERT(&efrm_buffers.buddy);
|
|
+ EFRM_ASSERT(a);
|
|
+ EFRM_ASSERT(a->base != -1);
|
|
+ EFRM_ASSERT((unsigned long)a->base + (1ul << a->order) <=
|
|
+ efrm_buddy_size(&efrm_buffers.buddy));
|
|
+
|
|
+ EFRM_TRACE("efrm_buffer_table_free: base=%d n=%ld",
|
|
+ a->base, (1ul << a->order));
|
|
+
|
|
+ EFRM_FOR_EACH_NIC(nic_i, nic)
|
|
+ efhw_nic_buffer_table_clear(nic, a->base, 1ul << a->order);
|
|
+
|
|
+ spin_lock_irqsave(&efrm_buffers.lock, lock_flags);
|
|
+ efrm_buddy_free(&efrm_buffers.buddy, a->base, a->order);
|
|
+ spin_unlock_irqrestore(&efrm_buffers.lock, lock_flags);
|
|
+
|
|
+ EFRM_DO_DEBUG(a->base = a->order = -1);
|
|
+}
|
|
+
|
|
+/**********************************************************************/
|
|
+
|
|
+void
|
|
+efrm_buffer_table_set(struct efhw_buffer_table_allocation *a,
|
|
+ struct efhw_nic *nic,
|
|
+ unsigned i, dma_addr_t dma_addr, int owner)
|
|
+{
|
|
+ EFRM_ASSERT(a);
|
|
+ EFRM_ASSERT(i < (unsigned)1 << a->order);
|
|
+
|
|
+ efhw_nic_buffer_table_set(nic, dma_addr, EFHW_NIC_PAGE_SIZE,
|
|
+ 0, owner, a->base + i);
|
|
+}
|
|
+
|
|
+
|
|
+int efrm_buffer_table_size(void)
|
|
+{
|
|
+ return efrm_buddy_size(&efrm_buffers.buddy);
|
|
+}
|
|
+
|
|
+/**********************************************************************/
|
|
+
|
|
+int
|
|
+efrm_page_register(struct efhw_nic *nic, dma_addr_t dma_addr, int owner,
|
|
+ efhw_buffer_addr_t *buf_addr_out)
|
|
+{
|
|
+ struct efhw_buffer_table_allocation alloc;
|
|
+ int rc;
|
|
+
|
|
+ rc = efrm_buffer_table_alloc(0, &alloc);
|
|
+ if (rc == 0) {
|
|
+ efrm_buffer_table_set(&alloc, nic, 0, dma_addr, owner);
|
|
+ efrm_buffer_table_commit();
|
|
+ *buf_addr_out = EFHW_BUFFER_ADDR(alloc.base, 0);
|
|
+ }
|
|
+ return rc;
|
|
+}
|
|
+EXPORT_SYMBOL(efrm_page_register);
|
|
+
|
|
+void efrm_page_unregister(efhw_buffer_addr_t buf_addr)
|
|
+{
|
|
+ struct efhw_buffer_table_allocation alloc;
|
|
+
|
|
+ alloc.order = 0;
|
|
+ alloc.base = EFHW_BUFFER_PAGE(buf_addr);
|
|
+ efrm_buffer_table_free(&alloc);
|
|
+}
|
|
+EXPORT_SYMBOL(efrm_page_unregister);
|
|
+
|
|
+void efrm_buffer_table_commit(void)
|
|
+{
|
|
+ struct efhw_nic *nic;
|
|
+ int nic_i;
|
|
+
|
|
+ EFRM_FOR_EACH_NIC(nic_i, nic)
|
|
+ efhw_nic_buffer_table_commit(nic);
|
|
+}
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,188 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides EtherFabric NIC hardware interface.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_DRIVER_EFAB_HARDWARE_H__
|
|
+#define __CI_DRIVER_EFAB_HARDWARE_H__
|
|
+
|
|
+#include "ci/driver/efab/hardware/workarounds.h"
|
|
+#include <ci/efhw/hardware_sysdep.h>
|
|
+
|
|
+
|
|
+/*----------------------------------------------------------------------------
|
|
+ *
|
|
+ * Common EtherFabric definitions
|
|
+ *
|
|
+ *---------------------------------------------------------------------------*/
|
|
+
|
|
+#include <ci/efhw/debug.h>
|
|
+#include <ci/efhw/common.h>
|
|
+#include <ci/driver/efab/hardware/common.h>
|
|
+
|
|
+/*----------------------------------------------------------------------------
|
|
+ *
|
|
+ * EtherFabric varients
|
|
+ *
|
|
+ *---------------------------------------------------------------------------*/
|
|
+
|
|
+#include <ci/driver/efab/hardware/falcon.h>
|
|
+
|
|
+/*----------------------------------------------------------------------------
|
|
+ *
|
|
+ * EtherFabric Portable Hardware Layer defines
|
|
+ *
|
|
+ *---------------------------------------------------------------------------*/
|
|
+
|
|
+ /*-------------- Initialisation ------------ */
|
|
+#define efhw_nic_close_hardware(nic) \
|
|
+ ((nic)->efhw_func->close_hardware(nic))
|
|
+
|
|
+#define efhw_nic_init_hardware(nic, ev_handlers, mac_addr, non_irq_evq) \
|
|
+ ((nic)->efhw_func->init_hardware((nic), (ev_handlers), (mac_addr), \
|
|
+ (non_irq_evq)))
|
|
+
|
|
+/*-------------- Interrupt support ------------ */
|
|
+/** Handle interrupt. Return 0 if not handled, 1 if handled. */
|
|
+#define efhw_nic_interrupt(nic) \
|
|
+ ((nic)->efhw_func->interrupt(nic))
|
|
+
|
|
+#define efhw_nic_interrupt_enable(nic) \
|
|
+ ((nic)->efhw_func->interrupt_enable(nic))
|
|
+
|
|
+#define efhw_nic_interrupt_disable(nic) \
|
|
+ ((nic)->efhw_func->interrupt_disable(nic))
|
|
+
|
|
+#define efhw_nic_set_interrupt_moderation(nic, evq, val) \
|
|
+ ((nic)->efhw_func->set_interrupt_moderation(nic, evq, val))
|
|
+
|
|
+/*-------------- Event support ------------ */
|
|
+
|
|
+#define efhw_nic_event_queue_enable(nic, evq, size, q_base, buf_base, \
|
|
+ interrupting) \
|
|
+ ((nic)->efhw_func->event_queue_enable((nic), (evq), (size), (q_base), \
|
|
+ (buf_base), (interrupting)))
|
|
+
|
|
+#define efhw_nic_event_queue_disable(nic, evq, timer_only) \
|
|
+ ((nic)->efhw_func->event_queue_disable(nic, evq, timer_only))
|
|
+
|
|
+#define efhw_nic_wakeup_request(nic, q_base, index, evq) \
|
|
+ ((nic)->efhw_func->wakeup_request(nic, q_base, index, evq))
|
|
+
|
|
+#define efhw_nic_sw_event(nic, data, ev) \
|
|
+ ((nic)->efhw_func->sw_event(nic, data, ev))
|
|
+
|
|
+/*-------------- Filter support ------------ */
|
|
+#define efhw_nic_ipfilter_set(nic, type, index, dmaq, \
|
|
+ saddr, sport, daddr, dport) \
|
|
+ ((nic)->efhw_func->ipfilter_set(nic, type, index, dmaq, \
|
|
+ saddr, sport, daddr, dport))
|
|
+
|
|
+#define efhw_nic_ipfilter_clear(nic, index) \
|
|
+ ((nic)->efhw_func->ipfilter_clear(nic, index))
|
|
+
|
|
+/*-------------- DMA support ------------ */
|
|
+#define efhw_nic_dmaq_tx_q_init(nic, dmaq, evq, owner, tag, \
|
|
+ dmaq_size, index, flags) \
|
|
+ ((nic)->efhw_func->dmaq_tx_q_init(nic, dmaq, evq, owner, tag, \
|
|
+ dmaq_size, index, flags))
|
|
+
|
|
+#define efhw_nic_dmaq_rx_q_init(nic, dmaq, evq, owner, tag, \
|
|
+ dmaq_size, index, flags) \
|
|
+ ((nic)->efhw_func->dmaq_rx_q_init(nic, dmaq, evq, owner, tag, \
|
|
+ dmaq_size, index, flags))
|
|
+
|
|
+#define efhw_nic_dmaq_tx_q_disable(nic, dmaq) \
|
|
+ ((nic)->efhw_func->dmaq_tx_q_disable(nic, dmaq))
|
|
+
|
|
+#define efhw_nic_dmaq_rx_q_disable(nic, dmaq) \
|
|
+ ((nic)->efhw_func->dmaq_rx_q_disable(nic, dmaq))
|
|
+
|
|
+#define efhw_nic_flush_tx_dma_channel(nic, dmaq) \
|
|
+ ((nic)->efhw_func->flush_tx_dma_channel(nic, dmaq))
|
|
+
|
|
+#define efhw_nic_flush_rx_dma_channel(nic, dmaq) \
|
|
+ ((nic)->efhw_func->flush_rx_dma_channel(nic, dmaq))
|
|
+
|
|
+/*-------------- MAC Low level interface ---- */
|
|
+#define efhw_gmac_get_mac_addr(nic) \
|
|
+ ((nic)->gmac->get_mac_addr((nic)->gmac))
|
|
+
|
|
+/*-------------- Buffer table -------------- */
|
|
+#define efhw_nic_buffer_table_set(nic, addr, bufsz, region, \
|
|
+ own_id, buf_id) \
|
|
+ ((nic)->efhw_func->buffer_table_set(nic, addr, bufsz, region, \
|
|
+ own_id, buf_id))
|
|
+
|
|
+#define efhw_nic_buffer_table_set_n(nic, buf_id, addr, bufsz, \
|
|
+ region, n_pages, own_id) \
|
|
+ ((nic)->efhw_func->buffer_table_set_n(nic, buf_id, addr, bufsz, \
|
|
+ region, n_pages, own_id))
|
|
+
|
|
+#define efhw_nic_buffer_table_clear(nic, id, num) \
|
|
+ ((nic)->efhw_func->buffer_table_clear(nic, id, num))
|
|
+
|
|
+#define efhw_nic_buffer_table_commit(nic) \
|
|
+ ((nic)->efhw_func->buffer_table_commit(nic))
|
|
+
|
|
+/*-------------- New filter API ------------ */
|
|
+#define efhw_nic_filter_set(nic, spec, index_out) \
|
|
+ ((nic)->efhw_func->filter_set(nic, spec, index_out))
|
|
+
|
|
+#define efhw_nic_filter_clear(nic, type, index_out) \
|
|
+ ((nic)->efhw_func->filter_clear(nic, type, index_out))
|
|
+
|
|
+
|
|
+/* --- DMA --- */
|
|
+#define EFHW_DMA_ADDRMASK (0xffffffffffffffffULL)
|
|
+
|
|
+/* --- Buffers --- */
|
|
+#define EFHW_BUFFER_ADDR FALCON_BUFFER_4K_ADDR
|
|
+#define EFHW_BUFFER_PAGE FALCON_BUFFER_4K_PAGE
|
|
+#define EFHW_BUFFER_OFF FALCON_BUFFER_4K_OFF
|
|
+
|
|
+/* --- Filters --- */
|
|
+#define EFHW_IP_FILTER_NUM FALCON_FILTER_TBL_NUM
|
|
+
|
|
+#define EFHW_MAX_PAGE_SIZE FALCON_MAX_PAGE_SIZE
|
|
+
|
|
+#if PAGE_SIZE <= EFHW_MAX_PAGE_SIZE
|
|
+#define EFHW_NIC_PAGE_SIZE PAGE_SIZE
|
|
+#else
|
|
+#define EFHW_NIC_PAGE_SIZE EFHW_MAX_PAGE_SIZE
|
|
+#endif
|
|
+#define EFHW_NIC_PAGE_MASK (~(EFHW_NIC_PAGE_SIZE-1))
|
|
+
|
|
+#endif /* __CI_DRIVER_EFAB_HARDWARE_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/common.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,68 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides EtherFabric NIC hardware interface common
|
|
+ * definitions.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_DRIVER_EFAB_HARDWARE_COMMON_H__
|
|
+#define __CI_DRIVER_EFAB_HARDWARE_COMMON_H__
|
|
+
|
|
+/*----------------------------------------------------------------------------
|
|
+ *
|
|
+ * EtherFabric constants
|
|
+ *
|
|
+ *---------------------------------------------------------------------------*/
|
|
+
|
|
+#define EFHW_1K 0x00000400u
|
|
+#define EFHW_2K 0x00000800u
|
|
+#define EFHW_4K 0x00001000u
|
|
+#define EFHW_8K 0x00002000u
|
|
+#define EFHW_16K 0x00004000u
|
|
+#define EFHW_32K 0x00008000u
|
|
+#define EFHW_64K 0x00010000u
|
|
+#define EFHW_128K 0x00020000u
|
|
+#define EFHW_256K 0x00040000u
|
|
+#define EFHW_512K 0x00080000u
|
|
+#define EFHW_1M 0x00100000u
|
|
+#define EFHW_2M 0x00200000u
|
|
+#define EFHW_4M 0x00400000u
|
|
+#define EFHW_8M 0x00800000u
|
|
+#define EFHW_16M 0x01000000u
|
|
+#define EFHW_32M 0x02000000u
|
|
+#define EFHW_48M 0x03000000u
|
|
+#define EFHW_64M 0x04000000u
|
|
+#define EFHW_128M 0x08000000u
|
|
+#define EFHW_256M 0x10000000u
|
|
+#define EFHW_512M 0x20000000u
|
|
+#define EFHW_1G 0x40000000u
|
|
+#define EFHW_2G 0x80000000u
|
|
+#define EFHW_4G 0x100000000ULL
|
|
+#define EFHW_8G 0x200000000ULL
|
|
+
|
|
+#endif /* __CI_DRIVER_EFAB_HARDWARE_COMMON_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,422 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides EtherFabric NIC - EFXXXX (aka Falcon) specific
|
|
+ * definitions.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_DRIVER_EFAB_HARDWARE_FALCON_H__
|
|
+#define __CI_DRIVER_EFAB_HARDWARE_FALCON_H__
|
|
+
|
|
+/*----------------------------------------------------------------------------
|
|
+ * Compile options
|
|
+ *---------------------------------------------------------------------------*/
|
|
+
|
|
+/* Falcon has an 8K maximum page size. */
|
|
+#define FALCON_MAX_PAGE_SIZE EFHW_8K
|
|
+
|
|
+/* include the register definitions */
|
|
+#include <ci/driver/efab/hardware/falcon/falcon_core.h>
|
|
+#include <ci/driver/efab/hardware/falcon/falcon_desc.h>
|
|
+#include <ci/driver/efab/hardware/falcon/falcon_event.h>
|
|
+#include <ci/driver/efab/hardware/falcon/falcon_intr_vec.h>
|
|
+
|
|
+#define FALCON_DMA_TX_DESC_BYTES 8
|
|
+#define FALCON_DMA_RX_PHYS_DESC_BYTES 8
|
|
+#define FALCON_DMA_RX_BUF_DESC_BYTES 4
|
|
+
|
|
+
|
|
+/* ---- efhw_event_t helpers --- */
|
|
+
|
|
+#ifndef EFHW_IS_LITTLE_ENDIAN
|
|
+#error This needs lots of cpu_to_le64s() in
|
|
+#endif
|
|
+
|
|
+/*!\ TODO look at whether there is an efficiency gain to be had by
|
|
+ treating the event codes to 32bit masks as is done for EF1
|
|
+
|
|
+ These masks apply to the full 64 bits of the event to extract the
|
|
+ event code - followed by the common event codes to expect
|
|
+ */
|
|
+#define __FALCON_OPEN_MASK(WIDTH) ((((uint64_t)1) << (WIDTH)) - 1)
|
|
+#define FALCON_EVENT_CODE_MASK \
|
|
+ (__FALCON_OPEN_MASK(EV_CODE_WIDTH) << EV_CODE_LBN)
|
|
+#define FALCON_EVENT_EV_Q_ID_MASK \
|
|
+ (__FALCON_OPEN_MASK(DRIVER_EV_EVQ_ID_WIDTH) << DRIVER_EV_EVQ_ID_LBN)
|
|
+#define FALCON_EVENT_TX_FLUSH_Q_ID_MASK \
|
|
+ (__FALCON_OPEN_MASK(DRIVER_EV_TX_DESCQ_ID_WIDTH) << \
|
|
+ DRIVER_EV_TX_DESCQ_ID_LBN)
|
|
+#define FALCON_EVENT_RX_FLUSH_Q_ID_MASK \
|
|
+ (__FALCON_OPEN_MASK(DRIVER_EV_RX_DESCQ_ID_WIDTH) << \
|
|
+ DRIVER_EV_RX_DESCQ_ID_LBN)
|
|
+#define FALCON_EVENT_DRV_SUBCODE_MASK \
|
|
+ (__FALCON_OPEN_MASK(DRIVER_EV_SUB_CODE_WIDTH) << \
|
|
+ DRIVER_EV_SUB_CODE_LBN)
|
|
+
|
|
+#define FALCON_EVENT_FMT "[ev:%x:%08x:%08x]"
|
|
+#define FALCON_EVENT_PRI_ARG(e) \
|
|
+ ((unsigned)(((e).u64 & FALCON_EVENT_CODE_MASK) >> EV_CODE_LBN)), \
|
|
+ ((unsigned)((e).u64 >> 32)), ((unsigned)((e).u64 & 0xFFFFFFFF))
|
|
+
|
|
+#define FALCON_EVENT_CODE(evp) ((evp)->u64 & FALCON_EVENT_CODE_MASK)
|
|
+#define FALCON_EVENT_WAKE_EVQ_ID(evp) \
|
|
+ (((evp)->u64 & FALCON_EVENT_EV_Q_ID_MASK) >> DRIVER_EV_EVQ_ID_LBN)
|
|
+#define FALCON_EVENT_TX_FLUSH_Q_ID(evp) \
|
|
+ (((evp)->u64 & FALCON_EVENT_TX_FLUSH_Q_ID_MASK) >> \
|
|
+ DRIVER_EV_TX_DESCQ_ID_LBN)
|
|
+#define FALCON_EVENT_RX_FLUSH_Q_ID(evp) \
|
|
+ (((evp)->u64 & FALCON_EVENT_RX_FLUSH_Q_ID_MASK) >> \
|
|
+ DRIVER_EV_RX_DESCQ_ID_LBN)
|
|
+#define FALCON_EVENT_DRIVER_SUBCODE(evp) \
|
|
+ (((evp)->u64 & FALCON_EVENT_DRV_SUBCODE_MASK) >> \
|
|
+ DRIVER_EV_SUB_CODE_LBN)
|
|
+
|
|
+#define FALCON_EVENT_CODE_CHAR ((uint64_t)DRIVER_EV_DECODE << EV_CODE_LBN)
|
|
+#define FALCON_EVENT_CODE_SW ((uint64_t)DRV_GEN_EV_DECODE << EV_CODE_LBN)
|
|
+
|
|
+
|
|
+/* so this is the size in bytes of an awful lot of things */
|
|
+#define FALCON_REGISTER128 (16)
|
|
+
|
|
+/* we define some unique dummy values as a debug aid */
|
|
+#ifdef _WIN32
|
|
+#define FALCON_ATOMIC_BASE 0xdeadbeef00000000ui64
|
|
+#else
|
|
+#define FALCON_ATOMIC_BASE 0xdeadbeef00000000ULL
|
|
+#endif
|
|
+#define FALCON_ATOMIC_UPD_REG (FALCON_ATOMIC_BASE | 0x1)
|
|
+#define FALCON_ATOMIC_PTR_TBL_REG (FALCON_ATOMIC_BASE | 0x2)
|
|
+#define FALCON_ATOMIC_SRPM_UDP_EVQ_REG (FALCON_ATOMIC_BASE | 0x3)
|
|
+#define FALCON_ATOMIC_RX_FLUSH_DESCQ (FALCON_ATOMIC_BASE | 0x4)
|
|
+#define FALCON_ATOMIC_TX_FLUSH_DESCQ (FALCON_ATOMIC_BASE | 0x5)
|
|
+#define FALCON_ATOMIC_INT_EN_REG (FALCON_ATOMIC_BASE | 0x6)
|
|
+#define FALCON_ATOMIC_TIMER_CMD_REG (FALCON_ATOMIC_BASE | 0x7)
|
|
+#define FALCON_ATOMIC_PACE_REG (FALCON_ATOMIC_BASE | 0x8)
|
|
+#define FALCON_ATOMIC_INT_ACK_REG (FALCON_ATOMIC_BASE | 0x9)
|
|
+/* XXX It crashed with odd value in FALCON_ATOMIC_INT_ADR_REG */
|
|
+#define FALCON_ATOMIC_INT_ADR_REG (FALCON_ATOMIC_BASE | 0xa)
|
|
+
|
|
+/*----------------------------------------------------------------------------
|
|
+ *
|
|
+ * PCI control blocks for Falcon -
|
|
+ * (P) primary is for NET
|
|
+ * (S) secondary is for CHAR
|
|
+ *
|
|
+ *---------------------------------------------------------------------------*/
|
|
+
|
|
+#define FALCON_P_CTR_AP_BAR 2
|
|
+#define FALCON_S_CTR_AP_BAR 0
|
|
+#define FALCON_S_DEVID 0x6703
|
|
+
|
|
+
|
|
+/*----------------------------------------------------------------------------
|
|
+ *
|
|
+ * Falcon constants
|
|
+ *
|
|
+ *---------------------------------------------------------------------------*/
|
|
+
|
|
+/* Note: the following constants have moved to values in struct efhw_nic:
|
|
+ * FALCON_EVQ_TBL_NUM -> nic->num_evqs
|
|
+ * FALCON_DMAQ_NUM -> nic->num_dmaqs
|
|
+ * FALCON_TIMERS_NUM -> nic->num_times
|
|
+ * These replacement constants are used as sanity checks in assertions in
|
|
+ * certain functions that don't have access to struct efhw_nic.
|
|
+ */
|
|
+#define FALCON_DMAQ_NUM_SANITY (EFHW_4K)
|
|
+#define FALCON_EVQ_TBL_NUM_SANITY (EFHW_4K)
|
|
+#define FALCON_TIMERS_NUM_SANITY (EFHW_4K)
|
|
+
|
|
+/* This value is an upper limit on the total number of filter table
|
|
+ * entries. The actual size of filter table is determined at runtime, as
|
|
+ * it can vary.
|
|
+ */
|
|
+#define FALCON_FILTER_TBL_NUM (EFHW_8K)
|
|
+
|
|
+/* max number of buffers which can be pushed before commiting */
|
|
+#define FALCON_BUFFER_UPD_MAX (128)
|
|
+
|
|
+/* We can tell falcon to write its RX buffers in 32 byte quantums,
|
|
+ and since we pad packets 2 bytes to the right we can't use
|
|
+ a full page (not unless we use jumbo mode for all queues)
|
|
+
|
|
+ NOTE: tests/nic/dma.c assumes that the value here is the real NIC
|
|
+ value, so we explicitly round it down to the nearest 32 bytes */
|
|
+
|
|
+/* #define FALCON_RX_USR_BUF_SIZE round_down(4096-2,32) */
|
|
+#define FALCON_RX_USR_BUF_SIZE 4064
|
|
+
|
|
+#define FALCON_EVQ_RPTR_REG_P0 0x400
|
|
+
|
|
+/*----------------------------------------------------------------------------
|
|
+ *
|
|
+ * Falcon requires user-space descriptor pushes to be:
|
|
+ * dword[0-2]; wiob(); dword[3]
|
|
+ *
|
|
+ * Driver register access must be locked against other threads from
|
|
+ * the same driver but can be in any order: i.e dword[0-3]; wiob()
|
|
+ *
|
|
+ * The following helpers ensure that valid dword orderings are exercised
|
|
+ *
|
|
+ *---------------------------------------------------------------------------*/
|
|
+
|
|
+/* A union to allow writting 64bit values as 32bit values, without
|
|
+ * hitting the compilers aliasing rules. We hope the compiler optimises
|
|
+ * away the copy's anyway */
|
|
+union __u64to32 {
|
|
+ uint64_t u64;
|
|
+ struct {
|
|
+#ifdef EFHW_IS_LITTLE_ENDIAN
|
|
+ uint32_t a;
|
|
+ uint32_t b;
|
|
+#else
|
|
+ uint32_t b;
|
|
+ uint32_t a;
|
|
+#endif
|
|
+ } s;
|
|
+};
|
|
+
|
|
+static inline void
|
|
+falcon_write_ddd_d(volatile char __iomem *kva,
|
|
+ uint32_t d0, uint32_t d1, uint32_t d2, uint32_t d3)
|
|
+{
|
|
+ writel(d0, kva + 0);
|
|
+ writel(d1, kva + 4);
|
|
+ writel(d2, kva + 8);
|
|
+ mmiowb();
|
|
+ writel(d3, kva + 12);
|
|
+}
|
|
+
|
|
+static inline void falcon_write_q(volatile char __iomem *kva, uint64_t q)
|
|
+{
|
|
+ union __u64to32 u;
|
|
+ u.u64 = q;
|
|
+
|
|
+ writel(u.s.a, kva);
|
|
+ mmiowb();
|
|
+ writel(u.s.b, kva + 4);
|
|
+}
|
|
+
|
|
+static inline void falcon_read_q(volatile char __iomem *addr, uint64_t *q0)
|
|
+{
|
|
+ /* It is essential that we read dword0 first, so that
|
|
+ * the shadow register is updated with the latest value
|
|
+ * and we get a self consistent value.
|
|
+ */
|
|
+ union __u64to32 u;
|
|
+ u.s.a = readl(addr);
|
|
+ rmb();
|
|
+ u.s.b = readl(addr + 4);
|
|
+
|
|
+ *q0 = u.u64;
|
|
+}
|
|
+
|
|
+static inline void
|
|
+falcon_write_qq(volatile char __iomem *kva, uint64_t q0, uint64_t q1)
|
|
+{
|
|
+ writeq(q0, kva + 0);
|
|
+ falcon_write_q(kva + 8, q1);
|
|
+}
|
|
+
|
|
+static inline void
|
|
+falcon_read_qq(volatile char __iomem *addr, uint64_t *q0, uint64_t *q1)
|
|
+{
|
|
+ falcon_read_q(addr, q0);
|
|
+ *q1 = readq(addr + 8);
|
|
+}
|
|
+
|
|
+
|
|
+
|
|
+/*----------------------------------------------------------------------------
|
|
+ *
|
|
+ * Buffer virtual addresses (4K buffers)
|
|
+ *
|
|
+ *---------------------------------------------------------------------------*/
|
|
+
|
|
+/* Form a buffer virtual address from buffer ID and offset. If the offset
|
|
+** is larger than the buffer size, then the buffer indexed will be
|
|
+** calculated appropriately. It is the responsibility of the caller to
|
|
+** ensure that they have valid buffers programmed at that address.
|
|
+*/
|
|
+#define FALCON_VADDR_8K_S (13)
|
|
+#define FALCON_VADDR_4K_S (12)
|
|
+#define FALCON_VADDR_M 0xfffff /* post shift mask */
|
|
+
|
|
+#define FALCON_BUFFER_8K_ADDR(id, off) (((id) << FALCON_VADDR_8K_S) + (off))
|
|
+#define FALCON_BUFFER_8K_PAGE(vaddr) \
|
|
+ (((vaddr) >> FALCON_VADDR_8K_S) & FALCON_VADDR_M)
|
|
+#define FALCON_BUFFER_8K_OFF(vaddr) \
|
|
+ ((vaddr) & __FALCON_MASK32(FALCON_VADDR_8K_S))
|
|
+
|
|
+#define FALCON_BUFFER_4K_ADDR(id, off) (((id) << FALCON_VADDR_4K_S) + (off))
|
|
+#define FALCON_BUFFER_4K_PAGE(vaddr) \
|
|
+ (((vaddr) >> FALCON_VADDR_4K_S) & FALCON_VADDR_M)
|
|
+#define FALCON_BUFFER_4K_OFF(vaddr) \
|
|
+ ((vaddr) & __FALCON_MASK32(FALCON_VADDR_4K_S))
|
|
+
|
|
+/*----------------------------------------------------------------------------
|
|
+ *
|
|
+ * Timer helpers
|
|
+ *
|
|
+ *---------------------------------------------------------------------------*/
|
|
+
|
|
+static inline int falcon_timer_page_addr(uint idx)
|
|
+{
|
|
+
|
|
+ EFHW_ASSERT(TIMER_CMD_REG_KER_OFST ==
|
|
+ (TIMER_CMD_REG_PAGE4_OFST - 4 * EFHW_8K));
|
|
+
|
|
+ EFHW_ASSERT(idx < FALCON_TIMERS_NUM_SANITY);
|
|
+
|
|
+ if (idx < 4)
|
|
+ return TIMER_CMD_REG_KER_OFST + (idx * EFHW_8K);
|
|
+ else if (idx < 1024)
|
|
+ return TIMER_CMD_REG_PAGE4_OFST + ((idx - 4) * EFHW_8K);
|
|
+ else
|
|
+ return TIMER_CMD_REG_PAGE123K_OFST + ((idx - 1024) * EFHW_8K);
|
|
+}
|
|
+
|
|
+#define FALCON_TIMER_PAGE_MASK (EFHW_8K-1)
|
|
+
|
|
+static inline int falcon_timer_page_offset(uint idx)
|
|
+{
|
|
+ return falcon_timer_page_addr(idx) & FALCON_TIMER_PAGE_MASK;
|
|
+}
|
|
+
|
|
+/*----------------------------------------------------------------------------
|
|
+ *
|
|
+ * DMA Queue helpers
|
|
+ *
|
|
+ *---------------------------------------------------------------------------*/
|
|
+
|
|
+/* iSCSI queue for A1; see bug 5427 for more details. */
|
|
+#define FALCON_A1_ISCSI_DMAQ 4
|
|
+
|
|
+/*! returns an address within a bar of the TX DMA doorbell */
|
|
+static inline uint falcon_tx_dma_page_addr(uint dmaq_idx)
|
|
+{
|
|
+ uint page;
|
|
+
|
|
+ EFHW_ASSERT((((TX_DESC_UPD_REG_PAGE123K_OFST) & (EFHW_8K - 1)) ==
|
|
+ (((TX_DESC_UPD_REG_PAGE4_OFST) & (EFHW_8K - 1)))));
|
|
+
|
|
+ EFHW_ASSERT(dmaq_idx < FALCON_DMAQ_NUM_SANITY);
|
|
+
|
|
+ if (dmaq_idx < 1024)
|
|
+ page = TX_DESC_UPD_REG_PAGE4_OFST + ((dmaq_idx - 4) * EFHW_8K);
|
|
+ else
|
|
+ page =
|
|
+ TX_DESC_UPD_REG_PAGE123K_OFST +
|
|
+ ((dmaq_idx - 1024) * EFHW_8K);
|
|
+
|
|
+ return page;
|
|
+}
|
|
+
|
|
+/*! returns an address within a bar of the RX DMA doorbell */
|
|
+static inline uint falcon_rx_dma_page_addr(uint dmaq_idx)
|
|
+{
|
|
+ uint page;
|
|
+
|
|
+ EFHW_ASSERT((((RX_DESC_UPD_REG_PAGE123K_OFST) & (EFHW_8K - 1)) ==
|
|
+ ((RX_DESC_UPD_REG_PAGE4_OFST) & (EFHW_8K - 1))));
|
|
+
|
|
+ EFHW_ASSERT(dmaq_idx < FALCON_DMAQ_NUM_SANITY);
|
|
+
|
|
+ if (dmaq_idx < 1024)
|
|
+ page = RX_DESC_UPD_REG_PAGE4_OFST + ((dmaq_idx - 4) * EFHW_8K);
|
|
+ else
|
|
+ page =
|
|
+ RX_DESC_UPD_REG_PAGE123K_OFST +
|
|
+ ((dmaq_idx - 1024) * EFHW_8K);
|
|
+
|
|
+ return page;
|
|
+}
|
|
+
|
|
+/*! "page"=NIC-dependent register set size */
|
|
+#define FALCON_DMA_PAGE_MASK (EFHW_8K-1)
|
|
+
|
|
+/*! returns an address within a bar of the start of the "page"
|
|
+ containing the TX DMA doorbell */
|
|
+static inline int falcon_tx_dma_page_base(uint dma_idx)
|
|
+{
|
|
+ return falcon_tx_dma_page_addr(dma_idx) & ~FALCON_DMA_PAGE_MASK;
|
|
+}
|
|
+
|
|
+/*! returns an address within a bar of the start of the "page"
|
|
+ containing the RX DMA doorbell */
|
|
+static inline int falcon_rx_dma_page_base(uint dma_idx)
|
|
+{
|
|
+ return falcon_rx_dma_page_addr(dma_idx) & ~FALCON_DMA_PAGE_MASK;
|
|
+}
|
|
+
|
|
+/*! returns an offset within a "page" of the TX DMA doorbell */
|
|
+static inline int falcon_tx_dma_page_offset(uint dma_idx)
|
|
+{
|
|
+ return falcon_tx_dma_page_addr(dma_idx) & FALCON_DMA_PAGE_MASK;
|
|
+}
|
|
+
|
|
+/*! returns an offset within a "page" of the RX DMA doorbell */
|
|
+static inline int falcon_rx_dma_page_offset(uint dma_idx)
|
|
+{
|
|
+ return falcon_rx_dma_page_addr(dma_idx) & FALCON_DMA_PAGE_MASK;
|
|
+}
|
|
+
|
|
+/*----------------------------------------------------------------------------
|
|
+ *
|
|
+ * Events
|
|
+ *
|
|
+ *---------------------------------------------------------------------------*/
|
|
+
|
|
+/* Falcon nails down the event queue mappings */
|
|
+#define FALCON_EVQ_KERNEL0 (0) /* hardwired for net driver */
|
|
+#define FALCON_EVQ_CHAR (4) /* char driver's event queue */
|
|
+
|
|
+/* reserved by the drivers */
|
|
+#define FALCON_EVQ_TBL_RESERVED (8)
|
|
+
|
|
+/* default DMA-Q sizes */
|
|
+#define FALCON_DMA_Q_DEFAULT_TX_SIZE 512
|
|
+
|
|
+#define FALCON_DMA_Q_DEFAULT_RX_SIZE 512
|
|
+
|
|
+#define FALCON_DMA_Q_DEFAULT_MMAP \
|
|
+ (FALCON_DMA_Q_DEFAULT_TX_SIZE * (FALCON_DMA_TX_DESC_BYTES * 2))
|
|
+
|
|
+/*----------------------------------------------------------------------------
|
|
+ *
|
|
+ * DEBUG - Analyser trigger
|
|
+ *
|
|
+ *---------------------------------------------------------------------------*/
|
|
+
|
|
+static inline void
|
|
+falcon_deadbeef(volatile char __iomem *efhw_kva, unsigned what)
|
|
+{
|
|
+ writel(what, efhw_kva + 0x300);
|
|
+ mmiowb();
|
|
+}
|
|
+#endif /* __CI_DRIVER_EFAB_HARDWARE_FALCON_H__ */
|
|
+/*! \cidoxg_end */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon/falcon_core.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,1147 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides EtherFabric NIC - EFXXXX (aka Falcon) core register
|
|
+ * definitions.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#define FALCON_EXTENDED_P_BAR 1
|
|
+
|
|
+/*************---- Bus Interface Unit Registers C Header ----*************/
|
|
+#define IOM_IND_ADR_REG_OFST 0x0 /* IO-mapped indirect access address
|
|
+ register */
|
|
+ #define IOM_AUTO_ADR_INC_EN_LBN 16
|
|
+ #define IOM_AUTO_ADR_INC_EN_WIDTH 1
|
|
+ #define IOM_IND_ADR_LBN 0
|
|
+ #define IOM_IND_ADR_WIDTH 16
|
|
+#define IOM_IND_DAT_REG_OFST 0x4 /* IO-mapped indirect access data register */
|
|
+ #define IOM_IND_DAT_LBN 0
|
|
+ #define IOM_IND_DAT_WIDTH 32
|
|
+#define ADR_REGION_REG_KER_OFST 0x0 /* Address region register */
|
|
+#define ADR_REGION_REG_OFST 0x0 /* Address region register */
|
|
+ #define ADR_REGION3_LBN 96
|
|
+ #define ADR_REGION3_WIDTH 18
|
|
+ #define ADR_REGION2_LBN 64
|
|
+ #define ADR_REGION2_WIDTH 18
|
|
+ #define ADR_REGION1_LBN 32
|
|
+ #define ADR_REGION1_WIDTH 18
|
|
+ #define ADR_REGION0_LBN 0
|
|
+ #define ADR_REGION0_WIDTH 18
|
|
+#define INT_EN_REG_KER_OFST 0x10 /* Kernel driver Interrupt enable register */
|
|
+ #define KER_INT_CHAR_LBN 4
|
|
+ #define KER_INT_CHAR_WIDTH 1
|
|
+ #define KER_INT_KER_LBN 3
|
|
+ #define KER_INT_KER_WIDTH 1
|
|
+ #define ILL_ADR_ERR_INT_EN_KER_LBN 2
|
|
+ #define ILL_ADR_ERR_INT_EN_KER_WIDTH 1
|
|
+ #define SRM_PERR_INT_EN_KER_LBN 1
|
|
+ #define SRM_PERR_INT_EN_KER_WIDTH 1
|
|
+ #define DRV_INT_EN_KER_LBN 0
|
|
+ #define DRV_INT_EN_KER_WIDTH 1
|
|
+#define INT_EN_REG_CHAR_OFST 0x20 /* Char Driver interrupt enable register */
|
|
+ #define CHAR_INT_CHAR_LBN 4
|
|
+ #define CHAR_INT_CHAR_WIDTH 1
|
|
+ #define CHAR_INT_KER_LBN 3
|
|
+ #define CHAR_INT_KER_WIDTH 1
|
|
+ #define ILL_ADR_ERR_INT_EN_CHAR_LBN 2
|
|
+ #define ILL_ADR_ERR_INT_EN_CHAR_WIDTH 1
|
|
+ #define SRM_PERR_INT_EN_CHAR_LBN 1
|
|
+ #define SRM_PERR_INT_EN_CHAR_WIDTH 1
|
|
+ #define DRV_INT_EN_CHAR_LBN 0
|
|
+ #define DRV_INT_EN_CHAR_WIDTH 1
|
|
+#define INT_ADR_REG_KER_OFST 0x30 /* Interrupt host address for Kernel driver */
|
|
+ #define INT_ADR_KER_LBN 0
|
|
+ #define INT_ADR_KER_WIDTH 64
|
|
+ #define DRV_INT_KER_LBN 32
|
|
+ #define DRV_INT_KER_WIDTH 1
|
|
+ #define EV_FF_HALF_INT_KER_LBN 3
|
|
+ #define EV_FF_HALF_INT_KER_WIDTH 1
|
|
+ #define EV_FF_FULL_INT_KER_LBN 2
|
|
+ #define EV_FF_FULL_INT_KER_WIDTH 1
|
|
+ #define ILL_ADR_ERR_INT_KER_LBN 1
|
|
+ #define ILL_ADR_ERR_INT_KER_WIDTH 1
|
|
+ #define SRAM_PERR_INT_KER_LBN 0
|
|
+ #define SRAM_PERR_INT_KER_WIDTH 1
|
|
+#define INT_ADR_REG_CHAR_OFST 0x40 /* Interrupt host address for Char driver */
|
|
+ #define INT_ADR_CHAR_LBN 0
|
|
+ #define INT_ADR_CHAR_WIDTH 64
|
|
+ #define DRV_INT_CHAR_LBN 32
|
|
+ #define DRV_INT_CHAR_WIDTH 1
|
|
+ #define EV_FF_HALF_INT_CHAR_LBN 3
|
|
+ #define EV_FF_HALF_INT_CHAR_WIDTH 1
|
|
+ #define EV_FF_FULL_INT_CHAR_LBN 2
|
|
+ #define EV_FF_FULL_INT_CHAR_WIDTH 1
|
|
+ #define ILL_ADR_ERR_INT_CHAR_LBN 1
|
|
+ #define ILL_ADR_ERR_INT_CHAR_WIDTH 1
|
|
+ #define SRAM_PERR_INT_CHAR_LBN 0
|
|
+ #define SRAM_PERR_INT_CHAR_WIDTH 1
|
|
+#define INT_ISR0_B0_OFST 0x90 /* B0 only */
|
|
+#define INT_ISR1_B0_OFST 0xA0
|
|
+#define INT_ACK_REG_KER_A1_OFST 0x50 /* Kernel interrupt acknowledge register */
|
|
+ #define RESERVED_LBN 0
|
|
+ #define RESERVED_WIDTH 32
|
|
+#define INT_ACK_REG_CHAR_A1_OFST 0x60 /* CHAR interrupt acknowledge register */
|
|
+ #define RESERVED_LBN 0
|
|
+ #define RESERVED_WIDTH 32
|
|
+/*************---- Global CSR Registers C Header ----*************/
|
|
+#define NIC_STAT_REG_KER_OFST 0x200 /* ASIC strap status register */
|
|
+#define NIC_STAT_REG_OFST 0x200 /* ASIC strap status register */
|
|
+ #define ONCHIP_SRAM_LBN 16
|
|
+ #define ONCHIP_SRAM_WIDTH 0
|
|
+ #define STRAP_PINS_LBN 0
|
|
+ #define STRAP_PINS_WIDTH 3
|
|
+#define GPIO_CTL_REG_KER_OFST 0x210 /* GPIO control register */
|
|
+#define GPIO_CTL_REG_OFST 0x210 /* GPIO control register */
|
|
+ #define GPIO_OEN_LBN 24
|
|
+ #define GPIO_OEN_WIDTH 4
|
|
+ #define GPIO_OUT_LBN 16
|
|
+ #define GPIO_OUT_WIDTH 4
|
|
+ #define GPIO_IN_LBN 8
|
|
+ #define GPIO_IN_WIDTH 4
|
|
+ #define GPIO_PWRUP_VALUE_LBN 0
|
|
+ #define GPIO_PWRUP_VALUE_WIDTH 4
|
|
+#define GLB_CTL_REG_KER_OFST 0x220 /* Global control register */
|
|
+#define GLB_CTL_REG_OFST 0x220 /* Global control register */
|
|
+ #define SWRST_LBN 0
|
|
+ #define SWRST_WIDTH 1
|
|
+#define FATAL_INTR_REG_KER_OFST 0x230 /* Fatal interrupt register for Kernel */
|
|
+ #define PCI_BUSERR_INT_KER_EN_LBN 43
|
|
+ #define PCI_BUSERR_INT_KER_EN_WIDTH 1
|
|
+ #define SRAM_OOB_INT_KER_EN_LBN 42
|
|
+ #define SRAM_OOB_INT_KER_EN_WIDTH 1
|
|
+ #define BUFID_OOB_INT_KER_EN_LBN 41
|
|
+ #define BUFID_OOB_INT_KER_EN_WIDTH 1
|
|
+ #define MEM_PERR_INT_KER_EN_LBN 40
|
|
+ #define MEM_PERR_INT_KER_EN_WIDTH 1
|
|
+ #define RBUF_OWN_INT_KER_EN_LBN 39
|
|
+ #define RBUF_OWN_INT_KER_EN_WIDTH 1
|
|
+ #define TBUF_OWN_INT_KER_EN_LBN 38
|
|
+ #define TBUF_OWN_INT_KER_EN_WIDTH 1
|
|
+ #define RDESCQ_OWN_INT_KER_EN_LBN 37
|
|
+ #define RDESCQ_OWN_INT_KER_EN_WIDTH 1
|
|
+ #define TDESCQ_OWN_INT_KER_EN_LBN 36
|
|
+ #define TDESCQ_OWN_INT_KER_EN_WIDTH 1
|
|
+ #define EVQ_OWN_INT_KER_EN_LBN 35
|
|
+ #define EVQ_OWN_INT_KER_EN_WIDTH 1
|
|
+ #define EVFF_OFLO_INT_KER_EN_LBN 34
|
|
+ #define EVFF_OFLO_INT_KER_EN_WIDTH 1
|
|
+ #define ILL_ADR_INT_KER_EN_LBN 33
|
|
+ #define ILL_ADR_INT_KER_EN_WIDTH 1
|
|
+ #define SRM_PERR_INT_KER_EN_LBN 32
|
|
+ #define SRM_PERR_INT_KER_EN_WIDTH 1
|
|
+ #define PCI_BUSERR_INT_KER_LBN 11
|
|
+ #define PCI_BUSERR_INT_KER_WIDTH 1
|
|
+ #define SRAM_OOB_INT_KER_LBN 10
|
|
+ #define SRAM_OOB_INT_KER_WIDTH 1
|
|
+ #define BUFID_OOB_INT_KER_LBN 9
|
|
+ #define BUFID_OOB_INT_KER_WIDTH 1
|
|
+ #define MEM_PERR_INT_KER_LBN 8
|
|
+ #define MEM_PERR_INT_KER_WIDTH 1
|
|
+ #define RBUF_OWN_INT_KER_LBN 7
|
|
+ #define RBUF_OWN_INT_KER_WIDTH 1
|
|
+ #define TBUF_OWN_INT_KER_LBN 6
|
|
+ #define TBUF_OWN_INT_KER_WIDTH 1
|
|
+ #define RDESCQ_OWN_INT_KER_LBN 5
|
|
+ #define RDESCQ_OWN_INT_KER_WIDTH 1
|
|
+ #define TDESCQ_OWN_INT_KER_LBN 4
|
|
+ #define TDESCQ_OWN_INT_KER_WIDTH 1
|
|
+ #define EVQ_OWN_INT_KER_LBN 3
|
|
+ #define EVQ_OWN_INT_KER_WIDTH 1
|
|
+ #define EVFF_OFLO_INT_KER_LBN 2
|
|
+ #define EVFF_OFLO_INT_KER_WIDTH 1
|
|
+ #define ILL_ADR_INT_KER_LBN 1
|
|
+ #define ILL_ADR_INT_KER_WIDTH 1
|
|
+ #define SRM_PERR_INT_KER_LBN 0
|
|
+ #define SRM_PERR_INT_KER_WIDTH 1
|
|
+#define FATAL_INTR_REG_OFST 0x240 /* Fatal interrupt register for Char */
|
|
+ #define PCI_BUSERR_INT_CHAR_EN_LBN 43
|
|
+ #define PCI_BUSERR_INT_CHAR_EN_WIDTH 1
|
|
+ #define SRAM_OOB_INT_CHAR_EN_LBN 42
|
|
+ #define SRAM_OOB_INT_CHAR_EN_WIDTH 1
|
|
+ #define BUFID_OOB_INT_CHAR_EN_LBN 41
|
|
+ #define BUFID_OOB_INT_CHAR_EN_WIDTH 1
|
|
+ #define MEM_PERR_INT_CHAR_EN_LBN 40
|
|
+ #define MEM_PERR_INT_CHAR_EN_WIDTH 1
|
|
+ #define RBUF_OWN_INT_CHAR_EN_LBN 39
|
|
+ #define RBUF_OWN_INT_CHAR_EN_WIDTH 1
|
|
+ #define TBUF_OWN_INT_CHAR_EN_LBN 38
|
|
+ #define TBUF_OWN_INT_CHAR_EN_WIDTH 1
|
|
+ #define RDESCQ_OWN_INT_CHAR_EN_LBN 37
|
|
+ #define RDESCQ_OWN_INT_CHAR_EN_WIDTH 1
|
|
+ #define TDESCQ_OWN_INT_CHAR_EN_LBN 36
|
|
+ #define TDESCQ_OWN_INT_CHAR_EN_WIDTH 1
|
|
+ #define EVQ_OWN_INT_CHAR_EN_LBN 35
|
|
+ #define EVQ_OWN_INT_CHAR_EN_WIDTH 1
|
|
+ #define EVFF_OFLO_INT_CHAR_EN_LBN 34
|
|
+ #define EVFF_OFLO_INT_CHAR_EN_WIDTH 1
|
|
+ #define ILL_ADR_INT_CHAR_EN_LBN 33
|
|
+ #define ILL_ADR_INT_CHAR_EN_WIDTH 1
|
|
+ #define SRM_PERR_INT_CHAR_EN_LBN 32
|
|
+ #define SRM_PERR_INT_CHAR_EN_WIDTH 1
|
|
+ #define FATAL_INTR_REG_EN_BITS 0xffffffffffffffffULL
|
|
+ #define PCI_BUSERR_INT_CHAR_LBN 11
|
|
+ #define PCI_BUSERR_INT_CHAR_WIDTH 1
|
|
+ #define SRAM_OOB_INT_CHAR_LBN 10
|
|
+ #define SRAM_OOB_INT_CHAR_WIDTH 1
|
|
+ #define BUFID_OOB_INT_CHAR_LBN 9
|
|
+ #define BUFID_OOB_INT_CHAR_WIDTH 1
|
|
+ #define MEM_PERR_INT_CHAR_LBN 8
|
|
+ #define MEM_PERR_INT_CHAR_WIDTH 1
|
|
+ #define RBUF_OWN_INT_CHAR_LBN 7
|
|
+ #define RBUF_OWN_INT_CHAR_WIDTH 1
|
|
+ #define TBUF_OWN_INT_CHAR_LBN 6
|
|
+ #define TBUF_OWN_INT_CHAR_WIDTH 1
|
|
+ #define RDESCQ_OWN_INT_CHAR_LBN 5
|
|
+ #define RDESCQ_OWN_INT_CHAR_WIDTH 1
|
|
+ #define TDESCQ_OWN_INT_CHAR_LBN 4
|
|
+ #define TDESCQ_OWN_INT_CHAR_WIDTH 1
|
|
+ #define EVQ_OWN_INT_CHAR_LBN 3
|
|
+ #define EVQ_OWN_INT_CHAR_WIDTH 1
|
|
+ #define EVFF_OFLO_INT_CHAR_LBN 2
|
|
+ #define EVFF_OFLO_INT_CHAR_WIDTH 1
|
|
+ #define ILL_ADR_INT_CHAR_LBN 1
|
|
+ #define ILL_ADR_INT_CHAR_WIDTH 1
|
|
+ #define SRM_PERR_INT_CHAR_LBN 0
|
|
+ #define SRM_PERR_INT_CHAR_WIDTH 1
|
|
+#define DP_CTRL_REG_OFST 0x250 /* Datapath control register */
|
|
+ #define FLS_EVQ_ID_LBN 0
|
|
+ #define FLS_EVQ_ID_WIDTH 12
|
|
+#define MEM_STAT_REG_KER_OFST 0x260 /* Memory status register */
|
|
+#define MEM_STAT_REG_OFST 0x260 /* Memory status register */
|
|
+ #define MEM_PERR_VEC_LBN 53
|
|
+ #define MEM_PERR_VEC_WIDTH 38
|
|
+ #define MBIST_CORR_LBN 38
|
|
+ #define MBIST_CORR_WIDTH 15
|
|
+ #define MBIST_ERR_LBN 0
|
|
+ #define MBIST_ERR_WIDTH 38
|
|
+#define DEBUG_REG_KER_OFST 0x270 /* Debug register */
|
|
+#define DEBUG_REG_OFST 0x270 /* Debug register */
|
|
+ #define DEBUG_BLK_SEL2_LBN 47
|
|
+ #define DEBUG_BLK_SEL2_WIDTH 3
|
|
+ #define DEBUG_BLK_SEL1_LBN 44
|
|
+ #define DEBUG_BLK_SEL1_WIDTH 3
|
|
+ #define DEBUG_BLK_SEL0_LBN 41
|
|
+ #define DEBUG_BLK_SEL0_WIDTH 3
|
|
+ #define MISC_DEBUG_ADDR_LBN 36
|
|
+ #define MISC_DEBUG_ADDR_WIDTH 5
|
|
+ #define SERDES_DEBUG_ADDR_LBN 31
|
|
+ #define SERDES_DEBUG_ADDR_WIDTH 5
|
|
+ #define EM_DEBUG_ADDR_LBN 26
|
|
+ #define EM_DEBUG_ADDR_WIDTH 5
|
|
+ #define SR_DEBUG_ADDR_LBN 21
|
|
+ #define SR_DEBUG_ADDR_WIDTH 5
|
|
+ #define EV_DEBUG_ADDR_LBN 16
|
|
+ #define EV_DEBUG_ADDR_WIDTH 5
|
|
+ #define RX_DEBUG_ADDR_LBN 11
|
|
+ #define RX_DEBUG_ADDR_WIDTH 5
|
|
+ #define TX_DEBUG_ADDR_LBN 6
|
|
+ #define TX_DEBUG_ADDR_WIDTH 5
|
|
+ #define BIU_DEBUG_ADDR_LBN 1
|
|
+ #define BIU_DEBUG_ADDR_WIDTH 5
|
|
+ #define DEBUG_EN_LBN 0
|
|
+ #define DEBUG_EN_WIDTH 1
|
|
+#define DRIVER_REG0_KER_OFST 0x280 /* Driver scratch register 0 */
|
|
+#define DRIVER_REG0_OFST 0x280 /* Driver scratch register 0 */
|
|
+ #define DRIVER_DW0_LBN 0
|
|
+ #define DRIVER_DW0_WIDTH 32
|
|
+#define DRIVER_REG1_KER_OFST 0x290 /* Driver scratch register 1 */
|
|
+#define DRIVER_REG1_OFST 0x290 /* Driver scratch register 1 */
|
|
+ #define DRIVER_DW1_LBN 0
|
|
+ #define DRIVER_DW1_WIDTH 32
|
|
+#define DRIVER_REG2_KER_OFST 0x2A0 /* Driver scratch register 2 */
|
|
+#define DRIVER_REG2_OFST 0x2A0 /* Driver scratch register 2 */
|
|
+ #define DRIVER_DW2_LBN 0
|
|
+ #define DRIVER_DW2_WIDTH 32
|
|
+#define DRIVER_REG3_KER_OFST 0x2B0 /* Driver scratch register 3 */
|
|
+#define DRIVER_REG3_OFST 0x2B0 /* Driver scratch register 3 */
|
|
+ #define DRIVER_DW3_LBN 0
|
|
+ #define DRIVER_DW3_WIDTH 32
|
|
+#define DRIVER_REG4_KER_OFST 0x2C0 /* Driver scratch register 4 */
|
|
+#define DRIVER_REG4_OFST 0x2C0 /* Driver scratch register 4 */
|
|
+ #define DRIVER_DW4_LBN 0
|
|
+ #define DRIVER_DW4_WIDTH 32
|
|
+#define DRIVER_REG5_KER_OFST 0x2D0 /* Driver scratch register 5 */
|
|
+#define DRIVER_REG5_OFST 0x2D0 /* Driver scratch register 5 */
|
|
+ #define DRIVER_DW5_LBN 0
|
|
+ #define DRIVER_DW5_WIDTH 32
|
|
+#define DRIVER_REG6_KER_OFST 0x2E0 /* Driver scratch register 6 */
|
|
+#define DRIVER_REG6_OFST 0x2E0 /* Driver scratch register 6 */
|
|
+ #define DRIVER_DW6_LBN 0
|
|
+ #define DRIVER_DW6_WIDTH 32
|
|
+#define DRIVER_REG7_KER_OFST 0x2F0 /* Driver scratch register 7 */
|
|
+#define DRIVER_REG7_OFST 0x2F0 /* Driver scratch register 7 */
|
|
+ #define DRIVER_DW7_LBN 0
|
|
+ #define DRIVER_DW7_WIDTH 32
|
|
+#define ALTERA_BUILD_REG_OFST 0x300 /* Altera build register */
|
|
+#define ALTERA_BUILD_REG_OFST 0x300 /* Altera build register */
|
|
+ #define ALTERA_BUILD_VER_LBN 0
|
|
+ #define ALTERA_BUILD_VER_WIDTH 32
|
|
+
|
|
+/* so called CSR spare register
|
|
+ - contains separate parity enable bits for the various internal memory
|
|
+ blocks */
|
|
+#define MEM_PARITY_ERR_EN_REG_KER 0x310
|
|
+#define MEM_PARITY_ALL_BLOCKS_EN_LBN 64
|
|
+#define MEM_PARITY_ALL_BLOCKS_EN_WIDTH 38
|
|
+#define MEM_PARITY_TX_DATA_EN_LBN 72
|
|
+#define MEM_PARITY_TX_DATA_EN_WIDTH 2
|
|
+
|
|
+/*************---- Event & Timer Module Registers C Header ----*************/
|
|
+
|
|
+#if FALCON_EXTENDED_P_BAR
|
|
+#define EVQ_RPTR_REG_KER_OFST 0x11B00 /* Event queue read pointer register */
|
|
+#else
|
|
+#define EVQ_RPTR_REG_KER_OFST 0x1B00 /* Event queue read pointer register */
|
|
+#endif
|
|
+
|
|
+#define EVQ_RPTR_REG_OFST 0xFA0000 /* Event queue read pointer register
|
|
+ array. */
|
|
+ #define EVQ_RPTR_LBN 0
|
|
+ #define EVQ_RPTR_WIDTH 15
|
|
+
|
|
+#if FALCON_EXTENDED_P_BAR
|
|
+#define EVQ_PTR_TBL_KER_OFST 0x11A00 /* Event queue pointer table for kernel
|
|
+ access */
|
|
+#else
|
|
+#define EVQ_PTR_TBL_KER_OFST 0x1A00 /* Event queue pointer table for kernel
|
|
+ access */
|
|
+#endif
|
|
+
|
|
+#define EVQ_PTR_TBL_CHAR_OFST 0xF60000 /* Event queue pointer table for char
|
|
+ direct access */
|
|
+ #define EVQ_WKUP_OR_INT_EN_LBN 39
|
|
+ #define EVQ_WKUP_OR_INT_EN_WIDTH 1
|
|
+ #define EVQ_NXT_WPTR_LBN 24
|
|
+ #define EVQ_NXT_WPTR_WIDTH 15
|
|
+ #define EVQ_EN_LBN 23
|
|
+ #define EVQ_EN_WIDTH 1
|
|
+ #define EVQ_SIZE_LBN 20
|
|
+ #define EVQ_SIZE_WIDTH 3
|
|
+ #define EVQ_BUF_BASE_ID_LBN 0
|
|
+ #define EVQ_BUF_BASE_ID_WIDTH 20
|
|
+#define TIMER_CMD_REG_KER_OFST 0x420 /* Timer table for kernel access.
|
|
+ Page-mapped */
|
|
+#define TIMER_CMD_REG_PAGE4_OFST 0x8420 /* Timer table for user-level access.
|
|
+ Page-mapped. For lowest 1K queues.
|
|
+ */
|
|
+#define TIMER_CMD_REG_PAGE123K_OFST 0x1000420 /* Timer table for user-level
|
|
+ access. Page-mapped.
|
|
+ For upper 3K queues. */
|
|
+#define TIMER_TBL_OFST 0xF70000 /* Timer table for char driver direct access */
|
|
+ #define TIMER_MODE_LBN 12
|
|
+ #define TIMER_MODE_WIDTH 2
|
|
+ #define TIMER_VAL_LBN 0
|
|
+ #define TIMER_VAL_WIDTH 12
|
|
+ #define TIMER_MODE_INT_HLDOFF 2
|
|
+ #define EVQ_BUF_SIZE_LBN 0
|
|
+ #define EVQ_BUF_SIZE_WIDTH 1
|
|
+#define DRV_EV_REG_KER_OFST 0x440 /* Driver generated event register */
|
|
+#define DRV_EV_REG_OFST 0x440 /* Driver generated event register */
|
|
+ #define DRV_EV_QID_LBN 64
|
|
+ #define DRV_EV_QID_WIDTH 12
|
|
+ #define DRV_EV_DATA_LBN 0
|
|
+ #define DRV_EV_DATA_WIDTH 64
|
|
+#define EVQ_CTL_REG_KER_OFST 0x450 /* Event queue control register */
|
|
+#define EVQ_CTL_REG_OFST 0x450 /* Event queue control register */
|
|
+ #define RX_EVQ_WAKEUP_MASK_B0_LBN 15
|
|
+ #define RX_EVQ_WAKEUP_MASK_B0_WIDTH 6
|
|
+ #define EVQ_OWNERR_CTL_LBN 14
|
|
+ #define EVQ_OWNERR_CTL_WIDTH 1
|
|
+ #define EVQ_FIFO_AF_TH_LBN 8
|
|
+ #define EVQ_FIFO_AF_TH_WIDTH 6
|
|
+ #define EVQ_FIFO_NOTAF_TH_LBN 0
|
|
+ #define EVQ_FIFO_NOTAF_TH_WIDTH 6
|
|
+/*************---- SRAM Module Registers C Header ----*************/
|
|
+#define BUF_TBL_CFG_REG_KER_OFST 0x600 /* Buffer table configuration register */
|
|
+#define BUF_TBL_CFG_REG_OFST 0x600 /* Buffer table configuration register */
|
|
+ #define BUF_TBL_MODE_LBN 3
|
|
+ #define BUF_TBL_MODE_WIDTH 1
|
|
+#define SRM_RX_DC_CFG_REG_KER_OFST 0x610 /* SRAM receive descriptor cache
|
|
+ configuration register */
|
|
+#define SRM_RX_DC_CFG_REG_OFST 0x610 /* SRAM receive descriptor cache
|
|
+ configuration register */
|
|
+ #define SRM_RX_DC_BASE_ADR_LBN 0
|
|
+ #define SRM_RX_DC_BASE_ADR_WIDTH 21
|
|
+#define SRM_TX_DC_CFG_REG_KER_OFST 0x620 /* SRAM transmit descriptor cache
|
|
+ configuration register */
|
|
+#define SRM_TX_DC_CFG_REG_OFST 0x620 /* SRAM transmit descriptor cache
|
|
+ configuration register */
|
|
+ #define SRM_TX_DC_BASE_ADR_LBN 0
|
|
+ #define SRM_TX_DC_BASE_ADR_WIDTH 21
|
|
+#define SRM_CFG_REG_KER_OFST 0x630 /* SRAM configuration register */
|
|
+#define SRM_CFG_REG_OFST 0x630 /* SRAM configuration register */
|
|
+ #define SRAM_OOB_ADR_INTEN_LBN 5
|
|
+ #define SRAM_OOB_ADR_INTEN_WIDTH 1
|
|
+ #define SRAM_OOB_BUF_INTEN_LBN 4
|
|
+ #define SRAM_OOB_BUF_INTEN_WIDTH 1
|
|
+ #define SRAM_BT_INIT_EN_LBN 3
|
|
+ #define SRAM_BT_INIT_EN_WIDTH 1
|
|
+ #define SRM_NUM_BANK_LBN 2
|
|
+ #define SRM_NUM_BANK_WIDTH 1
|
|
+ #define SRM_BANK_SIZE_LBN 0
|
|
+ #define SRM_BANK_SIZE_WIDTH 2
|
|
+#define BUF_TBL_UPD_REG_KER_OFST 0x650 /* Buffer table update register */
|
|
+#define BUF_TBL_UPD_REG_OFST 0x650 /* Buffer table update register */
|
|
+ #define BUF_UPD_CMD_LBN 63
|
|
+ #define BUF_UPD_CMD_WIDTH 1
|
|
+ #define BUF_CLR_CMD_LBN 62
|
|
+ #define BUF_CLR_CMD_WIDTH 1
|
|
+ #define BUF_CLR_END_ID_LBN 32
|
|
+ #define BUF_CLR_END_ID_WIDTH 20
|
|
+ #define BUF_CLR_START_ID_LBN 0
|
|
+ #define BUF_CLR_START_ID_WIDTH 20
|
|
+#define SRM_UPD_EVQ_REG_KER_OFST 0x660 /* Buffer table update register */
|
|
+#define SRM_UPD_EVQ_REG_OFST 0x660 /* Buffer table update register */
|
|
+ #define SRM_UPD_EVQ_ID_LBN 0
|
|
+ #define SRM_UPD_EVQ_ID_WIDTH 12
|
|
+#define SRAM_PARITY_REG_KER_OFST 0x670 /* SRAM parity register. */
|
|
+#define SRAM_PARITY_REG_OFST 0x670 /* SRAM parity register. */
|
|
+ #define FORCE_SRAM_PERR_LBN 0
|
|
+ #define FORCE_SRAM_PERR_WIDTH 1
|
|
+
|
|
+#if FALCON_EXTENDED_P_BAR
|
|
+#define BUF_HALF_TBL_KER_OFST 0x18000 /* Buffer table in half buffer table
|
|
+ mode direct access by kernel driver */
|
|
+#else
|
|
+#define BUF_HALF_TBL_KER_OFST 0x8000 /* Buffer table in half buffer table
|
|
+ mode direct access by kernel driver */
|
|
+#endif
|
|
+
|
|
+
|
|
+#define BUF_HALF_TBL_OFST 0x800000 /* Buffer table in half buffer table mode
|
|
+ direct access by char driver */
|
|
+ #define BUF_ADR_HBUF_ODD_LBN 44
|
|
+ #define BUF_ADR_HBUF_ODD_WIDTH 20
|
|
+ #define BUF_OWNER_ID_HBUF_ODD_LBN 32
|
|
+ #define BUF_OWNER_ID_HBUF_ODD_WIDTH 12
|
|
+ #define BUF_ADR_HBUF_EVEN_LBN 12
|
|
+ #define BUF_ADR_HBUF_EVEN_WIDTH 20
|
|
+ #define BUF_OWNER_ID_HBUF_EVEN_LBN 0
|
|
+ #define BUF_OWNER_ID_HBUF_EVEN_WIDTH 12
|
|
+
|
|
+
|
|
+#if FALCON_EXTENDED_P_BAR
|
|
+#define BUF_FULL_TBL_KER_OFST 0x18000 /* Buffer table in full buffer table
|
|
+ mode direct access by kernel driver */
|
|
+#else
|
|
+#define BUF_FULL_TBL_KER_OFST 0x8000 /* Buffer table in full buffer table mode
|
|
+ direct access by kernel driver */
|
|
+#endif
|
|
+
|
|
+
|
|
+
|
|
+
|
|
+#define BUF_FULL_TBL_OFST 0x800000 /* Buffer table in full buffer table mode
|
|
+ direct access by char driver */
|
|
+ #define IP_DAT_BUF_SIZE_LBN 50
|
|
+ #define IP_DAT_BUF_SIZE_WIDTH 1
|
|
+ #define BUF_ADR_REGION_LBN 48
|
|
+ #define BUF_ADR_REGION_WIDTH 2
|
|
+ #define BUF_ADR_FBUF_LBN 14
|
|
+ #define BUF_ADR_FBUF_WIDTH 34
|
|
+ #define BUF_OWNER_ID_FBUF_LBN 0
|
|
+ #define BUF_OWNER_ID_FBUF_WIDTH 14
|
|
+#define SRM_DBG_REG_OFST 0x3000000 /* SRAM debug access */
|
|
+ #define SRM_DBG_LBN 0
|
|
+ #define SRM_DBG_WIDTH 64
|
|
+/*************---- RX Datapath Registers C Header ----*************/
|
|
+
|
|
+#define RX_CFG_REG_KER_OFST 0x800 /* Receive configuration register */
|
|
+#define RX_CFG_REG_OFST 0x800 /* Receive configuration register */
|
|
+
|
|
+#if !defined(FALCON_64K_RXFIFO) && !defined(FALCON_PRE_02020029)
|
|
+# if !defined(FALCON_128K_RXFIFO)
|
|
+# define FALCON_128K_RXFIFO
|
|
+# endif
|
|
+#endif
|
|
+
|
|
+#if defined(FALCON_128K_RXFIFO)
|
|
+
|
|
+/* new for B0 */
|
|
+ #define RX_TOEP_TCP_SUPPRESS_B0_LBN 48
|
|
+ #define RX_TOEP_TCP_SUPPRESS_B0_WIDTH 1
|
|
+ #define RX_INGR_EN_B0_LBN 47
|
|
+ #define RX_INGR_EN_B0_WIDTH 1
|
|
+ #define RX_TOEP_IPV4_B0_LBN 46
|
|
+ #define RX_TOEP_IPV4_B0_WIDTH 1
|
|
+ #define RX_HASH_ALG_B0_LBN 45
|
|
+ #define RX_HASH_ALG_B0_WIDTH 1
|
|
+ #define RX_HASH_INSERT_HDR_B0_LBN 44
|
|
+ #define RX_HASH_INSERT_HDR_B0_WIDTH 1
|
|
+/* moved for B0 */
|
|
+ #define RX_DESC_PUSH_EN_B0_LBN 43
|
|
+ #define RX_DESC_PUSH_EN_B0_WIDTH 1
|
|
+ #define RX_RDW_PATCH_EN_LBN 42 /* Non head of line blocking */
|
|
+ #define RX_RDW_PATCH_EN_WIDTH 1
|
|
+ #define RX_PCI_BURST_SIZE_B0_LBN 39
|
|
+ #define RX_PCI_BURST_SIZE_B0_WIDTH 3
|
|
+ #define RX_OWNERR_CTL_B0_LBN 38
|
|
+ #define RX_OWNERR_CTL_B0_WIDTH 1
|
|
+ #define RX_XON_TX_TH_B0_LBN 33
|
|
+ #define RX_XON_TX_TH_B0_WIDTH 5
|
|
+ #define RX_XOFF_TX_TH_B0_LBN 28
|
|
+ #define RX_XOFF_TX_TH_B0_WIDTH 5
|
|
+ #define RX_USR_BUF_SIZE_B0_LBN 19
|
|
+ #define RX_USR_BUF_SIZE_B0_WIDTH 9
|
|
+ #define RX_XON_MAC_TH_B0_LBN 10
|
|
+ #define RX_XON_MAC_TH_B0_WIDTH 9
|
|
+ #define RX_XOFF_MAC_TH_B0_LBN 1
|
|
+ #define RX_XOFF_MAC_TH_B0_WIDTH 9
|
|
+ #define RX_XOFF_MAC_EN_B0_LBN 0
|
|
+ #define RX_XOFF_MAC_EN_B0_WIDTH 1
|
|
+
|
|
+#elif !defined(FALCON_PRE_02020029)
|
|
+/* new for B0 */
|
|
+ #define RX_TOEP_TCP_SUPPRESS_B0_LBN 46
|
|
+ #define RX_TOEP_TCP_SUPPRESS_B0_WIDTH 1
|
|
+ #define RX_INGR_EN_B0_LBN 45
|
|
+ #define RX_INGR_EN_B0_WIDTH 1
|
|
+ #define RX_TOEP_IPV4_B0_LBN 44
|
|
+ #define RX_TOEP_IPV4_B0_WIDTH 1
|
|
+ #define RX_HASH_ALG_B0_LBN 43
|
|
+ #define RX_HASH_ALG_B0_WIDTH 41
|
|
+ #define RX_HASH_INSERT_HDR_B0_LBN 42
|
|
+ #define RX_HASH_INSERT_HDR_B0_WIDTH 1
|
|
+/* moved for B0 */
|
|
+ #define RX_DESC_PUSH_EN_B0_LBN 41
|
|
+ #define RX_DESC_PUSH_EN_B0_WIDTH 1
|
|
+ #define RX_PCI_BURST_SIZE_B0_LBN 37
|
|
+ #define RX_PCI_BURST_SIZE_B0_WIDTH 3
|
|
+ #define RX_OWNERR_CTL_B0_LBN 36
|
|
+ #define RX_OWNERR_CTL_B0_WIDTH 1
|
|
+ #define RX_XON_TX_TH_B0_LBN 31
|
|
+ #define RX_XON_TX_TH_B0_WIDTH 5
|
|
+ #define RX_XOFF_TX_TH_B0_LBN 26
|
|
+ #define RX_XOFF_TX_TH_B0_WIDTH 5
|
|
+ #define RX_USR_BUF_SIZE_B0_LBN 17
|
|
+ #define RX_USR_BUF_SIZE_B0_WIDTH 9
|
|
+ #define RX_XON_MAC_TH_B0_LBN 9
|
|
+ #define RX_XON_MAC_TH_B0_WIDTH 8
|
|
+ #define RX_XOFF_MAC_TH_B0_LBN 1
|
|
+ #define RX_XOFF_MAC_TH_B0_WIDTH 8
|
|
+ #define RX_XOFF_MAC_EN_B0_LBN 0
|
|
+ #define RX_XOFF_MAC_EN_B0_WIDTH 1
|
|
+
|
|
+#else
|
|
+/* new for B0 */
|
|
+ #define RX_TOEP_TCP_SUPPRESS_B0_LBN 44
|
|
+ #define RX_TOEP_TCP_SUPPRESS_B0_WIDTH 1
|
|
+ #define RX_INGR_EN_B0_LBN 43
|
|
+ #define RX_INGR_EN_B0_WIDTH 1
|
|
+ #define RX_TOEP_IPV4_B0_LBN 42
|
|
+ #define RX_TOEP_IPV4_B0_WIDTH 1
|
|
+ #define RX_HASH_ALG_B0_LBN 41
|
|
+ #define RX_HASH_ALG_B0_WIDTH 41
|
|
+ #define RX_HASH_INSERT_HDR_B0_LBN 40
|
|
+ #define RX_HASH_INSERT_HDR_B0_WIDTH 1
|
|
+/* moved for B0 */
|
|
+ #define RX_DESC_PUSH_EN_B0_LBN 35
|
|
+ #define RX_DESC_PUSH_EN_B0_WIDTH 1
|
|
+ #define RX_PCI_BURST_SIZE_B0_LBN 35
|
|
+ #define RX_PCI_BURST_SIZE_B0_WIDTH 2
|
|
+ #define RX_OWNERR_CTL_B0_LBN 34
|
|
+ #define RX_OWNERR_CTL_B0_WIDTH 1
|
|
+ #define RX_XON_TX_TH_B0_LBN 29
|
|
+ #define RX_XON_TX_TH_B0_WIDTH 5
|
|
+ #define RX_XOFF_TX_TH_B0_LBN 24
|
|
+ #define RX_XOFF_TX_TH_B0_WIDTH 5
|
|
+ #define RX_USR_BUF_SIZE_B0_LBN 15
|
|
+ #define RX_USR_BUF_SIZE_B0_WIDTH 9
|
|
+ #define RX_XON_MAC_TH_B0_LBN 8
|
|
+ #define RX_XON_MAC_TH_B0_WIDTH 7
|
|
+ #define RX_XOFF_MAC_TH_B0_LBN 1
|
|
+ #define RX_XOFF_MAC_TH_B0_WIDTH 7
|
|
+ #define RX_XOFF_MAC_EN_B0_LBN 0
|
|
+ #define RX_XOFF_MAC_EN_B0_WIDTH 1
|
|
+
|
|
+#endif
|
|
+
|
|
+/* A0/A1 */
|
|
+ #define RX_PUSH_EN_A1_LBN 35
|
|
+ #define RX_PUSH_EN_A1_WIDTH 1
|
|
+ #define RX_PCI_BURST_SIZE_A1_LBN 31
|
|
+ #define RX_PCI_BURST_SIZE_A1_WIDTH 3
|
|
+ #define RX_OWNERR_CTL_A1_LBN 30
|
|
+ #define RX_OWNERR_CTL_A1_WIDTH 1
|
|
+ #define RX_XON_TX_TH_A1_LBN 25
|
|
+ #define RX_XON_TX_TH_A1_WIDTH 5
|
|
+ #define RX_XOFF_TX_TH_A1_LBN 20
|
|
+ #define RX_XOFF_TX_TH_A1_WIDTH 5
|
|
+ #define RX_USR_BUF_SIZE_A1_LBN 11
|
|
+ #define RX_USR_BUF_SIZE_A1_WIDTH 9
|
|
+ #define RX_XON_MAC_TH_A1_LBN 6
|
|
+ #define RX_XON_MAC_TH_A1_WIDTH 5
|
|
+ #define RX_XOFF_MAC_TH_A1_LBN 1
|
|
+ #define RX_XOFF_MAC_TH_A1_WIDTH 5
|
|
+ #define RX_XOFF_MAC_EN_A1_LBN 0
|
|
+ #define RX_XOFF_MAC_EN_A1_WIDTH 1
|
|
+
|
|
+#define RX_FILTER_CTL_REG_OFST 0x810 /* Receive filter control registers */
|
|
+ #define SCATTER_ENBL_NO_MATCH_Q_B0_LBN 40
|
|
+ #define SCATTER_ENBL_NO_MATCH_Q_B0_WIDTH 1
|
|
+ #define UDP_FULL_SRCH_LIMIT_LBN 32
|
|
+ #define UDP_FULL_SRCH_LIMIT_WIDTH 8
|
|
+ #define NUM_KER_LBN 24
|
|
+ #define NUM_KER_WIDTH 2
|
|
+ #define UDP_WILD_SRCH_LIMIT_LBN 16
|
|
+ #define UDP_WILD_SRCH_LIMIT_WIDTH 8
|
|
+ #define TCP_WILD_SRCH_LIMIT_LBN 8
|
|
+ #define TCP_WILD_SRCH_LIMIT_WIDTH 8
|
|
+ #define TCP_FULL_SRCH_LIMIT_LBN 0
|
|
+ #define TCP_FULL_SRCH_LIMIT_WIDTH 8
|
|
+#define RX_FLUSH_DESCQ_REG_KER_OFST 0x820 /* Receive flush descriptor queue
|
|
+ register */
|
|
+#define RX_FLUSH_DESCQ_REG_OFST 0x820 /* Receive flush descriptor queue
|
|
+ register */
|
|
+ #define RX_FLUSH_DESCQ_CMD_LBN 24
|
|
+ #define RX_FLUSH_DESCQ_CMD_WIDTH 1
|
|
+ #define RX_FLUSH_EVQ_ID_LBN 12
|
|
+ #define RX_FLUSH_EVQ_ID_WIDTH 12
|
|
+ #define RX_FLUSH_DESCQ_LBN 0
|
|
+ #define RX_FLUSH_DESCQ_WIDTH 12
|
|
+#define RX_DESC_UPD_REG_KER_OFST 0x830 /* Kernel receive descriptor update
|
|
+ register. Page-mapped */
|
|
+#define RX_DESC_UPD_REG_PAGE4_OFST 0x8830 /* Char & user receive descriptor
|
|
+ update register. Page-mapped.
|
|
+ For lowest 1K queues. */
|
|
+#define RX_DESC_UPD_REG_PAGE123K_OFST 0x1000830 /* Char & user receive
|
|
+ descriptor update register.
|
|
+ Page-mapped. For upper
|
|
+ 3K queues. */
|
|
+ #define RX_DESC_WPTR_LBN 96
|
|
+ #define RX_DESC_WPTR_WIDTH 12
|
|
+ #define RX_DESC_PUSH_CMD_LBN 95
|
|
+ #define RX_DESC_PUSH_CMD_WIDTH 1
|
|
+ #define RX_DESC_LBN 0
|
|
+ #define RX_DESC_WIDTH 64
|
|
+ #define RX_KER_DESC_LBN 0
|
|
+ #define RX_KER_DESC_WIDTH 64
|
|
+ #define RX_USR_DESC_LBN 0
|
|
+ #define RX_USR_DESC_WIDTH 32
|
|
+#define RX_DC_CFG_REG_KER_OFST 0x840 /* Receive descriptor cache
|
|
+ configuration register */
|
|
+#define RX_DC_CFG_REG_OFST 0x840 /* Receive descriptor cache
|
|
+ configuration register */
|
|
+ #define RX_DC_SIZE_LBN 0
|
|
+ #define RX_DC_SIZE_WIDTH 2
|
|
+#define RX_DC_PF_WM_REG_KER_OFST 0x850 /* Receive descriptor cache pre-fetch
|
|
+ watermark register */
|
|
+#define RX_DC_PF_WM_REG_OFST 0x850 /* Receive descriptor cache pre-fetch
|
|
+ watermark register */
|
|
+ #define RX_DC_PF_LWM_LO_LBN 0
|
|
+ #define RX_DC_PF_LWM_LO_WIDTH 6
|
|
+
|
|
+#define RX_RSS_TKEY_B0_OFST 0x860 /* RSS Toeplitz hash key (B0 only) */
|
|
+
|
|
+#define RX_NODESC_DROP_REG 0x880
|
|
+ #define RX_NODESC_DROP_CNT_LBN 0
|
|
+ #define RX_NODESC_DROP_CNT_WIDTH 16
|
|
+
|
|
+#define XM_TX_CFG_REG_OFST 0x1230
|
|
+ #define XM_AUTO_PAD_LBN 5
|
|
+ #define XM_AUTO_PAD_WIDTH 1
|
|
+
|
|
+#define RX_FILTER_TBL0_OFST 0xF00000 /* Receive filter table - even entries */
|
|
+ #define RSS_EN_0_B0_LBN 110
|
|
+ #define RSS_EN_0_B0_WIDTH 1
|
|
+ #define SCATTER_EN_0_B0_LBN 109
|
|
+ #define SCATTER_EN_0_B0_WIDTH 1
|
|
+ #define TCP_UDP_0_LBN 108
|
|
+ #define TCP_UDP_0_WIDTH 1
|
|
+ #define RXQ_ID_0_LBN 96
|
|
+ #define RXQ_ID_0_WIDTH 12
|
|
+ #define DEST_IP_0_LBN 64
|
|
+ #define DEST_IP_0_WIDTH 32
|
|
+ #define DEST_PORT_TCP_0_LBN 48
|
|
+ #define DEST_PORT_TCP_0_WIDTH 16
|
|
+ #define SRC_IP_0_LBN 16
|
|
+ #define SRC_IP_0_WIDTH 32
|
|
+ #define SRC_TCP_DEST_UDP_0_LBN 0
|
|
+ #define SRC_TCP_DEST_UDP_0_WIDTH 16
|
|
+#define RX_FILTER_TBL1_OFST 0xF00010 /* Receive filter table - odd entries */
|
|
+ #define RSS_EN_1_B0_LBN 110
|
|
+ #define RSS_EN_1_B0_WIDTH 1
|
|
+ #define SCATTER_EN_1_B0_LBN 109
|
|
+ #define SCATTER_EN_1_B0_WIDTH 1
|
|
+ #define TCP_UDP_1_LBN 108
|
|
+ #define TCP_UDP_1_WIDTH 1
|
|
+ #define RXQ_ID_1_LBN 96
|
|
+ #define RXQ_ID_1_WIDTH 12
|
|
+ #define DEST_IP_1_LBN 64
|
|
+ #define DEST_IP_1_WIDTH 32
|
|
+ #define DEST_PORT_TCP_1_LBN 48
|
|
+ #define DEST_PORT_TCP_1_WIDTH 16
|
|
+ #define SRC_IP_1_LBN 16
|
|
+ #define SRC_IP_1_WIDTH 32
|
|
+ #define SRC_TCP_DEST_UDP_1_LBN 0
|
|
+ #define SRC_TCP_DEST_UDP_1_WIDTH 16
|
|
+
|
|
+#if FALCON_EXTENDED_P_BAR
|
|
+#define RX_DESC_PTR_TBL_KER_OFST 0x11800 /* Receive descriptor pointer
|
|
+ kernel access */
|
|
+#else
|
|
+#define RX_DESC_PTR_TBL_KER_OFST 0x1800 /* Receive descriptor pointer
|
|
+ kernel access */
|
|
+#endif
|
|
+
|
|
+
|
|
+#define RX_DESC_PTR_TBL_OFST 0xF40000 /* Receive descriptor pointer table */
|
|
+ #define RX_ISCSI_DDIG_EN_LBN 88
|
|
+ #define RX_ISCSI_DDIG_EN_WIDTH 1
|
|
+ #define RX_ISCSI_HDIG_EN_LBN 87
|
|
+ #define RX_ISCSI_HDIG_EN_WIDTH 1
|
|
+ #define RX_DESC_PREF_ACT_LBN 86
|
|
+ #define RX_DESC_PREF_ACT_WIDTH 1
|
|
+ #define RX_DC_HW_RPTR_LBN 80
|
|
+ #define RX_DC_HW_RPTR_WIDTH 6
|
|
+ #define RX_DESCQ_HW_RPTR_LBN 68
|
|
+ #define RX_DESCQ_HW_RPTR_WIDTH 12
|
|
+ #define RX_DESCQ_SW_WPTR_LBN 56
|
|
+ #define RX_DESCQ_SW_WPTR_WIDTH 12
|
|
+ #define RX_DESCQ_BUF_BASE_ID_LBN 36
|
|
+ #define RX_DESCQ_BUF_BASE_ID_WIDTH 20
|
|
+ #define RX_DESCQ_EVQ_ID_LBN 24
|
|
+ #define RX_DESCQ_EVQ_ID_WIDTH 12
|
|
+ #define RX_DESCQ_OWNER_ID_LBN 10
|
|
+ #define RX_DESCQ_OWNER_ID_WIDTH 14
|
|
+ #define RX_DESCQ_LABEL_LBN 5
|
|
+ #define RX_DESCQ_LABEL_WIDTH 5
|
|
+ #define RX_DESCQ_SIZE_LBN 3
|
|
+ #define RX_DESCQ_SIZE_WIDTH 2
|
|
+ #define RX_DESCQ_TYPE_LBN 2
|
|
+ #define RX_DESCQ_TYPE_WIDTH 1
|
|
+ #define RX_DESCQ_JUMBO_LBN 1
|
|
+ #define RX_DESCQ_JUMBO_WIDTH 1
|
|
+ #define RX_DESCQ_EN_LBN 0
|
|
+ #define RX_DESCQ_EN_WIDTH 1
|
|
+
|
|
+
|
|
+#define RX_RSS_INDIR_TBL_B0_OFST 0xFB0000 /* RSS indirection table (B0 only) */
|
|
+ #define RX_RSS_INDIR_ENT_B0_LBN 0
|
|
+ #define RX_RSS_INDIR_ENT_B0_WIDTH 6
|
|
+
|
|
+/*************---- TX Datapath Registers C Header ----*************/
|
|
+#define TX_FLUSH_DESCQ_REG_KER_OFST 0xA00 /* Transmit flush descriptor
|
|
+ queue register */
|
|
+#define TX_FLUSH_DESCQ_REG_OFST 0xA00 /* Transmit flush descriptor queue
|
|
+ register */
|
|
+ #define TX_FLUSH_DESCQ_CMD_LBN 12
|
|
+ #define TX_FLUSH_DESCQ_CMD_WIDTH 1
|
|
+ #define TX_FLUSH_DESCQ_LBN 0
|
|
+ #define TX_FLUSH_DESCQ_WIDTH 12
|
|
+#define TX_DESC_UPD_REG_KER_OFST 0xA10 /* Kernel transmit descriptor update
|
|
+ register. Page-mapped */
|
|
+#define TX_DESC_UPD_REG_PAGE4_OFST 0x8A10 /* Char & user transmit descriptor
|
|
+ update register. Page-mapped */
|
|
+#define TX_DESC_UPD_REG_PAGE123K_OFST 0x1000A10 /* Char & user transmit
|
|
+ descriptor update register.
|
|
+ Page-mapped */
|
|
+ #define TX_DESC_WPTR_LBN 96
|
|
+ #define TX_DESC_WPTR_WIDTH 12
|
|
+ #define TX_DESC_PUSH_CMD_LBN 95
|
|
+ #define TX_DESC_PUSH_CMD_WIDTH 1
|
|
+ #define TX_DESC_LBN 0
|
|
+ #define TX_DESC_WIDTH 95
|
|
+ #define TX_KER_DESC_LBN 0
|
|
+ #define TX_KER_DESC_WIDTH 64
|
|
+ #define TX_USR_DESC_LBN 0
|
|
+ #define TX_USR_DESC_WIDTH 64
|
|
+#define TX_DC_CFG_REG_KER_OFST 0xA20 /* Transmit descriptor cache
|
|
+ configuration register */
|
|
+#define TX_DC_CFG_REG_OFST 0xA20 /* Transmit descriptor cache configuration
|
|
+ register */
|
|
+ #define TX_DC_SIZE_LBN 0
|
|
+ #define TX_DC_SIZE_WIDTH 2
|
|
+
|
|
+#if FALCON_EXTENDED_P_BAR
|
|
+#define TX_DESC_PTR_TBL_KER_OFST 0x11900 /* Transmit descriptor pointer. */
|
|
+#else
|
|
+#define TX_DESC_PTR_TBL_KER_OFST 0x1900 /* Transmit descriptor pointer. */
|
|
+#endif
|
|
+
|
|
+
|
|
+#define TX_DESC_PTR_TBL_OFST 0xF50000 /* Transmit descriptor pointer */
|
|
+ #define TX_NON_IP_DROP_DIS_B0_LBN 91
|
|
+ #define TX_NON_IP_DROP_DIS_B0_WIDTH 1
|
|
+ #define TX_IP_CHKSM_DIS_B0_LBN 90
|
|
+ #define TX_IP_CHKSM_DIS_B0_WIDTH 1
|
|
+ #define TX_TCP_CHKSM_DIS_B0_LBN 89
|
|
+ #define TX_TCP_CHKSM_DIS_B0_WIDTH 1
|
|
+ #define TX_DESCQ_EN_LBN 88
|
|
+ #define TX_DESCQ_EN_WIDTH 1
|
|
+ #define TX_ISCSI_DDIG_EN_LBN 87
|
|
+ #define TX_ISCSI_DDIG_EN_WIDTH 1
|
|
+ #define TX_ISCSI_HDIG_EN_LBN 86
|
|
+ #define TX_ISCSI_HDIG_EN_WIDTH 1
|
|
+ #define TX_DC_HW_RPTR_LBN 80
|
|
+ #define TX_DC_HW_RPTR_WIDTH 6
|
|
+ #define TX_DESCQ_HW_RPTR_LBN 68
|
|
+ #define TX_DESCQ_HW_RPTR_WIDTH 12
|
|
+ #define TX_DESCQ_SW_WPTR_LBN 56
|
|
+ #define TX_DESCQ_SW_WPTR_WIDTH 12
|
|
+ #define TX_DESCQ_BUF_BASE_ID_LBN 36
|
|
+ #define TX_DESCQ_BUF_BASE_ID_WIDTH 20
|
|
+ #define TX_DESCQ_EVQ_ID_LBN 24
|
|
+ #define TX_DESCQ_EVQ_ID_WIDTH 12
|
|
+ #define TX_DESCQ_OWNER_ID_LBN 10
|
|
+ #define TX_DESCQ_OWNER_ID_WIDTH 14
|
|
+ #define TX_DESCQ_LABEL_LBN 5
|
|
+ #define TX_DESCQ_LABEL_WIDTH 5
|
|
+ #define TX_DESCQ_SIZE_LBN 3
|
|
+ #define TX_DESCQ_SIZE_WIDTH 2
|
|
+ #define TX_DESCQ_TYPE_LBN 1
|
|
+ #define TX_DESCQ_TYPE_WIDTH 2
|
|
+ #define TX_DESCQ_FLUSH_LBN 0
|
|
+ #define TX_DESCQ_FLUSH_WIDTH 1
|
|
+#define TX_CFG_REG_KER_OFST 0xA50 /* Transmit configuration register */
|
|
+#define TX_CFG_REG_OFST 0xA50 /* Transmit configuration register */
|
|
+ #define TX_IP_ID_P1_OFS_LBN 32
|
|
+ #define TX_IP_ID_P1_OFS_WIDTH 15
|
|
+ #define TX_IP_ID_P0_OFS_LBN 16
|
|
+ #define TX_IP_ID_P0_OFS_WIDTH 15
|
|
+ #define TX_TURBO_EN_LBN 3
|
|
+ #define TX_TURBO_EN_WIDTH 1
|
|
+ #define TX_OWNERR_CTL_LBN 2
|
|
+ #define TX_OWNERR_CTL_WIDTH 2
|
|
+ #define TX_NON_IP_DROP_DIS_LBN 1
|
|
+ #define TX_NON_IP_DROP_DIS_WIDTH 1
|
|
+ #define TX_IP_ID_REP_EN_LBN 0
|
|
+ #define TX_IP_ID_REP_EN_WIDTH 1
|
|
+#define TX_RESERVED_REG_KER_OFST 0xA80 /* Transmit configuration register */
|
|
+#define TX_RESERVED_REG_OFST 0xA80 /* Transmit configuration register */
|
|
+ #define TX_CSR_PUSH_EN_LBN 89
|
|
+ #define TX_CSR_PUSH_EN_WIDTH 1
|
|
+ #define TX_RX_SPACER_LBN 64
|
|
+ #define TX_RX_SPACER_WIDTH 8
|
|
+ #define TX_SW_EV_EN_LBN 59
|
|
+ #define TX_SW_EV_EN_WIDTH 1
|
|
+ #define TX_RX_SPACER_EN_LBN 57
|
|
+ #define TX_RX_SPACER_EN_WIDTH 1
|
|
+ #define TX_CSR_PREF_WD_TMR_LBN 24
|
|
+ #define TX_CSR_PREF_WD_TMR_WIDTH 16
|
|
+ #define TX_CSR_ONLY1TAG_LBN 21
|
|
+ #define TX_CSR_ONLY1TAG_WIDTH 1
|
|
+ #define TX_PREF_THRESHOLD_LBN 19
|
|
+ #define TX_PREF_THRESHOLD_WIDTH 2
|
|
+ #define TX_ONE_PKT_PER_Q_LBN 18
|
|
+ #define TX_ONE_PKT_PER_Q_WIDTH 1
|
|
+ #define TX_DIS_NON_IP_EV_LBN 17
|
|
+ #define TX_DIS_NON_IP_EV_WIDTH 1
|
|
+ #define TX_DMA_SPACER_LBN 8
|
|
+ #define TX_DMA_SPACER_WIDTH 8
|
|
+ #define TX_FLUSH_MIN_LEN_EN_B0_LBN 7
|
|
+ #define TX_FLUSH_MIN_LEN_EN_B0_WIDTH 1
|
|
+ #define TX_TCP_DIS_A1_LBN 7
|
|
+ #define TX_TCP_DIS_A1_WIDTH 1
|
|
+ #define TX_IP_DIS_A1_LBN 6
|
|
+ #define TX_IP_DIS_A1_WIDTH 1
|
|
+ #define TX_MAX_CPL_LBN 2
|
|
+ #define TX_MAX_CPL_WIDTH 2
|
|
+ #define TX_MAX_PREF_LBN 0
|
|
+ #define TX_MAX_PREF_WIDTH 2
|
|
+#define TX_VLAN_REG_OFST 0xAE0 /* Transmit VLAN tag register */
|
|
+ #define TX_VLAN_EN_LBN 127
|
|
+ #define TX_VLAN_EN_WIDTH 1
|
|
+ #define TX_VLAN7_PORT1_EN_LBN 125
|
|
+ #define TX_VLAN7_PORT1_EN_WIDTH 1
|
|
+ #define TX_VLAN7_PORT0_EN_LBN 124
|
|
+ #define TX_VLAN7_PORT0_EN_WIDTH 1
|
|
+ #define TX_VLAN7_LBN 112
|
|
+ #define TX_VLAN7_WIDTH 12
|
|
+ #define TX_VLAN6_PORT1_EN_LBN 109
|
|
+ #define TX_VLAN6_PORT1_EN_WIDTH 1
|
|
+ #define TX_VLAN6_PORT0_EN_LBN 108
|
|
+ #define TX_VLAN6_PORT0_EN_WIDTH 1
|
|
+ #define TX_VLAN6_LBN 96
|
|
+ #define TX_VLAN6_WIDTH 12
|
|
+ #define TX_VLAN5_PORT1_EN_LBN 93
|
|
+ #define TX_VLAN5_PORT1_EN_WIDTH 1
|
|
+ #define TX_VLAN5_PORT0_EN_LBN 92
|
|
+ #define TX_VLAN5_PORT0_EN_WIDTH 1
|
|
+ #define TX_VLAN5_LBN 80
|
|
+ #define TX_VLAN5_WIDTH 12
|
|
+ #define TX_VLAN4_PORT1_EN_LBN 77
|
|
+ #define TX_VLAN4_PORT1_EN_WIDTH 1
|
|
+ #define TX_VLAN4_PORT0_EN_LBN 76
|
|
+ #define TX_VLAN4_PORT0_EN_WIDTH 1
|
|
+ #define TX_VLAN4_LBN 64
|
|
+ #define TX_VLAN4_WIDTH 12
|
|
+ #define TX_VLAN3_PORT1_EN_LBN 61
|
|
+ #define TX_VLAN3_PORT1_EN_WIDTH 1
|
|
+ #define TX_VLAN3_PORT0_EN_LBN 60
|
|
+ #define TX_VLAN3_PORT0_EN_WIDTH 1
|
|
+ #define TX_VLAN3_LBN 48
|
|
+ #define TX_VLAN3_WIDTH 12
|
|
+ #define TX_VLAN2_PORT1_EN_LBN 45
|
|
+ #define TX_VLAN2_PORT1_EN_WIDTH 1
|
|
+ #define TX_VLAN2_PORT0_EN_LBN 44
|
|
+ #define TX_VLAN2_PORT0_EN_WIDTH 1
|
|
+ #define TX_VLAN2_LBN 32
|
|
+ #define TX_VLAN2_WIDTH 12
|
|
+ #define TX_VLAN1_PORT1_EN_LBN 29
|
|
+ #define TX_VLAN1_PORT1_EN_WIDTH 1
|
|
+ #define TX_VLAN1_PORT0_EN_LBN 28
|
|
+ #define TX_VLAN1_PORT0_EN_WIDTH 1
|
|
+ #define TX_VLAN1_LBN 16
|
|
+ #define TX_VLAN1_WIDTH 12
|
|
+ #define TX_VLAN0_PORT1_EN_LBN 13
|
|
+ #define TX_VLAN0_PORT1_EN_WIDTH 1
|
|
+ #define TX_VLAN0_PORT0_EN_LBN 12
|
|
+ #define TX_VLAN0_PORT0_EN_WIDTH 1
|
|
+ #define TX_VLAN0_LBN 0
|
|
+ #define TX_VLAN0_WIDTH 12
|
|
+#define TX_FIL_CTL_REG_OFST 0xAF0 /* Transmit filter control register */
|
|
+ #define TX_MADR1_FIL_EN_LBN 65
|
|
+ #define TX_MADR1_FIL_EN_WIDTH 1
|
|
+ #define TX_MADR0_FIL_EN_LBN 64
|
|
+ #define TX_MADR0_FIL_EN_WIDTH 1
|
|
+ #define TX_IPFIL31_PORT1_EN_LBN 63
|
|
+ #define TX_IPFIL31_PORT1_EN_WIDTH 1
|
|
+ #define TX_IPFIL31_PORT0_EN_LBN 62
|
|
+ #define TX_IPFIL31_PORT0_EN_WIDTH 1
|
|
+ #define TX_IPFIL30_PORT1_EN_LBN 61
|
|
+ #define TX_IPFIL30_PORT1_EN_WIDTH 1
|
|
+ #define TX_IPFIL30_PORT0_EN_LBN 60
|
|
+ #define TX_IPFIL30_PORT0_EN_WIDTH 1
|
|
+ #define TX_IPFIL29_PORT1_EN_LBN 59
|
|
+ #define TX_IPFIL29_PORT1_EN_WIDTH 1
|
|
+ #define TX_IPFIL29_PORT0_EN_LBN 58
|
|
+ #define TX_IPFIL29_PORT0_EN_WIDTH 1
|
|
+ #define TX_IPFIL28_PORT1_EN_LBN 57
|
|
+ #define TX_IPFIL28_PORT1_EN_WIDTH 1
|
|
+ #define TX_IPFIL28_PORT0_EN_LBN 56
|
|
+ #define TX_IPFIL28_PORT0_EN_WIDTH 1
|
|
+ #define TX_IPFIL27_PORT1_EN_LBN 55
|
|
+ #define TX_IPFIL27_PORT1_EN_WIDTH 1
|
|
+ #define TX_IPFIL27_PORT0_EN_LBN 54
|
|
+ #define TX_IPFIL27_PORT0_EN_WIDTH 1
|
|
+ #define TX_IPFIL26_PORT1_EN_LBN 53
|
|
+ #define TX_IPFIL26_PORT1_EN_WIDTH 1
|
|
+ #define TX_IPFIL26_PORT0_EN_LBN 52
|
|
+ #define TX_IPFIL26_PORT0_EN_WIDTH 1
|
|
+ #define TX_IPFIL25_PORT1_EN_LBN 51
|
|
+ #define TX_IPFIL25_PORT1_EN_WIDTH 1
|
|
+ #define TX_IPFIL25_PORT0_EN_LBN 50
|
|
+ #define TX_IPFIL25_PORT0_EN_WIDTH 1
|
|
+ #define TX_IPFIL24_PORT1_EN_LBN 49
|
|
+ #define TX_IPFIL24_PORT1_EN_WIDTH 1
|
|
+ #define TX_IPFIL24_PORT0_EN_LBN 48
|
|
+ #define TX_IPFIL24_PORT0_EN_WIDTH 1
|
|
+ #define TX_IPFIL23_PORT1_EN_LBN 47
|
|
+ #define TX_IPFIL23_PORT1_EN_WIDTH 1
|
|
+ #define TX_IPFIL23_PORT0_EN_LBN 46
|
|
+ #define TX_IPFIL23_PORT0_EN_WIDTH 1
|
|
+ #define TX_IPFIL22_PORT1_EN_LBN 45
|
|
+ #define TX_IPFIL22_PORT1_EN_WIDTH 1
|
|
+ #define TX_IPFIL22_PORT0_EN_LBN 44
|
|
+ #define TX_IPFIL22_PORT0_EN_WIDTH 1
|
|
+ #define TX_IPFIL21_PORT1_EN_LBN 43
|
|
+ #define TX_IPFIL21_PORT1_EN_WIDTH 1
|
|
+ #define TX_IPFIL21_PORT0_EN_LBN 42
|
|
+ #define TX_IPFIL21_PORT0_EN_WIDTH 1
|
|
+ #define TX_IPFIL20_PORT1_EN_LBN 41
|
|
+ #define TX_IPFIL20_PORT1_EN_WIDTH 1
|
|
+ #define TX_IPFIL20_PORT0_EN_LBN 40
|
|
+ #define TX_IPFIL20_PORT0_EN_WIDTH 1
|
|
+ #define TX_IPFIL19_PORT1_EN_LBN 39
|
|
+ #define TX_IPFIL19_PORT1_EN_WIDTH 1
|
|
+ #define TX_IPFIL19_PORT0_EN_LBN 38
|
|
+ #define TX_IPFIL19_PORT0_EN_WIDTH 1
|
|
+ #define TX_IPFIL18_PORT1_EN_LBN 37
|
|
+ #define TX_IPFIL18_PORT1_EN_WIDTH 1
|
|
+ #define TX_IPFIL18_PORT0_EN_LBN 36
|
|
+ #define TX_IPFIL18_PORT0_EN_WIDTH 1
|
|
+ #define TX_IPFIL17_PORT1_EN_LBN 35
|
|
+ #define TX_IPFIL17_PORT1_EN_WIDTH 1
|
|
+ #define TX_IPFIL17_PORT0_EN_LBN 34
|
|
+ #define TX_IPFIL17_PORT0_EN_WIDTH 1
|
|
+ #define TX_IPFIL16_PORT1_EN_LBN 33
|
|
+ #define TX_IPFIL16_PORT1_EN_WIDTH 1
|
|
+ #define TX_IPFIL16_PORT0_EN_LBN 32
|
|
+ #define TX_IPFIL16_PORT0_EN_WIDTH 1
|
|
+ #define TX_IPFIL15_PORT1_EN_LBN 31
|
|
+ #define TX_IPFIL15_PORT1_EN_WIDTH 1
|
|
+ #define TX_IPFIL15_PORT0_EN_LBN 30
|
|
+ #define TX_IPFIL15_PORT0_EN_WIDTH 1
|
|
+ #define TX_IPFIL14_PORT1_EN_LBN 29
|
|
+ #define TX_IPFIL14_PORT1_EN_WIDTH 1
|
|
+ #define TX_IPFIL14_PORT0_EN_LBN 28
|
|
+ #define TX_IPFIL14_PORT0_EN_WIDTH 1
|
|
+ #define TX_IPFIL13_PORT1_EN_LBN 27
|
|
+ #define TX_IPFIL13_PORT1_EN_WIDTH 1
|
|
+ #define TX_IPFIL13_PORT0_EN_LBN 26
|
|
+ #define TX_IPFIL13_PORT0_EN_WIDTH 1
|
|
+ #define TX_IPFIL12_PORT1_EN_LBN 25
|
|
+ #define TX_IPFIL12_PORT1_EN_WIDTH 1
|
|
+ #define TX_IPFIL12_PORT0_EN_LBN 24
|
|
+ #define TX_IPFIL12_PORT0_EN_WIDTH 1
|
|
+ #define TX_IPFIL11_PORT1_EN_LBN 23
|
|
+ #define TX_IPFIL11_PORT1_EN_WIDTH 1
|
|
+ #define TX_IPFIL11_PORT0_EN_LBN 22
|
|
+ #define TX_IPFIL11_PORT0_EN_WIDTH 1
|
|
+ #define TX_IPFIL10_PORT1_EN_LBN 21
|
|
+ #define TX_IPFIL10_PORT1_EN_WIDTH 1
|
|
+ #define TX_IPFIL10_PORT0_EN_LBN 20
|
|
+ #define TX_IPFIL10_PORT0_EN_WIDTH 1
|
|
+ #define TX_IPFIL9_PORT1_EN_LBN 19
|
|
+ #define TX_IPFIL9_PORT1_EN_WIDTH 1
|
|
+ #define TX_IPFIL9_PORT0_EN_LBN 18
|
|
+ #define TX_IPFIL9_PORT0_EN_WIDTH 1
|
|
+ #define TX_IPFIL8_PORT1_EN_LBN 17
|
|
+ #define TX_IPFIL8_PORT1_EN_WIDTH 1
|
|
+ #define TX_IPFIL8_PORT0_EN_LBN 16
|
|
+ #define TX_IPFIL8_PORT0_EN_WIDTH 1
|
|
+ #define TX_IPFIL7_PORT1_EN_LBN 15
|
|
+ #define TX_IPFIL7_PORT1_EN_WIDTH 1
|
|
+ #define TX_IPFIL7_PORT0_EN_LBN 14
|
|
+ #define TX_IPFIL7_PORT0_EN_WIDTH 1
|
|
+ #define TX_IPFIL6_PORT1_EN_LBN 13
|
|
+ #define TX_IPFIL6_PORT1_EN_WIDTH 1
|
|
+ #define TX_IPFIL6_PORT0_EN_LBN 12
|
|
+ #define TX_IPFIL6_PORT0_EN_WIDTH 1
|
|
+ #define TX_IPFIL5_PORT1_EN_LBN 11
|
|
+ #define TX_IPFIL5_PORT1_EN_WIDTH 1
|
|
+ #define TX_IPFIL5_PORT0_EN_LBN 10
|
|
+ #define TX_IPFIL5_PORT0_EN_WIDTH 1
|
|
+ #define TX_IPFIL4_PORT1_EN_LBN 9
|
|
+ #define TX_IPFIL4_PORT1_EN_WIDTH 1
|
|
+ #define TX_IPFIL4_PORT0_EN_LBN 8
|
|
+ #define TX_IPFIL4_PORT0_EN_WIDTH 1
|
|
+ #define TX_IPFIL3_PORT1_EN_LBN 7
|
|
+ #define TX_IPFIL3_PORT1_EN_WIDTH 1
|
|
+ #define TX_IPFIL3_PORT0_EN_LBN 6
|
|
+ #define TX_IPFIL3_PORT0_EN_WIDTH 1
|
|
+ #define TX_IPFIL2_PORT1_EN_LBN 5
|
|
+ #define TX_IPFIL2_PORT1_EN_WIDTH 1
|
|
+ #define TX_IPFIL2_PORT0_EN_LBN 4
|
|
+ #define TX_IPFIL2_PORT0_EN_WIDTH 1
|
|
+ #define TX_IPFIL1_PORT1_EN_LBN 3
|
|
+ #define TX_IPFIL1_PORT1_EN_WIDTH 1
|
|
+ #define TX_IPFIL1_PORT0_EN_LBN 2
|
|
+ #define TX_IPFIL1_PORT0_EN_WIDTH 1
|
|
+ #define TX_IPFIL0_PORT1_EN_LBN 1
|
|
+ #define TX_IPFIL0_PORT1_EN_WIDTH 1
|
|
+ #define TX_IPFIL0_PORT0_EN_LBN 0
|
|
+ #define TX_IPFIL0_PORT0_EN_WIDTH 1
|
|
+#define TX_IPFIL_TBL_OFST 0xB00 /* Transmit IP source address filter table */
|
|
+ #define TX_IPFIL_MASK_LBN 32
|
|
+ #define TX_IPFIL_MASK_WIDTH 32
|
|
+ #define TX_IP_SRC_ADR_LBN 0
|
|
+ #define TX_IP_SRC_ADR_WIDTH 32
|
|
+#define TX_PACE_REG_A1_OFST 0xF80000 /* Transmit pace control register */
|
|
+#define TX_PACE_REG_B0_OFST 0xA90 /* Transmit pace control register */
|
|
+ #define TX_PACE_SB_NOTAF_LBN 19
|
|
+ #define TX_PACE_SB_NOTAF_WIDTH 10
|
|
+ #define TX_PACE_SB_AF_LBN 9
|
|
+ #define TX_PACE_SB_AF_WIDTH 10
|
|
+ #define TX_PACE_FB_BASE_LBN 5
|
|
+ #define TX_PACE_FB_BASE_WIDTH 4
|
|
+ #define TX_PACE_BIN_TH_LBN 0
|
|
+ #define TX_PACE_BIN_TH_WIDTH 5
|
|
+#define TX_PACE_TBL_A1_OFST 0xF80040 /* Transmit pacing table */
|
|
+#define TX_PACE_TBL_FIRST_QUEUE_A1 4
|
|
+#define TX_PACE_TBL_B0_OFST 0xF80000 /* Transmit pacing table */
|
|
+#define TX_PACE_TBL_FIRST_QUEUE_B0 0
|
|
+ #define TX_PACE_LBN 0
|
|
+ #define TX_PACE_WIDTH 5
|
|
+
|
|
+/*************---- EE/Flash Registers C Header ----*************/
|
|
+#define EE_SPI_HCMD_REG_KER_OFST 0x100 /* SPI host command register */
|
|
+#define EE_SPI_HCMD_REG_OFST 0x100 /* SPI host command register */
|
|
+ #define EE_SPI_HCMD_CMD_EN_LBN 31
|
|
+ #define EE_SPI_HCMD_CMD_EN_WIDTH 1
|
|
+ #define EE_WR_TIMER_ACTIVE_LBN 28
|
|
+ #define EE_WR_TIMER_ACTIVE_WIDTH 1
|
|
+ #define EE_SPI_HCMD_SF_SEL_LBN 24
|
|
+ #define EE_SPI_HCMD_SF_SEL_WIDTH 1
|
|
+ #define EE_SPI_HCMD_DABCNT_LBN 16
|
|
+ #define EE_SPI_HCMD_DABCNT_WIDTH 5
|
|
+ #define EE_SPI_HCMD_READ_LBN 15
|
|
+ #define EE_SPI_HCMD_READ_WIDTH 1
|
|
+ #define EE_SPI_HCMD_DUBCNT_LBN 12
|
|
+ #define EE_SPI_HCMD_DUBCNT_WIDTH 2
|
|
+ #define EE_SPI_HCMD_ADBCNT_LBN 8
|
|
+ #define EE_SPI_HCMD_ADBCNT_WIDTH 2
|
|
+ #define EE_SPI_HCMD_ENC_LBN 0
|
|
+ #define EE_SPI_HCMD_ENC_WIDTH 8
|
|
+#define EE_SPI_HADR_REG_KER_OFST 0X110 /* SPI host address register */
|
|
+#define EE_SPI_HADR_REG_OFST 0X110 /* SPI host address register */
|
|
+ #define EE_SPI_HADR_DUBYTE_LBN 24
|
|
+ #define EE_SPI_HADR_DUBYTE_WIDTH 8
|
|
+ #define EE_SPI_HADR_ADR_LBN 0
|
|
+ #define EE_SPI_HADR_ADR_WIDTH 24
|
|
+#define EE_SPI_HDATA_REG_KER_OFST 0x120 /* SPI host data register */
|
|
+#define EE_SPI_HDATA_REG_OFST 0x120 /* SPI host data register */
|
|
+ #define EE_SPI_HDATA3_LBN 96
|
|
+ #define EE_SPI_HDATA3_WIDTH 32
|
|
+ #define EE_SPI_HDATA2_LBN 64
|
|
+ #define EE_SPI_HDATA2_WIDTH 32
|
|
+ #define EE_SPI_HDATA1_LBN 32
|
|
+ #define EE_SPI_HDATA1_WIDTH 32
|
|
+ #define EE_SPI_HDATA0_LBN 0
|
|
+ #define EE_SPI_HDATA0_WIDTH 32
|
|
+#define EE_BASE_PAGE_REG_KER_OFST 0x130 /* Expansion ROM base mirror register */
|
|
+#define EE_BASE_PAGE_REG_OFST 0x130 /* Expansion ROM base mirror register */
|
|
+ #define EE_EXP_ROM_WINDOW_BASE_LBN 16
|
|
+ #define EE_EXP_ROM_WINDOW_BASE_WIDTH 13
|
|
+ #define EE_EXPROM_MASK_LBN 0
|
|
+ #define EE_EXPROM_MASK_WIDTH 13
|
|
+#define EE_VPD_CFG0_REG_KER_OFST 0X140 /* SPI/VPD configuration register */
|
|
+#define EE_VPD_CFG0_REG_OFST 0X140 /* SPI/VPD configuration register */
|
|
+ #define EE_SF_FASTRD_EN_LBN 127
|
|
+ #define EE_SF_FASTRD_EN_WIDTH 1
|
|
+ #define EE_SF_CLOCK_DIV_LBN 120
|
|
+ #define EE_SF_CLOCK_DIV_WIDTH 7
|
|
+ #define EE_VPD_WIP_POLL_LBN 119
|
|
+ #define EE_VPD_WIP_POLL_WIDTH 1
|
|
+ #define EE_VPDW_LENGTH_LBN 80
|
|
+ #define EE_VPDW_LENGTH_WIDTH 15
|
|
+ #define EE_VPDW_BASE_LBN 64
|
|
+ #define EE_VPDW_BASE_WIDTH 15
|
|
+ #define EE_VPD_WR_CMD_EN_LBN 56
|
|
+ #define EE_VPD_WR_CMD_EN_WIDTH 8
|
|
+ #define EE_VPD_BASE_LBN 32
|
|
+ #define EE_VPD_BASE_WIDTH 24
|
|
+ #define EE_VPD_LENGTH_LBN 16
|
|
+ #define EE_VPD_LENGTH_WIDTH 13
|
|
+ #define EE_VPD_AD_SIZE_LBN 8
|
|
+ #define EE_VPD_AD_SIZE_WIDTH 5
|
|
+ #define EE_VPD_ACCESS_ON_LBN 5
|
|
+ #define EE_VPD_ACCESS_ON_WIDTH 1
|
|
+#define EE_VPD_SW_CNTL_REG_KER_OFST 0X150 /* VPD access SW control register */
|
|
+#define EE_VPD_SW_CNTL_REG_OFST 0X150 /* VPD access SW control register */
|
|
+ #define EE_VPD_CYCLE_PENDING_LBN 31
|
|
+ #define EE_VPD_CYCLE_PENDING_WIDTH 1
|
|
+ #define EE_VPD_CYC_WRITE_LBN 28
|
|
+ #define EE_VPD_CYC_WRITE_WIDTH 1
|
|
+ #define EE_VPD_CYC_ADR_LBN 0
|
|
+ #define EE_VPD_CYC_ADR_WIDTH 15
|
|
+#define EE_VPD_SW_DATA_REG_KER_OFST 0x160 /* VPD access SW data register */
|
|
+#define EE_VPD_SW_DATA_REG_OFST 0x160 /* VPD access SW data register */
|
|
+ #define EE_VPD_CYC_DAT_LBN 0
|
|
+ #define EE_VPD_CYC_DAT_WIDTH 32
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon/falcon_desc.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,75 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides EtherFabric NIC - EFXXXX (aka Falcon) descriptor
|
|
+ * definitions.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+/*************---- Descriptors C Headers ----*************/
|
|
+/* Receive Kernel IP Descriptor */
|
|
+ #define RX_KER_BUF_SIZE_LBN 48
|
|
+ #define RX_KER_BUF_SIZE_WIDTH 14
|
|
+ #define RX_KER_BUF_REGION_LBN 46
|
|
+ #define RX_KER_BUF_REGION_WIDTH 2
|
|
+ #define RX_KER_BUF_REGION0_DECODE 0
|
|
+ #define RX_KER_BUF_REGION1_DECODE 1
|
|
+ #define RX_KER_BUF_REGION2_DECODE 2
|
|
+ #define RX_KER_BUF_REGION3_DECODE 3
|
|
+ #define RX_KER_BUF_ADR_LBN 0
|
|
+ #define RX_KER_BUF_ADR_WIDTH 46
|
|
+/* Receive User IP Descriptor */
|
|
+ #define RX_USR_2BYTE_OFS_LBN 20
|
|
+ #define RX_USR_2BYTE_OFS_WIDTH 12
|
|
+ #define RX_USR_BUF_ID_LBN 0
|
|
+ #define RX_USR_BUF_ID_WIDTH 20
|
|
+/* Transmit Kernel IP Descriptor */
|
|
+ #define TX_KER_PORT_LBN 63
|
|
+ #define TX_KER_PORT_WIDTH 1
|
|
+ #define TX_KER_CONT_LBN 62
|
|
+ #define TX_KER_CONT_WIDTH 1
|
|
+ #define TX_KER_BYTE_CNT_LBN 48
|
|
+ #define TX_KER_BYTE_CNT_WIDTH 14
|
|
+ #define TX_KER_BUF_REGION_LBN 46
|
|
+ #define TX_KER_BUF_REGION_WIDTH 2
|
|
+ #define TX_KER_BUF_REGION0_DECODE 0
|
|
+ #define TX_KER_BUF_REGION1_DECODE 1
|
|
+ #define TX_KER_BUF_REGION2_DECODE 2
|
|
+ #define TX_KER_BUF_REGION3_DECODE 3
|
|
+ #define TX_KER_BUF_ADR_LBN 0
|
|
+ #define TX_KER_BUF_ADR_WIDTH 46
|
|
+/* Transmit User IP Descriptor */
|
|
+ #define TX_USR_PORT_LBN 47
|
|
+ #define TX_USR_PORT_WIDTH 1
|
|
+ #define TX_USR_CONT_LBN 46
|
|
+ #define TX_USR_CONT_WIDTH 1
|
|
+ #define TX_USR_BYTE_CNT_LBN 33
|
|
+ #define TX_USR_BYTE_CNT_WIDTH 13
|
|
+ #define TX_USR_BUF_ID_LBN 13
|
|
+ #define TX_USR_BUF_ID_WIDTH 20
|
|
+ #define TX_USR_BYTE_OFS_LBN 0
|
|
+ #define TX_USR_BYTE_OFS_WIDTH 13
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon/falcon_event.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,155 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides EtherFabric NIC - EFXXXX (aka Falcon) event
|
|
+ * definitions.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+/*************---- Events Format C Header ----*************/
|
|
+/*************---- Event entry ----*************/
|
|
+ #define EV_CODE_LBN 60
|
|
+ #define EV_CODE_WIDTH 4
|
|
+ #define RX_IP_EV_DECODE 0
|
|
+ #define TX_IP_EV_DECODE 2
|
|
+ #define DRIVER_EV_DECODE 5
|
|
+ #define GLOBAL_EV_DECODE 6
|
|
+ #define DRV_GEN_EV_DECODE 7
|
|
+ #define EV_DATA_LBN 0
|
|
+ #define EV_DATA_WIDTH 60
|
|
+/******---- Receive IP events for both Kernel & User event queues ----******/
|
|
+ #define RX_EV_PKT_OK_LBN 56
|
|
+ #define RX_EV_PKT_OK_WIDTH 1
|
|
+ #define RX_EV_BUF_OWNER_ID_ERR_LBN 54
|
|
+ #define RX_EV_BUF_OWNER_ID_ERR_WIDTH 1
|
|
+ #define RX_EV_IP_HDR_CHKSUM_ERR_LBN 52
|
|
+ #define RX_EV_IP_HDR_CHKSUM_ERR_WIDTH 1
|
|
+ #define RX_EV_TCP_UDP_CHKSUM_ERR_LBN 51
|
|
+ #define RX_EV_TCP_UDP_CHKSUM_ERR_WIDTH 1
|
|
+ #define RX_EV_ETH_CRC_ERR_LBN 50
|
|
+ #define RX_EV_ETH_CRC_ERR_WIDTH 1
|
|
+ #define RX_EV_FRM_TRUNC_LBN 49
|
|
+ #define RX_EV_FRM_TRUNC_WIDTH 1
|
|
+ #define RX_EV_DRIB_NIB_LBN 48
|
|
+ #define RX_EV_DRIB_NIB_WIDTH 1
|
|
+ #define RX_EV_TOBE_DISC_LBN 47
|
|
+ #define RX_EV_TOBE_DISC_WIDTH 1
|
|
+ #define RX_EV_PKT_TYPE_LBN 44
|
|
+ #define RX_EV_PKT_TYPE_WIDTH 3
|
|
+ #define RX_EV_PKT_TYPE_ETH_DECODE 0
|
|
+ #define RX_EV_PKT_TYPE_LLC_DECODE 1
|
|
+ #define RX_EV_PKT_TYPE_JUMBO_DECODE 2
|
|
+ #define RX_EV_PKT_TYPE_VLAN_DECODE 3
|
|
+ #define RX_EV_PKT_TYPE_VLAN_LLC_DECODE 4
|
|
+ #define RX_EV_PKT_TYPE_VLAN_JUMBO_DECODE 5
|
|
+ #define RX_EV_HDR_TYPE_LBN 42
|
|
+ #define RX_EV_HDR_TYPE_WIDTH 2
|
|
+ #define RX_EV_HDR_TYPE_TCP_IPV4_DECODE 0
|
|
+ #define RX_EV_HDR_TYPE_UDP_IPV4_DECODE 1
|
|
+ #define RX_EV_HDR_TYPE_OTHER_IP_DECODE 2
|
|
+ #define RX_EV_HDR_TYPE_NON_IP_DECODE 3
|
|
+ #define RX_EV_DESC_Q_EMPTY_LBN 41
|
|
+ #define RX_EV_DESC_Q_EMPTY_WIDTH 1
|
|
+ #define RX_EV_MCAST_HASH_MATCH_LBN 40
|
|
+ #define RX_EV_MCAST_HASH_MATCH_WIDTH 1
|
|
+ #define RX_EV_MCAST_PKT_LBN 39
|
|
+ #define RX_EV_MCAST_PKT_WIDTH 1
|
|
+ #define RX_EV_Q_LABEL_LBN 32
|
|
+ #define RX_EV_Q_LABEL_WIDTH 5
|
|
+ #define RX_JUMBO_CONT_LBN 31
|
|
+ #define RX_JUMBO_CONT_WIDTH 1
|
|
+ #define RX_SOP_LBN 15
|
|
+ #define RX_SOP_WIDTH 1
|
|
+ #define RX_PORT_LBN 30
|
|
+ #define RX_PORT_WIDTH 1
|
|
+ #define RX_EV_BYTE_CNT_LBN 16
|
|
+ #define RX_EV_BYTE_CNT_WIDTH 14
|
|
+ #define RX_iSCSI_PKT_OK_LBN 14
|
|
+ #define RX_iSCSI_PKT_OK_WIDTH 1
|
|
+ #define RX_ISCSI_DDIG_ERR_LBN 13
|
|
+ #define RX_ISCSI_DDIG_ERR_WIDTH 1
|
|
+ #define RX_ISCSI_HDIG_ERR_LBN 12
|
|
+ #define RX_ISCSI_HDIG_ERR_WIDTH 1
|
|
+ #define RX_EV_DESC_PTR_LBN 0
|
|
+ #define RX_EV_DESC_PTR_WIDTH 12
|
|
+/******---- Transmit IP events for both Kernel & User event queues ----******/
|
|
+ #define TX_EV_PKT_ERR_LBN 38
|
|
+ #define TX_EV_PKT_ERR_WIDTH 1
|
|
+ #define TX_EV_PKT_TOO_BIG_LBN 37
|
|
+ #define TX_EV_PKT_TOO_BIG_WIDTH 1
|
|
+ #define TX_EV_Q_LABEL_LBN 32
|
|
+ #define TX_EV_Q_LABEL_WIDTH 5
|
|
+ #define TX_EV_PORT_LBN 16
|
|
+ #define TX_EV_PORT_WIDTH 1
|
|
+ #define TX_EV_WQ_FF_FULL_LBN 15
|
|
+ #define TX_EV_WQ_FF_FULL_WIDTH 1
|
|
+ #define TX_EV_BUF_OWNER_ID_ERR_LBN 14
|
|
+ #define TX_EV_BUF_OWNER_ID_ERR_WIDTH 1
|
|
+ #define TX_EV_COMP_LBN 12
|
|
+ #define TX_EV_COMP_WIDTH 1
|
|
+ #define TX_EV_DESC_PTR_LBN 0
|
|
+ #define TX_EV_DESC_PTR_WIDTH 12
|
|
+/*************---- Char or Kernel driver events ----*************/
|
|
+ #define DRIVER_EV_SUB_CODE_LBN 56
|
|
+ #define DRIVER_EV_SUB_CODE_WIDTH 4
|
|
+ #define TX_DESCQ_FLS_DONE_EV_DECODE 0x0
|
|
+ #define RX_DESCQ_FLS_DONE_EV_DECODE 0x1
|
|
+ #define EVQ_INIT_DONE_EV_DECODE 0x2
|
|
+ #define EVQ_NOT_EN_EV_DECODE 0x3
|
|
+ #define RX_DESCQ_FLSFF_OVFL_EV_DECODE 0x4
|
|
+ #define SRM_UPD_DONE_EV_DECODE 0x5
|
|
+ #define WAKE_UP_EV_DECODE 0x6
|
|
+ #define TX_PKT_NON_TCP_UDP_DECODE 0x9
|
|
+ #define TIMER_EV_DECODE 0xA
|
|
+ #define RX_DSC_ERROR_EV_DECODE 0xE
|
|
+ #define DRIVER_EV_TX_DESCQ_ID_LBN 0
|
|
+ #define DRIVER_EV_TX_DESCQ_ID_WIDTH 12
|
|
+ #define DRIVER_EV_RX_DESCQ_ID_LBN 0
|
|
+ #define DRIVER_EV_RX_DESCQ_ID_WIDTH 12
|
|
+ #define DRIVER_EV_EVQ_ID_LBN 0
|
|
+ #define DRIVER_EV_EVQ_ID_WIDTH 12
|
|
+ #define DRIVER_TMR_ID_LBN 0
|
|
+ #define DRIVER_TMR_ID_WIDTH 12
|
|
+ #define DRIVER_EV_SRM_UPD_LBN 0
|
|
+ #define DRIVER_EV_SRM_UPD_WIDTH 2
|
|
+ #define SRM_CLR_EV_DECODE 0
|
|
+ #define SRM_UPD_EV_DECODE 1
|
|
+ #define SRM_ILLCLR_EV_DECODE 2
|
|
+/********---- Global events. Sent to both event queue 0 and 4. ----********/
|
|
+ #define XFP_PHY_INTR_LBN 10
|
|
+ #define XFP_PHY_INTR_WIDTH 1
|
|
+ #define XG_PHY_INTR_LBN 9
|
|
+ #define XG_PHY_INTR_WIDTH 1
|
|
+ #define G_PHY1_INTR_LBN 8
|
|
+ #define G_PHY1_INTR_WIDTH 1
|
|
+ #define G_PHY0_INTR_LBN 7
|
|
+ #define G_PHY0_INTR_WIDTH 1
|
|
+/*************---- Driver generated events ----*************/
|
|
+ #define DRV_GEN_EV_CODE_LBN 60
|
|
+ #define DRV_GEN_EV_CODE_WIDTH 4
|
|
+ #define DRV_GEN_EV_DATA_LBN 0
|
|
+ #define DRV_GEN_EV_DATA_WIDTH 60
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon/falcon_intr_vec.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,44 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides EtherFabric NIC - EFXXXX (aka Falcon) interrupt
|
|
+ * vector definitions.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+/*************---- Interrupt Vector Format C Header ----*************/
|
|
+#define DW0_OFST 0x0 /* Double-word 0: Event queue FIFO interrupts */
|
|
+ #define EVQ_FIFO_HF_LBN 1
|
|
+ #define EVQ_FIFO_HF_WIDTH 1
|
|
+ #define EVQ_FIFO_AF_LBN 0
|
|
+ #define EVQ_FIFO_AF_WIDTH 1
|
|
+#define DW1_OFST 0x4 /* Double-word 1: Interrupt indicator */
|
|
+ #define INT_FLAG_LBN 0
|
|
+ #define INT_FLAG_WIDTH 1
|
|
+#define DW2_OFST 0x8 /* Double-word 2: Fatal interrupts */
|
|
+ #define FATAL_INT_LBN 0
|
|
+ #define FATAL_INT_WIDTH 1
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/workarounds.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,67 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides workaround settings for EtherFabric NICs.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_DRIVER_EFAB_WORKAROUNDS_H__
|
|
+#define __CI_DRIVER_EFAB_WORKAROUNDS_H__
|
|
+
|
|
+/*----------------------------------------------------------------------------
|
|
+ *
|
|
+ * Hardware workarounds which have global scope
|
|
+ *
|
|
+ *---------------------------------------------------------------------------*/
|
|
+
|
|
+#if defined(__CI_HARDWARE_CONFIG_FALCON_B0__)
|
|
+/*------------------------------- B0 ---------------------------------------*/
|
|
+
|
|
+#define BUG2175_WORKAROUND 0 /* TX event batching for dual port operation.
|
|
+ This removes the effect (dup TX events)
|
|
+ of the fix
|
|
+ (TX event per packet + batch events) */
|
|
+#define BUG5302_WORKAROUND 0 /* unstick TX DMAQ after out-of-range wr ptr */
|
|
+#define BUG5762_WORKAROUND 0 /* Set all queues to jumbo mode */
|
|
+#define BUG5391_WORKAROUND 0 /* Misaligned TX can't span 512-byte boundary */
|
|
+#define BUG7916_WORKAROUND 0 /* RX flush gets lost */
|
|
+
|
|
+#else
|
|
+/*------------------------------- A0/A1 ------------------------------------*/
|
|
+
|
|
+#define BUG2175_WORKAROUND 1 /* TX event batching for dual port operation.
|
|
+ This removes the effect (dup TX events)
|
|
+ of the fix
|
|
+ (TX event per packet + batch events) */
|
|
+#define BUG5302_WORKAROUND 1 /* unstick TX DMAQ after out-of-range wr ptr */
|
|
+#define BUG5762_WORKAROUND 1 /* Set all queues to jumbo mode */
|
|
+#define BUG5391_WORKAROUND 1 /* Misaligned TX can't span 512-byte boundary */
|
|
+#define BUG7916_WORKAROUND 1 /* RX flush gets lost */
|
|
+
|
|
+#endif /* B0/A01 */
|
|
+
|
|
+#endif /* __CI_DRIVER_EFAB_WORKAROUNDS_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/driver/resource/efx_vi.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,273 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file contains public EFX VI API to Solarflare resource manager.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_DRIVER_RESOURCE_EFX_VI_H__
|
|
+#define __CI_DRIVER_RESOURCE_EFX_VI_H__
|
|
+
|
|
+/* Default size of event queue in the efx_vi resource. Copied from
|
|
+ * CI_CFG_NETIF_EVENTQ_SIZE */
|
|
+#define EFX_VI_EVENTQ_SIZE_DEFAULT 1024
|
|
+
|
|
+extern int efx_vi_eventq_size;
|
|
+
|
|
+/**************************************************************************
|
|
+ * efx_vi_state types, allocation and free
|
|
+ **************************************************************************/
|
|
+
|
|
+/*! Handle for refering to a efx_vi */
|
|
+struct efx_vi_state;
|
|
+
|
|
+/*!
|
|
+ * Allocate an efx_vi, including event queue and pt_endpoint
|
|
+ *
|
|
+ * \param vih_out Pointer to a handle that is set on success
|
|
+ * \param ifindex Index of the network interface desired
|
|
+ * \return Zero on success (and vih_out set), non-zero on failure.
|
|
+ */
|
|
+extern int
|
|
+efx_vi_alloc(struct efx_vi_state **vih_out, int ifindex);
|
|
+
|
|
+/*!
|
|
+ * Free a previously allocated efx_vi
|
|
+ *
|
|
+ * \param vih The handle of the efx_vi to free
|
|
+ */
|
|
+extern void
|
|
+efx_vi_free(struct efx_vi_state *vih);
|
|
+
|
|
+/*!
|
|
+ * Reset a previously allocated efx_vi
|
|
+ *
|
|
+ * \param vih The handle of the efx_vi to reset
|
|
+ */
|
|
+extern void
|
|
+efx_vi_reset(struct efx_vi_state *vih);
|
|
+
|
|
+/**************************************************************************
|
|
+ * efx_vi_eventq types and functions
|
|
+ **************************************************************************/
|
|
+
|
|
+/*!
|
|
+ * Register a function to receive callbacks when event queue timeouts
|
|
+ * or wakeups occur. Only one function per efx_vi can be registered
|
|
+ * at once.
|
|
+ *
|
|
+ * \param vih The handle to identify the efx_vi
|
|
+ * \param callback The function to callback
|
|
+ * \param context An argument to pass to the callback function
|
|
+ * \return Zero on success, non-zero on failure.
|
|
+ */
|
|
+extern int
|
|
+efx_vi_eventq_register_callback(struct efx_vi_state *vih,
|
|
+ void (*callback)(void *context, int is_timeout),
|
|
+ void *context);
|
|
+
|
|
+/*!
|
|
+ * Remove the current eventq timeout or wakeup callback function
|
|
+ *
|
|
+ * \param vih The handle to identify the efx_vi
|
|
+ * \return Zero on success, non-zero on failure
|
|
+ */
|
|
+extern int
|
|
+efx_vi_eventq_kill_callback(struct efx_vi_state *vih);
|
|
+
|
|
+/**************************************************************************
|
|
+ * efx_vi_dma_map types and functions
|
|
+ **************************************************************************/
|
|
+
|
|
+/*!
|
|
+ * Handle for refering to a efx_vi
|
|
+ */
|
|
+struct efx_vi_dma_map_state;
|
|
+
|
|
+/*!
|
|
+ * Map a list of buffer pages so they are registered with the hardware
|
|
+ *
|
|
+ * \param vih The handle to identify the efx_vi
|
|
+ * \param addrs An array of page pointers to map
|
|
+ * \param n_addrs Length of the page pointer array. Must be a power of two.
|
|
+ * \param dmh_out Set on success to a handle used to refer to this mapping
|
|
+ * \return Zero on success, non-zero on failure.
|
|
+ */
|
|
+extern int
|
|
+efx_vi_dma_map_pages(struct efx_vi_state *vih, struct page **pages,
|
|
+ int n_pages, struct efx_vi_dma_map_state **dmh_out);
|
|
+extern int
|
|
+efx_vi_dma_map_addrs(struct efx_vi_state *vih,
|
|
+ unsigned long long *dev_bus_addrs, int n_pages,
|
|
+ struct efx_vi_dma_map_state **dmh_out);
|
|
+
|
|
+/*!
|
|
+ * Unmap a previously mapped set of pages so they are no longer registered
|
|
+ * with the hardware.
|
|
+ *
|
|
+ * \param vih The handle to identify the efx_vi
|
|
+ * \param dmh The handle to identify the dma mapping
|
|
+ */
|
|
+extern void
|
|
+efx_vi_dma_unmap_pages(struct efx_vi_state *vih,
|
|
+ struct efx_vi_dma_map_state *dmh);
|
|
+extern void
|
|
+efx_vi_dma_unmap_addrs(struct efx_vi_state *vih,
|
|
+ struct efx_vi_dma_map_state *dmh);
|
|
+
|
|
+/*!
|
|
+ * Retrieve the buffer address of the mapping
|
|
+ *
|
|
+ * \param vih The handle to identify the efx_vi
|
|
+ * \param dmh The handle to identify the buffer mapping
|
|
+ * \return The buffer address on success, or zero on failure
|
|
+ */
|
|
+extern unsigned
|
|
+efx_vi_dma_get_map_addr(struct efx_vi_state *vih,
|
|
+ struct efx_vi_dma_map_state *dmh);
|
|
+
|
|
+/**************************************************************************
|
|
+ * efx_vi filter functions
|
|
+ **************************************************************************/
|
|
+
|
|
+#define EFX_VI_STATIC_FILTERS 32
|
|
+
|
|
+/*! Handle to refer to a filter instance */
|
|
+struct filter_resource_t;
|
|
+
|
|
+/*!
|
|
+ * Allocate and add a filter
|
|
+ *
|
|
+ * \param vih The handle to identify the efx_vi
|
|
+ * \param protocol The protocol of the new filter: UDP or TCP
|
|
+ * \param ip_addr_be32 The local ip address of the filter
|
|
+ * \param port_le16 The local port of the filter
|
|
+ * \param fh_out Set on success to be a handle to refer to this filter
|
|
+ * \return Zero on success, non-zero on failure.
|
|
+ */
|
|
+extern int
|
|
+efx_vi_filter(struct efx_vi_state *vih, int protocol, unsigned ip_addr_be32,
|
|
+ int port_le16, struct filter_resource_t **fh_out);
|
|
+
|
|
+/*!
|
|
+ * Remove a filter and free resources associated with it
|
|
+ *
|
|
+ * \param vih The handle to identify the efx_vi
|
|
+ * \param fh The handle to identify the filter
|
|
+ * \return Zero on success, non-zero on failure
|
|
+ */
|
|
+extern int
|
|
+efx_vi_filter_stop(struct efx_vi_state *vih, struct filter_resource_t *fh);
|
|
+
|
|
+/**************************************************************************
|
|
+ * efx_vi hw resources types and functions
|
|
+ **************************************************************************/
|
|
+
|
|
+/*! Constants for the type field in efx_vi_hw_resource */
|
|
+#define EFX_VI_HW_RESOURCE_TXDMAQ 0x0 /* PFN of TX DMA Q */
|
|
+#define EFX_VI_HW_RESOURCE_RXDMAQ 0x1 /* PFN of RX DMA Q */
|
|
+#define EFX_VI_HW_RESOURCE_EVQTIMER 0x4 /* Address of event q timer */
|
|
+
|
|
+/* Address of event q pointer (EF1) */
|
|
+#define EFX_VI_HW_RESOURCE_EVQPTR 0x5
|
|
+/* Address of register pointer (Falcon A) */
|
|
+#define EFX_VI_HW_RESOURCE_EVQRPTR 0x6
|
|
+/* Offset of register pointer (Falcon B) */
|
|
+#define EFX_VI_HW_RESOURCE_EVQRPTR_OFFSET 0x7
|
|
+/* Address of mem KVA */
|
|
+#define EFX_VI_HW_RESOURCE_EVQMEMKVA 0x8
|
|
+/* PFN of doorbell page (Falcon) */
|
|
+#define EFX_VI_HW_RESOURCE_BELLPAGE 0x9
|
|
+
|
|
+/*! How large an array to allocate for the get_() functions - smaller
|
|
+ than the total number of constants as some are mutually exclusive */
|
|
+#define EFX_VI_HW_RESOURCE_MAXSIZE 0x7
|
|
+
|
|
+/*! Constants for the mem_type field in efx_vi_hw_resource */
|
|
+#define EFX_VI_HW_RESOURCE_IOBUFFER 0 /* Host memory */
|
|
+#define EFX_VI_HW_RESOURCE_PERIPHERAL 1 /* Card memory/registers */
|
|
+
|
|
+/*!
|
|
+ * Data structure providing information on a hardware resource mapping
|
|
+ */
|
|
+struct efx_vi_hw_resource {
|
|
+ u8 type; /*!< What this resource represents */
|
|
+ u8 mem_type; /*!< What type of memory is it in, eg,
|
|
+ * host or iomem */
|
|
+ u8 more_to_follow; /*!< Is this part of a multi-region resource */
|
|
+ u32 length; /*!< Length of the resource in bytes */
|
|
+ unsigned long address; /*!< Address of this resource */
|
|
+};
|
|
+
|
|
+/*!
|
|
+ * Metadata concerning the list of hardware resource mappings
|
|
+ */
|
|
+struct efx_vi_hw_resource_metadata {
|
|
+ int evq_order;
|
|
+ int evq_offs;
|
|
+ int evq_capacity;
|
|
+ int instance;
|
|
+ unsigned rx_capacity;
|
|
+ unsigned tx_capacity;
|
|
+ int nic_arch;
|
|
+ int nic_revision;
|
|
+ char nic_variant;
|
|
+};
|
|
+
|
|
+/*!
|
|
+ * Obtain a list of hardware resource mappings, using virtual addresses
|
|
+ *
|
|
+ * \param vih The handle to identify the efx_vi
|
|
+ * \param mdata Pointer to a structure to receive the metadata
|
|
+ * \param hw_res_array An array to receive the list of hardware resources
|
|
+ * \param length The length of hw_res_array. Updated on success to contain
|
|
+ * the number of entries in the supplied array that were used.
|
|
+ * \return Zero on success, non-zero on failure
|
|
+ */
|
|
+extern int
|
|
+efx_vi_hw_resource_get_virt(struct efx_vi_state *vih,
|
|
+ struct efx_vi_hw_resource_metadata *mdata,
|
|
+ struct efx_vi_hw_resource *hw_res_array,
|
|
+ int *length);
|
|
+
|
|
+/*!
|
|
+ * Obtain a list of hardware resource mappings, using physical addresses
|
|
+ *
|
|
+ * \param vih The handle to identify the efx_vi
|
|
+ * \param mdata Pointer to a structure to receive the metadata
|
|
+ * \param hw_res_array An array to receive the list of hardware resources
|
|
+ * \param length The length of hw_res_array. Updated on success to contain
|
|
+ * the number of entries in the supplied array that were used.
|
|
+ * \return Zero on success, non-zero on failure
|
|
+ */
|
|
+extern int
|
|
+efx_vi_hw_resource_get_phys(struct efx_vi_state *vih,
|
|
+ struct efx_vi_hw_resource_metadata *mdata,
|
|
+ struct efx_vi_hw_resource *hw_res_array,
|
|
+ int *length);
|
|
+
|
|
+#endif /* __CI_DRIVER_RESOURCE_EFX_VI_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/driver/resource/linux_efhw_nic.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,69 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file contains definition of the public type struct linux_efhw_nic.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_DRIVER_RESOURCE_LINUX_RESOURCE__
|
|
+#define __CI_DRIVER_RESOURCE_LINUX_RESOURCE__
|
|
+
|
|
+#include <ci/efrm/efrm_nic.h>
|
|
+#include <linux/interrupt.h>
|
|
+
|
|
+
|
|
+/************************************************************************
|
|
+ * Per-nic structure in the resource driver *
|
|
+ ************************************************************************/
|
|
+
|
|
+struct linux_efhw_nic {
|
|
+ struct efrm_nic efrm_nic;
|
|
+
|
|
+ struct pci_dev *pci_dev; /*!< pci descriptor */
|
|
+ struct tasklet_struct tasklet; /*!< for interrupt bottom half */
|
|
+
|
|
+ /* Physical addresses of the control aperture bar. */
|
|
+ unsigned long ctr_ap_pci_addr;
|
|
+
|
|
+ /*! Callbacks for driverlink, when needed. */
|
|
+ struct efx_dl_callbacks *dl_callbacks;
|
|
+
|
|
+ /*! Event handlers. */
|
|
+ struct efhw_ev_handler *ev_handlers;
|
|
+
|
|
+};
|
|
+
|
|
+#define linux_efhw_nic(_efhw_nic) \
|
|
+ container_of(_efhw_nic, struct linux_efhw_nic, efrm_nic.efhw_nic)
|
|
+
|
|
+#endif /* __CI_DRIVER_RESOURCE_LINUX_RESOURCE__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efhw/checks.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,118 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides helpers to turn bit shifts into dword shifts and
|
|
+ * check that the bit fields haven't overflown the dword etc.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_EFHW_CHECK_H__
|
|
+#define __CI_EFHW_CHECK_H__
|
|
+
|
|
+/*----------------------------------------------------------------------------
|
|
+ *
|
|
+ * Helpers to turn bit shifts into dword shifts and check that the bit fields
|
|
+ * haven't overflown the dword etc. Aim is to preserve consistency with the
|
|
+ * autogenerated headers - once stable we could hard code.
|
|
+ *
|
|
+ *---------------------------------------------------------------------------*/
|
|
+
|
|
+/* mask constructors */
|
|
+#define __FALCON_MASK(WIDTH, T) ((((T)1) << (WIDTH)) - 1)
|
|
+#define __FALCON_MASK32(WIDTH) __FALCON_MASK((WIDTH), uint32_t)
|
|
+#define __FALCON_MASK64(WIDTH) __FALCON_MASK((WIDTH), uint64_t)
|
|
+
|
|
+#define __FALCON_MASKFIELD32(LBN, WIDTH) \
|
|
+ ((uint32_t)(__FALCON_MASK32(WIDTH) << (LBN)))
|
|
+
|
|
+/* constructors for fields which span the first and second dwords */
|
|
+#define __LW(LBN) (32 - LBN)
|
|
+#define __LOW(v, LBN, WIDTH) \
|
|
+ ((uint32_t)(((v) & __FALCON_MASK64(__LW((LBN)))) << (LBN)))
|
|
+#define __HIGH(v, LBN, WIDTH) \
|
|
+ ((uint32_t)(((v) >> __LW((LBN))) & \
|
|
+ __FALCON_MASK64((WIDTH - __LW((LBN))))))
|
|
+/* constructors for fields within the second dword */
|
|
+#define __DW2(LBN) ((LBN) - 32)
|
|
+
|
|
+/* constructors for fields which span the second and third dwords */
|
|
+#define __LW2(LBN) (64 - LBN)
|
|
+#define __LOW2(v, LBN, WIDTH) \
|
|
+ ((uint32_t)(((v) & __FALCON_MASK64(__LW2((LBN)))) << ((LBN) - 32)))
|
|
+#define __HIGH2(v, LBN, WIDTH) \
|
|
+ ((uint32_t)(((v) >> __LW2((LBN))) & \
|
|
+ __FALCON_MASK64((WIDTH - __LW2((LBN))))))
|
|
+
|
|
+/* constructors for fields within the third dword */
|
|
+#define __DW3(LBN) ((LBN) - 64)
|
|
+
|
|
+/* constructors for fields which span the third and fourth dwords */
|
|
+#define __LW3(LBN) (96 - LBN)
|
|
+#define __LOW3(v, LBN, WIDTH) \
|
|
+ ((uint32_t)(((v) & __FALCON_MASK64(__LW3((LBN)))) << ((LBN) - 64)))
|
|
+#define __HIGH3(v, LBN, WIDTH) \
|
|
+ ((ci_unit32)(((v) >> __LW3((LBN))) & \
|
|
+ __FALCON_MASK64((WIDTH - __LW3((LBN))))))
|
|
+
|
|
+/* constructors for fields within the fourth dword */
|
|
+#define __DW4(LBN) ((LBN) - 96)
|
|
+
|
|
+/* checks that the autogenerated headers are consistent with our model */
|
|
+#define __WIDTHCHCK(a, b) EFHW_ASSERT((a) == (b))
|
|
+#define __RANGECHCK(v, WIDTH) \
|
|
+ EFHW_ASSERT(((uint64_t)(v) & ~(__FALCON_MASK64((WIDTH)))) == 0)
|
|
+
|
|
+/* fields within the first dword */
|
|
+#define __DWCHCK(LBN, WIDTH) \
|
|
+ EFHW_ASSERT(((LBN) >= 0) && (((LBN)+(WIDTH)) <= 32))
|
|
+
|
|
+/* fields which span the first and second dwords */
|
|
+#define __LWCHK(LBN, WIDTH) EFHW_ASSERT(WIDTH >= __LW(LBN))
|
|
+
|
|
+/* fields within the second dword */
|
|
+#define __DW2CHCK(LBN, WIDTH) \
|
|
+ EFHW_ASSERT(((LBN) >= 32) && (((LBN)+(WIDTH)) <= 64))
|
|
+
|
|
+/* fields which span the second and third dwords */
|
|
+#define __LW2CHK(LBN, WIDTH) EFHW_ASSERT(WIDTH >= __LW2(LBN))
|
|
+
|
|
+/* fields within the third dword */
|
|
+#define __DW3CHCK(LBN, WIDTH) \
|
|
+ EFHW_ASSERT(((LBN) >= 64) && (((LBN)+(WIDTH)) <= 96))
|
|
+
|
|
+/* fields which span the third and fourth dwords */
|
|
+#define __LW3CHK(LBN, WIDTH) EFHW_ASSERT(WIDTH >= __LW3(LBN))
|
|
+
|
|
+/* fields within the fourth dword */
|
|
+#define __DW4CHCK(LBN, WIDTH) \
|
|
+ EFHW_ASSERT(((LBN) >= 96) && (((LBN)+(WIDTH)) <= 128))
|
|
+
|
|
+/* fields in the first qword */
|
|
+#define __QWCHCK(LBN, WIDTH) \
|
|
+ EFHW_ASSERT(((LBN) >= 0) && (((LBN)+(WIDTH)) <= 64))
|
|
+
|
|
+#endif /* __CI_EFHW_CHECK_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efhw/common.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,93 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides API of the efhw library which may be used both from
|
|
+ * the kernel and from the user-space code.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_EFHW_COMMON_H__
|
|
+#define __CI_EFHW_COMMON_H__
|
|
+
|
|
+#include <ci/efhw/common_sysdep.h>
|
|
+
|
|
+typedef uint32_t efhw_buffer_addr_t;
|
|
+#define EFHW_BUFFER_ADDR_FMT "[ba:%"PRIx32"]"
|
|
+
|
|
+/*! Comment? */
|
|
+typedef union {
|
|
+ uint64_t u64;
|
|
+ struct {
|
|
+ uint32_t a;
|
|
+ uint32_t b;
|
|
+ } opaque;
|
|
+} efhw_event_t;
|
|
+
|
|
+/* Flags for TX/RX queues */
|
|
+#define EFHW_VI_JUMBO_EN 0x01 /*! scatter RX over multiple desc */
|
|
+#define EFHW_VI_ISCSI_RX_HDIG_EN 0x02 /*! iscsi rx header digest */
|
|
+#define EFHW_VI_ISCSI_TX_HDIG_EN 0x04 /*! iscsi tx header digest */
|
|
+#define EFHW_VI_ISCSI_RX_DDIG_EN 0x08 /*! iscsi rx data digest */
|
|
+#define EFHW_VI_ISCSI_TX_DDIG_EN 0x10 /*! iscsi tx data digest */
|
|
+#define EFHW_VI_TX_PHYS_ADDR_EN 0x20 /*! TX physical address mode */
|
|
+#define EFHW_VI_RX_PHYS_ADDR_EN 0x40 /*! RX physical address mode */
|
|
+#define EFHW_VI_RM_WITH_INTERRUPT 0x80 /*! VI with an interrupt */
|
|
+#define EFHW_VI_TX_IP_CSUM_DIS 0x100 /*! enable ip checksum generation */
|
|
+#define EFHW_VI_TX_TCPUDP_CSUM_DIS 0x200 /*! enable tcp/udp checksum
|
|
+ generation */
|
|
+#define EFHW_VI_TX_TCPUDP_ONLY 0x400 /*! drop non-tcp/udp packets */
|
|
+
|
|
+/* Types of hardware filter */
|
|
+/* Each of these values implicitly selects scatter filters on B0 - or in
|
|
+ EFHW_IP_FILTER_TYPE_NOSCAT_B0_MASK if a non-scatter filter is required */
|
|
+#define EFHW_IP_FILTER_TYPE_UDP_WILDCARD (0) /* dest host only */
|
|
+#define EFHW_IP_FILTER_TYPE_UDP_FULL (1) /* dest host and port */
|
|
+#define EFHW_IP_FILTER_TYPE_TCP_WILDCARD (2) /* dest based filter */
|
|
+#define EFHW_IP_FILTER_TYPE_TCP_FULL (3) /* src filter */
|
|
+/* Same again, but with RSS (for B0 only) */
|
|
+#define EFHW_IP_FILTER_TYPE_UDP_WILDCARD_RSS_B0 (4)
|
|
+#define EFHW_IP_FILTER_TYPE_UDP_FULL_RSS_B0 (5)
|
|
+#define EFHW_IP_FILTER_TYPE_TCP_WILDCARD_RSS_B0 (6)
|
|
+#define EFHW_IP_FILTER_TYPE_TCP_FULL_RSS_B0 (7)
|
|
+
|
|
+#define EFHW_IP_FILTER_TYPE_FULL_MASK (0x1) /* Mask for full / wildcard */
|
|
+#define EFHW_IP_FILTER_TYPE_TCP_MASK (0x2) /* Mask for TCP type */
|
|
+#define EFHW_IP_FILTER_TYPE_RSS_B0_MASK (0x4) /* Mask for B0 RSS enable */
|
|
+#define EFHW_IP_FILTER_TYPE_NOSCAT_B0_MASK (0x8) /* Mask for B0 SCATTER dsbl */
|
|
+
|
|
+#define EFHW_IP_FILTER_TYPE_MASK (0xffff) /* Mask of types above */
|
|
+
|
|
+#define EFHW_IP_FILTER_BROADCAST (0x10000) /* driverlink filter
|
|
+ support */
|
|
+
|
|
+#endif /* __CI_EFHW_COMMON_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efhw/common_sysdep.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,61 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides version-independent Linux kernel API for
|
|
+ * userland-to-kernel interfaces.
|
|
+ * Only kernels >=2.6.9 are supported.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_EFHW_COMMON_LINUX_H__
|
|
+#define __CI_EFHW_COMMON_LINUX_H__
|
|
+
|
|
+#include <linux/types.h>
|
|
+
|
|
+/* Dirty hack, but Linux kernel does not provide DMA_ADDR_T_FMT */
|
|
+#if BITS_PER_LONG == 64 || defined(CONFIG_HIGHMEM64G)
|
|
+#define DMA_ADDR_T_FMT "%llx"
|
|
+#else
|
|
+#define DMA_ADDR_T_FMT "%x"
|
|
+#endif
|
|
+
|
|
+/* Linux kernel also does not provide PRIx32... Sigh. */
|
|
+#define PRIx32 "x"
|
|
+
|
|
+#ifdef __ia64__
|
|
+# define PRIx64 "lx"
|
|
+#else
|
|
+# define PRIx64 "llx"
|
|
+#endif
|
|
+
|
|
+#endif /* __CI_EFHW_COMMON_LINUX_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efhw/debug.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,84 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides debug-related API for efhw library using Linux kernel
|
|
+ * primitives.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_EFHW_DEBUG_LINUX_H__
|
|
+#define __CI_EFHW_DEBUG_LINUX_H__
|
|
+
|
|
+#define EFHW_PRINTK_PREFIX "[sfc efhw] "
|
|
+
|
|
+#define EFHW_PRINTK(level, fmt, ...) \
|
|
+ printk(level EFHW_PRINTK_PREFIX fmt "\n", __VA_ARGS__)
|
|
+
|
|
+/* Following macros should be used with non-zero format parameters
|
|
+ * due to __VA_ARGS__ limitations. Use "%s" with __func__ if you can't
|
|
+ * find better parameters. */
|
|
+#define EFHW_ERR(fmt, ...) EFHW_PRINTK(KERN_ERR, fmt, __VA_ARGS__)
|
|
+#define EFHW_WARN(fmt, ...) EFHW_PRINTK(KERN_WARNING, fmt, __VA_ARGS__)
|
|
+#define EFHW_NOTICE(fmt, ...) EFHW_PRINTK(KERN_NOTICE, fmt, __VA_ARGS__)
|
|
+#if 0 && !defined(NDEBUG)
|
|
+#define EFHW_TRACE(fmt, ...) EFHW_PRINTK(KERN_DEBUG, fmt, __VA_ARGS__)
|
|
+#else
|
|
+#define EFHW_TRACE(fmt, ...)
|
|
+#endif
|
|
+
|
|
+#ifndef NDEBUG
|
|
+#define EFHW_ASSERT(cond) BUG_ON((cond) == 0)
|
|
+#define EFHW_DO_DEBUG(expr) expr
|
|
+#else
|
|
+#define EFHW_ASSERT(cond)
|
|
+#define EFHW_DO_DEBUG(expr)
|
|
+#endif
|
|
+
|
|
+#define EFHW_TEST(expr) \
|
|
+ do { \
|
|
+ if (unlikely(!(expr))) \
|
|
+ BUG(); \
|
|
+ } while (0)
|
|
+
|
|
+/* Build time asserts. We paste the line number into the type name
|
|
+ * so that the macro can be used more than once per file even if the
|
|
+ * compiler objects to multiple identical typedefs. Collisions
|
|
+ * between use in different header files is still possible. */
|
|
+#ifndef EFHW_BUILD_ASSERT
|
|
+#define __EFHW_BUILD_ASSERT_NAME(_x) __EFHW_BUILD_ASSERT_ILOATHECPP(_x)
|
|
+#define __EFHW_BUILD_ASSERT_ILOATHECPP(_x) __EFHW_BUILD_ASSERT__ ##_x
|
|
+#define EFHW_BUILD_ASSERT(e) \
|
|
+ typedef char __EFHW_BUILD_ASSERT_NAME(__LINE__)[(e) ? 1 : -1]
|
|
+#endif
|
|
+
|
|
+#endif /* __CI_EFHW_DEBUG_LINUX_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efhw/efhw_config.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,43 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides some limits used in both kernel and userland code.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_EFHW_EFAB_CONFIG_H__
|
|
+#define __CI_EFHW_EFAB_CONFIG_H__
|
|
+
|
|
+#define EFHW_MAX_NR_DEVS 5 /* max number of efhw devices supported */
|
|
+
|
|
+#endif /* __CI_EFHW_EFAB_CONFIG_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efhw/efhw_types.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,382 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides struct efhw_nic and some related types.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_EFHW_EFAB_TYPES_H__
|
|
+#define __CI_EFHW_EFAB_TYPES_H__
|
|
+
|
|
+#include <ci/efhw/efhw_config.h>
|
|
+#include <ci/efhw/hardware_sysdep.h>
|
|
+#include <ci/efhw/iopage_types.h>
|
|
+#include <ci/efhw/sysdep.h>
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * forward type declarations
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+struct efhw_nic;
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * Managed interface
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+struct efhw_buffer_table_allocation{
|
|
+ unsigned base;
|
|
+ unsigned order;
|
|
+};
|
|
+
|
|
+struct eventq_resource_hardware {
|
|
+ /*!iobuffer allocated for eventq - can be larger than eventq */
|
|
+ struct efhw_iopages iobuff;
|
|
+ unsigned iobuff_off;
|
|
+ struct efhw_buffer_table_allocation buf_tbl_alloc;
|
|
+ int capacity; /*!< capacity of event queue */
|
|
+};
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * event queues and event driven callbacks
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+struct efhw_keventq {
|
|
+ int lock;
|
|
+ caddr_t evq_base;
|
|
+ int32_t evq_ptr;
|
|
+ uint32_t evq_mask;
|
|
+ unsigned instance;
|
|
+ struct eventq_resource_hardware hw;
|
|
+ struct efhw_ev_handler *ev_handlers;
|
|
+};
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * filters
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+struct efhw_filter_spec {
|
|
+ uint dmaq_id;
|
|
+ uint32_t saddr_le32;
|
|
+ uint32_t daddr_le32;
|
|
+ uint16_t sport_le16;
|
|
+ uint16_t dport_le16;
|
|
+ unsigned tcp : 1;
|
|
+ unsigned full : 1;
|
|
+ unsigned rss : 1; /* not supported on A1 */
|
|
+ unsigned scatter : 1; /* not supported on A1 */
|
|
+};
|
|
+
|
|
+struct efhw_filter_depth {
|
|
+ unsigned needed;
|
|
+ unsigned max;
|
|
+};
|
|
+
|
|
+struct efhw_filter_search_limits {
|
|
+ unsigned tcp_full;
|
|
+ unsigned tcp_wild;
|
|
+ unsigned udp_full;
|
|
+ unsigned udp_wild;
|
|
+};
|
|
+
|
|
+
|
|
+/**********************************************************************
|
|
+ * Portable HW interface. ***************************************
|
|
+ **********************************************************************/
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * EtherFabric Functional units - configuration and control
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+struct efhw_func_ops {
|
|
+
|
|
+ /*-------------- Initialisation ------------ */
|
|
+
|
|
+ /*! close down all hardware functional units - leaves NIC in a safe
|
|
+ state for driver unload */
|
|
+ void (*close_hardware) (struct efhw_nic *nic);
|
|
+
|
|
+ /*! initialise all hardware functional units */
|
|
+ int (*init_hardware) (struct efhw_nic *nic,
|
|
+ struct efhw_ev_handler *,
|
|
+ const uint8_t *mac_addr, int non_irq_evq);
|
|
+
|
|
+ /*-------------- Interrupt support ------------ */
|
|
+
|
|
+ /*! Main interrupt routine
|
|
+ ** This function returns,
|
|
+ ** - zero, if the IRQ was not generated by EF1
|
|
+ ** - non-zero, if EF1 was the source of the IRQ
|
|
+ **
|
|
+ **
|
|
+ ** opaque is an OS provided pointer for use by the OS callbacks
|
|
+ ** e.g in Windows used to indicate DPC scheduled
|
|
+ */
|
|
+ int (*interrupt) (struct efhw_nic *nic);
|
|
+
|
|
+ /*! Enable the interrupt */
|
|
+ void (*interrupt_enable) (struct efhw_nic *nic);
|
|
+
|
|
+ /*! Disable the interrupt */
|
|
+ void (*interrupt_disable) (struct efhw_nic *nic);
|
|
+
|
|
+ /*! Set interrupt moderation strategy for the given IRQ unit
|
|
+ ** val is in usec
|
|
+ */
|
|
+ void (*set_interrupt_moderation)(struct efhw_nic *nic, int evq,
|
|
+ uint val);
|
|
+
|
|
+ /*-------------- Event support ------------ */
|
|
+
|
|
+ /*! Enable the given event queue
|
|
+ depending on the underlying implementation (EF1 or Falcon) then
|
|
+ either a q_base_addr in host memory, or a buffer base id should
|
|
+ be proivded
|
|
+ */
|
|
+ void (*event_queue_enable) (struct efhw_nic *nic,
|
|
+ uint evq, /* evnt queue index */
|
|
+ uint evq_size, /* units of #entries */
|
|
+ dma_addr_t q_base_addr, uint buf_base_id,
|
|
+ int interrupting);
|
|
+
|
|
+ /*! Disable the given event queue (and any associated timer) */
|
|
+ void (*event_queue_disable) (struct efhw_nic *nic, uint evq,
|
|
+ int timer_only);
|
|
+
|
|
+ /*! request wakeup from the NIC on a given event Q */
|
|
+ void (*wakeup_request) (struct efhw_nic *nic, dma_addr_t q_base_addr,
|
|
+ int next_i, int evq);
|
|
+
|
|
+ /*! Push a SW event on a given eventQ */
|
|
+ void (*sw_event) (struct efhw_nic *nic, int data, int evq);
|
|
+
|
|
+ /*-------------- IP Filter API ------------ */
|
|
+
|
|
+ /*! Setup a given filter - The software can request a filter_i,
|
|
+ * but some EtherFabric implementations will override with
|
|
+ * a more suitable index
|
|
+ */
|
|
+ int (*ipfilter_set) (struct efhw_nic *nic, int type,
|
|
+ int *filter_i, int dmaq,
|
|
+ unsigned saddr_be32, unsigned sport_be16,
|
|
+ unsigned daddr_be32, unsigned dport_be16);
|
|
+
|
|
+ /*! Clear down a given filter */
|
|
+ void (*ipfilter_clear) (struct efhw_nic *nic, int filter_idx);
|
|
+
|
|
+ /*-------------- DMA support ------------ */
|
|
+
|
|
+ /*! Initialise NIC state for a given TX DMAQ */
|
|
+ void (*dmaq_tx_q_init) (struct efhw_nic *nic,
|
|
+ uint dmaq, uint evq, uint owner, uint tag,
|
|
+ uint dmaq_size, uint buf_idx, uint flags);
|
|
+
|
|
+ /*! Initialise NIC state for a given RX DMAQ */
|
|
+ void (*dmaq_rx_q_init) (struct efhw_nic *nic,
|
|
+ uint dmaq, uint evq, uint owner, uint tag,
|
|
+ uint dmaq_size, uint buf_idx, uint flags);
|
|
+
|
|
+ /*! Disable a given TX DMAQ */
|
|
+ void (*dmaq_tx_q_disable) (struct efhw_nic *nic, uint dmaq);
|
|
+
|
|
+ /*! Disable a given RX DMAQ */
|
|
+ void (*dmaq_rx_q_disable) (struct efhw_nic *nic, uint dmaq);
|
|
+
|
|
+ /*! Flush a given TX DMA channel */
|
|
+ int (*flush_tx_dma_channel) (struct efhw_nic *nic, uint dmaq);
|
|
+
|
|
+ /*! Flush a given RX DMA channel */
|
|
+ int (*flush_rx_dma_channel) (struct efhw_nic *nic, uint dmaq);
|
|
+
|
|
+ /*-------------- Buffer table Support ------------ */
|
|
+
|
|
+ /*! Initialise a buffer table page */
|
|
+ void (*buffer_table_set) (struct efhw_nic *nic,
|
|
+ dma_addr_t dma_addr,
|
|
+ uint bufsz, uint region,
|
|
+ int own_id, int buffer_id);
|
|
+
|
|
+ /*! Initialise a block of buffer table pages */
|
|
+ void (*buffer_table_set_n) (struct efhw_nic *nic, int buffer_id,
|
|
+ dma_addr_t dma_addr,
|
|
+ uint bufsz, uint region,
|
|
+ int n_pages, int own_id);
|
|
+
|
|
+ /*! Clear a block of buffer table pages */
|
|
+ void (*buffer_table_clear) (struct efhw_nic *nic, int buffer_id,
|
|
+ int num);
|
|
+
|
|
+ /*! Commit a buffer table update */
|
|
+ void (*buffer_table_commit) (struct efhw_nic *nic);
|
|
+
|
|
+ /*-------------- New filter API ------------ */
|
|
+
|
|
+ /*! Set a given filter */
|
|
+ int (*filter_set) (struct efhw_nic *nic, struct efhw_filter_spec *spec,
|
|
+ int *filter_idx_out);
|
|
+
|
|
+ /*! Clear a given filter */
|
|
+ void (*filter_clear) (struct efhw_nic *nic, int filter_idx);
|
|
+};
|
|
+
|
|
+
|
|
+/*----------------------------------------------------------------------------
|
|
+ *
|
|
+ * NIC type
|
|
+ *
|
|
+ *---------------------------------------------------------------------------*/
|
|
+
|
|
+struct efhw_device_type {
|
|
+ int arch; /* enum efhw_arch */
|
|
+ char variant; /* 'A', 'B', ... */
|
|
+ int revision; /* 0, 1, ... */
|
|
+};
|
|
+
|
|
+
|
|
+/*----------------------------------------------------------------------------
|
|
+ *
|
|
+ * EtherFabric NIC instance - nic.c for HW independent functions
|
|
+ *
|
|
+ *---------------------------------------------------------------------------*/
|
|
+
|
|
+/*! */
|
|
+struct efhw_nic {
|
|
+ /*! zero base index in efrm_nic_tablep->nic array */
|
|
+ int index;
|
|
+ int ifindex; /*!< OS level nic index */
|
|
+ struct net *nd_net;
|
|
+
|
|
+ struct efhw_device_type devtype;
|
|
+
|
|
+ /*! Options that can be set by user. */
|
|
+ unsigned options;
|
|
+# define NIC_OPT_EFTEST 0x1 /* owner is an eftest app */
|
|
+
|
|
+# define NIC_OPT_DEFAULT 0
|
|
+
|
|
+ /*! Internal flags that indicate hardware properties at runtime. */
|
|
+ unsigned flags;
|
|
+# define NIC_FLAG_NO_INTERRUPT 0x01 /* to be set at init time only */
|
|
+# define NIC_FLAG_TRY_MSI 0x02
|
|
+# define NIC_FLAG_MSI 0x04
|
|
+# define NIC_FLAG_OS_IRQ_EN 0x08
|
|
+
|
|
+ unsigned mtu; /*!< MAC MTU (includes MAC hdr) */
|
|
+
|
|
+ /* hardware resources */
|
|
+
|
|
+ /*! I/O address of the start of the bar */
|
|
+ volatile char __iomem *bar_ioaddr;
|
|
+
|
|
+ /*! Bar number of control aperture. */
|
|
+ unsigned ctr_ap_bar;
|
|
+ /*! Length of control aperture in bytes. */
|
|
+ unsigned ctr_ap_bytes;
|
|
+
|
|
+ uint8_t mac_addr[ETH_ALEN]; /*!< mac address */
|
|
+
|
|
+ /*! EtherFabric Functional Units -- functions */
|
|
+ const struct efhw_func_ops *efhw_func;
|
|
+
|
|
+ /*! This lock protects a number of misc NIC resources. It should
|
|
+ * only be used for things that can be at the bottom of the lock
|
|
+ * order. ie. You mustn't attempt to grab any other lock while
|
|
+ * holding this one.
|
|
+ */
|
|
+ spinlock_t *reg_lock;
|
|
+ spinlock_t the_reg_lock;
|
|
+
|
|
+ int buf_commit_outstanding; /*!< outstanding buffer commits */
|
|
+
|
|
+ /*! interrupt callbacks (hard-irq) */
|
|
+ void (*irq_handler) (struct efhw_nic *, int unit);
|
|
+
|
|
+ /*! event queues per driver */
|
|
+ struct efhw_keventq interrupting_evq;
|
|
+
|
|
+/* for marking when we are not using an IRQ unit
|
|
+ - 0 is a valid offset to an IRQ unit on EF1! */
|
|
+#define EFHW_IRQ_UNIT_UNUSED 0xffff
|
|
+ /*! interrupt unit in use for the interrupting event queue */
|
|
+ unsigned int irq_unit;
|
|
+
|
|
+ struct efhw_keventq non_interrupting_evq;
|
|
+
|
|
+ struct efhw_iopage irq_iobuff; /*!< Falcon SYSERR interrupt */
|
|
+
|
|
+ /* The new driverlink infrastructure. */
|
|
+ struct efx_dl_device *net_driver_dev;
|
|
+ struct efx_dlfilt_cb_s *dlfilter_cb;
|
|
+
|
|
+ /*! Bit masks of the sizes of event queues and dma queues supported
|
|
+ * by the nic. */
|
|
+ unsigned evq_sizes;
|
|
+ unsigned rxq_sizes;
|
|
+ unsigned txq_sizes;
|
|
+
|
|
+ /* Size of filter table. */
|
|
+ unsigned ip_filter_tbl_size;
|
|
+
|
|
+ /* Number of filters currently used */
|
|
+ unsigned ip_filter_tbl_used;
|
|
+
|
|
+ /* Dynamically allocated filter state. */
|
|
+ uint8_t *filter_in_use;
|
|
+ struct efhw_filter_spec *filter_spec_cache;
|
|
+
|
|
+ /* Currently required and maximum filter table search depths. */
|
|
+ struct efhw_filter_depth tcp_full_srch;
|
|
+ struct efhw_filter_depth tcp_wild_srch;
|
|
+ struct efhw_filter_depth udp_full_srch;
|
|
+ struct efhw_filter_depth udp_wild_srch;
|
|
+
|
|
+ /* Number of event queues, DMA queues and timers. */
|
|
+ unsigned num_evqs;
|
|
+ unsigned num_dmaqs;
|
|
+ unsigned num_timers;
|
|
+};
|
|
+
|
|
+
|
|
+#define EFHW_KVA(nic) ((nic)->bar_ioaddr)
|
|
+
|
|
+
|
|
+#endif /* __CI_EFHW_EFHW_TYPES_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efhw/eventq.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,72 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file contains API provided by efhw/eventq.c file. This file is not
|
|
+ * designed for use outside of the SFC resource driver.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_EFHW_EVENTQ_H__
|
|
+#define __CI_EFHW_EVENTQ_H__
|
|
+
|
|
+#include <ci/efhw/efhw_types.h>
|
|
+#include <ci/efhw/eventq_macros.h>
|
|
+
|
|
+/*! Poll the event queue. */
|
|
+extern int efhw_keventq_poll(struct efhw_nic *, struct efhw_keventq *);
|
|
+
|
|
+/*! Callbacks for handling events. */
|
|
+struct efhw_ev_handler {
|
|
+ void (*wakeup_fn)(struct efhw_nic *nic, unsigned);
|
|
+ void (*timeout_fn)(struct efhw_nic *nic, unsigned);
|
|
+ void (*dmaq_flushed_fn) (struct efhw_nic *, unsigned, int);
|
|
+};
|
|
+
|
|
+extern int efhw_keventq_ctor(struct efhw_nic *, int instance,
|
|
+ struct efhw_keventq *, struct efhw_ev_handler *);
|
|
+extern void efhw_keventq_dtor(struct efhw_nic *, struct efhw_keventq *);
|
|
+
|
|
+extern void efhw_handle_txdmaq_flushed(struct efhw_nic *,
|
|
+ struct efhw_ev_handler *,
|
|
+ efhw_event_t *);
|
|
+extern void efhw_handle_rxdmaq_flushed(struct efhw_nic *,
|
|
+ struct efhw_ev_handler *,
|
|
+ efhw_event_t *);
|
|
+extern void efhw_handle_wakeup_event(struct efhw_nic *,
|
|
+ struct efhw_ev_handler *,
|
|
+ efhw_event_t *);
|
|
+extern void efhw_handle_timeout_event(struct efhw_nic *,
|
|
+ struct efhw_ev_handler *,
|
|
+ efhw_event_t *);
|
|
+
|
|
+#endif /* __CI_EFHW_EVENTQ_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efhw/eventq_macros.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,77 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides some event-related macros. This file is designed for
|
|
+ * use from kernel and from the userland contexts.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_EFHW_EVENTQ_MACROS_H__
|
|
+#define __CI_EFHW_EVENTQ_MACROS_H__
|
|
+
|
|
+#include <ci/efhw/common.h>
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * Event Queue manipulation
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+#define EFHW_EVENT_OFFSET(q, s, i) \
|
|
+ (((s)->evq_ptr - (i) * (int32_t)sizeof(efhw_event_t)) \
|
|
+ & (q)->evq_mask)
|
|
+
|
|
+#define EFHW_EVENT_PTR(q, s, i) \
|
|
+ ((efhw_event_t *)((q)->evq_base + EFHW_EVENT_OFFSET(q, s, i)))
|
|
+
|
|
+#define EFHW_EVENTQ_NEXT(s) \
|
|
+ do { ((s)->evq_ptr += sizeof(efhw_event_t)); } while (0)
|
|
+
|
|
+#define EFHW_EVENTQ_PREV(s) \
|
|
+ do { ((s)->evq_ptr -= sizeof(efhw_event_t)); } while (0)
|
|
+
|
|
+/* Be worried about this on byteswapped machines */
|
|
+/* Due to crazy chipsets, we see the event words being written in
|
|
+** arbitrary order (bug4539). So test for presence of event must ensure
|
|
+** that both halves have changed from the null.
|
|
+*/
|
|
+#define EFHW_IS_EVENT(evp) \
|
|
+ (((evp)->opaque.a != (uint32_t)-1) && \
|
|
+ ((evp)->opaque.b != (uint32_t)-1))
|
|
+#define EFHW_CLEAR_EVENT(evp) ((evp)->u64 = (uint64_t)-1)
|
|
+#define EFHW_CLEAR_EVENT_VALUE 0xff
|
|
+
|
|
+#define EFHW_EVENT_OVERFLOW(evq, s) \
|
|
+ (EFHW_IS_EVENT(EFHW_EVENT_PTR(evq, s, 1)))
|
|
+
|
|
+#endif /* __CI_EFHW_EVENTQ_MACROS_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efhw/falcon.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,94 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file contains API provided by efhw/falcon.c file. This file is not
|
|
+ * designed for use outside of the SFC resource driver.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_EFHW_FALCON_H__
|
|
+#define __CI_EFHW_FALCON_H__
|
|
+
|
|
+#include <ci/efhw/efhw_types.h>
|
|
+#include <ci/efhw/common.h>
|
|
+
|
|
+/*----------------------------------------------------------------------------
|
|
+ *
|
|
+ * Locks - unfortunately required
|
|
+ *
|
|
+ *---------------------------------------------------------------------------*/
|
|
+
|
|
+#define FALCON_LOCK_DECL irq_flags_t lock_state
|
|
+#define FALCON_LOCK_LOCK(nic) \
|
|
+ spin_lock_irqsave((nic)->reg_lock, lock_state)
|
|
+#define FALCON_LOCK_UNLOCK(nic) \
|
|
+ spin_unlock_irqrestore((nic)->reg_lock, lock_state)
|
|
+
|
|
+extern struct efhw_func_ops falcon_char_functional_units;
|
|
+
|
|
+/*! specify a pace value for a TX DMA Queue */
|
|
+extern void falcon_nic_pace(struct efhw_nic *nic, uint dmaq, uint pace);
|
|
+
|
|
+/*! configure the pace engine */
|
|
+extern void falcon_nic_pace_cfg(struct efhw_nic *nic, int fb_base,
|
|
+ int bin_thresh);
|
|
+
|
|
+/*! confirm buffer table updates - should be used for items where
|
|
+ loss of data would be unacceptable. E.g for the buffers that back
|
|
+ an event or DMA queue */
|
|
+extern void falcon_nic_buffer_table_confirm(struct efhw_nic *nic);
|
|
+
|
|
+/*! Reset the all the TX DMA queue pointers. */
|
|
+extern void falcon_clobber_tx_dma_ptrs(struct efhw_nic *nic, uint dmaq);
|
|
+
|
|
+extern int
|
|
+falcon_handle_char_event(struct efhw_nic *nic,
|
|
+ struct efhw_ev_handler *h, efhw_event_t *evp);
|
|
+
|
|
+/*! Acknowledge to HW that processing is complete on a given event queue */
|
|
+extern void falcon_nic_evq_ack(struct efhw_nic *nic, uint evq, /* evq id */
|
|
+ uint rptr, /* new read pointer update */
|
|
+ bool wakeup /* request a wakeup event if
|
|
+ ptr's != */
|
|
+ );
|
|
+
|
|
+extern void
|
|
+falcon_nic_buffer_table_set_n(struct efhw_nic *nic, int buffer_id,
|
|
+ dma_addr_t dma_addr, uint bufsz, uint region,
|
|
+ int n_pages, int own_id);
|
|
+
|
|
+extern int falcon_nic_filter_ctor(struct efhw_nic *nic);
|
|
+
|
|
+extern void falcon_nic_filter_dtor(struct efhw_nic *nic);
|
|
+
|
|
+#endif /* __CI_EFHW_FALCON_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efhw/falcon_hash.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,58 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file contains API provided by efhw/falcon_hash.c file.
|
|
+ * Function declared in this file are not exported from the Linux
|
|
+ * sfc_resource driver.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_EFHW_FALCON_HASH_H__
|
|
+#define __CI_EFHW_FALCON_HASH_H__
|
|
+
|
|
+extern unsigned int
|
|
+falcon_hash_get_ip_key(unsigned int src_ip, unsigned int src_port,
|
|
+ unsigned int dest_ip, unsigned int dest_port,
|
|
+ int tcp, int full);
|
|
+
|
|
+extern unsigned int
|
|
+falcon_hash_function1(unsigned int key, unsigned int nfilters);
|
|
+
|
|
+extern unsigned int
|
|
+falcon_hash_function2(unsigned int key, unsigned int nfilters);
|
|
+
|
|
+extern unsigned int
|
|
+falcon_hash_iterator(unsigned int hash1, unsigned int hash2,
|
|
+ unsigned int n_search, unsigned int nfilters);
|
|
+
|
|
+#endif /* __CI_EFHW_FALCON_HASH_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efhw/hardware_sysdep.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,69 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides version-independent Linux kernel API for header files
|
|
+ * with hardware-related definitions (in ci/driver/efab/hardware*).
|
|
+ * Only kernels >=2.6.9 are supported.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_EFHW_HARDWARE_LINUX_H__
|
|
+#define __CI_EFHW_HARDWARE_LINUX_H__
|
|
+
|
|
+#include <linux/io.h>
|
|
+
|
|
+#ifdef __LITTLE_ENDIAN
|
|
+#define EFHW_IS_LITTLE_ENDIAN
|
|
+#elif __BIG_ENDIAN
|
|
+#define EFHW_IS_BIG_ENDIAN
|
|
+#else
|
|
+#error Unknown endianness
|
|
+#endif
|
|
+
|
|
+#ifndef readq
|
|
+static inline uint64_t __readq(volatile void __iomem *addr)
|
|
+{
|
|
+ return *(volatile uint64_t *)addr;
|
|
+}
|
|
+#define readq(x) __readq(x)
|
|
+#endif
|
|
+
|
|
+#ifndef writeq
|
|
+static inline void __writeq(uint64_t v, volatile void __iomem *addr)
|
|
+{
|
|
+ *(volatile uint64_t *)addr = v;
|
|
+}
|
|
+#define writeq(val, addr) __writeq((val), (addr))
|
|
+#endif
|
|
+
|
|
+#endif /* __CI_EFHW_HARDWARE_LINUX_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efhw/iopage.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,58 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file contains OS-independent API for allocating iopage types.
|
|
+ * The implementation of these functions is highly OS-dependent.
|
|
+ * This file is not designed for use outside of the SFC resource driver.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_DRIVER_RESOURCE_IOPAGE_H__
|
|
+#define __CI_DRIVER_RESOURCE_IOPAGE_H__
|
|
+
|
|
+#include <ci/efhw/efhw_types.h>
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * memory allocation
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+extern int efhw_iopage_alloc(struct efhw_nic *, struct efhw_iopage *p);
|
|
+extern void efhw_iopage_free(struct efhw_nic *, struct efhw_iopage *p);
|
|
+
|
|
+extern int efhw_iopages_alloc(struct efhw_nic *, struct efhw_iopages *p,
|
|
+ unsigned order);
|
|
+extern void efhw_iopages_free(struct efhw_nic *, struct efhw_iopages *p);
|
|
+
|
|
+#endif /* __CI_DRIVER_RESOURCE_IOPAGE_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efhw/iopage_types.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,190 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides struct efhw_page and struct efhw_iopage for Linux
|
|
+ * kernel.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_EFHW_IOPAGE_LINUX_H__
|
|
+#define __CI_EFHW_IOPAGE_LINUX_H__
|
|
+
|
|
+#include <linux/gfp.h>
|
|
+#include <linux/hardirq.h>
|
|
+#include <linux/errno.h>
|
|
+#include <ci/efhw/debug.h>
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * struct efhw_page: A single page of memory. Directly mapped in the
|
|
+ * driver, and can be mapped to userlevel.
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+struct efhw_page {
|
|
+ unsigned long kva;
|
|
+};
|
|
+
|
|
+static inline int efhw_page_alloc(struct efhw_page *p)
|
|
+{
|
|
+ p->kva = __get_free_page(in_interrupt()? GFP_ATOMIC : GFP_KERNEL);
|
|
+ return p->kva ? 0 : -ENOMEM;
|
|
+}
|
|
+
|
|
+static inline int efhw_page_alloc_zeroed(struct efhw_page *p)
|
|
+{
|
|
+ p->kva = get_zeroed_page(in_interrupt()? GFP_ATOMIC : GFP_KERNEL);
|
|
+ return p->kva ? 0 : -ENOMEM;
|
|
+}
|
|
+
|
|
+static inline void efhw_page_free(struct efhw_page *p)
|
|
+{
|
|
+ free_page(p->kva);
|
|
+ EFHW_DO_DEBUG(memset(p, 0, sizeof(*p)));
|
|
+}
|
|
+
|
|
+static inline char *efhw_page_ptr(struct efhw_page *p)
|
|
+{
|
|
+ return (char *)p->kva;
|
|
+}
|
|
+
|
|
+static inline unsigned efhw_page_pfn(struct efhw_page *p)
|
|
+{
|
|
+ return (unsigned)(__pa(p->kva) >> PAGE_SHIFT);
|
|
+}
|
|
+
|
|
+static inline void efhw_page_mark_invalid(struct efhw_page *p)
|
|
+{
|
|
+ p->kva = 0;
|
|
+}
|
|
+
|
|
+static inline int efhw_page_is_valid(struct efhw_page *p)
|
|
+{
|
|
+ return p->kva != 0;
|
|
+}
|
|
+
|
|
+static inline void efhw_page_init_from_va(struct efhw_page *p, void *va)
|
|
+{
|
|
+ p->kva = (unsigned long)va;
|
|
+}
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * struct efhw_iopage: A single page of memory. Directly mapped in the driver,
|
|
+ * and can be mapped to userlevel. Can also be accessed by the NIC.
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+struct efhw_iopage {
|
|
+ struct efhw_page p;
|
|
+ dma_addr_t dma_addr;
|
|
+};
|
|
+
|
|
+static inline dma_addr_t efhw_iopage_dma_addr(struct efhw_iopage *p)
|
|
+{
|
|
+ return p->dma_addr;
|
|
+}
|
|
+
|
|
+#define efhw_iopage_ptr(iop) efhw_page_ptr(&(iop)->p)
|
|
+#define efhw_iopage_pfn(iop) efhw_page_pfn(&(iop)->p)
|
|
+#define efhw_iopage_mark_invalid(iop) efhw_page_mark_invalid(&(iop)->p)
|
|
+#define efhw_iopage_is_valid(iop) efhw_page_is_valid(&(iop)->p)
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * struct efhw_iopages: A set of pages that are contiguous in physical
|
|
+ * memory. Directly mapped in the driver, and can be mapped to userlevel.
|
|
+ * Can also be accessed by the NIC.
|
|
+ *
|
|
+ * NB. The O/S may be unwilling to allocate many, or even any of these. So
|
|
+ * only use this type where the NIC really needs a physically contiguous
|
|
+ * buffer.
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+struct efhw_iopages {
|
|
+ caddr_t kva;
|
|
+ unsigned order;
|
|
+ dma_addr_t dma_addr;
|
|
+};
|
|
+
|
|
+static inline caddr_t efhw_iopages_ptr(struct efhw_iopages *p)
|
|
+{
|
|
+ return p->kva;
|
|
+}
|
|
+
|
|
+static inline unsigned efhw_iopages_pfn(struct efhw_iopages *p)
|
|
+{
|
|
+ return (unsigned)(__pa(p->kva) >> PAGE_SHIFT);
|
|
+}
|
|
+
|
|
+static inline dma_addr_t efhw_iopages_dma_addr(struct efhw_iopages *p)
|
|
+{
|
|
+ return p->dma_addr;
|
|
+}
|
|
+
|
|
+static inline unsigned efhw_iopages_size(struct efhw_iopages *p)
|
|
+{
|
|
+ return 1u << (p->order + PAGE_SHIFT);
|
|
+}
|
|
+
|
|
+/* struct efhw_iopage <-> struct efhw_iopages conversions for handling
|
|
+ * physically contiguous allocations in iobufsets for iSCSI. This allows
|
|
+ * the essential information about contiguous allocations from
|
|
+ * efhw_iopages_alloc() to be saved away in the struct efhw_iopage array in
|
|
+ * an iobufset. (Changing the iobufset resource to use a union type would
|
|
+ * involve a lot of code changes, and make the iobufset's metadata larger
|
|
+ * which could be bad as it's supposed to fit into a single page on some
|
|
+ * platforms.)
|
|
+ */
|
|
+static inline void
|
|
+efhw_iopage_init_from_iopages(struct efhw_iopage *iopage,
|
|
+ struct efhw_iopages *iopages, unsigned pageno)
|
|
+{
|
|
+ iopage->p.kva = ((unsigned long)efhw_iopages_ptr(iopages))
|
|
+ + (pageno * PAGE_SIZE);
|
|
+ iopage->dma_addr = efhw_iopages_dma_addr(iopages) +
|
|
+ (pageno * PAGE_SIZE);
|
|
+}
|
|
+
|
|
+static inline void
|
|
+efhw_iopages_init_from_iopage(struct efhw_iopages *iopages,
|
|
+ struct efhw_iopage *iopage, unsigned order)
|
|
+{
|
|
+ iopages->kva = (caddr_t) efhw_iopage_ptr(iopage);
|
|
+ EFHW_ASSERT(iopages->kva);
|
|
+ iopages->order = order;
|
|
+ iopages->dma_addr = efhw_iopage_dma_addr(iopage);
|
|
+}
|
|
+
|
|
+#endif /* __CI_EFHW_IOPAGE_LINUX_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efhw/nic.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,62 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file contains API provided by efhw/nic.c file. This file is not
|
|
+ * designed for use outside of the SFC resource driver.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_EFHW_NIC_H__
|
|
+#define __CI_EFHW_NIC_H__
|
|
+
|
|
+#include <ci/efhw/efhw_types.h>
|
|
+#include <ci/efhw/public.h>
|
|
+
|
|
+
|
|
+/* Convert PCI info to device type. Returns false when device is not
|
|
+ * recognised.
|
|
+ */
|
|
+extern int efhw_device_type_init(struct efhw_device_type *dt,
|
|
+ int vendor_id, int device_id, int revision);
|
|
+
|
|
+/* Initialise fields that do not involve touching hardware. */
|
|
+extern void efhw_nic_init(struct efhw_nic *nic, unsigned flags,
|
|
+ unsigned options, struct efhw_device_type dev_type);
|
|
+
|
|
+/*! Destruct NIC resources */
|
|
+extern void efhw_nic_dtor(struct efhw_nic *nic);
|
|
+
|
|
+/*! Shutdown interrupts */
|
|
+extern void efhw_nic_close_interrupts(struct efhw_nic *nic);
|
|
+
|
|
+#endif /* __CI_EFHW_NIC_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efhw/public.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,104 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides public API of efhw library exported from the SFC
|
|
+ * resource driver.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_EFHW_PUBLIC_H__
|
|
+#define __CI_EFHW_PUBLIC_H__
|
|
+
|
|
+#include <ci/efhw/common.h>
|
|
+#include <ci/efhw/efhw_types.h>
|
|
+
|
|
+/*! Returns true if we have some EtherFabric functional units -
|
|
+ whether configured or not */
|
|
+static inline int efhw_nic_have_functional_units(struct efhw_nic *nic)
|
|
+{
|
|
+ return nic->efhw_func != 0;
|
|
+}
|
|
+
|
|
+/*! Returns true if the EtherFabric functional units have been configured */
|
|
+static inline int efhw_nic_have_hw(struct efhw_nic *nic)
|
|
+{
|
|
+ return efhw_nic_have_functional_units(nic) && (EFHW_KVA(nic) != 0);
|
|
+}
|
|
+
|
|
+/*! Helper function to allocate the iobuffer needed by an eventq
|
|
+ * - it ensures the eventq has the correct alignment for the NIC
|
|
+ *
|
|
+ * \param rm Event-queue resource manager
|
|
+ * \param instance Event-queue instance (index)
|
|
+ * \param buf_bytes Requested size of eventq
|
|
+ * \return < 0 if iobuffer allocation fails
|
|
+ */
|
|
+int efhw_nic_event_queue_alloc_iobuffer(struct efhw_nic *nic,
|
|
+ struct eventq_resource_hardware *h,
|
|
+ int evq_instance, unsigned buf_bytes);
|
|
+
|
|
+extern void falcon_nic_set_rx_usr_buf_size(struct efhw_nic *,
|
|
+ int rx_usr_buf_size);
|
|
+
|
|
+/*! Get RX filter search limits from RX_FILTER_CTL_REG.
|
|
+ * use_raw_values = 0 to get actual depth of search, or 1 to get raw values
|
|
+ * from register.
|
|
+ */
|
|
+extern void
|
|
+falcon_nic_get_rx_filter_search_limits(struct efhw_nic *nic,
|
|
+ struct efhw_filter_search_limits *lim,
|
|
+ int use_raw_values);
|
|
+
|
|
+/*! Set RX filter search limits in RX_FILTER_CTL_REG.
|
|
+ * use_raw_values = 0 if specifying actual depth of search, or 1 if specifying
|
|
+ * raw values to write to the register.
|
|
+ */
|
|
+extern void
|
|
+falcon_nic_set_rx_filter_search_limits(struct efhw_nic *nic,
|
|
+ struct efhw_filter_search_limits *lim,
|
|
+ int use_raw_values);
|
|
+
|
|
+
|
|
+/*! Legacy RX IP filter search depth control interface */
|
|
+extern void
|
|
+falcon_nic_rx_filter_ctl_set(struct efhw_nic *nic, uint32_t tcp_full,
|
|
+ uint32_t tcp_wild,
|
|
+ uint32_t udp_full, uint32_t udp_wild);
|
|
+
|
|
+/*! Legacy RX IP filter search depth control interface */
|
|
+extern void
|
|
+falcon_nic_rx_filter_ctl_get(struct efhw_nic *nic, uint32_t *tcp_full,
|
|
+ uint32_t *tcp_wild,
|
|
+ uint32_t *udp_full, uint32_t *udp_wild);
|
|
+
|
|
+#endif /* __CI_EFHW_PUBLIC_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efhw/sysdep.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,55 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides version-independent Linux kernel API for efhw library.
|
|
+ * Only kernels >=2.6.9 are supported.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_EFHW_SYSDEP_LINUX_H__
|
|
+#define __CI_EFHW_SYSDEP_LINUX_H__
|
|
+
|
|
+#include <linux/module.h>
|
|
+#include <linux/spinlock.h>
|
|
+#include <linux/delay.h>
|
|
+#include <linux/vmalloc.h>
|
|
+#include <linux/if_ether.h>
|
|
+
|
|
+#include <linux/netdevice.h> /* necessary for etherdevice.h on some kernels */
|
|
+#include <linux/etherdevice.h>
|
|
+
|
|
+typedef unsigned long irq_flags_t;
|
|
+
|
|
+#define spin_lock_destroy(l_) do {} while (0)
|
|
+
|
|
+#endif /* __CI_EFHW_SYSDEP_LINUX_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efrm/buddy.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,68 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides private API for buddy allocator. This API is not
|
|
+ * designed for use outside of SFC resource driver.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_EFRM_BUDDY_H__
|
|
+#define __CI_EFRM_BUDDY_H__
|
|
+
|
|
+#include <ci/efrm/sysdep.h>
|
|
+
|
|
+/*! Comment? */
|
|
+struct efrm_buddy_allocator {
|
|
+ struct list_head *free_lists; /* array[order+1] */
|
|
+ struct list_head *links; /* array[1<<order] */
|
|
+ uint8_t *orders; /* array[1<<order] */
|
|
+ unsigned order; /*!< total size == (1 << order) */
|
|
+ /* ?? Consider recording largest available order + for each order the
|
|
+ ** smallest available order that is big enough.
|
|
+ */
|
|
+};
|
|
+
|
|
+ /*! Returns total size of managed space. */
|
|
+static inline unsigned long efrm_buddy_size(struct efrm_buddy_allocator *b)
|
|
+{
|
|
+ return 1ul << b->order;
|
|
+}
|
|
+
|
|
+int efrm_buddy_ctor(struct efrm_buddy_allocator *b, unsigned order);
|
|
+void efrm_buddy_dtor(struct efrm_buddy_allocator *b);
|
|
+int efrm_buddy_alloc(struct efrm_buddy_allocator *b, unsigned order);
|
|
+void efrm_buddy_free(struct efrm_buddy_allocator *b, unsigned addr,
|
|
+ unsigned order);
|
|
+
|
|
+
|
|
+#endif /* __CI_EFRM_BUDDY_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efrm/buffer_table.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,81 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides private buffer table API. This API is not designed
|
|
+ * for use outside of SFC resource driver.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_EFRM_BUFFER_TABLE_H__
|
|
+#define __CI_EFRM_BUFFER_TABLE_H__
|
|
+
|
|
+#include <ci/efhw/efhw_types.h>
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * NIC's buffer table.
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+/*! Managed interface. */
|
|
+
|
|
+/*! construct a managed buffer table object, allocated over a region of
|
|
+ * the NICs buffer table space
|
|
+ */
|
|
+extern int efrm_buffer_table_ctor(unsigned low, unsigned high);
|
|
+/*! destructor for above */
|
|
+extern void efrm_buffer_table_dtor(void);
|
|
+
|
|
+/*! allocate a contiguous region of buffer table space */
|
|
+extern int efrm_buffer_table_alloc(unsigned order,
|
|
+ struct efhw_buffer_table_allocation *a);
|
|
+
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * buffer table operations through the HW independent API
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+/*! free a previously allocated region of buffer table space */
|
|
+extern void efrm_buffer_table_free(struct efhw_buffer_table_allocation *a);
|
|
+
|
|
+/*! commit the update of a buffer table entry to every NIC */
|
|
+extern void efrm_buffer_table_commit(void);
|
|
+
|
|
+extern void efrm_buffer_table_set(struct efhw_buffer_table_allocation *,
|
|
+ struct efhw_nic *,
|
|
+ unsigned i, dma_addr_t dma_addr, int owner);
|
|
+
|
|
+
|
|
+#endif /* __CI_EFRM_BUFFER_TABLE_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efrm/debug.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,78 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides debug-related API for efrm library using Linux kernel
|
|
+ * primitives.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_EFRM_DEBUG_LINUX_H__
|
|
+#define __CI_EFRM_DEBUG_LINUX_H__
|
|
+
|
|
+#define EFRM_PRINTK_PREFIX "[sfc efrm] "
|
|
+
|
|
+#define EFRM_PRINTK(level, fmt, ...) \
|
|
+ printk(level EFRM_PRINTK_PREFIX fmt "\n", __VA_ARGS__)
|
|
+
|
|
+/* Following macros should be used with non-zero format parameters
|
|
+ * due to __VA_ARGS__ limitations. Use "%s" with __func__ if you can't
|
|
+ * find better parameters. */
|
|
+#define EFRM_ERR(fmt, ...) EFRM_PRINTK(KERN_ERR, fmt, __VA_ARGS__)
|
|
+#define EFRM_WARN(fmt, ...) EFRM_PRINTK(KERN_WARNING, fmt, __VA_ARGS__)
|
|
+#define EFRM_NOTICE(fmt, ...) EFRM_PRINTK(KERN_NOTICE, fmt, __VA_ARGS__)
|
|
+#if !defined(NDEBUG)
|
|
+#define EFRM_TRACE(fmt, ...) EFRM_PRINTK(KERN_DEBUG, fmt, __VA_ARGS__)
|
|
+#else
|
|
+#define EFRM_TRACE(fmt, ...)
|
|
+#endif
|
|
+
|
|
+#ifndef NDEBUG
|
|
+#define EFRM_ASSERT(cond) BUG_ON((cond) == 0)
|
|
+#define _EFRM_ASSERT(cond, file, line) \
|
|
+ do { \
|
|
+ if (unlikely(!(cond))) { \
|
|
+ EFRM_ERR("assertion \"%s\" failed at %s %d", \
|
|
+ #cond, file, line); \
|
|
+ BUG(); \
|
|
+ } \
|
|
+ } while (0)
|
|
+
|
|
+#define EFRM_DO_DEBUG(expr) expr
|
|
+#define EFRM_VERIFY_EQ(expr, val) EFRM_ASSERT((expr) == (val))
|
|
+#else
|
|
+#define EFRM_ASSERT(cond)
|
|
+#define EFRM_DO_DEBUG(expr)
|
|
+#define EFRM_VERIFY_EQ(expr, val) expr
|
|
+#endif
|
|
+
|
|
+#endif /* __CI_EFRM_DEBUG_LINUX_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efrm/driver_private.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,89 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides private API of efrm library to be used from the SFC
|
|
+ * resource driver.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_EFRM_DRIVER_PRIVATE_H__
|
|
+#define __CI_EFRM_DRIVER_PRIVATE_H__
|
|
+
|
|
+#include <ci/efrm/resource.h>
|
|
+#include <ci/efrm/sysdep.h>
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * global variables
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+/* Internal structure for resource driver */
|
|
+extern struct efrm_resource_manager *efrm_rm_table[];
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * efrm_nic_table handling
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+struct efrm_nic;
|
|
+
|
|
+extern void efrm_driver_ctor(void);
|
|
+extern void efrm_driver_dtor(void);
|
|
+extern int efrm_driver_register_nic(struct efrm_nic *, int nic_index,
|
|
+ int ifindex);
|
|
+extern int efrm_driver_unregister_nic(struct efrm_nic *);
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * create/destroy resource managers
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+struct vi_resource_dimensions {
|
|
+ unsigned evq_int_min, evq_int_lim;
|
|
+ unsigned evq_timer_min, evq_timer_lim;
|
|
+ unsigned rxq_min, rxq_lim;
|
|
+ unsigned txq_min, txq_lim;
|
|
+};
|
|
+
|
|
+/*! Initialise resources */
|
|
+extern int
|
|
+efrm_resources_init(const struct vi_resource_dimensions *,
|
|
+ int buffer_table_min, int buffer_table_lim);
|
|
+
|
|
+/*! Tear down resources */
|
|
+extern void efrm_resources_fini(void);
|
|
+
|
|
+#endif /* __CI_EFRM_DRIVER_PRIVATE_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efrm/efrm_client.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,32 @@
|
|
+#ifndef __EFRM_CLIENT_H__
|
|
+#define __EFRM_CLIENT_H__
|
|
+
|
|
+
|
|
+struct efrm_client;
|
|
+
|
|
+
|
|
+struct efrm_client_callbacks {
|
|
+ /* Called before device is reset. Callee may block. */
|
|
+ void (*pre_reset)(struct efrm_client *, void *user_data);
|
|
+ void (*stop)(struct efrm_client *, void *user_data);
|
|
+ void (*restart)(struct efrm_client *, void *user_data);
|
|
+};
|
|
+
|
|
+
|
|
+#define EFRM_IFINDEX_DEFAULT -1
|
|
+
|
|
+
|
|
+/* NB. Callbacks may be invoked even before this returns. */
|
|
+extern int efrm_client_get(int ifindex, struct efrm_client_callbacks *,
|
|
+ void *user_data, struct efrm_client **client_out);
|
|
+extern void efrm_client_put(struct efrm_client *);
|
|
+
|
|
+extern struct efhw_nic *efrm_client_get_nic(struct efrm_client *);
|
|
+
|
|
+#if 0
|
|
+/* For each resource type... */
|
|
+extern void efrm_x_resource_resume(struct x_resource *);
|
|
+#endif
|
|
+
|
|
+
|
|
+#endif /* __EFRM_CLIENT_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efrm/efrm_nic.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,26 @@
|
|
+#ifndef __EFRM_NIC_H__
|
|
+#define __EFRM_NIC_H__
|
|
+
|
|
+#include <ci/efhw/efhw_types.h>
|
|
+
|
|
+
|
|
+struct efrm_nic_per_vi {
|
|
+ unsigned long state;
|
|
+ struct vi_resource *vi;
|
|
+};
|
|
+
|
|
+
|
|
+struct efrm_nic {
|
|
+ struct efhw_nic efhw_nic;
|
|
+ struct list_head link;
|
|
+ struct list_head clients;
|
|
+ struct efrm_nic_per_vi *vis;
|
|
+};
|
|
+
|
|
+
|
|
+#define efrm_nic(_efhw_nic) \
|
|
+ container_of(_efhw_nic, struct efrm_nic, efhw_nic)
|
|
+
|
|
+
|
|
+
|
|
+#endif /* __EFRM_NIC_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efrm/filter.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,122 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides public API for filter resource.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_EFRM_FILTER_H__
|
|
+#define __CI_EFRM_FILTER_H__
|
|
+
|
|
+#include <ci/efrm/resource.h>
|
|
+#include <ci/efhw/common.h>
|
|
+
|
|
+
|
|
+struct filter_resource;
|
|
+struct vi_resource;
|
|
+struct efrm_client;
|
|
+
|
|
+
|
|
+/*!
|
|
+ * Allocate filter resource.
|
|
+ *
|
|
+ * \param vi_parent VI resource to use as parent. The function takes
|
|
+ * reference to the VI resource on success.
|
|
+ * \param frs_out pointer to return the new filter resource
|
|
+ *
|
|
+ * \return status code; if non-zero, frs_out is unchanged
|
|
+ */
|
|
+extern int
|
|
+efrm_filter_resource_alloc(struct vi_resource *vi_parent,
|
|
+ struct filter_resource **frs_out);
|
|
+
|
|
+extern void
|
|
+efrm_filter_resource_release(struct filter_resource *);
|
|
+
|
|
+
|
|
+extern int efrm_filter_resource_clear(struct filter_resource *frs);
|
|
+
|
|
+extern int __efrm_filter_resource_set(struct filter_resource *frs, int type,
|
|
+ unsigned saddr_be32, uint16_t sport_be16,
|
|
+ unsigned daddr_be32, uint16_t dport_be16);
|
|
+
|
|
+static inline int
|
|
+efrm_filter_resource_tcp_set(struct filter_resource *frs,
|
|
+ unsigned saddr, uint16_t sport,
|
|
+ unsigned daddr, uint16_t dport)
|
|
+{
|
|
+ int type;
|
|
+
|
|
+ EFRM_ASSERT((saddr && sport) || (!saddr && !sport));
|
|
+
|
|
+ type =
|
|
+ saddr ? EFHW_IP_FILTER_TYPE_TCP_FULL :
|
|
+ EFHW_IP_FILTER_TYPE_TCP_WILDCARD;
|
|
+
|
|
+ return __efrm_filter_resource_set(frs, type,
|
|
+ saddr, sport, daddr, dport);
|
|
+}
|
|
+
|
|
+static inline int
|
|
+efrm_filter_resource_udp_set(struct filter_resource *frs,
|
|
+ unsigned saddr, uint16_t sport,
|
|
+ unsigned daddr, uint16_t dport)
|
|
+{
|
|
+ int type;
|
|
+
|
|
+ EFRM_ASSERT((saddr && sport) || (!saddr && !sport));
|
|
+
|
|
+ type =
|
|
+ saddr ? EFHW_IP_FILTER_TYPE_UDP_FULL :
|
|
+ EFHW_IP_FILTER_TYPE_UDP_WILDCARD;
|
|
+
|
|
+ return __efrm_filter_resource_set(frs,
|
|
+ type, saddr, sport, daddr, dport);
|
|
+}
|
|
+
|
|
+
|
|
+extern int
|
|
+efrm_filter_resource_instance(struct filter_resource *);
|
|
+
|
|
+extern struct efrm_resource *
|
|
+efrm_filter_resource_to_resource(struct filter_resource *);
|
|
+
|
|
+extern struct filter_resource *
|
|
+efrm_filter_resource_from_resource(struct efrm_resource *);
|
|
+
|
|
+extern void
|
|
+efrm_filter_resource_free(struct filter_resource *);
|
|
+
|
|
+
|
|
+#endif /* __CI_EFRM_FILTER_H__ */
|
|
+/*! \cidoxg_end */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efrm/iobufset.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,110 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides public API for iobufset resource.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_EFRM_IOBUFSET_H__
|
|
+#define __CI_EFRM_IOBUFSET_H__
|
|
+
|
|
+#include <ci/efrm/vi_resource.h>
|
|
+
|
|
+/*! Iobufset resource structture.
|
|
+ * Users should not access the structure fields directly, but use the API
|
|
+ * below.
|
|
+ * However, this structure should not be moved out of public headers,
|
|
+ * because part of API (ex. efrm_iobufset_dma_addr function) is inline and
|
|
+ * is used in the fast-path code.
|
|
+ */
|
|
+struct iobufset_resource {
|
|
+ struct efrm_resource rs;
|
|
+ struct vi_resource *evq;
|
|
+ struct iobufset_resource *linked;
|
|
+ struct efhw_buffer_table_allocation buf_tbl_alloc;
|
|
+ unsigned int n_bufs;
|
|
+ unsigned int pages_per_contiguous_chunk;
|
|
+ unsigned chunk_order;
|
|
+ struct efhw_iopage bufs[1];
|
|
+ /*!< up to n_bufs can follow this, so this must be the last member */
|
|
+};
|
|
+
|
|
+#define iobufset_resource(rs1) \
|
|
+ container_of((rs1), struct iobufset_resource, rs)
|
|
+
|
|
+/*!
|
|
+ * Allocate iobufset resource.
|
|
+ *
|
|
+ * \param vi VI that "owns" these buffers. Grabs a reference
|
|
+ * on success.
|
|
+ * \param linked Uses memory from an existing iobufset. Grabs a
|
|
+ * reference on success.
|
|
+ * \param iobrs_out pointer to return the new filter resource
|
|
+ *
|
|
+ * \return status code; if non-zero, frs_out is unchanged
|
|
+ */
|
|
+extern int
|
|
+efrm_iobufset_resource_alloc(int32_t n_pages,
|
|
+ int32_t pages_per_contiguous_chunk,
|
|
+ struct vi_resource *vi,
|
|
+ struct iobufset_resource *linked,
|
|
+ bool phys_addr_mode,
|
|
+ struct iobufset_resource **iobrs_out);
|
|
+
|
|
+extern void efrm_iobufset_resource_free(struct iobufset_resource *);
|
|
+extern void efrm_iobufset_resource_release(struct iobufset_resource *);
|
|
+
|
|
+static inline char *
|
|
+efrm_iobufset_ptr(struct iobufset_resource *rs, unsigned offs)
|
|
+{
|
|
+ EFRM_ASSERT(offs < (unsigned)(rs->n_bufs << PAGE_SHIFT));
|
|
+ return efhw_iopage_ptr(&rs->bufs[offs >> PAGE_SHIFT])
|
|
+ + (offs & (PAGE_SIZE - 1));
|
|
+}
|
|
+
|
|
+static inline char *efrm_iobufset_page_ptr(struct iobufset_resource *rs,
|
|
+ unsigned page_i)
|
|
+{
|
|
+ EFRM_ASSERT(page_i < (unsigned)rs->n_bufs);
|
|
+ return efhw_iopage_ptr(&rs->bufs[page_i]);
|
|
+}
|
|
+
|
|
+static inline dma_addr_t
|
|
+efrm_iobufset_dma_addr(struct iobufset_resource *rs, unsigned offs)
|
|
+{
|
|
+ EFRM_ASSERT(offs < (unsigned)(rs->n_bufs << PAGE_SHIFT));
|
|
+ return efhw_iopage_dma_addr(&rs->bufs[offs >> PAGE_SHIFT])
|
|
+ + (offs & (PAGE_SIZE - 1));
|
|
+}
|
|
+
|
|
+#endif /* __CI_EFRM_IOBUFSET_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efrm/nic_set.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,104 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides public API for NIC sets.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_EFRM_NIC_SET_H__
|
|
+#define __CI_EFRM_NIC_SET_H__
|
|
+
|
|
+#include <ci/efrm/debug.h>
|
|
+#include <ci/efhw/common_sysdep.h>
|
|
+#include <ci/efhw/efhw_config.h>
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * efrm_nic_set_t - tracks which NICs something has been done on
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+/* Internal suructure of efrm_nic_set_t should not be referenced outside of
|
|
+ * this file. Add a new accessor if you should do it. */
|
|
+typedef struct {
|
|
+ uint32_t nics;
|
|
+} efrm_nic_set_t;
|
|
+
|
|
+#if EFHW_MAX_NR_DEVS > 32
|
|
+#error change efrm_nic_set to handle EFHW_MAX_NR_DEVS number of devices
|
|
+#endif
|
|
+
|
|
+static inline bool
|
|
+efrm_nic_set_read(const efrm_nic_set_t *nic_set, unsigned index)
|
|
+{
|
|
+ EFRM_ASSERT(nic_set);
|
|
+ EFRM_ASSERT(index < EFHW_MAX_NR_DEVS && index < 32);
|
|
+ return (nic_set->nics & (1 << index)) ? true : false;
|
|
+}
|
|
+
|
|
+static inline void
|
|
+efrm_nic_set_write(efrm_nic_set_t *nic_set, unsigned index, bool value)
|
|
+{
|
|
+ EFRM_ASSERT(nic_set);
|
|
+ EFRM_ASSERT(index < EFHW_MAX_NR_DEVS && index < 32);
|
|
+ EFRM_ASSERT(value == false || value == true);
|
|
+ nic_set->nics = (nic_set->nics & (~(1 << index))) + (value << index);
|
|
+}
|
|
+
|
|
+static inline void efrm_nic_set_clear(efrm_nic_set_t *nic_set)
|
|
+{
|
|
+ nic_set->nics = 0;
|
|
+}
|
|
+
|
|
+static inline void efrm_nic_set_all(efrm_nic_set_t *nic_set)
|
|
+{
|
|
+ nic_set->nics = 0xffffffff;
|
|
+}
|
|
+
|
|
+static inline bool efrm_nic_set_is_all_clear(efrm_nic_set_t *nic_set)
|
|
+{
|
|
+ return nic_set->nics == 0 ? true : false;
|
|
+}
|
|
+
|
|
+#define EFRM_NIC_SET_FMT "%x"
|
|
+
|
|
+static inline uint32_t efrm_nic_set_pri_arg(efrm_nic_set_t *nic_set)
|
|
+{
|
|
+ return nic_set->nics;
|
|
+}
|
|
+
|
|
+#define EFRM_FOR_EACH_NIC_INDEX_IN_SET(_set, _nic_i) \
|
|
+ for ((_nic_i) = 0; (_nic_i) < EFHW_MAX_NR_DEVS; ++(_nic_i)) \
|
|
+ if (efrm_nic_set_read((_set), (_nic_i)))
|
|
+
|
|
+#endif /* __CI_EFRM_NIC_SET_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efrm/nic_table.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,98 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides public API for NIC table.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_EFRM_NIC_TABLE_H__
|
|
+#define __CI_EFRM_NIC_TABLE_H__
|
|
+
|
|
+#include <ci/efhw/efhw_types.h>
|
|
+#include <ci/efrm/sysdep.h>
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * struct efrm_nic_table - top level driver object keeping all NICs -
|
|
+ * implemented in driver_object.c
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+/*! Comment? */
|
|
+struct efrm_nic_table {
|
|
+ /*! nics attached to this driver */
|
|
+ struct efhw_nic *nic[EFHW_MAX_NR_DEVS];
|
|
+ /*! pointer to an arbitrary struct efhw_nic if one exists;
|
|
+ * for code which does not care which NIC it wants but
|
|
+ * still needs one. Note you cannot assume nic[0] exists. */
|
|
+ struct efhw_nic *a_nic;
|
|
+ uint32_t nic_count; /*!< number of nics attached to this driver */
|
|
+ spinlock_t lock; /*!< lock for table modifications */
|
|
+ atomic_t ref_count; /*!< refcount for users of nic table */
|
|
+};
|
|
+
|
|
+/* Resource driver structures used by other drivers as well */
|
|
+extern struct efrm_nic_table *efrm_nic_tablep;
|
|
+
|
|
+static inline void efrm_nic_table_hold(void)
|
|
+{
|
|
+ atomic_inc(&efrm_nic_tablep->ref_count);
|
|
+}
|
|
+
|
|
+static inline void efrm_nic_table_rele(void)
|
|
+{
|
|
+ atomic_dec(&efrm_nic_tablep->ref_count);
|
|
+}
|
|
+
|
|
+static inline int efrm_nic_table_held(void)
|
|
+{
|
|
+ return atomic_read(&efrm_nic_tablep->ref_count) != 0;
|
|
+}
|
|
+
|
|
+/* Run code block _x multiple times with variable nic set to each
|
|
+ * registered NIC in turn.
|
|
+ * DO NOT "break" out of this loop early. */
|
|
+#define EFRM_FOR_EACH_NIC(_nic_i, _nic) \
|
|
+ for ((_nic_i) = (efrm_nic_table_hold(), 0); \
|
|
+ (_nic_i) < EFHW_MAX_NR_DEVS || (efrm_nic_table_rele(), 0); \
|
|
+ (_nic_i)++) \
|
|
+ if (((_nic) = efrm_nic_tablep->nic[_nic_i]))
|
|
+
|
|
+#define EFRM_FOR_EACH_NIC_IN_SET(_set, _i, _nic) \
|
|
+ for ((_i) = (efrm_nic_table_hold(), 0); \
|
|
+ (_i) < EFHW_MAX_NR_DEVS || (efrm_nic_table_rele(), 0); \
|
|
+ ++(_i)) \
|
|
+ if (((_nic) = efrm_nic_tablep->nic[_i]) && \
|
|
+ efrm_nic_set_read((_set), (_i)))
|
|
+
|
|
+#endif /* __CI_EFRM_NIC_TABLE_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efrm/private.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,118 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides private API of efrm library -- resource handling.
|
|
+ * This API is not designed for use outside of SFC resource driver.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_EFRM_PRIVATE_H__
|
|
+#define __CI_EFRM_PRIVATE_H__
|
|
+
|
|
+#include <ci/efrm/resource.h>
|
|
+#include <ci/efrm/driver_private.h>
|
|
+#include <ci/efrm/sysdep.h>
|
|
+#include <ci/efrm/debug.h>
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * create resource managers
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+/*! Create a resource manager for various types of resources
|
|
+ */
|
|
+extern int
|
|
+efrm_create_iobufset_resource_manager(struct efrm_resource_manager **out);
|
|
+
|
|
+extern int
|
|
+efrm_create_filter_resource_manager(struct efrm_resource_manager **out);
|
|
+
|
|
+extern int
|
|
+efrm_create_vi_resource_manager(struct efrm_resource_manager **out,
|
|
+ const struct vi_resource_dimensions *);
|
|
+
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * Instance pool management
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+/*! Allocate instance pool. Use kfifo_vfree to destroy it. */
|
|
+static inline int
|
|
+efrm_kfifo_id_ctor(struct kfifo **ids_out,
|
|
+ unsigned int base, unsigned int limit, spinlock_t *lock)
|
|
+{
|
|
+ unsigned int i;
|
|
+ struct kfifo *ids;
|
|
+ unsigned char *buffer;
|
|
+ unsigned int size = roundup_pow_of_two((limit - base) * sizeof(int));
|
|
+ EFRM_ASSERT(base <= limit);
|
|
+ buffer = vmalloc(size);
|
|
+ ids = kfifo_init(buffer, size, GFP_KERNEL, lock);
|
|
+ if (IS_ERR(ids))
|
|
+ return PTR_ERR(ids);
|
|
+ for (i = base; i < limit; i++)
|
|
+ EFRM_VERIFY_EQ(__kfifo_put(ids, (unsigned char *)&i,
|
|
+ sizeof(i)), sizeof(i));
|
|
+
|
|
+ *ids_out = ids;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * Various private functions
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+/*! Initialize the fields in the provided resource manager memory area
|
|
+ * \param rm The area of memory to be initialized
|
|
+ * \param dtor A method to destroy the resource manager
|
|
+ * \param name A Textual name for the resource manager
|
|
+ * \param type The type of resource managed
|
|
+ * \param initial_table_size Initial size of the ID table
|
|
+ * \param auto_destroy Destroy resource manager on driver onload iff true
|
|
+ *
|
|
+ * A default table size is provided if the value 0 is provided.
|
|
+ */
|
|
+extern int
|
|
+efrm_resource_manager_ctor(struct efrm_resource_manager *rm,
|
|
+ void (*dtor)(struct efrm_resource_manager *),
|
|
+ const char *name, unsigned type);
|
|
+
|
|
+extern void efrm_resource_manager_dtor(struct efrm_resource_manager *rm);
|
|
+
|
|
+
|
|
+#endif /* __CI_EFRM_PRIVATE_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efrm/resource.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,119 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides public interface of efrm library -- resource handling.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_EFRM_RESOURCE_H__
|
|
+#define __CI_EFRM_RESOURCE_H__
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * headers for type dependencies
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+#include <ci/efhw/efhw_types.h>
|
|
+#include <ci/efrm/resource_id.h>
|
|
+#include <ci/efrm/sysdep.h>
|
|
+#include <ci/efhw/common_sysdep.h>
|
|
+
|
|
+#ifndef __ci_driver__
|
|
+#error "Driver-only file"
|
|
+#endif
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * struct efrm_resource - represents an allocated resource
|
|
+ * (eg. pinned pages of memory, or resource on a NIC)
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+/*! Representation of an allocated resource */
|
|
+struct efrm_resource {
|
|
+ int rs_ref_count;
|
|
+ efrm_resource_handle_t rs_handle;
|
|
+ struct efrm_client *rs_client;
|
|
+ struct list_head rs_client_link;
|
|
+ struct list_head rs_manager_link;
|
|
+};
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * managed resource abstraction
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+/*! Factory for resources of a specific type */
|
|
+struct efrm_resource_manager {
|
|
+ const char *rm_name; /*!< human readable only */
|
|
+ spinlock_t rm_lock;
|
|
+#ifndef NDEBUG
|
|
+ unsigned rm_type;
|
|
+#endif
|
|
+ int rm_resources;
|
|
+ int rm_resources_hiwat;
|
|
+ struct list_head rm_resources_list;
|
|
+ /**
|
|
+ * Destructor for the resource manager. Other resource managers
|
|
+ * might be already dead, although the system guarantees that
|
|
+ * managers are destructed in the order by which they were created
|
|
+ */
|
|
+ void (*rm_dtor)(struct efrm_resource_manager *);
|
|
+};
|
|
+
|
|
+#ifdef NDEBUG
|
|
+# define EFRM_RESOURCE_ASSERT_VALID(rs, rc_mbz)
|
|
+# define EFRM_RESOURCE_MANAGER_ASSERT_VALID(rm)
|
|
+#else
|
|
+/*! Check validity of resource and report on failure */
|
|
+extern void efrm_resource_assert_valid(struct efrm_resource *,
|
|
+ int rc_may_be_zero,
|
|
+ const char *file, int line);
|
|
+# define EFRM_RESOURCE_ASSERT_VALID(rs, rc_mbz) \
|
|
+ efrm_resource_assert_valid((rs), (rc_mbz), __FILE__, __LINE__)
|
|
+
|
|
+/*! Check validity of resource manager and report on failure */
|
|
+extern void efrm_resource_manager_assert_valid(struct efrm_resource_manager *,
|
|
+ const char *file, int line);
|
|
+# define EFRM_RESOURCE_MANAGER_ASSERT_VALID(rm) \
|
|
+ efrm_resource_manager_assert_valid((rm), __FILE__, __LINE__)
|
|
+#endif
|
|
+
|
|
+
|
|
+extern void efrm_resource_ref(struct efrm_resource *rs);
|
|
+extern int __efrm_resource_release(struct efrm_resource *);
|
|
+
|
|
+
|
|
+#endif /* __CI_EFRM_RESOURCE_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efrm/resource_id.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,104 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides public type and definitions resource handle, and the
|
|
+ * definitions of resource types.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_DRIVER_EFRM_RESOURCE_ID_H__
|
|
+#define __CI_DRIVER_EFRM_RESOURCE_ID_H__
|
|
+
|
|
+/***********************************************************************
|
|
+ * Resource handles
|
|
+ *
|
|
+ * Resource handles are intended for identifying resources at kernel
|
|
+ * level, within the context of a particular NIC. particularly because
|
|
+ * for some resource types, the low 16 bites correspond to hardware
|
|
+ * IDs. They were historically also used at user level, with a nonce
|
|
+ * stored in the bits 16 to 27 (inclusive), but that approach is
|
|
+ * deprecated (but sill alive!).
|
|
+ *
|
|
+ * The handle value 0 is used to mean "no resource".
|
|
+ * Identify resources within the context of a file descriptor at user
|
|
+ * level.
|
|
+ ***********************************************************************/
|
|
+
|
|
+typedef struct {
|
|
+ uint32_t handle;
|
|
+} efrm_resource_handle_t;
|
|
+
|
|
+/* You may think these following functions should all have
|
|
+ * _HANDLE_ in their names, but really we are providing an abstract set
|
|
+ * of methods on a (hypothetical) efrm_resource_t object, with
|
|
+ * efrm_resource_handle_t being just the reference one holds to access
|
|
+ * the object (aka "this" or "self").
|
|
+ */
|
|
+
|
|
+/* Below I use inline instead of macros where possible in order to get
|
|
+ * more type checking help from the compiler; hopefully we'll never
|
|
+ * have to rewrite these to use #define as we've found some horrible
|
|
+ * compiler on which we cannot make static inline do the Right Thing (tm).
|
|
+ *
|
|
+ * For consistency and to avoid pointless change I spell these
|
|
+ * routines as macro names (CAPTILIZE_UNDERSCORED), which also serves
|
|
+ * to remind people they are compact and inlined.
|
|
+ */
|
|
+
|
|
+#define EFRM_RESOURCE_FMT "[rs:%08x]"
|
|
+
|
|
+static inline unsigned EFRM_RESOURCE_PRI_ARG(efrm_resource_handle_t h)
|
|
+{
|
|
+ return h.handle;
|
|
+}
|
|
+
|
|
+static inline unsigned EFRM_RESOURCE_INSTANCE(efrm_resource_handle_t h)
|
|
+{
|
|
+ return h.handle & 0x0000ffff;
|
|
+}
|
|
+
|
|
+static inline unsigned EFRM_RESOURCE_TYPE(efrm_resource_handle_t h)
|
|
+{
|
|
+ return (h.handle & 0xf0000000) >> 28;
|
|
+}
|
|
+
|
|
+/***********************************************************************
|
|
+ * Resource type codes
|
|
+ ***********************************************************************/
|
|
+
|
|
+#define EFRM_RESOURCE_IOBUFSET 0x0
|
|
+#define EFRM_RESOURCE_VI 0x1
|
|
+#define EFRM_RESOURCE_FILTER 0x2
|
|
+#define EFRM_RESOURCE_NUM 0x3 /* This isn't a resource! */
|
|
+
|
|
+#define EFRM_RESOURCE_NAME(type) \
|
|
+ ((type) == EFRM_RESOURCE_IOBUFSET? "IOBUFSET" : \
|
|
+ (type) == EFRM_RESOURCE_VI? "VI" : \
|
|
+ (type) == EFRM_RESOURCE_FILTER? "FILTER" : \
|
|
+ "<invalid>")
|
|
+
|
|
+#endif /* __CI_DRIVER_EFRM_RESOURCE_ID_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efrm/sysdep.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,46 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides Linux-like system-independent API for efrm library.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_EFRM_SYSDEP_H__
|
|
+#define __CI_EFRM_SYSDEP_H__
|
|
+
|
|
+/* Spinlocks are defined in efhw/sysdep.h */
|
|
+#include <ci/efhw/sysdep.h>
|
|
+
|
|
+#include <ci/efrm/sysdep_linux.h>
|
|
+
|
|
+#endif /* __CI_EFRM_SYSDEP_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efrm/sysdep_linux.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,93 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides version-independent Linux kernel API for efrm library.
|
|
+ * Only kernels >=2.6.9 are supported.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Kfifo API is partially stolen from linux-2.6.22/include/linux/list.h
|
|
+ * Copyright (C) 2004 Stelian Pop <stelian@popies.net>
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_EFRM_SYSDEP_LINUX_H__
|
|
+#define __CI_EFRM_SYSDEP_LINUX_H__
|
|
+
|
|
+#include <linux/list.h>
|
|
+#include <linux/vmalloc.h>
|
|
+#include <linux/errno.h>
|
|
+#include <linux/string.h>
|
|
+#include <linux/workqueue.h>
|
|
+#include <linux/gfp.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/hardirq.h>
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/if_ether.h>
|
|
+#include <linux/completion.h>
|
|
+#include <linux/in.h>
|
|
+#include <linux/log2.h>
|
|
+#include <linux/kfifo.h>
|
|
+
|
|
+
|
|
+/********************************************************************
|
|
+ *
|
|
+ * List API
|
|
+ *
|
|
+ ********************************************************************/
|
|
+
|
|
+static inline struct list_head *list_pop(struct list_head *list)
|
|
+{
|
|
+ struct list_head *link = list->next;
|
|
+ list_del(link);
|
|
+ return link;
|
|
+}
|
|
+
|
|
+static inline struct list_head *list_pop_tail(struct list_head *list)
|
|
+{
|
|
+ struct list_head *link = list->prev;
|
|
+ list_del(link);
|
|
+ return link;
|
|
+}
|
|
+
|
|
+/********************************************************************
|
|
+ *
|
|
+ * Kfifo API
|
|
+ *
|
|
+ ********************************************************************/
|
|
+
|
|
+static inline void kfifo_vfree(struct kfifo *fifo)
|
|
+{
|
|
+ vfree(fifo->buffer);
|
|
+ kfree(fifo);
|
|
+}
|
|
+
|
|
+#endif /* __CI_EFRM_SYSDEP_LINUX_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efrm/vi_resource.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,157 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file contains public API for VI resource.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_EFRM_VI_RESOURCE_H__
|
|
+#define __CI_EFRM_VI_RESOURCE_H__
|
|
+
|
|
+#include <ci/efhw/efhw_types.h>
|
|
+#include <ci/efrm/resource.h>
|
|
+#include <ci/efrm/debug.h>
|
|
+
|
|
+struct vi_resource;
|
|
+
|
|
+/* Make these inline instead of macros for type checking */
|
|
+static inline struct vi_resource *
|
|
+efrm_to_vi_resource(struct efrm_resource *rs)
|
|
+{
|
|
+ EFRM_ASSERT(EFRM_RESOURCE_TYPE(rs->rs_handle) == EFRM_RESOURCE_VI);
|
|
+ return (struct vi_resource *) rs;
|
|
+}
|
|
+static inline struct
|
|
+efrm_resource *efrm_from_vi_resource(struct vi_resource *rs)
|
|
+{
|
|
+ return (struct efrm_resource *)rs;
|
|
+}
|
|
+
|
|
+#define EFAB_VI_RESOURCE_INSTANCE(virs) \
|
|
+ EFRM_RESOURCE_INSTANCE(efrm_from_vi_resource(virs)->rs_handle)
|
|
+
|
|
+#define EFAB_VI_RESOURCE_PRI_ARG(virs) \
|
|
+ EFRM_RESOURCE_PRI_ARG(efrm_from_vi_resource(virs)->rs_handle)
|
|
+
|
|
+extern int
|
|
+efrm_vi_resource_alloc(struct efrm_client *client,
|
|
+ struct vi_resource *evq_virs,
|
|
+ uint16_t vi_flags, int32_t evq_capacity,
|
|
+ int32_t txq_capacity, int32_t rxq_capacity,
|
|
+ uint8_t tx_q_tag, uint8_t rx_q_tag,
|
|
+ struct vi_resource **virs_in_out,
|
|
+ uint32_t *out_io_mmap_bytes,
|
|
+ uint32_t *out_mem_mmap_bytes,
|
|
+ uint32_t *out_txq_capacity,
|
|
+ uint32_t *out_rxq_capacity);
|
|
+
|
|
+extern void efrm_vi_resource_free(struct vi_resource *);
|
|
+extern void efrm_vi_resource_release(struct vi_resource *);
|
|
+
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * eventq handling
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+/*! Reset an event queue and clear any associated timers */
|
|
+extern void efrm_eventq_reset(struct vi_resource *virs);
|
|
+
|
|
+/*! Register a kernel-level handler for the event queue. This function is
|
|
+ * called whenever a timer expires, or whenever the event queue is woken
|
|
+ * but no thread is blocked on it.
|
|
+ *
|
|
+ * This function returns -EBUSY if a callback is already installed.
|
|
+ *
|
|
+ * \param rs Event-queue resource
|
|
+ * \param handler Callback-handler
|
|
+ * \param arg Argument to pass to callback-handler
|
|
+ * \return Status code
|
|
+ */
|
|
+extern int
|
|
+efrm_eventq_register_callback(struct vi_resource *rs,
|
|
+ void (*handler)(void *arg, int is_timeout,
|
|
+ struct efhw_nic *nic),
|
|
+ void *arg);
|
|
+
|
|
+/*! Kill the kernel-level callback.
|
|
+ *
|
|
+ * This function stops the timer from running and unregisters the callback
|
|
+ * function. It waits for any running timeout handlers to complete before
|
|
+ * returning.
|
|
+ *
|
|
+ * \param rs Event-queue resource
|
|
+ * \return Nothing
|
|
+ */
|
|
+extern void efrm_eventq_kill_callback(struct vi_resource *rs);
|
|
+
|
|
+/*! Ask the NIC to generate a wakeup when an event is next delivered. */
|
|
+extern void efrm_eventq_request_wakeup(struct vi_resource *rs,
|
|
+ unsigned current_ptr);
|
|
+
|
|
+/*! Register a kernel-level handler for flush completions.
|
|
+ * \TODO Currently, it is unsafe to install a callback more than once.
|
|
+ *
|
|
+ * \param rs VI resource being flushed.
|
|
+ * \param handler Callback handler function.
|
|
+ * \param arg Argument to be passed to handler.
|
|
+ */
|
|
+extern void
|
|
+efrm_vi_register_flush_callback(struct vi_resource *rs,
|
|
+ void (*handler)(void *),
|
|
+ void *arg);
|
|
+
|
|
+int efrm_vi_resource_flush_retry(struct vi_resource *virs);
|
|
+
|
|
+/*! Comment? */
|
|
+extern int efrm_pt_flush(struct vi_resource *);
|
|
+
|
|
+/*! Comment? */
|
|
+extern int efrm_pt_pace(struct vi_resource *, unsigned int val);
|
|
+
|
|
+uint32_t efrm_vi_rm_txq_bytes(struct vi_resource *virs
|
|
+ /*,struct efhw_nic *nic */);
|
|
+uint32_t efrm_vi_rm_rxq_bytes(struct vi_resource *virs
|
|
+ /*,struct efhw_nic *nic */);
|
|
+uint32_t efrm_vi_rm_evq_bytes(struct vi_resource *virs
|
|
+ /*,struct efhw_nic *nic */);
|
|
+
|
|
+
|
|
+/* Fill [out_vi_data] with information required to allow a VI to be init'd.
|
|
+ * [out_vi_data] must ref at least VI_MAPPINGS_SIZE bytes.
|
|
+ */
|
|
+extern void efrm_vi_resource_mappings(struct vi_resource *, void *out_vi_data);
|
|
+
|
|
+
|
|
+#endif /* __CI_EFRM_VI_RESOURCE_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efrm/vi_resource_manager.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,155 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file contains type definitions for VI resource. These types
|
|
+ * may be used outside of the SFC resource driver, but such use is not
|
|
+ * recommended.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_DRIVER_EFAB_VI_RESOURCE_MANAGER_H__
|
|
+#define __CI_DRIVER_EFAB_VI_RESOURCE_MANAGER_H__
|
|
+
|
|
+#include <ci/efhw/common.h>
|
|
+#include <ci/efrm/vi_resource.h>
|
|
+
|
|
+
|
|
+#define EFRM_VI_RM_DMA_QUEUE_COUNT 2
|
|
+#define EFRM_VI_RM_DMA_QUEUE_TX 0
|
|
+#define EFRM_VI_RM_DMA_QUEUE_RX 1
|
|
+
|
|
+/** Numbers of bits which can be set in the evq_state member of
|
|
+ * vi_resource_evq_info. */
|
|
+enum {
|
|
+ /** This bit is set if a wakeup has been requested on the NIC. */
|
|
+ VI_RESOURCE_EVQ_STATE_WAKEUP_PENDING,
|
|
+ /** This bit is set if the wakeup is valid for the sleeping
|
|
+ * process. */
|
|
+ VI_RESOURCE_EVQ_STATE_CALLBACK_REGISTERED,
|
|
+ /** This bit is set if a wakeup or timeout event is currently being
|
|
+ * processed. */
|
|
+ VI_RESOURCE_EVQ_STATE_BUSY,
|
|
+};
|
|
+#define VI_RESOURCE_EVQ_STATE(X) \
|
|
+ (((int32_t)1) << (VI_RESOURCE_EVQ_STATE_##X))
|
|
+
|
|
+
|
|
+/*! Global information for the VI resource manager. */
|
|
+struct vi_resource_manager {
|
|
+ struct efrm_resource_manager rm;
|
|
+
|
|
+ struct kfifo *instances_with_timer;
|
|
+ int with_timer_base;
|
|
+ int with_timer_limit;
|
|
+ struct kfifo *instances_with_interrupt;
|
|
+ int with_interrupt_base;
|
|
+ int with_interrupt_limit;
|
|
+
|
|
+ bool iscsi_dmaq_instance_is_free;
|
|
+
|
|
+ /* We keep VI resources which need flushing on these lists. The VI
|
|
+ * is put on the outstanding list when the flush request is issued
|
|
+ * to the hardware and removed when the flush event arrives. The
|
|
+ * hardware can only handle a limited number of RX flush requests at
|
|
+ * once, so VIs are placed in the waiting list until the flush can
|
|
+ * be issued. Flushes can be requested by the client or internally
|
|
+ * by the VI resource manager. In the former case, the reference
|
|
+ * count must be non-zero for the duration of the flush and in the
|
|
+ * later case, the reference count must be zero. */
|
|
+ struct list_head rx_flush_waiting_list;
|
|
+ struct list_head rx_flush_outstanding_list;
|
|
+ struct list_head tx_flush_outstanding_list;
|
|
+ int rx_flush_outstanding_count;
|
|
+
|
|
+ /* once the flush has happened we push the close into the work queue
|
|
+ * so its OK on Windows to free the resources (Bug 3469). Resources
|
|
+ * on this list have zero reference count.
|
|
+ */
|
|
+ struct list_head close_pending;
|
|
+ struct work_struct work_item;
|
|
+ struct workqueue_struct *workqueue;
|
|
+};
|
|
+
|
|
+struct vi_resource_nic_info {
|
|
+ struct eventq_resource_hardware evq_pages;
|
|
+ struct efhw_iopages dmaq_pages[EFRM_VI_RM_DMA_QUEUE_COUNT];
|
|
+};
|
|
+
|
|
+struct vi_resource {
|
|
+ /* Some macros make the assumption that the struct efrm_resource is
|
|
+ * the first member of a struct vi_resource. */
|
|
+ struct efrm_resource rs;
|
|
+ atomic_t evq_refs; /*!< Number of users of the event queue. */
|
|
+
|
|
+ uint32_t bar_mmap_bytes;
|
|
+ uint32_t mem_mmap_bytes;
|
|
+
|
|
+ int32_t evq_capacity;
|
|
+ int32_t dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_COUNT];
|
|
+
|
|
+ uint8_t dmaq_tag[EFRM_VI_RM_DMA_QUEUE_COUNT];
|
|
+ uint16_t flags;
|
|
+
|
|
+ /* we keep PT endpoints that have been destroyed on a list
|
|
+ * until we have seen their TX and RX DMAQs flush complete
|
|
+ * (see Bug 1217)
|
|
+ */
|
|
+ struct list_head rx_flush_link;
|
|
+ struct list_head tx_flush_link;
|
|
+ int rx_flushing;
|
|
+ int rx_flush_outstanding;
|
|
+ int tx_flushing;
|
|
+ uint64_t flush_time;
|
|
+ int flush_count;
|
|
+
|
|
+ void (*flush_callback_fn)(void *);
|
|
+ void *flush_callback_arg;
|
|
+
|
|
+ void (*evq_callback_fn) (void *arg, int is_timeout,
|
|
+ struct efhw_nic *nic);
|
|
+ void *evq_callback_arg;
|
|
+
|
|
+ struct vi_resource *evq_virs; /*!< EVQ for DMA queues */
|
|
+
|
|
+ struct efhw_buffer_table_allocation
|
|
+ dmaq_buf_tbl_alloc[EFRM_VI_RM_DMA_QUEUE_COUNT];
|
|
+
|
|
+ struct vi_resource_nic_info nic_info;
|
|
+};
|
|
+
|
|
+#undef vi_resource
|
|
+#define vi_resource(rs1) container_of((rs1), struct vi_resource, rs)
|
|
+
|
|
+static inline dma_addr_t
|
|
+efrm_eventq_dma_addr(struct vi_resource *virs)
|
|
+{
|
|
+ struct eventq_resource_hardware *hw;
|
|
+ hw = &virs->nic_info.evq_pages;
|
|
+ return efhw_iopages_dma_addr(&hw->iobuff) + hw->iobuff_off;
|
|
+}
|
|
+
|
|
+#endif /* __CI_DRIVER_EFAB_VI_RESOURCE_MANAGER_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/ci/efrm/vi_resource_private.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,65 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file contains private API for VI resource. The API is not designed
|
|
+ * to be used outside of the SFC resource driver.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __CI_EFRM_VI_RESOURCE_PRIVATE_H__
|
|
+#define __CI_EFRM_VI_RESOURCE_PRIVATE_H__
|
|
+
|
|
+#include <ci/efhw/common.h>
|
|
+#include <ci/efrm/vi_resource_manager.h>
|
|
+
|
|
+extern struct vi_resource_manager *efrm_vi_manager;
|
|
+
|
|
+/*************************************************************************/
|
|
+
|
|
+extern void efrm_vi_rm_delayed_free(struct work_struct *data);
|
|
+
|
|
+extern void efrm_vi_rm_salvage_flushed_vis(void);
|
|
+
|
|
+void efrm_vi_rm_free_flushed_resource(struct vi_resource *virs);
|
|
+
|
|
+void efrm_vi_rm_init_dmaq(struct vi_resource *virs, int queue_index,
|
|
+ struct efhw_nic *nic);
|
|
+
|
|
+/*! Wakeup handler */
|
|
+extern void efrm_handle_wakeup_event(struct efhw_nic *nic, unsigned id);
|
|
+
|
|
+/*! Timeout handler */
|
|
+extern void efrm_handle_timeout_event(struct efhw_nic *nic, unsigned id);
|
|
+
|
|
+/*! DMA flush handler */
|
|
+extern void efrm_handle_dmaq_flushed(struct efhw_nic *nic, unsigned id,
|
|
+ int rx_flush);
|
|
+
|
|
+/*! SRAM update handler */
|
|
+extern void efrm_handle_sram_event(struct efhw_nic *nic);
|
|
+
|
|
+#endif /* __CI_EFRM_VI_RESOURCE_PRIVATE_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/driver_object.c 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,328 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file contains support for the global driver variables.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#include <ci/efrm/nic_table.h>
|
|
+#include <ci/efrm/resource.h>
|
|
+#include <ci/efrm/debug.h>
|
|
+#include <ci/efrm/efrm_client.h>
|
|
+#include <ci/efrm/efrm_nic.h>
|
|
+#include "efrm_internal.h"
|
|
+
|
|
+/* We use #define rather than static inline here so that the Windows
|
|
+ * "prefast" compiler can see its own locking primitive when these
|
|
+ * two function are used (and then perform extra checking where they
|
|
+ * are used)
|
|
+ *
|
|
+ * Both macros operate on an irq_flags_t
|
|
+*/
|
|
+
|
|
+#define efrm_driver_lock(irqlock_state) \
|
|
+ spin_lock_irqsave(&efrm_nic_tablep->lock, irqlock_state)
|
|
+
|
|
+#define efrm_driver_unlock(irqlock_state) \
|
|
+ spin_unlock_irqrestore(&efrm_nic_tablep->lock, \
|
|
+ irqlock_state);
|
|
+
|
|
+/* These routines are all methods on the architecturally singleton
|
|
+ global variables: efrm_nic_table, efrm_rm_table.
|
|
+
|
|
+ I hope we never find a driver model that does not allow global
|
|
+ structure variables :) (but that would break almost every driver I've
|
|
+ ever seen).
|
|
+*/
|
|
+
|
|
+/*! Exported driver state */
|
|
+static struct efrm_nic_table efrm_nic_table;
|
|
+struct efrm_nic_table *efrm_nic_tablep;
|
|
+EXPORT_SYMBOL(efrm_nic_tablep);
|
|
+
|
|
+
|
|
+/* Internal table with resource managers.
|
|
+ * We'd like to not export it, but we are still using efrm_rm_table
|
|
+ * in the char driver. So, it is declared in the private header with
|
|
+ * a purpose. */
|
|
+struct efrm_resource_manager *efrm_rm_table[EFRM_RESOURCE_NUM];
|
|
+EXPORT_SYMBOL(efrm_rm_table);
|
|
+
|
|
+
|
|
+/* List of registered nics. */
|
|
+static LIST_HEAD(efrm_nics);
|
|
+
|
|
+
|
|
+void efrm_driver_ctor(void)
|
|
+{
|
|
+ efrm_nic_tablep = &efrm_nic_table;
|
|
+ spin_lock_init(&efrm_nic_tablep->lock);
|
|
+ EFRM_TRACE("%s: driver created", __func__);
|
|
+}
|
|
+
|
|
+void efrm_driver_dtor(void)
|
|
+{
|
|
+ EFRM_ASSERT(!efrm_nic_table_held());
|
|
+
|
|
+ spin_lock_destroy(&efrm_nic_tablep->lock);
|
|
+ memset(&efrm_nic_table, 0, sizeof(efrm_nic_table));
|
|
+ memset(&efrm_rm_table, 0, sizeof(efrm_rm_table));
|
|
+ EFRM_TRACE("%s: driver deleted", __func__);
|
|
+}
|
|
+
|
|
+int efrm_driver_register_nic(struct efrm_nic *rnic, int nic_index,
|
|
+ int ifindex)
|
|
+{
|
|
+ struct efhw_nic *nic = &rnic->efhw_nic;
|
|
+ struct efrm_nic_per_vi *vis;
|
|
+ int max_vis, rc = 0;
|
|
+ irq_flags_t lock_flags;
|
|
+
|
|
+ EFRM_ASSERT(nic_index >= 0);
|
|
+ EFRM_ASSERT(ifindex >= 0);
|
|
+
|
|
+ max_vis = 4096; /* TODO: Get runtime value. */
|
|
+ vis = vmalloc(max_vis * sizeof(rnic->vis[0]));
|
|
+ if (vis == NULL) {
|
|
+ EFRM_ERR("%s: Out of memory", __func__);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ efrm_driver_lock(lock_flags);
|
|
+
|
|
+ if (efrm_nic_table_held()) {
|
|
+ EFRM_ERR("%s: driver object is in use", __func__);
|
|
+ rc = -EBUSY;
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ if (efrm_nic_tablep->nic_count == EFHW_MAX_NR_DEVS) {
|
|
+ EFRM_ERR("%s: filled up NIC table size %d", __func__,
|
|
+ EFHW_MAX_NR_DEVS);
|
|
+ rc = -E2BIG;
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ rnic->vis = vis;
|
|
+
|
|
+ EFRM_ASSERT(efrm_nic_tablep->nic[nic_index] == NULL);
|
|
+ efrm_nic_tablep->nic[nic_index] = nic;
|
|
+ nic->index = nic_index;
|
|
+ nic->ifindex = ifindex;
|
|
+
|
|
+ if (efrm_nic_tablep->a_nic == NULL)
|
|
+ efrm_nic_tablep->a_nic = nic;
|
|
+
|
|
+ efrm_nic_tablep->nic_count++;
|
|
+
|
|
+ INIT_LIST_HEAD(&rnic->clients);
|
|
+ list_add(&rnic->link, &efrm_nics);
|
|
+
|
|
+ efrm_driver_unlock(lock_flags);
|
|
+ return 0;
|
|
+
|
|
+done:
|
|
+ efrm_driver_unlock(lock_flags);
|
|
+ vfree(vis);
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+int efrm_driver_unregister_nic(struct efrm_nic *rnic)
|
|
+{
|
|
+ struct efhw_nic *nic = &rnic->efhw_nic;
|
|
+ int rc = 0;
|
|
+ int nic_index = nic->index;
|
|
+ irq_flags_t lock_flags;
|
|
+
|
|
+ EFRM_ASSERT(nic_index >= 0);
|
|
+
|
|
+ efrm_driver_lock(lock_flags);
|
|
+
|
|
+ if (efrm_nic_table_held()) {
|
|
+ EFRM_ERR("%s: driver object is in use", __func__);
|
|
+ rc = -EBUSY;
|
|
+ goto done;
|
|
+ }
|
|
+ if (!list_empty(&rnic->clients)) {
|
|
+ EFRM_ERR("%s: nic has active clients", __func__);
|
|
+ rc = -EBUSY;
|
|
+ goto done;
|
|
+ }
|
|
+
|
|
+ EFRM_ASSERT(efrm_nic_tablep->nic[nic_index] == nic);
|
|
+ EFRM_ASSERT(list_empty(&rnic->clients));
|
|
+
|
|
+ list_del(&rnic->link);
|
|
+
|
|
+ nic->index = -1;
|
|
+ efrm_nic_tablep->nic[nic_index] = NULL;
|
|
+
|
|
+ --efrm_nic_tablep->nic_count;
|
|
+
|
|
+ if (efrm_nic_tablep->a_nic == nic) {
|
|
+ if (efrm_nic_tablep->nic_count == 0) {
|
|
+ efrm_nic_tablep->a_nic = NULL;
|
|
+ } else {
|
|
+ for (nic_index = 0; nic_index < EFHW_MAX_NR_DEVS;
|
|
+ nic_index++) {
|
|
+ if (efrm_nic_tablep->nic[nic_index] != NULL)
|
|
+ efrm_nic_tablep->a_nic =
|
|
+ efrm_nic_tablep->nic[nic_index];
|
|
+ }
|
|
+ EFRM_ASSERT(efrm_nic_tablep->a_nic);
|
|
+ }
|
|
+ }
|
|
+
|
|
+done:
|
|
+ efrm_driver_unlock(lock_flags);
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+
|
|
+int efrm_nic_pre_reset(struct efhw_nic *nic)
|
|
+{
|
|
+ struct efrm_nic *rnic = efrm_nic(nic);
|
|
+ struct efrm_client *client;
|
|
+ struct efrm_resource *rs;
|
|
+ struct list_head *client_link;
|
|
+ struct list_head *rs_link;
|
|
+ irq_flags_t lock_flags;
|
|
+
|
|
+ spin_lock_irqsave(&efrm_nic_tablep->lock, lock_flags);
|
|
+ list_for_each(client_link, &rnic->clients) {
|
|
+ client = container_of(client_link, struct efrm_client, link);
|
|
+ EFRM_ERR("%s: client %p", __func__, client);
|
|
+ if (client->callbacks->pre_reset)
|
|
+ client->callbacks->pre_reset(client, client->user_data);
|
|
+ list_for_each(rs_link, &client->resources) {
|
|
+ rs = container_of(rs_link, struct efrm_resource,
|
|
+ rs_client_link);
|
|
+ EFRM_ERR("%s: resource %p", __func__, rs);
|
|
+ /* TODO: mark rs defunct */
|
|
+ }
|
|
+ }
|
|
+ spin_unlock_irqrestore(&efrm_nic_tablep->lock, lock_flags);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+int efrm_nic_stop(struct efhw_nic *nic)
|
|
+{
|
|
+ /* TODO */
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+int efrm_nic_resume(struct efhw_nic *nic)
|
|
+{
|
|
+ /* TODO */
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+static void efrm_client_nullcb(struct efrm_client *client, void *user_data)
|
|
+{
|
|
+}
|
|
+
|
|
+static struct efrm_client_callbacks efrm_null_callbacks = {
|
|
+ efrm_client_nullcb,
|
|
+ efrm_client_nullcb,
|
|
+ efrm_client_nullcb
|
|
+};
|
|
+
|
|
+
|
|
+int efrm_client_get(int ifindex, struct efrm_client_callbacks *callbacks,
|
|
+ void *user_data, struct efrm_client **client_out)
|
|
+{
|
|
+ struct efrm_nic *n, *rnic = NULL;
|
|
+ irq_flags_t lock_flags;
|
|
+ struct list_head *link;
|
|
+ struct efrm_client *client;
|
|
+
|
|
+ if (callbacks == NULL)
|
|
+ callbacks = &efrm_null_callbacks;
|
|
+
|
|
+ client = kmalloc(sizeof(*client), GFP_KERNEL);
|
|
+ if (client == NULL)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ spin_lock_irqsave(&efrm_nic_tablep->lock, lock_flags);
|
|
+ list_for_each(link, &efrm_nics) {
|
|
+ n = container_of(link, struct efrm_nic, link);
|
|
+ if (n->efhw_nic.ifindex == ifindex || ifindex < 0) {
|
|
+ rnic = n;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ if (rnic) {
|
|
+ client->user_data = user_data;
|
|
+ client->callbacks = callbacks;
|
|
+ client->nic = &rnic->efhw_nic;
|
|
+ client->ref_count = 1;
|
|
+ INIT_LIST_HEAD(&client->resources);
|
|
+ list_add(&client->link, &rnic->clients);
|
|
+ }
|
|
+ spin_unlock_irqrestore(&efrm_nic_tablep->lock, lock_flags);
|
|
+
|
|
+ if (rnic == NULL)
|
|
+ return -ENODEV;
|
|
+
|
|
+ *client_out = client;
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL(efrm_client_get);
|
|
+
|
|
+
|
|
+void efrm_client_put(struct efrm_client *client)
|
|
+{
|
|
+ irq_flags_t lock_flags;
|
|
+
|
|
+ EFRM_ASSERT(client->ref_count > 0);
|
|
+
|
|
+ spin_lock_irqsave(&efrm_nic_tablep->lock, lock_flags);
|
|
+ if (--client->ref_count > 0)
|
|
+ client = NULL;
|
|
+ else
|
|
+ list_del(&client->link);
|
|
+ spin_unlock_irqrestore(&efrm_nic_tablep->lock, lock_flags);
|
|
+ kfree(client);
|
|
+}
|
|
+EXPORT_SYMBOL(efrm_client_put);
|
|
+
|
|
+
|
|
+struct efhw_nic *efrm_client_get_nic(struct efrm_client *client)
|
|
+{
|
|
+ return client->nic;
|
|
+}
|
|
+EXPORT_SYMBOL(efrm_client_get_nic);
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/driverlink_new.c 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,260 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file contains driverlink code which interacts with the sfc network
|
|
+ * driver.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#include "linux_resource_internal.h"
|
|
+#include "driverlink_api.h"
|
|
+#include "kernel_compat.h"
|
|
+#include <ci/efhw/falcon.h>
|
|
+
|
|
+#include <linux/rtnetlink.h>
|
|
+#include <linux/netdevice.h>
|
|
+#include <net/net_namespace.h>
|
|
+
|
|
+/* The DL driver and associated calls */
|
|
+static int efrm_dl_probe(struct efx_dl_device *efrm_dev,
|
|
+ const struct net_device *net_dev,
|
|
+ const struct efx_dl_device_info *dev_info,
|
|
+ const char *silicon_rev);
|
|
+
|
|
+static void efrm_dl_remove(struct efx_dl_device *efrm_dev);
|
|
+
|
|
+static void efrm_dl_reset_suspend(struct efx_dl_device *efrm_dev);
|
|
+
|
|
+static void efrm_dl_reset_resume(struct efx_dl_device *efrm_dev, int ok);
|
|
+
|
|
+static void efrm_dl_mtu_changed(struct efx_dl_device *, int);
|
|
+static void efrm_dl_event_falcon(struct efx_dl_device *efx_dev, void *p_event);
|
|
+
|
|
+static struct efx_dl_driver efrm_dl_driver = {
|
|
+ .name = "resource",
|
|
+ .probe = efrm_dl_probe,
|
|
+ .remove = efrm_dl_remove,
|
|
+ .reset_suspend = efrm_dl_reset_suspend,
|
|
+ .reset_resume = efrm_dl_reset_resume
|
|
+};
|
|
+
|
|
+static void
|
|
+init_vi_resource_dimensions(struct vi_resource_dimensions *rd,
|
|
+ const struct efx_dl_falcon_resources *res)
|
|
+{
|
|
+ rd->evq_timer_min = res->evq_timer_min;
|
|
+ rd->evq_timer_lim = res->evq_timer_lim;
|
|
+ rd->evq_int_min = res->evq_int_min;
|
|
+ rd->evq_int_lim = res->evq_int_lim;
|
|
+ rd->rxq_min = res->rxq_min;
|
|
+ rd->rxq_lim = res->rxq_lim;
|
|
+ rd->txq_min = res->txq_min;
|
|
+ rd->txq_lim = res->txq_lim;
|
|
+ EFRM_TRACE
|
|
+ ("Using evq_int(%d-%d) evq_timer(%d-%d) RXQ(%d-%d) TXQ(%d-%d)",
|
|
+ res->evq_int_min, res->evq_int_lim, res->evq_timer_min,
|
|
+ res->evq_timer_lim, res->rxq_min, res->rxq_lim, res->txq_min,
|
|
+ res->txq_lim);
|
|
+}
|
|
+
|
|
+static int
|
|
+efrm_dl_probe(struct efx_dl_device *efrm_dev,
|
|
+ const struct net_device *net_dev,
|
|
+ const struct efx_dl_device_info *dev_info,
|
|
+ const char *silicon_rev)
|
|
+{
|
|
+ struct vi_resource_dimensions res_dim;
|
|
+ struct efx_dl_falcon_resources *res;
|
|
+ struct linux_efhw_nic *lnic;
|
|
+ struct pci_dev *dev;
|
|
+ struct efhw_nic *nic;
|
|
+ unsigned probe_flags = 0;
|
|
+ int non_irq_evq;
|
|
+ int rc;
|
|
+
|
|
+ efrm_dev->priv = NULL;
|
|
+
|
|
+ efx_dl_search_device_info(dev_info, EFX_DL_FALCON_RESOURCES,
|
|
+ struct efx_dl_falcon_resources,
|
|
+ hdr, res);
|
|
+
|
|
+ if (res == NULL) {
|
|
+ EFRM_ERR("%s: Unable to find falcon driverlink resources",
|
|
+ __func__);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ if (res->flags & EFX_DL_FALCON_USE_MSI)
|
|
+ probe_flags |= NIC_FLAG_TRY_MSI;
|
|
+
|
|
+ dev = efrm_dev->pci_dev;
|
|
+ if (res->flags & EFX_DL_FALCON_DUAL_FUNC) {
|
|
+ unsigned vendor = dev->vendor;
|
|
+ EFRM_ASSERT(dev->bus != NULL);
|
|
+ dev = NULL;
|
|
+
|
|
+ while ((dev = pci_get_device(vendor, FALCON_S_DEVID, dev))
|
|
+ != NULL) {
|
|
+ EFRM_ASSERT(dev->bus != NULL);
|
|
+ /* With PCIe (since it's point to point)
|
|
+ * the slot ID is usually 0 and
|
|
+ * the bus ID changes NIC to NIC, so we really
|
|
+ * need to check both. */
|
|
+ if (PCI_SLOT(dev->devfn) ==
|
|
+ PCI_SLOT(efrm_dev->pci_dev->devfn)
|
|
+ && dev->bus->number ==
|
|
+ efrm_dev->pci_dev->bus->number)
|
|
+ break;
|
|
+ }
|
|
+ if (dev == NULL) {
|
|
+ EFRM_ERR("%s: Unable to find falcon secondary "
|
|
+ "PCI device.", __func__);
|
|
+ return -ENODEV;
|
|
+ }
|
|
+ pci_dev_put(dev);
|
|
+ }
|
|
+
|
|
+ init_vi_resource_dimensions(&res_dim, res);
|
|
+
|
|
+ EFRM_ASSERT(res_dim.evq_timer_lim > res_dim.evq_timer_min);
|
|
+ res_dim.evq_timer_lim--;
|
|
+ non_irq_evq = res_dim.evq_timer_lim;
|
|
+
|
|
+ rc = efrm_nic_add(dev, probe_flags, net_dev->dev_addr, &lnic,
|
|
+ res->biu_lock,
|
|
+ res->buffer_table_min, res->buffer_table_lim,
|
|
+ non_irq_evq, &res_dim);
|
|
+ if (rc != 0)
|
|
+ return rc;
|
|
+
|
|
+ nic = &lnic->efrm_nic.efhw_nic;
|
|
+ nic->mtu = net_dev->mtu + ETH_HLEN;
|
|
+ nic->net_driver_dev = efrm_dev;
|
|
+ nic->ifindex = net_dev->ifindex;
|
|
+#ifdef CONFIG_NET_NS
|
|
+ nic->nd_net = net_dev->nd_net;
|
|
+#endif
|
|
+ efrm_dev->priv = nic;
|
|
+
|
|
+ /* Register a callback so we're told when MTU changes.
|
|
+ * We dynamically allocate efx_dl_callbacks, because
|
|
+ * the callbacks that we want depends on the NIC type.
|
|
+ */
|
|
+ lnic->dl_callbacks =
|
|
+ kmalloc(sizeof(struct efx_dl_callbacks), GFP_KERNEL);
|
|
+ if (!lnic->dl_callbacks) {
|
|
+ EFRM_ERR("Out of memory (%s)", __func__);
|
|
+ efrm_nic_del(lnic);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ memset(lnic->dl_callbacks, 0, sizeof(*lnic->dl_callbacks));
|
|
+ lnic->dl_callbacks->mtu_changed = efrm_dl_mtu_changed;
|
|
+
|
|
+ if ((res->flags & EFX_DL_FALCON_DUAL_FUNC) == 0) {
|
|
+ /* Net driver receives all management events.
|
|
+ * Register a callback to receive the ones
|
|
+ * we're interested in. */
|
|
+ lnic->dl_callbacks->event = efrm_dl_event_falcon;
|
|
+ }
|
|
+
|
|
+ rc = efx_dl_register_callbacks(efrm_dev, lnic->dl_callbacks);
|
|
+ if (rc < 0) {
|
|
+ EFRM_ERR("%s: efx_dl_register_callbacks failed (%d)",
|
|
+ __func__, rc);
|
|
+ kfree(lnic->dl_callbacks);
|
|
+ efrm_nic_del(lnic);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* When we unregister ourselves on module removal, this function will be
|
|
+ * called for all the devices we claimed */
|
|
+static void efrm_dl_remove(struct efx_dl_device *efrm_dev)
|
|
+{
|
|
+ struct efhw_nic *nic = efrm_dev->priv;
|
|
+ struct linux_efhw_nic *lnic = linux_efhw_nic(nic);
|
|
+ EFRM_TRACE("%s called", __func__);
|
|
+ if (lnic->dl_callbacks) {
|
|
+ efx_dl_unregister_callbacks(efrm_dev, lnic->dl_callbacks);
|
|
+ kfree(lnic->dl_callbacks);
|
|
+ }
|
|
+ if (efrm_dev->priv)
|
|
+ efrm_nic_del(lnic);
|
|
+ EFRM_TRACE("%s OK", __func__);
|
|
+}
|
|
+
|
|
+static void efrm_dl_reset_suspend(struct efx_dl_device *efrm_dev)
|
|
+{
|
|
+ EFRM_NOTICE("%s:", __func__);
|
|
+}
|
|
+
|
|
+static void efrm_dl_reset_resume(struct efx_dl_device *efrm_dev, int ok)
|
|
+{
|
|
+ EFRM_NOTICE("%s: ok=%d", __func__, ok);
|
|
+}
|
|
+
|
|
+int efrm_driverlink_register(void)
|
|
+{
|
|
+ EFRM_TRACE("%s:", __func__);
|
|
+ return efx_dl_register_driver(&efrm_dl_driver);
|
|
+}
|
|
+
|
|
+void efrm_driverlink_unregister(void)
|
|
+{
|
|
+ EFRM_TRACE("%s:", __func__);
|
|
+ efx_dl_unregister_driver(&efrm_dl_driver);
|
|
+}
|
|
+
|
|
+static void efrm_dl_mtu_changed(struct efx_dl_device *efx_dev, int mtu)
|
|
+{
|
|
+ struct efhw_nic *nic = efx_dev->priv;
|
|
+
|
|
+ ASSERT_RTNL(); /* Since we're looking at efx_dl_device::port_net_dev */
|
|
+
|
|
+ EFRM_TRACE("%s: old=%d new=%d", __func__, nic->mtu, mtu + ETH_HLEN);
|
|
+ /* If this happened we must have agreed to it above */
|
|
+ nic->mtu = mtu + ETH_HLEN;
|
|
+}
|
|
+
|
|
+static void efrm_dl_event_falcon(struct efx_dl_device *efx_dev, void *p_event)
|
|
+{
|
|
+ struct efhw_nic *nic = efx_dev->priv;
|
|
+ struct linux_efhw_nic *lnic = linux_efhw_nic(nic);
|
|
+ efhw_event_t *ev = p_event;
|
|
+
|
|
+ switch (FALCON_EVENT_CODE(ev)) {
|
|
+ case FALCON_EVENT_CODE_CHAR:
|
|
+ falcon_handle_char_event(nic, lnic->ev_handlers, ev);
|
|
+ break;
|
|
+ default:
|
|
+ EFRM_WARN("%s: unknown event type=%x", __func__,
|
|
+ (unsigned)FALCON_EVENT_CODE(ev));
|
|
+ break;
|
|
+ }
|
|
+}
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/efrm_internal.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,41 @@
|
|
+#ifndef __EFRM_INTERNAL_H__
|
|
+#define __EFRM_INTERNAL_H__
|
|
+
|
|
+
|
|
+struct filter_resource {
|
|
+ struct efrm_resource rs;
|
|
+ struct vi_resource *pt;
|
|
+ int filter_idx;
|
|
+};
|
|
+
|
|
+#define filter_resource(rs1) container_of((rs1), struct filter_resource, rs)
|
|
+
|
|
+
|
|
+struct efrm_client {
|
|
+ void *user_data;
|
|
+ struct list_head link;
|
|
+ struct efrm_client_callbacks *callbacks;
|
|
+ struct efhw_nic *nic;
|
|
+ int ref_count;
|
|
+ struct list_head resources;
|
|
+};
|
|
+
|
|
+
|
|
+extern void efrm_client_add_resource(struct efrm_client *,
|
|
+ struct efrm_resource *);
|
|
+
|
|
+extern int efrm_buffer_table_size(void);
|
|
+
|
|
+
|
|
+static inline void efrm_resource_init(struct efrm_resource *rs,
|
|
+ int type, int instance)
|
|
+{
|
|
+ EFRM_ASSERT(instance >= 0);
|
|
+ EFRM_ASSERT(type >= 0 && type < EFRM_RESOURCE_NUM);
|
|
+ rs->rs_ref_count = 1;
|
|
+ rs->rs_handle.handle = (type << 28u) |
|
|
+ (((unsigned)jiffies & 0xfff) << 16) | instance;
|
|
+}
|
|
+
|
|
+
|
|
+#endif /* __EFRM_INTERNAL_H__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/efx_vi_shm.c 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,707 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides implementation of EFX VI API, used from Xen
|
|
+ * acceleration driver.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#include "linux_resource_internal.h"
|
|
+#include <ci/efrm/vi_resource_manager.h>
|
|
+#include <ci/driver/resource/efx_vi.h>
|
|
+#include <ci/efrm/filter.h>
|
|
+#include <ci/efrm/buffer_table.h>
|
|
+#include <ci/efrm/efrm_client.h>
|
|
+#include <linux/pci.h>
|
|
+#include "kernel_compat.h"
|
|
+
|
|
+#if EFX_VI_STATIC_FILTERS
|
|
+struct filter_list_t {
|
|
+ struct filter_list_t *next;
|
|
+ struct filter_resource *fres;
|
|
+};
|
|
+#endif
|
|
+
|
|
+struct efx_vi_state {
|
|
+ struct vi_resource *vi_res;
|
|
+
|
|
+ int ifindex;
|
|
+ struct efrm_client *efrm_client;
|
|
+ struct efhw_nic *nic;
|
|
+
|
|
+ void (*callback_fn)(void *arg, int is_timeout);
|
|
+ void *callback_arg;
|
|
+
|
|
+ struct completion flush_completion;
|
|
+
|
|
+#if EFX_VI_STATIC_FILTERS
|
|
+ struct filter_list_t fres[EFX_VI_STATIC_FILTERS];
|
|
+ struct filter_list_t *free_fres;
|
|
+ struct filter_list_t *used_fres;
|
|
+#endif
|
|
+};
|
|
+
|
|
+static void efx_vi_flush_complete(void *state_void)
|
|
+{
|
|
+ struct efx_vi_state *state = (struct efx_vi_state *)state_void;
|
|
+
|
|
+ complete(&state->flush_completion);
|
|
+}
|
|
+
|
|
+static inline int alloc_ep(struct efx_vi_state *state)
|
|
+{
|
|
+ int rc;
|
|
+
|
|
+ rc = efrm_vi_resource_alloc(state->efrm_client, NULL, EFHW_VI_JUMBO_EN,
|
|
+ efx_vi_eventq_size,
|
|
+ FALCON_DMA_Q_DEFAULT_TX_SIZE,
|
|
+ FALCON_DMA_Q_DEFAULT_RX_SIZE,
|
|
+ 0, 0, &state->vi_res, NULL, NULL, NULL,
|
|
+ NULL);
|
|
+ if (rc < 0) {
|
|
+ EFRM_ERR("%s: ERROR efrm_vi_resource_alloc error %d",
|
|
+ __func__, rc);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ efrm_vi_register_flush_callback(state->vi_res, &efx_vi_flush_complete,
|
|
+ (void *)state);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int free_ep(struct efx_vi_state *efx_state)
|
|
+{
|
|
+ efrm_vi_resource_release(efx_state->vi_res);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+#if EFX_VI_STATIC_FILTERS
|
|
+static int efx_vi_alloc_static_filters(struct efx_vi_state *efx_state)
|
|
+{
|
|
+ int i;
|
|
+ int rc;
|
|
+
|
|
+ efx_state->free_fres = efx_state->used_fres = NULL;
|
|
+
|
|
+ for (i = 0; i < EFX_VI_STATIC_FILTERS; i++) {
|
|
+ rc = efrm_filter_resource_alloc(efx_state->vi_res,
|
|
+ &efx_state->fres[i].fres);
|
|
+ if (rc < 0) {
|
|
+ EFRM_ERR("%s: efrm_filter_resource_alloc failed: %d",
|
|
+ __func__, rc);
|
|
+ while (i > 0) {
|
|
+ i--;
|
|
+ efrm_filter_resource_release(efx_state->
|
|
+ fres[i].fres);
|
|
+ }
|
|
+ efx_state->free_fres = NULL;
|
|
+ return rc;
|
|
+ }
|
|
+ efx_state->fres[i].next = efx_state->free_fres;
|
|
+ efx_state->free_fres = &efx_state->fres[i];
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+#endif
|
|
+
|
|
+int efx_vi_alloc(struct efx_vi_state **vih_out, int ifindex)
|
|
+{
|
|
+ struct efx_vi_state *efx_state;
|
|
+ int rc;
|
|
+
|
|
+ efx_state = kmalloc(sizeof(struct efx_vi_state), GFP_KERNEL);
|
|
+
|
|
+ if (!efx_state) {
|
|
+ EFRM_ERR("%s: failed to allocate memory for efx_vi_state",
|
|
+ __func__);
|
|
+ rc = -ENOMEM;
|
|
+ goto fail;
|
|
+ }
|
|
+
|
|
+ efx_state->ifindex = ifindex;
|
|
+ rc = efrm_client_get(ifindex, NULL, NULL, &efx_state->efrm_client);
|
|
+ if (rc < 0) {
|
|
+ EFRM_ERR("%s: efrm_client_get(%d) failed: %d", __func__,
|
|
+ ifindex, rc);
|
|
+ rc = -ENODEV;
|
|
+ goto fail_no_ifindex;
|
|
+ }
|
|
+ efx_state->nic = efrm_client_get_nic(efx_state->efrm_client);
|
|
+
|
|
+ init_completion(&efx_state->flush_completion);
|
|
+
|
|
+ /* basically allocate_pt_endpoint() */
|
|
+ rc = alloc_ep(efx_state);
|
|
+ if (rc) {
|
|
+ EFRM_ERR("%s: alloc_ep failed: %d", __func__, rc);
|
|
+ goto fail_no_pt;
|
|
+ }
|
|
+#if EFX_VI_STATIC_FILTERS
|
|
+ /* Statically allocate a set of filter resources - removes the
|
|
+ restriction on not being able to use efx_vi_filter() from
|
|
+ in_atomic() */
|
|
+ rc = efx_vi_alloc_static_filters(efx_state);
|
|
+ if (rc)
|
|
+ goto fail_no_filters;
|
|
+#endif
|
|
+
|
|
+ *vih_out = efx_state;
|
|
+
|
|
+ return 0;
|
|
+#if EFX_VI_STATIC_FILTERS
|
|
+fail_no_filters:
|
|
+ free_ep(efx_state);
|
|
+#endif
|
|
+fail_no_pt:
|
|
+ efrm_client_put(efx_state->efrm_client);
|
|
+fail_no_ifindex:
|
|
+ kfree(efx_state);
|
|
+fail:
|
|
+ return rc;
|
|
+}
|
|
+EXPORT_SYMBOL(efx_vi_alloc);
|
|
+
|
|
+void efx_vi_free(struct efx_vi_state *vih)
|
|
+{
|
|
+ struct efx_vi_state *efx_state = vih;
|
|
+
|
|
+ /* TODO flush dma channels, init dma queues?. See ef_free_vnic() */
|
|
+#if EFX_VI_STATIC_FILTERS
|
|
+ int i;
|
|
+
|
|
+ for (i = 0; i < EFX_VI_STATIC_FILTERS; i++)
|
|
+ efrm_filter_resource_release(efx_state->fres[i].fres);
|
|
+#endif
|
|
+
|
|
+ if (efx_state->vi_res)
|
|
+ free_ep(efx_state);
|
|
+
|
|
+ efrm_client_put(efx_state->efrm_client);
|
|
+
|
|
+ kfree(efx_state);
|
|
+}
|
|
+EXPORT_SYMBOL(efx_vi_free);
|
|
+
|
|
+void efx_vi_reset(struct efx_vi_state *vih)
|
|
+{
|
|
+ struct efx_vi_state *efx_state = vih;
|
|
+
|
|
+ efrm_pt_flush(efx_state->vi_res);
|
|
+
|
|
+ while (wait_for_completion_timeout(&efx_state->flush_completion, HZ)
|
|
+ == 0)
|
|
+ efrm_vi_resource_flush_retry(efx_state->vi_res);
|
|
+
|
|
+ /* Bosch the eventq */
|
|
+ efrm_eventq_reset(efx_state->vi_res);
|
|
+ return;
|
|
+}
|
|
+EXPORT_SYMBOL(efx_vi_reset);
|
|
+
|
|
+static void
|
|
+efx_vi_eventq_callback(void *context, int is_timeout, struct efhw_nic *nic)
|
|
+{
|
|
+ struct efx_vi_state *efx_state = (struct efx_vi_state *)context;
|
|
+
|
|
+ EFRM_ASSERT(efx_state->callback_fn);
|
|
+
|
|
+ return efx_state->callback_fn(efx_state->callback_arg, is_timeout);
|
|
+}
|
|
+
|
|
+int
|
|
+efx_vi_eventq_register_callback(struct efx_vi_state *vih,
|
|
+ void (*callback)(void *context, int is_timeout),
|
|
+ void *context)
|
|
+{
|
|
+ struct efx_vi_state *efx_state = vih;
|
|
+
|
|
+ efx_state->callback_fn = callback;
|
|
+ efx_state->callback_arg = context;
|
|
+
|
|
+ /* Register the eventq timeout event callback */
|
|
+ efrm_eventq_register_callback(efx_state->vi_res,
|
|
+ efx_vi_eventq_callback, efx_state);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL(efx_vi_eventq_register_callback);
|
|
+
|
|
+int efx_vi_eventq_kill_callback(struct efx_vi_state *vih)
|
|
+{
|
|
+ struct efx_vi_state *efx_state = vih;
|
|
+
|
|
+ if (efx_state->vi_res->evq_callback_fn)
|
|
+ efrm_eventq_kill_callback(efx_state->vi_res);
|
|
+
|
|
+ efx_state->callback_fn = NULL;
|
|
+ efx_state->callback_arg = NULL;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL(efx_vi_eventq_kill_callback);
|
|
+
|
|
+struct efx_vi_dma_map_state {
|
|
+ struct efhw_buffer_table_allocation bt_handle;
|
|
+ int n_pages;
|
|
+ dma_addr_t *dma_addrs;
|
|
+};
|
|
+
|
|
+int
|
|
+efx_vi_dma_map_pages(struct efx_vi_state *vih, struct page **pages,
|
|
+ int n_pages, struct efx_vi_dma_map_state **dmh_out)
|
|
+{
|
|
+ struct efx_vi_state *efx_state = vih;
|
|
+ int order = fls(n_pages - 1), rc, i, evq_id;
|
|
+ dma_addr_t dma_addr;
|
|
+ struct efx_vi_dma_map_state *dm_state;
|
|
+
|
|
+ if (n_pages != (1 << order)) {
|
|
+ EFRM_WARN("%s: Can only allocate buffers in power of 2 "
|
|
+ "sizes (not %d)", __func__, n_pages);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ dm_state = kmalloc(sizeof(struct efx_vi_dma_map_state), GFP_KERNEL);
|
|
+ if (!dm_state)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ dm_state->dma_addrs = kmalloc(sizeof(dma_addr_t) * n_pages,
|
|
+ GFP_KERNEL);
|
|
+ if (!dm_state->dma_addrs) {
|
|
+ kfree(dm_state);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ rc = efrm_buffer_table_alloc(order, &dm_state->bt_handle);
|
|
+ if (rc < 0) {
|
|
+ kfree(dm_state->dma_addrs);
|
|
+ kfree(dm_state);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ evq_id = EFRM_RESOURCE_INSTANCE(efx_state->vi_res->rs.rs_handle);
|
|
+ for (i = 0; i < n_pages; i++) {
|
|
+ /* TODO do we need to get_page() here ? */
|
|
+
|
|
+ dma_addr = pci_map_page(linux_efhw_nic(efx_state->nic)->
|
|
+ pci_dev, pages[i], 0, PAGE_SIZE,
|
|
+ PCI_DMA_TODEVICE);
|
|
+
|
|
+ efrm_buffer_table_set(&dm_state->bt_handle, efx_state->nic,
|
|
+ i, dma_addr, evq_id);
|
|
+
|
|
+ dm_state->dma_addrs[i] = dma_addr;
|
|
+
|
|
+ /* Would be nice to not have to call commit each time, but
|
|
+ * comment says there are hardware restrictions on how often
|
|
+ * you can go without it, so do this to be safe */
|
|
+ efrm_buffer_table_commit();
|
|
+ }
|
|
+
|
|
+ dm_state->n_pages = n_pages;
|
|
+
|
|
+ *dmh_out = dm_state;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL(efx_vi_dma_map_pages);
|
|
+
|
|
+/* Function needed as Xen can't get pages for grants in dom0, but can
|
|
+ get dma address */
|
|
+int
|
|
+efx_vi_dma_map_addrs(struct efx_vi_state *vih,
|
|
+ unsigned long long *bus_dev_addrs,
|
|
+ int n_pages, struct efx_vi_dma_map_state **dmh_out)
|
|
+{
|
|
+ struct efx_vi_state *efx_state = vih;
|
|
+ int order = fls(n_pages - 1), rc, i, evq_id;
|
|
+ dma_addr_t dma_addr;
|
|
+ struct efx_vi_dma_map_state *dm_state;
|
|
+
|
|
+ if (n_pages != (1 << order)) {
|
|
+ EFRM_WARN("%s: Can only allocate buffers in power of 2 "
|
|
+ "sizes (not %d)", __func__, n_pages);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ dm_state = kmalloc(sizeof(struct efx_vi_dma_map_state), GFP_KERNEL);
|
|
+ if (!dm_state)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ dm_state->dma_addrs = kmalloc(sizeof(dma_addr_t) * n_pages,
|
|
+ GFP_KERNEL);
|
|
+ if (!dm_state->dma_addrs) {
|
|
+ kfree(dm_state);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ rc = efrm_buffer_table_alloc(order, &dm_state->bt_handle);
|
|
+ if (rc < 0) {
|
|
+ kfree(dm_state->dma_addrs);
|
|
+ kfree(dm_state);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ evq_id = EFRM_RESOURCE_INSTANCE(efx_state->vi_res->rs.rs_handle);
|
|
+#if 0
|
|
+ EFRM_WARN("%s: mapping %d pages to evq %d, bt_ids %d-%d\n",
|
|
+ __func__, n_pages, evq_id,
|
|
+ dm_state->bt_handle.base,
|
|
+ dm_state->bt_handle.base + n_pages);
|
|
+#endif
|
|
+ for (i = 0; i < n_pages; i++) {
|
|
+
|
|
+ dma_addr = (dma_addr_t)bus_dev_addrs[i];
|
|
+
|
|
+ efrm_buffer_table_set(&dm_state->bt_handle, efx_state->nic,
|
|
+ i, dma_addr, evq_id);
|
|
+
|
|
+ dm_state->dma_addrs[i] = dma_addr;
|
|
+
|
|
+ /* Would be nice to not have to call commit each time, but
|
|
+ * comment says there are hardware restrictions on how often
|
|
+ * you can go without it, so do this to be safe */
|
|
+ efrm_buffer_table_commit();
|
|
+ }
|
|
+
|
|
+ dm_state->n_pages = n_pages;
|
|
+
|
|
+ *dmh_out = dm_state;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL(efx_vi_dma_map_addrs);
|
|
+
|
|
+void
|
|
+efx_vi_dma_unmap_pages(struct efx_vi_state *vih,
|
|
+ struct efx_vi_dma_map_state *dmh)
|
|
+{
|
|
+ struct efx_vi_state *efx_state = vih;
|
|
+ struct efx_vi_dma_map_state *dm_state =
|
|
+ (struct efx_vi_dma_map_state *)dmh;
|
|
+ int i;
|
|
+
|
|
+ efrm_buffer_table_free(&dm_state->bt_handle);
|
|
+
|
|
+ for (i = 0; i < dm_state->n_pages; ++i)
|
|
+ pci_unmap_page(linux_efhw_nic(efx_state->nic)->pci_dev,
|
|
+ dm_state->dma_addrs[i], PAGE_SIZE,
|
|
+ PCI_DMA_TODEVICE);
|
|
+
|
|
+ kfree(dm_state->dma_addrs);
|
|
+ kfree(dm_state);
|
|
+
|
|
+ return;
|
|
+}
|
|
+EXPORT_SYMBOL(efx_vi_dma_unmap_pages);
|
|
+
|
|
+void
|
|
+efx_vi_dma_unmap_addrs(struct efx_vi_state *vih,
|
|
+ struct efx_vi_dma_map_state *dmh)
|
|
+{
|
|
+ struct efx_vi_dma_map_state *dm_state =
|
|
+ (struct efx_vi_dma_map_state *)dmh;
|
|
+
|
|
+ efrm_buffer_table_free(&dm_state->bt_handle);
|
|
+
|
|
+ kfree(dm_state->dma_addrs);
|
|
+ kfree(dm_state);
|
|
+
|
|
+ return;
|
|
+}
|
|
+EXPORT_SYMBOL(efx_vi_dma_unmap_addrs);
|
|
+
|
|
+unsigned
|
|
+efx_vi_dma_get_map_addr(struct efx_vi_state *vih,
|
|
+ struct efx_vi_dma_map_state *dmh)
|
|
+{
|
|
+ struct efx_vi_dma_map_state *dm_state =
|
|
+ (struct efx_vi_dma_map_state *)dmh;
|
|
+
|
|
+ return EFHW_BUFFER_ADDR(dm_state->bt_handle.base, 0);
|
|
+}
|
|
+EXPORT_SYMBOL(efx_vi_dma_get_map_addr);
|
|
+
|
|
+#if EFX_VI_STATIC_FILTERS
|
|
+static int
|
|
+get_filter(struct efx_vi_state *efx_state,
|
|
+ efrm_resource_handle_t pthandle, struct filter_resource **fres_out)
|
|
+{
|
|
+ struct filter_list_t *flist;
|
|
+ if (efx_state->free_fres == NULL)
|
|
+ return -ENOMEM;
|
|
+ else {
|
|
+ flist = efx_state->free_fres;
|
|
+ efx_state->free_fres = flist->next;
|
|
+ flist->next = efx_state->used_fres;
|
|
+ efx_state->used_fres = flist;
|
|
+ *fres_out = flist->fres;
|
|
+ return 0;
|
|
+ }
|
|
+}
|
|
+#endif
|
|
+
|
|
+static void
|
|
+release_filter(struct efx_vi_state *efx_state, struct filter_resource *fres)
|
|
+{
|
|
+#if EFX_VI_STATIC_FILTERS
|
|
+ struct filter_list_t *flist = efx_state->used_fres, *prev = NULL;
|
|
+ while (flist) {
|
|
+ if (flist->fres == fres) {
|
|
+ if (prev)
|
|
+ prev->next = flist->next;
|
|
+ else
|
|
+ efx_state->used_fres = flist->next;
|
|
+ flist->next = efx_state->free_fres;
|
|
+ efx_state->free_fres = flist;
|
|
+ return;
|
|
+ }
|
|
+ prev = flist;
|
|
+ flist = flist->next;
|
|
+ }
|
|
+ EFRM_ERR("%s: couldn't find filter", __func__);
|
|
+#else
|
|
+ return efrm_filter_resource_release(fres);
|
|
+#endif
|
|
+}
|
|
+
|
|
+int
|
|
+efx_vi_filter(struct efx_vi_state *vih, int protocol,
|
|
+ unsigned ip_addr_be32, int port_le16,
|
|
+ struct filter_resource_t **fh_out)
|
|
+{
|
|
+ struct efx_vi_state *efx_state = vih;
|
|
+ struct filter_resource *uninitialized_var(frs);
|
|
+ int rc;
|
|
+
|
|
+#if EFX_VI_STATIC_FILTERS
|
|
+ rc = get_filter(efx_state, efx_state->vi_res->rs.rs_handle, &frs);
|
|
+#else
|
|
+ rc = efrm_filter_resource_alloc(efx_state->vi_res, &frs);
|
|
+#endif
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ /* Add the hardware filter. We pass in the source port and address
|
|
+ * as 0 (wildcard) to minimise the number of filters needed. */
|
|
+ if (protocol == IPPROTO_TCP) {
|
|
+ rc = efrm_filter_resource_tcp_set(frs, 0, 0, ip_addr_be32,
|
|
+ port_le16);
|
|
+ } else {
|
|
+ rc = efrm_filter_resource_udp_set(frs, 0, 0, ip_addr_be32,
|
|
+ port_le16);
|
|
+ }
|
|
+
|
|
+ *fh_out = (struct filter_resource_t *)frs;
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+EXPORT_SYMBOL(efx_vi_filter);
|
|
+
|
|
+int
|
|
+efx_vi_filter_stop(struct efx_vi_state *vih, struct filter_resource_t *fh)
|
|
+{
|
|
+ struct efx_vi_state *efx_state = vih;
|
|
+ struct filter_resource *frs = (struct filter_resource *)fh;
|
|
+ int rc;
|
|
+
|
|
+ rc = efrm_filter_resource_clear(frs);
|
|
+ release_filter(efx_state, frs);
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+EXPORT_SYMBOL(efx_vi_filter_stop);
|
|
+
|
|
+int
|
|
+efx_vi_hw_resource_get_virt(struct efx_vi_state *vih,
|
|
+ struct efx_vi_hw_resource_metadata *mdata,
|
|
+ struct efx_vi_hw_resource *hw_res_array,
|
|
+ int *length)
|
|
+{
|
|
+ EFRM_NOTICE("%s: TODO!", __func__);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL(efx_vi_hw_resource_get_virt);
|
|
+
|
|
+int
|
|
+efx_vi_hw_resource_get_phys(struct efx_vi_state *vih,
|
|
+ struct efx_vi_hw_resource_metadata *mdata,
|
|
+ struct efx_vi_hw_resource *hw_res_array,
|
|
+ int *length)
|
|
+{
|
|
+ struct efx_vi_state *efx_state = vih;
|
|
+ struct linux_efhw_nic *lnic = linux_efhw_nic(efx_state->nic);
|
|
+ unsigned long phys = lnic->ctr_ap_pci_addr;
|
|
+ struct efrm_resource *ep_res = &efx_state->vi_res->rs;
|
|
+ unsigned ep_mmap_bytes;
|
|
+ int i;
|
|
+
|
|
+ if (*length < EFX_VI_HW_RESOURCE_MAXSIZE)
|
|
+ return -EINVAL;
|
|
+
|
|
+ mdata->nic_arch = efx_state->nic->devtype.arch;
|
|
+ mdata->nic_variant = efx_state->nic->devtype.variant;
|
|
+ mdata->nic_revision = efx_state->nic->devtype.revision;
|
|
+
|
|
+ mdata->evq_order =
|
|
+ efx_state->vi_res->nic_info.evq_pages.iobuff.order;
|
|
+ mdata->evq_offs = efx_state->vi_res->nic_info.evq_pages.iobuff_off;
|
|
+ mdata->evq_capacity = efx_vi_eventq_size;
|
|
+ mdata->instance = EFRM_RESOURCE_INSTANCE(ep_res->rs_handle);
|
|
+ mdata->rx_capacity = FALCON_DMA_Q_DEFAULT_RX_SIZE;
|
|
+ mdata->tx_capacity = FALCON_DMA_Q_DEFAULT_TX_SIZE;
|
|
+
|
|
+ ep_mmap_bytes = FALCON_DMA_Q_DEFAULT_MMAP;
|
|
+ EFRM_ASSERT(ep_mmap_bytes == PAGE_SIZE * 2);
|
|
+
|
|
+#ifndef NDEBUG
|
|
+ {
|
|
+ /* Sanity about doorbells */
|
|
+ unsigned long tx_dma_page_addr, rx_dma_page_addr;
|
|
+
|
|
+ /* get rx doorbell address */
|
|
+ rx_dma_page_addr =
|
|
+ phys + falcon_rx_dma_page_addr(mdata->instance);
|
|
+ /* get tx doorbell address */
|
|
+ tx_dma_page_addr =
|
|
+ phys + falcon_tx_dma_page_addr(mdata->instance);
|
|
+
|
|
+ /* Check the lower bits of the TX doorbell will be
|
|
+ * consistent. */
|
|
+ EFRM_ASSERT((TX_DESC_UPD_REG_PAGE4_OFST &
|
|
+ FALCON_DMA_PAGE_MASK) ==
|
|
+ (TX_DESC_UPD_REG_PAGE123K_OFST &
|
|
+ FALCON_DMA_PAGE_MASK));
|
|
+
|
|
+ /* Check the lower bits of the RX doorbell will be
|
|
+ * consistent. */
|
|
+ EFRM_ASSERT((RX_DESC_UPD_REG_PAGE4_OFST &
|
|
+ FALCON_DMA_PAGE_MASK) ==
|
|
+ (RX_DESC_UPD_REG_PAGE123K_OFST &
|
|
+ FALCON_DMA_PAGE_MASK));
|
|
+
|
|
+ /* Check that the doorbells will be in the same page. */
|
|
+ EFRM_ASSERT((TX_DESC_UPD_REG_PAGE4_OFST & PAGE_MASK) ==
|
|
+ (RX_DESC_UPD_REG_PAGE4_OFST & PAGE_MASK));
|
|
+
|
|
+ /* Check that the doorbells are in the same page. */
|
|
+ EFRM_ASSERT((tx_dma_page_addr & PAGE_MASK) ==
|
|
+ (rx_dma_page_addr & PAGE_MASK));
|
|
+
|
|
+ /* Check that the TX doorbell offset is correct. */
|
|
+ EFRM_ASSERT((TX_DESC_UPD_REG_PAGE4_OFST & ~PAGE_MASK) ==
|
|
+ (tx_dma_page_addr & ~PAGE_MASK));
|
|
+
|
|
+ /* Check that the RX doorbell offset is correct. */
|
|
+ EFRM_ASSERT((RX_DESC_UPD_REG_PAGE4_OFST & ~PAGE_MASK) ==
|
|
+ (rx_dma_page_addr & ~PAGE_MASK));
|
|
+ }
|
|
+#endif
|
|
+
|
|
+ i = 0;
|
|
+ hw_res_array[i].type = EFX_VI_HW_RESOURCE_TXDMAQ;
|
|
+ hw_res_array[i].mem_type = EFX_VI_HW_RESOURCE_PERIPHERAL;
|
|
+ hw_res_array[i].more_to_follow = 0;
|
|
+ hw_res_array[i].length = PAGE_SIZE;
|
|
+ hw_res_array[i].address =
|
|
+ (unsigned long)efx_state->vi_res->nic_info.
|
|
+ dmaq_pages[EFRM_VI_RM_DMA_QUEUE_TX].kva;
|
|
+
|
|
+ i++;
|
|
+ hw_res_array[i].type = EFX_VI_HW_RESOURCE_RXDMAQ;
|
|
+ hw_res_array[i].mem_type = EFX_VI_HW_RESOURCE_PERIPHERAL;
|
|
+ hw_res_array[i].more_to_follow = 0;
|
|
+ hw_res_array[i].length = PAGE_SIZE;
|
|
+ hw_res_array[i].address =
|
|
+ (unsigned long)efx_state->vi_res->nic_info.
|
|
+ dmaq_pages[EFRM_VI_RM_DMA_QUEUE_RX].kva;
|
|
+
|
|
+ i++;
|
|
+ hw_res_array[i].type = EFX_VI_HW_RESOURCE_EVQTIMER;
|
|
+ hw_res_array[i].mem_type = EFX_VI_HW_RESOURCE_PERIPHERAL;
|
|
+ hw_res_array[i].more_to_follow = 0;
|
|
+ hw_res_array[i].length = PAGE_SIZE;
|
|
+ hw_res_array[i].address =
|
|
+ (unsigned long)phys + falcon_timer_page_addr(mdata->instance);
|
|
+
|
|
+ /* NB EFX_VI_HW_RESOURCE_EVQPTR not used on Falcon */
|
|
+
|
|
+ i++;
|
|
+ switch (efx_state->nic->devtype.variant) {
|
|
+ case 'A':
|
|
+ hw_res_array[i].type = EFX_VI_HW_RESOURCE_EVQRPTR;
|
|
+ hw_res_array[i].mem_type = EFX_VI_HW_RESOURCE_PERIPHERAL;
|
|
+ hw_res_array[i].more_to_follow = 0;
|
|
+ hw_res_array[i].length = PAGE_SIZE;
|
|
+ hw_res_array[i].address = (unsigned long)phys +
|
|
+ EVQ_RPTR_REG_OFST +
|
|
+ (FALCON_REGISTER128 * mdata->instance);
|
|
+ break;
|
|
+ case 'B':
|
|
+ hw_res_array[i].type = EFX_VI_HW_RESOURCE_EVQRPTR_OFFSET;
|
|
+ hw_res_array[i].mem_type = EFX_VI_HW_RESOURCE_PERIPHERAL;
|
|
+ hw_res_array[i].more_to_follow = 0;
|
|
+ hw_res_array[i].length = PAGE_SIZE;
|
|
+ hw_res_array[i].address =
|
|
+ (unsigned long)FALCON_EVQ_RPTR_REG_P0;
|
|
+ break;
|
|
+ default:
|
|
+ EFRM_ASSERT(0);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ i++;
|
|
+ hw_res_array[i].type = EFX_VI_HW_RESOURCE_EVQMEMKVA;
|
|
+ hw_res_array[i].mem_type = EFX_VI_HW_RESOURCE_IOBUFFER;
|
|
+ hw_res_array[i].more_to_follow = 0;
|
|
+ hw_res_array[i].length = PAGE_SIZE;
|
|
+ hw_res_array[i].address = (unsigned long)efx_state->vi_res->
|
|
+ nic_info.evq_pages.iobuff.kva;
|
|
+
|
|
+ i++;
|
|
+ hw_res_array[i].type = EFX_VI_HW_RESOURCE_BELLPAGE;
|
|
+ hw_res_array[i].mem_type = EFX_VI_HW_RESOURCE_PERIPHERAL;
|
|
+ hw_res_array[i].more_to_follow = 0;
|
|
+ hw_res_array[i].length = PAGE_SIZE;
|
|
+ hw_res_array[i].address =
|
|
+ (unsigned long)(phys +
|
|
+ falcon_tx_dma_page_addr(mdata->instance))
|
|
+ >> PAGE_SHIFT;
|
|
+
|
|
+ i++;
|
|
+
|
|
+ EFRM_ASSERT(i <= *length);
|
|
+
|
|
+ *length = i;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL(efx_vi_hw_resource_get_phys);
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/eventq.c 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,321 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file contains event queue support.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#include <ci/efhw/debug.h>
|
|
+#include <ci/efhw/iopage.h>
|
|
+#include <ci/driver/efab/hardware.h>
|
|
+#include <ci/efhw/eventq.h>
|
|
+#include <ci/efhw/falcon.h>
|
|
+#include <ci/efhw/nic.h>
|
|
+
|
|
+#define KEVENTQ_MAGIC 0x07111974
|
|
+
|
|
+/*! Helper function to allocate the iobuffer needed by an eventq
|
|
+ * - it ensures the eventq has the correct alignment for the NIC
|
|
+ *
|
|
+ * \param rm Event-queue resource manager
|
|
+ * \param instance Event-queue instance (index)
|
|
+ * \param buf_bytes Requested size of eventq
|
|
+ * \return < 0 if iobuffer allocation fails
|
|
+ */
|
|
+int
|
|
+efhw_nic_event_queue_alloc_iobuffer(struct efhw_nic *nic,
|
|
+ struct eventq_resource_hardware *h,
|
|
+ int evq_instance, unsigned buf_bytes)
|
|
+{
|
|
+ unsigned int page_order;
|
|
+ int rc;
|
|
+
|
|
+ /* Allocate an iobuffer. */
|
|
+ page_order = get_order(buf_bytes);
|
|
+
|
|
+ h->iobuff_off = 0;
|
|
+
|
|
+ EFHW_TRACE("allocating eventq size %x",
|
|
+ 1u << (page_order + PAGE_SHIFT));
|
|
+ rc = efhw_iopages_alloc(nic, &h->iobuff, page_order);
|
|
+ if (rc < 0) {
|
|
+ EFHW_WARN("%s: failed to allocate %u pages",
|
|
+ __func__, 1u << page_order);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ /* Set the eventq pages to match EFHW_CLEAR_EVENT() */
|
|
+ if (EFHW_CLEAR_EVENT_VALUE)
|
|
+ memset(efhw_iopages_ptr(&h->iobuff) + h->iobuff_off,
|
|
+ EFHW_CLEAR_EVENT_VALUE, (1u << page_order) * PAGE_SIZE);
|
|
+
|
|
+ EFHW_TRACE("%s: allocated %u pages", __func__, 1u << (page_order));
|
|
+
|
|
+ /* For Falcon the NIC is programmed with the base buffer address of a
|
|
+ * contiguous region of buffer space. This means that larger than a
|
|
+ * PAGE event queues can be expected to allocate even when the host's
|
|
+ * physical memory is fragmented */
|
|
+ EFHW_ASSERT(efhw_nic_have_hw(nic));
|
|
+ EFHW_ASSERT(page_order <= h->buf_tbl_alloc.order);
|
|
+
|
|
+ /* Initialise the buffer table entries. */
|
|
+ falcon_nic_buffer_table_set_n(nic, h->buf_tbl_alloc.base,
|
|
+ efhw_iopages_dma_addr(&h->iobuff) +
|
|
+ h->iobuff_off, EFHW_NIC_PAGE_SIZE, 0,
|
|
+ 1 << page_order, 0);
|
|
+
|
|
+ if (evq_instance >= FALCON_EVQ_TBL_RESERVED)
|
|
+ falcon_nic_buffer_table_confirm(nic);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/**********************************************************************
|
|
+ * Kernel event queue management.
|
|
+ */
|
|
+
|
|
+/* Values for [struct efhw_keventq::lock] field. */
|
|
+#define KEVQ_UNLOCKED 0
|
|
+#define KEVQ_LOCKED 1
|
|
+#define KEVQ_RECHECK 2
|
|
+
|
|
+int
|
|
+efhw_keventq_ctor(struct efhw_nic *nic, int instance,
|
|
+ struct efhw_keventq *evq,
|
|
+ struct efhw_ev_handler *ev_handlers)
|
|
+{
|
|
+ int rc;
|
|
+ unsigned buf_bytes = evq->hw.capacity * sizeof(efhw_event_t);
|
|
+
|
|
+ evq->instance = instance;
|
|
+ evq->ev_handlers = ev_handlers;
|
|
+
|
|
+ /* allocate an IObuffer for the eventq */
|
|
+ rc = efhw_nic_event_queue_alloc_iobuffer(nic, &evq->hw, evq->instance,
|
|
+ buf_bytes);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ /* Zero the timer-value for this queue.
|
|
+ AND Tell the nic about the event queue. */
|
|
+ efhw_nic_event_queue_enable(nic, evq->instance, evq->hw.capacity,
|
|
+ efhw_iopages_dma_addr(&evq->hw.iobuff) +
|
|
+ evq->hw.iobuff_off,
|
|
+ evq->hw.buf_tbl_alloc.base,
|
|
+ 1 /* interrupting */);
|
|
+
|
|
+ evq->lock = KEVQ_UNLOCKED;
|
|
+ evq->evq_base = efhw_iopages_ptr(&evq->hw.iobuff) + evq->hw.iobuff_off;
|
|
+ evq->evq_ptr = 0;
|
|
+ evq->evq_mask = (evq->hw.capacity * sizeof(efhw_event_t)) - 1u;
|
|
+
|
|
+ EFHW_TRACE("%s: [%d] base=%p end=%p", __func__, evq->instance,
|
|
+ evq->evq_base, evq->evq_base + buf_bytes);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void efhw_keventq_dtor(struct efhw_nic *nic, struct efhw_keventq *evq)
|
|
+{
|
|
+ EFHW_ASSERT(evq);
|
|
+
|
|
+ EFHW_TRACE("%s: [%d]", __func__, evq->instance);
|
|
+
|
|
+ /* Zero the timer-value for this queue.
|
|
+ And Tell NIC to stop using this event queue. */
|
|
+ efhw_nic_event_queue_disable(nic, evq->instance, 0);
|
|
+
|
|
+ /* free the pages used by the eventq itself */
|
|
+ efhw_iopages_free(nic, &evq->hw.iobuff);
|
|
+}
|
|
+
|
|
+void
|
|
+efhw_handle_txdmaq_flushed(struct efhw_nic *nic, struct efhw_ev_handler *h,
|
|
+ efhw_event_t *evp)
|
|
+{
|
|
+ int instance = (int)FALCON_EVENT_TX_FLUSH_Q_ID(evp);
|
|
+ EFHW_TRACE("%s: instance=%d", __func__, instance);
|
|
+
|
|
+ if (!h->dmaq_flushed_fn) {
|
|
+ EFHW_WARN("%s: no handler registered", __func__);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ h->dmaq_flushed_fn(nic, instance, false);
|
|
+}
|
|
+
|
|
+void
|
|
+efhw_handle_rxdmaq_flushed(struct efhw_nic *nic, struct efhw_ev_handler *h,
|
|
+ efhw_event_t *evp)
|
|
+{
|
|
+ unsigned instance = (unsigned)FALCON_EVENT_RX_FLUSH_Q_ID(evp);
|
|
+ EFHW_TRACE("%s: instance=%d", __func__, instance);
|
|
+
|
|
+ if (!h->dmaq_flushed_fn) {
|
|
+ EFHW_WARN("%s: no handler registered", __func__);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ h->dmaq_flushed_fn(nic, instance, true);
|
|
+}
|
|
+
|
|
+void
|
|
+efhw_handle_wakeup_event(struct efhw_nic *nic, struct efhw_ev_handler *h,
|
|
+ efhw_event_t *evp)
|
|
+{
|
|
+ unsigned instance = (unsigned)FALCON_EVENT_WAKE_EVQ_ID(evp);
|
|
+
|
|
+ if (!h->wakeup_fn) {
|
|
+ EFHW_WARN("%s: no handler registered", __func__);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ h->wakeup_fn(nic, instance);
|
|
+}
|
|
+
|
|
+void
|
|
+efhw_handle_timeout_event(struct efhw_nic *nic, struct efhw_ev_handler *h,
|
|
+ efhw_event_t *evp)
|
|
+{
|
|
+ unsigned instance = (unsigned)FALCON_EVENT_WAKE_EVQ_ID(evp);
|
|
+
|
|
+ if (!h->timeout_fn) {
|
|
+ EFHW_WARN("%s: no handler registered", __func__);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ h->timeout_fn(nic, instance);
|
|
+}
|
|
+
|
|
+/**********************************************************************
|
|
+ * Kernel event queue event handling.
|
|
+ */
|
|
+
|
|
+int efhw_keventq_poll(struct efhw_nic *nic, struct efhw_keventq *q)
|
|
+{
|
|
+ efhw_event_t *ev;
|
|
+ int l, count = 0;
|
|
+
|
|
+ EFHW_ASSERT(nic);
|
|
+ EFHW_ASSERT(q);
|
|
+ EFHW_ASSERT(q->ev_handlers);
|
|
+
|
|
+ /* Acquire the lock, or mark the queue as needing re-checking. */
|
|
+ for (;;) {
|
|
+ l = q->lock;
|
|
+ if (l == KEVQ_UNLOCKED) {
|
|
+ if ((int)cmpxchg(&q->lock, l, KEVQ_LOCKED) == l)
|
|
+ break;
|
|
+ } else if (l == KEVQ_LOCKED) {
|
|
+ if ((int)cmpxchg(&q->lock, l, KEVQ_RECHECK) == l)
|
|
+ return 0;
|
|
+ } else { /* already marked for re-checking */
|
|
+ EFHW_ASSERT(l == KEVQ_RECHECK);
|
|
+ return 0;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (unlikely(EFHW_EVENT_OVERFLOW(q, q)))
|
|
+ goto overflow;
|
|
+
|
|
+ ev = EFHW_EVENT_PTR(q, q, 0);
|
|
+
|
|
+#ifndef NDEBUG
|
|
+ if (!EFHW_IS_EVENT(ev))
|
|
+ EFHW_TRACE("%s: %d NO EVENTS!", __func__, q->instance);
|
|
+#endif
|
|
+
|
|
+ for (;;) {
|
|
+ /* Convention for return codes for handlers is:
|
|
+ ** 0 - no error, event consumed
|
|
+ ** 1 - no error, event not consumed
|
|
+ ** -ve - error, event not consumed
|
|
+ */
|
|
+ if (likely(EFHW_IS_EVENT(ev))) {
|
|
+ count++;
|
|
+
|
|
+ switch (FALCON_EVENT_CODE(ev)) {
|
|
+
|
|
+ case FALCON_EVENT_CODE_CHAR:
|
|
+ falcon_handle_char_event(nic, q->ev_handlers,
|
|
+ ev);
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ EFHW_ERR("efhw_keventq_poll: [%d] UNEXPECTED "
|
|
+ "EVENT:"FALCON_EVENT_FMT,
|
|
+ q->instance,
|
|
+ FALCON_EVENT_PRI_ARG(*ev));
|
|
+ }
|
|
+
|
|
+ EFHW_CLEAR_EVENT(ev);
|
|
+ EFHW_EVENTQ_NEXT(q);
|
|
+
|
|
+ ev = EFHW_EVENT_PTR(q, q, 0);
|
|
+ } else {
|
|
+ /* No events left. Release the lock (checking if we
|
|
+ * need to re-poll to avoid race). */
|
|
+ l = q->lock;
|
|
+ if (l == KEVQ_LOCKED) {
|
|
+ if ((int)cmpxchg(&q->lock, l, KEVQ_UNLOCKED)
|
|
+ == l) {
|
|
+ EFHW_TRACE
|
|
+ ("efhw_keventq_poll: %d clean exit",
|
|
+ q->instance);
|
|
+ goto clean_exit;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Potentially more work to do. */
|
|
+ l = q->lock;
|
|
+ EFHW_ASSERT(l == KEVQ_RECHECK);
|
|
+ EFHW_TEST((int)cmpxchg(&q->lock, l, KEVQ_LOCKED) == l);
|
|
+ EFHW_TRACE("efhw_keventq_poll: %d re-poll required",
|
|
+ q->instance);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* shouldn't get here */
|
|
+ EFHW_ASSERT(0);
|
|
+
|
|
+overflow:
|
|
+ /* ?? Oh dear. Should we poll everything that could have possibly
|
|
+ ** happened? Or merely cry out in anguish...
|
|
+ */
|
|
+ EFHW_WARN("efhw_keventq_poll: %d ***** OVERFLOW nic %d *****",
|
|
+ q->instance, nic->index);
|
|
+
|
|
+ q->lock = KEVQ_UNLOCKED;
|
|
+ return count;
|
|
+
|
|
+clean_exit:
|
|
+ /* Ack the processed events so that this event queue can potentially
|
|
+ raise interrupts again */
|
|
+ falcon_nic_evq_ack(nic, q->instance,
|
|
+ (EFHW_EVENT_OFFSET(q, q, 0) / sizeof(efhw_event_t)),
|
|
+ false);
|
|
+ return count;
|
|
+}
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/falcon.c 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,2525 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file contains Falcon hardware support.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#include <ci/driver/efab/hardware.h>
|
|
+#include <ci/efhw/debug.h>
|
|
+#include <ci/efhw/iopage.h>
|
|
+#include <ci/efhw/falcon.h>
|
|
+#include <ci/efhw/falcon_hash.h>
|
|
+#include <ci/efhw/nic.h>
|
|
+#include <ci/efhw/eventq.h>
|
|
+#include <ci/efhw/checks.h>
|
|
+
|
|
+
|
|
+/*----------------------------------------------------------------------------
|
|
+ *
|
|
+ * Workarounds and options
|
|
+ *
|
|
+ *---------------------------------------------------------------------------*/
|
|
+
|
|
+/* Keep a software copy of the filter table and check for duplicates. */
|
|
+#define FALCON_FULL_FILTER_CACHE 1
|
|
+
|
|
+/* Read filters back from the hardware to detect corruption. */
|
|
+#define FALCON_VERIFY_FILTERS 0
|
|
+
|
|
+/* Options */
|
|
+#define RX_FILTER_CTL_SRCH_LIMIT_TCP_FULL 8 /* default search limit */
|
|
+#define RX_FILTER_CTL_SRCH_LIMIT_TCP_WILD 8 /* default search limit */
|
|
+#define RX_FILTER_CTL_SRCH_LIMIT_UDP_FULL 8 /* default search limit */
|
|
+#define RX_FILTER_CTL_SRCH_LIMIT_UDP_WILD 8 /* default search limit */
|
|
+
|
|
+#define FALCON_MAC_SET_TYPE_BY_SPEED 0
|
|
+
|
|
+/* FIXME: We should detect mode at runtime. */
|
|
+#define FALCON_BUFFER_TABLE_FULL_MODE 1
|
|
+
|
|
+/* "Fudge factors" - difference between programmed value and actual depth */
|
|
+#define RX_FILTER_CTL_SRCH_FUDGE_WILD 3 /* increase the search limit */
|
|
+#define RX_FILTER_CTL_SRCH_FUDGE_FULL 1 /* increase the search limit */
|
|
+#define TX_FILTER_CTL_SRCH_FUDGE_WILD 3 /* increase the search limit */
|
|
+#define TX_FILTER_CTL_SRCH_FUDGE_FULL 1 /* increase the search limit */
|
|
+
|
|
+/*----------------------------------------------------------------------------
|
|
+ *
|
|
+ * Debug Macros
|
|
+ *
|
|
+ *---------------------------------------------------------------------------*/
|
|
+
|
|
+#define _DEBUG_SYM_ static
|
|
+
|
|
+ /*----------------------------------------------------------------------------
|
|
+ *
|
|
+ * Macros and forward declarations
|
|
+ *
|
|
+ *--------------------------------------------------------------------------*/
|
|
+
|
|
+#define FALCON_REGION_NUM 4 /* number of supported memory regions */
|
|
+
|
|
+#define FALCON_BUFFER_TBL_HALF_BYTES 4
|
|
+#define FALCON_BUFFER_TBL_FULL_BYTES 8
|
|
+
|
|
+/* Shadow buffer table - hack for testing only */
|
|
+#if FALCON_BUFFER_TABLE_FULL_MODE == 0
|
|
+# define FALCON_USE_SHADOW_BUFFER_TABLE 1
|
|
+#else
|
|
+# define FALCON_USE_SHADOW_BUFFER_TABLE 0
|
|
+#endif
|
|
+
|
|
+
|
|
+/*----------------------------------------------------------------------------
|
|
+ *
|
|
+ * Header assertion checks
|
|
+ *
|
|
+ *---------------------------------------------------------------------------*/
|
|
+
|
|
+#define FALCON_ASSERT_VALID() /* nothing yet */
|
|
+
|
|
+/* Falcon has a 128bit register model but most registers have useful
|
|
+ defaults or only implement a small number of bits. Some registers
|
|
+ can be programmed 32bits UNLOCKED all others should be interlocked
|
|
+ against other threads within the same protection domain.
|
|
+
|
|
+ Aim is for software to perform the minimum number of writes and
|
|
+ also to minimise the read-modify-write activity (which generally
|
|
+ indicates a lack of clarity in the use model).
|
|
+
|
|
+ Registers which are programmed in this module are listed below
|
|
+ together with the method of access. Care must be taken to ensure
|
|
+ remain adequate if the register spec changes.
|
|
+
|
|
+ All 128bits programmed
|
|
+ FALCON_BUFFER_TBL_HALF
|
|
+ RX_FILTER_TBL
|
|
+ TX_DESC_PTR_TBL
|
|
+ RX_DESC_PTR_TBL
|
|
+ DRV_EV_REG
|
|
+
|
|
+ All 64bits programmed
|
|
+ FALCON_BUFFER_TBL_FULL
|
|
+
|
|
+ 32 bits are programmed (UNLOCKED)
|
|
+ EVQ_RPTR_REG
|
|
+
|
|
+ Low 64bits programmed remainder are written with a random number
|
|
+ RX_DC_CFG_REG
|
|
+ TX_DC_CFG_REG
|
|
+ SRM_RX_DC_CFG_REG
|
|
+ SRM_TX_DC_CFG_REG
|
|
+ BUF_TBL_CFG_REG
|
|
+ BUF_TBL_UPD_REG
|
|
+ SRM_UPD_EVQ_REG
|
|
+ EVQ_PTR_TBL
|
|
+ TIMER_CMD_REG
|
|
+ TX_PACE_TBL
|
|
+ FATAL_INTR_REG
|
|
+ INT_EN_REG (When enabling interrupts)
|
|
+ TX_FLUSH_DESCQ_REG
|
|
+ RX_FLUSH_DESCQ
|
|
+
|
|
+ Read Modify Write on low 32bits remainder are written with a random number
|
|
+ INT_EN_REG (When sending a driver interrupt)
|
|
+ DRIVER_REGX
|
|
+
|
|
+ Read Modify Write on low 64bits remainder are written with a random number
|
|
+ SRM_CFG_REG_OFST
|
|
+ RX_CFG_REG_OFST
|
|
+ RX_FILTER_CTL_REG
|
|
+
|
|
+ Read Modify Write on full 128bits
|
|
+ TXDP_RESERVED_REG (aka TXDP_UNDOCUMENTED)
|
|
+ TX_CFG_REG
|
|
+
|
|
+*/
|
|
+
|
|
+
|
|
+/*----------------------------------------------------------------------------
|
|
+ *
|
|
+ * DMAQ low-level register interface
|
|
+ *
|
|
+ *---------------------------------------------------------------------------*/
|
|
+
|
|
+static unsigned dmaq_sizes[] = {
|
|
+ 512,
|
|
+ EFHW_1K,
|
|
+ EFHW_2K,
|
|
+ EFHW_4K,
|
|
+};
|
|
+
|
|
+#define N_DMAQ_SIZES (sizeof(dmaq_sizes) / sizeof(dmaq_sizes[0]))
|
|
+
|
|
+static inline ulong falcon_dma_tx_q_offset(struct efhw_nic *nic, unsigned dmaq)
|
|
+{
|
|
+ EFHW_ASSERT(dmaq < nic->num_dmaqs);
|
|
+ return TX_DESC_PTR_TBL_OFST + dmaq * FALCON_REGISTER128;
|
|
+}
|
|
+
|
|
+static inline uint falcon_dma_tx_q_size_index(uint dmaq_size)
|
|
+{
|
|
+ uint i;
|
|
+
|
|
+ /* size must be one of the various options, otherwise we assert */
|
|
+ for (i = 0; i < N_DMAQ_SIZES; i++) {
|
|
+ if (dmaq_size == dmaq_sizes[i])
|
|
+ break;
|
|
+ }
|
|
+ EFHW_ASSERT(i < N_DMAQ_SIZES);
|
|
+ return i;
|
|
+}
|
|
+
|
|
+static void
|
|
+falcon_dmaq_tx_q_init(struct efhw_nic *nic,
|
|
+ uint dmaq, uint evq_id, uint own_id,
|
|
+ uint tag, uint dmaq_size, uint buf_idx, uint flags)
|
|
+{
|
|
+ FALCON_LOCK_DECL;
|
|
+ uint index, desc_type;
|
|
+ uint64_t val1, val2, val3;
|
|
+ ulong offset;
|
|
+ volatile char __iomem *efhw_kva = EFHW_KVA(nic);
|
|
+
|
|
+ /* Q attributes */
|
|
+ int iscsi_hdig_en = ((flags & EFHW_VI_ISCSI_TX_HDIG_EN) != 0);
|
|
+ int iscsi_ddig_en = ((flags & EFHW_VI_ISCSI_TX_DDIG_EN) != 0);
|
|
+ int csum_ip_dis = ((flags & EFHW_VI_TX_IP_CSUM_DIS) != 0);
|
|
+ int csum_tcp_dis = ((flags & EFHW_VI_TX_TCPUDP_CSUM_DIS) != 0);
|
|
+ int non_ip_drop_dis = ((flags & EFHW_VI_TX_TCPUDP_ONLY) == 0);
|
|
+
|
|
+ /* initialise the TX descriptor queue pointer table */
|
|
+
|
|
+ /* NB physical vs buffer addressing is determined by the Queue ID. */
|
|
+
|
|
+ offset = falcon_dma_tx_q_offset(nic, dmaq);
|
|
+ index = falcon_dma_tx_q_size_index(dmaq_size);
|
|
+
|
|
+ /* allow VI flag to override this queue's descriptor type */
|
|
+ desc_type = (flags & EFHW_VI_TX_PHYS_ADDR_EN) ? 0 : 1;
|
|
+
|
|
+ /* bug9403: It is dangerous to allow buffer-addressed queues to
|
|
+ * have owner_id=0. */
|
|
+ EFHW_ASSERT((own_id > 0) || desc_type == 0);
|
|
+
|
|
+ /* dword 1 */
|
|
+ __DWCHCK(TX_DESCQ_FLUSH_LBN, TX_DESCQ_FLUSH_WIDTH);
|
|
+ __DWCHCK(TX_DESCQ_TYPE_LBN, TX_DESCQ_TYPE_WIDTH);
|
|
+ __DWCHCK(TX_DESCQ_SIZE_LBN, TX_DESCQ_SIZE_WIDTH);
|
|
+ __DWCHCK(TX_DESCQ_LABEL_LBN, TX_DESCQ_LABEL_WIDTH);
|
|
+ __DWCHCK(TX_DESCQ_OWNER_ID_LBN, TX_DESCQ_OWNER_ID_WIDTH);
|
|
+
|
|
+ __LWCHK(TX_DESCQ_EVQ_ID_LBN, TX_DESCQ_EVQ_ID_WIDTH);
|
|
+
|
|
+ __RANGECHCK(1, TX_DESCQ_FLUSH_WIDTH);
|
|
+ __RANGECHCK(desc_type, TX_DESCQ_TYPE_WIDTH);
|
|
+ __RANGECHCK(index, TX_DESCQ_SIZE_WIDTH);
|
|
+ __RANGECHCK(tag, TX_DESCQ_LABEL_WIDTH);
|
|
+ __RANGECHCK(own_id, TX_DESCQ_OWNER_ID_WIDTH);
|
|
+ __RANGECHCK(evq_id, TX_DESCQ_EVQ_ID_WIDTH);
|
|
+
|
|
+ val1 = ((desc_type << TX_DESCQ_TYPE_LBN) |
|
|
+ (index << TX_DESCQ_SIZE_LBN) |
|
|
+ (tag << TX_DESCQ_LABEL_LBN) |
|
|
+ (own_id << TX_DESCQ_OWNER_ID_LBN) |
|
|
+ (__LOW(evq_id, TX_DESCQ_EVQ_ID_LBN, TX_DESCQ_EVQ_ID_WIDTH)));
|
|
+
|
|
+ /* dword 2 */
|
|
+ __DW2CHCK(TX_DESCQ_BUF_BASE_ID_LBN, TX_DESCQ_BUF_BASE_ID_WIDTH);
|
|
+ __RANGECHCK(buf_idx, TX_DESCQ_BUF_BASE_ID_WIDTH);
|
|
+
|
|
+ val2 = ((__HIGH(evq_id, TX_DESCQ_EVQ_ID_LBN, TX_DESCQ_EVQ_ID_WIDTH)) |
|
|
+ (buf_idx << __DW2(TX_DESCQ_BUF_BASE_ID_LBN)));
|
|
+
|
|
+ /* dword 3 */
|
|
+ __DW3CHCK(TX_ISCSI_HDIG_EN_LBN, TX_ISCSI_HDIG_EN_WIDTH);
|
|
+ __DW3CHCK(TX_ISCSI_DDIG_EN_LBN, TX_ISCSI_DDIG_EN_WIDTH);
|
|
+ __RANGECHCK(iscsi_hdig_en, TX_ISCSI_HDIG_EN_WIDTH);
|
|
+ __RANGECHCK(iscsi_ddig_en, TX_ISCSI_DDIG_EN_WIDTH);
|
|
+
|
|
+ val3 = ((iscsi_hdig_en << __DW3(TX_ISCSI_HDIG_EN_LBN)) |
|
|
+ (iscsi_ddig_en << __DW3(TX_ISCSI_DDIG_EN_LBN)) |
|
|
+ (1 << __DW3(TX_DESCQ_EN_LBN))); /* queue enable bit */
|
|
+
|
|
+ switch (nic->devtype.variant) {
|
|
+ case 'B':
|
|
+ __DW3CHCK(TX_NON_IP_DROP_DIS_B0_LBN,
|
|
+ TX_NON_IP_DROP_DIS_B0_WIDTH);
|
|
+ __DW3CHCK(TX_IP_CHKSM_DIS_B0_LBN, TX_IP_CHKSM_DIS_B0_WIDTH);
|
|
+ __DW3CHCK(TX_TCP_CHKSM_DIS_B0_LBN, TX_TCP_CHKSM_DIS_B0_WIDTH);
|
|
+
|
|
+ val3 |= ((non_ip_drop_dis << __DW3(TX_NON_IP_DROP_DIS_B0_LBN))|
|
|
+ (csum_ip_dis << __DW3(TX_IP_CHKSM_DIS_B0_LBN)) |
|
|
+ (csum_tcp_dis << __DW3(TX_TCP_CHKSM_DIS_B0_LBN)));
|
|
+ break;
|
|
+ case 'A':
|
|
+ if (csum_ip_dis || csum_tcp_dis || !non_ip_drop_dis)
|
|
+ EFHW_WARN
|
|
+ ("%s: bad settings for A1 csum_ip_dis=%d "
|
|
+ "csum_tcp_dis=%d non_ip_drop_dis=%d",
|
|
+ __func__, csum_ip_dis,
|
|
+ csum_tcp_dis, non_ip_drop_dis);
|
|
+ break;
|
|
+ default:
|
|
+ EFHW_ASSERT(0);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ EFHW_TRACE("%s: txq %x evq %u tag %x id %x buf %x "
|
|
+ "%x:%x:%x->%" PRIx64 ":%" PRIx64 ":%" PRIx64,
|
|
+ __func__,
|
|
+ dmaq, evq_id, tag, own_id, buf_idx, dmaq_size,
|
|
+ iscsi_hdig_en, iscsi_ddig_en, val1, val2, val3);
|
|
+
|
|
+ /* Falcon requires 128 bit atomic access for this register */
|
|
+ FALCON_LOCK_LOCK(nic);
|
|
+ falcon_write_qq(efhw_kva + offset, ((val2 << 32) | val1), val3);
|
|
+ mmiowb();
|
|
+ FALCON_LOCK_UNLOCK(nic);
|
|
+ return;
|
|
+}
|
|
+
|
|
+static inline ulong
|
|
+falcon_dma_rx_q_offset(struct efhw_nic *nic, unsigned dmaq)
|
|
+{
|
|
+ EFHW_ASSERT(dmaq < nic->num_dmaqs);
|
|
+ return RX_DESC_PTR_TBL_OFST + dmaq * FALCON_REGISTER128;
|
|
+}
|
|
+
|
|
+static void
|
|
+falcon_dmaq_rx_q_init(struct efhw_nic *nic,
|
|
+ uint dmaq, uint evq_id, uint own_id,
|
|
+ uint tag, uint dmaq_size, uint buf_idx, uint flags)
|
|
+{
|
|
+ FALCON_LOCK_DECL;
|
|
+ uint i, desc_type = 1;
|
|
+ uint64_t val1, val2, val3;
|
|
+ ulong offset;
|
|
+ volatile char __iomem *efhw_kva = EFHW_KVA(nic);
|
|
+
|
|
+ /* Q attributes */
|
|
+#if BUG5762_WORKAROUND
|
|
+ int jumbo = 1; /* Queues must not have mixed types */
|
|
+#else
|
|
+ int jumbo = ((flags & EFHW_VI_JUMBO_EN) != 0);
|
|
+#endif
|
|
+ int iscsi_hdig_en = ((flags & EFHW_VI_ISCSI_RX_HDIG_EN) != 0);
|
|
+ int iscsi_ddig_en = ((flags & EFHW_VI_ISCSI_RX_DDIG_EN) != 0);
|
|
+
|
|
+ /* initialise the TX descriptor queue pointer table */
|
|
+ offset = falcon_dma_rx_q_offset(nic, dmaq);
|
|
+
|
|
+ /* size must be one of the various options, otherwise we assert */
|
|
+ for (i = 0; i < N_DMAQ_SIZES; i++) {
|
|
+ if (dmaq_size == dmaq_sizes[i])
|
|
+ break;
|
|
+ }
|
|
+ EFHW_ASSERT(i < N_DMAQ_SIZES);
|
|
+
|
|
+ /* allow VI flag to override this queue's descriptor type */
|
|
+ desc_type = (flags & EFHW_VI_RX_PHYS_ADDR_EN) ? 0 : 1;
|
|
+
|
|
+ /* bug9403: It is dangerous to allow buffer-addressed queues to have
|
|
+ * owner_id=0 */
|
|
+ EFHW_ASSERT((own_id > 0) || desc_type == 0);
|
|
+
|
|
+ /* dword 1 */
|
|
+ __DWCHCK(RX_DESCQ_EN_LBN, RX_DESCQ_EN_WIDTH);
|
|
+ __DWCHCK(RX_DESCQ_JUMBO_LBN, RX_DESCQ_JUMBO_WIDTH);
|
|
+ __DWCHCK(RX_DESCQ_TYPE_LBN, RX_DESCQ_TYPE_WIDTH);
|
|
+ __DWCHCK(RX_DESCQ_SIZE_LBN, RX_DESCQ_SIZE_WIDTH);
|
|
+ __DWCHCK(RX_DESCQ_LABEL_LBN, RX_DESCQ_LABEL_WIDTH);
|
|
+ __DWCHCK(RX_DESCQ_OWNER_ID_LBN, RX_DESCQ_OWNER_ID_WIDTH);
|
|
+
|
|
+ __LWCHK(RX_DESCQ_EVQ_ID_LBN, RX_DESCQ_EVQ_ID_WIDTH);
|
|
+
|
|
+ __RANGECHCK(1, RX_DESCQ_EN_WIDTH);
|
|
+ __RANGECHCK(jumbo, RX_DESCQ_JUMBO_WIDTH);
|
|
+ __RANGECHCK(desc_type, RX_DESCQ_TYPE_WIDTH);
|
|
+ __RANGECHCK(i, RX_DESCQ_SIZE_WIDTH);
|
|
+ __RANGECHCK(tag, RX_DESCQ_LABEL_WIDTH);
|
|
+ __RANGECHCK(own_id, RX_DESCQ_OWNER_ID_WIDTH);
|
|
+ __RANGECHCK(evq_id, RX_DESCQ_EVQ_ID_WIDTH);
|
|
+
|
|
+ val1 = ((1 << RX_DESCQ_EN_LBN) |
|
|
+ (jumbo << RX_DESCQ_JUMBO_LBN) |
|
|
+ (desc_type << RX_DESCQ_TYPE_LBN) |
|
|
+ (i << RX_DESCQ_SIZE_LBN) |
|
|
+ (tag << RX_DESCQ_LABEL_LBN) |
|
|
+ (own_id << RX_DESCQ_OWNER_ID_LBN) |
|
|
+ (__LOW(evq_id, RX_DESCQ_EVQ_ID_LBN, RX_DESCQ_EVQ_ID_WIDTH)));
|
|
+
|
|
+ /* dword 2 */
|
|
+ __DW2CHCK(RX_DESCQ_BUF_BASE_ID_LBN, RX_DESCQ_BUF_BASE_ID_WIDTH);
|
|
+ __RANGECHCK(buf_idx, RX_DESCQ_BUF_BASE_ID_WIDTH);
|
|
+
|
|
+ val2 = ((__HIGH(evq_id, RX_DESCQ_EVQ_ID_LBN, RX_DESCQ_EVQ_ID_WIDTH)) |
|
|
+ (buf_idx << __DW2(RX_DESCQ_BUF_BASE_ID_LBN)));
|
|
+
|
|
+ /* dword 3 */
|
|
+ __DW3CHCK(RX_ISCSI_HDIG_EN_LBN, RX_ISCSI_HDIG_EN_WIDTH);
|
|
+ __DW3CHCK(RX_ISCSI_DDIG_EN_LBN, RX_ISCSI_DDIG_EN_WIDTH);
|
|
+ __RANGECHCK(iscsi_hdig_en, RX_ISCSI_HDIG_EN_WIDTH);
|
|
+ __RANGECHCK(iscsi_ddig_en, RX_ISCSI_DDIG_EN_WIDTH);
|
|
+
|
|
+ val3 = (iscsi_hdig_en << __DW3(RX_ISCSI_HDIG_EN_LBN)) |
|
|
+ (iscsi_ddig_en << __DW3(RX_ISCSI_DDIG_EN_LBN));
|
|
+
|
|
+ EFHW_TRACE("%s: rxq %x evq %u tag %x id %x buf %x %s "
|
|
+ "%x:%x:%x -> %" PRIx64 ":%" PRIx64 ":%" PRIx64,
|
|
+ __func__,
|
|
+ dmaq, evq_id, tag, own_id, buf_idx,
|
|
+ jumbo ? "jumbo" : "normal", dmaq_size,
|
|
+ iscsi_hdig_en, iscsi_ddig_en, val1, val2, val3);
|
|
+
|
|
+ /* Falcon requires 128 bit atomic access for this register */
|
|
+ FALCON_LOCK_LOCK(nic);
|
|
+ falcon_write_qq(efhw_kva + offset, ((val2 << 32) | val1), val3);
|
|
+ mmiowb();
|
|
+ FALCON_LOCK_UNLOCK(nic);
|
|
+ return;
|
|
+}
|
|
+
|
|
+static void falcon_dmaq_tx_q_disable(struct efhw_nic *nic, uint dmaq)
|
|
+{
|
|
+ FALCON_LOCK_DECL;
|
|
+ uint64_t val1, val2, val3;
|
|
+ ulong offset;
|
|
+ volatile char __iomem *efhw_kva = EFHW_KVA(nic);
|
|
+
|
|
+ /* initialise the TX descriptor queue pointer table */
|
|
+
|
|
+ offset = falcon_dma_tx_q_offset(nic, dmaq);
|
|
+
|
|
+ /* dword 1 */
|
|
+ __DWCHCK(TX_DESCQ_TYPE_LBN, TX_DESCQ_TYPE_WIDTH);
|
|
+
|
|
+ val1 = ((uint64_t) 1 << TX_DESCQ_TYPE_LBN);
|
|
+
|
|
+ /* dword 2 */
|
|
+ val2 = 0;
|
|
+
|
|
+ /* dword 3 */
|
|
+ val3 = (0 << __DW3(TX_DESCQ_EN_LBN)); /* queue enable bit */
|
|
+
|
|
+ EFHW_TRACE("%s: %x->%" PRIx64 ":%" PRIx64 ":%" PRIx64,
|
|
+ __func__, dmaq, val1, val2, val3);
|
|
+
|
|
+ /* Falcon requires 128 bit atomic access for this register */
|
|
+ FALCON_LOCK_LOCK(nic);
|
|
+ falcon_write_qq(efhw_kva + offset, ((val2 << 32) | val1), val3);
|
|
+ mmiowb();
|
|
+ FALCON_LOCK_UNLOCK(nic);
|
|
+ return;
|
|
+}
|
|
+
|
|
+static void falcon_dmaq_rx_q_disable(struct efhw_nic *nic, uint dmaq)
|
|
+{
|
|
+ FALCON_LOCK_DECL;
|
|
+ uint64_t val1, val2, val3;
|
|
+ ulong offset;
|
|
+ volatile char __iomem *efhw_kva = EFHW_KVA(nic);
|
|
+
|
|
+ /* initialise the TX descriptor queue pointer table */
|
|
+ offset = falcon_dma_rx_q_offset(nic, dmaq);
|
|
+
|
|
+ /* dword 1 */
|
|
+ __DWCHCK(RX_DESCQ_EN_LBN, RX_DESCQ_EN_WIDTH);
|
|
+ __DWCHCK(RX_DESCQ_TYPE_LBN, RX_DESCQ_TYPE_WIDTH);
|
|
+
|
|
+ val1 = ((0 << RX_DESCQ_EN_LBN) | (1 << RX_DESCQ_TYPE_LBN));
|
|
+
|
|
+ /* dword 2 */
|
|
+ val2 = 0;
|
|
+
|
|
+ /* dword 3 */
|
|
+ val3 = 0;
|
|
+
|
|
+ EFHW_TRACE("falcon_dmaq_rx_q_disable: %x->%"
|
|
+ PRIx64 ":%" PRIx64 ":%" PRIx64,
|
|
+ dmaq, val1, val2, val3);
|
|
+
|
|
+ /* Falcon requires 128 bit atomic access for this register */
|
|
+ FALCON_LOCK_LOCK(nic);
|
|
+ falcon_write_qq(efhw_kva + offset, ((val2 << 32) | val1), val3);
|
|
+ mmiowb();
|
|
+ FALCON_LOCK_UNLOCK(nic);
|
|
+ return;
|
|
+}
|
|
+
|
|
+
|
|
+/*----------------------------------------------------------------------------
|
|
+ *
|
|
+ * Buffer Table low-level register interface
|
|
+ *
|
|
+ *---------------------------------------------------------------------------*/
|
|
+
|
|
+/*! Convert a (potentially) 64-bit physical address to 32-bits. Every use
|
|
+** of this function is a place where we're not 64-bit clean.
|
|
+*/
|
|
+static inline uint32_t dma_addr_to_u32(dma_addr_t addr)
|
|
+{
|
|
+ /* Top bits had better be zero! */
|
|
+ EFHW_ASSERT(addr == (addr & 0xffffffff));
|
|
+ return (uint32_t) addr;
|
|
+}
|
|
+
|
|
+static inline uint32_t
|
|
+falcon_nic_buffer_table_entry32_mk(dma_addr_t dma_addr, int own_id)
|
|
+{
|
|
+ uint32_t dma_addr32 = FALCON_BUFFER_4K_PAGE(dma_addr_to_u32(dma_addr));
|
|
+
|
|
+ /* don't do this to me */
|
|
+ EFHW_BUILD_ASSERT(BUF_ADR_HBUF_ODD_LBN == BUF_ADR_HBUF_EVEN_LBN + 32);
|
|
+ EFHW_BUILD_ASSERT(BUF_OWNER_ID_HBUF_ODD_LBN ==
|
|
+ BUF_OWNER_ID_HBUF_EVEN_LBN + 32);
|
|
+
|
|
+ EFHW_BUILD_ASSERT(BUF_OWNER_ID_HBUF_ODD_WIDTH ==
|
|
+ BUF_OWNER_ID_HBUF_EVEN_WIDTH);
|
|
+ EFHW_BUILD_ASSERT(BUF_ADR_HBUF_ODD_WIDTH == BUF_ADR_HBUF_EVEN_WIDTH);
|
|
+
|
|
+ __DWCHCK(BUF_ADR_HBUF_EVEN_LBN, BUF_ADR_HBUF_EVEN_WIDTH);
|
|
+ __DWCHCK(BUF_OWNER_ID_HBUF_EVEN_LBN, BUF_OWNER_ID_HBUF_EVEN_WIDTH);
|
|
+
|
|
+ __RANGECHCK(dma_addr32, BUF_ADR_HBUF_EVEN_WIDTH);
|
|
+ __RANGECHCK(own_id, BUF_OWNER_ID_HBUF_EVEN_WIDTH);
|
|
+
|
|
+ return (dma_addr32 << BUF_ADR_HBUF_EVEN_LBN) |
|
|
+ (own_id << BUF_OWNER_ID_HBUF_EVEN_LBN);
|
|
+}
|
|
+
|
|
+static inline uint64_t
|
|
+falcon_nic_buffer_table_entry64_mk(dma_addr_t dma_addr,
|
|
+ int bufsz, /* bytes */
|
|
+ int region, int own_id)
|
|
+{
|
|
+ __DW2CHCK(IP_DAT_BUF_SIZE_LBN, IP_DAT_BUF_SIZE_WIDTH);
|
|
+ __DW2CHCK(BUF_ADR_REGION_LBN, BUF_ADR_REGION_WIDTH);
|
|
+ __LWCHK(BUF_ADR_FBUF_LBN, BUF_ADR_FBUF_WIDTH);
|
|
+ __DWCHCK(BUF_OWNER_ID_FBUF_LBN, BUF_OWNER_ID_FBUF_WIDTH);
|
|
+
|
|
+ EFHW_ASSERT((bufsz == EFHW_4K) || (bufsz == EFHW_8K));
|
|
+
|
|
+ dma_addr = (dma_addr >> 12) & __FALCON_MASK64(BUF_ADR_FBUF_WIDTH);
|
|
+
|
|
+ __RANGECHCK(dma_addr, BUF_ADR_FBUF_WIDTH);
|
|
+ __RANGECHCK(1, IP_DAT_BUF_SIZE_WIDTH);
|
|
+ __RANGECHCK(region, BUF_ADR_REGION_WIDTH);
|
|
+ __RANGECHCK(own_id, BUF_OWNER_ID_FBUF_WIDTH);
|
|
+
|
|
+ return ((uint64_t) (bufsz == EFHW_8K) << IP_DAT_BUF_SIZE_LBN) |
|
|
+ ((uint64_t) region << BUF_ADR_REGION_LBN) |
|
|
+ ((uint64_t) dma_addr << BUF_ADR_FBUF_LBN) |
|
|
+ ((uint64_t) own_id << BUF_OWNER_ID_FBUF_LBN);
|
|
+}
|
|
+
|
|
+static inline void
|
|
+_falcon_nic_buffer_table_set32(struct efhw_nic *nic,
|
|
+ dma_addr_t dma_addr, uint bufsz,
|
|
+ uint region, /* not used */
|
|
+ int own_id, int buffer_id)
|
|
+{
|
|
+ /* programming the half table needs to be done in pairs. */
|
|
+ uint64_t entry, val, shift;
|
|
+ volatile char __iomem *efhw_kva = EFHW_KVA(nic);
|
|
+ volatile char __iomem *offset;
|
|
+
|
|
+ EFHW_BUILD_ASSERT(BUF_ADR_HBUF_ODD_LBN == BUF_ADR_HBUF_EVEN_LBN + 32);
|
|
+ EFHW_BUILD_ASSERT(BUF_OWNER_ID_HBUF_ODD_LBN ==
|
|
+ BUF_OWNER_ID_HBUF_EVEN_LBN + 32);
|
|
+
|
|
+ shift = (buffer_id & 1) ? 32 : 0;
|
|
+
|
|
+ offset = (efhw_kva + BUF_HALF_TBL_OFST +
|
|
+ ((buffer_id & ~1) * FALCON_BUFFER_TBL_HALF_BYTES));
|
|
+
|
|
+ entry = falcon_nic_buffer_table_entry32_mk(dma_addr_to_u32(dma_addr),
|
|
+ own_id);
|
|
+
|
|
+#if FALCON_USE_SHADOW_BUFFER_TABLE
|
|
+ val = _falcon_buffer_table[buffer_id & ~1];
|
|
+#else
|
|
+ /* This will not work unless we've completed
|
|
+ * the buffer table updates */
|
|
+ falcon_read_q(offset, &val);
|
|
+#endif
|
|
+ val &= ~(((uint64_t) 0xffffffff) << shift);
|
|
+ val |= (entry << shift);
|
|
+
|
|
+ EFHW_TRACE("%s[%x]: %lx:%x:%" PRIx64 "->%x = %"
|
|
+ PRIx64, __func__, buffer_id, (unsigned long) dma_addr,
|
|
+ own_id, entry, (unsigned)(offset - efhw_kva), val);
|
|
+
|
|
+ /* Falcon requires that access to this register is serialised */
|
|
+ falcon_write_q(offset, val);
|
|
+
|
|
+ /* NB. No mmiowb(). Caller should do that e.g by calling commit */
|
|
+
|
|
+#if FALCON_USE_SHADOW_BUFFER_TABLE
|
|
+ _falcon_buffer_table[buffer_id & ~1] = val;
|
|
+#endif
|
|
+
|
|
+ /* Confirm the entry if the event queues haven't been set up. */
|
|
+ if (!nic->irq_handler) {
|
|
+ uint64_t new_val;
|
|
+ int count = 0;
|
|
+ while (1) {
|
|
+ mmiowb();
|
|
+ falcon_read_q(offset, &new_val);
|
|
+ if (new_val == val)
|
|
+ break;
|
|
+ count++;
|
|
+ if (count > 1000) {
|
|
+ EFHW_WARN("%s: poll Timeout", __func__);
|
|
+ break;
|
|
+ }
|
|
+ udelay(1);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static inline void
|
|
+_falcon_nic_buffer_table_set64(struct efhw_nic *nic,
|
|
+ dma_addr_t dma_addr, uint bufsz,
|
|
+ uint region, int own_id, int buffer_id)
|
|
+{
|
|
+ volatile char __iomem *offset;
|
|
+ uint64_t entry;
|
|
+ volatile char __iomem *efhw_kva = EFHW_KVA(nic);
|
|
+
|
|
+ EFHW_ASSERT(region < FALCON_REGION_NUM);
|
|
+
|
|
+ EFHW_ASSERT((bufsz == EFHW_4K) ||
|
|
+ (bufsz == EFHW_8K && FALCON_BUFFER_TABLE_FULL_MODE));
|
|
+
|
|
+ offset = (efhw_kva + BUF_FULL_TBL_OFST +
|
|
+ (buffer_id * FALCON_BUFFER_TBL_FULL_BYTES));
|
|
+
|
|
+ entry = falcon_nic_buffer_table_entry64_mk(dma_addr, bufsz, region,
|
|
+ own_id);
|
|
+
|
|
+ EFHW_TRACE("%s[%x]: %lx:bufsz=%x:region=%x:ownid=%x",
|
|
+ __func__, buffer_id, (unsigned long) dma_addr, bufsz,
|
|
+ region, own_id);
|
|
+
|
|
+ EFHW_TRACE("%s: BUF[%x]:NIC[%x]->%" PRIx64,
|
|
+ __func__, buffer_id,
|
|
+ (unsigned int)(offset - efhw_kva), entry);
|
|
+
|
|
+ /* Falcon requires that access to this register is serialised */
|
|
+ falcon_write_q(offset, entry);
|
|
+
|
|
+ /* NB. No mmiowb(). Caller should do that e.g by calling commit */
|
|
+
|
|
+ /* Confirm the entry if the event queues haven't been set up. */
|
|
+ if (!nic->irq_handler) {
|
|
+ uint64_t new_entry;
|
|
+ int count = 0;
|
|
+ while (1) {
|
|
+ mmiowb();
|
|
+ falcon_read_q(offset, &new_entry);
|
|
+ if (new_entry == entry)
|
|
+ return;
|
|
+ count++;
|
|
+ if (count > 1000) {
|
|
+ EFHW_WARN("%s: poll Timeout waiting for "
|
|
+ "value %"PRIx64
|
|
+ " (last was %"PRIx64")",
|
|
+ __func__, entry, new_entry);
|
|
+ break;
|
|
+ }
|
|
+ udelay(1);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+#if FALCON_BUFFER_TABLE_FULL_MODE
|
|
+#define _falcon_nic_buffer_table_set _falcon_nic_buffer_table_set64
|
|
+#else
|
|
+#define _falcon_nic_buffer_table_set _falcon_nic_buffer_table_set32
|
|
+#endif
|
|
+
|
|
+static inline void _falcon_nic_buffer_table_commit(struct efhw_nic *nic)
|
|
+{
|
|
+ /* MUST be called holding the FALCON_LOCK */
|
|
+ volatile char __iomem *efhw_kva = EFHW_KVA(nic);
|
|
+ uint64_t cmd;
|
|
+
|
|
+ EFHW_BUILD_ASSERT(BUF_TBL_UPD_REG_KER_OFST == BUF_TBL_UPD_REG_OFST);
|
|
+
|
|
+ __DW2CHCK(BUF_UPD_CMD_LBN, BUF_UPD_CMD_WIDTH);
|
|
+ __RANGECHCK(1, BUF_UPD_CMD_WIDTH);
|
|
+
|
|
+ cmd = ((uint64_t) 1 << BUF_UPD_CMD_LBN);
|
|
+
|
|
+ /* Falcon requires 128 bit atomic access for this register */
|
|
+ falcon_write_qq(efhw_kva + BUF_TBL_UPD_REG_OFST,
|
|
+ cmd, FALCON_ATOMIC_UPD_REG);
|
|
+ mmiowb();
|
|
+
|
|
+ nic->buf_commit_outstanding++;
|
|
+ EFHW_TRACE("COMMIT REQ out=%d", nic->buf_commit_outstanding);
|
|
+}
|
|
+
|
|
+static void falcon_nic_buffer_table_commit(struct efhw_nic *nic)
|
|
+{
|
|
+ /* nothing to do */
|
|
+}
|
|
+
|
|
+static inline void
|
|
+_falcon_nic_buffer_table_clear(struct efhw_nic *nic, int buffer_id, int num)
|
|
+{
|
|
+ uint64_t cmd;
|
|
+ uint64_t start_id = buffer_id;
|
|
+ uint64_t end_id = buffer_id + num - 1;
|
|
+ volatile char __iomem *efhw_kva = EFHW_KVA(nic);
|
|
+
|
|
+ volatile char __iomem *offset = (efhw_kva + BUF_TBL_UPD_REG_OFST);
|
|
+
|
|
+ EFHW_BUILD_ASSERT(BUF_TBL_UPD_REG_KER_OFST == BUF_TBL_UPD_REG_OFST);
|
|
+
|
|
+#if !FALCON_BUFFER_TABLE_FULL_MODE
|
|
+ /* buffer_ids in half buffer mode reference pairs of buffers */
|
|
+ EFHW_ASSERT(buffer_id % 1 == 0);
|
|
+ EFHW_ASSERT(num % 1 == 0);
|
|
+ start_id = start_id >> 1;
|
|
+ end_id = end_id >> 1;
|
|
+#endif
|
|
+
|
|
+ EFHW_ASSERT(num >= 1);
|
|
+
|
|
+ __DWCHCK(BUF_CLR_START_ID_LBN, BUF_CLR_START_ID_WIDTH);
|
|
+ __DW2CHCK(BUF_CLR_END_ID_LBN, BUF_CLR_END_ID_WIDTH);
|
|
+
|
|
+ __DW2CHCK(BUF_CLR_CMD_LBN, BUF_CLR_CMD_WIDTH);
|
|
+ __RANGECHCK(1, BUF_CLR_CMD_WIDTH);
|
|
+
|
|
+ __RANGECHCK(start_id, BUF_CLR_START_ID_WIDTH);
|
|
+ __RANGECHCK(end_id, BUF_CLR_END_ID_WIDTH);
|
|
+
|
|
+ cmd = (((uint64_t) 1 << BUF_CLR_CMD_LBN) |
|
|
+ (start_id << BUF_CLR_START_ID_LBN) |
|
|
+ (end_id << BUF_CLR_END_ID_LBN));
|
|
+
|
|
+ /* Falcon requires 128 bit atomic access for this register */
|
|
+ falcon_write_qq(offset, cmd, FALCON_ATOMIC_UPD_REG);
|
|
+ mmiowb();
|
|
+
|
|
+ nic->buf_commit_outstanding++;
|
|
+ EFHW_TRACE("COMMIT CLEAR out=%d", nic->buf_commit_outstanding);
|
|
+}
|
|
+
|
|
+/*----------------------------------------------------------------------------
|
|
+ *
|
|
+ * Events low-level register interface
|
|
+ *
|
|
+ *---------------------------------------------------------------------------*/
|
|
+
|
|
+static unsigned eventq_sizes[] = {
|
|
+ 512,
|
|
+ EFHW_1K,
|
|
+ EFHW_2K,
|
|
+ EFHW_4K,
|
|
+ EFHW_8K,
|
|
+ EFHW_16K,
|
|
+ EFHW_32K
|
|
+};
|
|
+
|
|
+#define N_EVENTQ_SIZES (sizeof(eventq_sizes) / sizeof(eventq_sizes[0]))
|
|
+
|
|
+static inline void falcon_nic_srm_upd_evq(struct efhw_nic *nic, int evq)
|
|
+{
|
|
+ /* set up the eventq which will receive events from the SRAM module.
|
|
+ * i.e buffer table updates and clears, TX and RX aperture table
|
|
+ * updates */
|
|
+
|
|
+ FALCON_LOCK_DECL;
|
|
+ volatile char __iomem *efhw_kva = EFHW_KVA(nic);
|
|
+
|
|
+ EFHW_BUILD_ASSERT(SRM_UPD_EVQ_REG_OFST == SRM_UPD_EVQ_REG_KER_OFST);
|
|
+
|
|
+ __DWCHCK(SRM_UPD_EVQ_ID_LBN, SRM_UPD_EVQ_ID_WIDTH);
|
|
+ __RANGECHCK(evq, SRM_UPD_EVQ_ID_WIDTH);
|
|
+
|
|
+ /* Falcon requires 128 bit atomic access for this register */
|
|
+ FALCON_LOCK_LOCK(nic);
|
|
+ falcon_write_qq(efhw_kva + SRM_UPD_EVQ_REG_OFST,
|
|
+ ((uint64_t) evq << SRM_UPD_EVQ_ID_LBN),
|
|
+ FALCON_ATOMIC_SRPM_UDP_EVQ_REG);
|
|
+ mmiowb();
|
|
+ FALCON_LOCK_UNLOCK(nic);
|
|
+}
|
|
+
|
|
+static void
|
|
+falcon_nic_evq_ptr_tbl(struct efhw_nic *nic,
|
|
+ uint evq, /* evq id */
|
|
+ uint enable, /* 1 to enable, 0 to disable */
|
|
+ uint buf_base_id,/* Buffer table base for EVQ */
|
|
+ uint evq_size /* Number of events */)
|
|
+{
|
|
+ FALCON_LOCK_DECL;
|
|
+ uint i, val;
|
|
+ ulong offset;
|
|
+ volatile char __iomem *efhw_kva = EFHW_KVA(nic);
|
|
+
|
|
+ /* size must be one of the various options, otherwise we assert */
|
|
+ for (i = 0; i < N_EVENTQ_SIZES; i++) {
|
|
+ if (evq_size <= eventq_sizes[i])
|
|
+ break;
|
|
+ }
|
|
+ EFHW_ASSERT(i < N_EVENTQ_SIZES);
|
|
+
|
|
+ __DWCHCK(EVQ_BUF_BASE_ID_LBN, EVQ_BUF_BASE_ID_WIDTH);
|
|
+ __DWCHCK(EVQ_SIZE_LBN, EVQ_SIZE_WIDTH);
|
|
+ __DWCHCK(EVQ_EN_LBN, EVQ_EN_WIDTH);
|
|
+
|
|
+ __RANGECHCK(i, EVQ_SIZE_WIDTH);
|
|
+ __RANGECHCK(buf_base_id, EVQ_BUF_BASE_ID_WIDTH);
|
|
+ __RANGECHCK(1, EVQ_EN_WIDTH);
|
|
+
|
|
+ /* if !enable then only evq needs to be correct, although valid
|
|
+ * values need to be passed in for other arguments to prevent
|
|
+ * assertions */
|
|
+
|
|
+ val = ((i << EVQ_SIZE_LBN) | (buf_base_id << EVQ_BUF_BASE_ID_LBN) |
|
|
+ (enable ? (1 << EVQ_EN_LBN) : 0));
|
|
+
|
|
+ EFHW_ASSERT(evq < nic->num_evqs);
|
|
+
|
|
+ offset = EVQ_PTR_TBL_CHAR_OFST;
|
|
+ offset += evq * FALCON_REGISTER128;
|
|
+
|
|
+ EFHW_TRACE("%s: evq %u en=%x:buf=%x:size=%x->%x at %lx",
|
|
+ __func__, evq, enable, buf_base_id, evq_size, val,
|
|
+ offset);
|
|
+
|
|
+ /* Falcon requires 128 bit atomic access for this register */
|
|
+ FALCON_LOCK_LOCK(nic);
|
|
+ falcon_write_qq(efhw_kva + offset, val, FALCON_ATOMIC_PTR_TBL_REG);
|
|
+ mmiowb();
|
|
+ FALCON_LOCK_UNLOCK(nic);
|
|
+
|
|
+ /* caller must wait for an update done event before writing any more
|
|
+ table entries */
|
|
+
|
|
+ return;
|
|
+}
|
|
+
|
|
+void
|
|
+falcon_nic_evq_ack(struct efhw_nic *nic,
|
|
+ uint evq, /* evq id */
|
|
+ uint rptr, /* new read pointer update */
|
|
+ bool wakeup /* request a wakeup event if ptr's != */
|
|
+ )
|
|
+{
|
|
+ uint val;
|
|
+ ulong offset;
|
|
+ volatile char __iomem *efhw_kva = EFHW_KVA(nic);
|
|
+
|
|
+ EFHW_BUILD_ASSERT(FALCON_EVQ_CHAR == 4);
|
|
+
|
|
+ __DWCHCK(EVQ_RPTR_LBN, EVQ_RPTR_WIDTH);
|
|
+ __RANGECHCK(rptr, EVQ_RPTR_WIDTH);
|
|
+
|
|
+ val = (rptr << EVQ_RPTR_LBN);
|
|
+
|
|
+ EFHW_ASSERT(evq < nic->num_evqs);
|
|
+
|
|
+ if (evq < FALCON_EVQ_CHAR) {
|
|
+ offset = EVQ_RPTR_REG_KER_OFST;
|
|
+ offset += evq * FALCON_REGISTER128;
|
|
+
|
|
+ EFHW_ASSERT(!wakeup); /* don't try this at home */
|
|
+ } else {
|
|
+ offset = EVQ_RPTR_REG_OFST + (FALCON_EVQ_CHAR *
|
|
+ FALCON_REGISTER128);
|
|
+ offset += (evq - FALCON_EVQ_CHAR) * FALCON_REGISTER128;
|
|
+
|
|
+ /* nothing to do for interruptless event queues which do
|
|
+ * not want a wakeup */
|
|
+ if (evq != FALCON_EVQ_CHAR && !wakeup)
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ EFHW_TRACE("%s: %x %x %x->%x", __func__, evq, rptr, wakeup, val);
|
|
+
|
|
+ writel(val, efhw_kva + offset);
|
|
+ mmiowb();
|
|
+}
|
|
+
|
|
+/*---------------------------------------------------------------------------*/
|
|
+
|
|
+static inline void
|
|
+falcon_drv_ev(struct efhw_nic *nic, uint64_t data, uint qid)
|
|
+{
|
|
+ FALCON_LOCK_DECL;
|
|
+ volatile char __iomem *efhw_kva = EFHW_KVA(nic);
|
|
+
|
|
+ /* send an event from one driver to the other */
|
|
+ EFHW_BUILD_ASSERT(DRV_EV_REG_KER_OFST == DRV_EV_REG_OFST);
|
|
+ EFHW_BUILD_ASSERT(DRV_EV_DATA_LBN == 0);
|
|
+ EFHW_BUILD_ASSERT(DRV_EV_DATA_WIDTH == 64);
|
|
+ EFHW_BUILD_ASSERT(DRV_EV_QID_LBN == 64);
|
|
+ EFHW_BUILD_ASSERT(DRV_EV_QID_WIDTH == 12);
|
|
+
|
|
+ FALCON_LOCK_LOCK(nic);
|
|
+ falcon_write_qq(efhw_kva + DRV_EV_REG_OFST, data, qid);
|
|
+ mmiowb();
|
|
+ FALCON_LOCK_UNLOCK(nic);
|
|
+}
|
|
+
|
|
+_DEBUG_SYM_ void
|
|
+falcon_ab_timer_tbl_set(struct efhw_nic *nic,
|
|
+ uint evq, /* timer id */
|
|
+ uint mode, /* mode bits */
|
|
+ uint countdown /* counting value to set */)
|
|
+{
|
|
+ FALCON_LOCK_DECL;
|
|
+ uint val;
|
|
+ ulong offset;
|
|
+ volatile char __iomem *efhw_kva = EFHW_KVA(nic);
|
|
+
|
|
+ EFHW_BUILD_ASSERT(TIMER_VAL_LBN == 0);
|
|
+
|
|
+ __DWCHCK(TIMER_MODE_LBN, TIMER_MODE_WIDTH);
|
|
+ __DWCHCK(TIMER_VAL_LBN, TIMER_VAL_WIDTH);
|
|
+
|
|
+ __RANGECHCK(mode, TIMER_MODE_WIDTH);
|
|
+ __RANGECHCK(countdown, TIMER_VAL_WIDTH);
|
|
+
|
|
+ val = ((mode << TIMER_MODE_LBN) | (countdown << TIMER_VAL_LBN));
|
|
+
|
|
+ if (evq < FALCON_EVQ_CHAR) {
|
|
+ offset = TIMER_CMD_REG_KER_OFST;
|
|
+ offset += evq * EFHW_8K; /* PAGE mapped register */
|
|
+ } else {
|
|
+ offset = TIMER_TBL_OFST;
|
|
+ offset += evq * FALCON_REGISTER128;
|
|
+ }
|
|
+ EFHW_ASSERT(evq < nic->num_evqs);
|
|
+
|
|
+ EFHW_TRACE("%s: evq %u mode %x (%s) time %x -> %08x",
|
|
+ __func__, evq, mode,
|
|
+ mode == 0 ? "DISABLE" :
|
|
+ mode == 1 ? "IMMED" :
|
|
+ mode == 2 ? (evq < 5 ? "HOLDOFF" : "RX_TRIG") :
|
|
+ "<BAD>", countdown, val);
|
|
+
|
|
+ /* Falcon requires 128 bit atomic access for this register when
|
|
+ * accessed from the driver. User access to timers is paged mapped
|
|
+ */
|
|
+ FALCON_LOCK_LOCK(nic);
|
|
+ falcon_write_qq(efhw_kva + offset, val, FALCON_ATOMIC_TIMER_CMD_REG);
|
|
+ mmiowb();
|
|
+ FALCON_LOCK_UNLOCK(nic);
|
|
+ return;
|
|
+}
|
|
+
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * Rate pacing - Low level interface
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+void falcon_nic_pace(struct efhw_nic *nic, uint dmaq, uint pace)
|
|
+{
|
|
+ /* Pace specified in 2^(units of microseconds). This is the minimum
|
|
+ additional delay imposed over and above the IPG.
|
|
+
|
|
+ Pacing only available on the virtual interfaces
|
|
+ */
|
|
+ FALCON_LOCK_DECL;
|
|
+ volatile char __iomem *efhw_kva = EFHW_KVA(nic);
|
|
+ ulong offset;
|
|
+
|
|
+ if (pace > 20)
|
|
+ pace = 20; /* maxm supported value */
|
|
+
|
|
+ __DWCHCK(TX_PACE_LBN, TX_PACE_WIDTH);
|
|
+ __RANGECHCK(pace, TX_PACE_WIDTH);
|
|
+
|
|
+ switch (nic->devtype.variant) {
|
|
+ case 'A':
|
|
+ EFHW_ASSERT(dmaq >= TX_PACE_TBL_FIRST_QUEUE_A1);
|
|
+ offset = TX_PACE_TBL_A1_OFST;
|
|
+ offset += (dmaq - TX_PACE_TBL_FIRST_QUEUE_A1) * 16;
|
|
+ break;
|
|
+ case 'B':
|
|
+ /* Would be nice to assert this, but as dmaq is unsigned and
|
|
+ * TX_PACE_TBL_FIRST_QUEUE_B0 is 0, it makes no sense
|
|
+ * EFHW_ASSERT(dmaq >= TX_PACE_TBL_FIRST_QUEUE_B0);
|
|
+ */
|
|
+ offset = TX_PACE_TBL_B0_OFST;
|
|
+ offset += (dmaq - TX_PACE_TBL_FIRST_QUEUE_B0) * 16;
|
|
+ break;
|
|
+ default:
|
|
+ EFHW_ASSERT(0);
|
|
+ offset = 0;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ /* Falcon requires 128 bit atomic access for this register */
|
|
+ FALCON_LOCK_LOCK(nic);
|
|
+ falcon_write_qq(efhw_kva + offset, pace, FALCON_ATOMIC_PACE_REG);
|
|
+ mmiowb();
|
|
+ FALCON_LOCK_UNLOCK(nic);
|
|
+
|
|
+ EFHW_TRACE("%s: txq %d offset=%lx pace=2^%x",
|
|
+ __func__, dmaq, offset, pace);
|
|
+}
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * Interrupt - Low level interface
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+static void falcon_nic_handle_fatal_int(struct efhw_nic *nic)
|
|
+{
|
|
+ FALCON_LOCK_DECL;
|
|
+ volatile char __iomem *offset;
|
|
+ volatile char __iomem *efhw_kva = EFHW_KVA(nic);
|
|
+ uint64_t val;
|
|
+
|
|
+ offset = (efhw_kva + FATAL_INTR_REG_OFST);
|
|
+
|
|
+ /* Falcon requires 32 bit atomic access for this register */
|
|
+ FALCON_LOCK_LOCK(nic);
|
|
+ val = readl(offset);
|
|
+ FALCON_LOCK_UNLOCK(nic);
|
|
+
|
|
+ /* ?? BUG3249 - need to disable illegal address interrupt */
|
|
+ /* ?? BUG3114 - need to backport interrupt storm protection code */
|
|
+ EFHW_ERR("fatal interrupt: %s%s%s%s%s%s%s%s%s%s%s%s[%" PRIx64 "]",
|
|
+ val & (1 << PCI_BUSERR_INT_CHAR_LBN) ? "PCI-bus-error " : "",
|
|
+ val & (1 << SRAM_OOB_INT_CHAR_LBN) ? "SRAM-oob " : "",
|
|
+ val & (1 << BUFID_OOB_INT_CHAR_LBN) ? "bufid-oob " : "",
|
|
+ val & (1 << MEM_PERR_INT_CHAR_LBN) ? "int-parity " : "",
|
|
+ val & (1 << RBUF_OWN_INT_CHAR_LBN) ? "rx-bufid-own " : "",
|
|
+ val & (1 << TBUF_OWN_INT_CHAR_LBN) ? "tx-bufid-own " : "",
|
|
+ val & (1 << RDESCQ_OWN_INT_CHAR_LBN) ? "rx-desc-own " : "",
|
|
+ val & (1 << TDESCQ_OWN_INT_CHAR_LBN) ? "tx-desc-own " : "",
|
|
+ val & (1 << EVQ_OWN_INT_CHAR_LBN) ? "evq-own " : "",
|
|
+ val & (1 << EVFF_OFLO_INT_CHAR_LBN) ? "evq-fifo " : "",
|
|
+ val & (1 << ILL_ADR_INT_CHAR_LBN) ? "ill-addr " : "",
|
|
+ val & (1 << SRM_PERR_INT_CHAR_LBN) ? "sram-parity " : "", val);
|
|
+}
|
|
+
|
|
+static void falcon_nic_interrupt_hw_enable(struct efhw_nic *nic)
|
|
+{
|
|
+ FALCON_LOCK_DECL;
|
|
+ uint val;
|
|
+ volatile char __iomem *offset;
|
|
+ volatile char __iomem *efhw_kva = EFHW_KVA(nic);
|
|
+
|
|
+ EFHW_BUILD_ASSERT(DRV_INT_EN_CHAR_WIDTH == 1);
|
|
+
|
|
+ if (nic->flags & NIC_FLAG_NO_INTERRUPT)
|
|
+ return;
|
|
+
|
|
+ offset = (efhw_kva + INT_EN_REG_CHAR_OFST);
|
|
+ val = 1 << DRV_INT_EN_CHAR_LBN;
|
|
+
|
|
+ EFHW_NOTICE("%s: %x -> %x", __func__, (int)(offset - efhw_kva),
|
|
+ val);
|
|
+
|
|
+ /* Falcon requires 128 bit atomic access for this register */
|
|
+ FALCON_LOCK_LOCK(nic);
|
|
+ falcon_write_qq(offset, val, FALCON_ATOMIC_INT_EN_REG);
|
|
+ mmiowb();
|
|
+ FALCON_LOCK_UNLOCK(nic);
|
|
+}
|
|
+
|
|
+static void falcon_nic_interrupt_hw_disable(struct efhw_nic *nic)
|
|
+{
|
|
+ FALCON_LOCK_DECL;
|
|
+ volatile char __iomem *offset;
|
|
+ volatile char __iomem *efhw_kva = EFHW_KVA(nic);
|
|
+
|
|
+ EFHW_BUILD_ASSERT(SRAM_PERR_INT_KER_WIDTH == 1);
|
|
+ EFHW_BUILD_ASSERT(DRV_INT_EN_KER_LBN == 0);
|
|
+ EFHW_BUILD_ASSERT(SRAM_PERR_INT_CHAR_WIDTH == 1);
|
|
+ EFHW_BUILD_ASSERT(DRV_INT_EN_CHAR_LBN == 0);
|
|
+ EFHW_BUILD_ASSERT(SRAM_PERR_INT_KER_LBN == SRAM_PERR_INT_CHAR_LBN);
|
|
+ EFHW_BUILD_ASSERT(DRV_INT_EN_KER_LBN == DRV_INT_EN_CHAR_LBN);
|
|
+
|
|
+ if (nic->flags & NIC_FLAG_NO_INTERRUPT)
|
|
+ return;
|
|
+
|
|
+ offset = (efhw_kva + INT_EN_REG_CHAR_OFST);
|
|
+
|
|
+ EFHW_NOTICE("%s: %x -> 0", __func__, (int)(offset - efhw_kva));
|
|
+
|
|
+ /* Falcon requires 128 bit atomic access for this register */
|
|
+ FALCON_LOCK_LOCK(nic);
|
|
+ falcon_write_qq(offset, 0, FALCON_ATOMIC_INT_EN_REG);
|
|
+ mmiowb();
|
|
+ FALCON_LOCK_UNLOCK(nic);
|
|
+}
|
|
+
|
|
+static void falcon_nic_irq_addr_set(struct efhw_nic *nic, dma_addr_t dma_addr)
|
|
+{
|
|
+ FALCON_LOCK_DECL;
|
|
+ volatile char __iomem *offset;
|
|
+ volatile char __iomem *efhw_kva = EFHW_KVA(nic);
|
|
+
|
|
+ offset = (efhw_kva + INT_ADR_REG_CHAR_OFST);
|
|
+
|
|
+ EFHW_NOTICE("%s: %x -> " DMA_ADDR_T_FMT, __func__,
|
|
+ (int)(offset - efhw_kva), dma_addr);
|
|
+
|
|
+ /* Falcon requires 128 bit atomic access for this register */
|
|
+ FALCON_LOCK_LOCK(nic);
|
|
+ falcon_write_qq(offset, dma_addr, FALCON_ATOMIC_INT_ADR_REG);
|
|
+ mmiowb();
|
|
+ FALCON_LOCK_UNLOCK(nic);
|
|
+}
|
|
+
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * RXDP - low level interface
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+void
|
|
+falcon_nic_set_rx_usr_buf_size(struct efhw_nic *nic, int usr_buf_bytes)
|
|
+{
|
|
+ FALCON_LOCK_DECL;
|
|
+ volatile char __iomem *efhw_kva = EFHW_KVA(nic);
|
|
+ uint64_t val, val2, usr_buf_size = usr_buf_bytes / 32;
|
|
+ int rubs_lbn, rubs_width, roec_lbn;
|
|
+
|
|
+ EFHW_BUILD_ASSERT(RX_CFG_REG_OFST == RX_CFG_REG_KER_OFST);
|
|
+
|
|
+ switch (nic->devtype.variant) {
|
|
+ default:
|
|
+ EFHW_ASSERT(0);
|
|
+ /* Fall-through to avoid compiler warnings. */
|
|
+ case 'A':
|
|
+ rubs_lbn = RX_USR_BUF_SIZE_A1_LBN;
|
|
+ rubs_width = RX_USR_BUF_SIZE_A1_WIDTH;
|
|
+ roec_lbn = RX_OWNERR_CTL_A1_LBN;
|
|
+ break;
|
|
+ case 'B':
|
|
+ rubs_lbn = RX_USR_BUF_SIZE_B0_LBN;
|
|
+ rubs_width = RX_USR_BUF_SIZE_B0_WIDTH;
|
|
+ roec_lbn = RX_OWNERR_CTL_B0_LBN;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ __DWCHCK(rubs_lbn, rubs_width);
|
|
+ __QWCHCK(roec_lbn, 1);
|
|
+ __RANGECHCK(usr_buf_size, rubs_width);
|
|
+
|
|
+ /* Falcon requires 128 bit atomic access for this register */
|
|
+ FALCON_LOCK_LOCK(nic);
|
|
+ falcon_read_qq(efhw_kva + RX_CFG_REG_OFST, &val, &val2);
|
|
+
|
|
+ val &= ~((__FALCON_MASK64(rubs_width)) << rubs_lbn);
|
|
+ val |= (usr_buf_size << rubs_lbn);
|
|
+
|
|
+ /* shouldn't be needed for a production driver */
|
|
+ val |= ((uint64_t) 1 << roec_lbn);
|
|
+
|
|
+ falcon_write_qq(efhw_kva + RX_CFG_REG_OFST, val, val2);
|
|
+ mmiowb();
|
|
+ FALCON_LOCK_UNLOCK(nic);
|
|
+}
|
|
+EXPORT_SYMBOL(falcon_nic_set_rx_usr_buf_size);
|
|
+
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * TXDP - low level interface
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+_DEBUG_SYM_ void falcon_nic_tx_cfg(struct efhw_nic *nic, int unlocked)
|
|
+{
|
|
+ FALCON_LOCK_DECL;
|
|
+ volatile char __iomem *efhw_kva = EFHW_KVA(nic);
|
|
+ uint64_t val1, val2;
|
|
+
|
|
+ EFHW_BUILD_ASSERT(TX_CFG_REG_OFST == TX_CFG_REG_KER_OFST);
|
|
+ __DWCHCK(TX_OWNERR_CTL_LBN, TX_OWNERR_CTL_WIDTH);
|
|
+ __DWCHCK(TX_NON_IP_DROP_DIS_LBN, TX_NON_IP_DROP_DIS_WIDTH);
|
|
+
|
|
+ FALCON_LOCK_LOCK(nic);
|
|
+ falcon_read_qq(efhw_kva + TX_CFG_REG_OFST, &val1, &val2);
|
|
+
|
|
+ /* Will flag fatal interrupts on owner id errors. This should not be
|
|
+ on for production code because there is otherwise a denial of
|
|
+ serivce attack possible */
|
|
+ val1 |= (1 << TX_OWNERR_CTL_LBN);
|
|
+
|
|
+ /* Setup user queue TCP/UDP only packet security */
|
|
+ if (unlocked)
|
|
+ val1 |= (1 << TX_NON_IP_DROP_DIS_LBN);
|
|
+ else
|
|
+ val1 &= ~(1 << TX_NON_IP_DROP_DIS_LBN);
|
|
+
|
|
+ falcon_write_qq(efhw_kva + TX_CFG_REG_OFST, val1, val2);
|
|
+ mmiowb();
|
|
+ FALCON_LOCK_UNLOCK(nic);
|
|
+}
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * Random thresholds - Low level interface (Would like these to be op
|
|
+ * defaults wherever possible)
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+void falcon_nic_pace_cfg(struct efhw_nic *nic, int fb_base, int bin_thresh)
|
|
+{
|
|
+ FALCON_LOCK_DECL;
|
|
+ volatile char __iomem *efhw_kva = EFHW_KVA(nic);
|
|
+ unsigned offset = 0;
|
|
+ uint64_t val;
|
|
+
|
|
+ __DWCHCK(TX_PACE_FB_BASE_LBN, TX_PACE_FB_BASE_WIDTH);
|
|
+ __DWCHCK(TX_PACE_BIN_TH_LBN, TX_PACE_BIN_TH_WIDTH);
|
|
+
|
|
+ switch (nic->devtype.variant) {
|
|
+ case 'A': offset = TX_PACE_REG_A1_OFST; break;
|
|
+ case 'B': offset = TX_PACE_REG_B0_OFST; break;
|
|
+ default: EFHW_ASSERT(0); break;
|
|
+ }
|
|
+
|
|
+ val = (0x15 << TX_PACE_SB_NOTAF_LBN);
|
|
+ val |= (0xb << TX_PACE_SB_AF_LBN);
|
|
+
|
|
+ val |= ((fb_base & __FALCON_MASK64(TX_PACE_FB_BASE_WIDTH)) <<
|
|
+ TX_PACE_FB_BASE_LBN);
|
|
+ val |= ((bin_thresh & __FALCON_MASK64(TX_PACE_BIN_TH_WIDTH)) <<
|
|
+ TX_PACE_BIN_TH_LBN);
|
|
+
|
|
+ /* Falcon requires 128 bit atomic access for this register */
|
|
+ FALCON_LOCK_LOCK(nic);
|
|
+ falcon_write_qq(efhw_kva + offset, val, 0);
|
|
+ mmiowb();
|
|
+ FALCON_LOCK_UNLOCK(nic);
|
|
+}
|
|
+
|
|
+
|
|
+/**********************************************************************
|
|
+ * Implementation of the HAL. ********************************************
|
|
+ **********************************************************************/
|
|
+
|
|
+/*----------------------------------------------------------------------------
|
|
+ *
|
|
+ * Initialisation and configuration discovery
|
|
+ *
|
|
+ *---------------------------------------------------------------------------*/
|
|
+
|
|
+static int falcon_nic_init_irq_channel(struct efhw_nic *nic, int enable)
|
|
+{
|
|
+ /* create a buffer for the irq channel */
|
|
+ int rc;
|
|
+
|
|
+ if (enable) {
|
|
+ rc = efhw_iopage_alloc(nic, &nic->irq_iobuff);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ falcon_nic_irq_addr_set(nic,
|
|
+ efhw_iopage_dma_addr(&nic->irq_iobuff));
|
|
+ } else {
|
|
+ if (efhw_iopage_is_valid(&nic->irq_iobuff))
|
|
+ efhw_iopage_free(nic, &nic->irq_iobuff);
|
|
+
|
|
+ efhw_iopage_mark_invalid(&nic->irq_iobuff);
|
|
+ falcon_nic_irq_addr_set(nic, 0);
|
|
+ }
|
|
+
|
|
+ EFHW_TRACE("%s: %lx %sable", __func__,
|
|
+ (unsigned long) efhw_iopage_dma_addr(&nic->irq_iobuff),
|
|
+ enable ? "en" : "dis");
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void falcon_nic_close_hardware(struct efhw_nic *nic)
|
|
+{
|
|
+ /* check we are in possession of some hardware */
|
|
+ if (!efhw_nic_have_hw(nic))
|
|
+ return;
|
|
+
|
|
+ falcon_nic_init_irq_channel(nic, 0);
|
|
+ falcon_nic_filter_dtor(nic);
|
|
+
|
|
+ EFHW_NOTICE("%s:", __func__);
|
|
+}
|
|
+
|
|
+static int
|
|
+falcon_nic_init_hardware(struct efhw_nic *nic,
|
|
+ struct efhw_ev_handler *ev_handlers,
|
|
+ const uint8_t *mac_addr, int non_irq_evq)
|
|
+{
|
|
+ int rc;
|
|
+
|
|
+ /* header sanity checks */
|
|
+ FALCON_ASSERT_VALID();
|
|
+
|
|
+ /* Initialise supporting modules */
|
|
+ rc = falcon_nic_filter_ctor(nic);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+#if FALCON_USE_SHADOW_BUFFER_TABLE
|
|
+ CI_ZERO_ARRAY(_falcon_buffer_table, FALCON_BUFFER_TBL_NUM);
|
|
+#endif
|
|
+
|
|
+ /* Initialise the top level hardware blocks */
|
|
+ memcpy(nic->mac_addr, mac_addr, ETH_ALEN);
|
|
+
|
|
+ EFHW_TRACE("%s:", __func__);
|
|
+
|
|
+ /* nic.c:efhw_nic_init marks all the interrupt units as unused.
|
|
+
|
|
+ ?? TODO we should be able to request the non-interrupting event
|
|
+ queue and the net driver's (for a net driver that is using libefhw)
|
|
+ additional RSS queues here.
|
|
+
|
|
+ Result would be that that net driver could call
|
|
+ nic.c:efhw_nic_allocate_common_hardware_resources() and that the
|
|
+ IFDEF FALCON's can be removed from
|
|
+ nic.c:efhw_nic_allocate_common_hardware_resources()
|
|
+ */
|
|
+ nic->irq_unit = INT_EN_REG_CHAR_OFST;
|
|
+
|
|
+ /*****************************************************************
|
|
+ * The rest of this function deals with initialization of the NICs
|
|
+ * hardware (as opposed to the initialization of the
|
|
+ * struct efhw_nic data structure */
|
|
+
|
|
+ /* char driver grabs SRM events onto the non interrupting
|
|
+ * event queue */
|
|
+ falcon_nic_srm_upd_evq(nic, non_irq_evq);
|
|
+
|
|
+ /* RXDP tweaks */
|
|
+
|
|
+ /* ?? bug2396 rx_cfg should be ok so long as the net driver
|
|
+ * always pushes buffers big enough for the link MTU */
|
|
+
|
|
+ /* set the RX buffer cutoff size to be the same as PAGE_SIZE.
|
|
+ * Use this value when we think that there will be a lot of
|
|
+ * jumbo frames.
|
|
+ *
|
|
+ * The default value 1600 is useful when packets are small,
|
|
+ * but would means that jumbo frame RX queues would need more
|
|
+ * descriptors pushing */
|
|
+ falcon_nic_set_rx_usr_buf_size(nic, FALCON_RX_USR_BUF_SIZE);
|
|
+
|
|
+ /* TXDP tweaks */
|
|
+ /* ?? bug2396 looks ok */
|
|
+ falcon_nic_tx_cfg(nic, /*unlocked(for non-UDP/TCP)= */ 0);
|
|
+ falcon_nic_pace_cfg(nic, 4, 2);
|
|
+
|
|
+ /* ?? bug2396
|
|
+ * netdriver must load first or else must RMW this register */
|
|
+ falcon_nic_rx_filter_ctl_set(nic, RX_FILTER_CTL_SRCH_LIMIT_TCP_FULL,
|
|
+ RX_FILTER_CTL_SRCH_LIMIT_TCP_WILD,
|
|
+ RX_FILTER_CTL_SRCH_LIMIT_UDP_FULL,
|
|
+ RX_FILTER_CTL_SRCH_LIMIT_UDP_WILD);
|
|
+
|
|
+ if (!(nic->flags & NIC_FLAG_NO_INTERRUPT)) {
|
|
+ rc = efhw_keventq_ctor(nic, FALCON_EVQ_CHAR,
|
|
+ &nic->interrupting_evq, ev_handlers);
|
|
+ if (rc < 0) {
|
|
+ EFHW_ERR("%s: efhw_keventq_ctor() failed (%d) evq=%d",
|
|
+ __func__, rc, FALCON_EVQ_CHAR);
|
|
+ return rc;
|
|
+ }
|
|
+ }
|
|
+ rc = efhw_keventq_ctor(nic, non_irq_evq,
|
|
+ &nic->non_interrupting_evq, NULL);
|
|
+ if (rc < 0) {
|
|
+ EFHW_ERR("%s: efhw_keventq_ctor() failed (%d) evq=%d",
|
|
+ __func__, rc, non_irq_evq);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ /* allocate IRQ channel */
|
|
+ rc = falcon_nic_init_irq_channel(nic, 1);
|
|
+ /* ignore failure at user-level for eftest */
|
|
+ if ((rc < 0) && !(nic->options & NIC_OPT_EFTEST))
|
|
+ return rc;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * Interrupt
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+static void
|
|
+falcon_nic_interrupt_enable(struct efhw_nic *nic)
|
|
+{
|
|
+ struct efhw_keventq *q;
|
|
+ unsigned rdptr;
|
|
+
|
|
+ if (nic->flags & NIC_FLAG_NO_INTERRUPT)
|
|
+ return;
|
|
+
|
|
+ /* Enable driver interrupts */
|
|
+ EFHW_NOTICE("%s: enable master interrupt", __func__);
|
|
+ falcon_nic_interrupt_hw_enable(nic);
|
|
+
|
|
+ /* An interrupting eventq must start of day ack its read pointer */
|
|
+ q = &nic->interrupting_evq;
|
|
+ rdptr = EFHW_EVENT_OFFSET(q, q, 1) / sizeof(efhw_event_t);
|
|
+ falcon_nic_evq_ack(nic, FALCON_EVQ_CHAR, rdptr, false);
|
|
+ EFHW_NOTICE("%s: ACK evq[%d]:%x", __func__,
|
|
+ FALCON_EVQ_CHAR, rdptr);
|
|
+}
|
|
+
|
|
+static void falcon_nic_interrupt_disable(struct efhw_nic *nic)
|
|
+{
|
|
+ /* NB. No need to check for NIC_FLAG_NO_INTERRUPT, as
|
|
+ ** falcon_nic_interrupt_hw_disable() will do it. */
|
|
+ falcon_nic_interrupt_hw_disable(nic);
|
|
+}
|
|
+
|
|
+static void
|
|
+falcon_nic_set_interrupt_moderation(struct efhw_nic *nic, int evq,
|
|
+ uint32_t val)
|
|
+{
|
|
+ if (evq < 0)
|
|
+ evq = FALCON_EVQ_CHAR;
|
|
+
|
|
+ falcon_ab_timer_tbl_set(nic, evq, TIMER_MODE_INT_HLDOFF, val / 5);
|
|
+}
|
|
+
|
|
+static inline void legacy_irq_ack(struct efhw_nic *nic)
|
|
+{
|
|
+ EFHW_ASSERT(!(nic->flags & NIC_FLAG_NO_INTERRUPT));
|
|
+
|
|
+ if (!(nic->flags & NIC_FLAG_MSI)) {
|
|
+ writel(1, EFHW_KVA(nic) + INT_ACK_REG_CHAR_A1_OFST);
|
|
+ mmiowb();
|
|
+ /* ?? FIXME: We should be doing a read here to ensure IRQ is
|
|
+ * thoroughly acked before we return from ISR. */
|
|
+ }
|
|
+}
|
|
+
|
|
+static int falcon_nic_interrupt(struct efhw_nic *nic)
|
|
+{
|
|
+ uint32_t *syserr_ptr =
|
|
+ (uint32_t *) efhw_iopage_ptr(&nic->irq_iobuff);
|
|
+ int handled = 0;
|
|
+ int done_ack = 0;
|
|
+
|
|
+ EFHW_ASSERT(!(nic->flags & NIC_FLAG_NO_INTERRUPT));
|
|
+ EFHW_ASSERT(syserr_ptr);
|
|
+
|
|
+ /* FIFO fill level interrupt - just log it. */
|
|
+ if (unlikely(*(syserr_ptr + (DW0_OFST / 4)))) {
|
|
+ EFHW_WARN("%s: *** FIFO *** %x", __func__,
|
|
+ *(syserr_ptr + (DW0_OFST / 4)));
|
|
+ *(syserr_ptr + (DW0_OFST / 4)) = 0;
|
|
+ handled++;
|
|
+ }
|
|
+
|
|
+ /* Fatal interrupts. */
|
|
+ if (unlikely(*(syserr_ptr + (DW2_OFST / 4)))) {
|
|
+ *(syserr_ptr + (DW2_OFST / 4)) = 0;
|
|
+ falcon_nic_handle_fatal_int(nic);
|
|
+ handled++;
|
|
+ }
|
|
+
|
|
+ /* Event queue interrupt. For legacy interrupts we have to check
|
|
+ * that the interrupt is for us, because it could be shared. */
|
|
+ if (*(syserr_ptr + (DW1_OFST / 4))) {
|
|
+ *(syserr_ptr + (DW1_OFST / 4)) = 0;
|
|
+ /* ACK must come before callback to handler fn. */
|
|
+ legacy_irq_ack(nic);
|
|
+ done_ack = 1;
|
|
+ handled++;
|
|
+ if (nic->irq_handler)
|
|
+ nic->irq_handler(nic, 0);
|
|
+ }
|
|
+
|
|
+ if (unlikely(!done_ack)) {
|
|
+ if (!handled)
|
|
+ /* Shared interrupt line (hopefully). */
|
|
+ return 0;
|
|
+ legacy_irq_ack(nic);
|
|
+ }
|
|
+
|
|
+ EFHW_TRACE("%s: handled %d", __func__, handled);
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * Event Management - and SW event posting
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+static void
|
|
+falcon_nic_event_queue_enable(struct efhw_nic *nic, uint evq, uint evq_size,
|
|
+ dma_addr_t q_base_addr, /* not used */
|
|
+ uint buf_base_id, int interrupting)
|
|
+{
|
|
+ EFHW_ASSERT(nic);
|
|
+
|
|
+ /* Whether or not queue has an interrupt depends on
|
|
+ * instance number and h/w variant, so [interrupting] is
|
|
+ * ignored.
|
|
+ */
|
|
+ falcon_ab_timer_tbl_set(nic, evq, 0/*disable*/, 0);
|
|
+
|
|
+ falcon_nic_evq_ptr_tbl(nic, evq, 1, buf_base_id, evq_size);
|
|
+ EFHW_TRACE("%s: enable evq %u size %u", __func__, evq, evq_size);
|
|
+}
|
|
+
|
|
+static void
|
|
+falcon_nic_event_queue_disable(struct efhw_nic *nic, uint evq, int timer_only)
|
|
+{
|
|
+ EFHW_ASSERT(nic);
|
|
+
|
|
+ falcon_ab_timer_tbl_set(nic, evq, 0 /* disable */ , 0);
|
|
+
|
|
+ if (!timer_only)
|
|
+ falcon_nic_evq_ptr_tbl(nic, evq, 0, 0, 0);
|
|
+ EFHW_TRACE("%s: disenable evq %u", __func__, evq);
|
|
+}
|
|
+
|
|
+static void
|
|
+falcon_nic_wakeup_request(struct efhw_nic *nic, dma_addr_t q_base_addr,
|
|
+ int next_i, int evq)
|
|
+{
|
|
+ EFHW_ASSERT(evq > FALCON_EVQ_CHAR);
|
|
+ falcon_nic_evq_ack(nic, evq, next_i, true);
|
|
+ EFHW_TRACE("%s: evq %d next_i %d", __func__, evq, next_i);
|
|
+}
|
|
+
|
|
+static void falcon_nic_sw_event(struct efhw_nic *nic, int data, int evq)
|
|
+{
|
|
+ uint64_t ev_data = data;
|
|
+
|
|
+ ev_data &= ~FALCON_EVENT_CODE_MASK;
|
|
+ ev_data |= FALCON_EVENT_CODE_SW;
|
|
+
|
|
+ falcon_drv_ev(nic, ev_data, evq);
|
|
+ EFHW_NOTICE("%s: evq[%d]->%x", __func__, evq, data);
|
|
+}
|
|
+
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * Buffer table - helpers
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+#define FALCON_LAZY_COMMIT_HWM (FALCON_BUFFER_UPD_MAX - 16)
|
|
+
|
|
+/* Note re.:
|
|
+ * falcon_nic_buffer_table_lazy_commit(struct efhw_nic *nic)
|
|
+ * falcon_nic_buffer_table_update_poll(struct efhw_nic *nic)
|
|
+ * falcon_nic_buffer_table_confirm(struct efhw_nic *nic)
|
|
+ * -- these are no-ops in the user-level driver because it would need to
|
|
+ * coordinate with the real driver on the number of outstanding commits.
|
|
+ *
|
|
+ * An exception is made for eftest apps, which manage the hardware without
|
|
+ * using the char driver.
|
|
+ */
|
|
+
|
|
+static inline void falcon_nic_buffer_table_lazy_commit(struct efhw_nic *nic)
|
|
+{
|
|
+ /* Do nothing if operating in synchronous mode. */
|
|
+ if (!nic->irq_handler)
|
|
+ return;
|
|
+}
|
|
+
|
|
+static inline void falcon_nic_buffer_table_update_poll(struct efhw_nic *nic)
|
|
+{
|
|
+ FALCON_LOCK_DECL;
|
|
+ int count = 0, rc = 0;
|
|
+
|
|
+ /* We can be called here early days */
|
|
+ if (!nic->irq_handler)
|
|
+ return;
|
|
+
|
|
+ /* If we need to gather buffer update events then poll the
|
|
+ non-interrupting event queue */
|
|
+
|
|
+ /* For each _buffer_table_commit there will be an update done
|
|
+ event. We don't keep track of how many buffers each commit has
|
|
+ committed, just make sure that all the expected events have been
|
|
+ gathered */
|
|
+ FALCON_LOCK_LOCK(nic);
|
|
+
|
|
+ EFHW_TRACE("%s: %d", __func__, nic->buf_commit_outstanding);
|
|
+
|
|
+ while (nic->buf_commit_outstanding > 0) {
|
|
+ /* we're not expecting to handle any events that require
|
|
+ * upcalls into the core driver */
|
|
+ struct efhw_ev_handler handler;
|
|
+ memset(&handler, 0, sizeof(handler));
|
|
+ nic->non_interrupting_evq.ev_handlers = &handler;
|
|
+ rc = efhw_keventq_poll(nic, &nic->non_interrupting_evq);
|
|
+ nic->non_interrupting_evq.ev_handlers = NULL;
|
|
+
|
|
+ if (rc < 0) {
|
|
+ EFHW_ERR("%s: poll ERROR (%d:%d) ***** ",
|
|
+ __func__, rc,
|
|
+ nic->buf_commit_outstanding);
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ FALCON_LOCK_UNLOCK(nic);
|
|
+
|
|
+ if (count++)
|
|
+ udelay(1);
|
|
+
|
|
+ if (count > 1000) {
|
|
+ EFHW_WARN("%s: poll Timeout ***** (%d)", __func__,
|
|
+ nic->buf_commit_outstanding);
|
|
+ nic->buf_commit_outstanding = 0;
|
|
+ return;
|
|
+ }
|
|
+ FALCON_LOCK_LOCK(nic);
|
|
+ }
|
|
+
|
|
+out:
|
|
+ FALCON_LOCK_UNLOCK(nic);
|
|
+ return;
|
|
+}
|
|
+
|
|
+void falcon_nic_buffer_table_confirm(struct efhw_nic *nic)
|
|
+{
|
|
+ /* confirm buffer table updates - should be used for items where
|
|
+ loss of data would be unacceptable. E.g for the buffers that back
|
|
+ an event or DMA queue */
|
|
+ FALCON_LOCK_DECL;
|
|
+
|
|
+ /* Do nothing if operating in synchronous mode. */
|
|
+ if (!nic->irq_handler)
|
|
+ return;
|
|
+
|
|
+ FALCON_LOCK_LOCK(nic);
|
|
+
|
|
+ _falcon_nic_buffer_table_commit(nic);
|
|
+
|
|
+ FALCON_LOCK_UNLOCK(nic);
|
|
+
|
|
+ falcon_nic_buffer_table_update_poll(nic);
|
|
+}
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * Buffer table - API
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+static void
|
|
+falcon_nic_buffer_table_clear(struct efhw_nic *nic, int buffer_id, int num)
|
|
+{
|
|
+ FALCON_LOCK_DECL;
|
|
+ FALCON_LOCK_LOCK(nic);
|
|
+ _falcon_nic_buffer_table_clear(nic, buffer_id, num);
|
|
+ FALCON_LOCK_UNLOCK(nic);
|
|
+}
|
|
+
|
|
+static void
|
|
+falcon_nic_buffer_table_set(struct efhw_nic *nic, dma_addr_t dma_addr,
|
|
+ uint bufsz, uint region,
|
|
+ int own_id, int buffer_id)
|
|
+{
|
|
+ FALCON_LOCK_DECL;
|
|
+
|
|
+ EFHW_ASSERT(region < FALCON_REGION_NUM);
|
|
+
|
|
+ EFHW_ASSERT((bufsz == EFHW_4K) ||
|
|
+ (bufsz == EFHW_8K && FALCON_BUFFER_TABLE_FULL_MODE));
|
|
+
|
|
+ falcon_nic_buffer_table_update_poll(nic);
|
|
+
|
|
+ FALCON_LOCK_LOCK(nic);
|
|
+
|
|
+ _falcon_nic_buffer_table_set(nic, dma_addr, bufsz, region, own_id,
|
|
+ buffer_id);
|
|
+
|
|
+ falcon_nic_buffer_table_lazy_commit(nic);
|
|
+
|
|
+ FALCON_LOCK_UNLOCK(nic);
|
|
+}
|
|
+
|
|
+void
|
|
+falcon_nic_buffer_table_set_n(struct efhw_nic *nic, int buffer_id,
|
|
+ dma_addr_t dma_addr, uint bufsz, uint region,
|
|
+ int n_pages, int own_id)
|
|
+{
|
|
+ /* used to set up a contiguous range of buffers */
|
|
+ FALCON_LOCK_DECL;
|
|
+
|
|
+ EFHW_ASSERT(region < FALCON_REGION_NUM);
|
|
+
|
|
+ EFHW_ASSERT((bufsz == EFHW_4K) ||
|
|
+ (bufsz == EFHW_8K && FALCON_BUFFER_TABLE_FULL_MODE));
|
|
+
|
|
+ while (n_pages--) {
|
|
+
|
|
+ falcon_nic_buffer_table_update_poll(nic);
|
|
+
|
|
+ FALCON_LOCK_LOCK(nic);
|
|
+
|
|
+ _falcon_nic_buffer_table_set(nic, dma_addr, bufsz, region,
|
|
+ own_id, buffer_id++);
|
|
+
|
|
+ falcon_nic_buffer_table_lazy_commit(nic);
|
|
+
|
|
+ FALCON_LOCK_UNLOCK(nic);
|
|
+
|
|
+ dma_addr += bufsz;
|
|
+ }
|
|
+}
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * DMA Queues - mid level API
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+#if BUG5302_WORKAROUND
|
|
+
|
|
+/* Tx queues can get stuck if the software write pointer is set to an index
|
|
+ * beyond the configured size of the queue, such that they will not flush.
|
|
+ * This code can be run before attempting a flush; it will detect the bogus
|
|
+ * value and reset it. This fixes most instances of this problem, although
|
|
+ * sometimes it does not work, or we may not detect it in the first place,
|
|
+ * if the out-of-range value was replaced by an in-range value earlier.
|
|
+ * (In those cases we have to apply a bigger hammer later, if we see that
|
|
+ * the queue is still not flushing.)
|
|
+ */
|
|
+static void
|
|
+falcon_check_for_bogus_tx_dma_wptr(struct efhw_nic *nic, uint dmaq)
|
|
+{
|
|
+ FALCON_LOCK_DECL;
|
|
+ uint64_t val_low64, val_high64;
|
|
+ uint64_t size, hwptr, swptr, val;
|
|
+ volatile char __iomem *efhw_kva = EFHW_KVA(nic);
|
|
+ ulong offset = falcon_dma_tx_q_offset(nic, dmaq);
|
|
+
|
|
+ /* Falcon requires 128 bit atomic access for this register */
|
|
+ FALCON_LOCK_LOCK(nic);
|
|
+ falcon_read_qq(efhw_kva + offset, &val_low64, &val_high64);
|
|
+ FALCON_LOCK_UNLOCK(nic);
|
|
+
|
|
+ size = (val_low64 >> TX_DESCQ_SIZE_LBN)
|
|
+ & __FALCON_MASK64(TX_DESCQ_SIZE_WIDTH);
|
|
+ size = (1 << size) * 512;
|
|
+ hwptr = (val_high64 >> __DW3(TX_DESCQ_HW_RPTR_LBN))
|
|
+ & __FALCON_MASK64(TX_DESCQ_HW_RPTR_WIDTH);
|
|
+ swptr = (val_low64 >> TX_DESCQ_SW_WPTR_LBN)
|
|
+ & __FALCON_MASK64(__LW2(TX_DESCQ_SW_WPTR_LBN));
|
|
+ val = (val_high64)
|
|
+ &
|
|
+ __FALCON_MASK64(__DW3
|
|
+ (TX_DESCQ_SW_WPTR_LBN + TX_DESCQ_SW_WPTR_WIDTH));
|
|
+ val = val << __LW2(TX_DESCQ_SW_WPTR_LBN);
|
|
+ swptr = swptr | val;
|
|
+
|
|
+ if (swptr >= size) {
|
|
+ EFHW_WARN("Resetting bad write pointer for TXQ[%d]", dmaq);
|
|
+ writel((uint32_t) ((hwptr + 0) & (size - 1)),
|
|
+ efhw_kva + falcon_tx_dma_page_addr(dmaq) + 12);
|
|
+ mmiowb();
|
|
+ }
|
|
+}
|
|
+
|
|
+/* Here's that "bigger hammer": we reset all the pointers (hardware read,
|
|
+ * hardware descriptor cache read, software write) to zero.
|
|
+ */
|
|
+void falcon_clobber_tx_dma_ptrs(struct efhw_nic *nic, uint dmaq)
|
|
+{
|
|
+ FALCON_LOCK_DECL;
|
|
+ uint64_t val_low64, val_high64;
|
|
+ volatile char __iomem *efhw_kva = EFHW_KVA(nic);
|
|
+ ulong offset = falcon_dma_tx_q_offset(nic, dmaq);
|
|
+
|
|
+ EFHW_WARN("Recovering stuck TXQ[%d]", dmaq);
|
|
+ FALCON_LOCK_LOCK(nic);
|
|
+ falcon_read_qq(efhw_kva + offset, &val_low64, &val_high64);
|
|
+ val_high64 &= ~(__FALCON_MASK64(TX_DESCQ_HW_RPTR_WIDTH)
|
|
+ << __DW3(TX_DESCQ_HW_RPTR_LBN));
|
|
+ val_high64 &= ~(__FALCON_MASK64(TX_DC_HW_RPTR_WIDTH)
|
|
+ << __DW3(TX_DC_HW_RPTR_LBN));
|
|
+ falcon_write_qq(efhw_kva + offset, val_low64, val_high64);
|
|
+ mmiowb();
|
|
+ writel(0, efhw_kva + falcon_tx_dma_page_addr(dmaq) + 12);
|
|
+ mmiowb();
|
|
+ FALCON_LOCK_UNLOCK(nic);
|
|
+}
|
|
+
|
|
+#endif
|
|
+
|
|
+static inline int
|
|
+__falcon_really_flush_tx_dma_channel(struct efhw_nic *nic, uint dmaq)
|
|
+{
|
|
+ FALCON_LOCK_DECL;
|
|
+ volatile char __iomem *efhw_kva = EFHW_KVA(nic);
|
|
+ uint val;
|
|
+
|
|
+ EFHW_BUILD_ASSERT(TX_FLUSH_DESCQ_REG_KER_OFST ==
|
|
+ TX_FLUSH_DESCQ_REG_OFST);
|
|
+
|
|
+ __DWCHCK(TX_FLUSH_DESCQ_CMD_LBN, TX_FLUSH_DESCQ_CMD_WIDTH);
|
|
+ __DWCHCK(TX_FLUSH_DESCQ_LBN, TX_FLUSH_DESCQ_WIDTH);
|
|
+ __RANGECHCK(dmaq, TX_FLUSH_DESCQ_WIDTH);
|
|
+
|
|
+ val = ((1 << TX_FLUSH_DESCQ_CMD_LBN) | (dmaq << TX_FLUSH_DESCQ_LBN));
|
|
+
|
|
+ EFHW_TRACE("TX DMA flush[%d]", dmaq);
|
|
+
|
|
+#if BUG5302_WORKAROUND
|
|
+ falcon_check_for_bogus_tx_dma_wptr(nic, dmaq);
|
|
+#endif
|
|
+
|
|
+ /* Falcon requires 128 bit atomic access for this register */
|
|
+ FALCON_LOCK_LOCK(nic);
|
|
+ falcon_write_qq(efhw_kva + TX_FLUSH_DESCQ_REG_OFST,
|
|
+ val, FALCON_ATOMIC_TX_FLUSH_DESCQ);
|
|
+
|
|
+ mmiowb();
|
|
+ FALCON_LOCK_UNLOCK(nic);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static inline int
|
|
+__falcon_is_tx_dma_channel_flushed(struct efhw_nic *nic, uint dmaq)
|
|
+{
|
|
+ FALCON_LOCK_DECL;
|
|
+ uint64_t val_low64, val_high64;
|
|
+ uint64_t enable, flush_pending;
|
|
+ volatile char __iomem *efhw_kva = EFHW_KVA(nic);
|
|
+ ulong offset = falcon_dma_tx_q_offset(nic, dmaq);
|
|
+
|
|
+ /* Falcon requires 128 bit atomic access for this register */
|
|
+ FALCON_LOCK_LOCK(nic);
|
|
+ falcon_read_qq(efhw_kva + offset, &val_low64, &val_high64);
|
|
+ FALCON_LOCK_UNLOCK(nic);
|
|
+
|
|
+ /* should see one of three values for these 2 bits
|
|
+ * 1, queue enabled no flush pending
|
|
+ * - i.e. first flush request
|
|
+ * 2, queue enabled, flush pending
|
|
+ * - i.e. request to reflush before flush finished
|
|
+ * 3, queue disabled (no flush pending)
|
|
+ * - flush complete
|
|
+ */
|
|
+ __DWCHCK(TX_DESCQ_FLUSH_LBN, TX_DESCQ_FLUSH_WIDTH);
|
|
+ __DW3CHCK(TX_DESCQ_EN_LBN, TX_DESCQ_EN_WIDTH);
|
|
+ enable = val_high64 & (1 << __DW3(TX_DESCQ_EN_LBN));
|
|
+ flush_pending = val_low64 & (1 << TX_DESCQ_FLUSH_LBN);
|
|
+
|
|
+ if (enable && !flush_pending)
|
|
+ return 0;
|
|
+
|
|
+ EFHW_TRACE("%d, %s: %s, %sflush pending", dmaq, __func__,
|
|
+ enable ? "enabled" : "disabled",
|
|
+ flush_pending ? "" : "NO ");
|
|
+ /* still in progress */
|
|
+ if (enable && flush_pending)
|
|
+ return -EALREADY;
|
|
+
|
|
+ return -EAGAIN;
|
|
+}
|
|
+
|
|
+static int falcon_flush_tx_dma_channel(struct efhw_nic *nic, uint dmaq)
|
|
+{
|
|
+ int rc;
|
|
+ rc = __falcon_is_tx_dma_channel_flushed(nic, dmaq);
|
|
+ if (rc < 0) {
|
|
+ EFHW_WARN("%s: failed %d", __func__, rc);
|
|
+ return rc;
|
|
+ }
|
|
+ return __falcon_really_flush_tx_dma_channel(nic, dmaq);
|
|
+}
|
|
+
|
|
+static int
|
|
+__falcon_really_flush_rx_dma_channel(struct efhw_nic *nic, uint dmaq)
|
|
+{
|
|
+ FALCON_LOCK_DECL;
|
|
+ volatile char __iomem *efhw_kva = EFHW_KVA(nic);
|
|
+ uint val;
|
|
+
|
|
+ EFHW_BUILD_ASSERT(RX_FLUSH_DESCQ_REG_KER_OFST ==
|
|
+ RX_FLUSH_DESCQ_REG_OFST);
|
|
+
|
|
+ __DWCHCK(RX_FLUSH_DESCQ_CMD_LBN, RX_FLUSH_DESCQ_CMD_WIDTH);
|
|
+ __DWCHCK(RX_FLUSH_DESCQ_LBN, RX_FLUSH_DESCQ_WIDTH);
|
|
+ __RANGECHCK(dmaq, RX_FLUSH_DESCQ_WIDTH);
|
|
+
|
|
+ val = ((1 << RX_FLUSH_DESCQ_CMD_LBN) | (dmaq << RX_FLUSH_DESCQ_LBN));
|
|
+
|
|
+ EFHW_TRACE("RX DMA flush[%d]", dmaq);
|
|
+
|
|
+ /* Falcon requires 128 bit atomic access for this register */
|
|
+ FALCON_LOCK_LOCK(nic);
|
|
+ falcon_write_qq(efhw_kva + RX_FLUSH_DESCQ_REG_OFST, val,
|
|
+ FALCON_ATOMIC_RX_FLUSH_DESCQ);
|
|
+ mmiowb();
|
|
+ FALCON_LOCK_UNLOCK(nic);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static inline int
|
|
+__falcon_is_rx_dma_channel_flushed(struct efhw_nic *nic, uint dmaq)
|
|
+{
|
|
+ FALCON_LOCK_DECL;
|
|
+ uint64_t val;
|
|
+ volatile char __iomem *efhw_kva = EFHW_KVA(nic);
|
|
+ ulong offset = falcon_dma_rx_q_offset(nic, dmaq);
|
|
+
|
|
+ /* Falcon requires 128 bit atomic access for this register */
|
|
+ FALCON_LOCK_LOCK(nic);
|
|
+ falcon_read_q(efhw_kva + offset, &val);
|
|
+ FALCON_LOCK_UNLOCK(nic);
|
|
+
|
|
+ __DWCHCK(RX_DESCQ_EN_LBN, RX_DESCQ_EN_WIDTH);
|
|
+
|
|
+ /* is it enabled? */
|
|
+ return (val & (1 << RX_DESCQ_EN_LBN))
|
|
+ ? 0 : -EAGAIN;
|
|
+}
|
|
+
|
|
+static int falcon_flush_rx_dma_channel(struct efhw_nic *nic, uint dmaq)
|
|
+{
|
|
+ int rc;
|
|
+ rc = __falcon_is_rx_dma_channel_flushed(nic, dmaq);
|
|
+ if (rc < 0) {
|
|
+ EFHW_ERR("%s: failed %d", __func__, rc);
|
|
+ return rc;
|
|
+ }
|
|
+ return __falcon_really_flush_rx_dma_channel(nic, dmaq);
|
|
+}
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * Falcon specific event callbacks
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+int
|
|
+falcon_handle_char_event(struct efhw_nic *nic, struct efhw_ev_handler *h,
|
|
+ efhw_event_t *ev)
|
|
+{
|
|
+ EFHW_TRACE("DRIVER EVENT: "FALCON_EVENT_FMT,
|
|
+ FALCON_EVENT_PRI_ARG(*ev));
|
|
+
|
|
+ switch (FALCON_EVENT_DRIVER_SUBCODE(ev)) {
|
|
+
|
|
+ case TX_DESCQ_FLS_DONE_EV_DECODE:
|
|
+ EFHW_TRACE("TX[%d] flushed",
|
|
+ (int)FALCON_EVENT_TX_FLUSH_Q_ID(ev));
|
|
+ efhw_handle_txdmaq_flushed(nic, h, ev);
|
|
+ break;
|
|
+
|
|
+ case RX_DESCQ_FLS_DONE_EV_DECODE:
|
|
+ EFHW_TRACE("RX[%d] flushed",
|
|
+ (int)FALCON_EVENT_TX_FLUSH_Q_ID(ev));
|
|
+ efhw_handle_rxdmaq_flushed(nic, h, ev);
|
|
+ break;
|
|
+
|
|
+ case SRM_UPD_DONE_EV_DECODE:
|
|
+ nic->buf_commit_outstanding =
|
|
+ max(0, nic->buf_commit_outstanding - 1);
|
|
+ EFHW_TRACE("COMMIT DONE %d", nic->buf_commit_outstanding);
|
|
+ break;
|
|
+
|
|
+ case EVQ_INIT_DONE_EV_DECODE:
|
|
+ EFHW_TRACE("%sEVQ INIT", "");
|
|
+ break;
|
|
+
|
|
+ case WAKE_UP_EV_DECODE:
|
|
+ EFHW_TRACE("%sWAKE UP", "");
|
|
+ efhw_handle_wakeup_event(nic, h, ev);
|
|
+ break;
|
|
+
|
|
+ case TIMER_EV_DECODE:
|
|
+ EFHW_TRACE("%sTIMER", "");
|
|
+ efhw_handle_timeout_event(nic, h, ev);
|
|
+ break;
|
|
+
|
|
+ case RX_DESCQ_FLSFF_OVFL_EV_DECODE:
|
|
+ /* This shouldn't happen. */
|
|
+ EFHW_ERR("%s: RX flush fifo overflowed", __func__);
|
|
+ return -EINVAL;
|
|
+
|
|
+ default:
|
|
+ EFHW_TRACE("UNKOWN DRIVER EVENT: " FALCON_EVENT_FMT,
|
|
+ FALCON_EVENT_PRI_ARG(*ev));
|
|
+ break;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * Filter search depth control
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+
|
|
+#define Q0_READ(q0, name) \
|
|
+ ((unsigned)(((q0) >> name##_LBN) & (__FALCON_MASK64(name##_WIDTH))))
|
|
+#define Q0_MASK(name) \
|
|
+ ((__FALCON_MASK64(name##_WIDTH)) << name##_LBN)
|
|
+#define Q0_VALUE(name, value) \
|
|
+ (((uint64_t)(value)) << name##_LBN)
|
|
+
|
|
+#define Q1_READ(q1, name) \
|
|
+ ((unsigned)(((q1) >> (name##_LBN - 64)) & \
|
|
+ (__FALCON_MASK64(name##_WIDTH))))
|
|
+#define Q1_MASK(name) \
|
|
+ ((__FALCON_MASK64(name##_WIDTH)) << (name##_LBN - 64))
|
|
+#define Q1_VALUE(name, value) \
|
|
+ (((uint64_t)(value)) << (name##_LBN - 64))
|
|
+
|
|
+
|
|
+void
|
|
+falcon_nic_get_rx_filter_search_limits(struct efhw_nic *nic,
|
|
+ struct efhw_filter_search_limits *lim,
|
|
+ int use_raw_values)
|
|
+{
|
|
+ volatile char __iomem *efhw_kva = EFHW_KVA(nic);
|
|
+ FALCON_LOCK_DECL;
|
|
+ uint64_t q0, q1;
|
|
+ unsigned ff = (use_raw_values ? 0 : RX_FILTER_CTL_SRCH_FUDGE_FULL);
|
|
+ unsigned wf = (use_raw_values ? 0 : RX_FILTER_CTL_SRCH_FUDGE_WILD);
|
|
+
|
|
+ FALCON_LOCK_LOCK(nic);
|
|
+ falcon_read_qq(efhw_kva + RX_FILTER_CTL_REG_OFST, &q0, &q1);
|
|
+ FALCON_LOCK_UNLOCK(nic);
|
|
+
|
|
+ lim->tcp_full = Q0_READ(q0, TCP_FULL_SRCH_LIMIT) - ff;
|
|
+ lim->tcp_wild = Q0_READ(q0, TCP_WILD_SRCH_LIMIT) - wf;
|
|
+ lim->udp_full = Q0_READ(q0, UDP_FULL_SRCH_LIMIT) - ff;
|
|
+ lim->udp_wild = Q0_READ(q0, UDP_WILD_SRCH_LIMIT) - wf;
|
|
+}
|
|
+EXPORT_SYMBOL(falcon_nic_get_rx_filter_search_limits);
|
|
+
|
|
+
|
|
+void
|
|
+falcon_nic_set_rx_filter_search_limits(struct efhw_nic *nic,
|
|
+ struct efhw_filter_search_limits *lim,
|
|
+ int use_raw_values)
|
|
+{
|
|
+ volatile char __iomem *efhw_kva = EFHW_KVA(nic);
|
|
+ FALCON_LOCK_DECL;
|
|
+ uint64_t q0, q1;
|
|
+ unsigned ff = (use_raw_values ? 0 : RX_FILTER_CTL_SRCH_FUDGE_FULL);
|
|
+ unsigned wf = (use_raw_values ? 0 : RX_FILTER_CTL_SRCH_FUDGE_WILD);
|
|
+
|
|
+ FALCON_LOCK_LOCK(nic);
|
|
+ falcon_read_qq(efhw_kva + RX_FILTER_CTL_REG_OFST, &q0, &q1);
|
|
+
|
|
+ q0 &= ~Q0_MASK(TCP_FULL_SRCH_LIMIT);
|
|
+ q0 &= ~Q0_MASK(TCP_WILD_SRCH_LIMIT);
|
|
+ q0 &= ~Q0_MASK(UDP_FULL_SRCH_LIMIT);
|
|
+ q0 &= ~Q0_MASK(UDP_WILD_SRCH_LIMIT);
|
|
+ q0 |= Q0_VALUE(TCP_FULL_SRCH_LIMIT, lim->tcp_full + ff);
|
|
+ q0 |= Q0_VALUE(TCP_WILD_SRCH_LIMIT, lim->tcp_wild + wf);
|
|
+ q0 |= Q0_VALUE(UDP_FULL_SRCH_LIMIT, lim->udp_full + ff);
|
|
+ q0 |= Q0_VALUE(UDP_WILD_SRCH_LIMIT, lim->udp_wild + wf);
|
|
+ nic->tcp_full_srch.max = lim->tcp_full + ff
|
|
+ - RX_FILTER_CTL_SRCH_FUDGE_FULL;
|
|
+ nic->tcp_wild_srch.max = lim->tcp_wild + wf
|
|
+ - RX_FILTER_CTL_SRCH_FUDGE_WILD;
|
|
+ nic->udp_full_srch.max = lim->udp_full + ff
|
|
+ - RX_FILTER_CTL_SRCH_FUDGE_FULL;
|
|
+ nic->udp_wild_srch.max = lim->udp_wild + wf
|
|
+ - RX_FILTER_CTL_SRCH_FUDGE_WILD;
|
|
+
|
|
+ falcon_write_qq(efhw_kva + RX_FILTER_CTL_REG_OFST, q0, q1);
|
|
+ mmiowb();
|
|
+ FALCON_LOCK_UNLOCK(nic);
|
|
+}
|
|
+EXPORT_SYMBOL(falcon_nic_set_rx_filter_search_limits);
|
|
+
|
|
+
|
|
+#undef READ_Q0
|
|
+#undef Q0_MASK
|
|
+#undef Q0_VALUE
|
|
+#undef READ_Q1
|
|
+#undef Q1_MASK
|
|
+#undef Q1_VALUE
|
|
+
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * New unified filter API
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+
|
|
+#if FALCON_FULL_FILTER_CACHE
|
|
+static inline struct efhw_filter_spec *
|
|
+filter_spec_cache_entry(struct efhw_nic *nic, int filter_idx)
|
|
+{
|
|
+ EFHW_ASSERT(nic->filter_spec_cache);
|
|
+ return &nic->filter_spec_cache[filter_idx];
|
|
+}
|
|
+#endif
|
|
+
|
|
+
|
|
+static int filter_is_active(struct efhw_nic *nic, int filter_idx)
|
|
+{
|
|
+ return nic->filter_in_use[filter_idx];
|
|
+}
|
|
+
|
|
+
|
|
+static void set_filter_cache_entry(struct efhw_nic *nic,
|
|
+ struct efhw_filter_spec *spec,
|
|
+ int filter_idx)
|
|
+{
|
|
+ nic->filter_in_use[filter_idx] = 1;
|
|
+#if FALCON_FULL_FILTER_CACHE
|
|
+ memcpy(filter_spec_cache_entry(nic, filter_idx), spec,
|
|
+ sizeof(struct efhw_filter_spec));
|
|
+#endif
|
|
+}
|
|
+
|
|
+
|
|
+static void clear_filter_cache_entry(struct efhw_nic *nic,
|
|
+ int filter_idx)
|
|
+{
|
|
+ nic->filter_in_use[filter_idx] = 0;
|
|
+#if FALCON_FULL_FILTER_CACHE
|
|
+ memset(filter_spec_cache_entry(nic, filter_idx), 0,
|
|
+ sizeof(struct efhw_filter_spec));
|
|
+#endif
|
|
+}
|
|
+
|
|
+
|
|
+#if FALCON_FULL_FILTER_CACHE
|
|
+static int filter_is_duplicate(struct efhw_nic *nic,
|
|
+ struct efhw_filter_spec *spec, int filter_idx)
|
|
+{
|
|
+ struct efhw_filter_spec *cmp;
|
|
+
|
|
+ cmp = filter_spec_cache_entry(nic, filter_idx);
|
|
+
|
|
+ EFHW_ASSERT(filter_is_active(nic, filter_idx));
|
|
+
|
|
+ return (spec->saddr_le32 == cmp->saddr_le32) &&
|
|
+ (spec->daddr_le32 == cmp->daddr_le32) &&
|
|
+ (spec->sport_le16 == cmp->sport_le16) &&
|
|
+ (spec->dport_le16 == cmp->dport_le16) &&
|
|
+ (spec->tcp == cmp->tcp) &&
|
|
+ (spec->full == cmp->full);
|
|
+}
|
|
+#endif
|
|
+
|
|
+
|
|
+static void common_build_ip_filter(struct efhw_nic *nic, int tcp, int full,
|
|
+ int rss, int scatter, uint dmaq_id,
|
|
+ unsigned saddr_le32, unsigned sport_le16,
|
|
+ unsigned daddr_le32, unsigned dport_le16,
|
|
+ uint64_t *q0, uint64_t *q1)
|
|
+{
|
|
+ uint64_t v1, v2, v3, v4;
|
|
+ unsigned tmp_port_le16;
|
|
+
|
|
+ if (!full) {
|
|
+ saddr_le32 = 0;
|
|
+ sport_le16 = 0;
|
|
+ if (!tcp) {
|
|
+ tmp_port_le16 = sport_le16;
|
|
+ sport_le16 = dport_le16;
|
|
+ dport_le16 = tmp_port_le16;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ v4 = (((!tcp) << __DW4(TCP_UDP_0_LBN)) |
|
|
+ (dmaq_id << __DW4(RXQ_ID_0_LBN)));
|
|
+
|
|
+ switch (nic->devtype.variant) {
|
|
+ case 'A':
|
|
+ EFHW_ASSERT(!rss);
|
|
+ break;
|
|
+ case 'B':
|
|
+ v4 |= scatter << __DW4(SCATTER_EN_0_B0_LBN);
|
|
+ v4 |= rss << __DW4(RSS_EN_0_B0_LBN);
|
|
+ break;
|
|
+ default:
|
|
+ EFHW_ASSERT(0);
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ v3 = daddr_le32;
|
|
+ v2 = ((dport_le16 << __DW2(DEST_PORT_TCP_0_LBN)) |
|
|
+ (__HIGH(saddr_le32, SRC_IP_0_LBN, SRC_IP_0_WIDTH)));
|
|
+ v1 = ((__LOW(saddr_le32, SRC_IP_0_LBN, SRC_IP_0_WIDTH)) |
|
|
+ (sport_le16 << SRC_TCP_DEST_UDP_0_LBN));
|
|
+
|
|
+ *q0 = (v2 << 32) | v1;
|
|
+ *q1 = (v4 << 32) | v3;
|
|
+}
|
|
+
|
|
+
|
|
+static void build_filter(struct efhw_nic *nic, struct efhw_filter_spec *spec,
|
|
+ unsigned *key, unsigned *tbl_size,
|
|
+ struct efhw_filter_depth **depth,
|
|
+ uint64_t *q0, uint64_t *q1)
|
|
+{
|
|
+ *key = falcon_hash_get_ip_key(spec->saddr_le32,
|
|
+ spec->sport_le16,
|
|
+ spec->daddr_le32,
|
|
+ spec->dport_le16,
|
|
+ spec->tcp,
|
|
+ spec->full);
|
|
+ *tbl_size = nic->ip_filter_tbl_size;
|
|
+ if (spec->tcp && spec->full)
|
|
+ *depth = &nic->tcp_full_srch;
|
|
+ else if (spec->tcp && !spec->full)
|
|
+ *depth = &nic->tcp_wild_srch;
|
|
+ else if (!spec->tcp && spec->full)
|
|
+ *depth = &nic->udp_full_srch;
|
|
+ else
|
|
+ *depth = &nic->udp_wild_srch;
|
|
+ common_build_ip_filter(nic, spec->tcp, spec->full,
|
|
+ spec->rss, spec->scatter,
|
|
+ spec->dmaq_id,
|
|
+ spec->saddr_le32,
|
|
+ spec->sport_le16,
|
|
+ spec->daddr_le32,
|
|
+ spec->dport_le16,
|
|
+ q0, q1);
|
|
+}
|
|
+
|
|
+
|
|
+#if FALCON_VERIFY_FILTERS
|
|
+static void verify_filters(struct efhw_nic *nic)
|
|
+{
|
|
+ unsigned table_offset, table_stride;
|
|
+ unsigned i, dummy_key, dummy_tbl_size;
|
|
+ struct efhw_filter_depth *dummy_depth;
|
|
+ unsigned filter_tbl_size;
|
|
+ struct efhw_filter_spec *spec;
|
|
+ uint64_t q0_expect, q1_expect, q0_got, q1_got;
|
|
+
|
|
+ filter_tbl_size = nic->ip_filter_tbl_size;
|
|
+ table_offset = RX_FILTER_TBL0_OFST;
|
|
+ table_stride = 2 * FALCON_REGISTER128;
|
|
+
|
|
+ for (i = 0; i < filter_tbl_size; i++) {
|
|
+ if (!filter_is_active(nic, type, i))
|
|
+ continue;
|
|
+
|
|
+ spec = filter_spec_cache_entry(nic, type, i);
|
|
+
|
|
+ build_filter(nic, spec, &dummy_key, &dummy_tbl_size,
|
|
+ &dummy_depth, &q0_expect, &q1_expect);
|
|
+
|
|
+ falcon_read_qq(EFHW_KVA(nic) + table_offset + i * table_stride,
|
|
+ &q0_got, &q1_got);
|
|
+
|
|
+ if ((q0_got != q0_expect) || (q1_got != q1_expect)) {
|
|
+ falcon_write_qq(EFHW_KVA(nic) + 0x300,
|
|
+ q0_got, q1_got);
|
|
+ EFHW_ERR("ERROR: RX-filter[%d][%d] was "
|
|
+ "%"PRIx64":%" PRIx64" expected "
|
|
+ "%"PRIx64":%"PRIx64,
|
|
+ nic->index, i, q0_got, q1_got,
|
|
+ q0_expect, q1_expect);
|
|
+ }
|
|
+ }
|
|
+}
|
|
+#endif
|
|
+
|
|
+
|
|
+static void write_filter_table_entry(struct efhw_nic *nic,
|
|
+ unsigned filter_idx,
|
|
+ uint64_t q0, uint64_t q1)
|
|
+{
|
|
+ unsigned table_offset, table_stride, offset;
|
|
+
|
|
+ EFHW_ASSERT(filter_idx < nic->ip_filter_tbl_size);
|
|
+ table_offset = RX_FILTER_TBL0_OFST;
|
|
+ table_stride = 2 * FALCON_REGISTER128;
|
|
+
|
|
+ offset = table_offset + filter_idx * table_stride;
|
|
+ falcon_write_qq(EFHW_KVA(nic) + offset, q0, q1);
|
|
+ mmiowb();
|
|
+
|
|
+#if FALCON_VERIFY_FILTERS
|
|
+ {
|
|
+ uint64_t q0read, q1read;
|
|
+
|
|
+ /* Read a different entry first - ensure BIU flushed shadow */
|
|
+ falcon_read_qq(EFHW_KVA(nic) + offset + 0x10, &q0read, &q1read);
|
|
+ falcon_read_qq(EFHW_KVA(nic) + offset, &q0read, &q1read);
|
|
+ EFHW_ASSERT(q0read == q0);
|
|
+ EFHW_ASSERT(q1read == q1);
|
|
+
|
|
+ verify_filters(nic, type);
|
|
+ }
|
|
+#endif
|
|
+}
|
|
+
|
|
+
|
|
+static int falcon_nic_filter_set(struct efhw_nic *nic,
|
|
+ struct efhw_filter_spec *spec,
|
|
+ int *filter_idx_out)
|
|
+{
|
|
+ FALCON_LOCK_DECL;
|
|
+ unsigned key = 0, tbl_size = 0, hash1, hash2, k;
|
|
+ struct efhw_filter_depth *depth = NULL;
|
|
+ int filter_idx = -1;
|
|
+ int rc = 0;
|
|
+ uint64_t q0, q1;
|
|
+
|
|
+ build_filter(nic, spec, &key, &tbl_size, &depth, &q0, &q1);
|
|
+
|
|
+ if (tbl_size == 0)
|
|
+ return -EINVAL;
|
|
+
|
|
+ EFHW_TRACE("%s: depth->max=%d", __func__, depth->max);
|
|
+
|
|
+ hash1 = falcon_hash_function1(key, tbl_size);
|
|
+ hash2 = falcon_hash_function2(key, tbl_size);
|
|
+
|
|
+ FALCON_LOCK_LOCK(nic);
|
|
+
|
|
+ for (k = 0; k < depth->max; k++) {
|
|
+ filter_idx = falcon_hash_iterator(hash1, hash2, k, tbl_size);
|
|
+ if (!filter_is_active(nic, filter_idx))
|
|
+ break;
|
|
+#if FALCON_FULL_FILTER_CACHE
|
|
+ if (filter_is_duplicate(nic, spec, filter_idx)) {
|
|
+ EFHW_WARN("%s: ERROR: duplicate filter (disabling "
|
|
+ "interrupts)", __func__);
|
|
+ falcon_nic_interrupt_hw_disable(nic);
|
|
+ rc = -EINVAL;
|
|
+ goto fail1;
|
|
+ }
|
|
+#endif
|
|
+ }
|
|
+ if (k == depth->max) {
|
|
+ rc = -EADDRINUSE;
|
|
+ filter_idx = -1;
|
|
+ goto fail1;
|
|
+ } else if (depth->needed < (k + 1)) {
|
|
+ depth->needed = k + 1;
|
|
+ }
|
|
+
|
|
+ EFHW_ASSERT(filter_idx < (int)tbl_size);
|
|
+
|
|
+ set_filter_cache_entry(nic, spec, filter_idx);
|
|
+ write_filter_table_entry(nic, filter_idx, q0, q1);
|
|
+
|
|
+ ++nic->ip_filter_tbl_used;
|
|
+
|
|
+ *filter_idx_out = filter_idx;
|
|
+
|
|
+ EFHW_TRACE("%s: filter index %d rxq %u set in %u",
|
|
+ __func__, filter_idx, spec->dmaq_id, k);
|
|
+
|
|
+fail1:
|
|
+ FALCON_LOCK_UNLOCK(nic);
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+
|
|
+static void falcon_nic_filter_clear(struct efhw_nic *nic,
|
|
+ int filter_idx)
|
|
+{
|
|
+ FALCON_LOCK_DECL;
|
|
+
|
|
+ if (filter_idx < 0)
|
|
+ return;
|
|
+
|
|
+ FALCON_LOCK_LOCK(nic);
|
|
+ if (filter_is_active(nic, filter_idx)) {
|
|
+ if (--nic->ip_filter_tbl_used == 0) {
|
|
+ nic->tcp_full_srch.needed = 0;
|
|
+ nic->tcp_wild_srch.needed = 0;
|
|
+ nic->udp_full_srch.needed = 0;
|
|
+ nic->udp_wild_srch.needed = 0;
|
|
+ }
|
|
+ }
|
|
+ clear_filter_cache_entry(nic, filter_idx);
|
|
+ write_filter_table_entry(nic, filter_idx, 0, 0);
|
|
+ FALCON_LOCK_UNLOCK(nic);
|
|
+}
|
|
+
|
|
+
|
|
+int
|
|
+falcon_nic_filter_ctor(struct efhw_nic *nic)
|
|
+{
|
|
+ nic->ip_filter_tbl_size = 8 * 1024;
|
|
+ nic->ip_filter_tbl_used = 0;
|
|
+
|
|
+ nic->tcp_full_srch.needed = 0;
|
|
+ nic->tcp_full_srch.max = RX_FILTER_CTL_SRCH_LIMIT_TCP_FULL
|
|
+ - RX_FILTER_CTL_SRCH_FUDGE_FULL;
|
|
+ nic->tcp_wild_srch.needed = 0;
|
|
+ nic->tcp_wild_srch.max = RX_FILTER_CTL_SRCH_LIMIT_TCP_WILD
|
|
+ - RX_FILTER_CTL_SRCH_FUDGE_WILD;
|
|
+ nic->udp_full_srch.needed = 0;
|
|
+ nic->udp_full_srch.max = RX_FILTER_CTL_SRCH_LIMIT_UDP_FULL
|
|
+ - RX_FILTER_CTL_SRCH_FUDGE_FULL;
|
|
+ nic->udp_wild_srch.needed = 0;
|
|
+ nic->udp_wild_srch.max = RX_FILTER_CTL_SRCH_LIMIT_UDP_WILD
|
|
+ - RX_FILTER_CTL_SRCH_FUDGE_WILD;
|
|
+
|
|
+ nic->filter_in_use = vmalloc(FALCON_FILTER_TBL_NUM);
|
|
+ if (nic->filter_in_use == NULL)
|
|
+ return -ENOMEM;
|
|
+ memset(nic->filter_in_use, 0, FALCON_FILTER_TBL_NUM);
|
|
+#if FALCON_FULL_FILTER_CACHE
|
|
+ nic->filter_spec_cache = vmalloc(FALCON_FILTER_TBL_NUM
|
|
+ * sizeof(struct efhw_filter_spec));
|
|
+ if (nic->filter_spec_cache == NULL)
|
|
+ return -ENOMEM;
|
|
+ memset(nic->filter_spec_cache, 0, FALCON_FILTER_TBL_NUM
|
|
+ * sizeof(struct efhw_filter_spec));
|
|
+#endif
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+void
|
|
+falcon_nic_filter_dtor(struct efhw_nic *nic)
|
|
+{
|
|
+#if FALCON_FULL_FILTER_CACHE
|
|
+ if (nic->filter_spec_cache)
|
|
+ vfree(nic->filter_spec_cache);
|
|
+#endif
|
|
+ if (nic->filter_in_use)
|
|
+ vfree(nic->filter_in_use);
|
|
+}
|
|
+
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * Compatibility with old filter API
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+void
|
|
+falcon_nic_rx_filter_ctl_get(struct efhw_nic *nic, uint32_t *tcp_full,
|
|
+ uint32_t *tcp_wild,
|
|
+ uint32_t *udp_full, uint32_t *udp_wild)
|
|
+{
|
|
+ struct efhw_filter_search_limits lim;
|
|
+
|
|
+ falcon_nic_get_rx_filter_search_limits(nic, &lim, 0);
|
|
+ *tcp_full = (uint32_t)lim.tcp_full;
|
|
+ *tcp_wild = (uint32_t)lim.tcp_wild;
|
|
+ *udp_full = (uint32_t)lim.udp_full;
|
|
+ *udp_wild = (uint32_t)lim.udp_wild;
|
|
+}
|
|
+EXPORT_SYMBOL(falcon_nic_rx_filter_ctl_get);
|
|
+
|
|
+
|
|
+void
|
|
+falcon_nic_rx_filter_ctl_set(struct efhw_nic *nic, uint32_t tcp_full,
|
|
+ uint32_t tcp_wild,
|
|
+ uint32_t udp_full, uint32_t udp_wild)
|
|
+{
|
|
+ struct efhw_filter_search_limits lim;
|
|
+
|
|
+ lim.tcp_full = (unsigned)tcp_full;
|
|
+ lim.tcp_wild = (unsigned)tcp_wild;
|
|
+ lim.udp_full = (unsigned)udp_full;
|
|
+ lim.udp_wild = (unsigned)udp_wild;
|
|
+ falcon_nic_set_rx_filter_search_limits(nic, &lim, 0);
|
|
+}
|
|
+EXPORT_SYMBOL(falcon_nic_rx_filter_ctl_set);
|
|
+
|
|
+
|
|
+static int
|
|
+falcon_nic_ipfilter_set(struct efhw_nic *nic, int type, int *_filter_idx,
|
|
+ int dmaq,
|
|
+ unsigned saddr_be32, unsigned sport_be16,
|
|
+ unsigned daddr_be32, unsigned dport_be16)
|
|
+{
|
|
+ struct efhw_filter_spec spec;
|
|
+
|
|
+ spec.dmaq_id = dmaq;
|
|
+ spec.saddr_le32 = ntohl(saddr_be32);
|
|
+ spec.daddr_le32 = ntohl(daddr_be32);
|
|
+ spec.sport_le16 = ntohs((unsigned short) sport_be16);
|
|
+ spec.dport_le16 = ntohs((unsigned short) dport_be16);
|
|
+ spec.tcp = ((type & EFHW_IP_FILTER_TYPE_TCP_MASK) != 0);
|
|
+ spec.full = ((type & EFHW_IP_FILTER_TYPE_FULL_MASK) != 0);
|
|
+ spec.rss = ((type & EFHW_IP_FILTER_TYPE_RSS_B0_MASK) != 0);
|
|
+ spec.scatter = ((type & EFHW_IP_FILTER_TYPE_NOSCAT_B0_MASK) == 0);
|
|
+ return falcon_nic_filter_set(nic, &spec, _filter_idx);
|
|
+}
|
|
+
|
|
+static void falcon_nic_ipfilter_clear(struct efhw_nic *nic, int filter_idx)
|
|
+{
|
|
+ falcon_nic_filter_clear(nic, filter_idx);
|
|
+}
|
|
+
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * Abstraction Layer Hooks
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+struct efhw_func_ops falcon_char_functional_units = {
|
|
+ falcon_nic_close_hardware,
|
|
+ falcon_nic_init_hardware,
|
|
+ falcon_nic_interrupt,
|
|
+ falcon_nic_interrupt_enable,
|
|
+ falcon_nic_interrupt_disable,
|
|
+ falcon_nic_set_interrupt_moderation,
|
|
+ falcon_nic_event_queue_enable,
|
|
+ falcon_nic_event_queue_disable,
|
|
+ falcon_nic_wakeup_request,
|
|
+ falcon_nic_sw_event,
|
|
+ falcon_nic_ipfilter_set,
|
|
+ falcon_nic_ipfilter_clear,
|
|
+ falcon_dmaq_tx_q_init,
|
|
+ falcon_dmaq_rx_q_init,
|
|
+ falcon_dmaq_tx_q_disable,
|
|
+ falcon_dmaq_rx_q_disable,
|
|
+ falcon_flush_tx_dma_channel,
|
|
+ falcon_flush_rx_dma_channel,
|
|
+ falcon_nic_buffer_table_set,
|
|
+ falcon_nic_buffer_table_set_n,
|
|
+ falcon_nic_buffer_table_clear,
|
|
+ falcon_nic_buffer_table_commit,
|
|
+ falcon_nic_filter_set,
|
|
+ falcon_nic_filter_clear,
|
|
+};
|
|
+
|
|
+
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/falcon_hash.c 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,159 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file contains EtherFabric NIC hash algorithms implementation.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#include <ci/efhw/debug.h>
|
|
+#include <ci/driver/efab/hardware.h>
|
|
+
|
|
+
|
|
+static unsigned int
|
|
+common_get_ip_key(unsigned int src_ip, unsigned int src_port,
|
|
+ unsigned int dest_ip, unsigned int dest_port,
|
|
+ int tcp, int full, int tx, unsigned int masked_q_id)
|
|
+{
|
|
+
|
|
+ unsigned int tmp_port, result;
|
|
+
|
|
+ EFHW_ASSERT(tcp == 0 || tcp == 1);
|
|
+ EFHW_ASSERT(full == 0 || full == 1);
|
|
+ EFHW_ASSERT(masked_q_id < (1 << 10));
|
|
+
|
|
+ /* m=masked_q_id(TX)/0(RX) u=UDP S,D=src/dest addr s,d=src/dest port
|
|
+ *
|
|
+ * Wildcard filters have src(TX)/dest(RX) addr and port = 0;
|
|
+ * and UDP wildcard filters have the src and dest port fields swapped.
|
|
+ *
|
|
+ * Addr/port fields are little-endian.
|
|
+ *
|
|
+ * 3322222222221111111111
|
|
+ * 10987654321098765432109876543210
|
|
+ *
|
|
+ * 000000000000000000000mmmmmmmmmmu ^
|
|
+ * DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD ^
|
|
+ * ddddddddddddddddSSSSSSSSSSSSSSSS ^
|
|
+ * SSSSSSSSSSSSSSSSssssssssssssssss
|
|
+ */
|
|
+
|
|
+ if (!tx)
|
|
+ masked_q_id = 0;
|
|
+
|
|
+ if (!full) {
|
|
+ if (tx) {
|
|
+ dest_ip = 0;
|
|
+ dest_port = 0;
|
|
+ } else {
|
|
+ src_ip = 0;
|
|
+ src_port = 0;
|
|
+ }
|
|
+ if (!tcp) {
|
|
+ tmp_port = src_port;
|
|
+ src_port = dest_port;
|
|
+ dest_port = tmp_port;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ result = ((masked_q_id << 1) | (!tcp)) ^
|
|
+ (dest_ip) ^
|
|
+ (((dest_port & 0xffff) << 16) | ((src_ip >> 16) & 0xffff)) ^
|
|
+ (((src_ip & 0xffff) << 16) | (src_port & 0xffff));
|
|
+
|
|
+ EFHW_TRACE("%s: IP %s %s %x", __func__, tcp ? "TCP" : "UDP",
|
|
+ full ? "Full" : "Wildcard", result);
|
|
+
|
|
+ return result;
|
|
+}
|
|
+
|
|
+
|
|
+unsigned int
|
|
+falcon_hash_get_ip_key(unsigned int src_ip, unsigned int src_port,
|
|
+ unsigned int dest_ip, unsigned int dest_port,
|
|
+ int tcp, int full)
|
|
+{
|
|
+ return common_get_ip_key(src_ip, src_port, dest_ip, dest_port, tcp,
|
|
+ full, 0, 0);
|
|
+}
|
|
+
|
|
+
|
|
+/* This function generates the First Hash key */
|
|
+unsigned int falcon_hash_function1(unsigned int key, unsigned int nfilters)
|
|
+{
|
|
+
|
|
+ unsigned short int lfsr_reg;
|
|
+ unsigned int tmp_key;
|
|
+ int index;
|
|
+
|
|
+ unsigned short int lfsr_input;
|
|
+ unsigned short int single_bit_key;
|
|
+ unsigned short int bit16_lfsr;
|
|
+ unsigned short int bit3_lfsr;
|
|
+
|
|
+ lfsr_reg = 0xFFFF;
|
|
+ tmp_key = key;
|
|
+
|
|
+ /* For Polynomial equation X^16+X^3+1 */
|
|
+ for (index = 0; index < 32; index++) {
|
|
+ /* Get the bit from key and shift the key */
|
|
+ single_bit_key = (tmp_key & 0x80000000) >> 31;
|
|
+ tmp_key = tmp_key << 1;
|
|
+
|
|
+ /* get the Tap bits to XOR operation */
|
|
+ bit16_lfsr = (lfsr_reg & 0x8000) >> 15;
|
|
+ bit3_lfsr = (lfsr_reg & 0x0004) >> 2;
|
|
+
|
|
+ /* Get the Input value to the LFSR */
|
|
+ lfsr_input = ((bit16_lfsr ^ bit3_lfsr) ^ single_bit_key);
|
|
+
|
|
+ /* Shift and store out of the two TAPs */
|
|
+ lfsr_reg = lfsr_reg << 1;
|
|
+ lfsr_reg = lfsr_reg | (lfsr_input & 0x0001);
|
|
+
|
|
+ }
|
|
+
|
|
+ lfsr_reg = lfsr_reg & (nfilters - 1);
|
|
+
|
|
+ return lfsr_reg;
|
|
+}
|
|
+
|
|
+/* This function generates the Second Hash */
|
|
+unsigned int
|
|
+falcon_hash_function2(unsigned int key, unsigned int nfilters)
|
|
+{
|
|
+ return (unsigned int)(((unsigned long long)key * 2 - 1) &
|
|
+ (nfilters - 1));
|
|
+}
|
|
+
|
|
+/* This function iterates through the hash table */
|
|
+unsigned int
|
|
+falcon_hash_iterator(unsigned int hash1, unsigned int hash2,
|
|
+ unsigned int n_search, unsigned int nfilters)
|
|
+{
|
|
+ return (hash1 + (n_search * hash2)) & (nfilters - 1);
|
|
+}
|
|
+
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/filter_resource.c 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,250 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file contains filters support.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#include <ci/efrm/nic_table.h>
|
|
+#include <ci/driver/efab/hardware.h>
|
|
+#include <ci/efhw/falcon.h>
|
|
+#include <ci/efrm/vi_resource_manager.h>
|
|
+#include <ci/efrm/private.h>
|
|
+#include <ci/efrm/filter.h>
|
|
+#include <ci/efrm/buffer_table.h>
|
|
+#include <ci/efrm/efrm_client.h>
|
|
+#include "efrm_internal.h"
|
|
+
|
|
+
|
|
+struct filter_resource_manager {
|
|
+ struct efrm_resource_manager rm;
|
|
+ struct kfifo *free_ids;
|
|
+};
|
|
+
|
|
+static struct filter_resource_manager *efrm_filter_manager;
|
|
+
|
|
+
|
|
+void efrm_filter_resource_free(struct filter_resource *frs)
|
|
+{
|
|
+ struct efhw_nic *nic = frs->rs.rs_client->nic;
|
|
+ int id;
|
|
+
|
|
+ EFRM_RESOURCE_ASSERT_VALID(&frs->rs, 1);
|
|
+
|
|
+ EFRM_TRACE("%s: " EFRM_RESOURCE_FMT, __func__,
|
|
+ EFRM_RESOURCE_PRI_ARG(frs->rs.rs_handle));
|
|
+
|
|
+ efhw_nic_ipfilter_clear(nic, frs->filter_idx);
|
|
+ frs->filter_idx = -1;
|
|
+ efrm_vi_resource_release(frs->pt);
|
|
+
|
|
+ /* Free this filter. */
|
|
+ id = EFRM_RESOURCE_INSTANCE(frs->rs.rs_handle);
|
|
+ EFRM_VERIFY_EQ(kfifo_put(efrm_filter_manager->free_ids,
|
|
+ (unsigned char *)&id, sizeof(id)),
|
|
+ sizeof(id));
|
|
+
|
|
+ efrm_client_put(frs->rs.rs_client);
|
|
+ EFRM_DO_DEBUG(memset(frs, 0, sizeof(*frs)));
|
|
+ kfree(frs);
|
|
+}
|
|
+EXPORT_SYMBOL(efrm_filter_resource_free);
|
|
+
|
|
+
|
|
+void efrm_filter_resource_release(struct filter_resource *frs)
|
|
+{
|
|
+ if (__efrm_resource_release(&frs->rs))
|
|
+ efrm_filter_resource_free(frs);
|
|
+}
|
|
+EXPORT_SYMBOL(efrm_filter_resource_release);
|
|
+
|
|
+
|
|
+static void filter_rm_dtor(struct efrm_resource_manager *rm)
|
|
+{
|
|
+ EFRM_TRACE("%s:", __func__);
|
|
+
|
|
+ EFRM_RESOURCE_MANAGER_ASSERT_VALID(&efrm_filter_manager->rm);
|
|
+ EFRM_ASSERT(&efrm_filter_manager->rm == rm);
|
|
+
|
|
+ kfifo_vfree(efrm_filter_manager->free_ids);
|
|
+ EFRM_TRACE("%s: done", __func__);
|
|
+}
|
|
+
|
|
+/**********************************************************************/
|
|
+/**********************************************************************/
|
|
+/**********************************************************************/
|
|
+
|
|
+int efrm_create_filter_resource_manager(struct efrm_resource_manager **rm_out)
|
|
+{
|
|
+ int rc;
|
|
+
|
|
+ EFRM_ASSERT(rm_out);
|
|
+
|
|
+ efrm_filter_manager =
|
|
+ kmalloc(sizeof(struct filter_resource_manager), GFP_KERNEL);
|
|
+ if (efrm_filter_manager == 0)
|
|
+ return -ENOMEM;
|
|
+ memset(efrm_filter_manager, 0, sizeof(*efrm_filter_manager));
|
|
+
|
|
+ rc = efrm_resource_manager_ctor(&efrm_filter_manager->rm,
|
|
+ filter_rm_dtor, "FILTER",
|
|
+ EFRM_RESOURCE_FILTER);
|
|
+ if (rc < 0)
|
|
+ goto fail1;
|
|
+
|
|
+ /* Create a pool of free instances */
|
|
+ rc = efrm_kfifo_id_ctor(&efrm_filter_manager->free_ids,
|
|
+ 0, EFHW_IP_FILTER_NUM,
|
|
+ &efrm_filter_manager->rm.rm_lock);
|
|
+ if (rc != 0)
|
|
+ goto fail2;
|
|
+
|
|
+ *rm_out = &efrm_filter_manager->rm;
|
|
+ EFRM_TRACE("%s: filter resources created - %d IDs",
|
|
+ __func__, kfifo_len(efrm_filter_manager->free_ids));
|
|
+ return 0;
|
|
+
|
|
+fail2:
|
|
+ efrm_resource_manager_dtor(&efrm_filter_manager->rm);
|
|
+fail1:
|
|
+ memset(efrm_filter_manager, 0, sizeof(*efrm_filter_manager));
|
|
+ kfree(efrm_filter_manager);
|
|
+ return rc;
|
|
+
|
|
+}
|
|
+
|
|
+
|
|
+int efrm_filter_resource_clear(struct filter_resource *frs)
|
|
+{
|
|
+ struct efhw_nic *nic = frs->rs.rs_client->nic;
|
|
+
|
|
+ efhw_nic_ipfilter_clear(nic, frs->filter_idx);
|
|
+ frs->filter_idx = -1;
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL(efrm_filter_resource_clear);
|
|
+
|
|
+
|
|
+int
|
|
+__efrm_filter_resource_set(struct filter_resource *frs, int type,
|
|
+ unsigned saddr, uint16_t sport,
|
|
+ unsigned daddr, uint16_t dport)
|
|
+{
|
|
+ struct efhw_nic *nic = frs->rs.rs_client->nic;
|
|
+ int vi_instance;
|
|
+
|
|
+ EFRM_ASSERT(frs);
|
|
+
|
|
+ if (efrm_nic_tablep->a_nic->devtype.variant >= 'B' &&
|
|
+ (frs->pt->flags & EFHW_VI_JUMBO_EN) == 0)
|
|
+ type |= EFHW_IP_FILTER_TYPE_NOSCAT_B0_MASK;
|
|
+ vi_instance = EFRM_RESOURCE_INSTANCE(frs->pt->rs.rs_handle);
|
|
+
|
|
+ return efhw_nic_ipfilter_set(nic, type, &frs->filter_idx,
|
|
+ vi_instance, saddr, sport, daddr, dport);
|
|
+}
|
|
+EXPORT_SYMBOL(__efrm_filter_resource_set);;
|
|
+
|
|
+
|
|
+int
|
|
+efrm_filter_resource_alloc(struct vi_resource *vi_parent,
|
|
+ struct filter_resource **frs_out)
|
|
+{
|
|
+ struct filter_resource *frs;
|
|
+ int rc, instance;
|
|
+
|
|
+ EFRM_ASSERT(frs_out);
|
|
+ EFRM_ASSERT(efrm_filter_manager);
|
|
+ EFRM_RESOURCE_MANAGER_ASSERT_VALID(&efrm_filter_manager->rm);
|
|
+ EFRM_ASSERT(vi_parent != NULL);
|
|
+ EFRM_ASSERT(EFRM_RESOURCE_TYPE(vi_parent->rs.rs_handle) ==
|
|
+ EFRM_RESOURCE_VI);
|
|
+
|
|
+ /* Allocate resource data structure. */
|
|
+ frs = kmalloc(sizeof(struct filter_resource), GFP_KERNEL);
|
|
+ if (!frs)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ /* Allocate an instance. */
|
|
+ rc = kfifo_get(efrm_filter_manager->free_ids,
|
|
+ (unsigned char *)&instance, sizeof(instance));
|
|
+ if (rc != sizeof(instance)) {
|
|
+ EFRM_TRACE("%s: out of instances", __func__);
|
|
+ EFRM_ASSERT(rc == 0);
|
|
+ rc = -EBUSY;
|
|
+ goto fail1;
|
|
+ }
|
|
+
|
|
+ /* Initialise the resource DS. */
|
|
+ efrm_resource_init(&frs->rs, EFRM_RESOURCE_FILTER, instance);
|
|
+ frs->pt = vi_parent;
|
|
+ efrm_resource_ref(&frs->pt->rs);
|
|
+ frs->filter_idx = -1;
|
|
+
|
|
+ EFRM_TRACE("%s: " EFRM_RESOURCE_FMT " VI %d", __func__,
|
|
+ EFRM_RESOURCE_PRI_ARG(frs->rs.rs_handle),
|
|
+ EFRM_RESOURCE_INSTANCE(vi_parent->rs.rs_handle));
|
|
+
|
|
+ efrm_client_add_resource(vi_parent->rs.rs_client, &frs->rs);
|
|
+ *frs_out = frs;
|
|
+ return 0;
|
|
+
|
|
+fail1:
|
|
+ memset(frs, 0, sizeof(*frs));
|
|
+ kfree(frs);
|
|
+ return rc;
|
|
+}
|
|
+EXPORT_SYMBOL(efrm_filter_resource_alloc);
|
|
+
|
|
+
|
|
+int efrm_filter_resource_instance(struct filter_resource *frs)
|
|
+{
|
|
+ return EFRM_RESOURCE_INSTANCE(frs->rs.rs_handle);
|
|
+}
|
|
+EXPORT_SYMBOL(efrm_filter_resource_instance);
|
|
+
|
|
+
|
|
+struct efrm_resource *
|
|
+efrm_filter_resource_to_resource(struct filter_resource *frs)
|
|
+{
|
|
+ return &frs->rs;
|
|
+}
|
|
+EXPORT_SYMBOL(efrm_filter_resource_to_resource);
|
|
+
|
|
+
|
|
+struct filter_resource *
|
|
+efrm_filter_resource_from_resource(struct efrm_resource *rs)
|
|
+{
|
|
+ return filter_resource(rs);
|
|
+}
|
|
+EXPORT_SYMBOL(efrm_filter_resource_from_resource);
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/iobufset_resource.c 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,404 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file contains non-contiguous I/O buffers support.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#include <ci/efrm/nic_table.h>
|
|
+#include <ci/efhw/iopage.h>
|
|
+#include <ci/driver/efab/hardware.h>
|
|
+#include <ci/efrm/private.h>
|
|
+#include <ci/efrm/iobufset.h>
|
|
+#include <ci/efrm/vi_resource_manager.h>
|
|
+#include <ci/efrm/buffer_table.h>
|
|
+#include <ci/efrm/efrm_client.h>
|
|
+#include "efrm_internal.h"
|
|
+
|
|
+
|
|
+#define EFRM_IOBUFSET_MAX_NUM_INSTANCES 0x00010000
|
|
+
|
|
+struct iobufset_resource_manager {
|
|
+ struct efrm_resource_manager rm;
|
|
+ struct kfifo *free_ids;
|
|
+};
|
|
+
|
|
+struct iobufset_resource_manager *efrm_iobufset_manager;
|
|
+
|
|
+#define iobsrs(rs1) iobufset_resource(rs1)
|
|
+
|
|
+/* Returns size of iobufset resource data structure. */
|
|
+static inline size_t iobsrs_size(int n_pages)
|
|
+{
|
|
+ return offsetof(struct iobufset_resource, bufs) +
|
|
+ n_pages * sizeof(struct efhw_iopage);
|
|
+}
|
|
+
|
|
+void efrm_iobufset_resource_free(struct iobufset_resource *rs)
|
|
+{
|
|
+ unsigned int i;
|
|
+ int id;
|
|
+
|
|
+ EFRM_RESOURCE_ASSERT_VALID(&rs->rs, 1);
|
|
+
|
|
+ if (!rs->linked && rs->buf_tbl_alloc.base != (unsigned) -1)
|
|
+ efrm_buffer_table_free(&rs->buf_tbl_alloc);
|
|
+
|
|
+ /* see comment on call to efhw_iopage_alloc in the alloc routine above
|
|
+ for discussion on use of efrm_nic_tablep->a_nic here */
|
|
+ EFRM_ASSERT(efrm_nic_tablep->a_nic);
|
|
+ if (rs->linked) {
|
|
+ /* Nothing to do. */
|
|
+ } else if (rs->chunk_order == 0) {
|
|
+ for (i = 0; i < rs->n_bufs; ++i)
|
|
+ efhw_iopage_free(efrm_nic_tablep->a_nic, &rs->bufs[i]);
|
|
+ } else {
|
|
+ /* it is important that this is executed in increasing page
|
|
+ * order because some implementations of
|
|
+ * efhw_iopages_init_from_iopage() assume this */
|
|
+ for (i = 0; i < rs->n_bufs;
|
|
+ i += rs->pages_per_contiguous_chunk) {
|
|
+ struct efhw_iopages iopages;
|
|
+ efhw_iopages_init_from_iopage(&iopages, &rs->bufs[i],
|
|
+ rs->chunk_order);
|
|
+ efhw_iopages_free(efrm_nic_tablep->a_nic, &iopages);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* free the instance number */
|
|
+ id = EFRM_RESOURCE_INSTANCE(rs->rs.rs_handle);
|
|
+ EFRM_VERIFY_EQ(kfifo_put(efrm_iobufset_manager->free_ids,
|
|
+ (unsigned char *)&id, sizeof(id)), sizeof(id));
|
|
+
|
|
+ efrm_vi_resource_release(rs->evq);
|
|
+ if (rs->linked)
|
|
+ efrm_iobufset_resource_release(rs->linked);
|
|
+
|
|
+ efrm_client_put(rs->rs.rs_client);
|
|
+ if (iobsrs_size(rs->n_bufs) < PAGE_SIZE) {
|
|
+ EFRM_DO_DEBUG(memset(rs, 0, sizeof(*rs)));
|
|
+ kfree(rs);
|
|
+ } else {
|
|
+ EFRM_DO_DEBUG(memset(rs, 0, sizeof(*rs)));
|
|
+ vfree(rs);
|
|
+ }
|
|
+}
|
|
+EXPORT_SYMBOL(efrm_iobufset_resource_free);
|
|
+
|
|
+
|
|
+void efrm_iobufset_resource_release(struct iobufset_resource *iobrs)
|
|
+{
|
|
+ if (__efrm_resource_release(&iobrs->rs))
|
|
+ efrm_iobufset_resource_free(iobrs);
|
|
+}
|
|
+EXPORT_SYMBOL(efrm_iobufset_resource_release);
|
|
+
|
|
+
|
|
+
|
|
+int
|
|
+efrm_iobufset_resource_alloc(int32_t n_pages,
|
|
+ int32_t pages_per_contiguous_chunk,
|
|
+ struct vi_resource *vi_evq,
|
|
+ struct iobufset_resource *linked,
|
|
+ bool phys_addr_mode,
|
|
+ struct iobufset_resource **iobrs_out)
|
|
+{
|
|
+ struct iobufset_resource *iobrs;
|
|
+ int rc, instance, object_size;
|
|
+ unsigned int i;
|
|
+
|
|
+ EFRM_ASSERT(iobrs_out);
|
|
+ EFRM_ASSERT(efrm_iobufset_manager);
|
|
+ EFRM_RESOURCE_MANAGER_ASSERT_VALID(&efrm_iobufset_manager->rm);
|
|
+ EFRM_RESOURCE_ASSERT_VALID(&vi_evq->rs, 0);
|
|
+ EFRM_ASSERT(EFRM_RESOURCE_TYPE(vi_evq->rs.rs_handle) ==
|
|
+ EFRM_RESOURCE_VI);
|
|
+ EFRM_ASSERT(efrm_nic_tablep->a_nic);
|
|
+
|
|
+ if (linked) {
|
|
+ /* This resource will share properties and memory with
|
|
+ * another. Only difference is that we'll program it into
|
|
+ * the buffer table of another nic.
|
|
+ */
|
|
+ n_pages = linked->n_bufs;
|
|
+ pages_per_contiguous_chunk = linked->pages_per_contiguous_chunk;
|
|
+ phys_addr_mode = linked->buf_tbl_alloc.base == (unsigned) -1;
|
|
+ }
|
|
+
|
|
+ /* allocate the resource data structure. */
|
|
+ object_size = iobsrs_size(n_pages);
|
|
+ if (object_size < PAGE_SIZE) {
|
|
+ /* this should be OK from a tasklet */
|
|
+ /* Necessary to do atomic alloc() as this
|
|
+ can be called from a weird-ass iSCSI context that is
|
|
+ !in_interrupt but is in_atomic - See BUG3163 */
|
|
+ iobrs = kmalloc(object_size, GFP_ATOMIC);
|
|
+ } else { /* can't do this within a tasklet */
|
|
+#ifndef NDEBUG
|
|
+ if (in_interrupt() || in_atomic()) {
|
|
+ EFRM_ERR("%s(): alloc->u.iobufset.in_n_pages=%d",
|
|
+ __func__, n_pages);
|
|
+ EFRM_ASSERT(!in_interrupt());
|
|
+ EFRM_ASSERT(!in_atomic());
|
|
+ }
|
|
+#endif
|
|
+ iobrs = (struct iobufset_resource *) vmalloc(object_size);
|
|
+ }
|
|
+ if (iobrs == NULL) {
|
|
+ EFRM_WARN("%s: failed to allocate container", __func__);
|
|
+ rc = -ENOMEM;
|
|
+ goto fail1;
|
|
+ }
|
|
+
|
|
+ /* Allocate an instance number. */
|
|
+ rc = kfifo_get(efrm_iobufset_manager->free_ids,
|
|
+ (unsigned char *)&instance, sizeof(instance));
|
|
+ if (rc != sizeof(instance)) {
|
|
+ EFRM_WARN("%s: out of instances", __func__);
|
|
+ EFRM_ASSERT(rc == 0);
|
|
+ rc = -EBUSY;
|
|
+ goto fail3;
|
|
+ }
|
|
+
|
|
+ efrm_resource_init(&iobrs->rs, EFRM_RESOURCE_IOBUFSET, instance);
|
|
+
|
|
+ iobrs->evq = vi_evq;
|
|
+ iobrs->linked = linked;
|
|
+ iobrs->n_bufs = n_pages;
|
|
+ iobrs->pages_per_contiguous_chunk = pages_per_contiguous_chunk;
|
|
+ iobrs->chunk_order = fls(iobrs->pages_per_contiguous_chunk - 1);
|
|
+ iobrs->buf_tbl_alloc.base = (unsigned) -1;
|
|
+
|
|
+ EFRM_TRACE("%s: " EFRM_RESOURCE_FMT " %u pages", __func__,
|
|
+ EFRM_RESOURCE_PRI_ARG(iobrs->rs.rs_handle), iobrs->n_bufs);
|
|
+
|
|
+ /* Allocate the iobuffers. */
|
|
+ if (linked) {
|
|
+ memcpy(iobrs->bufs, linked->bufs,
|
|
+ iobrs->n_bufs * sizeof(iobrs->bufs[0]));
|
|
+ } else if (iobrs->chunk_order == 0) {
|
|
+ memset(iobrs->bufs, 0, iobrs->n_bufs * sizeof(iobrs->bufs[0]));
|
|
+ for (i = 0; i < iobrs->n_bufs; ++i) {
|
|
+ /* due to bug2426 we have to specifiy a NIC when
|
|
+ * allocating a DMAable page, which is a bit messy.
|
|
+ * For now we assume that if the page is suitable
|
|
+ * (e.g. DMAable) by one nic (efrm_nic_tablep->a_nic),
|
|
+ * it is suitable for all NICs.
|
|
+ * XXX I bet that breaks in Solaris.
|
|
+ */
|
|
+ rc = efhw_iopage_alloc(efrm_nic_tablep->a_nic,
|
|
+ &iobrs->bufs[i]);
|
|
+ if (rc < 0) {
|
|
+ EFRM_WARN("%s: failed (rc %d) to allocate "
|
|
+ "page (i=%u)", __func__, rc, i);
|
|
+ goto fail4;
|
|
+ }
|
|
+ }
|
|
+ } else {
|
|
+ struct efhw_iopages iopages;
|
|
+ unsigned j;
|
|
+
|
|
+ memset(iobrs->bufs, 0, iobrs->n_bufs * sizeof(iobrs->bufs[0]));
|
|
+ for (i = 0; i < iobrs->n_bufs;
|
|
+ i += iobrs->pages_per_contiguous_chunk) {
|
|
+ rc = efhw_iopages_alloc(efrm_nic_tablep->a_nic,
|
|
+ &iopages, iobrs->chunk_order);
|
|
+ if (rc < 0) {
|
|
+ EFRM_WARN("%s: failed (rc %d) to allocate "
|
|
+ "pages (i=%u order %d)",
|
|
+ __func__, rc, i,
|
|
+ iobrs->chunk_order);
|
|
+ goto fail4;
|
|
+ }
|
|
+ for (j = 0; j < iobrs->pages_per_contiguous_chunk;
|
|
+ j++) {
|
|
+ /* some implementation of
|
|
+ * efhw_iopage_init_from_iopages() rely on
|
|
+ * this function being called for
|
|
+ * _all_ pages in the chunk */
|
|
+ efhw_iopage_init_from_iopages(
|
|
+ &iobrs->bufs[i + j],
|
|
+ &iopages, j);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!phys_addr_mode) {
|
|
+ unsigned owner_id = EFAB_VI_RESOURCE_INSTANCE(iobrs->evq);
|
|
+
|
|
+ if (!linked) {
|
|
+ /* Allocate space in the NIC's buffer table. */
|
|
+ rc = efrm_buffer_table_alloc(fls(iobrs->n_bufs - 1),
|
|
+ &iobrs->buf_tbl_alloc);
|
|
+ if (rc < 0) {
|
|
+ EFRM_WARN("%s: failed (%d) to alloc %d buffer "
|
|
+ "table entries", __func__, rc,
|
|
+ iobrs->n_bufs);
|
|
+ goto fail5;
|
|
+ }
|
|
+ EFRM_ASSERT(((unsigned)1 << iobrs->buf_tbl_alloc.order)
|
|
+ >= (unsigned) iobrs->n_bufs);
|
|
+ } else {
|
|
+ iobrs->buf_tbl_alloc = linked->buf_tbl_alloc;
|
|
+ }
|
|
+
|
|
+ /* Initialise the buffer table entries. */
|
|
+ for (i = 0; i < iobrs->n_bufs; ++i) {
|
|
+ /*\ ?? \TODO burst them! */
|
|
+ efrm_buffer_table_set(&iobrs->buf_tbl_alloc,
|
|
+ vi_evq->rs.rs_client->nic,
|
|
+ i,
|
|
+ efhw_iopage_dma_addr(&iobrs->
|
|
+ bufs[i]),
|
|
+ owner_id);
|
|
+ }
|
|
+ efrm_buffer_table_commit();
|
|
+ }
|
|
+
|
|
+ EFRM_TRACE("%s: " EFRM_RESOURCE_FMT " %d pages @ "
|
|
+ EFHW_BUFFER_ADDR_FMT, __func__,
|
|
+ EFRM_RESOURCE_PRI_ARG(iobrs->rs.rs_handle),
|
|
+ iobrs->n_bufs, EFHW_BUFFER_ADDR(iobrs->buf_tbl_alloc.base,
|
|
+ 0));
|
|
+ efrm_resource_ref(&iobrs->evq->rs);
|
|
+ if (linked != NULL)
|
|
+ efrm_resource_ref(&linked->rs);
|
|
+ efrm_client_add_resource(vi_evq->rs.rs_client, &iobrs->rs);
|
|
+ *iobrs_out = iobrs;
|
|
+ return 0;
|
|
+
|
|
+fail5:
|
|
+ i = iobrs->n_bufs;
|
|
+fail4:
|
|
+ /* see comment on call to efhw_iopage_alloc above for a discussion
|
|
+ * on use of efrm_nic_tablep->a_nic here */
|
|
+ if (linked) {
|
|
+ /* Nothing to do. */
|
|
+ } else if (iobrs->chunk_order == 0) {
|
|
+ while (i--) {
|
|
+ struct efhw_iopage *page = &iobrs->bufs[i];
|
|
+ efhw_iopage_free(efrm_nic_tablep->a_nic, page);
|
|
+ }
|
|
+ } else {
|
|
+ unsigned int j;
|
|
+ for (j = 0; j < i; j += iobrs->pages_per_contiguous_chunk) {
|
|
+ struct efhw_iopages iopages;
|
|
+
|
|
+ EFRM_ASSERT(j % iobrs->pages_per_contiguous_chunk
|
|
+ == 0);
|
|
+ /* it is important that this is executed in increasing
|
|
+ * page order because some implementations of
|
|
+ * efhw_iopages_init_from_iopage() assume this */
|
|
+ efhw_iopages_init_from_iopage(&iopages,
|
|
+ &iobrs->bufs[j],
|
|
+ iobrs->chunk_order);
|
|
+ efhw_iopages_free(efrm_nic_tablep->a_nic, &iopages);
|
|
+ }
|
|
+ }
|
|
+fail3:
|
|
+ if (object_size < PAGE_SIZE)
|
|
+ kfree(iobrs);
|
|
+ else
|
|
+ vfree(iobrs);
|
|
+fail1:
|
|
+ return rc;
|
|
+}
|
|
+EXPORT_SYMBOL(efrm_iobufset_resource_alloc);
|
|
+
|
|
+static void iobufset_rm_dtor(struct efrm_resource_manager *rm)
|
|
+{
|
|
+ EFRM_ASSERT(&efrm_iobufset_manager->rm == rm);
|
|
+ kfifo_vfree(efrm_iobufset_manager->free_ids);
|
|
+}
|
|
+
|
|
+int
|
|
+efrm_create_iobufset_resource_manager(struct efrm_resource_manager **rm_out)
|
|
+{
|
|
+ int rc, max;
|
|
+
|
|
+ EFRM_ASSERT(rm_out);
|
|
+
|
|
+ efrm_iobufset_manager =
|
|
+ kmalloc(sizeof(*efrm_iobufset_manager), GFP_KERNEL);
|
|
+ if (efrm_iobufset_manager == 0)
|
|
+ return -ENOMEM;
|
|
+ memset(efrm_iobufset_manager, 0, sizeof(*efrm_iobufset_manager));
|
|
+
|
|
+ /*
|
|
+ * Bug 1145, 1370: We need to set initial size of both the resource
|
|
+ * table and instance id table so they never need to grow as we
|
|
+ * want to be allocate new iobufset at tasklet time. Lets make
|
|
+ * a pessimistic guess at maximum number of iobufsets possible.
|
|
+ * Could be less because
|
|
+ * - jumbo frames have same no of packets per iobufset BUT more
|
|
+ * pages per buffer
|
|
+ * - buffer table entries used independently of iobufsets by
|
|
+ * sendfile
|
|
+ *
|
|
+ * Based on TCP/IP stack setting of PKTS_PER_SET_S=5 ...
|
|
+ * - can't use this define here as it breaks the layering.
|
|
+ */
|
|
+#define MIN_PAGES_PER_IOBUFSET (1 << 4)
|
|
+
|
|
+ max = efrm_buffer_table_size() / MIN_PAGES_PER_IOBUFSET;
|
|
+ max = min_t(int, max, EFRM_IOBUFSET_MAX_NUM_INSTANCES);
|
|
+
|
|
+ /* HACK: There currently exists an option to allocate buffers that
|
|
+ * are not programmed into the buffer table, so the max number is
|
|
+ * not limited by the buffer table size. I'm hoping this usage
|
|
+ * will go away eventually.
|
|
+ */
|
|
+ max = 32768;
|
|
+
|
|
+ rc = efrm_kfifo_id_ctor(&efrm_iobufset_manager->free_ids,
|
|
+ 0, max, &efrm_iobufset_manager->rm.rm_lock);
|
|
+ if (rc != 0)
|
|
+ goto fail1;
|
|
+
|
|
+ rc = efrm_resource_manager_ctor(&efrm_iobufset_manager->rm,
|
|
+ iobufset_rm_dtor, "IOBUFSET",
|
|
+ EFRM_RESOURCE_IOBUFSET);
|
|
+ if (rc < 0)
|
|
+ goto fail2;
|
|
+
|
|
+ *rm_out = &efrm_iobufset_manager->rm;
|
|
+ return 0;
|
|
+
|
|
+fail2:
|
|
+ kfifo_vfree(efrm_iobufset_manager->free_ids);
|
|
+fail1:
|
|
+ EFRM_DO_DEBUG(memset(efrm_iobufset_manager, 0,
|
|
+ sizeof(*efrm_iobufset_manager)));
|
|
+ kfree(efrm_iobufset_manager);
|
|
+ return rc;
|
|
+}
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/iopage.c 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,103 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides Linux-specific implementation for iopage API used
|
|
+ * from efhw library.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#include <ci/driver/resource/linux_efhw_nic.h>
|
|
+#include "kernel_compat.h"
|
|
+#include <ci/efhw/common_sysdep.h> /* for dma_addr_t */
|
|
+
|
|
+int efhw_iopage_alloc(struct efhw_nic *nic, struct efhw_iopage *p)
|
|
+{
|
|
+ struct linux_efhw_nic *lnic = linux_efhw_nic(nic);
|
|
+ dma_addr_t handle;
|
|
+ void *kva;
|
|
+
|
|
+ kva = efrm_pci_alloc_consistent(lnic->pci_dev, PAGE_SIZE,
|
|
+ &handle);
|
|
+ if (kva == 0)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ EFHW_ASSERT((handle & ~PAGE_MASK) == 0);
|
|
+
|
|
+ memset((void *)kva, 0, PAGE_SIZE);
|
|
+ efhw_page_init_from_va(&p->p, kva);
|
|
+
|
|
+ p->dma_addr = handle;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void efhw_iopage_free(struct efhw_nic *nic, struct efhw_iopage *p)
|
|
+{
|
|
+ struct linux_efhw_nic *lnic = linux_efhw_nic(nic);
|
|
+ EFHW_ASSERT(efhw_page_is_valid(&p->p));
|
|
+
|
|
+ efrm_pci_free_consistent(lnic->pci_dev, PAGE_SIZE,
|
|
+ efhw_iopage_ptr(p), p->dma_addr);
|
|
+}
|
|
+
|
|
+int
|
|
+efhw_iopages_alloc(struct efhw_nic *nic, struct efhw_iopages *p,
|
|
+ unsigned order)
|
|
+{
|
|
+ unsigned bytes = 1u << (order + PAGE_SHIFT);
|
|
+ struct linux_efhw_nic *lnic = linux_efhw_nic(nic);
|
|
+ dma_addr_t handle;
|
|
+ caddr_t addr;
|
|
+ int gfp_flag;
|
|
+
|
|
+ /* Set __GFP_COMP if available to make reference counting work.
|
|
+ * This is recommended here:
|
|
+ * http://www.forbiddenweb.org/viewtopic.php?id=83167&page=4#348331
|
|
+ */
|
|
+ gfp_flag = ((in_atomic() ? GFP_ATOMIC : GFP_KERNEL) | __GFP_COMP);
|
|
+ addr = efrm_dma_alloc_coherent(&lnic->pci_dev->dev, bytes, &handle,
|
|
+ gfp_flag);
|
|
+ if (addr == NULL)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ EFHW_ASSERT((handle & ~PAGE_MASK) == 0);
|
|
+
|
|
+ p->order = order;
|
|
+ p->dma_addr = handle;
|
|
+ p->kva = addr;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void efhw_iopages_free(struct efhw_nic *nic, struct efhw_iopages *p)
|
|
+{
|
|
+ unsigned bytes = 1u << (p->order + PAGE_SHIFT);
|
|
+ struct linux_efhw_nic *lnic = linux_efhw_nic(nic);
|
|
+
|
|
+ efrm_dma_free_coherent(&lnic->pci_dev->dev, bytes,
|
|
+ (void *)p->kva, p->dma_addr);
|
|
+}
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/kernel_compat.c 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,118 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides compatibility layer for various Linux kernel versions
|
|
+ * (starting from 2.6.9 RHEL kernel).
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#define IN_KERNEL_COMPAT_C
|
|
+#include <linux/types.h>
|
|
+#include <ci/efrm/debug.h>
|
|
+#include "kernel_compat.h"
|
|
+
|
|
+/* Set this to 1 to enable very basic counting of iopage(s) allocations, then
|
|
+ * call dump_iopage_counts() to show the number of current allocations of
|
|
+ * orders 0-7.
|
|
+ */
|
|
+#define EFRM_IOPAGE_COUNTS_ENABLED 0
|
|
+
|
|
+
|
|
+/****************************************************************************
|
|
+ *
|
|
+ * allocate a buffer suitable for DMA to/from the NIC
|
|
+ *
|
|
+ ****************************************************************************/
|
|
+
|
|
+#if EFRM_IOPAGE_COUNTS_ENABLED
|
|
+
|
|
+static int iopage_counts[8];
|
|
+
|
|
+void dump_iopage_counts(void)
|
|
+{
|
|
+ EFRM_NOTICE("iopage counts: %d %d %d %d %d %d %d %d", iopage_counts[0],
|
|
+ iopage_counts[1], iopage_counts[2], iopage_counts[3],
|
|
+ iopage_counts[4], iopage_counts[5], iopage_counts[6],
|
|
+ iopage_counts[7]);
|
|
+}
|
|
+
|
|
+#endif
|
|
+
|
|
+
|
|
+
|
|
+/*********** pci_alloc_consistent / pci_free_consistent ***********/
|
|
+
|
|
+void *efrm_dma_alloc_coherent(struct device *dev, size_t size,
|
|
+ dma_addr_t *dma_addr, int flag)
|
|
+{
|
|
+ void *ptr;
|
|
+ unsigned order;
|
|
+
|
|
+ order = __ffs(size/PAGE_SIZE);
|
|
+ EFRM_ASSERT(size == (PAGE_SIZE<<order));
|
|
+
|
|
+ /* Can't take a spinlock here since the allocation can
|
|
+ * block. */
|
|
+ ptr = dma_alloc_coherent(dev, size, dma_addr, flag);
|
|
+ if (ptr == NULL)
|
|
+ return ptr;
|
|
+
|
|
+#if EFRM_IOPAGE_COUNTS_ENABLED
|
|
+ if (order < 8)
|
|
+ iopage_counts[order]++;
|
|
+ else
|
|
+ EFRM_ERR("Huge iopages alloc (order=%d) ??? (not counted)",
|
|
+ order);
|
|
+#endif
|
|
+
|
|
+ return ptr;
|
|
+}
|
|
+
|
|
+void efrm_dma_free_coherent(struct device *dev, size_t size,
|
|
+ void *ptr, dma_addr_t dma_addr)
|
|
+{
|
|
+ unsigned order;
|
|
+
|
|
+ order = __ffs(size/PAGE_SIZE);
|
|
+ EFRM_ASSERT(size == (PAGE_SIZE<<order));
|
|
+
|
|
+#if EFRM_IOPAGE_COUNTS_ENABLED
|
|
+ if (order < 8)
|
|
+ --iopage_counts[order];
|
|
+ else
|
|
+ EFRM_ERR("Huge iopages free (order=%d) ??? (not counted)",
|
|
+ order);
|
|
+#endif
|
|
+
|
|
+ dma_free_coherent(dev, size, ptr, dma_addr);
|
|
+}
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/kernel_compat.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,70 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file provides compatibility layer for various Linux kernel versions
|
|
+ * (starting from 2.6.9 RHEL kernel).
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef DRIVER_LINUX_RESOURCE_KERNEL_COMPAT_H
|
|
+#define DRIVER_LINUX_RESOURCE_KERNEL_COMPAT_H
|
|
+
|
|
+#include <linux/moduleparam.h>
|
|
+#include <linux/sched.h>
|
|
+#include <linux/io.h>
|
|
+#include <linux/pci.h>
|
|
+
|
|
+/********* pci_map_*() ********************/
|
|
+
|
|
+extern void *efrm_dma_alloc_coherent(struct device *dev, size_t size,
|
|
+ dma_addr_t *dma_addr, int flag);
|
|
+
|
|
+extern void efrm_dma_free_coherent(struct device *dev, size_t size,
|
|
+ void *ptr, dma_addr_t dma_addr);
|
|
+
|
|
+static inline void *efrm_pci_alloc_consistent(struct pci_dev *hwdev,
|
|
+ size_t size,
|
|
+ dma_addr_t *dma_addr)
|
|
+{
|
|
+ return efrm_dma_alloc_coherent(&hwdev->dev, size, dma_addr,
|
|
+ GFP_ATOMIC);
|
|
+}
|
|
+
|
|
+static inline void efrm_pci_free_consistent(struct pci_dev *hwdev, size_t size,
|
|
+ void *ptr, dma_addr_t dma_addr)
|
|
+{
|
|
+ efrm_dma_free_coherent(&hwdev->dev, size, ptr, dma_addr);
|
|
+}
|
|
+
|
|
+
|
|
+#endif /* DRIVER_LINUX_RESOURCE_KERNEL_COMPAT_H */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/kernel_proc.c 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,109 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file contains /proc/driver/sfc_resource/ implementation.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#include <ci/efrm/debug.h>
|
|
+#include <ci/efrm/driver_private.h>
|
|
+#include <linux/proc_fs.h>
|
|
+
|
|
+/** Top level directory for sfc specific stats **/
|
|
+static struct proc_dir_entry *efrm_proc_root; /* = NULL */
|
|
+
|
|
+static int
|
|
+efrm_resource_read_proc(char *buf, char **start, off_t offset, int count,
|
|
+ int *eof, void *data);
|
|
+
|
|
+int efrm_install_proc_entries(void)
|
|
+{
|
|
+ /* create the top-level directory for etherfabric specific stuff */
|
|
+ efrm_proc_root = proc_mkdir("driver/sfc_resource", NULL);
|
|
+ if (!efrm_proc_root)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ if (create_proc_read_entry("resources", 0, efrm_proc_root,
|
|
+ efrm_resource_read_proc, 0) == NULL) {
|
|
+ EFRM_WARN("%s: Unable to create /proc/drivers/sfc_resource/"
|
|
+ "resources", __func__);
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void efrm_uninstall_proc_entries(void)
|
|
+{
|
|
+ EFRM_ASSERT(efrm_proc_root);
|
|
+ remove_proc_entry("resources", efrm_proc_root);
|
|
+ remove_proc_entry(efrm_proc_root->name, efrm_proc_root->parent);
|
|
+ efrm_proc_root = NULL;
|
|
+}
|
|
+
|
|
+/****************************************************************************
|
|
+ *
|
|
+ * /proc/drivers/sfc/resources
|
|
+ *
|
|
+ ****************************************************************************/
|
|
+
|
|
+#define EFRM_PROC_PRINTF(buf, len, fmt, ...) \
|
|
+ do { \
|
|
+ if (count - len > 0) \
|
|
+ len += snprintf(buf+len, count-len, (fmt), \
|
|
+ __VA_ARGS__); \
|
|
+ } while (0)
|
|
+
|
|
+static int
|
|
+efrm_resource_read_proc(char *buf, char **start, off_t offset, int count,
|
|
+ int *eof, void *data)
|
|
+{
|
|
+ irq_flags_t lock_flags;
|
|
+ int len = 0;
|
|
+ int type;
|
|
+ struct efrm_resource_manager *rm;
|
|
+
|
|
+ for (type = 0; type < EFRM_RESOURCE_NUM; type++) {
|
|
+ rm = efrm_rm_table[type];
|
|
+ if (rm == NULL)
|
|
+ continue;
|
|
+
|
|
+ EFRM_PROC_PRINTF(buf, len, "*** %s ***\n", rm->rm_name);
|
|
+
|
|
+ spin_lock_irqsave(&rm->rm_lock, lock_flags);
|
|
+ EFRM_PROC_PRINTF(buf, len, "current = %u\n", rm->rm_resources);
|
|
+ EFRM_PROC_PRINTF(buf, len, " max = %u\n\n",
|
|
+ rm->rm_resources_hiwat);
|
|
+ spin_unlock_irqrestore(&rm->rm_lock, lock_flags);
|
|
+ }
|
|
+
|
|
+ return count ? strlen(buf) : 0;
|
|
+}
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/kfifo.c 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,208 @@
|
|
+/*
|
|
+ * A simple kernel FIFO implementation.
|
|
+ *
|
|
+ * Copyright (C) 2004 Stelian Pop <stelian@popies.net>
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
+ *
|
|
+ */
|
|
+
|
|
+/*
|
|
+ * This file is stolen from the Linux kernel sources
|
|
+ * (linux-2.6.22/kernel/kfifo.c) into sfc_resource driver.
|
|
+ * It should be used for old kernels without kfifo implementation.
|
|
+ * Most part of linux/kfifo.h is incorporated into
|
|
+ * ci/efrm/sysdep_linux.h.
|
|
+ */
|
|
+#include <ci/efrm/sysdep_linux.h>
|
|
+#ifdef HAS_NO_KFIFO
|
|
+
|
|
+#include <linux/kernel.h>
|
|
+#include <linux/module.h>
|
|
+#include <linux/slab.h>
|
|
+#include <linux/err.h>
|
|
+/*#include <linux/kfifo.h>*/
|
|
+
|
|
+/**
|
|
+ * kfifo_init - allocates a new FIFO using a preallocated buffer
|
|
+ * @buffer: the preallocated buffer to be used.
|
|
+ * @size: the size of the internal buffer, this have to be a power of 2.
|
|
+ * @gfp_mask: get_free_pages mask, passed to kmalloc()
|
|
+ * @lock: the lock to be used to protect the fifo buffer
|
|
+ *
|
|
+ * Do NOT pass the kfifo to kfifo_free() after use! Simply free the
|
|
+ * &struct kfifo with kfree().
|
|
+ */
|
|
+struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size,
|
|
+ gfp_t gfp_mask, spinlock_t *lock)
|
|
+{
|
|
+ struct kfifo *fifo;
|
|
+
|
|
+ /* size must be a power of 2 */
|
|
+ BUG_ON(size & (size - 1));
|
|
+
|
|
+ fifo = kmalloc(sizeof(struct kfifo), gfp_mask);
|
|
+ if (!fifo)
|
|
+ return ERR_PTR(-ENOMEM);
|
|
+
|
|
+ fifo->buffer = buffer;
|
|
+ fifo->size = size;
|
|
+ fifo->in = fifo->out = 0;
|
|
+ fifo->lock = lock;
|
|
+
|
|
+ return fifo;
|
|
+}
|
|
+EXPORT_SYMBOL(kfifo_init);
|
|
+
|
|
+/**
|
|
+ * kfifo_alloc - allocates a new FIFO and its internal buffer
|
|
+ * @size: the size of the internal buffer to be allocated.
|
|
+ * @gfp_mask: get_free_pages mask, passed to kmalloc()
|
|
+ * @lock: the lock to be used to protect the fifo buffer
|
|
+ *
|
|
+ * The size will be rounded-up to a power of 2.
|
|
+ */
|
|
+struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask, spinlock_t *lock)
|
|
+{
|
|
+ unsigned char *buffer;
|
|
+ struct kfifo *ret;
|
|
+
|
|
+ /*
|
|
+ * round up to the next power of 2, since our 'let the indices
|
|
+ * wrap' tachnique works only in this case.
|
|
+ */
|
|
+ if (size & (size - 1)) {
|
|
+ BUG_ON(size > 0x80000000);
|
|
+ size = roundup_pow_of_two(size);
|
|
+ }
|
|
+
|
|
+ buffer = kmalloc(size, gfp_mask);
|
|
+ if (!buffer)
|
|
+ return ERR_PTR(-ENOMEM);
|
|
+
|
|
+ ret = kfifo_init(buffer, size, gfp_mask, lock);
|
|
+
|
|
+ if (IS_ERR(ret))
|
|
+ kfree(buffer);
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+EXPORT_SYMBOL(kfifo_alloc);
|
|
+
|
|
+/**
|
|
+ * kfifo_free - frees the FIFO
|
|
+ * @fifo: the fifo to be freed.
|
|
+ */
|
|
+void kfifo_free(struct kfifo *fifo)
|
|
+{
|
|
+ kfree(fifo->buffer);
|
|
+ kfree(fifo);
|
|
+}
|
|
+EXPORT_SYMBOL(kfifo_free);
|
|
+
|
|
+/**
|
|
+ * __kfifo_put - puts some data into the FIFO, no locking version
|
|
+ * @fifo: the fifo to be used.
|
|
+ * @buffer: the data to be added.
|
|
+ * @len: the length of the data to be added.
|
|
+ *
|
|
+ * This function copies at most @len bytes from the @buffer into
|
|
+ * the FIFO depending on the free space, and returns the number of
|
|
+ * bytes copied.
|
|
+ *
|
|
+ * Note that with only one concurrent reader and one concurrent
|
|
+ * writer, you don't need extra locking to use these functions.
|
|
+ */
|
|
+unsigned int
|
|
+__kfifo_put(struct kfifo *fifo, unsigned char *buffer, unsigned int len)
|
|
+{
|
|
+ unsigned int l;
|
|
+
|
|
+ len = min(len, fifo->size - fifo->in + fifo->out);
|
|
+
|
|
+ /*
|
|
+ * Ensure that we sample the fifo->out index -before- we
|
|
+ * start putting bytes into the kfifo.
|
|
+ */
|
|
+
|
|
+ smp_mb();
|
|
+
|
|
+ /* first put the data starting from fifo->in to buffer end */
|
|
+ l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));
|
|
+ memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l);
|
|
+
|
|
+ /* then put the rest (if any) at the beginning of the buffer */
|
|
+ memcpy(fifo->buffer, buffer + l, len - l);
|
|
+
|
|
+ /*
|
|
+ * Ensure that we add the bytes to the kfifo -before-
|
|
+ * we update the fifo->in index.
|
|
+ */
|
|
+
|
|
+ smp_wmb();
|
|
+
|
|
+ fifo->in += len;
|
|
+
|
|
+ return len;
|
|
+}
|
|
+EXPORT_SYMBOL(__kfifo_put);
|
|
+
|
|
+/**
|
|
+ * __kfifo_get - gets some data from the FIFO, no locking version
|
|
+ * @fifo: the fifo to be used.
|
|
+ * @buffer: where the data must be copied.
|
|
+ * @len: the size of the destination buffer.
|
|
+ *
|
|
+ * This function copies at most @len bytes from the FIFO into the
|
|
+ * @buffer and returns the number of copied bytes.
|
|
+ *
|
|
+ * Note that with only one concurrent reader and one concurrent
|
|
+ * writer, you don't need extra locking to use these functions.
|
|
+ */
|
|
+unsigned int
|
|
+__kfifo_get(struct kfifo *fifo, unsigned char *buffer, unsigned int len)
|
|
+{
|
|
+ unsigned int l;
|
|
+
|
|
+ len = min(len, fifo->in - fifo->out);
|
|
+
|
|
+ /*
|
|
+ * Ensure that we sample the fifo->in index -before- we
|
|
+ * start removing bytes from the kfifo.
|
|
+ */
|
|
+
|
|
+ smp_rmb();
|
|
+
|
|
+ /* first get the data from fifo->out until the end of the buffer */
|
|
+ l = min(len, fifo->size - (fifo->out & (fifo->size - 1)));
|
|
+ memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), l);
|
|
+
|
|
+ /* then get the rest (if any) from the beginning of the buffer */
|
|
+ memcpy(buffer + l, fifo->buffer, len - l);
|
|
+
|
|
+ /*
|
|
+ * Ensure that we remove the bytes from the kfifo -before-
|
|
+ * we update the fifo->out index.
|
|
+ */
|
|
+
|
|
+ smp_mb();
|
|
+
|
|
+ fifo->out += len;
|
|
+
|
|
+ return len;
|
|
+}
|
|
+EXPORT_SYMBOL(__kfifo_get);
|
|
+
|
|
+#endif
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/linux_resource_internal.h 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,76 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file contains Linux-specific API internal for the resource driver.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#ifndef __LINUX_RESOURCE_INTERNAL__
|
|
+#define __LINUX_RESOURCE_INTERNAL__
|
|
+
|
|
+#include <ci/driver/resource/linux_efhw_nic.h>
|
|
+#include <ci/efrm/debug.h>
|
|
+#include <ci/efrm/driver_private.h>
|
|
+#include <ci/driver/efab/hardware.h>
|
|
+
|
|
+
|
|
+/*! Linux specific EtherFabric initialisation */
|
|
+extern int
|
|
+linux_efrm_nic_ctor(struct linux_efhw_nic *, struct pci_dev *,
|
|
+ spinlock_t *reg_lock,
|
|
+ unsigned nic_flags, unsigned nic_options);
|
|
+
|
|
+/*! Linux specific EtherFabric initialisation */
|
|
+extern void linux_efrm_nic_dtor(struct linux_efhw_nic *);
|
|
+
|
|
+/*! Linux specific EtherFabric initialisation -- interrupt registration */
|
|
+extern int linux_efrm_irq_ctor(struct linux_efhw_nic *);
|
|
+
|
|
+/*! Linux specific EtherFabric initialisation -- interrupt deregistration */
|
|
+extern void linux_efrm_irq_dtor(struct linux_efhw_nic *);
|
|
+
|
|
+extern int efrm_driverlink_register(void);
|
|
+extern void efrm_driverlink_unregister(void);
|
|
+
|
|
+extern int
|
|
+efrm_nic_add(struct pci_dev *dev, unsigned int opts, const uint8_t *mac_addr,
|
|
+ struct linux_efhw_nic **lnic_out, spinlock_t *reg_lock,
|
|
+ int bt_min, int bt_max, int non_irq_evq,
|
|
+ const struct vi_resource_dimensions *);
|
|
+extern void efrm_nic_del(struct linux_efhw_nic *);
|
|
+
|
|
+
|
|
+extern int efrm_install_proc_entries(void);
|
|
+extern void efrm_uninstall_proc_entries(void);
|
|
+
|
|
+#endif /* __LINUX_RESOURCE_INTERNAL__ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/nic.c 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,174 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file contains EtherFabric Generic NIC instance (init, interrupts,
|
|
+ * etc)
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#include <ci/efhw/debug.h>
|
|
+#include <ci/driver/efab/hardware.h>
|
|
+#include <ci/efhw/falcon.h>
|
|
+#include <ci/efhw/nic.h>
|
|
+#include <ci/efhw/eventq.h>
|
|
+
|
|
+
|
|
+int efhw_device_type_init(struct efhw_device_type *dt,
|
|
+ int vendor_id, int device_id,
|
|
+ int class_revision)
|
|
+{
|
|
+ if (vendor_id != 0x1924)
|
|
+ return 0;
|
|
+
|
|
+ switch (device_id) {
|
|
+ case 0x0703:
|
|
+ case 0x6703:
|
|
+ dt->variant = 'A';
|
|
+ switch (class_revision) {
|
|
+ case 0:
|
|
+ dt->revision = 0;
|
|
+ break;
|
|
+ case 1:
|
|
+ dt->revision = 1;
|
|
+ break;
|
|
+ default:
|
|
+ return 0;
|
|
+ }
|
|
+ break;
|
|
+ case 0x0710:
|
|
+ dt->variant = 'B';
|
|
+ switch (class_revision) {
|
|
+ case 2:
|
|
+ dt->revision = 0;
|
|
+ break;
|
|
+ default:
|
|
+ return 0;
|
|
+ }
|
|
+ break;
|
|
+ default:
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * NIC Initialisation
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+/* make this separate from initialising data structure
|
|
+** to allow this to be called at a later time once we can access PCI
|
|
+** config space to find out what hardware we have
|
|
+*/
|
|
+void efhw_nic_init(struct efhw_nic *nic, unsigned flags, unsigned options,
|
|
+ struct efhw_device_type dev_type)
|
|
+{
|
|
+ nic->devtype = dev_type;
|
|
+ nic->flags = flags;
|
|
+ nic->options = options;
|
|
+ nic->bar_ioaddr = 0;
|
|
+ spin_lock_init(&nic->the_reg_lock);
|
|
+ nic->reg_lock = &nic->the_reg_lock;
|
|
+ nic->mtu = 1500 + ETH_HLEN;
|
|
+
|
|
+ nic->irq_unit = EFHW_IRQ_UNIT_UNUSED;
|
|
+
|
|
+ nic->evq_sizes = 512 | 1024 | 2048 | 4096 | 8192 |
|
|
+ 16384 | 32768;
|
|
+ nic->txq_sizes = 512 | 1024 | 2048 | 4096;
|
|
+ nic->rxq_sizes = 512 | 1024 | 2048 | 4096;
|
|
+ nic->efhw_func = &falcon_char_functional_units;
|
|
+ nic->ctr_ap_bytes = EFHW_64M;
|
|
+ switch (nic->devtype.variant) {
|
|
+ case 'A':
|
|
+ nic->ctr_ap_bar = FALCON_S_CTR_AP_BAR;
|
|
+ nic->num_evqs = 4096;
|
|
+ nic->num_dmaqs = 4096;
|
|
+ nic->num_timers = 4096;
|
|
+ break;
|
|
+ case 'B':
|
|
+ nic->flags |= NIC_FLAG_NO_INTERRUPT;
|
|
+ nic->ctr_ap_bar = FALCON_P_CTR_AP_BAR;
|
|
+ nic->num_evqs = 4096;
|
|
+ nic->num_dmaqs = 4096;
|
|
+ nic->num_timers = 4096;
|
|
+ break;
|
|
+ default:
|
|
+ EFHW_ASSERT(0);
|
|
+ break;
|
|
+ }
|
|
+}
|
|
+
|
|
+
|
|
+void efhw_nic_close_interrupts(struct efhw_nic *nic)
|
|
+{
|
|
+ EFHW_ASSERT(nic);
|
|
+ if (!efhw_nic_have_hw(nic))
|
|
+ return;
|
|
+
|
|
+ EFHW_ASSERT(efhw_nic_have_hw(nic));
|
|
+
|
|
+ if (nic->irq_unit != EFHW_IRQ_UNIT_UNUSED)
|
|
+ efhw_nic_interrupt_disable(nic);
|
|
+}
|
|
+
|
|
+void efhw_nic_dtor(struct efhw_nic *nic)
|
|
+{
|
|
+ EFHW_ASSERT(nic);
|
|
+
|
|
+ /* Check that we have functional units because the software only
|
|
+ * driver doesn't initialise anything hardware related any more */
|
|
+
|
|
+ /* close interrupts is called first because the act of deregistering
|
|
+ the driver could cause this driver to change from master to slave
|
|
+ and hence the implicit interrupt mappings would be wrong */
|
|
+
|
|
+ EFHW_TRACE("%s: functional units ... ", __func__);
|
|
+
|
|
+ if (efhw_nic_have_functional_units(nic)) {
|
|
+ efhw_nic_close_interrupts(nic);
|
|
+ efhw_nic_close_hardware(nic);
|
|
+ }
|
|
+ EFHW_TRACE("%s: functional units ... done", __func__);
|
|
+
|
|
+ /* destroy event queues */
|
|
+ EFHW_TRACE("%s: event queues ... ", __func__);
|
|
+
|
|
+ if (nic->interrupting_evq.evq_mask)
|
|
+ efhw_keventq_dtor(nic, &nic->interrupting_evq);
|
|
+ if (nic->non_interrupting_evq.evq_mask)
|
|
+ efhw_keventq_dtor(nic, &nic->non_interrupting_evq);
|
|
+
|
|
+ EFHW_TRACE("%s: event queues ... done", __func__);
|
|
+
|
|
+ spin_lock_destroy(&nic->the_reg_lock);
|
|
+
|
|
+ EFHW_TRACE("%s: DONE", __func__);
|
|
+}
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/resource_driver.c 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,600 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file contains main driver entry points.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#include "linux_resource_internal.h"
|
|
+#include "kernel_compat.h"
|
|
+#include <ci/efrm/nic_table.h>
|
|
+#include <ci/driver/resource/efx_vi.h>
|
|
+#include <ci/efhw/eventq.h>
|
|
+#include <ci/efhw/nic.h>
|
|
+#include <ci/efrm/buffer_table.h>
|
|
+#include <ci/efrm/vi_resource_private.h>
|
|
+#include <ci/efrm/driver_private.h>
|
|
+
|
|
+MODULE_AUTHOR("Solarflare Communications");
|
|
+MODULE_LICENSE("GPL");
|
|
+
|
|
+static struct efhw_ev_handler ev_handler = {
|
|
+ .wakeup_fn = efrm_handle_wakeup_event,
|
|
+ .timeout_fn = efrm_handle_timeout_event,
|
|
+ .dmaq_flushed_fn = efrm_handle_dmaq_flushed,
|
|
+};
|
|
+
|
|
+const int max_hardware_init_repeats = 10;
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * Module load time variables
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+/* See docs/notes/pci_alloc_consistent */
|
|
+static int do_irq = 1; /* enable interrupts */
|
|
+
|
|
+#if defined(CONFIG_X86_XEN)
|
|
+static int irq_moderation = 60; /* interrupt moderation (60 usec) */
|
|
+#else
|
|
+static int irq_moderation = 20; /* interrupt moderation (20 usec) */
|
|
+#endif
|
|
+static int nic_options = NIC_OPT_DEFAULT;
|
|
+int efx_vi_eventq_size = EFX_VI_EVENTQ_SIZE_DEFAULT;
|
|
+
|
|
+module_param(do_irq, int, S_IRUGO);
|
|
+MODULE_PARM_DESC(do_irq, "Enable interrupts. "
|
|
+ "Do not turn it off unless you know what are you doing.");
|
|
+module_param(irq_moderation, int, S_IRUGO);
|
|
+MODULE_PARM_DESC(irq_moderation, "IRQ moderation in usec");
|
|
+module_param(nic_options, int, S_IRUGO);
|
|
+MODULE_PARM_DESC(nic_options, "Nic options -- see efhw_types.h");
|
|
+module_param(efx_vi_eventq_size, int, S_IRUGO);
|
|
+MODULE_PARM_DESC(efx_vi_eventq_size,
|
|
+ "Size of event queue allocated by efx_vi library");
|
|
+
|
|
+/*--------------------------------------------------------------------
|
|
+ *
|
|
+ * Linux specific NIC initialisation
|
|
+ *
|
|
+ *--------------------------------------------------------------------*/
|
|
+
|
|
+static inline irqreturn_t
|
|
+linux_efrm_interrupt(int irr, void *dev_id)
|
|
+{
|
|
+ return efhw_nic_interrupt((struct efhw_nic *)dev_id);
|
|
+}
|
|
+
|
|
+int linux_efrm_irq_ctor(struct linux_efhw_nic *lnic)
|
|
+{
|
|
+ struct efhw_nic *nic = &lnic->efrm_nic.efhw_nic;
|
|
+
|
|
+ nic->flags &= ~NIC_FLAG_MSI;
|
|
+ if (nic->flags & NIC_FLAG_TRY_MSI) {
|
|
+ int rc = pci_enable_msi(lnic->pci_dev);
|
|
+ if (rc < 0) {
|
|
+ EFRM_WARN("%s: Could not enable MSI (%d)",
|
|
+ __func__, rc);
|
|
+ EFRM_WARN("%s: Continuing with legacy interrupt mode",
|
|
+ __func__);
|
|
+ } else {
|
|
+ EFRM_NOTICE("%s: MSI enabled", __func__);
|
|
+ nic->flags |= NIC_FLAG_MSI;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (request_irq(lnic->pci_dev->irq, linux_efrm_interrupt,
|
|
+ IRQF_SHARED, "sfc_resource", nic)) {
|
|
+ EFRM_ERR("Request for interrupt #%d failed",
|
|
+ lnic->pci_dev->irq);
|
|
+ nic->flags &= ~NIC_FLAG_OS_IRQ_EN;
|
|
+ return -EBUSY;
|
|
+ }
|
|
+ nic->flags |= NIC_FLAG_OS_IRQ_EN;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void linux_efrm_irq_dtor(struct linux_efhw_nic *lnic)
|
|
+{
|
|
+ EFRM_TRACE("%s: start", __func__);
|
|
+
|
|
+ if (lnic->efrm_nic.efhw_nic.flags & NIC_FLAG_OS_IRQ_EN) {
|
|
+ free_irq(lnic->pci_dev->irq, &lnic->efrm_nic.efhw_nic);
|
|
+ lnic->efrm_nic.efhw_nic.flags &= ~NIC_FLAG_OS_IRQ_EN;
|
|
+ }
|
|
+
|
|
+ if (lnic->efrm_nic.efhw_nic.flags & NIC_FLAG_MSI) {
|
|
+ pci_disable_msi(lnic->pci_dev);
|
|
+ lnic->efrm_nic.efhw_nic.flags &= ~NIC_FLAG_MSI;
|
|
+ }
|
|
+
|
|
+ EFRM_TRACE("%s: done", __func__);
|
|
+}
|
|
+
|
|
+/* Allocate buffer table entries for a particular NIC.
|
|
+ */
|
|
+static int efrm_nic_buffer_table_alloc(struct efhw_nic *nic)
|
|
+{
|
|
+ int capacity;
|
|
+ int page_order;
|
|
+ int rc;
|
|
+
|
|
+ /* Choose queue size. */
|
|
+ for (capacity = 8192; capacity <= nic->evq_sizes; capacity <<= 1) {
|
|
+ if (capacity > nic->evq_sizes) {
|
|
+ EFRM_ERR
|
|
+ ("%s: Unable to choose EVQ size (supported=%x)",
|
|
+ __func__, nic->evq_sizes);
|
|
+ return -E2BIG;
|
|
+ } else if (capacity & nic->evq_sizes)
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ nic->interrupting_evq.hw.capacity = capacity;
|
|
+ nic->interrupting_evq.hw.buf_tbl_alloc.base = (unsigned)-1;
|
|
+
|
|
+ nic->non_interrupting_evq.hw.capacity = capacity;
|
|
+ nic->non_interrupting_evq.hw.buf_tbl_alloc.base = (unsigned)-1;
|
|
+
|
|
+ /* allocate buffer table entries to map onto the iobuffer */
|
|
+ page_order = get_order(capacity * sizeof(efhw_event_t));
|
|
+ if (!(nic->flags & NIC_FLAG_NO_INTERRUPT)) {
|
|
+ rc = efrm_buffer_table_alloc(page_order,
|
|
+ &nic->interrupting_evq
|
|
+ .hw.buf_tbl_alloc);
|
|
+ if (rc < 0) {
|
|
+ EFRM_WARN
|
|
+ ("%s: failed (%d) to alloc %d buffer table entries",
|
|
+ __func__, rc, page_order);
|
|
+ return rc;
|
|
+ }
|
|
+ }
|
|
+ rc = efrm_buffer_table_alloc(page_order,
|
|
+ &nic->non_interrupting_evq.hw.
|
|
+ buf_tbl_alloc);
|
|
+ if (rc < 0) {
|
|
+ EFRM_WARN
|
|
+ ("%s: failed (%d) to alloc %d buffer table entries",
|
|
+ __func__, rc, page_order);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* Free buffer table entries allocated for a particular NIC.
|
|
+ */
|
|
+static void efrm_nic_buffer_table_free(struct efhw_nic *nic)
|
|
+{
|
|
+ if (nic->interrupting_evq.hw.buf_tbl_alloc.base != (unsigned)-1)
|
|
+ efrm_buffer_table_free(&nic->interrupting_evq.hw
|
|
+ .buf_tbl_alloc);
|
|
+ if (nic->non_interrupting_evq.hw.buf_tbl_alloc.base != (unsigned)-1)
|
|
+ efrm_buffer_table_free(&nic->non_interrupting_evq
|
|
+ .hw.buf_tbl_alloc);
|
|
+}
|
|
+
|
|
+static int iomap_bar(struct linux_efhw_nic *lnic, size_t len)
|
|
+{
|
|
+ volatile char __iomem *ioaddr;
|
|
+
|
|
+ ioaddr = ioremap_nocache(lnic->ctr_ap_pci_addr, len);
|
|
+ if (ioaddr == 0)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ lnic->efrm_nic.efhw_nic.bar_ioaddr = ioaddr;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int linux_efhw_nic_map_ctr_ap(struct linux_efhw_nic *lnic)
|
|
+{
|
|
+ struct efhw_nic *nic = &lnic->efrm_nic.efhw_nic;
|
|
+ int rc;
|
|
+
|
|
+ rc = iomap_bar(lnic, nic->ctr_ap_bytes);
|
|
+
|
|
+ /* Bug 5195: workaround for now. */
|
|
+ if (rc != 0 && nic->ctr_ap_bytes > 16 * 1024 * 1024) {
|
|
+ /* Try half the size for now. */
|
|
+ nic->ctr_ap_bytes /= 2;
|
|
+ EFRM_WARN("Bug 5195 WORKAROUND: retrying iomap of %d bytes",
|
|
+ nic->ctr_ap_bytes);
|
|
+ rc = iomap_bar(lnic, nic->ctr_ap_bytes);
|
|
+ }
|
|
+
|
|
+ if (rc < 0) {
|
|
+ EFRM_ERR("Failed (%d) to map bar (%d bytes)",
|
|
+ rc, nic->ctr_ap_bytes);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+int
|
|
+linux_efrm_nic_ctor(struct linux_efhw_nic *lnic, struct pci_dev *dev,
|
|
+ spinlock_t *reg_lock,
|
|
+ unsigned nic_flags, unsigned nic_options)
|
|
+{
|
|
+ struct efhw_device_type dev_type;
|
|
+ struct efhw_nic *nic = &lnic->efrm_nic.efhw_nic;
|
|
+ u8 class_revision;
|
|
+ int rc;
|
|
+
|
|
+ rc = pci_read_config_byte(dev, PCI_CLASS_REVISION, &class_revision);
|
|
+ if (rc != 0) {
|
|
+ EFRM_ERR("%s: pci_read_config_byte failed (%d)",
|
|
+ __func__, rc);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ if (!efhw_device_type_init(&dev_type, dev->vendor, dev->device,
|
|
+ class_revision)) {
|
|
+ EFRM_ERR("%s: efhw_device_type_init failed %04x:%04x(%d)",
|
|
+ __func__, (unsigned) dev->vendor,
|
|
+ (unsigned) dev->device, (int) class_revision);
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
+ EFRM_NOTICE("attaching device type %04x:%04x %d:%c%d",
|
|
+ (unsigned) dev->vendor, (unsigned) dev->device,
|
|
+ dev_type.arch, dev_type.variant, dev_type.revision);
|
|
+
|
|
+ /* Initialise the adapter-structure. */
|
|
+ efhw_nic_init(nic, nic_flags, nic_options, dev_type);
|
|
+ lnic->pci_dev = dev;
|
|
+
|
|
+ rc = pci_enable_device(dev);
|
|
+ if (rc < 0) {
|
|
+ EFRM_ERR("%s: pci_enable_device failed (%d)",
|
|
+ __func__, rc);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ lnic->ctr_ap_pci_addr = pci_resource_start(dev, nic->ctr_ap_bar);
|
|
+
|
|
+ if (!pci_dma_supported(dev, (dma_addr_t)EFHW_DMA_ADDRMASK)) {
|
|
+ EFRM_ERR("%s: pci_dma_supported(%lx) failed", __func__,
|
|
+ (unsigned long)EFHW_DMA_ADDRMASK);
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
+ if (pci_set_dma_mask(dev, (dma_addr_t)EFHW_DMA_ADDRMASK)) {
|
|
+ EFRM_ERR("%s: pci_set_dma_mask(%lx) failed", __func__,
|
|
+ (unsigned long)EFHW_DMA_ADDRMASK);
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
+ if (pci_set_consistent_dma_mask(dev, (dma_addr_t)EFHW_DMA_ADDRMASK)) {
|
|
+ EFRM_ERR("%s: pci_set_consistent_dma_mask(%lx) failed",
|
|
+ __func__, (unsigned long)EFHW_DMA_ADDRMASK);
|
|
+ return -ENODEV;
|
|
+ }
|
|
+
|
|
+ rc = linux_efhw_nic_map_ctr_ap(lnic);
|
|
+ if (rc < 0)
|
|
+ return rc;
|
|
+
|
|
+ /* By default struct efhw_nic contains its own lock for protecting
|
|
+ * access to nic registers. We override it with a pointer to the
|
|
+ * lock in the net driver. This is needed when resource and net
|
|
+ * drivers share a single PCI function (falcon B series).
|
|
+ */
|
|
+ nic->reg_lock = reg_lock;
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void linux_efrm_nic_dtor(struct linux_efhw_nic *lnic)
|
|
+{
|
|
+ struct efhw_nic *nic = &lnic->efrm_nic.efhw_nic;
|
|
+ volatile char __iomem *bar_ioaddr = nic->bar_ioaddr;
|
|
+
|
|
+ efhw_nic_dtor(nic);
|
|
+
|
|
+ /* Unmap the bar. */
|
|
+ EFRM_ASSERT(bar_ioaddr);
|
|
+ iounmap(bar_ioaddr);
|
|
+ nic->bar_ioaddr = 0;
|
|
+}
|
|
+
|
|
+/****************************************************************************
|
|
+ *
|
|
+ * efrm_tasklet - used to poll the eventq which may result in further callbacks
|
|
+ *
|
|
+ ****************************************************************************/
|
|
+
|
|
+static void efrm_tasklet(unsigned long pdev)
|
|
+{
|
|
+ struct efhw_nic *nic = (struct efhw_nic *)pdev;
|
|
+
|
|
+ EFRM_ASSERT(!(nic->flags & NIC_FLAG_NO_INTERRUPT));
|
|
+
|
|
+ efhw_keventq_poll(nic, &nic->interrupting_evq);
|
|
+ EFRM_TRACE("%s: complete", __func__);
|
|
+}
|
|
+
|
|
+/****************************************************************************
|
|
+ *
|
|
+ * char driver specific interrupt callbacks -- run at hard IRQL
|
|
+ *
|
|
+ ****************************************************************************/
|
|
+static void efrm_handle_eventq_irq(struct efhw_nic *nic, int evq)
|
|
+{
|
|
+ /* NB. The interrupt must have already been acked (for legacy mode). */
|
|
+
|
|
+ EFRM_TRACE("%s: starting tasklet", __func__);
|
|
+ EFRM_ASSERT(!(nic->flags & NIC_FLAG_NO_INTERRUPT));
|
|
+
|
|
+ tasklet_schedule(&linux_efhw_nic(nic)->tasklet);
|
|
+}
|
|
+
|
|
+/* A count of how many NICs this driver knows about. */
|
|
+static int n_nics_probed;
|
|
+
|
|
+/****************************************************************************
|
|
+ *
|
|
+ * efrm_nic_add: add the NIC to the resource driver
|
|
+ *
|
|
+ * NOTE: the flow of control through this routine is quite subtle
|
|
+ * because of the number of operations that can fail. We therefore
|
|
+ * take the apporaching of keeping the return code (rc) variable
|
|
+ * accurate, and only do operations while it is non-negative. Tear down
|
|
+ * is done at the end if rc is negative, depending on what has been set up
|
|
+ * by that point.
|
|
+ *
|
|
+ * So basically just make sure that any code you add checks rc>=0 before
|
|
+ * doing any work and you'll be fine.
|
|
+ *
|
|
+ ****************************************************************************/
|
|
+int
|
|
+efrm_nic_add(struct pci_dev *dev, unsigned flags, const uint8_t *mac_addr,
|
|
+ struct linux_efhw_nic **lnic_out, spinlock_t *reg_lock,
|
|
+ int bt_min, int bt_lim, int non_irq_evq,
|
|
+ const struct vi_resource_dimensions *res_dim)
|
|
+{
|
|
+ struct linux_efhw_nic *lnic = NULL;
|
|
+ struct efhw_nic *nic = NULL;
|
|
+ int count = 0, rc = 0, resources_init = 0;
|
|
+ int constructed = 0;
|
|
+ int registered_nic = 0;
|
|
+ int buffers_allocated = 0;
|
|
+ static unsigned nic_index; /* = 0; */
|
|
+
|
|
+ EFRM_TRACE("%s: device detected (Slot '%s', IRQ %d)", __func__,
|
|
+ pci_name(dev) ? pci_name(dev) : "?", dev->irq);
|
|
+
|
|
+ /* Ensure that we have room for the new adapter-structure. */
|
|
+ if (efrm_nic_tablep->nic_count == EFHW_MAX_NR_DEVS) {
|
|
+ EFRM_WARN("%s: WARNING: too many devices", __func__);
|
|
+ rc = -ENOMEM;
|
|
+ goto failed;
|
|
+ }
|
|
+
|
|
+ if (n_nics_probed == 0) {
|
|
+ rc = efrm_resources_init(res_dim, bt_min, bt_lim);
|
|
+ if (rc != 0)
|
|
+ goto failed;
|
|
+ resources_init = 1;
|
|
+ }
|
|
+
|
|
+ /* Allocate memory for the new adapter-structure. */
|
|
+ lnic = kmalloc(sizeof(*lnic), GFP_KERNEL);
|
|
+ if (lnic == NULL) {
|
|
+ EFRM_ERR("%s: ERROR: failed to allocate memory", __func__);
|
|
+ rc = -ENOMEM;
|
|
+ goto failed;
|
|
+ }
|
|
+ memset(lnic, 0, sizeof(*lnic));
|
|
+ nic = &lnic->efrm_nic.efhw_nic;
|
|
+
|
|
+ lnic->ev_handlers = &ev_handler;
|
|
+
|
|
+ /* OS specific hardware mappings */
|
|
+ rc = linux_efrm_nic_ctor(lnic, dev, reg_lock, flags, nic_options);
|
|
+ if (rc < 0) {
|
|
+ EFRM_ERR("%s: ERROR: initialisation failed", __func__);
|
|
+ goto failed;
|
|
+ }
|
|
+
|
|
+ constructed = 1;
|
|
+
|
|
+ /* Tell the driver about the NIC - this needs to be done before the
|
|
+ resources managers get created below. Note we haven't initialised
|
|
+ the hardware yet, and I don't like doing this before the perhaps
|
|
+ unreliable hardware initialisation. However, there's quite a lot
|
|
+ of code to review if we wanted to hardware init before bringing
|
|
+ up the resource managers. */
|
|
+ rc = efrm_driver_register_nic(&lnic->efrm_nic, nic_index,
|
|
+ /* TODO: ifindex */ nic_index);
|
|
+ if (rc < 0) {
|
|
+ EFRM_ERR("%s: cannot register nic %d with nic error code %d",
|
|
+ __func__, efrm_nic_tablep->nic_count, rc);
|
|
+ goto failed;
|
|
+ }
|
|
+ ++nic_index;
|
|
+ registered_nic = 1;
|
|
+
|
|
+ rc = efrm_nic_buffer_table_alloc(nic);
|
|
+ if (rc < 0)
|
|
+ goto failed;
|
|
+ buffers_allocated = 1;
|
|
+
|
|
+ /****************************************************/
|
|
+ /* hardware bringup */
|
|
+ /****************************************************/
|
|
+ /* Detecting hardware can be a slightly unreliable process;
|
|
+ we want to make sure that we maximise our chances, so we
|
|
+ loop a few times until all is good. */
|
|
+ for (count = 0; count < max_hardware_init_repeats; count++) {
|
|
+ rc = efhw_nic_init_hardware(nic, &ev_handler, mac_addr,
|
|
+ non_irq_evq);
|
|
+ if (rc >= 0)
|
|
+ break;
|
|
+
|
|
+ /* pain */
|
|
+ EFRM_ERR
|
|
+ ("error - hardware initialisation failed code %d, "
|
|
+ "attempt %d of %d", rc, count + 1,
|
|
+ max_hardware_init_repeats);
|
|
+ }
|
|
+ if (rc < 0)
|
|
+ goto failed;
|
|
+
|
|
+ tasklet_init(&lnic->tasklet, efrm_tasklet, (ulong)nic);
|
|
+
|
|
+ /* set up interrupt handlers (hard-irq) */
|
|
+ nic->irq_handler = &efrm_handle_eventq_irq;
|
|
+
|
|
+ /* this device can now take management interrupts */
|
|
+ if (do_irq && !(nic->flags & NIC_FLAG_NO_INTERRUPT)) {
|
|
+ rc = linux_efrm_irq_ctor(lnic);
|
|
+ if (rc < 0) {
|
|
+ EFRM_ERR("Interrupt initialisation failed (%d)", rc);
|
|
+ goto failed;
|
|
+ }
|
|
+ efhw_nic_set_interrupt_moderation(nic, -1, irq_moderation);
|
|
+ efhw_nic_interrupt_enable(nic);
|
|
+ }
|
|
+ EFRM_TRACE("interrupts are %sregistered", do_irq ? "" : "not ");
|
|
+
|
|
+ *lnic_out = lnic;
|
|
+ EFRM_ASSERT(rc == 0);
|
|
+ ++n_nics_probed;
|
|
+ return 0;
|
|
+
|
|
+failed:
|
|
+ if (buffers_allocated)
|
|
+ efrm_nic_buffer_table_free(nic);
|
|
+ if (registered_nic)
|
|
+ efrm_driver_unregister_nic(&lnic->efrm_nic);
|
|
+ if (constructed)
|
|
+ linux_efrm_nic_dtor(lnic);
|
|
+ kfree(lnic); /* safe in any case */
|
|
+ if (resources_init)
|
|
+ efrm_resources_fini();
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/****************************************************************************
|
|
+ *
|
|
+ * efrm_nic_del: Remove the nic from the resource driver structures
|
|
+ *
|
|
+ ****************************************************************************/
|
|
+void efrm_nic_del(struct linux_efhw_nic *lnic)
|
|
+{
|
|
+ struct efhw_nic *nic = &lnic->efrm_nic.efhw_nic;
|
|
+
|
|
+ EFRM_TRACE("%s:", __func__);
|
|
+ EFRM_ASSERT(nic);
|
|
+
|
|
+ efrm_nic_buffer_table_free(nic);
|
|
+
|
|
+ efrm_driver_unregister_nic(&lnic->efrm_nic);
|
|
+
|
|
+ /*
|
|
+ * Synchronise here with any running ISR.
|
|
+ * Remove the OS handler. There should be no IRQs being generated
|
|
+ * by our NIC at this point.
|
|
+ */
|
|
+ if (efhw_nic_have_functional_units(nic)) {
|
|
+ efhw_nic_close_interrupts(nic);
|
|
+ linux_efrm_irq_dtor(lnic);
|
|
+ tasklet_kill(&lnic->tasklet);
|
|
+ }
|
|
+
|
|
+ /* Close down hardware and free resources. */
|
|
+ linux_efrm_nic_dtor(lnic);
|
|
+ kfree(lnic);
|
|
+
|
|
+ if (--n_nics_probed == 0)
|
|
+ efrm_resources_fini();
|
|
+
|
|
+ EFRM_TRACE("%s: done", __func__);
|
|
+}
|
|
+
|
|
+/****************************************************************************
|
|
+ *
|
|
+ * init_module: register as a PCI driver.
|
|
+ *
|
|
+ ****************************************************************************/
|
|
+static int init_sfc_resource(void)
|
|
+{
|
|
+ int rc = 0;
|
|
+
|
|
+ EFRM_TRACE("%s: RESOURCE driver starting", __func__);
|
|
+
|
|
+ efrm_driver_ctor();
|
|
+
|
|
+ /* Register the driver so that our 'probe' function is called for
|
|
+ * each EtherFabric device in the system.
|
|
+ */
|
|
+ rc = efrm_driverlink_register();
|
|
+ if (rc == -ENODEV)
|
|
+ EFRM_ERR("%s: no devices found", __func__);
|
|
+ if (rc < 0)
|
|
+ goto failed_driverlink;
|
|
+
|
|
+ if (efrm_install_proc_entries() != 0) {
|
|
+ /* Do not fail, but print a warning */
|
|
+ EFRM_WARN("%s: WARNING: failed to install /proc entries",
|
|
+ __func__);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+
|
|
+failed_driverlink:
|
|
+ efrm_driver_dtor();
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/****************************************************************************
|
|
+ *
|
|
+ * cleanup_module: module-removal entry-point
|
|
+ *
|
|
+ ****************************************************************************/
|
|
+static void cleanup_sfc_resource(void)
|
|
+{
|
|
+ efrm_uninstall_proc_entries();
|
|
+
|
|
+ efrm_driverlink_unregister();
|
|
+
|
|
+ /* Clean up char-driver specific initialisation.
|
|
+ - driver dtor can use both work queue and buffer table entries */
|
|
+ efrm_driver_dtor();
|
|
+
|
|
+ EFRM_TRACE("%s: unloaded", __func__);
|
|
+}
|
|
+
|
|
+module_init(init_sfc_resource);
|
|
+module_exit(cleanup_sfc_resource);
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/resource_manager.c 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,145 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file contains generic code for resources and resource managers.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#include <ci/efrm/debug.h>
|
|
+#include <ci/efrm/nic_table.h>
|
|
+#include <ci/efhw/iopage.h>
|
|
+#include <ci/efrm/driver_private.h>
|
|
+#include <ci/efrm/private.h>
|
|
+#include "efrm_internal.h"
|
|
+
|
|
+/**********************************************************************
|
|
+ * struct efrm_resource_manager
|
|
+ */
|
|
+
|
|
+void efrm_resource_manager_dtor(struct efrm_resource_manager *rm)
|
|
+{
|
|
+ EFRM_RESOURCE_MANAGER_ASSERT_VALID(rm);
|
|
+
|
|
+ /* call destructor */
|
|
+ EFRM_DO_DEBUG(if (rm->rm_resources)
|
|
+ EFRM_ERR("%s: %s leaked %d resources",
|
|
+ __func__, rm->rm_name, rm->rm_resources));
|
|
+ EFRM_ASSERT(rm->rm_resources == 0);
|
|
+ EFRM_ASSERT(list_empty(&rm->rm_resources_list));
|
|
+
|
|
+ rm->rm_dtor(rm);
|
|
+
|
|
+ /* clear out things built by efrm_resource_manager_ctor */
|
|
+ spin_lock_destroy(&rm->rm_lock);
|
|
+
|
|
+ /* and the free the memory */
|
|
+ EFRM_DO_DEBUG(memset(rm, 0, sizeof(*rm)));
|
|
+ kfree(rm);
|
|
+}
|
|
+
|
|
+/* Construct a resource manager. Resource managers are singletons. */
|
|
+int
|
|
+efrm_resource_manager_ctor(struct efrm_resource_manager *rm,
|
|
+ void (*dtor)(struct efrm_resource_manager *),
|
|
+ const char *name, unsigned type)
|
|
+{
|
|
+ EFRM_ASSERT(rm);
|
|
+ EFRM_ASSERT(dtor);
|
|
+
|
|
+ rm->rm_name = name;
|
|
+ EFRM_DO_DEBUG(rm->rm_type = type);
|
|
+ rm->rm_dtor = dtor;
|
|
+ spin_lock_init(&rm->rm_lock);
|
|
+ rm->rm_resources = 0;
|
|
+ rm->rm_resources_hiwat = 0;
|
|
+ INIT_LIST_HEAD(&rm->rm_resources_list);
|
|
+ EFRM_RESOURCE_MANAGER_ASSERT_VALID(rm);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+void efrm_client_add_resource(struct efrm_client *client,
|
|
+ struct efrm_resource *rs)
|
|
+{
|
|
+ struct efrm_resource_manager *rm;
|
|
+ irq_flags_t lock_flags;
|
|
+
|
|
+ EFRM_ASSERT(client != NULL);
|
|
+ EFRM_ASSERT(rs != NULL);
|
|
+
|
|
+ spin_lock_irqsave(&efrm_nic_tablep->lock, lock_flags);
|
|
+ rm = efrm_rm_table[EFRM_RESOURCE_TYPE(rs->rs_handle)];
|
|
+ ++rm->rm_resources;
|
|
+ list_add(&rs->rs_manager_link, &rm->rm_resources_list);
|
|
+ if (rm->rm_resources > rm->rm_resources_hiwat)
|
|
+ rm->rm_resources_hiwat = rm->rm_resources;
|
|
+ rs->rs_client = client;
|
|
+ ++client->ref_count;
|
|
+ list_add(&rs->rs_client_link, &client->resources);
|
|
+ spin_unlock_irqrestore(&efrm_nic_tablep->lock, lock_flags);
|
|
+}
|
|
+
|
|
+
|
|
+void efrm_resource_ref(struct efrm_resource *rs)
|
|
+{
|
|
+ irq_flags_t lock_flags;
|
|
+ spin_lock_irqsave(&efrm_nic_tablep->lock, lock_flags);
|
|
+ ++rs->rs_ref_count;
|
|
+ spin_unlock_irqrestore(&efrm_nic_tablep->lock, lock_flags);
|
|
+}
|
|
+EXPORT_SYMBOL(efrm_resource_ref);
|
|
+
|
|
+
|
|
+int __efrm_resource_release(struct efrm_resource *rs)
|
|
+{
|
|
+ struct efrm_resource_manager *rm;
|
|
+ irq_flags_t lock_flags;
|
|
+ int free_rs;
|
|
+
|
|
+ spin_lock_irqsave(&efrm_nic_tablep->lock, lock_flags);
|
|
+ free_rs = --rs->rs_ref_count == 0;
|
|
+ if (free_rs) {
|
|
+ rm = efrm_rm_table[EFRM_RESOURCE_TYPE(rs->rs_handle)];
|
|
+ EFRM_ASSERT(rm->rm_resources > 0);
|
|
+ --rm->rm_resources;
|
|
+ list_del(&rs->rs_manager_link);
|
|
+ list_del(&rs->rs_client_link);
|
|
+ }
|
|
+ spin_unlock_irqrestore(&efrm_nic_tablep->lock, lock_flags);
|
|
+ return free_rs;
|
|
+}
|
|
+EXPORT_SYMBOL(__efrm_resource_release);
|
|
+
|
|
+/*
|
|
+ * vi: sw=8:ai:aw
|
|
+ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/resources.c 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,94 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file contains resource managers initialisation functions.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#include <ci/efrm/private.h>
|
|
+#include <ci/efrm/buffer_table.h>
|
|
+
|
|
+int
|
|
+efrm_resources_init(const struct vi_resource_dimensions *vi_res_dim,
|
|
+ int buffer_table_min, int buffer_table_lim)
|
|
+{
|
|
+ int i, rc;
|
|
+
|
|
+ rc = efrm_buffer_table_ctor(buffer_table_min, buffer_table_lim);
|
|
+ if (rc != 0)
|
|
+ return rc;
|
|
+
|
|
+ /* Create resources in the correct order */
|
|
+ for (i = 0; i < EFRM_RESOURCE_NUM; ++i) {
|
|
+ struct efrm_resource_manager **rmp = &efrm_rm_table[i];
|
|
+
|
|
+ EFRM_ASSERT(*rmp == NULL);
|
|
+ switch (i) {
|
|
+ case EFRM_RESOURCE_VI:
|
|
+ rc = efrm_create_vi_resource_manager(rmp,
|
|
+ vi_res_dim);
|
|
+ break;
|
|
+ case EFRM_RESOURCE_FILTER:
|
|
+ rc = efrm_create_filter_resource_manager(rmp);
|
|
+ break;
|
|
+ case EFRM_RESOURCE_IOBUFSET:
|
|
+ rc = efrm_create_iobufset_resource_manager(rmp);
|
|
+ break;
|
|
+ default:
|
|
+ rc = 0;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ if (rc < 0) {
|
|
+ EFRM_ERR("%s: failed type=%d (%d)",
|
|
+ __func__, i, rc);
|
|
+ efrm_buffer_table_dtor();
|
|
+ return rc;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void efrm_resources_fini(void)
|
|
+{
|
|
+ int i;
|
|
+
|
|
+ for (i = EFRM_RESOURCE_NUM - 1; i >= 0; --i)
|
|
+ if (efrm_rm_table[i]) {
|
|
+ efrm_resource_manager_dtor(efrm_rm_table[i]);
|
|
+ efrm_rm_table[i] = NULL;
|
|
+ }
|
|
+
|
|
+ efrm_buffer_table_dtor();
|
|
+}
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/vi_resource_alloc.c 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,820 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file contains allocation of VI resources.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#include <ci/efrm/nic_table.h>
|
|
+#include <ci/efhw/iopage.h>
|
|
+#include <ci/driver/efab/hardware.h>
|
|
+#include <ci/efhw/public.h>
|
|
+#include <ci/efhw/falcon.h>
|
|
+#include <ci/efrm/private.h>
|
|
+#include <ci/efrm/buffer_table.h>
|
|
+#include <ci/efrm/vi_resource_private.h>
|
|
+#include <ci/efrm/efrm_client.h>
|
|
+#include "efrm_internal.h"
|
|
+
|
|
+
|
|
+/*** Data definitions ****************************************************/
|
|
+
|
|
+static const char *dmaq_names[] = { "TX", "RX" };
|
|
+
|
|
+struct vi_resource_manager *efrm_vi_manager;
|
|
+
|
|
+/*** Forward references **************************************************/
|
|
+
|
|
+static int
|
|
+efrm_vi_resource_alloc_or_free(struct efrm_client *client,
|
|
+ int alloc, struct vi_resource *evq_virs,
|
|
+ uint16_t vi_flags, int32_t evq_capacity,
|
|
+ int32_t txq_capacity, int32_t rxq_capacity,
|
|
+ uint8_t tx_q_tag, uint8_t rx_q_tag,
|
|
+ struct vi_resource **virs_in_out);
|
|
+
|
|
+/*** Reference count handling ********************************************/
|
|
+
|
|
+static inline void efrm_vi_rm_get_ref(struct vi_resource *virs)
|
|
+{
|
|
+ atomic_inc(&virs->evq_refs);
|
|
+}
|
|
+
|
|
+static inline void efrm_vi_rm_drop_ref(struct vi_resource *virs)
|
|
+{
|
|
+ EFRM_ASSERT(atomic_read(&virs->evq_refs) != 0);
|
|
+ if (atomic_dec_and_test(&virs->evq_refs))
|
|
+ efrm_vi_resource_alloc_or_free(virs->rs.rs_client, false, NULL,
|
|
+ 0, 0, 0, 0, 0, 0, &virs);
|
|
+}
|
|
+
|
|
+/*** Instance numbers ****************************************************/
|
|
+
|
|
+static inline int efrm_vi_rm_alloc_id(uint16_t vi_flags, int32_t evq_capacity)
|
|
+{
|
|
+ irq_flags_t lock_flags;
|
|
+ int instance;
|
|
+ int rc;
|
|
+
|
|
+ if (efrm_nic_tablep->a_nic == NULL) /* ?? FIXME: surely not right */
|
|
+ return -ENODEV;
|
|
+
|
|
+ spin_lock_irqsave(&efrm_vi_manager->rm.rm_lock, lock_flags);
|
|
+
|
|
+ /* Falcon A1 RX phys addr wierdness. */
|
|
+ if (efrm_nic_tablep->a_nic->devtype.variant == 'A' &&
|
|
+ (vi_flags & EFHW_VI_RX_PHYS_ADDR_EN)) {
|
|
+ if (vi_flags & EFHW_VI_JUMBO_EN) {
|
|
+ /* Falcon-A cannot do phys + scatter. */
|
|
+ EFRM_WARN
|
|
+ ("%s: falcon-A does not support phys+scatter mode",
|
|
+ __func__);
|
|
+ instance = -1;
|
|
+ } else if (efrm_vi_manager->iscsi_dmaq_instance_is_free
|
|
+ && evq_capacity == 0) {
|
|
+ /* Falcon-A has a single RXQ that gives the correct
|
|
+ * semantics for physical addressing. However, it
|
|
+ * happens to have the same instance number as the
|
|
+ * 'char' event queue, so we cannot also hand out
|
|
+ * the event queue. */
|
|
+ efrm_vi_manager->iscsi_dmaq_instance_is_free = false;
|
|
+ instance = FALCON_A1_ISCSI_DMAQ;
|
|
+ } else {
|
|
+ EFRM_WARN("%s: iSCSI receive queue not free",
|
|
+ __func__);
|
|
+ instance = -1;
|
|
+ }
|
|
+ goto unlock_out;
|
|
+ }
|
|
+
|
|
+ if (vi_flags & EFHW_VI_RM_WITH_INTERRUPT) {
|
|
+ rc = __kfifo_get(efrm_vi_manager->instances_with_interrupt,
|
|
+ (unsigned char *)&instance, sizeof(instance));
|
|
+ if (rc != sizeof(instance)) {
|
|
+ EFRM_ASSERT(rc == 0);
|
|
+ instance = -1;
|
|
+ }
|
|
+ goto unlock_out;
|
|
+ }
|
|
+
|
|
+ /* Otherwise a normal run-of-the-mill VI. */
|
|
+ rc = __kfifo_get(efrm_vi_manager->instances_with_timer,
|
|
+ (unsigned char *)&instance, sizeof(instance));
|
|
+ if (rc != sizeof(instance)) {
|
|
+ EFRM_ASSERT(rc == 0);
|
|
+ instance = -1;
|
|
+ }
|
|
+
|
|
+unlock_out:
|
|
+ spin_unlock_irqrestore(&efrm_vi_manager->rm.rm_lock, lock_flags);
|
|
+ return instance;
|
|
+}
|
|
+
|
|
+static void efrm_vi_rm_free_id(int instance)
|
|
+{
|
|
+ irq_flags_t lock_flags;
|
|
+ struct kfifo *instances;
|
|
+
|
|
+ if (efrm_nic_tablep->a_nic == NULL) /* ?? FIXME: surely not right */
|
|
+ return;
|
|
+
|
|
+ if (efrm_nic_tablep->a_nic->devtype.variant == 'A' &&
|
|
+ instance == FALCON_A1_ISCSI_DMAQ) {
|
|
+ EFRM_ASSERT(efrm_vi_manager->iscsi_dmaq_instance_is_free ==
|
|
+ false);
|
|
+ spin_lock_irqsave(&efrm_vi_manager->rm.rm_lock, lock_flags);
|
|
+ efrm_vi_manager->iscsi_dmaq_instance_is_free = true;
|
|
+ spin_unlock_irqrestore(&efrm_vi_manager->rm.rm_lock,
|
|
+ lock_flags);
|
|
+ } else {
|
|
+ if (instance >= efrm_vi_manager->with_timer_base &&
|
|
+ instance < efrm_vi_manager->with_timer_limit) {
|
|
+ instances = efrm_vi_manager->instances_with_timer;
|
|
+ } else {
|
|
+ EFRM_ASSERT(instance >=
|
|
+ efrm_vi_manager->with_interrupt_base);
|
|
+ EFRM_ASSERT(instance <
|
|
+ efrm_vi_manager->with_interrupt_limit);
|
|
+ instances = efrm_vi_manager->instances_with_interrupt;
|
|
+ }
|
|
+
|
|
+ EFRM_VERIFY_EQ(kfifo_put(instances, (unsigned char *)&instance,
|
|
+ sizeof(instance)), sizeof(instance));
|
|
+ }
|
|
+}
|
|
+
|
|
+/*** Queue sizes *********************************************************/
|
|
+
|
|
+/* NB. This should really take a nic as an argument, but that makes
|
|
+ * the buffer table allocation difficult. */
|
|
+uint32_t efrm_vi_rm_evq_bytes(struct vi_resource *virs
|
|
+ /*,struct efhw_nic *nic */)
|
|
+{
|
|
+ return virs->evq_capacity * sizeof(efhw_event_t);
|
|
+}
|
|
+EXPORT_SYMBOL(efrm_vi_rm_evq_bytes);
|
|
+
|
|
+/* NB. This should really take a nic as an argument, but that makes
|
|
+ * the buffer table allocation difficult. */
|
|
+uint32_t efrm_vi_rm_txq_bytes(struct vi_resource *virs
|
|
+ /*,struct efhw_nic *nic */)
|
|
+{
|
|
+ return virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX] *
|
|
+ FALCON_DMA_TX_DESC_BYTES;
|
|
+}
|
|
+EXPORT_SYMBOL(efrm_vi_rm_txq_bytes);
|
|
+
|
|
+/* NB. This should really take a nic as an argument, but that makes
|
|
+ * the buffer table allocation difficult. */
|
|
+uint32_t efrm_vi_rm_rxq_bytes(struct vi_resource *virs
|
|
+ /*,struct efhw_nic *nic */)
|
|
+{
|
|
+ uint32_t bytes_per_desc = ((virs->flags & EFHW_VI_RX_PHYS_ADDR_EN)
|
|
+ ? FALCON_DMA_RX_PHYS_DESC_BYTES
|
|
+ : FALCON_DMA_RX_BUF_DESC_BYTES);
|
|
+ return virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX] * bytes_per_desc;
|
|
+}
|
|
+EXPORT_SYMBOL(efrm_vi_rm_rxq_bytes);
|
|
+
|
|
+static int choose_size(int size_rq, unsigned sizes)
|
|
+{
|
|
+ int size;
|
|
+
|
|
+ /* size_rq < 0 means default, but we interpret this as 'minimum'. */
|
|
+
|
|
+ for (size = 256;; size <<= 1)
|
|
+ if ((size & sizes) && size >= size_rq)
|
|
+ return size;
|
|
+ else if ((sizes & ~((size - 1) | size)) == 0)
|
|
+ return -1;
|
|
+}
|
|
+
|
|
+static int
|
|
+efrm_vi_rm_adjust_alloc_request(struct vi_resource *virs, struct efhw_nic *nic)
|
|
+{
|
|
+ int capacity;
|
|
+
|
|
+ EFRM_ASSERT(nic->efhw_func);
|
|
+
|
|
+ if (virs->evq_capacity) {
|
|
+ capacity = choose_size(virs->evq_capacity, nic->evq_sizes);
|
|
+ if (capacity < 0) {
|
|
+ EFRM_ERR("vi_resource: bad evq size %d (supported=%x)",
|
|
+ virs->evq_capacity, nic->evq_sizes);
|
|
+ return -E2BIG;
|
|
+ }
|
|
+ virs->evq_capacity = capacity;
|
|
+ }
|
|
+ if (virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX]) {
|
|
+ capacity =
|
|
+ choose_size(virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX],
|
|
+ nic->txq_sizes);
|
|
+ if (capacity < 0) {
|
|
+ EFRM_ERR("vi_resource: bad txq size %d (supported=%x)",
|
|
+ virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX],
|
|
+ nic->txq_sizes);
|
|
+ return -E2BIG;
|
|
+ }
|
|
+ virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX] = capacity;
|
|
+ }
|
|
+ if (virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX]) {
|
|
+ capacity =
|
|
+ choose_size(virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX],
|
|
+ nic->rxq_sizes);
|
|
+ if (capacity < 0) {
|
|
+ EFRM_ERR("vi_resource: bad rxq size %d (supported=%x)",
|
|
+ virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX],
|
|
+ nic->rxq_sizes);
|
|
+ return -E2BIG;
|
|
+ }
|
|
+ virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX] = capacity;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+/* remove the reference to the event queue in this VI resource and decrement
|
|
+ the event queue's use count */
|
|
+static inline void efrm_vi_rm_detach_evq(struct vi_resource *virs)
|
|
+{
|
|
+ struct vi_resource *evq_virs;
|
|
+
|
|
+ EFRM_ASSERT(virs != NULL);
|
|
+
|
|
+ evq_virs = virs->evq_virs;
|
|
+
|
|
+ if (evq_virs != NULL) {
|
|
+ virs->evq_virs = NULL;
|
|
+ if (evq_virs == virs) {
|
|
+ EFRM_TRACE("%s: " EFRM_RESOURCE_FMT
|
|
+ " had internal event queue ", __func__,
|
|
+ EFRM_RESOURCE_PRI_ARG(virs->rs.rs_handle));
|
|
+ } else {
|
|
+ efrm_vi_rm_drop_ref(evq_virs);
|
|
+ EFRM_TRACE("%s: " EFRM_RESOURCE_FMT " had event queue "
|
|
+ EFRM_RESOURCE_FMT, __func__,
|
|
+ EFRM_RESOURCE_PRI_ARG(virs->rs.rs_handle),
|
|
+ EFRM_RESOURCE_PRI_ARG(evq_virs->rs.
|
|
+ rs_handle));
|
|
+ }
|
|
+ } else {
|
|
+ EFRM_TRACE("%s: " EFRM_RESOURCE_FMT
|
|
+ " had no event queue (nothing to do)",
|
|
+ __func__,
|
|
+ EFRM_RESOURCE_PRI_ARG(virs->rs.rs_handle));
|
|
+ }
|
|
+}
|
|
+
|
|
+/*** Buffer Table allocations ********************************************/
|
|
+
|
|
+static int
|
|
+efrm_vi_rm_alloc_or_free_buffer_table(struct vi_resource *virs, bool is_alloc)
|
|
+{
|
|
+ uint32_t bytes;
|
|
+ int page_order;
|
|
+ int rc;
|
|
+
|
|
+ if (!is_alloc)
|
|
+ goto destroy;
|
|
+
|
|
+ if (virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX]) {
|
|
+ bytes = efrm_vi_rm_txq_bytes(virs);
|
|
+ page_order = get_order(bytes);
|
|
+ rc = efrm_buffer_table_alloc(page_order,
|
|
+ (virs->dmaq_buf_tbl_alloc +
|
|
+ EFRM_VI_RM_DMA_QUEUE_TX));
|
|
+ if (rc != 0) {
|
|
+ EFRM_TRACE
|
|
+ ("%s: Error %d allocating TX buffer table entry",
|
|
+ __func__, rc);
|
|
+ goto fail_txq_alloc;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX]) {
|
|
+ bytes = efrm_vi_rm_rxq_bytes(virs);
|
|
+ page_order = get_order(bytes);
|
|
+ rc = efrm_buffer_table_alloc(page_order,
|
|
+ (virs->dmaq_buf_tbl_alloc +
|
|
+ EFRM_VI_RM_DMA_QUEUE_RX));
|
|
+ if (rc != 0) {
|
|
+ EFRM_TRACE
|
|
+ ("%s: Error %d allocating RX buffer table entry",
|
|
+ __func__, rc);
|
|
+ goto fail_rxq_alloc;
|
|
+ }
|
|
+ }
|
|
+ return 0;
|
|
+
|
|
+destroy:
|
|
+ rc = 0;
|
|
+
|
|
+ if (virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX]) {
|
|
+ efrm_buffer_table_free(&virs->
|
|
+ dmaq_buf_tbl_alloc
|
|
+ [EFRM_VI_RM_DMA_QUEUE_RX]);
|
|
+ }
|
|
+fail_rxq_alloc:
|
|
+
|
|
+ if (virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX]) {
|
|
+ efrm_buffer_table_free(&virs->
|
|
+ dmaq_buf_tbl_alloc
|
|
+ [EFRM_VI_RM_DMA_QUEUE_TX]);
|
|
+ }
|
|
+fail_txq_alloc:
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*** Per-NIC allocations *************************************************/
|
|
+
|
|
+static inline int
|
|
+efrm_vi_rm_init_evq(struct vi_resource *virs, struct efhw_nic *nic)
|
|
+{
|
|
+ int instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle);
|
|
+ struct eventq_resource_hardware *evq_hw =
|
|
+ &virs->nic_info.evq_pages;
|
|
+ uint32_t buf_bytes = efrm_vi_rm_evq_bytes(virs);
|
|
+ int rc;
|
|
+
|
|
+ if (virs->evq_capacity == 0)
|
|
+ return 0;
|
|
+ evq_hw->capacity = virs->evq_capacity;
|
|
+
|
|
+ /* Allocate buffer table entries to map onto the iobuffer. This
|
|
+ * currently allocates its own buffer table entries on Falcon which is
|
|
+ * a bit wasteful on a multi-NIC system. */
|
|
+ evq_hw->buf_tbl_alloc.base = (unsigned)-1;
|
|
+ rc = efrm_buffer_table_alloc(get_order(buf_bytes),
|
|
+ &evq_hw->buf_tbl_alloc);
|
|
+ if (rc < 0) {
|
|
+ EFHW_WARN("%s: failed (%d) to alloc %d buffer table entries",
|
|
+ __func__, rc, get_order(buf_bytes));
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ /* Allocate the event queue memory. */
|
|
+ rc = efhw_nic_event_queue_alloc_iobuffer(nic, evq_hw, instance,
|
|
+ buf_bytes);
|
|
+ if (rc != 0) {
|
|
+ EFRM_ERR("%s: Error allocating iobuffer: %d", __func__, rc);
|
|
+ efrm_buffer_table_free(&evq_hw->buf_tbl_alloc);
|
|
+ return rc;
|
|
+ }
|
|
+
|
|
+ /* Initialise the event queue hardware */
|
|
+ efhw_nic_event_queue_enable(nic, instance, virs->evq_capacity,
|
|
+ efhw_iopages_dma_addr(&evq_hw->iobuff) +
|
|
+ evq_hw->iobuff_off,
|
|
+ evq_hw->buf_tbl_alloc.base,
|
|
+ instance < 64);
|
|
+
|
|
+ EFRM_TRACE("%s: " EFRM_RESOURCE_FMT " capacity=%u", __func__,
|
|
+ EFRM_RESOURCE_PRI_ARG(virs->rs.rs_handle),
|
|
+ virs->evq_capacity);
|
|
+
|
|
+#if defined(__ia64__)
|
|
+ /* Page size may be large, so for now just increase the
|
|
+ * size of the requested evq up to a round number of
|
|
+ * pages
|
|
+ */
|
|
+ buf_bytes = CI_ROUNDUP(buf_bytes, PAGE_SIZE);
|
|
+#endif
|
|
+ EFRM_ASSERT(buf_bytes % PAGE_SIZE == 0);
|
|
+
|
|
+ virs->mem_mmap_bytes += buf_bytes;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static inline void
|
|
+efrm_vi_rm_fini_evq(struct vi_resource *virs, struct efhw_nic *nic)
|
|
+{
|
|
+ int instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle);
|
|
+ struct vi_resource_nic_info *nic_info = &virs->nic_info;
|
|
+
|
|
+ if (virs->evq_capacity == 0)
|
|
+ return;
|
|
+
|
|
+ /* Zero the timer-value for this queue.
|
|
+ And Tell NIC to stop using this event queue. */
|
|
+ efhw_nic_event_queue_disable(nic, instance, 0);
|
|
+
|
|
+ if (nic_info->evq_pages.buf_tbl_alloc.base != (unsigned)-1)
|
|
+ efrm_buffer_table_free(&nic_info->evq_pages.buf_tbl_alloc);
|
|
+
|
|
+ efhw_iopages_free(nic, &nic_info->evq_pages.iobuff);
|
|
+}
|
|
+
|
|
+/*! FIXME: we should make sure this number is never zero (=> unprotected) */
|
|
+/*! FIXME: put this definition in a relevant header (e.g. as (evqid)+1) */
|
|
+#define EFAB_EVQ_OWNER_ID(evqid) ((evqid))
|
|
+
|
|
+void
|
|
+efrm_vi_rm_init_dmaq(struct vi_resource *virs, int queue_type,
|
|
+ struct efhw_nic *nic)
|
|
+{
|
|
+ int instance;
|
|
+ int evq_instance;
|
|
+ efhw_buffer_addr_t buf_addr;
|
|
+
|
|
+ instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle);
|
|
+ evq_instance = EFRM_RESOURCE_INSTANCE(virs->evq_virs->rs.rs_handle);
|
|
+
|
|
+ buf_addr = virs->dmaq_buf_tbl_alloc[queue_type].base;
|
|
+
|
|
+ if (queue_type == EFRM_VI_RM_DMA_QUEUE_TX) {
|
|
+ efhw_nic_dmaq_tx_q_init(nic,
|
|
+ instance, /* dmaq */
|
|
+ evq_instance, /* evq */
|
|
+ EFAB_EVQ_OWNER_ID(evq_instance), /* owner */
|
|
+ virs->dmaq_tag[queue_type], /* tag */
|
|
+ virs->dmaq_capacity[queue_type], /* size of queue */
|
|
+ buf_addr, /* buffer index */
|
|
+ virs->flags); /* user specified Q attrs */
|
|
+ } else {
|
|
+ efhw_nic_dmaq_rx_q_init(nic,
|
|
+ instance, /* dmaq */
|
|
+ evq_instance, /* evq */
|
|
+ EFAB_EVQ_OWNER_ID(evq_instance), /* owner */
|
|
+ virs->dmaq_tag[queue_type], /* tag */
|
|
+ virs->dmaq_capacity[queue_type], /* size of queue */
|
|
+ buf_addr, /* buffer index */
|
|
+ virs->flags); /* user specified Q attrs */
|
|
+ }
|
|
+}
|
|
+
|
|
+static int
|
|
+efrm_vi_rm_init_or_fini_dmaq(struct vi_resource *virs,
|
|
+ int queue_type, int init,
|
|
+ struct efhw_nic *nic)
|
|
+{
|
|
+ int rc;
|
|
+ int instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle);
|
|
+ uint32_t buf_bytes;
|
|
+ struct vi_resource_nic_info *nic_info = &virs->nic_info;
|
|
+ int page_order;
|
|
+ uint32_t num_pages;
|
|
+ struct efhw_iopages *iobuff;
|
|
+
|
|
+ if (!init)
|
|
+ goto destroy;
|
|
+
|
|
+ /* Ignore disabled queues. */
|
|
+ if (virs->dmaq_capacity[queue_type] == 0) {
|
|
+ if (queue_type == EFRM_VI_RM_DMA_QUEUE_TX)
|
|
+ efhw_nic_dmaq_tx_q_disable(nic, instance);
|
|
+ else
|
|
+ efhw_nic_dmaq_rx_q_disable(nic, instance);
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ buf_bytes = (queue_type == EFRM_VI_RM_DMA_QUEUE_TX
|
|
+ ? efrm_vi_rm_txq_bytes(virs)
|
|
+ : efrm_vi_rm_rxq_bytes(virs));
|
|
+
|
|
+ page_order = get_order(buf_bytes);
|
|
+
|
|
+ rc = efhw_iopages_alloc(nic, &nic_info->dmaq_pages[queue_type],
|
|
+ page_order);
|
|
+ if (rc != 0) {
|
|
+ EFRM_ERR("%s: Failed to allocate %s DMA buffer.", __func__,
|
|
+ dmaq_names[queue_type]);
|
|
+ goto fail_iopages;
|
|
+ }
|
|
+
|
|
+ num_pages = 1 << page_order;
|
|
+ iobuff = &nic_info->dmaq_pages[queue_type];
|
|
+ efhw_nic_buffer_table_set_n(nic,
|
|
+ virs->dmaq_buf_tbl_alloc[queue_type].base,
|
|
+ efhw_iopages_dma_addr(iobuff),
|
|
+ EFHW_NIC_PAGE_SIZE, 0, num_pages, 0);
|
|
+
|
|
+ falcon_nic_buffer_table_confirm(nic);
|
|
+
|
|
+ virs->mem_mmap_bytes += roundup(buf_bytes, PAGE_SIZE);
|
|
+
|
|
+ /* Make sure there is an event queue. */
|
|
+ if (virs->evq_virs->evq_capacity <= 0) {
|
|
+ EFRM_ERR("%s: Cannot use empty event queue for %s DMA",
|
|
+ __func__, dmaq_names[queue_type]);
|
|
+ rc = -EINVAL;
|
|
+ goto fail_evq;
|
|
+ }
|
|
+
|
|
+ efrm_vi_rm_init_dmaq(virs, queue_type, nic);
|
|
+
|
|
+ return 0;
|
|
+
|
|
+destroy:
|
|
+ rc = 0;
|
|
+
|
|
+ /* Ignore disabled queues. */
|
|
+ if (virs->dmaq_capacity[queue_type] == 0)
|
|
+ return 0;
|
|
+
|
|
+ /* Ensure TX pacing turned off -- queue flush doesn't reset this. */
|
|
+ if (queue_type == EFRM_VI_RM_DMA_QUEUE_TX)
|
|
+ falcon_nic_pace(nic, instance, 0);
|
|
+
|
|
+ /* No need to disable the queue here. Nobody is using it anyway. */
|
|
+
|
|
+fail_evq:
|
|
+ efhw_iopages_free(nic, &nic_info->dmaq_pages[queue_type]);
|
|
+fail_iopages:
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static int
|
|
+efrm_vi_rm_init_or_fini_nic(struct vi_resource *virs, int init,
|
|
+ struct efhw_nic *nic)
|
|
+{
|
|
+ int rc;
|
|
+#ifndef NDEBUG
|
|
+ int instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle);
|
|
+#endif
|
|
+
|
|
+ if (!init)
|
|
+ goto destroy;
|
|
+
|
|
+ rc = efrm_vi_rm_init_evq(virs, nic);
|
|
+ if (rc != 0)
|
|
+ goto fail_evq;
|
|
+
|
|
+ rc = efrm_vi_rm_init_or_fini_dmaq(virs, EFRM_VI_RM_DMA_QUEUE_TX,
|
|
+ init, nic);
|
|
+ if (rc != 0)
|
|
+ goto fail_txq;
|
|
+
|
|
+ rc = efrm_vi_rm_init_or_fini_dmaq(virs, EFRM_VI_RM_DMA_QUEUE_RX,
|
|
+ init, nic);
|
|
+ if (rc != 0)
|
|
+ goto fail_rxq;
|
|
+
|
|
+ /* Allocate space for the control page. */
|
|
+ EFRM_ASSERT(falcon_tx_dma_page_offset(instance) < PAGE_SIZE);
|
|
+ EFRM_ASSERT(falcon_rx_dma_page_offset(instance) < PAGE_SIZE);
|
|
+ EFRM_ASSERT(falcon_timer_page_offset(instance) < PAGE_SIZE);
|
|
+ virs->bar_mmap_bytes += PAGE_SIZE;
|
|
+
|
|
+ return 0;
|
|
+
|
|
+destroy:
|
|
+ rc = 0;
|
|
+
|
|
+ efrm_vi_rm_init_or_fini_dmaq(virs, EFRM_VI_RM_DMA_QUEUE_RX,
|
|
+ false, nic);
|
|
+fail_rxq:
|
|
+
|
|
+ efrm_vi_rm_init_or_fini_dmaq(virs, EFRM_VI_RM_DMA_QUEUE_TX,
|
|
+ false, nic);
|
|
+fail_txq:
|
|
+
|
|
+ efrm_vi_rm_fini_evq(virs, nic);
|
|
+fail_evq:
|
|
+
|
|
+ EFRM_ASSERT(rc != 0 || !init);
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+static int
|
|
+efrm_vi_resource_alloc_or_free(struct efrm_client *client,
|
|
+ int alloc, struct vi_resource *evq_virs,
|
|
+ uint16_t vi_flags, int32_t evq_capacity,
|
|
+ int32_t txq_capacity, int32_t rxq_capacity,
|
|
+ uint8_t tx_q_tag, uint8_t rx_q_tag,
|
|
+ struct vi_resource **virs_in_out)
|
|
+{
|
|
+ struct efhw_nic *nic = client->nic;
|
|
+ struct vi_resource *virs;
|
|
+ int rc;
|
|
+ int instance;
|
|
+
|
|
+ EFRM_ASSERT(virs_in_out);
|
|
+ EFRM_ASSERT(efrm_vi_manager);
|
|
+ EFRM_RESOURCE_MANAGER_ASSERT_VALID(&efrm_vi_manager->rm);
|
|
+
|
|
+ if (!alloc)
|
|
+ goto destroy;
|
|
+
|
|
+ rx_q_tag &= (1 << TX_DESCQ_LABEL_WIDTH) - 1;
|
|
+ tx_q_tag &= (1 << RX_DESCQ_LABEL_WIDTH) - 1;
|
|
+
|
|
+ virs = kmalloc(sizeof(*virs), GFP_KERNEL);
|
|
+ if (virs == NULL) {
|
|
+ EFRM_ERR("%s: Error allocating VI resource object",
|
|
+ __func__);
|
|
+ rc = -ENOMEM;
|
|
+ goto fail_alloc;
|
|
+ }
|
|
+ memset(virs, 0, sizeof(*virs));
|
|
+
|
|
+ /* Some macros make the assumption that the struct efrm_resource is
|
|
+ * the first member of a struct vi_resource. */
|
|
+ EFRM_ASSERT(&virs->rs == (struct efrm_resource *) (virs));
|
|
+
|
|
+ instance = efrm_vi_rm_alloc_id(vi_flags, evq_capacity);
|
|
+ if (instance < 0) {
|
|
+ /* Clear out the close list... */
|
|
+ efrm_vi_rm_salvage_flushed_vis();
|
|
+ instance = efrm_vi_rm_alloc_id(vi_flags, evq_capacity);
|
|
+ if (instance >= 0)
|
|
+ EFRM_TRACE("%s: Salvaged a closed VI.", __func__);
|
|
+ }
|
|
+
|
|
+ if (instance < 0) {
|
|
+ /* Could flush resources and try again here. */
|
|
+ EFRM_ERR("%s: Out of appropriate VI resources", __func__);
|
|
+ rc = -EBUSY;
|
|
+ goto fail_alloc_id;
|
|
+ }
|
|
+
|
|
+ EFRM_TRACE("%s: new VI ID %d", __func__, instance);
|
|
+ efrm_resource_init(&virs->rs, EFRM_RESOURCE_VI, instance);
|
|
+
|
|
+ /* Start with one reference. Any external VIs using the EVQ of this
|
|
+ * resource will increment this reference rather than the resource
|
|
+ * reference to avoid DMAQ flushes from waiting for other DMAQ
|
|
+ * flushes to complete. When the resource reference goes to zero,
|
|
+ * the DMAQ flush happens. When the flush completes, this reference
|
|
+ * is decremented. When this reference reaches zero, the instance
|
|
+ * is freed. */
|
|
+ atomic_set(&virs->evq_refs, 1);
|
|
+
|
|
+ virs->bar_mmap_bytes = 0;
|
|
+ virs->mem_mmap_bytes = 0;
|
|
+ virs->evq_capacity = evq_capacity;
|
|
+ virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX] = txq_capacity;
|
|
+ virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX] = rxq_capacity;
|
|
+ virs->dmaq_tag[EFRM_VI_RM_DMA_QUEUE_TX] = tx_q_tag;
|
|
+ virs->dmaq_tag[EFRM_VI_RM_DMA_QUEUE_RX] = rx_q_tag;
|
|
+ virs->flags = vi_flags;
|
|
+ INIT_LIST_HEAD(&virs->tx_flush_link);
|
|
+ INIT_LIST_HEAD(&virs->rx_flush_link);
|
|
+ virs->tx_flushing = 0;
|
|
+ virs->rx_flushing = 0;
|
|
+
|
|
+ /* Adjust the queue sizes. */
|
|
+ rc = efrm_vi_rm_adjust_alloc_request(virs, nic);
|
|
+ if (rc != 0)
|
|
+ goto fail_adjust_request;
|
|
+
|
|
+ /* Attach the EVQ early so that we can ensure that the NIC sets
|
|
+ * match. */
|
|
+ if (evq_virs == NULL) {
|
|
+ evq_virs = virs;
|
|
+ EFRM_TRACE("%s: " EFRM_RESOURCE_FMT
|
|
+ " has no external event queue", __func__,
|
|
+ EFRM_RESOURCE_PRI_ARG(virs->rs.rs_handle));
|
|
+ } else {
|
|
+ /* Make sure the resource managers are the same. */
|
|
+ if (EFRM_RESOURCE_TYPE(evq_virs->rs.rs_handle) !=
|
|
+ EFRM_RESOURCE_VI) {
|
|
+ EFRM_ERR("%s: Mismatched owner for event queue VI "
|
|
+ EFRM_RESOURCE_FMT, __func__,
|
|
+ EFRM_RESOURCE_PRI_ARG(evq_virs->rs.rs_handle));
|
|
+ return -EINVAL;
|
|
+ }
|
|
+ EFRM_ASSERT(atomic_read(&evq_virs->evq_refs) != 0);
|
|
+ efrm_vi_rm_get_ref(evq_virs);
|
|
+ EFRM_TRACE("%s: " EFRM_RESOURCE_FMT " uses event queue "
|
|
+ EFRM_RESOURCE_FMT,
|
|
+ __func__,
|
|
+ EFRM_RESOURCE_PRI_ARG(virs->rs.rs_handle),
|
|
+ EFRM_RESOURCE_PRI_ARG(evq_virs->rs.rs_handle));
|
|
+ }
|
|
+ virs->evq_virs = evq_virs;
|
|
+
|
|
+ rc = efrm_vi_rm_alloc_or_free_buffer_table(virs, true);
|
|
+ if (rc != 0)
|
|
+ goto fail_buffer_table;
|
|
+
|
|
+ rc = efrm_vi_rm_init_or_fini_nic(virs, true, nic);
|
|
+ if (rc != 0)
|
|
+ goto fail_init_nic;
|
|
+
|
|
+ efrm_client_add_resource(client, &virs->rs);
|
|
+ *virs_in_out = virs;
|
|
+ EFRM_TRACE("%s: Allocated " EFRM_RESOURCE_FMT, __func__,
|
|
+ EFRM_RESOURCE_PRI_ARG(virs->rs.rs_handle));
|
|
+ return 0;
|
|
+
|
|
+destroy:
|
|
+ virs = *virs_in_out;
|
|
+ EFRM_RESOURCE_ASSERT_VALID(&virs->rs, 1);
|
|
+ instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle);
|
|
+
|
|
+ EFRM_TRACE("%s: Freeing %d", __func__,
|
|
+ EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle));
|
|
+
|
|
+ /* Destroying the VI. The reference count must be zero. */
|
|
+ EFRM_ASSERT(atomic_read(&virs->evq_refs) == 0);
|
|
+
|
|
+ /* The EVQ should have gone (and DMA disabled) so that this
|
|
+ * function can't be re-entered to destroy the EVQ VI. */
|
|
+ EFRM_ASSERT(virs->evq_virs == NULL);
|
|
+ rc = 0;
|
|
+
|
|
+fail_init_nic:
|
|
+ efrm_vi_rm_init_or_fini_nic(virs, false, nic);
|
|
+
|
|
+ efrm_vi_rm_alloc_or_free_buffer_table(virs, false);
|
|
+fail_buffer_table:
|
|
+
|
|
+ efrm_vi_rm_detach_evq(virs);
|
|
+
|
|
+fail_adjust_request:
|
|
+
|
|
+ EFRM_ASSERT(virs->evq_callback_fn == NULL);
|
|
+ EFRM_TRACE("%s: delete VI ID %d", __func__, instance);
|
|
+ efrm_vi_rm_free_id(instance);
|
|
+fail_alloc_id:
|
|
+ if (!alloc)
|
|
+ efrm_client_put(virs->rs.rs_client);
|
|
+ EFRM_DO_DEBUG(memset(virs, 0, sizeof(*virs)));
|
|
+ kfree(virs);
|
|
+fail_alloc:
|
|
+ *virs_in_out = NULL;
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+/*** Resource object ****************************************************/
|
|
+
|
|
+int
|
|
+efrm_vi_resource_alloc(struct efrm_client *client,
|
|
+ struct vi_resource *evq_virs,
|
|
+ uint16_t vi_flags, int32_t evq_capacity,
|
|
+ int32_t txq_capacity, int32_t rxq_capacity,
|
|
+ uint8_t tx_q_tag, uint8_t rx_q_tag,
|
|
+ struct vi_resource **virs_out,
|
|
+ uint32_t *out_io_mmap_bytes,
|
|
+ uint32_t *out_mem_mmap_bytes,
|
|
+ uint32_t *out_txq_capacity, uint32_t *out_rxq_capacity)
|
|
+{
|
|
+ int rc;
|
|
+ EFRM_ASSERT(client != NULL);
|
|
+ rc = efrm_vi_resource_alloc_or_free(client, true, evq_virs, vi_flags,
|
|
+ evq_capacity, txq_capacity,
|
|
+ rxq_capacity, tx_q_tag, rx_q_tag,
|
|
+ virs_out);
|
|
+ if (rc == 0) {
|
|
+ if (out_io_mmap_bytes != NULL)
|
|
+ *out_io_mmap_bytes = (*virs_out)->bar_mmap_bytes;
|
|
+ if (out_mem_mmap_bytes != NULL)
|
|
+ *out_mem_mmap_bytes = (*virs_out)->mem_mmap_bytes;
|
|
+ if (out_txq_capacity != NULL)
|
|
+ *out_txq_capacity =
|
|
+ (*virs_out)->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX];
|
|
+ if (out_rxq_capacity != NULL)
|
|
+ *out_rxq_capacity =
|
|
+ (*virs_out)->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX];
|
|
+ }
|
|
+
|
|
+ return rc;
|
|
+}
|
|
+EXPORT_SYMBOL(efrm_vi_resource_alloc);
|
|
+
|
|
+void efrm_vi_rm_free_flushed_resource(struct vi_resource *virs)
|
|
+{
|
|
+ EFRM_ASSERT(virs != NULL);
|
|
+ EFRM_ASSERT(virs->rs.rs_ref_count == 0);
|
|
+
|
|
+ EFRM_TRACE("%s: " EFRM_RESOURCE_FMT, __func__,
|
|
+ EFRM_RESOURCE_PRI_ARG(virs->rs.rs_handle));
|
|
+ /* release the associated event queue then drop our own reference
|
|
+ * count */
|
|
+ efrm_vi_rm_detach_evq(virs);
|
|
+ efrm_vi_rm_drop_ref(virs);
|
|
+}
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/vi_resource_event.c 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,250 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file contains event handling for VI resource.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#include <ci/efrm/nic_table.h>
|
|
+#include <ci/driver/efab/hardware.h>
|
|
+#include <ci/efhw/eventq.h>
|
|
+#include <ci/efrm/private.h>
|
|
+#include <ci/efrm/vi_resource_private.h>
|
|
+#include <ci/efrm/efrm_nic.h>
|
|
+#include "efrm_internal.h"
|
|
+
|
|
+
|
|
+static inline int
|
|
+efrm_eventq_bytes(struct vi_resource *virs)
|
|
+{
|
|
+ return efrm_vi_rm_evq_bytes(virs);
|
|
+}
|
|
+
|
|
+
|
|
+static inline efhw_event_t *
|
|
+efrm_eventq_base(struct vi_resource *virs)
|
|
+{
|
|
+ struct eventq_resource_hardware *hw;
|
|
+ hw = &(virs->nic_info.evq_pages);
|
|
+ return (efhw_event_t *) (efhw_iopages_ptr(&(hw->iobuff)) +
|
|
+ hw->iobuff_off);
|
|
+}
|
|
+
|
|
+
|
|
+void
|
|
+efrm_eventq_request_wakeup(struct vi_resource *virs, unsigned current_ptr)
|
|
+{
|
|
+ struct efhw_nic *nic = virs->rs.rs_client->nic;
|
|
+ int next_i;
|
|
+ next_i = ((current_ptr / sizeof(efhw_event_t)) &
|
|
+ (virs->evq_capacity - 1));
|
|
+
|
|
+ efhw_nic_wakeup_request(nic, efrm_eventq_dma_addr(virs), next_i,
|
|
+ EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle));
|
|
+}
|
|
+EXPORT_SYMBOL(efrm_eventq_request_wakeup);
|
|
+
|
|
+void efrm_eventq_reset(struct vi_resource *virs)
|
|
+{
|
|
+ struct efhw_nic *nic = virs->rs.rs_client->nic;
|
|
+ int instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle);
|
|
+
|
|
+ EFRM_ASSERT(virs->evq_capacity != 0);
|
|
+
|
|
+ /* FIXME: Protect against concurrent resets. */
|
|
+
|
|
+ efhw_nic_event_queue_disable(nic, instance, 0);
|
|
+
|
|
+ memset(efrm_eventq_base(virs), EFHW_CLEAR_EVENT_VALUE,
|
|
+ efrm_eventq_bytes(virs));
|
|
+ efhw_nic_event_queue_enable(nic, instance, virs->evq_capacity,
|
|
+ efrm_eventq_dma_addr(virs),
|
|
+ virs->nic_info.evq_pages.
|
|
+ buf_tbl_alloc.base,
|
|
+ instance < 64);
|
|
+ EFRM_TRACE("%s: " EFRM_RESOURCE_FMT, __func__,
|
|
+ EFRM_RESOURCE_PRI_ARG(virs->rs.rs_handle));
|
|
+}
|
|
+EXPORT_SYMBOL(efrm_eventq_reset);
|
|
+
|
|
+int
|
|
+efrm_eventq_register_callback(struct vi_resource *virs,
|
|
+ void (*handler) (void *, int,
|
|
+ struct efhw_nic *nic),
|
|
+ void *arg)
|
|
+{
|
|
+ struct efrm_nic_per_vi *cb_info;
|
|
+ int instance;
|
|
+ int bit;
|
|
+
|
|
+ EFRM_RESOURCE_ASSERT_VALID(&virs->rs, 0);
|
|
+ EFRM_ASSERT(virs->evq_capacity != 0);
|
|
+ EFRM_ASSERT(handler != NULL);
|
|
+
|
|
+ /* ?? TODO: Get rid of this test when client is compulsory. */
|
|
+ if (virs->rs.rs_client == NULL) {
|
|
+ EFRM_ERR("%s: no client", __func__);
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ virs->evq_callback_arg = arg;
|
|
+ virs->evq_callback_fn = handler;
|
|
+ instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle);
|
|
+ cb_info = &efrm_nic(virs->rs.rs_client->nic)->vis[instance];
|
|
+
|
|
+ /* The handler can be set only once. */
|
|
+ bit = test_and_set_bit(VI_RESOURCE_EVQ_STATE_CALLBACK_REGISTERED,
|
|
+ &cb_info->state);
|
|
+ if (bit)
|
|
+ return -EBUSY;
|
|
+ cb_info->vi = virs;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL(efrm_eventq_register_callback);
|
|
+
|
|
+void efrm_eventq_kill_callback(struct vi_resource *virs)
|
|
+{
|
|
+ struct efrm_nic_per_vi *cb_info;
|
|
+ int32_t evq_state;
|
|
+ int instance;
|
|
+ int bit;
|
|
+
|
|
+ EFRM_RESOURCE_ASSERT_VALID(&virs->rs, 0);
|
|
+ EFRM_ASSERT(virs->evq_capacity != 0);
|
|
+ EFRM_ASSERT(virs->rs.rs_client != NULL);
|
|
+
|
|
+ instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle);
|
|
+ cb_info = &efrm_nic(virs->rs.rs_client->nic)->vis[instance];
|
|
+ cb_info->vi = NULL;
|
|
+
|
|
+ /* Disable the timer. */
|
|
+ efhw_nic_event_queue_disable(virs->rs.rs_client->nic,
|
|
+ instance, /*timer_only */ 1);
|
|
+
|
|
+ /* Disable the callback. */
|
|
+ bit = test_and_clear_bit(VI_RESOURCE_EVQ_STATE_CALLBACK_REGISTERED,
|
|
+ &cb_info->state);
|
|
+ EFRM_ASSERT(bit); /* do not call me twice! */
|
|
+
|
|
+ /* Spin until the callback is complete. */
|
|
+ do {
|
|
+ rmb();
|
|
+
|
|
+ udelay(1);
|
|
+ evq_state = cb_info->state;
|
|
+ } while ((evq_state & VI_RESOURCE_EVQ_STATE(BUSY)));
|
|
+
|
|
+ virs->evq_callback_fn = NULL;
|
|
+}
|
|
+EXPORT_SYMBOL(efrm_eventq_kill_callback);
|
|
+
|
|
+static void
|
|
+efrm_eventq_do_callback(struct efhw_nic *nic, unsigned instance,
|
|
+ bool is_timeout)
|
|
+{
|
|
+ struct efrm_nic *rnic = efrm_nic(nic);
|
|
+ void (*handler) (void *, int is_timeout, struct efhw_nic *nic);
|
|
+ void *arg;
|
|
+ struct efrm_nic_per_vi *cb_info;
|
|
+ int32_t evq_state;
|
|
+ int32_t new_evq_state;
|
|
+ struct vi_resource *virs;
|
|
+ int bit;
|
|
+
|
|
+ EFRM_ASSERT(efrm_vi_manager);
|
|
+
|
|
+ cb_info = &rnic->vis[instance];
|
|
+
|
|
+ /* Set the BUSY bit and clear WAKEUP_PENDING. Do this
|
|
+ * before waking up the sleeper to avoid races. */
|
|
+ while (1) {
|
|
+ evq_state = cb_info->state;
|
|
+ new_evq_state = evq_state;
|
|
+
|
|
+ if ((evq_state & VI_RESOURCE_EVQ_STATE(BUSY)) != 0) {
|
|
+ EFRM_ERR("%s:%d: evq_state[%d] corrupted!",
|
|
+ __func__, __LINE__, instance);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (!is_timeout)
|
|
+ new_evq_state &= ~VI_RESOURCE_EVQ_STATE(WAKEUP_PENDING);
|
|
+
|
|
+ if (evq_state & VI_RESOURCE_EVQ_STATE(CALLBACK_REGISTERED)) {
|
|
+ new_evq_state |= VI_RESOURCE_EVQ_STATE(BUSY);
|
|
+ virs = cb_info->vi;
|
|
+ if (cmpxchg(&cb_info->state, evq_state,
|
|
+ new_evq_state) == evq_state)
|
|
+ break;
|
|
+ } else {
|
|
+ /* Just update the state if necessary. */
|
|
+ if (new_evq_state == evq_state ||
|
|
+ cmpxchg(&cb_info->state, evq_state,
|
|
+ new_evq_state) == evq_state)
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (virs) {
|
|
+ handler = virs->evq_callback_fn;
|
|
+ arg = virs->evq_callback_arg;
|
|
+ EFRM_ASSERT(handler != NULL);
|
|
+ handler(arg, is_timeout, nic);
|
|
+ }
|
|
+
|
|
+ /* Clear the BUSY bit. */
|
|
+ bit =
|
|
+ test_and_clear_bit(VI_RESOURCE_EVQ_STATE_BUSY,
|
|
+ &cb_info->state);
|
|
+ if (!bit) {
|
|
+ EFRM_ERR("%s:%d: evq_state corrupted!",
|
|
+ __func__, __LINE__);
|
|
+ }
|
|
+}
|
|
+
|
|
+void efrm_handle_wakeup_event(struct efhw_nic *nic, unsigned instance)
|
|
+{
|
|
+ efrm_eventq_do_callback(nic, instance, false);
|
|
+}
|
|
+
|
|
+void efrm_handle_timeout_event(struct efhw_nic *nic, unsigned instance)
|
|
+{
|
|
+ efrm_eventq_do_callback(nic, instance, true);
|
|
+}
|
|
+
|
|
+void efrm_handle_sram_event(struct efhw_nic *nic)
|
|
+{
|
|
+ if (nic->buf_commit_outstanding > 0)
|
|
+ nic->buf_commit_outstanding--;
|
|
+}
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/vi_resource_flush.c 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,483 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file contains DMA queue flushing of VI resources.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#include <ci/efrm/nic_table.h>
|
|
+#include <ci/driver/efab/hardware.h>
|
|
+#include <ci/efhw/falcon.h>
|
|
+#include <ci/efrm/private.h>
|
|
+#include <ci/efrm/sysdep.h>
|
|
+#include <ci/efrm/buffer_table.h>
|
|
+#include <ci/efrm/vi_resource_private.h>
|
|
+#include "efrm_internal.h"
|
|
+
|
|
+
|
|
+/* can fail as workitem can already be scheuled -- ignore failure */
|
|
+#define EFRM_VI_RM_DELAYED_FREE(manager) \
|
|
+ queue_work(manager->workqueue, &manager->work_item)
|
|
+
|
|
+static const int flush_fifo_hwm = 8 /* TODO should be a HW specific const */ ;
|
|
+
|
|
+static void
|
|
+efrm_vi_resource_rx_flush_done(struct vi_resource *virs, bool *completed)
|
|
+{
|
|
+ /* We should only get a flush event if there is a flush
|
|
+ * outstanding. */
|
|
+ EFRM_ASSERT(virs->rx_flush_outstanding);
|
|
+
|
|
+ virs->rx_flush_outstanding = 0;
|
|
+ virs->rx_flushing = 0;
|
|
+
|
|
+ list_del(&virs->rx_flush_link);
|
|
+ efrm_vi_manager->rx_flush_outstanding_count--;
|
|
+
|
|
+ if (virs->tx_flushing == 0) {
|
|
+ list_add_tail(&virs->rx_flush_link,
|
|
+ &efrm_vi_manager->close_pending);
|
|
+ *completed = 1;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+efrm_vi_resource_tx_flush_done(struct vi_resource *virs, bool *completed)
|
|
+{
|
|
+ /* We should only get a flush event if there is a flush
|
|
+ * outstanding. */
|
|
+ EFRM_ASSERT(virs->tx_flushing);
|
|
+
|
|
+ virs->tx_flushing = 0;
|
|
+
|
|
+ list_del(&virs->tx_flush_link);
|
|
+
|
|
+ if (virs->rx_flushing == 0) {
|
|
+ list_add_tail(&virs->rx_flush_link,
|
|
+ &efrm_vi_manager->close_pending);
|
|
+ *completed = 1;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+efrm_vi_resource_issue_rx_flush(struct vi_resource *virs, bool *completed)
|
|
+{
|
|
+ struct efhw_nic *nic = virs->rs.rs_client->nic;
|
|
+ int instance;
|
|
+ int rc;
|
|
+
|
|
+ instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle);
|
|
+
|
|
+ list_add_tail(&virs->rx_flush_link,
|
|
+ &efrm_vi_manager->rx_flush_outstanding_list);
|
|
+ virs->rx_flush_outstanding = virs->rx_flushing;
|
|
+ efrm_vi_manager->rx_flush_outstanding_count++;
|
|
+
|
|
+ EFRM_TRACE("%s: rx queue %d flush requested for nic %d",
|
|
+ __func__, instance, nic->index);
|
|
+ rc = efhw_nic_flush_rx_dma_channel(nic, instance);
|
|
+ if (rc == -EAGAIN)
|
|
+ efrm_vi_resource_rx_flush_done(virs, completed);
|
|
+}
|
|
+
|
|
+static void
|
|
+efrm_vi_resource_issue_tx_flush(struct vi_resource *virs, bool *completed)
|
|
+{
|
|
+ struct efhw_nic *nic = virs->rs.rs_client->nic;
|
|
+ int instance;
|
|
+ int rc;
|
|
+
|
|
+ instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle);
|
|
+
|
|
+ list_add_tail(&virs->tx_flush_link,
|
|
+ &efrm_vi_manager->tx_flush_outstanding_list);
|
|
+
|
|
+ EFRM_TRACE("%s: tx queue %d flush requested for nic %d",
|
|
+ __func__, instance, nic->index);
|
|
+ rc = efhw_nic_flush_tx_dma_channel(nic, instance);
|
|
+ if (rc == -EAGAIN)
|
|
+ efrm_vi_resource_tx_flush_done(virs, completed);
|
|
+}
|
|
+
|
|
+static void efrm_vi_resource_process_waiting_flushes(bool *completed)
|
|
+{
|
|
+ struct vi_resource *virs;
|
|
+
|
|
+ while (efrm_vi_manager->rx_flush_outstanding_count < flush_fifo_hwm &&
|
|
+ !list_empty(&efrm_vi_manager->rx_flush_waiting_list)) {
|
|
+ virs =
|
|
+ list_entry(list_pop
|
|
+ (&efrm_vi_manager->rx_flush_waiting_list),
|
|
+ struct vi_resource, rx_flush_link);
|
|
+ efrm_vi_resource_issue_rx_flush(virs, completed);
|
|
+ }
|
|
+}
|
|
+
|
|
+#if BUG7916_WORKAROUND || BUG5302_WORKAROUND
|
|
+static void
|
|
+efrm_vi_resource_flush_retry_vi(struct vi_resource *virs,
|
|
+ int64_t time_now, bool *completed)
|
|
+{
|
|
+ struct efhw_nic *nic;
|
|
+ int instance;
|
|
+
|
|
+ instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle);
|
|
+
|
|
+ virs->flush_count++;
|
|
+ virs->flush_time = time_now;
|
|
+ nic = virs->rs.rs_client->nic;
|
|
+
|
|
+#if BUG7916_WORKAROUND
|
|
+ if (virs->rx_flush_outstanding) {
|
|
+ EFRM_TRACE("%s: Retrying RX flush on instance %d",
|
|
+ __func__, instance);
|
|
+
|
|
+ list_del(&virs->rx_flush_link);
|
|
+ efrm_vi_manager->rx_flush_outstanding_count--;
|
|
+ efrm_vi_resource_issue_rx_flush(virs, completed);
|
|
+ efrm_vi_resource_process_waiting_flushes(completed);
|
|
+ }
|
|
+#endif
|
|
+
|
|
+#if BUG5302_WORKAROUND
|
|
+ if (virs->tx_flushing) {
|
|
+ if (virs->flush_count > 5) {
|
|
+ EFRM_TRACE("%s: VI resource stuck flush pending "
|
|
+ "(instance=%d, count=%d)",
|
|
+ __func__, instance, virs->flush_count);
|
|
+ falcon_clobber_tx_dma_ptrs(nic, instance);
|
|
+ } else {
|
|
+ EFRM_TRACE("%s: Retrying TX flush on instance %d",
|
|
+ __func__, instance);
|
|
+ }
|
|
+
|
|
+ list_del(&virs->tx_flush_link);
|
|
+ efrm_vi_resource_issue_tx_flush(virs, completed);
|
|
+ }
|
|
+#endif
|
|
+}
|
|
+#endif
|
|
+
|
|
+int efrm_vi_resource_flush_retry(struct vi_resource *virs)
|
|
+{
|
|
+#if BUG7916_WORKAROUND || BUG5302_WORKAROUND
|
|
+ irq_flags_t lock_flags;
|
|
+ bool completed = false;
|
|
+
|
|
+ if (virs->rx_flushing == 0 && virs->tx_flushing == 0)
|
|
+ return -EALREADY;
|
|
+
|
|
+ spin_lock_irqsave(&efrm_vi_manager->rm.rm_lock, lock_flags);
|
|
+ efrm_vi_resource_flush_retry_vi(virs, get_jiffies_64(), &completed);
|
|
+ spin_unlock_irqrestore(&efrm_vi_manager->rm.rm_lock, lock_flags);
|
|
+
|
|
+ if (completed)
|
|
+ EFRM_VI_RM_DELAYED_FREE(efrm_vi_manager);
|
|
+#endif
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL(efrm_vi_resource_flush_retry);
|
|
+
|
|
+#if BUG7916_WORKAROUND || BUG5302_WORKAROUND
|
|
+/* resource manager lock should be taken before this call */
|
|
+static void efrm_vi_handle_flush_loss(bool *completed)
|
|
+{
|
|
+ struct list_head *pos, *temp;
|
|
+ struct vi_resource *virs;
|
|
+ int64_t time_now, time_pending;
|
|
+
|
|
+ /* It's possible we miss flushes - the list is sorted in order we
|
|
+ * generate flushes, see if any are very old. It's also possible
|
|
+ * that we decide an endpoint is flushed even though we've not
|
|
+ * received all the flush events. We *should * mark as
|
|
+ * completed, reclaim and loop again. ??
|
|
+ * THIS NEEDS BACKPORTING FROM THE FALCON branch
|
|
+ */
|
|
+ time_now = get_jiffies_64();
|
|
+
|
|
+#if BUG7916_WORKAROUND
|
|
+ list_for_each_safe(pos, temp,
|
|
+ &efrm_vi_manager->rx_flush_outstanding_list) {
|
|
+ virs = container_of(pos, struct vi_resource, rx_flush_link);
|
|
+
|
|
+ time_pending = time_now - virs->flush_time;
|
|
+
|
|
+ /* List entries are held in reverse chronological order. Only
|
|
+ * process the old ones. */
|
|
+ if (time_pending <= 0x100000000LL)
|
|
+ break;
|
|
+
|
|
+ efrm_vi_resource_flush_retry_vi(virs, time_now, completed);
|
|
+ }
|
|
+#endif
|
|
+
|
|
+#if BUG5302_WORKAROUND
|
|
+ list_for_each_safe(pos, temp,
|
|
+ &efrm_vi_manager->tx_flush_outstanding_list) {
|
|
+ virs = container_of(pos, struct vi_resource, tx_flush_link);
|
|
+
|
|
+ time_pending = time_now - virs->flush_time;
|
|
+
|
|
+ /* List entries are held in reverse chronological order.
|
|
+ * Only process the old ones. */
|
|
+ if (time_pending <= 0x100000000LL)
|
|
+ break;
|
|
+
|
|
+ efrm_vi_resource_flush_retry_vi(virs, time_now, completed);
|
|
+ }
|
|
+#endif
|
|
+}
|
|
+#endif
|
|
+
|
|
+void
|
|
+efrm_vi_register_flush_callback(struct vi_resource *virs,
|
|
+ void (*handler)(void *), void *arg)
|
|
+{
|
|
+ if (handler == NULL) {
|
|
+ virs->flush_callback_fn = handler;
|
|
+ wmb();
|
|
+ virs->flush_callback_arg = arg;
|
|
+ } else {
|
|
+ virs->flush_callback_arg = arg;
|
|
+ wmb();
|
|
+ virs->flush_callback_fn = handler;
|
|
+ }
|
|
+}
|
|
+EXPORT_SYMBOL(efrm_vi_register_flush_callback);
|
|
+
|
|
+int efrm_pt_flush(struct vi_resource *virs)
|
|
+{
|
|
+ int instance;
|
|
+ irq_flags_t lock_flags;
|
|
+ bool completed = false;
|
|
+
|
|
+ instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle);
|
|
+
|
|
+ EFRM_ASSERT(virs->rx_flushing == 0);
|
|
+ EFRM_ASSERT(virs->rx_flush_outstanding == 0);
|
|
+ EFRM_ASSERT(virs->tx_flushing == 0);
|
|
+
|
|
+ EFRM_TRACE("%s: " EFRM_RESOURCE_FMT " EVQ=%d TXQ=%d RXQ=%d",
|
|
+ __func__, EFRM_RESOURCE_PRI_ARG(virs->rs.rs_handle),
|
|
+ virs->evq_capacity,
|
|
+ virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX],
|
|
+ virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX]);
|
|
+
|
|
+ spin_lock_irqsave(&efrm_vi_manager->rm.rm_lock, lock_flags);
|
|
+
|
|
+ if (virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX] != 0)
|
|
+ virs->rx_flushing = 1;
|
|
+
|
|
+ if (virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX] != 0)
|
|
+ virs->tx_flushing = 1;
|
|
+
|
|
+ /* Clean up immediately if there are no flushes. */
|
|
+ if (virs->rx_flushing == 0 && virs->tx_flushing == 0) {
|
|
+ list_add_tail(&virs->rx_flush_link,
|
|
+ &efrm_vi_manager->close_pending);
|
|
+ completed = true;
|
|
+ }
|
|
+
|
|
+ /* Issue the RX flush if possible or queue it for later. */
|
|
+ if (virs->rx_flushing) {
|
|
+#if BUG7916_WORKAROUND || BUG5302_WORKAROUND
|
|
+ if (efrm_vi_manager->rx_flush_outstanding_count >=
|
|
+ flush_fifo_hwm)
|
|
+ efrm_vi_handle_flush_loss(&completed);
|
|
+#endif
|
|
+ if (efrm_vi_manager->rx_flush_outstanding_count >=
|
|
+ flush_fifo_hwm) {
|
|
+ list_add_tail(&virs->rx_flush_link,
|
|
+ &efrm_vi_manager->rx_flush_waiting_list);
|
|
+ } else {
|
|
+ efrm_vi_resource_issue_rx_flush(virs, &completed);
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Issue the TX flush. There's no limit to the number of
|
|
+ * outstanding TX flushes. */
|
|
+ if (virs->tx_flushing)
|
|
+ efrm_vi_resource_issue_tx_flush(virs, &completed);
|
|
+
|
|
+ virs->flush_time = get_jiffies_64();
|
|
+
|
|
+ spin_unlock_irqrestore(&efrm_vi_manager->rm.rm_lock, lock_flags);
|
|
+
|
|
+ if (completed)
|
|
+ EFRM_VI_RM_DELAYED_FREE(efrm_vi_manager);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL(efrm_pt_flush);
|
|
+
|
|
+static void
|
|
+efrm_handle_rx_dmaq_flushed(struct efhw_nic *flush_nic, int instance,
|
|
+ bool *completed)
|
|
+{
|
|
+ struct list_head *pos, *temp;
|
|
+ struct vi_resource *virs;
|
|
+
|
|
+ list_for_each_safe(pos, temp,
|
|
+ &efrm_vi_manager->rx_flush_outstanding_list) {
|
|
+ virs = container_of(pos, struct vi_resource, rx_flush_link);
|
|
+
|
|
+ if (instance == EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle)) {
|
|
+ efrm_vi_resource_rx_flush_done(virs, completed);
|
|
+ efrm_vi_resource_process_waiting_flushes(completed);
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ EFRM_TRACE("%s: Unhandled rx flush event, nic %d, instance %d",
|
|
+ __func__, flush_nic->index, instance);
|
|
+}
|
|
+
|
|
+static void
|
|
+efrm_handle_tx_dmaq_flushed(struct efhw_nic *flush_nic, int instance,
|
|
+ bool *completed)
|
|
+{
|
|
+ struct list_head *pos, *temp;
|
|
+ struct vi_resource *virs;
|
|
+
|
|
+ list_for_each_safe(pos, temp,
|
|
+ &efrm_vi_manager->tx_flush_outstanding_list) {
|
|
+ virs = container_of(pos, struct vi_resource, tx_flush_link);
|
|
+
|
|
+ if (instance == EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle)) {
|
|
+ efrm_vi_resource_tx_flush_done(virs, completed);
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ EFRM_TRACE("%s: Unhandled tx flush event, nic %d, instance %d",
|
|
+ __func__, flush_nic->index, instance);
|
|
+}
|
|
+
|
|
+void
|
|
+efrm_handle_dmaq_flushed(struct efhw_nic *flush_nic, unsigned instance,
|
|
+ int rx_flush)
|
|
+{
|
|
+ irq_flags_t lock_flags;
|
|
+ bool completed = false;
|
|
+
|
|
+ EFRM_TRACE("%s: nic_i=%d instance=%d rx_flush=%d", __func__,
|
|
+ flush_nic->index, instance, rx_flush);
|
|
+
|
|
+ spin_lock_irqsave(&efrm_vi_manager->rm.rm_lock, lock_flags);
|
|
+
|
|
+ if (rx_flush)
|
|
+ efrm_handle_rx_dmaq_flushed(flush_nic, instance, &completed);
|
|
+ else
|
|
+ efrm_handle_tx_dmaq_flushed(flush_nic, instance, &completed);
|
|
+
|
|
+#if BUG7916_WORKAROUND || BUG5302_WORKAROUND
|
|
+ efrm_vi_handle_flush_loss(&completed);
|
|
+#endif
|
|
+
|
|
+ spin_unlock_irqrestore(&efrm_vi_manager->rm.rm_lock, lock_flags);
|
|
+
|
|
+ if (completed)
|
|
+ EFRM_VI_RM_DELAYED_FREE(efrm_vi_manager);
|
|
+}
|
|
+
|
|
+static void
|
|
+efrm_vi_rm_reinit_dmaqs(struct vi_resource *virs)
|
|
+{
|
|
+ struct efhw_nic *nic = virs->rs.rs_client->nic;
|
|
+
|
|
+ if (virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX] != 0)
|
|
+ efrm_vi_rm_init_dmaq(virs, EFRM_VI_RM_DMA_QUEUE_TX, nic);
|
|
+ if (virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX])
|
|
+ efrm_vi_rm_init_dmaq(virs, EFRM_VI_RM_DMA_QUEUE_RX, nic);
|
|
+}
|
|
+
|
|
+/* free any PT endpoints whose flush has now complete */
|
|
+void efrm_vi_rm_delayed_free(struct work_struct *data)
|
|
+{
|
|
+ irq_flags_t lock_flags;
|
|
+ struct list_head close_pending;
|
|
+ struct vi_resource *virs;
|
|
+
|
|
+ EFRM_RESOURCE_MANAGER_ASSERT_VALID(&efrm_vi_manager->rm);
|
|
+
|
|
+ spin_lock_irqsave(&efrm_vi_manager->rm.rm_lock, lock_flags);
|
|
+ list_replace_init(&efrm_vi_manager->close_pending, &close_pending);
|
|
+ spin_unlock_irqrestore(&efrm_vi_manager->rm.rm_lock, lock_flags);
|
|
+
|
|
+ EFRM_TRACE("%s: %p", __func__, efrm_vi_manager);
|
|
+ while (!list_empty(&close_pending)) {
|
|
+ virs =
|
|
+ list_entry(list_pop(&close_pending), struct vi_resource,
|
|
+ rx_flush_link);
|
|
+ EFRM_TRACE("%s: flushed VI instance=%d", __func__,
|
|
+ EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle));
|
|
+
|
|
+ if (virs->flush_callback_fn != NULL) {
|
|
+ efrm_vi_rm_reinit_dmaqs(virs);
|
|
+ virs->flush_callback_fn(virs->flush_callback_arg);
|
|
+ } else
|
|
+ efrm_vi_rm_free_flushed_resource(virs);
|
|
+ }
|
|
+}
|
|
+
|
|
+void efrm_vi_rm_salvage_flushed_vis(void)
|
|
+{
|
|
+#if BUG7916_WORKAROUND || BUG5302_WORKAROUND
|
|
+ irq_flags_t lock_flags;
|
|
+ bool completed;
|
|
+
|
|
+ spin_lock_irqsave(&efrm_vi_manager->rm.rm_lock, lock_flags);
|
|
+ efrm_vi_handle_flush_loss(&completed);
|
|
+ spin_unlock_irqrestore(&efrm_vi_manager->rm.rm_lock, lock_flags);
|
|
+#endif
|
|
+
|
|
+ efrm_vi_rm_delayed_free(&efrm_vi_manager->work_item);
|
|
+}
|
|
+
|
|
+void efrm_vi_resource_free(struct vi_resource *virs)
|
|
+{
|
|
+ efrm_vi_register_flush_callback(virs, NULL, NULL);
|
|
+ efrm_pt_flush(virs);
|
|
+}
|
|
+EXPORT_SYMBOL(efrm_vi_resource_free);
|
|
+
|
|
+
|
|
+void efrm_vi_resource_release(struct vi_resource *virs)
|
|
+{
|
|
+ if (__efrm_resource_release(&virs->rs))
|
|
+ efrm_vi_resource_free(virs);
|
|
+}
|
|
+EXPORT_SYMBOL(efrm_vi_resource_release);
|
|
+
|
|
+/*
|
|
+ * vi: sw=8:ai:aw
|
|
+ */
|
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
+++ head-2009-04-21/drivers/net/sfc/sfc_resource/vi_resource_manager.c 2008-07-17 16:18:07.000000000 +0200
|
|
@@ -0,0 +1,231 @@
|
|
+/****************************************************************************
|
|
+ * Driver for Solarflare network controllers -
|
|
+ * resource management for Xen backend, OpenOnload, etc
|
|
+ * (including support for SFE4001 10GBT NIC)
|
|
+ *
|
|
+ * This file contains the VI resource manager.
|
|
+ *
|
|
+ * Copyright 2005-2007: Solarflare Communications Inc,
|
|
+ * 9501 Jeronimo Road, Suite 250,
|
|
+ * Irvine, CA 92618, USA
|
|
+ *
|
|
+ * Developed and maintained by Solarflare Communications:
|
|
+ * <linux-xen-drivers@solarflare.com>
|
|
+ * <onload-dev@solarflare.com>
|
|
+ *
|
|
+ * Certain parts of the driver were implemented by
|
|
+ * Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
|
|
+ * OKTET Labs Ltd, Russia,
|
|
+ * http://oktetlabs.ru, <info@oktetlabs.ru>
|
|
+ * by request of Solarflare Communications
|
|
+ *
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify it
|
|
+ * under the terms of the GNU General Public License version 2 as published
|
|
+ * by the Free Software Foundation, incorporated herein by reference.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+ ****************************************************************************
|
|
+ */
|
|
+
|
|
+#include <ci/efrm/nic_table.h>
|
|
+#include <ci/driver/efab/hardware.h>
|
|
+#include <ci/efhw/falcon.h>
|
|
+#include <ci/efrm/private.h>
|
|
+#include <ci/efrm/vi_resource_private.h>
|
|
+#include "efrm_internal.h"
|
|
+
|
|
+
|
|
+int efrm_pt_pace(struct vi_resource *virs, unsigned int val)
|
|
+{
|
|
+ struct efhw_nic *nic = virs->rs.rs_client->nic;
|
|
+ int instance;
|
|
+
|
|
+ EFRM_RESOURCE_ASSERT_VALID(&virs->rs, 0);
|
|
+ instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle);
|
|
+ falcon_nic_pace(nic, instance, val);
|
|
+ EFRM_TRACE("%s[%d]=%d DONE", __func__, instance, val);
|
|
+ return 0;
|
|
+}
|
|
+EXPORT_SYMBOL(efrm_pt_pace);
|
|
+
|
|
+/*** Resource manager creation/destruction *******************************/
|
|
+
|
|
+static void efrm_vi_rm_dtor(struct efrm_resource_manager *rm);
|
|
+
|
|
+static int
|
|
+efrm_create_or_destroy_vi_resource_manager(
|
|
+ struct efrm_resource_manager **rm_in_out,
|
|
+ const struct vi_resource_dimensions *dims,
|
|
+ bool destroy)
|
|
+{
|
|
+ struct vi_resource *virs;
|
|
+ struct list_head *pos, *temp;
|
|
+ struct list_head flush_pending;
|
|
+ irq_flags_t lock_flags;
|
|
+ int rc;
|
|
+ unsigned dmaq_min, dmaq_lim;
|
|
+
|
|
+ EFRM_ASSERT(rm_in_out);
|
|
+
|
|
+ if (destroy)
|
|
+ goto destroy;
|
|
+
|
|
+ EFRM_ASSERT(dims);
|
|
+ EFRM_NOTICE("vi_resource_manager: evq_int=%u-%u evq_timer=%u-%u",
|
|
+ dims->evq_int_min, dims->evq_int_lim,
|
|
+ dims->evq_timer_min, dims->evq_timer_lim);
|
|
+ EFRM_NOTICE("vi_resource_manager: rxq=%u-%u txq=%u-%u",
|
|
+ dims->rxq_min, dims->rxq_lim,
|
|
+ dims->txq_min, dims->txq_lim);
|
|
+
|
|
+ efrm_vi_manager = kmalloc(sizeof(*efrm_vi_manager), GFP_KERNEL);
|
|
+ if (efrm_vi_manager == NULL) {
|
|
+ rc = -ENOMEM;
|
|
+ goto fail_alloc;
|
|
+ }
|
|
+
|
|
+ memset(efrm_vi_manager, 0, sizeof(*efrm_vi_manager));
|
|
+
|
|
+ efrm_vi_manager->iscsi_dmaq_instance_is_free = true;
|
|
+
|
|
+ dmaq_min = max(dims->rxq_min, dims->txq_min);
|
|
+ dmaq_lim = min(dims->rxq_lim, dims->txq_lim);
|
|
+
|
|
+ efrm_vi_manager->with_timer_base =
|
|
+ max(dmaq_min, dims->evq_timer_min);
|
|
+ efrm_vi_manager->with_timer_limit =
|
|
+ min(dmaq_lim, dims->evq_timer_lim);
|
|
+ rc = efrm_kfifo_id_ctor(&efrm_vi_manager->instances_with_timer,
|
|
+ efrm_vi_manager->with_timer_base,
|
|
+ efrm_vi_manager->with_timer_limit,
|
|
+ &efrm_vi_manager->rm.rm_lock);
|
|
+ if (rc < 0)
|
|
+ goto fail_with_timer_id_pool;
|
|
+
|
|
+ efrm_vi_manager->with_interrupt_base =
|
|
+ max(dmaq_min, dims->evq_int_min);
|
|
+ efrm_vi_manager->with_interrupt_limit =
|
|
+ min(dmaq_lim, dims->evq_int_lim);
|
|
+ efrm_vi_manager->with_interrupt_limit =
|
|
+ max(efrm_vi_manager->with_interrupt_limit,
|
|
+ efrm_vi_manager->with_interrupt_base);
|
|
+ rc = efrm_kfifo_id_ctor(&efrm_vi_manager->instances_with_interrupt,
|
|
+ efrm_vi_manager->with_interrupt_base,
|
|
+ efrm_vi_manager->with_interrupt_limit,
|
|
+ &efrm_vi_manager->rm.rm_lock);
|
|
+ if (rc < 0)
|
|
+ goto fail_with_int_id_pool;
|
|
+
|
|
+ INIT_LIST_HEAD(&efrm_vi_manager->rx_flush_waiting_list);
|
|
+ INIT_LIST_HEAD(&efrm_vi_manager->rx_flush_outstanding_list);
|
|
+ INIT_LIST_HEAD(&efrm_vi_manager->tx_flush_outstanding_list);
|
|
+ efrm_vi_manager->rx_flush_outstanding_count = 0;
|
|
+
|
|
+ INIT_LIST_HEAD(&efrm_vi_manager->close_pending);
|
|
+ efrm_vi_manager->workqueue = create_workqueue("sfc_vi");
|
|
+ if (efrm_vi_manager->workqueue == NULL)
|
|
+ goto fail_create_workqueue;
|
|
+ INIT_WORK(&efrm_vi_manager->work_item, efrm_vi_rm_delayed_free);
|
|
+
|
|
+ /* NB. This must be the last step to avoid things getting tangled.
|
|
+ * efrm_resource_manager_dtor calls the vi_rm_dtor which ends up in
|
|
+ * this function. */
|
|
+ rc = efrm_resource_manager_ctor(&efrm_vi_manager->rm, efrm_vi_rm_dtor,
|
|
+ "VI", EFRM_RESOURCE_VI);
|
|
+ if (rc < 0)
|
|
+ goto fail_rm_ctor;
|
|
+
|
|
+ *rm_in_out = &efrm_vi_manager->rm;
|
|
+ return 0;
|
|
+
|
|
+destroy:
|
|
+ rc = 0;
|
|
+ EFRM_RESOURCE_MANAGER_ASSERT_VALID(*rm_in_out);
|
|
+
|
|
+ /* Abort outstanding flushes. Note, a VI resource can be on more
|
|
+ * than one of these lists. We handle this by starting with the TX
|
|
+ * list and then append VIs to this list if they aren't on the TX
|
|
+ * list already. A VI is on the TX flush list if tx_flushing
|
|
+ * is not empty. */
|
|
+ spin_lock_irqsave(&efrm_vi_manager->rm.rm_lock, lock_flags);
|
|
+
|
|
+ list_replace_init(&efrm_vi_manager->tx_flush_outstanding_list,
|
|
+ &flush_pending);
|
|
+
|
|
+ list_for_each_safe(pos, temp,
|
|
+ &efrm_vi_manager->rx_flush_waiting_list) {
|
|
+ virs = container_of(pos, struct vi_resource, rx_flush_link);
|
|
+
|
|
+ list_del(&virs->rx_flush_link);
|
|
+ if (virs->tx_flushing == 0)
|
|
+ list_add_tail(&virs->tx_flush_link, &flush_pending);
|
|
+ }
|
|
+
|
|
+ list_for_each_safe(pos, temp,
|
|
+ &efrm_vi_manager->rx_flush_outstanding_list) {
|
|
+ virs = container_of(pos, struct vi_resource, rx_flush_link);
|
|
+
|
|
+ list_del(&virs->rx_flush_link);
|
|
+ if (virs->tx_flushing == 0)
|
|
+ list_add_tail(&virs->tx_flush_link, &flush_pending);
|
|
+ }
|
|
+
|
|
+ spin_unlock_irqrestore(&efrm_vi_manager->rm.rm_lock, lock_flags);
|
|
+
|
|
+ while (!list_empty(&flush_pending)) {
|
|
+ virs =
|
|
+ list_entry(list_pop(&flush_pending), struct vi_resource,
|
|
+ tx_flush_link);
|
|
+ EFRM_TRACE("%s: found PT endpoint " EFRM_RESOURCE_FMT
|
|
+ " with flush pending [Tx=0x%x, Rx=0x%x, RxO=0x%x]",
|
|
+ __func__,
|
|
+ EFRM_RESOURCE_PRI_ARG(virs->rs.rs_handle),
|
|
+ virs->tx_flushing,
|
|
+ virs->rx_flushing,
|
|
+ virs->rx_flush_outstanding);
|
|
+ efrm_vi_rm_free_flushed_resource(virs);
|
|
+ }
|
|
+
|
|
+fail_rm_ctor:
|
|
+
|
|
+ /* Complete outstanding closes. */
|
|
+ destroy_workqueue(efrm_vi_manager->workqueue);
|
|
+fail_create_workqueue:
|
|
+ EFRM_ASSERT(list_empty(&efrm_vi_manager->close_pending));
|
|
+ kfifo_vfree(efrm_vi_manager->instances_with_interrupt);
|
|
+fail_with_int_id_pool:
|
|
+
|
|
+ kfifo_vfree(efrm_vi_manager->instances_with_timer);
|
|
+fail_with_timer_id_pool:
|
|
+
|
|
+ if (destroy)
|
|
+ return 0;
|
|
+
|
|
+ EFRM_DO_DEBUG(memset(efrm_vi_manager, 0, sizeof(*efrm_vi_manager)));
|
|
+ kfree(efrm_vi_manager);
|
|
+fail_alloc:
|
|
+
|
|
+ *rm_in_out = NULL;
|
|
+ EFRM_ERR("%s: failed rc=%d", __func__, rc);
|
|
+ return rc;
|
|
+}
|
|
+
|
|
+int
|
|
+efrm_create_vi_resource_manager(struct efrm_resource_manager **rm_out,
|
|
+ const struct vi_resource_dimensions *dims)
|
|
+{
|
|
+ return efrm_create_or_destroy_vi_resource_manager(rm_out, dims, false);
|
|
+}
|
|
+
|
|
+static void efrm_vi_rm_dtor(struct efrm_resource_manager *rm)
|
|
+{
|
|
+ efrm_create_or_destroy_vi_resource_manager(&rm, NULL, true);
|
|
+}
|