Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 14 Mar 2011 23:13:02 +0000 (UTC)
From:      Jeff Roberson <jeff@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-projects@freebsd.org
Subject:   svn commit: r219650 - projects/ofed/head/sys/ofed/drivers/net/mlx4
Message-ID:  <201103142313.p2END2HI014467@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jeff
Date: Mon Mar 14 23:13:01 2011
New Revision: 219650
URL: http://svn.freebsd.org/changeset/base/219650

Log:
   - Port the Mellanox 10gigE driver.  This supports ConnectX-2 cards which
     can be dual IB/Ethernet adapters.  The port supports all of the usual
     high-end offloads.  TSO/LRO/RSS/checksums etc.  This is a beta
     quality driver, work is still underway.
  
  Sponsored by:	Mellanox Technologies

Modified:
  projects/ofed/head/sys/ofed/drivers/net/mlx4/en_cq.c
  projects/ofed/head/sys/ofed/drivers/net/mlx4/en_ethtool.c
  projects/ofed/head/sys/ofed/drivers/net/mlx4/en_frag.c
  projects/ofed/head/sys/ofed/drivers/net/mlx4/en_main.c
  projects/ofed/head/sys/ofed/drivers/net/mlx4/en_netdev.c
  projects/ofed/head/sys/ofed/drivers/net/mlx4/en_port.c
  projects/ofed/head/sys/ofed/drivers/net/mlx4/en_port.h
  projects/ofed/head/sys/ofed/drivers/net/mlx4/en_rx.c
  projects/ofed/head/sys/ofed/drivers/net/mlx4/en_selftest.c
  projects/ofed/head/sys/ofed/drivers/net/mlx4/en_tx.c
  projects/ofed/head/sys/ofed/drivers/net/mlx4/main.c
  projects/ofed/head/sys/ofed/drivers/net/mlx4/mlx4_en.h

Modified: projects/ofed/head/sys/ofed/drivers/net/mlx4/en_cq.c
==============================================================================
--- projects/ofed/head/sys/ofed/drivers/net/mlx4/en_cq.c	Mon Mar 14 23:09:15 2011	(r219649)
+++ projects/ofed/head/sys/ofed/drivers/net/mlx4/en_cq.c	Mon Mar 14 23:13:01 2011	(r219650)
@@ -31,12 +31,12 @@
  *
  */
 
+#include "mlx4_en.h"
+
 #include <linux/mlx4/cq.h>
 #include <linux/mlx4/qp.h>
 #include <linux/mlx4/cmd.h>
 
-#include "mlx4_en.h"
-
 static void mlx4_en_cq_event(struct mlx4_cq *cq, enum mlx4_event event)
 {
 	return;
@@ -55,14 +55,20 @@ int mlx4_en_create_cq(struct mlx4_en_pri
 		cq->buf_size = cq->size * sizeof(struct mlx4_cqe);
 		cq->vector   = (ring + priv->port) %
 				mdev->dev->caps.num_comp_vectors;
+		TASK_INIT(&cq->cq_task, 0, mlx4_en_rx_que, cq);
 	} else {
 		cq->buf_size = sizeof(struct mlx4_cqe);
 		cq->vector   = MLX4_LEAST_ATTACHED_VECTOR;
+		TASK_INIT(&cq->cq_task, 0, mlx4_en_tx_que, cq);
 	}
 
+	cq->tq = taskqueue_create_fast("mlx4_en_que", M_NOWAIT,
+	    taskqueue_thread_enqueue, &cq->tq);
+	taskqueue_start_threads(&cq->tq, 1, PI_NET, "%s cq",
+	    if_name(priv->dev));
 	cq->ring = ring;
 	cq->is_tx = mode;
-	spin_lock_init(&cq->lock);
+	mtx_init(&cq->lock.m, "mlx4 cq", NULL, MTX_DEF);
 
 	err = mlx4_alloc_hwq_res(mdev->dev, &cq->wqres,
 				cq->buf_size, 2 * PAGE_SIZE);
@@ -105,9 +111,6 @@ int mlx4_en_activate_cq(struct mlx4_en_p
 		init_timer(&cq->timer);
 		cq->timer.function = mlx4_en_poll_tx_cq;
 		cq->timer.data = (unsigned long) cq;
-	} else {
-		netif_napi_add(cq->dev, &cq->napi, mlx4_en_poll_rx_cq, 64);
-		napi_enable(&cq->napi);
 	}
 
 	return 0;
@@ -117,22 +120,22 @@ void mlx4_en_destroy_cq(struct mlx4_en_p
 {
 	struct mlx4_en_dev *mdev = priv->mdev;
 
+	taskqueue_drain(cq->tq, &cq->cq_task);
+	taskqueue_free(cq->tq);
 	mlx4_en_unmap_buffer(&cq->wqres.buf);
 	mlx4_free_hwq_res(mdev->dev, &cq->wqres, cq->buf_size);
 	cq->buf_size = 0;
 	cq->buf = NULL;
+	mtx_destroy(&cq->lock.m);
 }
 
 void mlx4_en_deactivate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq)
 {
 	struct mlx4_en_dev *mdev = priv->mdev;
 
+	taskqueue_drain(cq->tq, &cq->cq_task);
 	if (cq->is_tx)
 		del_timer(&cq->timer);
-	else {
-		napi_disable(&cq->napi);
-		netif_napi_del(&cq->napi);
-	}
 
 	mlx4_cq_free(mdev->dev, &cq->mcq);
 }

Modified: projects/ofed/head/sys/ofed/drivers/net/mlx4/en_ethtool.c
==============================================================================
--- projects/ofed/head/sys/ofed/drivers/net/mlx4/en_ethtool.c	Mon Mar 14 23:09:15 2011	(r219649)
+++ projects/ofed/head/sys/ofed/drivers/net/mlx4/en_ethtool.c	Mon Mar 14 23:13:01 2011	(r219650)
@@ -390,7 +390,7 @@ static int mlx4_en_set_pauseparam(struct
 	priv->prof->tx_pause = pause->tx_pause != 0;
 	priv->prof->rx_pause = pause->rx_pause != 0;
 	err = mlx4_SET_PORT_general(mdev->dev, priv->port,
-				    priv->rx_skb_size + ETH_FCS_LEN,
+				    priv->rx_mb_size + ETH_FCS_LEN,
 				    priv->prof->tx_pause,
 				    priv->prof->tx_ppp,
 				    priv->prof->rx_pause,

Modified: projects/ofed/head/sys/ofed/drivers/net/mlx4/en_frag.c
==============================================================================
--- projects/ofed/head/sys/ofed/drivers/net/mlx4/en_frag.c	Mon Mar 14 23:09:15 2011	(r219649)
+++ projects/ofed/head/sys/ofed/drivers/net/mlx4/en_frag.c	Mon Mar 14 23:13:01 2011	(r219650)
@@ -31,17 +31,14 @@
  *
  */
 
-#include <linux/skbuff.h>
-#include <linux/ip.h>
-#include <linux/if_vlan.h>
-#include <net/ip.h>
-#include <linux/etherdevice.h>
-
 #include "mlx4_en.h"
 
+#include <net/ethernet.h>
+#include <netinet/ip.h>
+#include <machine/in_cksum.h>
 
 static struct mlx4_en_ipfrag *find_session(struct mlx4_en_rx_ring *ring,
-					   struct iphdr *iph)
+					   struct ip *iph)
 {
 	struct mlx4_en_ipfrag *session;
 	int i;
@@ -50,10 +47,10 @@ static struct mlx4_en_ipfrag *find_sessi
 		session = &ring->ipfrag[i];
 		if (session->fragments == NULL)
 			continue;
-		if (session->daddr == iph->daddr &&
-		    session->saddr == iph->saddr &&
-		    session->id == iph->id &&
-		    session->protocol == iph->protocol) {
+		if (session->daddr == iph->ip_dst.s_addr &&
+		    session->saddr == iph->ip_src.s_addr &&
+		    session->id == iph->ip_id &&
+		    session->protocol == iph->ip_p) {
 			return session;
 		}
 	}
@@ -61,7 +58,7 @@ static struct mlx4_en_ipfrag *find_sessi
 }
 
 static struct mlx4_en_ipfrag *start_session(struct mlx4_en_rx_ring *ring,
-					    struct iphdr *iph)
+					    struct ip *iph)
 {
 	struct mlx4_en_ipfrag *session;
 	int index = -1;
@@ -86,22 +83,18 @@ static void flush_session(struct mlx4_en
 			  struct mlx4_en_ipfrag *session,
 			  u16 more)
 {
-	struct sk_buff *skb = session->fragments;
-	struct iphdr *iph = ip_hdr(skb);
-	struct net_device *dev = skb->dev;
+	struct mbuf *mb = session->fragments;
+	struct ip *iph = mb->m_pkthdr.header;
+	struct net_device *dev = mb->m_pkthdr.rcvif;
 
 	/* Update IP length and checksum */
-	iph->tot_len = htons(session->total_len);
-	iph->frag_off = htons(more | (session->offset >> 3));
-	iph->check = 0;
-	iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
-
-	if (session->vlan)
-		vlan_hwaccel_receive_skb(skb, priv->vlgrp,
-					 be16_to_cpu(session->sl_vid));
-	else
-		netif_receive_skb(skb);
-	dev->last_rx = jiffies;
+	iph->ip_len = htons(session->total_len);
+	iph->ip_off = htons(more | (session->offset >> 3));
+	iph->ip_sum = 0;
+	iph->ip_sum = in_cksum_skip(mb, iph->ip_hl * 4,
+	    (char *)iph - mb->m_data);
+
+	dev->if_input(dev, mb);
 	session->fragments = NULL;
 	session->last = NULL;
 }
@@ -109,89 +102,73 @@ static void flush_session(struct mlx4_en
 
 static inline void frag_append(struct mlx4_en_priv *priv,
 			       struct mlx4_en_ipfrag *session,
-			       struct sk_buff *skb,
+			       struct mbuf *mb,
 			       unsigned int data_len)
 {
-	struct sk_buff *parent = session->fragments;
+	struct mbuf *parent = session->fragments;
 
-	/* Update skb bookkeeping */
-	parent->len += data_len;
-	parent->data_len += data_len;
+	/* Update mb bookkeeping */
+	parent->m_pkthdr.len += data_len;
 	session->total_len += data_len;
 
-	skb_pull(skb, skb->len - data_len);
-	parent->truesize += skb->truesize;
+	m_adj(mb, mb->m_pkthdr.len - data_len);
 
-	if (session->last)
-		session->last->next = skb;
-	else
-		skb_shinfo(parent)->frag_list = skb;
-
-	session->last = skb;
+	session->last->m_next = mb;
+	for (; mb->m_next != NULL; mb = mb->m_next);
+	session->last = mb;
 }
 
 int mlx4_en_rx_frags(struct mlx4_en_priv *priv, struct mlx4_en_rx_ring *ring,
-		     struct sk_buff *skb, struct mlx4_cqe *cqe)
+		     struct mbuf *mb, struct mlx4_cqe *cqe)
 {
 	struct mlx4_en_ipfrag *session;
-	struct iphdr *iph;
+	struct ip *iph;
 	u16 ip_len;
 	u16 ip_hlen;
 	int data_len;
 	u16 offset;
 
-	skb_reset_network_header(skb);
-	skb_reset_transport_header(skb);
-	iph = ip_hdr(skb);
-	ip_len = ntohs(iph->tot_len);
-	ip_hlen = iph->ihl * 4;
+	iph = (struct ip *)(mtod(mb, char *) + ETHER_HDR_LEN);
+	mb->m_pkthdr.header = iph;
+	ip_len = ntohs(iph->ip_len);
+	ip_hlen = iph->ip_hl * 4;
 	data_len = ip_len - ip_hlen;
-	offset = ntohs(iph->frag_off);
-	offset &= IP_OFFSET;
+	offset = ntohs(iph->ip_off);
+	offset &= IP_OFFMASK;
 	offset <<= 3;
 
 	session = find_session(ring, iph);
-	if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl))) {
+	if (unlikely(in_cksum_skip(mb, ip_hlen, (char *)iph - mb->m_data))) {
 		if (session)
 			flush_session(priv, session, IP_MF);
 		return -EINVAL;
 	}
 	if (session) {
 		if (unlikely(session->offset + session->total_len !=
-			     offset + ip_hlen)) {
+		    offset + ip_hlen ||
+		    session->total_len + mb->m_pkthdr.len > 65536)) {
 			flush_session(priv, session, IP_MF);
 			goto new_session;
 		}
-		/* Packets smaller then 60 bytes are padded to that size
-		 * Need to fix len field of the skb to fit the actual data size
-		 * Since ethernet header already removed, the IP total length
-		 * is exactly the data size (the skb is linear)
-		 */
-		skb->len = ip_len;
-
-		frag_append(priv, session, skb, data_len);
+		frag_append(priv, session, mb, data_len);
 	} else {
 new_session:
 		session = start_session(ring, iph);
 		if (unlikely(!session))
 			return -ENOSPC;
 
-		session->fragments = skb;
-		session->daddr = iph->daddr;
-		session->saddr = iph->saddr;
-		session->id = iph->id;
-		session->protocol = iph->protocol;
+		session->fragments = mb;
+		session->daddr = iph->ip_dst.s_addr;
+		session->saddr = iph->ip_src.s_addr;
+		session->id = iph->ip_id;
+		session->protocol = iph->ip_p;
 		session->total_len = ip_len;
 		session->offset = offset;
-		session->vlan = (priv->vlgrp &&
-				 (be32_to_cpu(cqe->vlan_my_qpn) &
-				  MLX4_CQE_VLAN_PRESENT_MASK)) ? 1 : 0;
-		session->sl_vid = cqe->sl_vid;
+		for (; mb->m_next != NULL; mb = mb->m_next);
+		session->last = mb;
 	}
