static inline int set_av_attr(struct ocrdma_dev *dev, struct ocrdma_ah *ah, struct ib_ah_attr *attr, int pdid) { int status = 0; u16 vlan_tag; bool vlan_enabled = false; struct ocrdma_eth_vlan eth; struct ocrdma_grh grh; int eth_sz; memset(ð, 0, sizeof(eth)); memset(&grh, 0, sizeof(grh)); ah->sgid_index = attr->grh.sgid_index; vlan_tag = attr->vlan_id; if (!vlan_tag || (vlan_tag > 0xFFF)) vlan_tag = dev->pvid; if (vlan_tag && (vlan_tag < 0x1000)) { eth.eth_type = cpu_to_be16(0x8100); eth.roce_eth_type = cpu_to_be16(OCRDMA_ROCE_ETH_TYPE); vlan_tag |= (dev->sl & 0x07) << OCRDMA_VID_PCP_SHIFT; eth.vlan_tag = cpu_to_be16(vlan_tag); eth_sz = sizeof(struct ocrdma_eth_vlan); vlan_enabled = true; } else { eth.eth_type = cpu_to_be16(OCRDMA_ROCE_ETH_TYPE); eth_sz = sizeof(struct ocrdma_eth_basic); } memcpy(ð.smac[0], &dev->nic_info.mac_addr[0], ETH_ALEN); memcpy(ð.dmac[0], attr->dmac, ETH_ALEN); status = ocrdma_resolve_dmac(dev, attr, ð.dmac[0]); if (status) return status; status = ocrdma_query_gid(&dev->ibdev, 1, attr->grh.sgid_index, (union ib_gid *)&grh.sgid[0]); if (status) return status; 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); memcpy(&grh.dgid[0], attr->grh.dgid.raw, sizeof(attr->grh.dgid.raw)); memcpy(&ah->av->eth_hdr, ð, eth_sz); memcpy((u8 *)ah->av + eth_sz, &grh, sizeof(struct ocrdma_grh)); if (vlan_enabled) ah->av->valid |= OCRDMA_AV_VLAN_VALID; ah->av->valid = cpu_to_le32(ah->av->valid); return status; }
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) { int status; 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; if (vlan_tag || dev->pfc_state) { if (!vlan_tag) { pr_err("ocrdma%d:Using VLAN with PFC is recommended\n", dev->id); pr_err("ocrdma%d:Using VLAN 0 for this connection\n", dev->id); } eth.eth_type = cpu_to_be16(0x8100); 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(proto_num); eth_sz = sizeof(struct ocrdma_eth_basic); } /* MAC */ memcpy(ð.smac[0], &dev->nic_info.mac_addr[0], ETH_ALEN); status = ocrdma_resolve_dmac(dev, attr, ð.dmac[0]); if (status) return status; ah->sgid_index = attr->grh.sgid_index; /* Eth HDR */ memcpy(&ah->av->eth_hdr, ð, eth_sz); 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); return status; }