|
@@ -55,6 +55,21 @@
|
|
|
|
|
|
#define OCRDMA_VID_PCP_SHIFT 0xD
|
|
|
|
|
|
+static u16 ocrdma_hdr_type_to_proto_num(int devid, u8 hdr_type)
|
|
|
+{
|
|
|
+ switch (hdr_type) {
|
|
|
+ case OCRDMA_L3_TYPE_IB_GRH:
|
|
|
+ return (u16)0x8915;
|
|
|
+ case OCRDMA_L3_TYPE_IPV4:
|
|
|
+ return (u16)0x0800;
|
|
|
+ case OCRDMA_L3_TYPE_IPV6:
|
|
|
+ return (u16)0x86dd;
|
|
|
+ default:
|
|
|
+ pr_err("ocrdma%d: Invalid network header\n", devid);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static inline int set_av_attr(struct ocrdma_dev *dev, struct ocrdma_ah *ah,
|
|
|
struct ib_ah_attr *attr, union ib_gid *sgid,
|
|
|
int pdid, bool *isvlan, u16 vlan_tag)
|
|
@@ -63,10 +78,23 @@ static inline int set_av_attr(struct ocrdma_dev *dev, struct ocrdma_ah *ah,
|
|
|
struct ocrdma_eth_vlan eth;
|
|
|
struct ocrdma_grh grh;
|
|
|
int eth_sz;
|
|
|
+ u16 proto_num = 0;
|
|
|
+ u8 nxthdr = 0x11;
|
|
|
+ struct iphdr ipv4;
|
|
|
+ union {
|
|
|
+ struct sockaddr _sockaddr;
|
|
|
+ struct sockaddr_in _sockaddr_in;
|
|
|
+ struct sockaddr_in6 _sockaddr_in6;
|
|
|
+ } sgid_addr, dgid_addr;
|
|
|
|
|
|
memset(ð, 0, sizeof(eth));
|
|
|
memset(&grh, 0, sizeof(grh));
|
|
|
|
|
|
+ /* Protocol Number */
|
|
|
+ proto_num = ocrdma_hdr_type_to_proto_num(dev->id, ah->hdr_type);
|
|
|
+ if (!proto_num)
|
|
|
+ return -EINVAL;
|
|
|
+ nxthdr = (proto_num == 0x8915) ? 0x1b : 0x11;
|
|
|
/* VLAN */
|
|
|
if (!vlan_tag || (vlan_tag > 0xFFF))
|
|
|
vlan_tag = dev->pvid;
|
|
@@ -78,13 +106,13 @@ static inline int set_av_attr(struct ocrdma_dev *dev, struct ocrdma_ah *ah,
|
|
|
dev->id);
|
|
|
}
|
|
|
eth.eth_type = cpu_to_be16(0x8100);
|
|
|
- eth.roce_eth_type = cpu_to_be16(OCRDMA_ROCE_ETH_TYPE);
|
|
|
+ eth.roce_eth_type = cpu_to_be16(proto_num);
|
|
|
vlan_tag |= (dev->sl & 0x07) << OCRDMA_VID_PCP_SHIFT;
|
|
|
eth.vlan_tag = cpu_to_be16(vlan_tag);
|
|
|
eth_sz = sizeof(struct ocrdma_eth_vlan);
|
|
|
*isvlan = true;
|
|
|
} else {
|
|
|
- eth.eth_type = cpu_to_be16(OCRDMA_ROCE_ETH_TYPE);
|
|
|
+ eth.eth_type = cpu_to_be16(proto_num);
|
|
|
eth_sz = sizeof(struct ocrdma_eth_basic);
|
|
|
}
|
|
|
/* MAC */
|
|
@@ -93,18 +121,33 @@ static inline int set_av_attr(struct ocrdma_dev *dev, struct ocrdma_ah *ah,
|
|
|
if (status)
|
|
|
return status;
|
|
|
ah->sgid_index = attr->grh.sgid_index;
|
|
|
- memcpy(&grh.sgid[0], sgid->raw, sizeof(union ib_gid));
|
|
|
- memcpy(&grh.dgid[0], attr->grh.dgid.raw, sizeof(attr->grh.dgid.raw));
|
|
|
-
|
|
|
- grh.tclass_flow = cpu_to_be32((6 << 28) |
|
|
|
- (attr->grh.traffic_class << 24) |
|
|
|
- attr->grh.flow_label);
|
|
|
- /* 0x1b is next header value in GRH */
|
|
|
- grh.pdid_hoplimit = cpu_to_be32((pdid << 16) |
|
|
|
- (0x1b << 8) | attr->grh.hop_limit);
|
|
|
/* Eth HDR */
|
|
|
memcpy(&ah->av->eth_hdr, ð, eth_sz);
|
|
|
- memcpy((u8 *)ah->av + eth_sz, &grh, sizeof(struct ocrdma_grh));
|
|
|
+ if (ah->hdr_type == RDMA_NETWORK_IPV4) {
|
|
|
+ *((__be16 *)&ipv4) = htons((4 << 12) | (5 << 8) |
|
|
|
+ attr->grh.traffic_class);
|
|
|
+ ipv4.id = cpu_to_be16(pdid);
|
|
|
+ ipv4.frag_off = htons(IP_DF);
|
|
|
+ ipv4.tot_len = htons(0);
|
|
|
+ ipv4.ttl = attr->grh.hop_limit;
|
|
|
+ ipv4.protocol = nxthdr;
|
|
|
+ rdma_gid2ip(&sgid_addr._sockaddr, sgid);
|
|
|
+ ipv4.saddr = sgid_addr._sockaddr_in.sin_addr.s_addr;
|
|
|
+ rdma_gid2ip(&dgid_addr._sockaddr, &attr->grh.dgid);
|
|
|
+ ipv4.daddr = dgid_addr._sockaddr_in.sin_addr.s_addr;
|
|
|
+ memcpy((u8 *)ah->av + eth_sz, &ipv4, sizeof(struct iphdr));
|
|
|
+ } else {
|
|
|
+ memcpy(&grh.sgid[0], sgid->raw, sizeof(union ib_gid));
|
|
|
+ grh.tclass_flow = cpu_to_be32((6 << 28) |
|
|
|
+ (attr->grh.traffic_class << 24) |
|
|
|
+ attr->grh.flow_label);
|
|
|
+ memcpy(&grh.dgid[0], attr->grh.dgid.raw,
|
|
|
+ sizeof(attr->grh.dgid.raw));
|
|
|
+ grh.pdid_hoplimit = cpu_to_be32((pdid << 16) |
|
|
|
+ (nxthdr << 8) |
|
|
|
+ attr->grh.hop_limit);
|
|
|
+ memcpy((u8 *)ah->av + eth_sz, &grh, sizeof(struct ocrdma_grh));
|
|
|
+ }
|
|
|
if (*isvlan)
|
|
|
ah->av->valid |= OCRDMA_AV_VLAN_VALID;
|
|
|
ah->av->valid = cpu_to_le32(ah->av->valid);
|
|
@@ -128,6 +171,7 @@ struct ib_ah *ocrdma_create_ah(struct ib_pd *ibpd, struct ib_ah_attr *attr)
|
|
|
|
|
|
if (atomic_cmpxchg(&dev->update_sl, 1, 0))
|
|
|
ocrdma_init_service_level(dev);
|
|
|
+
|
|
|
ah = kzalloc(sizeof(*ah), GFP_ATOMIC);
|
|
|
if (!ah)
|
|
|
return ERR_PTR(-ENOMEM);
|
|
@@ -148,6 +192,8 @@ struct ib_ah *ocrdma_create_ah(struct ib_pd *ibpd, struct ib_ah_attr *attr)
|
|
|
vlan_tag = vlan_dev_vlan_id(sgid_attr.ndev);
|
|
|
dev_put(sgid_attr.ndev);
|
|
|
}
|
|
|
+ /* Get network header type for this GID */
|
|
|
+ ah->hdr_type = ib_gid_to_network_type(sgid_attr.gid_type, &sgid);
|
|
|
|
|
|
if ((pd->uctx) &&
|
|
|
(!rdma_is_multicast_addr((struct in6_addr *)attr->grh.dgid.raw)) &&
|