From owner-svn-src-projects@FreeBSD.ORG Mon Mar 14 23:13:02 2011 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 2E930106566B; Mon, 14 Mar 2011 23:13:02 +0000 (UTC) (envelope-from jeff@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 1D31B8FC08; Mon, 14 Mar 2011 23:13:02 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id p2END2Xs014474; Mon, 14 Mar 2011 23:13:02 GMT (envelope-from jeff@svn.freebsd.org) Received: (from jeff@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id p2END2HI014467; Mon, 14 Mar 2011 23:13:02 GMT (envelope-from jeff@svn.freebsd.org) Message-Id: <201103142313.p2END2HI014467@svn.freebsd.org> From: Jeff Roberson Date: Mon, 14 Mar 2011 23:13:02 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r219650 - projects/ofed/head/sys/ofed/drivers/net/mlx4 X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 14 Mar 2011 23:13:02 -0000 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 #include #include -#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 -#include -#include -#include -#include - #include "mlx4_en.h" +#include +#include +#include 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 #include #include #include @@ -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 +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 -#include -#include -#include +#include "mlx4_en.h" #include #include #include #include -#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 +#include +#include +#include - 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 ***