#include <linux/init.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
-#include <linux/kernel.h>
#include <linux/if_arp.h> /* For ARPHRD_xxx */
MODULE_DESCRIPTION("IP-over-InfiniBand net driver");
MODULE_LICENSE("Dual BSD/GPL");
-int ipoib_sendq_size __read_mostly = IPOIB_TX_RING_SIZE;
-int ipoib_recvq_size __read_mostly = IPOIB_RX_RING_SIZE;
-
-module_param_named(send_queue_size, ipoib_sendq_size, int, 0444);
-MODULE_PARM_DESC(send_queue_size, "Number of descriptors in send queue");
-module_param_named(recv_queue_size, ipoib_recvq_size, int, 0444);
-MODULE_PARM_DESC(recv_queue_size, "Number of descriptors in receive queue");
-
#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG
int ipoib_debug_level;
netif_stop_queue(dev);
- /*
- * Now flush workqueue to make sure a scheduled task doesn't
- * bring our internal state back up.
- */
- flush_workqueue(ipoib_workqueue);
-
- ipoib_ib_dev_down(dev, 1);
+ ipoib_ib_dev_down(dev);
ipoib_ib_dev_stop(dev);
if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) {
*/
if (neigh->ah)
ipoib_put_ah(neigh->ah);
-
- ipoib_neigh_free(neigh);
+ *to_ipoib_neigh(neigh->neighbour) = NULL;
+ neigh->neighbour->ops->destructor = NULL;
+ kfree(neigh);
}
spin_unlock_irqrestore(&priv->lock, flags);
struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ipoib_path *path, *tp;
LIST_HEAD(remove_list);
+ unsigned long flags;
- spin_lock_irq(&priv->lock);
+ spin_lock_irqsave(&priv->lock, flags);
list_splice(&priv->path_list, &remove_list);
INIT_LIST_HEAD(&priv->path_list);
list_for_each_entry(path, &remove_list, list)
rb_erase(&path->rb_node, &priv->path_tree);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
list_for_each_entry_safe(path, tp, &remove_list, list) {
if (path->query)
ib_sa_cancel_query(path->query_id, path->query);
- spin_unlock_irq(&priv->lock);
wait_for_completion(&path->done);
path_free(dev, path);
- spin_lock_irq(&priv->lock);
}
- spin_unlock_irq(&priv->lock);
}
static void path_rec_completion(int status,
struct ib_ah_attr av = {
.dlid = be16_to_cpu(pathrec->dlid),
.sl = pathrec->sl,
- .port_num = priv->port,
- .static_rate = pathrec->rate
+ .port_num = priv->port
};
+ int path_rate = ib_sa_rate_enum_to_int(pathrec->rate);
+
+ if (path_rate > 0 && priv->local_rate > path_rate)
+ av.static_rate = (priv->local_rate - 1) / path_rate;
+
+ ipoib_dbg(priv, "static_rate %d for local port %dX, path %dX\n",
+ av.static_rate, priv->local_rate,
+ ib_sa_rate_enum_to_int(pathrec->rate));
ah = ipoib_create_ah(dev, priv->pd, &av);
}
struct ipoib_path *path;
struct ipoib_neigh *neigh;
- neigh = ipoib_neigh_alloc(skb->dst->neighbour);
+ neigh = kmalloc(sizeof *neigh, GFP_ATOMIC);
if (!neigh) {
++priv->stats.tx_dropped;
dev_kfree_skb_any(skb);
}
skb_queue_head_init(&neigh->queue);
+ neigh->neighbour = skb->dst->neighbour;
+ *to_ipoib_neigh(skb->dst->neighbour) = neigh;
/*
* We can only be called from ipoib_start_xmit, so we're
path = path_rec_create(dev,
(union ib_gid *) (skb->dst->neighbour->ha + 4));
if (!path)
- goto err_path;
+ goto err;
__path_add(dev, path);
}
be32_to_cpup((__be32 *) skb->dst->neighbour->ha));
} else {
neigh->ah = NULL;
- __skb_queue_tail(&neigh->queue, skb);
+ if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
+ __skb_queue_tail(&neigh->queue, skb);
+ } else {
+ ++priv->stats.tx_dropped;
+ dev_kfree_skb_any(skb);
+ }
if (!path->query && path_rec_start(dev, path))
- goto err_list;
+ goto err;
}
spin_unlock(&priv->lock);
return;
-err_list:
+err:
+ *to_ipoib_neigh(skb->dst->neighbour) = NULL;
list_del(&neigh->list);
+ neigh->neighbour->ops->destructor = NULL;
+ kfree(neigh);
-err_path:
- ipoib_neigh_free(neigh);
++priv->stats.tx_dropped;
dev_kfree_skb_any(skb);
* destination address onto the front of the skb so we can
* figure out where to send the packet later.
*/
- if ((!skb->dst || !skb->dst->neighbour) && daddr) {
+ if (!skb->dst || !skb->dst->neighbour) {
struct ipoib_pseudoheader *phdr =
(struct ipoib_pseudoheader *) skb_push(skb, sizeof *phdr);
memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN);
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
- if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) {
- ipoib_dbg(priv, "IPOIB_FLAG_OPER_UP not set");
- return;
- }
-
queue_work(ipoib_workqueue, &priv->restart_task);
}
if (neigh->ah)
ah = neigh->ah;
list_del(&neigh->list);
- ipoib_neigh_free(neigh);
+ *to_ipoib_neigh(n) = NULL;
+ kfree(neigh);
}
spin_unlock_irqrestore(&priv->lock, flags);
ipoib_put_ah(ah);
}
-struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neighbour)
+static int ipoib_neigh_setup(struct neighbour *neigh)
{
- struct ipoib_neigh *neigh;
-
- neigh = kmalloc(sizeof *neigh, GFP_ATOMIC);
- if (!neigh)
- return NULL;
-
- neigh->neighbour = neighbour;
- *to_ipoib_neigh(neighbour) = neigh;
-
- return neigh;
-}
+ /*
+ * Is this kosher? I can't find anybody in the kernel that
+ * sets neigh->destructor, so we should be able to set it here
+ * without trouble.
+ */
+ neigh->ops->destructor = ipoib_neigh_destructor;
-void ipoib_neigh_free(struct ipoib_neigh *neigh)
-{
- *to_ipoib_neigh(neigh->neighbour) = NULL;
- kfree(neigh);
+ return 0;
}
static int ipoib_neigh_setup_dev(struct net_device *dev, struct neigh_parms *parms)
{
- parms->neigh_destructor = ipoib_neigh_destructor;
+ parms->neigh_setup = ipoib_neigh_setup;
return 0;
}
struct ipoib_dev_priv *priv = netdev_priv(dev);
/* Allocate RX/TX "rings" to hold queued skbs */
- priv->rx_ring = kzalloc(ipoib_recvq_size * sizeof *priv->rx_ring,
+
+ priv->rx_ring = kzalloc(IPOIB_RX_RING_SIZE * sizeof (struct ipoib_rx_buf),
GFP_KERNEL);
if (!priv->rx_ring) {
printk(KERN_WARNING "%s: failed to allocate RX ring (%d entries)\n",
- ca->name, ipoib_recvq_size);
+ ca->name, IPOIB_RX_RING_SIZE);
goto out;
}
- priv->tx_ring = kzalloc(ipoib_sendq_size * sizeof *priv->tx_ring,
+ priv->tx_ring = kzalloc(IPOIB_TX_RING_SIZE * sizeof (struct ipoib_tx_buf),
GFP_KERNEL);
if (!priv->tx_ring) {
printk(KERN_WARNING "%s: failed to allocate TX ring (%d entries)\n",
- ca->name, ipoib_sendq_size);
+ ca->name, IPOIB_TX_RING_SIZE);
goto out_rx_ring_cleanup;
}
dev->hard_header_len = IPOIB_ENCAP_LEN + INFINIBAND_ALEN;
dev->addr_len = INFINIBAND_ALEN;
dev->type = ARPHRD_INFINIBAND;
- dev->tx_queue_len = ipoib_sendq_size * 2;
+ dev->tx_queue_len = IPOIB_TX_RING_SIZE * 2;
dev->features = NETIF_F_VLAN_CHALLENGED | NETIF_F_LLTX;
/* MTU will be reset when mcast join happens */
{
int ret;
- ipoib_recvq_size = roundup_pow_of_two(ipoib_recvq_size);
- ipoib_recvq_size = min(ipoib_recvq_size, IPOIB_MAX_QUEUE_SIZE);
- ipoib_recvq_size = max(ipoib_recvq_size, IPOIB_MIN_QUEUE_SIZE);
-
- ipoib_sendq_size = roundup_pow_of_two(ipoib_sendq_size);
- ipoib_sendq_size = min(ipoib_sendq_size, IPOIB_MAX_QUEUE_SIZE);
- ipoib_sendq_size = max(ipoib_sendq_size, IPOIB_MIN_QUEUE_SIZE);
-
ret = ipoib_register_debugfs();
if (ret)
return ret;