-	if (!(ntohs(iph->frag_off) & IP_MF))
+	if (!(ntohs(iph->ip_off) & IP_MF))
 		flush_session(priv, session, 0);
-	else if (session->fragments->len + priv->dev->mtu > 65536)
-		flush_session(priv, session, IP_MF);
 
 	return 0;
 }

Modified: projects/ofed/head/sys/ofed/drivers/net/mlx4/en_main.c
==============================================================================
--- projects/ofed/head/sys/ofed/drivers/net/mlx4/en_main.c	Mon Mar 14 23:09:15 2011	(r219649)
+++ projects/ofed/head/sys/ofed/drivers/net/mlx4/en_main.c	Mon Mar 14 23:13:01 2011	(r219650)
@@ -31,7 +31,6 @@
  *
  */
 
-#include <linux/cpumask.h>
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/netdevice.h>
@@ -162,6 +161,8 @@ static void mlx4_en_remove(struct mlx4_d
 	mlx4_mr_free(dev, &mdev->mr);
 	mlx4_uar_free(dev, &mdev->priv_uar);
 	mlx4_pd_free(dev, mdev->priv_pdn);
+	sx_destroy(&mdev->state_lock.sx);
+	mtx_destroy(&mdev->uar_lock.m);
 	kfree(mdev);
 }
 
