Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 14 Mar 2011 09:50:14 +0000 (UTC)
From:      Navdeep Parhar <np@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-8@freebsd.org
Subject:   svn commit: r219633 - in stable/8: share/man/man4 sys/conf sys/dev/cxgbe sys/dev/cxgbe/common sys/modules sys/modules/cxgbe usr.sbin/sysinstall
Message-ID:  <201103140950.p2E9oEm4084178@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: np
Date: Mon Mar 14 09:50:14 2011
New Revision: 219633
URL: http://svn.freebsd.org/changeset/base/219633

Log:
  MFC cxgbe(4) and fixes.
  
  r218792:
  cxgbe(4) - NIC driver for Chelsio T4 (Terminator 4) based 10Gb/1Gb adapters.
  
  r219285:
  Fix incorrect assertion.
  
  r219286:
  Resume tx immediately in response to an SGE egress update from the hardware.
  
  r219287:
  Upgrade the firmware on the card automatically if a better version is
  available.  Downgrade only for a major version mismatch.
  
  r219288:
  A txpkts work request should have a valid FID.
  
  r219289:
  Store the ifnet rather than the port_info in each txq and rxq struct.
  
  r219290:
  Tweaks for rx:
  - everything related to LRO should be in #ifdef INET blocks
  - reorder sge_iq's fields so that the most frequently used are all together
  - pull all rx code into t4_intr_data directly
  - let go of the ingress queue lock when passing up data
  - refill the freelist only if it is short of at least 32 buffers
  
  r219292:
  Calculate how many descriptors can be reclaimed before calling
  reclaim_tx_descs
  
  r219293:
  There is no need to hold an ingress queue's lock while processing its
  descriptors
  
  r219299:
  Be sure to stay within the bounds of the mod_str array when displaying
  the transceiver type.
  
  r219392:
  cxgbe shouldn't directly know of the UMA zones where network buffers
  come from.
  
  r219436:
  Display holdoff timers and packet counts as a list of numbers.

Added:
  stable/8/share/man/man4/cxgbe.4
     - copied unchanged from r218792, head/share/man/man4/cxgbe.4
  stable/8/sys/dev/cxgbe/
     - copied from r218792, head/sys/dev/cxgbe/
  stable/8/sys/modules/cxgbe/
     - copied from r218792, head/sys/modules/cxgbe/
Modified:
  stable/8/share/man/man4/Makefile
  stable/8/share/man/man4/altq.4
  stable/8/share/man/man4/vlan.4
  stable/8/sys/conf/NOTES
  stable/8/sys/conf/files
  stable/8/sys/conf/kern.pre.mk
  stable/8/sys/dev/cxgbe/adapter.h
  stable/8/sys/dev/cxgbe/common/common.h
  stable/8/sys/dev/cxgbe/t4_main.c
  stable/8/sys/dev/cxgbe/t4_sge.c
  stable/8/sys/modules/Makefile
  stable/8/usr.sbin/sysinstall/devices.c
Directory Properties:
  stable/8/share/man/man4/   (props changed)
  stable/8/sys/   (props changed)
  stable/8/sys/amd64/include/xen/   (props changed)
  stable/8/sys/cddl/contrib/opensolaris/   (props changed)
  stable/8/sys/contrib/dev/acpica/   (props changed)
  stable/8/sys/contrib/pf/   (props changed)
  stable/8/usr.sbin/sysinstall/   (props changed)

Modified: stable/8/share/man/man4/Makefile
==============================================================================
--- stable/8/share/man/man4/Makefile	Mon Mar 14 05:29:45 2011	(r219632)
+++ stable/8/share/man/man4/Makefile	Mon Mar 14 09:50:14 2011	(r219633)
@@ -81,6 +81,7 @@ MAN=	aac.4 \
 	crypto.4 \
 	cue.4 \
 	cxgb.4 \
+	cxgbe.4 \
 	cy.4 \
 	da.4 \
 	dc.4 \

Modified: stable/8/share/man/man4/altq.4
==============================================================================
--- stable/8/share/man/man4/altq.4	Mon Mar 14 05:29:45 2011	(r219632)
+++ stable/8/share/man/man4/altq.4	Mon Mar 14 09:50:14 2011	(r219633)
@@ -127,6 +127,7 @@ They have been applied to the following 
 .Xr bfe 4 ,
 .Xr bge 4 ,
 .Xr cas 4 ,
+.Xr cxgbe 4 ,
 .Xr dc 4 ,
 .Xr de 4 ,
 .Xr ed 4 ,

