📄 ipoib_ib.c
字号:
addr = dma_map_single(priv->ca->dma_device, skb->data, skb->len, DMA_TO_DEVICE); pci_unmap_addr_set(tx_req, mapping, addr); if (unlikely(post_send(priv, priv->tx_head & (IPOIB_TX_RING_SIZE - 1), address->ah, qpn, addr, skb->len))) { ipoib_warn(priv, "post_send failed\n"); ++priv->stats.tx_errors; dma_unmap_single(priv->ca->dma_device, addr, skb->len, DMA_TO_DEVICE); dev_kfree_skb_any(skb); } else { dev->trans_start = jiffies; address->last_send = priv->tx_head; ++priv->tx_head; if (priv->tx_head - priv->tx_tail == IPOIB_TX_RING_SIZE) { ipoib_dbg(priv, "TX ring full, stopping kernel net queue\n"); netif_stop_queue(dev); } }}static void __ipoib_reap_ah(struct net_device *dev){ struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_ah *ah, *tah; LIST_HEAD(remove_list); spin_lock_irq(&priv->lock); list_for_each_entry_safe(ah, tah, &priv->dead_ahs, list) if ((int) priv->tx_tail - (int) ah->last_send >= 0) { list_del(&ah->list); list_add_tail(&ah->list, &remove_list); } spin_unlock_irq(&priv->lock); list_for_each_entry_safe(ah, tah, &remove_list, list) { ipoib_dbg(priv, "Reaping ah %p\n", ah->ah); ib_destroy_ah(ah->ah); kfree(ah); }}void ipoib_reap_ah(void *dev_ptr){ struct net_device *dev = dev_ptr; struct ipoib_dev_priv *priv = netdev_priv(dev); __ipoib_reap_ah(dev); if (!test_bit(IPOIB_STOP_REAPER, &priv->flags)) queue_delayed_work(ipoib_workqueue, &priv->ah_reap_task, HZ);}int ipoib_ib_dev_open(struct net_device *dev){ struct ipoib_dev_priv *priv = netdev_priv(dev); int ret; ret = ipoib_init_qp(dev); if (ret) { ipoib_warn(priv, "ipoib_init_qp returned %d\n", ret); return -1; } ret = ipoib_ib_post_receives(dev); if (ret) { ipoib_warn(priv, "ipoib_ib_post_receives returned %d\n", ret); return -1; } clear_bit(IPOIB_STOP_REAPER, &priv->flags); queue_delayed_work(ipoib_workqueue, &priv->ah_reap_task, HZ); return 0;}int ipoib_ib_dev_up(struct net_device *dev){ struct ipoib_dev_priv *priv = netdev_priv(dev); set_bit(IPOIB_FLAG_OPER_UP, &priv->flags); return ipoib_mcast_start_thread(dev);}int ipoib_ib_dev_down(struct net_device *dev){ struct ipoib_dev_priv *priv = netdev_priv(dev); ipoib_dbg(priv, "downing ib_dev\n"); clear_bit(IPOIB_FLAG_OPER_UP, &priv->flags); netif_carrier_off(dev); /* Shutdown the P_Key thread if still active */ if (!test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags)) { down(&pkey_sem); set_bit(IPOIB_PKEY_STOP, &priv->flags); cancel_delayed_work(&priv->pkey_task); up(&pkey_sem); flush_workqueue(ipoib_workqueue); } ipoib_mcast_stop_thread(dev, 1); /* * Flush the multicast groups first so we stop any multicast joins. The * completion thread may have already died and we may deadlock waiting * for the completion thread to finish some multicast joins. */ ipoib_mcast_dev_flush(dev); /* Delete broadcast and local addresses since they will be recreated */ ipoib_mcast_dev_down(dev); ipoib_flush_paths(dev); return 0;}static int recvs_pending(struct net_device *dev){ struct ipoib_dev_priv *priv = netdev_priv(dev); int pending = 0; int i; for (i = 0; i < IPOIB_RX_RING_SIZE; ++i) if (priv->rx_ring[i].skb) ++pending; return pending;}int ipoib_ib_dev_stop(struct net_device *dev){ struct ipoib_dev_priv *priv = netdev_priv(dev); struct ib_qp_attr qp_attr; unsigned long begin; struct ipoib_tx_buf *tx_req; int i; /* * Move our QP to the error state and then reinitialize in * when all work requests have completed or have been flushed. */ qp_attr.qp_state = IB_QPS_ERR; if (ib_modify_qp(priv->qp, &qp_attr, IB_QP_STATE)) ipoib_warn(priv, "Failed to modify QP to ERROR state\n"); /* Wait for all sends and receives to complete */ begin = jiffies; while (priv->tx_head != priv->tx_tail || recvs_pending(dev)) { if (time_after(jiffies, begin + 5 * HZ)) { ipoib_warn(priv, "timing out; %d sends %d receives not completed\n", priv->tx_head - priv->tx_tail, recvs_pending(dev)); /* * assume the HW is wedged and just free up * all our pending work requests. */ while ((int) priv->tx_tail - (int) priv->tx_head < 0) { tx_req = &priv->tx_ring[priv->tx_tail & (IPOIB_TX_RING_SIZE - 1)]; dma_unmap_single(priv->ca->dma_device, pci_unmap_addr(tx_req, mapping), tx_req->skb->len, DMA_TO_DEVICE); dev_kfree_skb_any(tx_req->skb); ++priv->tx_tail; } for (i = 0; i < IPOIB_RX_RING_SIZE; ++i) if (priv->rx_ring[i].skb) { dma_unmap_single(priv->ca->dma_device, pci_unmap_addr(&priv->rx_ring[i], mapping), IPOIB_BUF_SIZE, DMA_FROM_DEVICE); dev_kfree_skb_any(priv->rx_ring[i].skb); priv->rx_ring[i].skb = NULL; } goto timeout; } msleep(1); } ipoib_dbg(priv, "All sends and receives done.\n");timeout: qp_attr.qp_state = IB_QPS_RESET; if (ib_modify_qp(priv->qp, &qp_attr, IB_QP_STATE)) ipoib_warn(priv, "Failed to modify QP to RESET state\n"); /* Wait for all AHs to be reaped */ set_bit(IPOIB_STOP_REAPER, &priv->flags); cancel_delayed_work(&priv->ah_reap_task); flush_workqueue(ipoib_workqueue); begin = jiffies; while (!list_empty(&priv->dead_ahs)) { __ipoib_reap_ah(dev); if (time_after(jiffies, begin + HZ)) { ipoib_warn(priv, "timing out; will leak address handles\n"); break; } msleep(1); } return 0;}int ipoib_ib_dev_init(struct net_device *dev, struct ib_device *ca, int port){ struct ipoib_dev_priv *priv = netdev_priv(dev); priv->ca = ca; priv->port = port; priv->qp = NULL; if (ipoib_transport_dev_init(dev, ca)) { printk(KERN_WARNING "%s: ipoib_transport_dev_init failed\n", ca->name); return -ENODEV; } if (dev->flags & IFF_UP) { if (ipoib_ib_dev_open(dev)) { ipoib_transport_dev_cleanup(dev); return -ENODEV; } } return 0;}void ipoib_ib_dev_flush(void *_dev){ struct net_device *dev = (struct net_device *)_dev; struct ipoib_dev_priv *priv = netdev_priv(dev), *cpriv; if (!test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)) return; ipoib_dbg(priv, "flushing\n"); ipoib_ib_dev_down(dev); /* * The device could have been brought down between the start and when * we get here, don't bring it back up if it's not configured up */ if (test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)) ipoib_ib_dev_up(dev); down(&priv->vlan_mutex); /* Flush any child interfaces too */ list_for_each_entry(cpriv, &priv->child_intfs, list) ipoib_ib_dev_flush(&cpriv->dev); up(&priv->vlan_mutex);}void ipoib_ib_dev_cleanup(struct net_device *dev){ struct ipoib_dev_priv *priv = netdev_priv(dev); ipoib_dbg(priv, "cleaning up ib_dev\n"); ipoib_mcast_stop_thread(dev, 1); /* Delete the broadcast address and the local address */ ipoib_mcast_dev_down(dev); ipoib_transport_dev_cleanup(dev);}/* * Delayed P_Key Assigment Interim Support * * The following is initial implementation of delayed P_Key assigment * mechanism. It is using the same approach implemented for the multicast * group join. The single goal of this implementation is to quickly address * Bug #2507. This implementation will probably be removed when the P_Key * change async notification is available. */static void ipoib_pkey_dev_check_presence(struct net_device *dev){ struct ipoib_dev_priv *priv = netdev_priv(dev); u16 pkey_index = 0; if (ib_find_cached_pkey(priv->ca, priv->port, priv->pkey, &pkey_index)) clear_bit(IPOIB_PKEY_ASSIGNED, &priv->flags); else set_bit(IPOIB_PKEY_ASSIGNED, &priv->flags);}void ipoib_pkey_poll(void *dev_ptr){ struct net_device *dev = dev_ptr; struct ipoib_dev_priv *priv = netdev_priv(dev); ipoib_pkey_dev_check_presence(dev); if (test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags)) ipoib_open(dev); else { down(&pkey_sem); if (!test_bit(IPOIB_PKEY_STOP, &priv->flags)) queue_delayed_work(ipoib_workqueue, &priv->pkey_task, HZ); up(&pkey_sem); }}int ipoib_pkey_dev_delay_open(struct net_device *dev){ struct ipoib_dev_priv *priv = netdev_priv(dev); /* Look for the interface pkey value in the IB Port P_Key table and */ /* set the interface pkey assigment flag */ ipoib_pkey_dev_check_presence(dev); /* P_Key value not assigned yet - start polling */ if (!test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags)) { down(&pkey_sem); clear_bit(IPOIB_PKEY_STOP, &priv->flags); queue_delayed_work(ipoib_workqueue, &priv->pkey_task, HZ); up(&pkey_sem); return 1; } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -