svn commit: r219650 - projects/ofed/head/sys/ofed/drivers/net/mlx4
Jeff Roberson
jeff at FreeBSD.org
Mon Mar 14 23:13:02 UTC 2011
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 ***
More information about the svn-src-projects
mailing list