Copied: stable/8/share/man/man4/cxgbe.4 (from r218792, head/share/man/man4/cxgbe.4)
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ stable/8/share/man/man4/cxgbe.4	Mon Mar 14 09:50:14 2011	(r219633, copy of r218792, head/share/man/man4/cxgbe.4)
@@ -0,0 +1,167 @@
+.\" Copyright (c) 2011, Chelsio Inc
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions are met:
+.\"
+.\" 1. Redistributions of source code must retain the above copyright notice,
+.\"    this list of conditions and the following disclaimer.
+.\"
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" 3. Neither the name of the Chelsio Inc nor the names of its
+.\"    contributors may be used to endorse or promote products derived from
+.\"    this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+.\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.\" * Other names and brands may be claimed as the property of others.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd February 14, 2011
+.Dt CXGBE 4
+.Os
+.Sh NAME
+.Nm cxgbe
+.Nd "Chelsio T4 10Gb and 1Gb Ethernet adapter driver"
+.Sh SYNOPSIS
+To compile this driver into the kernel,
+place the following lines in your
+kernel configuration file:
+.Bd -ragged -offset indent
+.Cd "device cxgbe"
+.Ed
+.Pp
+To load the driver as a
+module at boot time, place the following line in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+if_cxgbe_load="YES"
+.Ed
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for PCI Express Ethernet adapters based on
+the Chelsio Terminator 4 (T4) ASIC.
+The driver supprts Jumbo Frames, Transmit/Receive checksum offload,
+TCP segmentation offload (TSO), Large Receive Offload (LRO), VLAN
+tag insertion/extraction, VLAN checksum offload, VLAN TSO, and
+Receive Side Steering (RSS).
+
+For further hardware information and questions related to hardware
+requirements, see
+.Pa http://www.chelsio.com/ .
+.Pp
+For more information on configuring this device, see
+.Xr ifconfig 8 .
+.Sh HARDWARE
+The
+.Nm
+driver supports 10Gb and 1Gb Ethernet adapters based on the T4 ASIC:
+.Pp
+.Bl -bullet -compact
+.It
+Chelsio T420-CR
+.It
+Chelsio T422-CR
+.It
+Chelsio T440-CR
+.It
+Chelsio T420-BCH
+.It
+Chelsio T440-BCH
+.It
+Chelsio T440-CH
+.It
+Chelsio T420-SO
+.It
+Chelsio T420-CX
+.It
+Chelsio T420-BT
+.It
+Chelsio T404-BT
+.El
+.Sh LOADER TUNABLES
+Tunables can be set at the
+.Xr loader 8
+prompt before booting the kernel or stored in
+.Xr loader.conf 5 .
+.Bl -tag -width indent
+.It Va hw.cxgbe.max_ntxq_10G_port
+The maximum number of tx queues to use for a 10Gb port.
+The default value is 8.
+.It Va hw.cxgbe.max_nrxq_10G_port
+The maximum number of rx queues to use for a 10Gb port.
+The default value is 8.
+.It Va hw.cxgbe.max_ntxq_1G_port
+The maximum number of tx queues to use for a 1Gb port.
+The default value is 2.
+.It Va hw.cxgbe.max_nrxq_1G_port
+The maximum number of rx queues to use for a 1Gb port.
+The default value is 2.
+.It Va hw.cxgbe.holdoff_timer_idx_10G
+.It Va hw.cxgbe.holdoff_timer_idx_1G
+The timer index value to use to delay interrupts.
+The holdoff timer list has the values 1, 5, 10, 50, 100, and 200
+by default (all values are in microseconds) and the index selects a
+value from this list.
+The default value is 1 for both 10Gb and 1Gb ports, which means the
+timer value is 5us.
+.It Va hw.cxgbe.holdoff_pktc_idx_10G
+.It Va hw.cxgbe.holdoff_pktc_idx_1G
+The packet-count index value to use to delay interrupts.
+The packet-count list has the values 1, 8, 16, and 32 by default
+and the index selects a value from this list.
+The default value is 2 for both 10Gb and 1Gb ports, which means 16
+packets (or the holdoff timer going off) before an interrupt is
+generated.
+.It Va hw.cxgbe.qsize_txq
+The size, in number of entries, of the descriptor ring used for a tx
+queue.
+A buf_ring of the same size is also allocated for additional
+software queuing.  See
+.Xr ifnet 9 .
+The default value is 1024.
+.It Va hw.cxgbe.qsize_rxq
+The size, in number of entries, of the descriptor ring used for an
+rx queue.
+The default value is 1024.
+.Sh SUPPORT
+For general information and support,
+go to the Chelsio support website at:
+.Pa http://www.chelsio.com/ .
+.Pp
+If an issue is identified with this driver with a supported adapter,
+email all the specific information related to the issue to
+.Aq support@chelsio.com .
+.Sh SEE ALSO
+.Xr altq 4 ,
+.Xr arp 4 ,
+.Xr cxgb 4 ,
+.Xr netintro 4 ,
+.Xr ng_ether 4 ,
+.Xr ifconfig 8
+.Sh HISTORY
+The
+.Nm
+device driver first appeared in
+.Fx 9.0
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+driver was written by
+.An Navdeep Parhar Aq np@FreeBSD.org .

Modified: stable/8/share/man/man4/vlan.4
==============================================================================
--- stable/8/share/man/man4/vlan.4	Mon Mar 14 05:29:45 2011	(r219632)
+++ stable/8/share/man/man4/vlan.4	Mon Mar 14 09:50:14 2011	(r219633)
@@ -128,6 +128,7 @@ in the hardware is limited to the follow
 .Xr bce 4 ,
 .Xr bge 4 ,
 .Xr cxgb 4 ,
+.Xr cxgbe 4 ,
 .Xr em 4 ,
 .Xr igb 4 ,
 .Xr ixgb 4 ,

Modified: stable/8/sys/conf/NOTES
==============================================================================
--- stable/8/sys/conf/NOTES	Mon Mar 14 05:29:45 2011	(r219632)
+++ stable/8/sys/conf/NOTES	Mon Mar 14 09:50:14 2011	(r219633)
@@ -1877,6 +1877,8 @@ device		xmphy		# XaQti XMAC II
 # cas:	Sun Cassini/Cassini+ and National Semiconductor DP83065 Saturn
 # cm:	Arcnet SMC COM90c26 / SMC COM90c56
 #	(and SMC COM90c66 in '56 compatibility mode) adapters.
+# cxgbe: Support for PCI express 10Gb/1Gb adapters based on the Chelsio T4
+#       (Terminator 4) ASIC.
 # dc:   Support for PCI fast ethernet adapters based on the DEC/Intel 21143
 #       and various workalikes including:
 #       the ADMtek AL981 Comet and AN985 Centaur, the ASIX Electronics
@@ -2048,6 +2050,7 @@ device		xl		# 3Com 3c90x (``Boomerang'',
 
 # PCI Ethernet NICs.
 device		bwi		# Broadcom BCM430* BCM431*
+device		cxgbe		# Chelsio T4 10GbE PCIe adapter
 device		de		# DEC/Intel DC21x4x (``Tulip'')
 device		em		# Intel Pro/1000 Gigabit Ethernet
 device		igb		# Intel Pro/1000 PCIE Gigabit Ethernet