@@ -191,10 +192,10 @@ static void *mlx4_en_add(struct mlx4_dev
 	if (mlx4_uar_alloc(dev, &mdev->priv_uar))
 		goto err_pd;
 
+	mtx_init(&mdev->uar_lock.m, "mlx4 uar", NULL, MTX_DEF);
 	mdev->uar_map = ioremap(mdev->priv_uar.pfn << PAGE_SHIFT, PAGE_SIZE);
 	if (!mdev->uar_map)
 		goto err_uar;
-	spin_lock_init(&mdev->uar_lock);
 
 	mdev->dev = dev;
 	mdev->dma_device = &(dev->pdev->dev);
@@ -253,7 +254,7 @@ static void *mlx4_en_add(struct mlx4_dev
 
 	/* At this stage all non-port specific tasks are complete:
 	 * mark the card state as up */
-	mutex_init(&mdev->state_lock);
+	sx_init(&mdev->state_lock.sx, "mlxen state");
 	mdev->device_up = true;
 
 	/* Setup ports */
@@ -286,6 +287,7 @@ err_free_netdev:
 err_mr:
 	mlx4_mr_free(dev, &mdev->mr);
 err_uar:
+	mtx_destroy(&mdev->uar_lock.m);
 	mlx4_uar_free(dev, &mdev->priv_uar);
 err_pd:
 	mlx4_pd_free(dev, mdev->priv_pdn);
@@ -308,6 +310,7 @@ enum mlx4_query_reply mlx4_en_query(void
 	return MLX4_QUERY_NOT_MINE;
 }
 
+#if 0
 static struct pci_device_id mlx4_en_pci_table[] = {
 	{ PCI_VDEVICE(MELLANOX, 0x6340) }, /* MT25408 "Hermon" SDR */
 	{ PCI_VDEVICE(MELLANOX, 0x634a) }, /* MT25408 "Hermon" DDR */
@@ -342,6 +345,7 @@ static struct pci_device_id mlx4_en_pci_
 };
 
 MODULE_DEVICE_TABLE(pci, mlx4_en_pci_table);
+#endif
 
 static struct mlx4_interface mlx4_en_interface = {
 	.add	= mlx4_en_add,
@@ -365,3 +369,16 @@ static void __exit mlx4_en_cleanup(void)
 module_init(mlx4_en_init);
 module_exit(mlx4_en_cleanup);
 
+#undef MODULE_VERSION
+#include <sys/module.h>
+static int
+mlxen_evhand(module_t mod, int event, void *arg)
+{
+        return (0);
+}
+static moduledata_t mlxen_mod = {
+        .name = "mlxen",
+	.evhand = mlxen_evhand,
+};
+DECLARE_MODULE(mlxen, mlxen_mod, SI_SUB_KLD, SI_ORDER_ANY);
+MODULE_DEPEND(mlxen, mlx4, 1, 1, 1);

Modified: projects/ofed/head/sys/ofed/drivers/net/mlx4/en_netdev.c
==============================================================================
--- projects/ofed/head/sys/ofed/drivers/net/mlx4/en_netdev.c	Mon Mar 14 23:09:15 2011	(r219649)
+++ projects/ofed/head/sys/ofed/drivers/net/mlx4/en_netdev.c	Mon Mar 14 23:13:01 2011	(r219650)
@@ -31,85 +31,62 @@
  *
  */
 
-#include <linux/etherdevice.h>
-#include <linux/tcp.h>
-#include <linux/if_vlan.h>
-#include <linux/delay.h>
+#include "mlx4_en.h"
 
 #include <linux/mlx4/driver.h>
 #include <linux/mlx4/device.h>
 #include <linux/mlx4/cmd.h>
 #include <linux/mlx4/cq.h>
 
-#include "mlx4_en.h"
-#include "en_port.h"
-
-
-static void mlx4_en_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
-{
-	struct mlx4_en_priv *priv = netdev_priv(dev);
-
-	en_dbg(HW, priv, "Registering VLAN group:%p\n", grp);
+#include <linux/delay.h>
+#include <net/ethernet.h>
+#include <net/if_vlan_var.h>
+#include <sys/sockio.h>
 
-	spin_lock_bh(&priv->vlan_lock);
-	priv->vlgrp = grp;
-	priv->vlgrp_modified = true;
-	spin_unlock_bh(&priv->vlan_lock);
-}
+static void mlx4_en_sysctl_stat(struct mlx4_en_priv *priv);
 
-static void mlx4_en_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
+static void mlx4_en_vlan_rx_add_vid(void *arg, struct net_device *dev, u16 vid)
 {
 	struct mlx4_en_priv *priv = netdev_priv(dev);
 	int idx;
 	u8 field;
-#ifndef HAVE_NETDEV_VLAN_FEATURES
-	struct net_device *vdev;
-#endif
 
-	if (!priv->vlgrp)
+	if ((vid == 0) || (vid > 4095))    /* Invalid */
 		return;
 
-	en_dbg(HW, priv, "adding VLAN:%d (vlgrp entry:%p)\n",
-	       vid, vlan_group_get_device(priv->vlgrp, vid));
+	en_dbg(HW, priv, "adding VLAN:%d\n", vid);
 
-	spin_lock_bh(&priv->vlan_lock);
+	spin_lock(&priv->vlan_lock);
 	priv->vlgrp_modified = true;
-	idx = vid >> 3;
-	field = 1 << (vid & 0x7);
+	idx = vid >> 5;
+	field = 1 << (vid & 0x1f);
 	if (priv->vlan_unregister[idx] & field)
 		priv->vlan_unregister[idx] &= ~field;
 	else
 		priv->vlan_register[idx] |= field;
-	spin_unlock_bh(&priv->vlan_lock);
-#ifndef HAVE_NETDEV_VLAN_FEATURES
-	vdev = vlan_group_get_device(priv->vlgrp, vid);
-	vdev->features |= dev->features;
-	vdev->features |= NETIF_F_LLTX;
-	vlan_group_set_device(priv->vlgrp, vid, vdev);
-#endif
+	priv->vlans[idx] |= field;
+	spin_unlock(&priv->vlan_lock);
 }
 
-static void mlx4_en_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+static void mlx4_en_vlan_rx_kill_vid(void *arg, struct net_device *dev, u16 vid)
 {
 	struct mlx4_en_priv *priv = netdev_priv(dev);
 	int idx;
 	u8 field;
 
-	if (!priv->vlgrp)
+	if ((vid == 0) || (vid > 4095))    /* Invalid */
 		return;
-
-	en_dbg(HW, priv, "Killing VID:%d (vlgrp:%p vlgrp entry:%p)\n",
-	       vid, priv->vlgrp, vlan_group_get_device(priv->vlgrp, vid));
-	spin_lock_bh(&priv->vlan_lock);
+	en_dbg(HW, priv, "Killing VID:%d\n", vid);
+	spin_lock(&priv->vlan_lock);
 	priv->vlgrp_modified = true;
-	vlan_group_set_device(priv->vlgrp, vid, NULL);
-	idx = vid >> 3;
-	field = 1 << (vid & 0x7);
+	idx = vid >> 5;
+	field = 1 << (vid & 0x1f);
 	if (priv->vlan_register[idx] & field)
 		priv->vlan_register[idx] &= ~field;
 	else
 		priv->vlan_unregister[idx] |= field;
-	spin_unlock_bh(&priv->vlan_lock);
+	priv->vlans[idx] &= ~field;
+	spin_unlock(&priv->vlan_lock);
 }
 
 u64 mlx4_en_mac_to_u64(u8 *addr)
@@ -117,86 +94,58 @@ u64 mlx4_en_mac_to_u64(u8 *addr)
 	u64 mac = 0;
 	int i;
 
-	for (i = 0; i < ETH_ALEN; i++) {
+	for (i = 0; i < ETHER_ADDR_LEN; i++) {
 		mac <<= 8;
 		mac |= addr[i];
 	}
 	return mac;
 }
 
-static int mlx4_en_set_mac(struct net_device *dev, void *addr)
-{
-	struct mlx4_en_priv *priv = netdev_priv(dev);
-	struct mlx4_en_dev *mdev = priv->mdev;
-	struct sockaddr *saddr = addr;
-
-	if (!is_valid_ether_addr(saddr->sa_data))
-		return -EADDRNOTAVAIL;
-
-	memcpy(dev->dev_addr, saddr->sa_data, ETH_ALEN);
-	priv->mac = mlx4_en_mac_to_u64(dev->dev_addr);
-	queue_work(mdev->workqueue, &priv->mac_task);
-	return 0;
-}
-
-static void mlx4_en_do_set_mac(struct work_struct *work)
-{
-	struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv,
-						 mac_task);
-	struct mlx4_en_dev *mdev = priv->mdev;
-	int err = 0;
-
-	mutex_lock(&mdev->state_lock);
-	if (priv->port_up) {
-		/* Remove old MAC and insert the new one */
-		mlx4_unregister_mac(mdev->dev, priv->port, priv->mac_index);
-		err = mlx4_register_mac(mdev->dev, priv->port,
-					priv->mac, &priv->mac_index);
-		if (err)
-			en_err(priv, "Failed changing HW MAC address\n");
-	} else
-		en_dbg(HW, priv, "Port is down while "
-				 "registering mac, exiting...\n");
-
-	mutex_unlock(&mdev->state_lock);
-}
-
-static void mlx4_en_clear_list(struct net_device *dev)
+static int mlx4_en_cache_mclist(struct net_device *dev, u64 **mcaddrp)
 {
-	struct mlx4_en_priv *priv = netdev_priv(dev);
-	struct dev_mc_list *plist = priv->mc_list;
-	struct dev_mc_list *next;
-
-	while (plist) {
-		next = plist->next;
-		kfree(plist);
-		plist = next;
-	}
-	priv->mc_list = NULL;
-}
+	struct ifmultiaddr *ifma;;
+	u64 *mcaddr;
+	int cnt;
+	int i;
 
-static void mlx4_en_cache_mclist(struct net_device *dev)
-{
-	struct mlx4_en_priv *priv = netdev_priv(dev);
-	struct dev_mc_list *mclist;
-	struct dev_mc_list *tmp;
-	struct dev_mc_list *plist = NULL;
-
-	for (mclist = dev->mc_list; mclist; mclist = mclist->next) {
-		tmp = kmalloc(sizeof(struct dev_mc_list), GFP_ATOMIC);
-		if (!tmp) {
-			en_err(priv, "failed to allocate multicast list\n");
-			mlx4_en_clear_list(dev);
-			return;
+	*mcaddrp = NULL;
+restart:
+	cnt = 0;
+	if_maddr_rlock(dev);
+	TAILQ_FOREACH(ifma, &dev->if_multiaddrs, ifma_link) {
+		if (ifma->ifma_addr->sa_family != AF_LINK)
+			continue;
+		if (((struct sockaddr_dl *)ifma->ifma_addr)->sdl_alen !=
+		    ETHER_ADDR_LEN)
+			continue;
+		cnt++;
+	}
+	if_maddr_runlock(dev);
+	if (cnt == 0)
+		return (0);
+	mcaddr = kmalloc(sizeof(u64) * cnt, GFP_KERNEL);
+	if (mcaddr == NULL)
+		return (0);
+	i = 0;
+	if_maddr_rlock(dev);
+	TAILQ_FOREACH(ifma, &dev->if_multiaddrs, ifma_link) {
+		if (ifma->ifma_addr->sa_family != AF_LINK)
+			continue;
+		if (((struct sockaddr_dl *)ifma->ifma_addr)->sdl_alen !=
+		    ETHER_ADDR_LEN)
+			continue;
+		/* Make sure the list didn't grow. */
+		if (i == cnt) {
+			if_maddr_runlock(dev);
+			kfree(mcaddr);
+			goto restart;
 		}
-		memcpy(tmp, mclist, sizeof(struct dev_mc_list));
-		tmp->next = NULL;
-		if (plist)
-			plist->next = tmp;
-		else
-			priv->mc_list = tmp;
-		plist = tmp;
+		mcaddr[i++] = mlx4_en_mac_to_u64(
+		    LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
 	}
+	if_maddr_runlock(dev);
+	*mcaddrp = mcaddr;
+	return (i);
 }
 
 
@@ -214,10 +163,8 @@ static void mlx4_en_do_set_multicast(str
 {
 	struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv,
 						 mcast_task);
-	struct mlx4_en_dev *mdev = priv->mdev;
 	struct net_device *dev = priv->dev;
-	struct dev_mc_list *mclist;
-	u64 mcast_addr = 0;
+	struct mlx4_en_dev *mdev = priv->mdev;
 	int err;
 
 	mutex_lock(&mdev->state_lock);
@@ -236,10 +183,8 @@ static void mlx4_en_do_set_multicast(str
 	 * Promsicuous mode: disable all filters
 	 */
 
-	if (dev->flags & IFF_PROMISC) {
+	if (dev->if_flags & IFF_PROMISC) {
 		if (!(priv->flags & MLX4_EN_FLAG_PROMISC)) {
-			if (netif_msg_rx_status(priv))
-				en_warn(priv, "Entering promiscuous mode\n");
 			priv->flags |= MLX4_EN_FLAG_PROMISC;
 
 			/* Enable promiscouos mode */
@@ -269,8 +214,6 @@ static void mlx4_en_do_set_multicast(str
 	 */
 
 	if (priv->flags & MLX4_EN_FLAG_PROMISC) {
-		if (netif_msg_rx_status(priv))
-			en_warn(priv, "Leaving promiscuous mode\n");
 		priv->flags &= ~MLX4_EN_FLAG_PROMISC;
 
 		/* Disable promiscouos mode */
@@ -280,18 +223,22 @@ static void mlx4_en_do_set_multicast(str
 			en_err(priv, "Failed disabling promiscous mode\n");
 
 		/* Enable port VLAN filter */
-		err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, priv->vlgrp);
+		err = mlx4_SET_VLAN_FLTR(mdev->dev, priv->port, priv->vlans);
 		if (err)
 			en_err(priv, "Failed enabling VLAN filter\n");
 	}
 
 	/* Enable/disable the multicast filter according to IFF_ALLMULTI */
-	if (dev->flags & IFF_ALLMULTI) {
+	if (dev->if_flags & IFF_ALLMULTI) {
 		err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0,
 					  0, MLX4_MCAST_DISABLE);
 		if (err)
 			en_err(priv, "Failed disabling multicast filter\n");
 	} else {
+		u64 *mcaddr;
+		int mccount;
+		int i;
+
 		err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0,
 					  0, MLX4_MCAST_DISABLE);
 		if (err)
@@ -303,20 +250,16 @@ static void mlx4_en_do_set_multicast(str
 
 		/* Update multicast list - we cache all addresses so they won't
 		 * change while HW is updated holding the command semaphor */
-		netif_tx_lock_bh(dev);
-		mlx4_en_cache_mclist(dev);
-		netif_tx_unlock_bh(dev);
-		for (mclist = priv->mc_list; mclist; mclist = mclist->next) {
-			mcast_addr = mlx4_en_mac_to_u64(mclist->dmi_addr);
+		mccount = mlx4_en_cache_mclist(dev, &mcaddr);
+		for (i = 0; i < mccount; i++)
 			mlx4_SET_MCAST_FLTR(mdev->dev, priv->port,
-					    mcast_addr, 0, MLX4_MCAST_CONFIG);
-		}
+					    mcaddr[i], 0, MLX4_MCAST_CONFIG);
 		err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0,
 					  0, MLX4_MCAST_ENABLE);
 		if (err)
 			en_err(priv, "Failed enabling multicast filter\n");
 
-		mlx4_en_clear_list(dev);
+		kfree(mcaddr);
 	}
 out:
 	mutex_unlock(&mdev->state_lock);
@@ -337,37 +280,26 @@ static void mlx4_en_netpoll(struct net_d
 		if (priv->rx_ring[i].use_frags)
 			mlx4_en_process_rx_cq(dev, cq, 0);
 		else
-			mlx4_en_process_rx_cq_skb(dev, cq, 0);
+			mlx4_en_process_rx_cq_mb(dev, cq, 0);
 		spin_unlock_irqrestore(&cq->lock, flags);
 	}
 }
 #endif
 
-static void mlx4_en_tx_timeout(struct net_device *dev)
+static void mlx4_en_watchdog_timeout(void *arg)
 {
-	struct mlx4_en_priv *priv = netdev_priv(dev);
+	struct mlx4_en_priv *priv = arg;
 	struct mlx4_en_dev *mdev = priv->mdev;
 
-	if (netif_msg_timer(priv))
-		en_warn(priv, "Tx timeout called on port:%d\n", priv->port);
-
-	priv->port_stats.tx_timeout++;
 	en_dbg(DRV, priv, "Scheduling watchdog\n");
 	queue_work(mdev->workqueue, &priv->watchdog_task);
+	if (priv->port_up)
+		callout_reset(&priv->watchdog_timer, MLX4_EN_WATCHDOG_TIMEOUT,
+		    mlx4_en_watchdog_timeout, priv);
 }
 
 
-static struct net_device_stats *mlx4_en_get_stats(struct net_device *dev)
-{
-	struct mlx4_en_priv *priv = netdev_priv(dev);
-
-	spin_lock_bh(&priv->stats_lock);
-	memcpy(&priv->ret_stats, &priv->stats, sizeof(priv->stats));
-	spin_unlock_bh(&priv->stats_lock);
-
-	return &priv->ret_stats;
-}
-
+/* XXX This clears user settings in too many cases. */
 static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv)
 {
 	struct mlx4_en_cq *cq;
@@ -379,11 +311,11 @@ static void mlx4_en_set_default_moderati
 	 *   satisfy our coelsing target.
 	 * - moder_time is set to a fixed value.
 	 */
-	priv->rx_frames = MLX4_EN_RX_COAL_TARGET / priv->dev->mtu + 1;
+	priv->rx_frames = MLX4_EN_RX_COAL_TARGET / priv->dev->if_mtu + 1;
 	priv->rx_usecs = MLX4_EN_RX_COAL_TIME;
-	en_dbg(INTR, priv, "Default coalesing params for mtu:%d - "
+	en_dbg(INTR, priv, "Default coalesing params for mtu:%ld - "
 			   "rx_frames:%d rx_usecs:%d\n",
-		 priv->dev->mtu, priv->rx_frames, priv->rx_usecs);
+		 priv->dev->if_mtu, priv->rx_frames, priv->rx_usecs);
 
 	/* Setup cq moderation params */
 	for (i = 0; i < priv->rx_ring_num; i++) {
@@ -430,11 +362,11 @@ static void mlx4_en_auto_moderation(stru
 	if (!priv->adaptive_rx_coal || period < priv->sample_interval * HZ)
 		return;
 
-	spin_lock_bh(&priv->stats_lock);
-	rx_packets = priv->stats.rx_packets;
-	rx_bytes = priv->stats.rx_bytes;
-	tx_packets = priv->stats.tx_packets;
-	spin_unlock_bh(&priv->stats_lock);
+	spin_lock(&priv->stats_lock);
+	rx_packets = priv->dev->if_ipackets;
+	rx_bytes = priv->dev->if_ibytes;
+	tx_packets = priv->dev->if_opackets;
+	spin_unlock(&priv->stats_lock);
 
 	if (!priv->last_moder_jiffies || !period)
 		goto out;
@@ -505,32 +437,32 @@ out:
 
 static void mlx4_en_handle_vlans(struct mlx4_en_priv *priv)
 {
-	u8 vlan_register[MLX4_VLREG_SIZE];
-	u8 vlan_unregister[MLX4_VLREG_SIZE];
+	u8 vlan_register[VLAN_FLTR_SIZE];
+	u8 vlan_unregister[VLAN_FLTR_SIZE];
 	int i, j, idx;
 	u16 vid;
 
 	/* cache the vlan data for processing 
 	 * done under lock to avoid changes during work */
-	spin_lock_bh(&priv->vlan_lock);
-	for (i = 0; i < MLX4_VLREG_SIZE; i++) {
+	spin_lock(&priv->vlan_lock);
+	for (i = 0; i < VLAN_FLTR_SIZE; i++) {
 		vlan_register[i] = priv->vlan_register[i];
 		priv->vlan_register[i] = 0;
 		vlan_unregister[i] = priv->vlan_unregister[i];
 		priv->vlan_unregister[i] = 0;
 	}
 	priv->vlgrp_modified = false;
-	spin_unlock_bh(&priv->vlan_lock);
+	spin_unlock(&priv->vlan_lock);
 
 	/* Configure the vlan filter 
 	 * The vlgrp is updated with all the vids that need to be allowed */
-	if (mlx4_SET_VLAN_FLTR(priv->mdev->dev, priv->port, priv->vlgrp))
+	if (mlx4_SET_VLAN_FLTR(priv->mdev->dev, priv->port, priv->vlans))
 		en_err(priv, "Failed configuring VLAN filter\n");
 
 	/* Configure the VLAN table */
-	for (i = 0; i < MLX4_VLREG_SIZE; i++) {
-		for (j = 0; j < 8; j++) {
-			vid = (i << 3) + j;
+	for (i = 0; i < VLAN_FLTR_SIZE; i++) {
+		for (j = 0; j < 32; j++) {
+			vid = (i << 5) + j;
 			if (vlan_register[i] & (1 << j))
 				if (mlx4_register_vlan(priv->mdev->dev, priv->port, vid, &idx))
 					en_dbg(HW, priv, "failed registering vlan %d\n", vid);
@@ -569,7 +501,8 @@ static void mlx4_en_do_get_stats(struct 
 		queue_delayed_work(mdev->workqueue, &priv->stats_task, STATS_DELAY);
 	}
 	if (mdev->mac_removed[MLX4_MAX_PORTS + 1 - priv->port]) {
-		queue_work(mdev->workqueue, &priv->mac_task);
+		panic("mlx4_en_do_get_stats: Unexpected mac removed for %d\n",
+		    priv->port);
 		mdev->mac_removed[MLX4_MAX_PORTS + 1 - priv->port] = 0;
 	}
 	mutex_unlock(&mdev->state_lock);
@@ -587,11 +520,10 @@ static void mlx4_en_linkstate(struct wor
 	 * report to system log */
 	if (priv->last_link_state != linkstate) {
 		if (linkstate == MLX4_DEV_EVENT_PORT_DOWN) {
-			en_info(priv, "Link Down\n");
-			netif_carrier_off(priv->dev);
+			if_link_state_change(priv->dev, LINK_STATE_DOWN);
 		} else {
 			en_info(priv, "Link Up\n");
-			netif_carrier_on(priv->dev);
+			if_link_state_change(priv->dev, LINK_STATE_UP);
 		}
 	}
 	priv->last_link_state = linkstate;
@@ -617,9 +549,9 @@ int mlx4_en_start_port(struct net_device
 	}
 
 	/* Calculate Rx buf size */
-	dev->mtu = min(dev->mtu, priv->max_mtu);
+	dev->if_mtu = min(dev->if_mtu, priv->max_mtu);
 	mlx4_en_calc_rx_buf(dev);
-	en_dbg(DRV, priv, "Rx buf size:%d\n", priv->rx_skb_size);
+	en_dbg(DRV, priv, "Rx buf size:%d\n", priv->rx_mb_size);
 
 	/* Configure rx cq's and rings */
 	err = mlx4_en_activate_rx_rings(priv);
@@ -689,7 +621,7 @@ int mlx4_en_start_port(struct net_device
 
 	/* Configure port */
 	err = mlx4_SET_PORT_general(mdev->dev, priv->port,
-				    priv->rx_skb_size + ETH_FCS_LEN,
+				    priv->rx_mb_size + ETHER_CRC_LEN,
 				    priv->prof->tx_pause,
 				    priv->prof->tx_ppp,
 				    priv->prof->rx_pause,
@@ -708,7 +640,8 @@ int mlx4_en_start_port(struct net_device
 	/* Set port mac number */
 	en_dbg(DRV, priv, "Setting mac for port %d\n", priv->port);
 	err = mlx4_register_mac(mdev->dev, priv->port,
-				priv->mac, &priv->mac_index);
+				mlx4_en_mac_to_u64(IF_LLADDR(dev)),
+				&priv->mac_index);
 	if (err) {
 		en_err(priv, "Failed setting port mac\n");
 		goto tx_err;
@@ -723,11 +656,29 @@ int mlx4_en_start_port(struct net_device
 		goto mac_err;
 	}
 
-	/* Schedule multicast task to populate multicast list */
-	queue_work(mdev->workqueue, &priv->mcast_task);
+	/* Set the various hardware offload abilities */
+	dev->if_hwassist = 0;
+	if (dev->if_capenable & IFCAP_TSO4)
+		dev->if_hwassist |= CSUM_TSO;
+	if (dev->if_capenable & IFCAP_TXCSUM)
+		dev->if_hwassist |= (CSUM_TCP | CSUM_UDP | CSUM_IP);
+	if (dev->if_capenable & IFCAP_RXCSUM)
+		priv->rx_csum = 1;
+	else
+		priv->rx_csum = 0;
 
 	priv->port_up = true;
-	netif_tx_start_all_queues(dev);
+
+	/* Populate multicast list */
+	mlx4_en_set_multicast(dev);
+
+	/* Enable the queues. */
+	atomic_clear_int(&dev->if_drv_flags, IFF_DRV_OACTIVE);
+	atomic_set_int(&dev->if_drv_flags, IFF_DRV_RUNNING);
+
+	callout_reset(&priv->watchdog_timer, MLX4_EN_WATCHDOG_TIMEOUT,
+	    mlx4_en_watchdog_timeout, priv);
+
 	return 0;
 
 mac_err:
@@ -760,11 +711,6 @@ void mlx4_en_stop_port(struct net_device
 		return;
 	}
 
-	/* Synchronize with tx routine */
-	netif_tx_lock_bh(dev);
-	netif_tx_stop_all_queues(dev);
-	netif_tx_unlock_bh(dev);
-
 	/* Set port as not active */
 	priv->port_up = false;
 
@@ -788,13 +734,15 @@ void mlx4_en_stop_port(struct net_device
 	/* Free RX Rings */
 	for (i = 0; i < priv->rx_ring_num; i++) {
 		mlx4_en_deactivate_rx_ring(priv, &priv->rx_ring[i]);
-		while (test_bit(NAPI_STATE_SCHED, &priv->rx_cq[i].napi.state))
-			msleep(1);
 		mlx4_en_deactivate_cq(priv, &priv->rx_cq[i]);
 	}
 
 	/* close port*/
 	mlx4_CLOSE_PORT(mdev->dev, priv->port);
+
+	callout_stop(&priv->watchdog_timer);
+
+	atomic_clear_int(&dev->if_drv_flags, IFF_DRV_RUNNING);
 }
 
 static void mlx4_en_restart(struct work_struct *work)
@@ -803,7 +751,21 @@ static void mlx4_en_restart(struct work_
 						 watchdog_task);
 	struct mlx4_en_dev *mdev = priv->mdev;
 	struct net_device *dev = priv->dev;
+	struct mlx4_en_tx_ring *ring;
+	int i;
+
+	if (priv->blocked == 0 || priv->port_up == 0)
+		return;
+	for (i = 0; i < priv->tx_ring_num; i++) {
+		ring = &priv->tx_ring[i];
+		if (ring->blocked &&
+		    ring->watchdog_time + MLX4_EN_WATCHDOG_TIMEOUT < ticks)
+			goto reset;
+	}
+	return;
 
+reset:
+	priv->port_stats.tx_timeout++;
 	en_dbg(DRV, priv, "Watchdog task called for port %d\n", priv->port);
 
 	mutex_lock(&mdev->state_lock);
@@ -816,18 +778,23 @@ static void mlx4_en_restart(struct work_
 }
 
 
-static int mlx4_en_open(struct net_device *dev)
+static void
+mlx4_en_init(void *arg)
 {
-	struct mlx4_en_priv *priv = netdev_priv(dev);
-	struct mlx4_en_dev *mdev = priv->mdev;
+	struct mlx4_en_priv *priv;
+	struct mlx4_en_dev *mdev;
+	struct ifnet *dev;
 	int i;
-	int err = 0;
 
+	priv = arg;
+	dev = priv->dev;
+	mdev = priv->mdev;
 	mutex_lock(&mdev->state_lock);
+	if (dev->if_drv_flags & IFF_DRV_RUNNING)
+		mlx4_en_stop_port(dev);
 
 	if (!mdev->device_up) {
 		en_err(priv, "Cannot open - device down/disabled\n");
-		err = -EBUSY;
 		goto out;
 	}
 
@@ -835,7 +802,6 @@ static int mlx4_en_open(struct net_devic
 	if (mlx4_en_DUMP_ETH_STATS(mdev, priv->port, 1))
 		en_dbg(HW, priv, "Failed dumping statistics\n");
 
-	memset(&priv->stats, 0, sizeof(priv->stats));
 	memset(&priv->pstats, 0, sizeof(priv->pstats));
 
 	for (i = 0; i < priv->tx_ring_num; i++) {
@@ -848,30 +814,11 @@ static int mlx4_en_open(struct net_devic
 	}
 
 	mlx4_en_set_default_moderation(priv);
-	err = mlx4_en_start_port(dev);
-	if (err)
+	if (mlx4_en_start_port(dev))
 		en_err(priv, "Failed starting port:%d\n", priv->port);
 
 out:
 	mutex_unlock(&mdev->state_lock);
-	return err;
-}
-
-

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



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