IPOIB_FLAG_UMCAST = 10,
IPOIB_STOP_NEIGH_GC = 11,
IPOIB_NEIGH_TBL_FLUSH = 12,
+ IPOIB_FLAG_CSUM = 15,
IPOIB_MAX_BACKOFF_SECONDS = 16,
struct ib_cm_id;
+/* Signature so driver can make sure ipoib_cm_data.caps is valid */
+#define IPOIB_CM_PROTO_SIG 0x2211
+/* Current driver ipoib_cm_data version */
+#define IPOIB_CM_PROTO_VER (1UL << 12)
+
+enum ipoib_cm_data_caps {
+ IPOIB_CM_CAPS_IBCRC_AS_CSUM = 1UL << 0,
+};
+
struct ipoib_cm_data {
__be32 qpn; /* High byte MUST be ignored on receive */
__be32 mtu;
+ __be16 sig; /* must be IPOIB_CM_PROTO_SIG */
+ __be16 caps; /* 4 bits proto ver and 12 bits capabilities */
};
/*
unsigned long jiffies;
enum ipoib_cm_state state;
int recv_count;
+ u16 caps;
};
struct ipoib_cm_tx {
unsigned tx_tail;
unsigned long flags;
u32 mtu;
+ u16 caps;
};
struct ipoib_cm_rx_buf {
extern struct workqueue_struct *ipoib_workqueue;
+extern int cm_ibcrc_as_csum;
+
/* functions */
+static inline int ipoib_cm_check_proto_sig(u16 proto_sig)
+{
+ return (proto_sig == IPOIB_CM_PROTO_SIG);
+}
+
+static inline int ipoib_cm_check_proto_ver(u16 caps)
+{
+ return ((caps & 0xF000) == IPOIB_CM_PROTO_VER);
+}
+
int ipoib_poll(struct napi_struct *napi, int budget);
void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr);
void ipoib_send_comp_handler(struct ib_cq *cq, void *dev_ptr);
struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ipoib_cm_data data = {};
struct ib_cm_rep_param rep = {};
+ u16 caps = 0;
+
+ caps |= IPOIB_CM_PROTO_VER;
+ if (cm_ibcrc_as_csum && test_bit(IPOIB_FLAG_CSUM, &priv->flags))
+ caps |= IPOIB_CM_CAPS_IBCRC_AS_CSUM;
data.qpn = cpu_to_be32(priv->qp->qp_num);
data.mtu = cpu_to_be32(IPOIB_CM_BUF_SIZE);
+ data.sig = cpu_to_be16(IPOIB_CM_PROTO_SIG);
+ data.caps = cpu_to_be16(caps);
rep.private_data = &data;
rep.private_data_len = sizeof data;
struct ipoib_cm_rx *p;
unsigned psn;
int ret;
+ struct ipoib_cm_data *cm_data;
ipoib_dbg(priv, "REQ arrived\n");
p = kzalloc(sizeof *p, GFP_KERNEL);
goto err_qp;
}
+ cm_data = (struct ipoib_cm_data *)event->private_data;
+ ipoib_dbg(priv, "Otherend sig=0x%x\n", be16_to_cpu(cm_data->sig));
+ if (ipoib_cm_check_proto_sig(be16_to_cpu(cm_data->sig)) &&
+ ipoib_cm_check_proto_ver(be16_to_cpu(cm_data->caps)))
+ p->caps = be16_to_cpu(cm_data->caps);
+ ipoib_dbg(priv, "Otherend caps=0x%x\n", p->caps);
+
psn = prandom_u32() & 0xffffff;
ret = ipoib_cm_modify_rx_qp(dev, cm_id, p->qp, psn);
if (ret)
skb->dev = dev;
/* XXX get correct PACKET_ type here */
skb->pkt_type = PACKET_HOST;
+
+ if (cm_ibcrc_as_csum && test_bit(IPOIB_FLAG_CSUM, &priv->flags))
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+
netif_receive_skb(skb);
repost:
tx_req = &tx->tx_ring[tx->tx_head & (ipoib_sendq_size - 1)];
tx_req->skb = skb;
+ /* Calculate checksum if we support ibcrc_as_csum but peer is not */
+ if ((skb->ip_summed == CHECKSUM_PARTIAL) && cm_ibcrc_as_csum &&
+ test_bit(IPOIB_FLAG_CSUM, &priv->flags) &&
+ !(tx->caps & IPOIB_CM_CAPS_IBCRC_AS_CSUM)) {
+ if (skb_checksum_help(skb)) {
+ ipoib_warn(priv, "Fail to csum skb\n");
+ ++dev->stats.tx_errors;
+ dev_kfree_skb_any(skb);
+ return;
+ }
+ }
+
if (skb_shinfo(skb)->nr_frags) {
if (unlikely(ipoib_dma_map_tx(priv->ca, tx_req))) {
++dev->stats.tx_errors;
struct ib_qp_attr qp_attr;
int qp_attr_mask, ret;
struct sk_buff *skb;
+ struct ipoib_cm_data *cm_data;
p->mtu = be32_to_cpu(data->mtu);
return -EINVAL;
}
+ cm_data = (struct ipoib_cm_data *)event->private_data;
+ ipoib_dbg(priv, "Otherend sig=0x%x\n", be16_to_cpu(cm_data->sig));
+ if (ipoib_cm_check_proto_sig(be16_to_cpu(cm_data->sig)) &&
+ ipoib_cm_check_proto_ver(be16_to_cpu(cm_data->caps)))
+ p->caps = be16_to_cpu(cm_data->caps);
+ ipoib_dbg(priv, "Otherend caps=0x%x\n", p->caps);
+
qp_attr.qp_state = IB_QPS_RTR;
ret = ib_cm_init_qp_attr(cm_id, &qp_attr, &qp_attr_mask);
if (ret) {
struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ipoib_cm_data data = {};
struct ib_cm_req_param req = {};
+ u16 caps = 0;
+
+ caps |= IPOIB_CM_PROTO_VER;
+ if (cm_ibcrc_as_csum && test_bit(IPOIB_FLAG_CSUM, &priv->flags))
+ caps |= IPOIB_CM_CAPS_IBCRC_AS_CSUM;
data.qpn = cpu_to_be32(priv->qp->qp_num);
data.mtu = cpu_to_be32(IPOIB_CM_BUF_SIZE);
+ data.sig = cpu_to_be16(IPOIB_CM_PROTO_SIG);
+ data.caps = cpu_to_be16(caps);
req.primary_path = pathrec;
req.alternate_path = NULL;
MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0");
#endif
+int cm_ibcrc_as_csum = 1;
+module_param_named(cm_ibcrc_as_csum, cm_ibcrc_as_csum, int, 0444);
+MODULE_PARM_DESC(cm_ibcrc_as_csum,
+ "Indicates whether to utilize IB-CRC as CSUM in connected mode,(default: 1)");
+
struct ipoib_path_iter {
struct net_device *dev;
struct ipoib_path path;
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
- if (test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags))
- features &= ~(NETIF_F_IP_CSUM | NETIF_F_TSO);
+ if (test_bit(IPOIB_FLAG_ADMIN_CM, &priv->flags)) {
+ features &= ~NETIF_F_TSO;
+ if (!(cm_ibcrc_as_csum && (test_bit(IPOIB_FLAG_CSUM,
+ &priv->flags))))
+ features &= ~(NETIF_F_IP_CSUM | NETIF_F_TSO);
+ }
return features;
}
"will cause multicast packet drops\n");
netdev_update_features(dev);
rtnl_unlock();
- priv->tx_wr.send_flags &= ~IB_SEND_IP_CSUM;
+ if (cm_ibcrc_as_csum && (test_bit(IPOIB_FLAG_CSUM,
+ &priv->flags)))
+ priv->tx_wr.send_flags |= IB_SEND_IP_CSUM;
+ else
+ priv->tx_wr.send_flags &= ~IB_SEND_IP_CSUM;
ipoib_flush_paths(dev);
kfree(device_attr);
if (priv->hca_caps & IB_DEVICE_UD_IP_CSUM) {
+ set_bit(IPOIB_FLAG_CSUM, &priv->flags);
priv->dev->hw_features = NETIF_F_SG |
NETIF_F_IP_CSUM | NETIF_F_RXCSUM;