Modified: stable/8/sys/conf/files
==============================================================================
--- stable/8/sys/conf/files	Mon Mar 14 05:29:45 2011	(r219632)
+++ stable/8/sys/conf/files	Mon Mar 14 09:50:14 2011	(r219633)
@@ -822,6 +822,12 @@ dev/cxgb/sys/uipc_mvec.c	optional cxgb p
 	compile-with "${NORMAL_C} -I$S/dev/cxgb"
 dev/cxgb/cxgb_t3fw.c		optional cxgb cxgb_t3fw \
 	compile-with "${NORMAL_C} -I$S/dev/cxgb"
+dev/cxgbe/t4_main.c		optional cxgbe pci \
+	compile-with "${NORMAL_C} -I$S/dev/cxgbe"
+dev/cxgbe/t4_sge.c		optional cxgbe pci \
+	compile-with "${NORMAL_C} -I$S/dev/cxgbe"
+dev/cxgbe/common/t4_hw.c	optional cxgbe pci \
+	compile-with "${NORMAL_C} -I$S/dev/cxgbe"
 dev/cy/cy.c			optional cy
 dev/cy/cy_isa.c			optional cy isa
 dev/cy/cy_pci.c			optional cy pci

Modified: stable/8/sys/conf/kern.pre.mk
==============================================================================
--- stable/8/sys/conf/kern.pre.mk	Mon Mar 14 05:29:45 2011	(r219632)
+++ stable/8/sys/conf/kern.pre.mk	Mon Mar 14 09:50:14 2011	(r219633)
@@ -79,8 +79,8 @@ INCLUDES+= -I$S/dev/twa
 # ...  and XFS
 INCLUDES+= -I$S/gnu/fs/xfs/FreeBSD -I$S/gnu/fs/xfs/FreeBSD/support -I$S/gnu/fs/xfs
 
-# ... and the same for cxgb
-INCLUDES+= -I$S/dev/cxgb
+# ... and the same for cxgb and cxgbe
+INCLUDES+= -I$S/dev/cxgb -I$S/dev/cxgbe
 
 .endif
 

Modified: stable/8/sys/dev/cxgbe/adapter.h
==============================================================================
--- head/sys/dev/cxgbe/adapter.h	Fri Feb 18 08:00:26 2011	(r218792)
+++ stable/8/sys/dev/cxgbe/adapter.h	Mon Mar 14 09:50:14 2011	(r219633)
@@ -70,8 +70,8 @@ static __inline uint64_t
 t4_bus_space_read_8(bus_space_tag_t tag, bus_space_handle_t handle,
     bus_size_t offset)
 {
-	KASSERT(tag == X86_BUS_SPACE_IO,
-	    ("64-bit reads from I/O space not possible."));
+	KASSERT(tag == AMD64_BUS_SPACE_MEM,
+	    ("%s: can only handle mem space", __func__));
 
 	return (*(volatile uint64_t *)(handle + offset));
 }
@@ -80,8 +80,9 @@ static __inline void
 t4_bus_space_write_8(bus_space_tag_t tag, bus_space_handle_t bsh,
     bus_size_t offset, uint64_t value)
 {
-	KASSERT(tag == X86_BUS_SPACE_IO,
-	    ("64-bit writes to I/O space not possible."));
+	KASSERT(tag == AMD64_BUS_SPACE_MEM,
+	    ("%s: can only handle mem space", __func__));
+
 	*(volatile uint64_t *)(bsh + offset) = value;
 }
 #else
@@ -114,7 +115,11 @@ enum {
 
 	RX_FL_ESIZE = 64,	/* 8 64bit addresses */
 
-	FL_BUF_SIZES = 4,
+#if MJUMPAGESIZE != MCLBYTES
+	FL_BUF_SIZES = 4,	/* cluster, jumbop, jumbo9k, jumbo16k */
+#else
+	FL_BUF_SIZES = 3,	/* cluster, jumbo9k, jumbo16k */
+#endif
 
 	TX_EQ_QSIZE = 1024,
 	TX_EQ_ESIZE = 64,
@@ -176,6 +181,7 @@ struct port_info {
 	struct link_config link_cfg;
 	struct port_stats stats;
 
+	struct taskqueue *tq;
 	struct callout tick;
 	struct sysctl_ctx_list ctx;	/* lives from ifconfig up to down */
 	struct sysctl_oid *oid_rxq;
@@ -222,24 +228,25 @@ enum {
 struct sge_iq {
 	bus_dma_tag_t desc_tag;
 	bus_dmamap_t desc_map;
-	struct mtx iq_lock;
+	bus_addr_t ba;		/* bus address of descriptor ring */
 	char lockname[16];
-	unsigned int flags;
-	struct adapter *adapter;
+	uint32_t flags;
+	uint16_t abs_id;	/* absolute SGE id for the iq */
+	int8_t   intr_pktc_idx;	/* packet count threshold index */
+	int8_t   pad0;
+	iq_intr_handler_t *handler;
+	__be64  *desc;		/* KVA of descriptor ring */
 
-	__be64 *desc;		/* KVA of descriptor ring */
-	bus_addr_t ba;		/* bus address of descriptor ring */
+	struct mtx iq_lock;
+	struct adapter *adapter;
 	const __be64 *cdesc;	/* current descriptor */
 	uint8_t  gen;		/* generation bit */
 	uint8_t  intr_params;	/* interrupt holdoff parameters */
-	int8_t   intr_pktc_idx;	/* packet count threshold index */
 	uint8_t  intr_next;	/* holdoff for next interrupt */
 	uint8_t  esize;		/* size (bytes) of each entry in the queue */
 	uint16_t qsize;		/* size (# of entries) of the queue */
 	uint16_t cidx;		/* consumer index */
 	uint16_t cntxt_id;	/* SGE context id  for the iq */
-	uint16_t abs_id;	/* absolute SGE id for the iq */
-	iq_intr_handler_t *handler;
 };
 
 enum {
@@ -274,6 +281,7 @@ struct sge_eq {
 	uint16_t cidx;		/* consumer idx (desc idx) */
 	uint16_t pidx;		/* producer idx (desc idx) */
 	uint16_t pending;	/* # of descriptors used since last doorbell */
+	uint16_t iqid;		/* iq that gets egr_update for the eq */
 	uint32_t cntxt_id;	/* SGE context id for the eq */
 
 	/* DMA maps used for tx */
@@ -309,6 +317,9 @@ struct sge_fl {
 struct sge_txq {
 	struct sge_eq eq;	/* MUST be first */
 	struct mbuf *m;		/* held up due to temporary resource shortage */
+	struct task resume_tx;
+
+	struct ifnet *ifp;	/* the interface this txq belongs to */
 
 	/* stats for common events first */
 
@@ -336,9 +347,11 @@ struct sge_rxq {
 	struct sge_iq iq;	/* MUST be first */
 	struct sge_fl fl;
 
+	struct ifnet *ifp;	/* the interface this rxq belongs to */
 	unsigned int flags;
-	struct port_info *port;	/* the port this rxq belongs to */
+#ifdef INET
 	struct lro_ctrl lro;	/* LRO state */
+#endif
 
 	/* stats for common events first */
 
@@ -544,13 +557,16 @@ static inline bool is_10G_port(const str
 	return ((pi->link_cfg.supported & FW_PORT_CAP_SPEED_10G) != 0);
 }
 
+/* t4_main.c */
+void cxgbe_txq_start(void *, int);
 int t4_os_find_pci_capability(struct adapter *, int);
 int t4_os_pci_save_state(struct adapter *);
 int t4_os_pci_restore_state(struct adapter *);
-
 void t4_os_portmod_changed(const struct adapter *, int);
 void t4_os_link_changed(struct adapter *, int, int);
 
+/* t4_sge.c */
+void t4_sge_modload(void);
 void t4_sge_init(struct adapter *);
 int t4_create_dma_tag(struct adapter *);
 int t4_destroy_dma_tag(struct adapter *);

Modified: stable/8/sys/dev/cxgbe/common/common.h
==============================================================================
--- head/sys/dev/cxgbe/common/common.h	Fri Feb 18 08:00:26 2011	(r218792)
+++ stable/8/sys/dev/cxgbe/common/common.h	Mon Mar 14 09:50:14 2011	(r219633)
@@ -53,8 +53,8 @@ enum {
 };
 
 #define FW_VERSION_MAJOR 1
-#define FW_VERSION_MINOR 2
-#define FW_VERSION_MICRO 65
+#define FW_VERSION_MINOR 3
+#define FW_VERSION_MICRO 0
 
 struct port_stats {
 	u64 tx_octets;            /* total # of octets in good frames */

Modified: stable/8/sys/dev/cxgbe/t4_main.c
==============================================================================
--- head/sys/dev/cxgbe/t4_main.c	Fri Feb 18 08:00:26 2011	(r218792)
+++ stable/8/sys/dev/cxgbe/t4_main.c	Mon Mar 14 09:50:14 2011	(r219633)
@@ -36,11 +36,15 @@ __FBSDID("$FreeBSD$");
 #include <sys/kernel.h>
 #include <sys/bus.h>
 #include <sys/module.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
 #include <sys/pciio.h>
 #include <dev/pci/pcireg.h>
 #include <dev/pci/pcivar.h>
 #include <dev/pci/pci_private.h>
 #include <sys/firmware.h>
+#include <sys/sbuf.h>
 #include <sys/smp.h>
 #include <sys/socket.h>
 #include <sys/sockio.h>
@@ -269,12 +273,14 @@ static void t4_get_regs(struct adapter *
 static void cxgbe_tick(void *);
 static int t4_sysctls(struct adapter *);
 static int cxgbe_sysctls(struct port_info *);
+static int sysctl_int_array(SYSCTL_HANDLER_ARGS);
 static int sysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS);
 static int sysctl_holdoff_pktc_idx(SYSCTL_HANDLER_ARGS);
 static int sysctl_qsize_rxq(SYSCTL_HANDLER_ARGS);
 static int sysctl_qsize_txq(SYSCTL_HANDLER_ARGS);
 static int sysctl_handle_t4_reg64(SYSCTL_HANDLER_ARGS);
-
+static inline void txq_start(struct ifnet *, struct sge_txq *);
+static int t4_mod_event(module_t, int, void *);
 
 struct t4_pciids {
 	uint16_t device;
@@ -692,6 +698,15 @@ cxgbe_attach(device_t dev)
 	ifp->if_softc = pi;
 
 	callout_init(&pi->tick, CALLOUT_MPSAFE);
+	pi->tq = taskqueue_create("cxgbe_taskq", M_NOWAIT,
+	    taskqueue_thread_enqueue, &pi->tq);
+	if (pi->tq == NULL) {
+		device_printf(dev, "failed to allocate port task queue\n");
+		if_free(pi->ifp);
+		return (ENOMEM);
+	}
+	taskqueue_start_threads(&pi->tq, 1, PI_NET, "%s taskq",
+	    device_get_nameunit(dev));
 
 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
@@ -746,6 +761,8 @@ cxgbe_detach(device_t dev)
 	if (rc != 0)
 		device_printf(dev, "port uninit failed: %d.\n", rc);
 
+	taskqueue_free(pi->tq);
+
 	ifmedia_removeall(&pi->media);
 	ether_ifdetach(pi->ifp);
 	if_free(pi->ifp);
@@ -951,13 +968,7 @@ cxgbe_start(struct ifnet *ifp)
 
 	for_each_txq(pi, i, txq) {
 		if (TXQ_TRYLOCK(txq)) {
-			struct buf_ring *br = txq->eq.br;
-			struct mbuf *m;
-
-			m = txq->m ? txq->m : drbr_dequeue(ifp, br);
-			if (m)
-				t4_eth_tx(ifp, txq, m);
-
+			txq_start(ifp, txq);
 			TXQ_UNLOCK(txq);
 		}
 	}
@@ -1247,28 +1258,69 @@ prep_firmware(struct adapter *sc)
 	/* Check firmware version and install a different one if necessary */
 	rc = t4_check_fw_version(sc);
 	if (rc != 0 || force_firmware_install) {
+		uint32_t v = 0;
 
 		fw = firmware_get(T4_FWNAME);
-		if (fw == NULL) {
-			device_printf(sc->dev,
-			    "Could not find firmware image %s\n", T4_FWNAME);
-			return (ENOENT);
+		if (fw != NULL) {
+			const struct fw_hdr *hdr = (const void *)fw->data;
+
+			v = ntohl(hdr->fw_ver);
+
+			/*
+			 * The firmware module will not be used if it isn't the
+			 * same major version as what the driver was compiled
+			 * with.  This check trumps force_firmware_install.
+			 */
+			if (G_FW_HDR_FW_VER_MAJOR(v) != FW_VERSION_MAJOR) {
+				device_printf(sc->dev,
+				    "Found firmware image but version %d "
+				    "can not be used with this driver (%d)\n",
+				    G_FW_HDR_FW_VER_MAJOR(v), FW_VERSION_MAJOR);
+
+				firmware_put(fw, FIRMWARE_UNLOAD);
+				fw = NULL;
+			}
 		}
 
-		device_printf(sc->dev,
-		    "installing firmware %d.%d.%d on card.\n",
-		    FW_VERSION_MAJOR, FW_VERSION_MINOR, FW_VERSION_MICRO);
-		rc = -t4_load_fw(sc, fw->data, fw->datasize);
-		if (rc != 0) {
+		if (fw == NULL && (rc < 0 || force_firmware_install)) {
+			device_printf(sc->dev, "No usable firmware. "
+			    "card has %d.%d.%d, driver compiled with %d.%d.%d, "
+			    "force_firmware_install%s set",
+			    G_FW_HDR_FW_VER_MAJOR(sc->params.fw_vers),
+			    G_FW_HDR_FW_VER_MINOR(sc->params.fw_vers),
+			    G_FW_HDR_FW_VER_MICRO(sc->params.fw_vers),
+			    FW_VERSION_MAJOR, FW_VERSION_MINOR,
+			    FW_VERSION_MICRO,
+			    force_firmware_install ? "" : " not");
+			return (EAGAIN);
+		}
+
+		/*
+		 * Always upgrade, even for minor/micro/build mismatches.
+		 * Downgrade only for a major version mismatch or if
+		 * force_firmware_install was specified.
+		 */
+		if (fw != NULL && (rc < 0 || force_firmware_install ||
+		    v > sc->params.fw_vers)) {
 			device_printf(sc->dev,
-			    "failed to install firmware: %d\n", rc);
-			return (rc);
-		} else {
-			t4_get_fw_version(sc, &sc->params.fw_vers);
-			t4_get_tp_version(sc, &sc->params.tp_vers);
+			    "installing firmware %d.%d.%d.%d on card.\n",
+			    G_FW_HDR_FW_VER_MAJOR(v), G_FW_HDR_FW_VER_MINOR(v),
+			    G_FW_HDR_FW_VER_MICRO(v), G_FW_HDR_FW_VER_BUILD(v));
+
+			rc = -t4_load_fw(sc, fw->data, fw->datasize);
+			if (rc != 0) {
+				device_printf(sc->dev,
+				    "failed to install firmware: %d\n", rc);
+				firmware_put(fw, FIRMWARE_UNLOAD);
+				return (rc);
+			} else {
+				/* refresh */
+				(void) t4_check_fw_version(sc);
+			}
 		}
 
-		firmware_put(fw, FIRMWARE_UNLOAD);
+		if (fw != NULL)
+			firmware_put(fw, FIRMWARE_UNLOAD);
 	}
 
 	/* Contact firmware, request master */
@@ -2244,15 +2296,13 @@ t4_sysctls(struct adapter *sc)
 	SYSCTL_ADD_INT(ctx, children, OID_AUTO, "core_clock", CTLFLAG_RD,
 	    &sc->params.vpd.cclk, 0, "core clock frequency (in KHz)");
 
-	/* XXX: this doesn't seem to show up */
-	SYSCTL_ADD_OPAQUE(ctx, children, OID_AUTO, "holdoff_tmr",
-	    CTLFLAG_RD, &intr_timer, sizeof(intr_timer), "IU",
-	    "interrupt holdoff timer values (us)");
-
-	/* XXX: this doesn't seem to show up */
-	SYSCTL_ADD_OPAQUE(ctx, children, OID_AUTO, "holdoff_pktc",
-	    CTLFLAG_RD, &intr_pktcount, sizeof(intr_pktcount), "IU",
-	    "interrupt holdoff packet counter values");
+	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_timers",
+	    CTLTYPE_STRING | CTLFLAG_RD, &intr_timer, sizeof(intr_timer),
+	    sysctl_int_array, "A", "interrupt holdoff timer values (us)");
+
+	SYSCTL_ADD_PROC(ctx, children, OID_AUTO, "holdoff_pkt_counts",
+	    CTLTYPE_STRING | CTLFLAG_RD, &intr_pktcount, sizeof(intr_pktcount),
+	    sysctl_int_array, "A", "interrupt holdoff packet counter values");
 
 	return (0);
 }
@@ -2304,7 +2354,7 @@ cxgbe_sysctls(struct port_info *pi)
 
 #define SYSCTL_ADD_T4_REG64(pi, name, desc, reg) \
 	SYSCTL_ADD_OID(ctx, children, OID_AUTO, name, \
-	    CTLTYPE_U64 | CTLFLAG_RD, pi->adapter, reg, \
+	    CTLTYPE_QUAD | CTLFLAG_RD, pi->adapter, reg, \
 	    sysctl_handle_t4_reg64, "QU", desc)
 
 	SYSCTL_ADD_T4_REG64(pi, "tx_octets", "# of octets in good frames",
@@ -2428,7 +2478,7 @@ cxgbe_sysctls(struct port_info *pi)
 #undef SYSCTL_ADD_T4_REG64
 
 #define SYSCTL_ADD_T4_PORTSTAT(name, desc) \
-	SYSCTL_ADD_UQUAD(ctx, children, OID_AUTO, #name, CTLFLAG_RD, \
+	SYSCTL_ADD_QUAD(ctx, children, OID_AUTO, #name, CTLFLAG_RD, \
 	    &pi->stats.name, desc)
 
 	/* We get these from port_stats and they may be stale by upto 1s */
@@ -2455,6 +2505,22 @@ cxgbe_sysctls(struct port_info *pi)
 }
 
 static int
+sysctl_int_array(SYSCTL_HANDLER_ARGS)
+{
+	int rc, *i;
+	struct sbuf sb;
+
+	sbuf_new(&sb, NULL, 32, SBUF_AUTOEXTEND);
+	for (i = arg1; arg2; arg2 -= sizeof(int), i++)
+		sbuf_printf(&sb, "%d ", *i);
+	sbuf_trim(&sb);
+	sbuf_finish(&sb);
+	rc = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req);
+	sbuf_delete(&sb);
+	return (rc);
+}
+
+static int
 sysctl_holdoff_tmr_idx(SYSCTL_HANDLER_ARGS)
 {
 	struct port_info *pi = arg1;
@@ -2578,7 +2644,31 @@ sysctl_handle_t4_reg64(SYSCTL_HANDLER_AR
 
 	val = t4_read_reg64(sc, reg);
 
-	return (sysctl_handle_64(oidp, &val, 0, req));
+	return (sysctl_handle_quad(oidp, &val, 0, req));
+}
+
+static inline void
+txq_start(struct ifnet *ifp, struct sge_txq *txq)
+{
+	struct buf_ring *br;
+	struct mbuf *m;
+
+	TXQ_LOCK_ASSERT_OWNED(txq);
+
+	br = txq->eq.br;
+	m = txq->m ? txq->m : drbr_dequeue(ifp, br);
+	if (m)
+		t4_eth_tx(ifp, txq, m);
+}
+
+void
+cxgbe_txq_start(void *arg, int count)
+{
+	struct sge_txq *txq = arg;
+
+	TXQ_LOCK(txq);
+	txq_start(txq->ifp, txq);
+	TXQ_UNLOCK(txq);
 }
 
 int
@@ -2646,6 +2736,7 @@ t4_os_pci_restore_state(struct adapter *
 	pci_cfg_restore(dev, dinfo);
 	return (0);
 }
+
 void
 t4_os_portmod_changed(const struct adapter *sc, int idx)
 {
@@ -2656,10 +2747,13 @@ t4_os_portmod_changed(const struct adapt
 
 	if (pi->mod_type == FW_PORT_MOD_TYPE_NONE)
 		if_printf(pi->ifp, "transceiver unplugged.\n");
-	else
+	else if (pi->mod_type > 0 && pi->mod_type < ARRAY_SIZE(mod_str)) {
 		if_printf(pi->ifp, "%s transceiver inserted.\n",
 		    mod_str[pi->mod_type]);
-
+	} else {
+		if_printf(pi->ifp, "transceiver (type %d) inserted.\n",
+		    pi->mod_type);
+	}
 }
 
 void
@@ -2737,10 +2831,20 @@ t4_ioctl(struct cdev *dev, unsigned long
 	return (rc);
 }
 
+static int
+t4_mod_event(module_t mod, int cmd, void *arg)
+{
+
+	if (cmd == MOD_LOAD)
+		t4_sge_modload();
+
+	return (0);
+}
+
 static devclass_t t4_devclass;
 static devclass_t cxgbe_devclass;
 
-DRIVER_MODULE(t4nex, pci, t4_driver, t4_devclass, 0, 0);
+DRIVER_MODULE(t4nex, pci, t4_driver, t4_devclass, t4_mod_event, 0);
 MODULE_VERSION(t4nex, 1);
 
 DRIVER_MODULE(cxgbe, t4nex, cxgbe_driver, cxgbe_devclass, 0, 0);

Modified: stable/8/sys/dev/cxgbe/t4_sge.c
==============================================================================
--- head/sys/dev/cxgbe/t4_sge.c	Fri Feb 18 08:00:26 2011	(r218792)
+++ stable/8/sys/dev/cxgbe/t4_sge.c	Mon Mar 14 09:50:14 2011	(r219633)
@@ -34,6 +34,9 @@ __FBSDID("$FreeBSD$");
 #include <sys/mbuf.h>
 #include <sys/socket.h>
 #include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
 #include <sys/sysctl.h>
 #include <net/bpf.h>
 #include <net/ethernet.h>
@@ -55,13 +58,9 @@ struct fl_buf_info {
 	uma_zone_t zone;
 };
 
-/* t4_sge_init will fill up the zone */
-static struct fl_buf_info fl_buf_info[FL_BUF_SIZES] = {
-	{ MCLBYTES, EXT_CLUSTER, NULL},
-	{ MJUMPAGESIZE, EXT_JUMBOP, NULL},
-	{ MJUM9BYTES, EXT_JUMBO9, NULL},
-	{ MJUM16BYTES, EXT_JUMBO16, NULL}
-};
+/* Filled up by t4_sge_modload */
+static struct fl_buf_info fl_buf_info[FL_BUF_SIZES];
+
 #define FL_BUF_SIZE(x)	(fl_buf_info[x].size)
 #define FL_BUF_TYPE(x)	(fl_buf_info[x].type)
 #define FL_BUF_ZONE(x)	(fl_buf_info[x].zone)
@@ -118,7 +117,6 @@ static int alloc_fl_sdesc(struct sge_fl 
 static void free_fl_sdesc(struct sge_fl *);
 static int alloc_eq_maps(struct sge_eq *);
 static void free_eq_maps(struct sge_eq *);
-static struct mbuf *get_fl_sdesc_data(struct sge_fl *, int, int);
 static void set_fl_tag_idx(struct sge_fl *, int);
 
 static int get_pkt_sgl(struct sge_txq *, struct mbuf **, struct sgl *, int);
@@ -133,9 +131,35 @@ static inline void write_ulp_cpl_sgl(str
 static int write_sgl_to_txd(struct sge_eq *, struct sgl *, caddr_t *);
 static inline void copy_to_txd(struct sge_eq *, caddr_t, caddr_t *, int);
 static inline void ring_tx_db(struct adapter *, struct sge_eq *);
+static inline int reclaimable(struct sge_eq *);
 static int reclaim_tx_descs(struct sge_eq *, int, int);
 static void write_eqflush_wr(struct sge_eq *);
 static __be64 get_flit(bus_dma_segment_t *, int, int);
+static int handle_sge_egr_update(struct adapter *,
+    const struct cpl_sge_egr_update *);
+
+/*
+ * Called on MOD_LOAD and fills up fl_buf_info[].
+ */
+void
+t4_sge_modload(void)
+{
+	int i;
+	int bufsize[FL_BUF_SIZES] = {
+		MCLBYTES,
+#if MJUMPAGESIZE != MCLBYTES
+		MJUMPAGESIZE,
+#endif
+		MJUM9BYTES,
+		MJUM16BYTES
+	};
+
+	for (i = 0; i < FL_BUF_SIZES; i++) {
+		FL_BUF_SIZE(i) = bufsize[i];
+		FL_BUF_TYPE(i) = m_gettype(bufsize[i]);
+		FL_BUF_ZONE(i) = m_getzone(bufsize[i]);
+	}
+}
 
 /**
  *	t4_sge_init - initialize SGE
@@ -151,11 +175,6 @@ t4_sge_init(struct adapter *sc)
 	struct sge *s = &sc->sge;
 	int i;
 
-	FL_BUF_ZONE(0) = zone_clust;
-	FL_BUF_ZONE(1) = zone_jumbop;
-	FL_BUF_ZONE(2) = zone_jumbo9;
-	FL_BUF_ZONE(3) = zone_jumbo16;
-
 	t4_set_reg_field(sc, A_SGE_CONTROL, V_PKTSHIFT(M_PKTSHIFT) |
 			 V_INGPADBOUNDARY(M_INGPADBOUNDARY) |
 			 F_EGRSTATUSPAGESIZE,
@@ -409,7 +428,6 @@ t4_intr_fwd(void *arg)
 	int ndesc_pending = 0, ndesc_total = 0;
 	int qid;
 
-	IQ_LOCK(iq);
 	while (is_new_response(iq, &ctrl)) {
 
 		rmb();
@@ -436,7 +454,6 @@ t4_intr_fwd(void *arg)
 
 		iq_next(iq);
 	}
-	IQ_UNLOCK(iq);
 
 	if (ndesc_total > 0) {
 		t4_write_reg(sc, MYPF_REG(A_SGE_PF_GTS),
@@ -469,7 +486,6 @@ t4_intr_evt(void *arg)
 
 	KASSERT(iq == &sc->sge.fwq, ("%s: unexpected ingress queue", __func__));
 
-	IQ_LOCK(iq);
 	while (is_new_response(iq, &ctrl)) {
 
 		rmb();
@@ -492,21 +508,9 @@ t4_intr_evt(void *arg)
 
 			break;
 			}
-		case CPL_SGE_EGR_UPDATE: {
-			const struct cpl_sge_egr_update *cpl;
-			unsigned int qid;
-			struct sge *s = &sc->sge;
-			struct sge_txq *txq;
-
-			cpl = (const void *)(rss + 1);
-			qid = G_EGR_QID(ntohl(cpl->opcode_qid));
-			txq = (void *)s->eqmap[qid - s->eq_start];
-			txq->egr_update++;
-
-			/* XXX: wake up stalled tx */
-
+		case CPL_SGE_EGR_UPDATE:
+			handle_sge_egr_update(sc, (const void *)(rss + 1));
 			break;
-			}
 
 		default:
 			device_printf(sc->dev,
@@ -524,7 +528,6 @@ t4_intr_evt(void *arg)
 		}
 		iq_next(iq);
 	}
-	IQ_UNLOCK(iq);
 
 	if (ndesc_total > 0) {
 		t4_write_reg(sc, MYPF_REG(A_SGE_PF_GTS),
@@ -538,63 +541,73 @@ t4_intr_data(void *arg)
 {
 	struct sge_rxq *rxq = arg;
 	struct sge_iq *iq = arg;
+	struct adapter *sc = iq->adapter;
 	struct rsp_ctrl *ctrl;
+	struct ifnet *ifp = rxq->ifp;
 	struct sge_fl *fl = &rxq->fl;
-	struct port_info *pi = rxq->port;
-	struct ifnet *ifp = pi->ifp;
-	struct adapter *sc = pi->adapter;
+	struct fl_sdesc *sd = &fl->sdesc[fl->cidx], *sd_next;
 	const struct rss_header *rss;
 	const struct cpl_rx_pkt *cpl;
-	int ndescs = 0, rsp_type;
 	uint32_t len;
+	int ndescs = 0, i;
 	struct mbuf *m0, *m;
 #ifdef INET
 	struct lro_ctrl *lro = &rxq->lro;
 	struct lro_entry *l;
 #endif
 
-	IQ_LOCK(iq);
+	prefetch(sd->m);
+	prefetch(sd->cl);
+
 	iq->intr_next = iq->intr_params;
 	while (is_new_response(iq, &ctrl)) {
 
 		rmb();
 
 		rss = (const void *)iq->cdesc;
-		cpl = (const void *)(rss + 1);
+		i = G_RSPD_TYPE(ctrl->u.type_gen);
 
-		rsp_type = G_RSPD_TYPE(ctrl->u.type_gen);
+		if (__predict_false(i == X_RSPD_TYPE_CPL)) {
 
-		if (__predict_false(rsp_type == X_RSPD_TYPE_CPL)) {
-			const struct cpl_sge_egr_update *p = (const void *)cpl;
-			unsigned int qid = G_EGR_QID(ntohl(p->opcode_qid));
+			/* Can't be anything except an egress update */
+			KASSERT(rss->opcode == CPL_SGE_EGR_UPDATE,
+			    ("%s: unexpected CPL %x", __func__, rss->opcode));
 
-			KASSERT(cpl->opcode == CPL_SGE_EGR_UPDATE,
-			    ("unexpected opcode on data ingress queue: %x",
-			    cpl->opcode));
-
-			/* XXX: noone's waiting to be woken up... */
-			wakeup(sc->sge.eqmap[qid - sc->sge.eq_start]);
+			handle_sge_egr_update(sc, (const void *)(rss + 1));
+			goto nextdesc;
+		}
+		KASSERT(i == X_RSPD_TYPE_FLBUF && rss->opcode == CPL_RX_PKT,
+		    ("%s: unexpected CPL %x rsp %d", __func__, rss->opcode, i));
 
-			ndescs++;
-			iq_next(iq);
+		sd_next = sd + 1;
+		if (__predict_false(fl->cidx + 1 == fl->cap))
+			sd_next = fl->sdesc;
+		prefetch(sd_next->m);
+		prefetch(sd_next->cl);
 
-			continue;
-		}
+		cpl = (const void *)(rss + 1);
 
-		KASSERT(G_RSPD_TYPE(ctrl->u.type_gen) == X_RSPD_TYPE_FLBUF,
-		    ("unexpected event on data ingress queue: %x",
-		    G_RSPD_TYPE(ctrl->u.type_gen)));
+		m0 = sd->m;
+		sd->m = NULL;	/* consumed */
 
 		len = be32toh(ctrl->pldbuflen_qid);
+		if (__predict_false((len & F_RSPD_NEWBUF) == 0))
+			panic("%s: cannot handle packed frames", __func__);
+		len = G_RSPD_LEN(len);
 
-		KASSERT(len & F_RSPD_NEWBUF,
-		    ("%s: T4 misconfigured to pack buffers.", __func__));
+		bus_dmamap_sync(fl->tag[sd->tag_idx], sd->map,
+		    BUS_DMASYNC_POSTREAD);
 
-		len = G_RSPD_LEN(len);
-		m0 = get_fl_sdesc_data(fl, len, M_PKTHDR);
-		if (m0 == NULL) {
-			iq->intr_next = V_QINTR_TIMER_IDX(SGE_NTIMERS - 1);
-			break;
+		m_init(m0, NULL, 0, M_NOWAIT, MT_DATA, M_PKTHDR);
+		if (len < MINCLSIZE) {
+			/* copy data to mbuf, buffer will be recycled */
+			bcopy(sd->cl, mtod(m0, caddr_t), len);
+			m0->m_len = len;
+		} else {
+			bus_dmamap_unload(fl->tag[sd->tag_idx], sd->map);
+			m_cljset(m0, sd->cl, FL_BUF_TYPE(sd->tag_idx));
+			sd->cl = NULL;	/* consumed */
+			m0->m_len = min(len, FL_BUF_SIZE(sd->tag_idx));
 		}
 
 		len -= FL_PKTSHIFT;
@@ -623,16 +636,49 @@ t4_intr_data(void *arg)
 			rxq->vlan_extraction++;
 		}
 
+		i = 1;	/* # of fl sdesc used */
+		sd = sd_next;
+		if (__predict_false(++fl->cidx == fl->cap))
+			fl->cidx = 0;
+
 		len -= m0->m_len;
 		m = m0;
 		while (len) {
-			m->m_next = get_fl_sdesc_data(fl, len, 0);
-			if (m->m_next == NULL)
-				CXGBE_UNIMPLEMENTED("mbuf recovery");
+			i++;
 
+			sd_next = sd + 1;
+			if (__predict_false(fl->cidx + 1 == fl->cap))
+				sd_next = fl->sdesc;
+			prefetch(sd_next->m);
+			prefetch(sd_next->cl);
+
+			m->m_next = sd->m;
+			sd->m = NULL;	/* consumed */
 			m = m->m_next;
+
+			bus_dmamap_sync(fl->tag[sd->tag_idx], sd->map,
+			    BUS_DMASYNC_POSTREAD);
+
+			m_init(m, NULL, 0, M_NOWAIT, MT_DATA, 0);
+			if (len <= MLEN) {
+				bcopy(sd->cl, mtod(m, caddr_t), len);
+				m->m_len = len;
+			} else {
+				bus_dmamap_unload(fl->tag[sd->tag_idx],
+				    sd->map);
+				m_cljset(m, sd->cl, FL_BUF_TYPE(sd->tag_idx));
+				sd->cl = NULL;	/* consumed */
+				m->m_len = min(len, FL_BUF_SIZE(sd->tag_idx));
+			}
+
+			i++;
+			sd = sd_next;
+			if (__predict_false(++fl->cidx == fl->cap))
+				fl->cidx = 0;
+
 			len -= m->m_len;
 		}
+
 #ifdef INET
 		if (cpl->l2info & htobe32(F_RXF_LRO) &&
 		    rxq->flags & RXQ_LRO_ENABLED &&
@@ -640,17 +686,17 @@ t4_intr_data(void *arg)
 			/* queued for LRO */
 		} else
 #endif
-			(*ifp->if_input)(ifp, m0);
+		ifp->if_input(ifp, m0);
 
 		FL_LOCK(fl);
-		if (fl->needed >= 32) {
+		fl->needed += i;
+		if (fl->needed >= 32)

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



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201103140950.p2E9oEm4084178>