diff options
| -rw-r--r-- | drivers/infiniband/core/Makefile | 12 | ||||
| -rw-r--r-- | drivers/infiniband/core/addr.c | 226 | ||||
| -rw-r--r-- | drivers/infiniband/core/core_priv.h | 16 | ||||
| -rw-r--r-- | drivers/infiniband/core/device.c | 58 | ||||
| -rw-r--r-- | drivers/infiniband/core/mad.c | 13 | ||||
| -rw-r--r-- | drivers/infiniband/core/multicast.c | 23 | ||||
| -rw-r--r-- | drivers/infiniband/core/sa_query.c | 211 | ||||
| -rw-r--r-- | drivers/infiniband/hw/qib/qib_mad.c | 6 | ||||
| -rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib.h | 4 | ||||
| -rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_ib.c | 109 | ||||
| -rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_main.c | 140 | ||||
| -rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_multicast.c | 48 | ||||
| -rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_verbs.c | 3 | ||||
| -rw-r--r-- | drivers/infiniband/ulp/ipoib/ipoib_vlan.c | 2 | ||||
| -rw-r--r-- | drivers/infiniband/ulp/srpt/ib_srpt.c | 2 | ||||
| -rw-r--r-- | include/rdma/ib_mad.h | 60 | ||||
| -rw-r--r-- | include/rdma/ib_sa.h | 12 | ||||
| -rw-r--r-- | include/uapi/rdma/rdma_netlink.h | 10 |
18 files changed, 844 insertions, 111 deletions
diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile index 26987d9d7e1c..edaae9f9853c 100644 --- a/drivers/infiniband/core/Makefile +++ b/drivers/infiniband/core/Makefile | |||
| @@ -1,8 +1,7 @@ | |||
| 1 | infiniband-$(CONFIG_INFINIBAND_ADDR_TRANS) := rdma_cm.o | 1 | infiniband-$(CONFIG_INFINIBAND_ADDR_TRANS) := rdma_cm.o |
| 2 | user_access-$(CONFIG_INFINIBAND_ADDR_TRANS) := rdma_ucm.o | 2 | user_access-$(CONFIG_INFINIBAND_ADDR_TRANS) := rdma_ucm.o |
| 3 | 3 | ||
| 4 | obj-$(CONFIG_INFINIBAND) += ib_core.o ib_mad.o ib_sa.o \ | 4 | obj-$(CONFIG_INFINIBAND) += ib_core.o ib_cm.o iw_cm.o \ |
| 5 | ib_cm.o iw_cm.o ib_addr.o \ | ||
| 6 | $(infiniband-y) | 5 | $(infiniband-y) |
| 7 | obj-$(CONFIG_INFINIBAND_USER_MAD) += ib_umad.o | 6 | obj-$(CONFIG_INFINIBAND_USER_MAD) += ib_umad.o |
| 8 | obj-$(CONFIG_INFINIBAND_USER_ACCESS) += ib_uverbs.o ib_ucm.o \ | 7 | obj-$(CONFIG_INFINIBAND_USER_ACCESS) += ib_uverbs.o ib_ucm.o \ |
| @@ -10,14 +9,11 @@ obj-$(CONFIG_INFINIBAND_USER_ACCESS) += ib_uverbs.o ib_ucm.o \ | |||
| 10 | 9 | ||
| 11 | ib_core-y := packer.o ud_header.o verbs.o cq.o rw.o sysfs.o \ | 10 | ib_core-y := packer.o ud_header.o verbs.o cq.o rw.o sysfs.o \ |
| 12 | device.o fmr_pool.o cache.o netlink.o \ | 11 | device.o fmr_pool.o cache.o netlink.o \ |
| 13 | roce_gid_mgmt.o mr_pool.o | 12 | roce_gid_mgmt.o mr_pool.o addr.o sa_query.o \ |
| 13 | multicast.o mad.o smi.o agent.o mad_rmpp.o | ||
| 14 | ib_core-$(CONFIG_INFINIBAND_USER_MEM) += umem.o | 14 | ib_core-$(CONFIG_INFINIBAND_USER_MEM) += umem.o |
| 15 | ib_core-$(CONFIG_INFINIBAND_ON_DEMAND_PAGING) += umem_odp.o umem_rbtree.o | 15 | ib_core-$(CONFIG_INFINIBAND_ON_DEMAND_PAGING) += umem_odp.o umem_rbtree.o |
| 16 | 16 | ||
| 17 | ib_mad-y := mad.o smi.o agent.o mad_rmpp.o | ||
| 18 | |||
| 19 | ib_sa-y := sa_query.o multicast.o | ||
| 20 | |||
| 21 | ib_cm-y := cm.o | 17 | ib_cm-y := cm.o |
| 22 | 18 | ||
| 23 | iw_cm-y := iwcm.o iwpm_util.o iwpm_msg.o | 19 | iw_cm-y := iwcm.o iwpm_util.o iwpm_msg.o |
| @@ -28,8 +24,6 @@ rdma_cm-$(CONFIG_INFINIBAND_ADDR_TRANS_CONFIGFS) += cma_configfs.o | |||
| 28 | 24 | ||
| 29 | rdma_ucm-y := ucma.o | 25 | rdma_ucm-y := ucma.o |
| 30 | 26 | ||
| 31 | ib_addr-y := addr.o | ||
| 32 | |||
| 33 | ib_umad-y := user_mad.o | 27 | ib_umad-y := user_mad.o |
| 34 | 28 | ||
| 35 | ib_ucm-y := ucm.o | 29 | ib_ucm-y := ucm.o |
diff --git a/drivers/infiniband/core/addr.c b/drivers/infiniband/core/addr.c index 337353d86cfa..1374541a4528 100644 --- a/drivers/infiniband/core/addr.c +++ b/drivers/infiniband/core/addr.c | |||
| @@ -46,10 +46,10 @@ | |||
| 46 | #include <net/ip6_route.h> | 46 | #include <net/ip6_route.h> |
| 47 | #include <rdma/ib_addr.h> | 47 | #include <rdma/ib_addr.h> |
| 48 | #include <rdma/ib.h> | 48 | #include <rdma/ib.h> |
| 49 | #include <rdma/rdma_netlink.h> | ||
| 50 | #include <net/netlink.h> | ||
| 49 | 51 | ||
| 50 | MODULE_AUTHOR("Sean Hefty"); | 52 | #include "core_priv.h" |
| 51 | MODULE_DESCRIPTION("IB Address Translation"); | ||
| 52 | MODULE_LICENSE("Dual BSD/GPL"); | ||
| 53 | 53 | ||
| 54 | struct addr_req { | 54 | struct addr_req { |
| 55 | struct list_head list; | 55 | struct list_head list; |
| @@ -62,8 +62,11 @@ struct addr_req { | |||
| 62 | struct rdma_dev_addr *addr, void *context); | 62 | struct rdma_dev_addr *addr, void *context); |
| 63 | unsigned long timeout; | 63 | unsigned long timeout; |
| 64 | int status; | 64 | int status; |
| 65 | u32 seq; | ||
| 65 | }; | 66 | }; |
| 66 | 67 | ||
| 68 | static atomic_t ib_nl_addr_request_seq = ATOMIC_INIT(0); | ||
| 69 | |||
| 67 | static void process_req(struct work_struct *work); | 70 | static void process_req(struct work_struct *work); |
| 68 | 71 | ||
| 69 | static DEFINE_MUTEX(lock); | 72 | static DEFINE_MUTEX(lock); |
| @@ -71,6 +74,126 @@ static LIST_HEAD(req_list); | |||
| 71 | static DECLARE_DELAYED_WORK(work, process_req); | 74 | static DECLARE_DELAYED_WORK(work, process_req); |
| 72 | static struct workqueue_struct *addr_wq; | 75 | static struct workqueue_struct *addr_wq; |
| 73 | 76 | ||
| 77 | static const struct nla_policy ib_nl_addr_policy[LS_NLA_TYPE_MAX] = { | ||
| 78 | [LS_NLA_TYPE_DGID] = {.type = NLA_BINARY, | ||
| 79 | .len = sizeof(struct rdma_nla_ls_gid)}, | ||
| 80 | }; | ||
| 81 | |||
| 82 | static inline bool ib_nl_is_good_ip_resp(const struct nlmsghdr *nlh) | ||
| 83 | { | ||
| 84 | struct nlattr *tb[LS_NLA_TYPE_MAX] = {}; | ||
| 85 | int ret; | ||
| 86 | |||
| 87 | if (nlh->nlmsg_flags & RDMA_NL_LS_F_ERR) | ||
| 88 | return false; | ||
| 89 | |||
| 90 | ret = nla_parse(tb, LS_NLA_TYPE_MAX - 1, nlmsg_data(nlh), | ||
| 91 | nlmsg_len(nlh), ib_nl_addr_policy); | ||
| 92 | if (ret) | ||
| 93 | return false; | ||
| 94 | |||
| 95 | return true; | ||
| 96 | } | ||
| 97 | |||
| 98 | static void ib_nl_process_good_ip_rsep(const struct nlmsghdr *nlh) | ||
| 99 | { | ||
| 100 | const struct nlattr *head, *curr; | ||
| 101 | union ib_gid gid; | ||
| 102 | struct addr_req *req; | ||
| 103 | int len, rem; | ||
| 104 | int found = 0; | ||
| 105 | |||
| 106 | head = (const struct nlattr *)nlmsg_data(nlh); | ||
| 107 | len = nlmsg_len(nlh); | ||
| 108 | |||
| 109 | nla_for_each_attr(curr, head, len, rem) { | ||
| 110 | if (curr->nla_type == LS_NLA_TYPE_DGID) | ||
| 111 | memcpy(&gid, nla_data(curr), nla_len(curr)); | ||
| 112 | } | ||
| 113 | |||
| 114 | mutex_lock(&lock); | ||
| 115 | list_for_each_entry(req, &req_list, list) { | ||
| 116 | if (nlh->nlmsg_seq != req->seq) | ||
| 117 | continue; | ||
| 118 | /* We set the DGID part, the rest was set earlier */ | ||
| 119 | rdma_addr_set_dgid(req->addr, &gid); | ||
| 120 | req->status = 0; | ||
| 121 | found = 1; | ||
| 122 | break; | ||
| 123 | } | ||
| 124 | mutex_unlock(&lock); | ||
| 125 | |||
| 126 | if (!found) | ||
| 127 | pr_info("Couldn't find request waiting for DGID: %pI6\n", | ||
| 128 | &gid); | ||
| 129 | } | ||
| 130 | |||
| 131 | int ib_nl_handle_ip_res_resp(struct sk_buff *skb, | ||
| 132 | struct netlink_callback *cb) | ||
| 133 | { | ||
| 134 | const struct nlmsghdr *nlh = (struct nlmsghdr *)cb->nlh; | ||
| 135 | |||
| 136 | if ((nlh->nlmsg_flags & NLM_F_REQUEST) || | ||
| 137 | !(NETLINK_CB(skb).sk) || | ||
| 138 | !netlink_capable(skb, CAP_NET_ADMIN)) | ||
| 139 | return -EPERM; | ||
| 140 | |||
| 141 | if (ib_nl_is_good_ip_resp(nlh)) | ||
| 142 | ib_nl_process_good_ip_rsep(nlh); | ||
| 143 | |||
| 144 | return skb->len; | ||
| 145 | } | ||
| 146 | |||
| 147 | static int ib_nl_ip_send_msg(struct rdma_dev_addr *dev_addr, | ||
| 148 | const void *daddr, | ||
| 149 | u32 seq, u16 family) | ||
| 150 | { | ||
| 151 | struct sk_buff *skb = NULL; | ||
| 152 | struct nlmsghdr *nlh; | ||
| 153 | struct rdma_ls_ip_resolve_header *header; | ||
| 154 | void *data; | ||
| 155 | size_t size; | ||
| 156 | int attrtype; | ||
| 157 | int len; | ||
| 158 | |||
| 159 | if (family == AF_INET) { | ||
| 160 | size = sizeof(struct in_addr); | ||
| 161 | attrtype = RDMA_NLA_F_MANDATORY | LS_NLA_TYPE_IPV4; | ||
| 162 | } else { | ||
| 163 | size = sizeof(struct in6_addr); | ||
| 164 | attrtype = RDMA_NLA_F_MANDATORY | LS_NLA_TYPE_IPV6; | ||
| 165 | } | ||
| 166 | |||
| 167 | len = nla_total_size(sizeof(size)); | ||
| 168 | len += NLMSG_ALIGN(sizeof(*header)); | ||
| 169 | |||
| 170 | skb = nlmsg_new(len, GFP_KERNEL); | ||
| 171 | if (!skb) | ||
| 172 | return -ENOMEM; | ||
| 173 | |||
| 174 | data = ibnl_put_msg(skb, &nlh, seq, 0, RDMA_NL_LS, | ||
| 175 | RDMA_NL_LS_OP_IP_RESOLVE, NLM_F_REQUEST); | ||
| 176 | if (!data) { | ||
| 177 | nlmsg_free(skb); | ||
| 178 | return -ENODATA; | ||
| 179 | } | ||
| 180 | |||
| 181 | /* Construct the family header first */ | ||
| 182 | header = (struct rdma_ls_ip_resolve_header *) | ||
| 183 | skb_put(skb, NLMSG_ALIGN(sizeof(*header))); | ||
| 184 | header->ifindex = dev_addr->bound_dev_if; | ||
| 185 | nla_put(skb, attrtype, size, daddr); | ||
| 186 | |||
| 187 | /* Repair the nlmsg header length */ | ||
| 188 | nlmsg_end(skb, nlh); | ||
| 189 | ibnl_multicast(skb, nlh, RDMA_NL_GROUP_LS, GFP_KERNEL); | ||
| 190 | |||
| 191 | /* Make the request retry, so when we get the response from userspace | ||
| 192 | * we will have something. | ||
| 193 | */ | ||
| 194 | return -ENODATA; | ||
| 195 | } | ||
| 196 | |||
| 74 | int rdma_addr_size(struct sockaddr *addr) | 197 | int rdma_addr_size(struct sockaddr *addr) |
| 75 | { | 198 | { |
| 76 | switch (addr->sa_family) { | 199 | switch (addr->sa_family) { |
| @@ -199,6 +322,17 @@ static void queue_req(struct addr_req *req) | |||
| 199 | mutex_unlock(&lock); | 322 | mutex_unlock(&lock); |
| 200 | } | 323 | } |
| 201 | 324 | ||
| 325 | static int ib_nl_fetch_ha(struct dst_entry *dst, struct rdma_dev_addr *dev_addr, | ||
| 326 | const void *daddr, u32 seq, u16 family) | ||
| 327 | { | ||
| 328 | if (ibnl_chk_listeners(RDMA_NL_GROUP_LS)) | ||
| 329 | return -EADDRNOTAVAIL; | ||
| 330 | |||
| 331 | /* We fill in what we can, the response will fill the rest */ | ||
| 332 | rdma_copy_addr(dev_addr, dst->dev, NULL); | ||
| 333 | return ib_nl_ip_send_msg(dev_addr, daddr, seq, family); | ||
| 334 | } | ||
| 335 | |||
| 202 | static int dst_fetch_ha(struct dst_entry *dst, struct rdma_dev_addr *dev_addr, | 336 | static int dst_fetch_ha(struct dst_entry *dst, struct rdma_dev_addr *dev_addr, |
| 203 | const void *daddr) | 337 | const void *daddr) |
| 204 | { | 338 | { |
| @@ -223,6 +357,39 @@ static int dst_fetch_ha(struct dst_entry *dst, struct rdma_dev_addr *dev_addr, | |||
| 223 | return ret; | 357 | return ret; |
| 224 | } | 358 | } |
| 225 | 359 | ||
| 360 | static bool has_gateway(struct dst_entry *dst, sa_family_t family) | ||
| 361 | { | ||
| 362 | struct rtable *rt; | ||
| 363 | struct rt6_info *rt6; | ||
| 364 | |||
| 365 | if (family == AF_INET) { | ||
| 366 | rt = container_of(dst, struct rtable, dst); | ||
| 367 | return rt->rt_uses_gateway; | ||
| 368 | } | ||
| 369 | |||
| 370 | rt6 = container_of(dst, struct rt6_info, dst); | ||
| 371 | return rt6->rt6i_flags & RTF_GATEWAY; | ||
| 372 | } | ||
| 373 | |||
| 374 | static int fetch_ha(struct dst_entry *dst, struct rdma_dev_addr *dev_addr, | ||
| 375 | const struct sockaddr *dst_in, u32 seq) | ||
| 376 | { | ||
| 377 | const struct sockaddr_in *dst_in4 = | ||
| 378 | (const struct sockaddr_in *)dst_in; | ||
| 379 | const struct sockaddr_in6 *dst_in6 = | ||
| 380 | (const struct sockaddr_in6 *)dst_in; | ||
| 381 | const void *daddr = (dst_in->sa_family == AF_INET) ? | ||
| 382 | (const void *)&dst_in4->sin_addr.s_addr : | ||
| 383 | (const void *)&dst_in6->sin6_addr; | ||
| 384 | sa_family_t family = dst_in->sa_family; | ||
| 385 | |||
| 386 | /* Gateway + ARPHRD_INFINIBAND -> IB router */ | ||
| 387 | if (has_gateway(dst, family) && dst->dev->type == ARPHRD_INFINIBAND) | ||
| 388 | return ib_nl_fetch_ha(dst, dev_addr, daddr, seq, family); | ||
| 389 | else | ||
| 390 | return dst_fetch_ha(dst, dev_addr, daddr); | ||
| 391 | } | ||
| 392 | |||
| 226 | static int addr4_resolve(struct sockaddr_in *src_in, | 393 | static int addr4_resolve(struct sockaddr_in *src_in, |
| 227 | const struct sockaddr_in *dst_in, | 394 | const struct sockaddr_in *dst_in, |
| 228 | struct rdma_dev_addr *addr, | 395 | struct rdma_dev_addr *addr, |
| @@ -246,10 +413,11 @@ static int addr4_resolve(struct sockaddr_in *src_in, | |||
| 246 | src_in->sin_family = AF_INET; | 413 | src_in->sin_family = AF_INET; |
| 247 | src_in->sin_addr.s_addr = fl4.saddr; | 414 | src_in->sin_addr.s_addr = fl4.saddr; |
| 248 | 415 | ||
| 249 | /* If there's a gateway, we're definitely in RoCE v2 (as RoCE v1 isn't | 416 | /* If there's a gateway and type of device not ARPHRD_INFINIBAND, we're |
| 250 | * routable) and we could set the network type accordingly. | 417 | * definitely in RoCE v2 (as RoCE v1 isn't routable) set the network |
| 418 | * type accordingly. | ||
| 251 | */ | 419 | */ |
| 252 | if (rt->rt_uses_gateway) | 420 | if (rt->rt_uses_gateway && rt->dst.dev->type != ARPHRD_INFINIBAND) |
| 253 | addr->network = RDMA_NETWORK_IPV4; | 421 | addr->network = RDMA_NETWORK_IPV4; |
| 254 | 422 | ||
| 255 | addr->hoplimit = ip4_dst_hoplimit(&rt->dst); | 423 | addr->hoplimit = ip4_dst_hoplimit(&rt->dst); |
| @@ -291,10 +459,12 @@ static int addr6_resolve(struct sockaddr_in6 *src_in, | |||
| 291 | src_in->sin6_addr = fl6.saddr; | 459 | src_in->sin6_addr = fl6.saddr; |
| 292 | } | 460 | } |
| 293 | 461 | ||
| 294 | /* If there's a gateway, we're definitely in RoCE v2 (as RoCE v1 isn't | 462 | /* If there's a gateway and type of device not ARPHRD_INFINIBAND, we're |
| 295 | * routable) and we could set the network type accordingly. | 463 | * definitely in RoCE v2 (as RoCE v1 isn't routable) set the network |
| 464 | * type accordingly. | ||
| 296 | */ | 465 | */ |
| 297 | if (rt->rt6i_flags & RTF_GATEWAY) | 466 | if (rt->rt6i_flags & RTF_GATEWAY && |
| 467 | ip6_dst_idev(dst)->dev->type != ARPHRD_INFINIBAND) | ||
| 298 | addr->network = RDMA_NETWORK_IPV6; | 468 | addr->network = RDMA_NETWORK_IPV6; |
| 299 | 469 | ||
| 300 | addr->hoplimit = ip6_dst_hoplimit(dst); | 470 | addr->hoplimit = ip6_dst_hoplimit(dst); |
| @@ -317,7 +487,8 @@ static int addr6_resolve(struct sockaddr_in6 *src_in, | |||
| 317 | 487 | ||
| 318 | static int addr_resolve_neigh(struct dst_entry *dst, | 488 | static int addr_resolve_neigh(struct dst_entry *dst, |
| 319 | const struct sockaddr *dst_in, | 489 | const struct sockaddr *dst_in, |
| 320 | struct rdma_dev_addr *addr) | 490 | struct rdma_dev_addr *addr, |
| 491 | u32 seq) | ||
| 321 | { | 492 | { |
| 322 | if (dst->dev->flags & IFF_LOOPBACK) { | 493 | if (dst->dev->flags & IFF_LOOPBACK) { |
| 323 | int ret; | 494 | int ret; |
| @@ -331,17 +502,8 @@ static int addr_resolve_neigh(struct dst_entry *dst, | |||
| 331 | } | 502 | } |
| 332 | 503 | ||
| 333 | /* If the device doesn't do ARP internally */ | 504 | /* If the device doesn't do ARP internally */ |
| 334 | if (!(dst->dev->flags & IFF_NOARP)) { | 505 | if (!(dst->dev->flags & IFF_NOARP)) |
| 335 | const struct sockaddr_in *dst_in4 = | 506 | return fetch_ha(dst, addr, dst_in, seq); |
| 336 | (const struct sockaddr_in *)dst_in; | ||
| 337 | const struct sockaddr_in6 *dst_in6 = | ||
| 338 | (const struct sockaddr_in6 *)dst_in; | ||
| 339 | |||
| 340 | return dst_fetch_ha(dst, addr, | ||
| 341 | dst_in->sa_family == AF_INET ? | ||
| 342 | (const void *)&dst_in4->sin_addr.s_addr : | ||
| 343 | (const void *)&dst_in6->sin6_addr); | ||
| 344 | } | ||
| 345 | 507 | ||
| 346 | return rdma_copy_addr(addr, dst->dev, NULL); | 508 | return rdma_copy_addr(addr, dst->dev, NULL); |
| 347 | } | 509 | } |
| @@ -349,7 +511,8 @@ static int addr_resolve_neigh(struct dst_entry *dst, | |||
| 349 | static int addr_resolve(struct sockaddr *src_in, | 511 | static int addr_resolve(struct sockaddr *src_in, |
| 350 | const struct sockaddr *dst_in, | 512 | const struct sockaddr *dst_in, |
| 351 | struct rdma_dev_addr *addr, | 513 | struct rdma_dev_addr *addr, |
| 352 | bool resolve_neigh) | 514 | bool resolve_neigh, |
| 515 | u32 seq) | ||
| 353 | { | 516 | { |
| 354 | struct net_device *ndev; | 517 | struct net_device *ndev; |
| 355 | struct dst_entry *dst; | 518 | struct dst_entry *dst; |
| @@ -366,7 +529,7 @@ static int addr_resolve(struct sockaddr *src_in, | |||
| 366 | return ret; | 529 | return ret; |
| 367 | 530 | ||
| 368 | if (resolve_neigh) | 531 | if (resolve_neigh) |
| 369 | ret = addr_resolve_neigh(&rt->dst, dst_in, addr); | 532 | ret = addr_resolve_neigh(&rt->dst, dst_in, addr, seq); |
| 370 | 533 | ||
| 371 | ndev = rt->dst.dev; | 534 | ndev = rt->dst.dev; |
| 372 | dev_hold(ndev); | 535 | dev_hold(ndev); |
| @@ -383,7 +546,7 @@ static int addr_resolve(struct sockaddr *src_in, | |||
| 383 | return ret; | 546 | return ret; |
| 384 | 547 | ||
| 385 | if (resolve_neigh) | 548 | if (resolve_neigh) |
| 386 | ret = addr_resolve_neigh(dst, dst_in, addr); | 549 | ret = addr_resolve_neigh(dst, dst_in, addr, seq); |
| 387 | 550 | ||
| 388 | ndev = dst->dev; | 551 | ndev = dst->dev; |
| 389 | dev_hold(ndev); | 552 | dev_hold(ndev); |
| @@ -412,7 +575,7 @@ static void process_req(struct work_struct *work) | |||
| 412 | src_in = (struct sockaddr *) &req->src_addr; | 575 | src_in = (struct sockaddr *) &req->src_addr; |
| 413 | dst_in = (struct sockaddr *) &req->dst_addr; | 576 | dst_in = (struct sockaddr *) &req->dst_addr; |
| 414 | req->status = addr_resolve(src_in, dst_in, req->addr, | 577 | req->status = addr_resolve(src_in, dst_in, req->addr, |
| 415 | true); | 578 | true, req->seq); |
| 416 | if (req->status && time_after_eq(jiffies, req->timeout)) | 579 | if (req->status && time_after_eq(jiffies, req->timeout)) |
| 417 | req->status = -ETIMEDOUT; | 580 | req->status = -ETIMEDOUT; |
| 418 | else if (req->status == -ENODATA) | 581 | else if (req->status == -ENODATA) |
| @@ -471,8 +634,9 @@ int rdma_resolve_ip(struct rdma_addr_client *client, | |||
| 471 | req->context = context; | 634 | req->context = context; |
| 472 | req->client = client; | 635 | req->client = client; |
| 473 | atomic_inc(&client->refcount); | 636 | atomic_inc(&client->refcount); |
| 637 | req->seq = (u32)atomic_inc_return(&ib_nl_addr_request_seq); | ||
| 474 | 638 | ||
| 475 | req->status = addr_resolve(src_in, dst_in, addr, true); | 639 | req->status = addr_resolve(src_in, dst_in, addr, true, req->seq); |
| 476 | switch (req->status) { | 640 | switch (req->status) { |
| 477 | case 0: | 641 | case 0: |
| 478 | req->timeout = jiffies; | 642 | req->timeout = jiffies; |
| @@ -510,7 +674,7 @@ int rdma_resolve_ip_route(struct sockaddr *src_addr, | |||
| 510 | src_in->sa_family = dst_addr->sa_family; | 674 | src_in->sa_family = dst_addr->sa_family; |
| 511 | } | 675 | } |
| 512 | 676 | ||
| 513 | return addr_resolve(src_in, dst_addr, addr, false); | 677 | return addr_resolve(src_in, dst_addr, addr, false, 0); |
| 514 | } | 678 | } |
| 515 | EXPORT_SYMBOL(rdma_resolve_ip_route); | 679 | EXPORT_SYMBOL(rdma_resolve_ip_route); |
| 516 | 680 | ||
| @@ -634,7 +798,7 @@ static struct notifier_block nb = { | |||
| 634 | .notifier_call = netevent_callback | 798 | .notifier_call = netevent_callback |
| 635 | }; | 799 | }; |
| 636 | 800 | ||
| 637 | static int __init addr_init(void) | 801 | int addr_init(void) |
| 638 | { | 802 | { |
| 639 | addr_wq = create_singlethread_workqueue("ib_addr"); | 803 | addr_wq = create_singlethread_workqueue("ib_addr"); |
| 640 | if (!addr_wq) | 804 | if (!addr_wq) |
| @@ -642,15 +806,13 @@ static int __init addr_init(void) | |||
| 642 | 806 | ||
| 643 | register_netevent_notifier(&nb); | 807 | register_netevent_notifier(&nb); |
| 644 | rdma_addr_register_client(&self); | 808 | rdma_addr_register_client(&self); |
| 809 | |||
| 645 | return 0; | 810 | return 0; |
| 646 | } | 811 | } |
| 647 | 812 | ||
| 648 | static void __exit addr_cleanup(void) | 813 | void addr_cleanup(void) |
| 649 | { | 814 | { |
| 650 | rdma_addr_unregister_client(&self); | 815 | rdma_addr_unregister_client(&self); |
| 651 | unregister_netevent_notifier(&nb); | 816 | unregister_netevent_notifier(&nb); |
| 652 | destroy_workqueue(addr_wq); | 817 | destroy_workqueue(addr_wq); |
| 653 | } | 818 | } |
| 654 | |||
| 655 | module_init(addr_init); | ||
| 656 | module_exit(addr_cleanup); | ||
diff --git a/drivers/infiniband/core/core_priv.h b/drivers/infiniband/core/core_priv.h index eab32215756b..19d499dcab76 100644 --- a/drivers/infiniband/core/core_priv.h +++ b/drivers/infiniband/core/core_priv.h | |||
| @@ -137,4 +137,20 @@ static inline bool rdma_is_upper_dev_rcu(struct net_device *dev, | |||
| 137 | return _upper == upper; | 137 | return _upper == upper; |
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | int addr_init(void); | ||
| 141 | void addr_cleanup(void); | ||
| 142 | |||
| 143 | int ib_mad_init(void); | ||
| 144 | void ib_mad_cleanup(void); | ||
| 145 | |||
| 146 | int ib_sa_init(void); | ||
| 147 | void ib_sa_cleanup(void); | ||
| 148 | |||
| 149 | int ib_nl_handle_resolve_resp(struct sk_buff *skb, | ||
| 150 | struct netlink_callback *cb); | ||
| 151 | int ib_nl_handle_set_timeout(struct sk_buff *skb, | ||
| 152 | struct netlink_callback *cb); | ||
| 153 | int ib_nl_handle_ip_res_resp(struct sk_buff *skb, | ||
| 154 | struct netlink_callback *cb); | ||
| 155 | |||
| 140 | #endif /* _CORE_PRIV_H */ | 156 | #endif /* _CORE_PRIV_H */ |
diff --git a/drivers/infiniband/core/device.c b/drivers/infiniband/core/device.c index 10979844026a..5516fb070344 100644 --- a/drivers/infiniband/core/device.c +++ b/drivers/infiniband/core/device.c | |||
| @@ -955,6 +955,29 @@ struct net_device *ib_get_net_dev_by_params(struct ib_device *dev, | |||
| 955 | } | 955 | } |
| 956 | EXPORT_SYMBOL(ib_get_net_dev_by_params); | 956 | EXPORT_SYMBOL(ib_get_net_dev_by_params); |
| 957 | 957 | ||
| 958 | static struct ibnl_client_cbs ibnl_ls_cb_table[] = { | ||
| 959 | [RDMA_NL_LS_OP_RESOLVE] = { | ||
| 960 | .dump = ib_nl_handle_resolve_resp, | ||
| 961 | .module = THIS_MODULE }, | ||
| 962 | [RDMA_NL_LS_OP_SET_TIMEOUT] = { | ||
| 963 | .dump = ib_nl_handle_set_timeout, | ||
| 964 | .module = THIS_MODULE }, | ||
| 965 | [RDMA_NL_LS_OP_IP_RESOLVE] = { | ||
| 966 | .dump = ib_nl_handle_ip_res_resp, | ||
| 967 | .module = THIS_MODULE }, | ||
| 968 | }; | ||
| 969 | |||
| 970 | static int ib_add_ibnl_clients(void) | ||
| 971 | { | ||
| 972 | return ibnl_add_client(RDMA_NL_LS, ARRAY_SIZE(ibnl_ls_cb_table), | ||
| 973 | ibnl_ls_cb_table); | ||
| 974 | } | ||
| 975 | |||
| 976 | static void ib_remove_ibnl_clients(void) | ||
| 977 | { | ||
| 978 | ibnl_remove_client(RDMA_NL_LS); | ||
| 979 | } | ||
| 980 | |||
| 958 | static int __init ib_core_init(void) | 981 | static int __init ib_core_init(void) |
| 959 | { | 982 | { |
| 960 | int ret; | 983 | int ret; |
| @@ -983,10 +1006,41 @@ static int __init ib_core_init(void) | |||
| 983 | goto err_sysfs; | 1006 | goto err_sysfs; |
| 984 | } | 1007 | } |
| 985 | 1008 | ||
| 1009 | ret = addr_init(); | ||
| 1010 | if (ret) { | ||
| 1011 | pr_warn("Could't init IB address resolution\n"); | ||
| 1012 | goto err_ibnl; | ||
| 1013 | } | ||
| 1014 | |||
| 1015 | ret = ib_mad_init(); | ||
| 1016 | if (ret) { | ||
| 1017 | pr_warn("Couldn't init IB MAD\n"); | ||
| 1018 | goto err_addr; | ||
| 1019 | } | ||
| 1020 | |||
| 1021 | ret = ib_sa_init(); | ||
| 1022 | if (ret) { | ||
| 1023 | pr_warn("Couldn't init SA\n"); | ||
| 1024 | goto err_mad; | ||
| 1025 | } | ||
| 1026 | |||
| 1027 | if (ib_add_ibnl_clients()) { | ||
| 1028 | pr_warn("Couldn't register ibnl clients\n"); | ||
| 1029 | goto err_sa; | ||
| 1030 | } | ||
| 1031 | |||
| 986 | ib_cache_setup(); | 1032 | ib_cache_setup(); |
| 987 | 1033 | ||
| 988 | return 0; | 1034 | return 0; |
| 989 | 1035 | ||
| 1036 | err_sa: | ||
| 1037 | ib_sa_cleanup(); | ||
| 1038 | err_mad: | ||
| 1039 | ib_mad_cleanup(); | ||
| 1040 | err_addr: | ||
| 1041 | addr_cleanup(); | ||
| 1042 | err_ibnl: | ||
| 1043 | ibnl_cleanup(); | ||
| 990 | err_sysfs: | 1044 | err_sysfs: |
| 991 | class_unregister(&ib_class); | 1045 | class_unregister(&ib_class); |
| 992 | err_comp: | 1046 | err_comp: |
| @@ -999,6 +1053,10 @@ err: | |||
| 999 | static void __exit ib_core_cleanup(void) | 1053 | static void __exit ib_core_cleanup(void) |
| 1000 | { | 1054 | { |
| 1001 | ib_cache_cleanup(); | 1055 | ib_cache_cleanup(); |
| 1056 | ib_remove_ibnl_clients(); | ||
| 1057 | ib_sa_cleanup(); | ||
| 1058 | ib_mad_cleanup(); | ||
| 1059 | addr_cleanup(); | ||
| 1002 | ibnl_cleanup(); | 1060 | ibnl_cleanup(); |
| 1003 | class_unregister(&ib_class); | 1061 | class_unregister(&ib_class); |
| 1004 | destroy_workqueue(ib_comp_wq); | 1062 | destroy_workqueue(ib_comp_wq); |
diff --git a/drivers/infiniband/core/mad.c b/drivers/infiniband/core/mad.c index 9fa5bf33f5a3..82fb511112da 100644 --- a/drivers/infiniband/core/mad.c +++ b/drivers/infiniband/core/mad.c | |||
| @@ -47,11 +47,7 @@ | |||
| 47 | #include "smi.h" | 47 | #include "smi.h" |
| 48 | #include "opa_smi.h" | 48 | #include "opa_smi.h" |
| 49 | #include "agent.h" | 49 | #include "agent.h" |
| 50 | 50 | #include "core_priv.h" | |
| 51 | MODULE_LICENSE("Dual BSD/GPL"); | ||
| 52 | MODULE_DESCRIPTION("kernel IB MAD API"); | ||
| 53 | MODULE_AUTHOR("Hal Rosenstock"); | ||
| 54 | MODULE_AUTHOR("Sean Hefty"); | ||
| 55 | 51 | ||
| 56 | static int mad_sendq_size = IB_MAD_QP_SEND_SIZE; | 52 | static int mad_sendq_size = IB_MAD_QP_SEND_SIZE; |
| 57 | static int mad_recvq_size = IB_MAD_QP_RECV_SIZE; | 53 | static int mad_recvq_size = IB_MAD_QP_RECV_SIZE; |
| @@ -3316,7 +3312,7 @@ static struct ib_client mad_client = { | |||
| 3316 | .remove = ib_mad_remove_device | 3312 | .remove = ib_mad_remove_device |
| 3317 | }; | 3313 | }; |
| 3318 | 3314 | ||
| 3319 | static int __init ib_mad_init_module(void) | 3315 | int ib_mad_init(void) |
| 3320 | { | 3316 | { |
| 3321 | mad_recvq_size = min(mad_recvq_size, IB_MAD_QP_MAX_SIZE); | 3317 | mad_recvq_size = min(mad_recvq_size, IB_MAD_QP_MAX_SIZE); |
| 3322 | mad_recvq_size = max(mad_recvq_size, IB_MAD_QP_MIN_SIZE); | 3318 | mad_recvq_size = max(mad_recvq_size, IB_MAD_QP_MIN_SIZE); |
| @@ -3334,10 +3330,7 @@ static int __init ib_mad_init_module(void) | |||
| 3334 | return 0; | 3330 | return 0; |
| 3335 | } | 3331 | } |
| 3336 | 3332 | ||
| 3337 | static void __exit ib_mad_cleanup_module(void) | 3333 | void ib_mad_cleanup(void) |
| 3338 | { | 3334 | { |
| 3339 | ib_unregister_client(&mad_client); | 3335 | ib_unregister_client(&mad_client); |
| 3340 | } | 3336 | } |
| 3341 | |||
| 3342 | module_init(ib_mad_init_module); | ||
| 3343 | module_exit(ib_mad_cleanup_module); | ||
diff --git a/drivers/infiniband/core/multicast.c b/drivers/infiniband/core/multicast.c index 250937cb9a1a..a83ec28a147b 100644 --- a/drivers/infiniband/core/multicast.c +++ b/drivers/infiniband/core/multicast.c | |||
| @@ -93,6 +93,18 @@ enum { | |||
| 93 | 93 | ||
| 94 | struct mcast_member; | 94 | struct mcast_member; |
| 95 | 95 | ||
| 96 | /* | ||
| 97 | * There are 4 types of join states: | ||
| 98 | * FullMember, NonMember, SendOnlyNonMember, SendOnlyFullMember. | ||
| 99 | */ | ||
| 100 | enum { | ||
| 101 | FULLMEMBER_JOIN, | ||
| 102 | NONMEMBER_JOIN, | ||
| 103 | SENDONLY_NONMEBER_JOIN, | ||
| 104 | SENDONLY_FULLMEMBER_JOIN, | ||
| 105 | NUM_JOIN_MEMBERSHIP_TYPES, | ||
| 106 | }; | ||
| 107 | |||
| 96 | struct mcast_group { | 108 | struct mcast_group { |
| 97 | struct ib_sa_mcmember_rec rec; | 109 | struct ib_sa_mcmember_rec rec; |
| 98 | struct rb_node node; | 110 | struct rb_node node; |
| @@ -102,7 +114,7 @@ struct mcast_group { | |||
| 102 | struct list_head pending_list; | 114 | struct list_head pending_list; |
| 103 | struct list_head active_list; | 115 | struct list_head active_list; |
| 104 | struct mcast_member *last_join; | 116 | struct mcast_member *last_join; |
| 105 | int members[3]; | 117 | int members[NUM_JOIN_MEMBERSHIP_TYPES]; |
| 106 | atomic_t refcount; | 118 | atomic_t refcount; |
| 107 | enum mcast_group_state state; | 119 | enum mcast_group_state state; |
| 108 | struct ib_sa_query *query; | 120 | struct ib_sa_query *query; |
| @@ -220,8 +232,9 @@ static void queue_join(struct mcast_member *member) | |||
| 220 | } | 232 | } |
| 221 | 233 | ||
| 222 | /* | 234 | /* |
| 223 | * A multicast group has three types of members: full member, non member, and | 235 | * A multicast group has four types of members: full member, non member, |
| 224 | * send only member. We need to keep track of the number of members of each | 236 | * sendonly non member and sendonly full member. |
| 237 | * We need to keep track of the number of members of each | ||
| 225 | * type based on their join state. Adjust the number of members the belong to | 238 | * type based on their join state. Adjust the number of members the belong to |
| 226 | * the specified join states. | 239 | * the specified join states. |
| 227 | */ | 240 | */ |
| @@ -229,7 +242,7 @@ static void adjust_membership(struct mcast_group *group, u8 join_state, int inc) | |||
| 229 | { | 242 | { |
| 230 | int i; | 243 | int i; |
| 231 | 244 | ||
| 232 | for (i = 0; i < 3; i++, join_state >>= 1) | 245 | for (i = 0; i < NUM_JOIN_MEMBERSHIP_TYPES; i++, join_state >>= 1) |
| 233 | if (join_state & 0x1) | 246 | if (join_state & 0x1) |
| 234 | group->members[i] += inc; | 247 | group->members[i] += inc; |
| 235 | } | 248 | } |
| @@ -245,7 +258,7 @@ static u8 get_leave_state(struct mcast_group *group) | |||
| 245 | u8 leave_state = 0; | 258 | u8 leave_state = 0; |
| 246 | int i; | 259 | int i; |
| 247 | 260 | ||
| 248 | for (i = 0; i < 3; i++) | 261 | for (i = 0; i < NUM_JOIN_MEMBERSHIP_TYPES; i++) |
| 249 | if (!group->members[i]) | 262 | if (!group->members[i]) |
| 250 | leave_state |= (0x1 << i); | 263 | leave_state |= (0x1 << i); |
| 251 | 264 | ||
diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c index 3ebd108bcc5f..e95538650dc6 100644 --- a/drivers/infiniband/core/sa_query.c +++ b/drivers/infiniband/core/sa_query.c | |||
| @@ -53,10 +53,6 @@ | |||
| 53 | #include "sa.h" | 53 | #include "sa.h" |
| 54 | #include "core_priv.h" | 54 | #include "core_priv.h" |
| 55 | 55 | ||
| 56 | MODULE_AUTHOR("Roland Dreier"); | ||
| 57 | MODULE_DESCRIPTION("InfiniBand subnet administration query support"); | ||
| 58 | MODULE_LICENSE("Dual BSD/GPL"); | ||
| 59 | |||
| 60 | #define IB_SA_LOCAL_SVC_TIMEOUT_MIN 100 | 56 | #define IB_SA_LOCAL_SVC_TIMEOUT_MIN 100 |
| 61 | #define IB_SA_LOCAL_SVC_TIMEOUT_DEFAULT 2000 | 57 | #define IB_SA_LOCAL_SVC_TIMEOUT_DEFAULT 2000 |
| 62 | #define IB_SA_LOCAL_SVC_TIMEOUT_MAX 200000 | 58 | #define IB_SA_LOCAL_SVC_TIMEOUT_MAX 200000 |
| @@ -119,6 +115,12 @@ struct ib_sa_guidinfo_query { | |||
| 119 | struct ib_sa_query sa_query; | 115 | struct ib_sa_query sa_query; |
| 120 | }; | 116 | }; |
| 121 | 117 | ||
| 118 | struct ib_sa_classport_info_query { | ||
| 119 | void (*callback)(int, struct ib_class_port_info *, void *); | ||
| 120 | void *context; | ||
| 121 | struct ib_sa_query sa_query; | ||
| 122 | }; | ||
| 123 | |||
| 122 | struct ib_sa_mcmember_query { | 124 | struct ib_sa_mcmember_query { |
| 123 | void (*callback)(int, struct ib_sa_mcmember_rec *, void *); | 125 | void (*callback)(int, struct ib_sa_mcmember_rec *, void *); |
| 124 | void *context; | 126 | void *context; |
| @@ -392,6 +394,82 @@ static const struct ib_field service_rec_table[] = { | |||
| 392 | .size_bits = 2*64 }, | 394 | .size_bits = 2*64 }, |
| 393 | }; | 395 | }; |
| 394 | 396 | ||
| 397 | #define CLASSPORTINFO_REC_FIELD(field) \ | ||
| 398 | .struct_offset_bytes = offsetof(struct ib_class_port_info, field), \ | ||
| 399 | .struct_size_bytes = sizeof((struct ib_class_port_info *)0)->field, \ | ||
| 400 | .field_name = "ib_class_port_info:" #field | ||
| 401 | |||
| 402 | static const struct ib_field classport_info_rec_table[] = { | ||
| 403 | { CLASSPORTINFO_REC_FIELD(base_version), | ||
| 404 | .offset_words = 0, | ||
| 405 | .offset_bits = 0, | ||
| 406 | .size_bits = 8 }, | ||
| 407 | { CLASSPORTINFO_REC_FIELD(class_version), | ||
| 408 | .offset_words = 0, | ||
| 409 | .offset_bits = 8, | ||
| 410 | .size_bits = 8 }, | ||
| 411 | { CLASSPORTINFO_REC_FIELD(capability_mask), | ||
| 412 | .offset_words = 0, | ||
| 413 | .offset_bits = 16, | ||
| 414 | .size_bits = 16 }, | ||
| 415 | { CLASSPORTINFO_REC_FIELD(cap_mask2_resp_time), | ||
| 416 | .offset_words = 1, | ||
| 417 | .offset_bits = 0, | ||
| 418 | .size_bits = 32 }, | ||
| 419 | { CLASSPORTINFO_REC_FIELD(redirect_gid), | ||
| 420 | .offset_words = 2, | ||
| 421 | .offset_bits = 0, | ||
| 422 | .size_bits = 128 }, | ||
| 423 | { CLASSPORTINFO_REC_FIELD(redirect_tcslfl), | ||
| 424 | .offset_words = 6, | ||
| 425 | .offset_bits = 0, | ||
| 426 | .size_bits = 32 }, | ||
| 427 | { CLASSPORTINFO_REC_FIELD(redirect_lid), | ||
| 428 | .offset_words = 7, | ||
| 429 | .offset_bits = 0, | ||
| 430 | .size_bits = 16 }, | ||
| 431 | { CLASSPORTINFO_REC_FIELD(redirect_pkey), | ||
| 432 | .offset_words = 7, | ||
| 433 | .offset_bits = 16, | ||
| 434 | .size_bits = 16 }, | ||
| 435 | |||
| 436 | { CLASSPORTINFO_REC_FIELD(redirect_qp), | ||
| 437 | .offset_words = 8, | ||
| 438 | .offset_bits = 0, | ||
| 439 | .size_bits = 32 }, | ||
| 440 | { CLASSPORTINFO_REC_FIELD(redirect_qkey), | ||
| 441 | .offset_words = 9, | ||
| 442 | .offset_bits = 0, | ||
| 443 | .size_bits = 32 }, | ||
| 444 | |||
| 445 | { CLASSPORTINFO_REC_FIELD(trap_gid), | ||
| 446 | .offset_words = 10, | ||
| 447 | .offset_bits = 0, | ||
| 448 | .size_bits = 128 }, | ||
| 449 | { CLASSPORTINFO_REC_FIELD(trap_tcslfl), | ||
| 450 | .offset_words = 14, | ||
| 451 | .offset_bits = 0, | ||
| 452 | .size_bits = 32 }, | ||
| 453 | |||
| 454 | { CLASSPORTINFO_REC_FIELD(trap_lid), | ||
| 455 | .offset_words = 15, | ||
| 456 | .offset_bits = 0, | ||
| 457 | .size_bits = 16 }, | ||
| 458 | { CLASSPORTINFO_REC_FIELD(trap_pkey), | ||
| 459 | .offset_words = 15, | ||
| 460 | .offset_bits = 16, | ||
| 461 | .size_bits = 16 }, | ||
| 462 | |||
| 463 | { CLASSPORTINFO_REC_FIELD(trap_hlqp), | ||
| 464 | .offset_words = 16, | ||
| 465 | .offset_bits = 0, | ||
| 466 | .size_bits = 32 }, | ||
| 467 | { CLASSPORTINFO_REC_FIELD(trap_qkey), | ||
| 468 | .offset_words = 17, | ||
| 469 | .offset_bits = 0, | ||
| 470 | .size_bits = 32 }, | ||
| 471 | }; | ||
| 472 | |||
| 395 | #define GUIDINFO_REC_FIELD(field) \ | 473 | #define GUIDINFO_REC_FIELD(field) \ |
| 396 | .struct_offset_bytes = offsetof(struct ib_sa_guidinfo_rec, field), \ | 474 | .struct_offset_bytes = offsetof(struct ib_sa_guidinfo_rec, field), \ |
| 397 | .struct_size_bytes = sizeof((struct ib_sa_guidinfo_rec *) 0)->field, \ | 475 | .struct_size_bytes = sizeof((struct ib_sa_guidinfo_rec *) 0)->field, \ |
| @@ -705,8 +783,8 @@ static void ib_nl_request_timeout(struct work_struct *work) | |||
| 705 | spin_unlock_irqrestore(&ib_nl_request_lock, flags); | 783 | spin_unlock_irqrestore(&ib_nl_request_lock, flags); |
| 706 | } | 784 | } |
| 707 | 785 | ||
| 708 | static int ib_nl_handle_set_timeout(struct sk_buff *skb, | 786 | int ib_nl_handle_set_timeout(struct sk_buff *skb, |
| 709 | struct netlink_callback *cb) | 787 | struct netlink_callback *cb) |
| 710 | { | 788 | { |
| 711 | const struct nlmsghdr *nlh = (struct nlmsghdr *)cb->nlh; | 789 | const struct nlmsghdr *nlh = (struct nlmsghdr *)cb->nlh; |
| 712 | int timeout, delta, abs_delta; | 790 | int timeout, delta, abs_delta; |
| @@ -782,8 +860,8 @@ static inline int ib_nl_is_good_resolve_resp(const struct nlmsghdr *nlh) | |||
| 782 | return 1; | 860 | return 1; |
| 783 | } | 861 | } |
| 784 | 862 | ||
| 785 | static int ib_nl_handle_resolve_resp(struct sk_buff *skb, | 863 | int ib_nl_handle_resolve_resp(struct sk_buff *skb, |
| 786 | struct netlink_callback *cb) | 864 | struct netlink_callback *cb) |
| 787 | { | 865 | { |
| 788 | const struct nlmsghdr *nlh = (struct nlmsghdr *)cb->nlh; | 866 | const struct nlmsghdr *nlh = (struct nlmsghdr *)cb->nlh; |
| 789 | unsigned long flags; | 867 | unsigned long flags; |
| @@ -838,15 +916,6 @@ resp_out: | |||
| 838 | return skb->len; | 916 | return skb->len; |
| 839 | } | 917 | } |
| 840 | 918 | ||
| 841 | static struct ibnl_client_cbs ib_sa_cb_table[] = { | ||
| 842 | [RDMA_NL_LS_OP_RESOLVE] = { | ||
| 843 | .dump = ib_nl_handle_resolve_resp, | ||
| 844 | .module = THIS_MODULE }, | ||
| 845 | [RDMA_NL_LS_OP_SET_TIMEOUT] = { | ||
| 846 | .dump = ib_nl_handle_set_timeout, | ||
| 847 | .module = THIS_MODULE }, | ||
| 848 | }; | ||
| 849 | |||
| 850 | static void free_sm_ah(struct kref *kref) | 919 | static void free_sm_ah(struct kref *kref) |
| 851 | { | 920 | { |
| 852 | struct ib_sa_sm_ah *sm_ah = container_of(kref, struct ib_sa_sm_ah, ref); | 921 | struct ib_sa_sm_ah *sm_ah = container_of(kref, struct ib_sa_sm_ah, ref); |
| @@ -1645,6 +1714,97 @@ err1: | |||
| 1645 | } | 1714 | } |
| 1646 | EXPORT_SYMBOL(ib_sa_guid_info_rec_query); | 1715 | EXPORT_SYMBOL(ib_sa_guid_info_rec_query); |
| 1647 | 1716 | ||
| 1717 | /* Support get SA ClassPortInfo */ | ||
| 1718 | static void ib_sa_classport_info_rec_callback(struct ib_sa_query *sa_query, | ||
| 1719 | int status, | ||
| 1720 | struct ib_sa_mad *mad) | ||
| 1721 | { | ||
| 1722 | struct ib_sa_classport_info_query *query = | ||
| 1723 | container_of(sa_query, struct ib_sa_classport_info_query, sa_query); | ||
| 1724 | |||
| 1725 | if (mad) { | ||
| 1726 | struct ib_class_port_info rec; | ||
| 1727 | |||
| 1728 | ib_unpack(classport_info_rec_table, | ||
| 1729 | ARRAY_SIZE(classport_info_rec_table), | ||
| 1730 | mad->data, &rec); | ||
| 1731 | query->callback(status, &rec, query->context); | ||
| 1732 | } else { | ||
| 1733 | query->callback(status, NULL, query->context); | ||
| 1734 | } | ||
| 1735 | } | ||
| 1736 | |||
| 1737 | static void ib_sa_portclass_info_rec_release(struct ib_sa_query *sa_query) | ||
| 1738 | { | ||
| 1739 | kfree(container_of(sa_query, struct ib_sa_classport_info_query, | ||
| 1740 | sa_query)); | ||
| 1741 | } | ||
| 1742 | |||
| 1743 | int ib_sa_classport_info_rec_query(struct ib_sa_client *client, | ||
| 1744 | struct ib_device *device, u8 port_num, | ||
| 1745 | int timeout_ms, gfp_t gfp_mask, | ||
| 1746 | void (*callback)(int status, | ||
| 1747 | struct ib_class_port_info *resp, | ||
| 1748 | void *context), | ||
| 1749 | void *context, | ||
| 1750 | struct ib_sa_query **sa_query) | ||
| 1751 | { | ||
| 1752 | struct ib_sa_classport_info_query *query; | ||
| 1753 | struct ib_sa_device *sa_dev = ib_get_client_data(device, &sa_client); | ||
| 1754 | struct ib_sa_port *port; | ||
| 1755 | struct ib_mad_agent *agent; | ||
| 1756 | struct ib_sa_mad *mad; | ||
| 1757 | int ret; | ||
| 1758 | |||
| 1759 | if (!sa_dev) | ||
| 1760 | return -ENODEV; | ||
| 1761 | |||
| 1762 | port = &sa_dev->port[port_num - sa_dev->start_port]; | ||
| 1763 | agent = port->agent; | ||
| 1764 | |||
| 1765 | query = kzalloc(sizeof(*query), gfp_mask); | ||
| 1766 | if (!query) | ||
| 1767 | return -ENOMEM; | ||
| 1768 | |||
| 1769 | query->sa_query.port = port; | ||
| 1770 | ret = alloc_mad(&query->sa_query, gfp_mask); | ||
| 1771 | if (ret) | ||
| 1772 | goto err1; | ||
| 1773 | |||
| 1774 | ib_sa_client_get(client); | ||
| 1775 | query->sa_query.client = client; | ||
| 1776 | query->callback = callback; | ||
| 1777 | query->context = context; | ||
| 1778 | |||
| 1779 | mad = query->sa_query.mad_buf->mad; | ||
| 1780 | init_mad(mad, agent); | ||
| 1781 | |||
| 1782 | query->sa_query.callback = callback ? ib_sa_classport_info_rec_callback : NULL; | ||
| 1783 | |||
| 1784 | query->sa_query.release = ib_sa_portclass_info_rec_release; | ||
| 1785 | /* support GET only */ | ||
| 1786 | mad->mad_hdr.method = IB_MGMT_METHOD_GET; | ||
| 1787 | mad->mad_hdr.attr_id = cpu_to_be16(IB_SA_ATTR_CLASS_PORTINFO); | ||
| 1788 | mad->sa_hdr.comp_mask = 0; | ||
| 1789 | *sa_query = &query->sa_query; | ||
| 1790 | |||
| 1791 | ret = send_mad(&query->sa_query, timeout_ms, gfp_mask); | ||
| 1792 | if (ret < 0) | ||
| 1793 | goto err2; | ||
| 1794 | |||
| 1795 | return ret; | ||
| 1796 | |||
| 1797 | err2: | ||
| 1798 | *sa_query = NULL; | ||
| 1799 | ib_sa_client_put(query->sa_query.client); | ||
| 1800 | free_mad(&query->sa_query); | ||
| 1801 | |||
| 1802 | err1: | ||
| 1803 | kfree(query); | ||
| 1804 | return ret; | ||
| 1805 | } | ||
| 1806 | EXPORT_SYMBOL(ib_sa_classport_info_rec_query); | ||
| 1807 | |||
| 1648 | static void send_handler(struct ib_mad_agent *agent, | 1808 | static void send_handler(struct ib_mad_agent *agent, |
| 1649 | struct ib_mad_send_wc *mad_send_wc) | 1809 | struct ib_mad_send_wc *mad_send_wc) |
| 1650 | { | 1810 | { |
| @@ -1794,7 +1954,7 @@ static void ib_sa_remove_one(struct ib_device *device, void *client_data) | |||
| 1794 | kfree(sa_dev); | 1954 | kfree(sa_dev); |
| 1795 | } | 1955 | } |
| 1796 | 1956 | ||
| 1797 | static int __init ib_sa_init(void) | 1957 | int ib_sa_init(void) |
| 1798 | { | 1958 | { |
| 1799 | int ret; | 1959 | int ret; |
| 1800 | 1960 | ||
| @@ -1820,17 +1980,10 @@ static int __init ib_sa_init(void) | |||
| 1820 | goto err3; | 1980 | goto err3; |
| 1821 | } | 1981 | } |
| 1822 | 1982 | ||
| 1823 | if (ibnl_add_client(RDMA_NL_LS, ARRAY_SIZE(ib_sa_cb_table), | ||
| 1824 | ib_sa_cb_table)) { | ||
| 1825 | pr_err("Failed to add netlink callback\n"); | ||
| 1826 | ret = -EINVAL; | ||
| 1827 | goto err4; | ||
| 1828 | } | ||
| 1829 | INIT_DELAYED_WORK(&ib_nl_timed_work, ib_nl_request_timeout); | 1983 | INIT_DELAYED_WORK(&ib_nl_timed_work, ib_nl_request_timeout); |
| 1830 | 1984 | ||
| 1831 | return 0; | 1985 | return 0; |
| 1832 | err4: | 1986 | |
| 1833 | destroy_workqueue(ib_nl_wq); | ||
| 1834 | err3: | 1987 | err3: |
| 1835 | mcast_cleanup(); | 1988 | mcast_cleanup(); |
| 1836 | err2: | 1989 | err2: |
| @@ -1839,9 +1992,8 @@ err1: | |||
| 1839 | return ret; | 1992 | return ret; |
| 1840 | } | 1993 | } |
| 1841 | 1994 | ||
| 1842 | static void __exit ib_sa_cleanup(void) | 1995 | void ib_sa_cleanup(void) |
| 1843 | { | 1996 | { |
| 1844 | ibnl_remove_client(RDMA_NL_LS); | ||
| 1845 | cancel_delayed_work(&ib_nl_timed_work); | 1997 | cancel_delayed_work(&ib_nl_timed_work); |
| 1846 | flush_workqueue(ib_nl_wq); | 1998 | flush_workqueue(ib_nl_wq); |
| 1847 | destroy_workqueue(ib_nl_wq); | 1999 | destroy_workqueue(ib_nl_wq); |
| @@ -1849,6 +2001,3 @@ static void __exit ib_sa_cleanup(void) | |||
| 1849 | ib_unregister_client(&sa_client); | 2001 | ib_unregister_client(&sa_client); |
| 1850 | idr_destroy(&query_idr); | 2002 | idr_destroy(&query_idr); |
| 1851 | } | 2003 | } |
| 1852 | |||
| 1853 | module_init(ib_sa_init); | ||
| 1854 | module_exit(ib_sa_cleanup); | ||
diff --git a/drivers/infiniband/hw/qib/qib_mad.c b/drivers/infiniband/hw/qib/qib_mad.c index 0bd18375d7df..d2ac29861af5 100644 --- a/drivers/infiniband/hw/qib/qib_mad.c +++ b/drivers/infiniband/hw/qib/qib_mad.c | |||
| @@ -1172,11 +1172,13 @@ static int pma_get_classportinfo(struct ib_pma_mad *pmp, | |||
| 1172 | * Set the most significant bit of CM2 to indicate support for | 1172 | * Set the most significant bit of CM2 to indicate support for |
| 1173 | * congestion statistics | 1173 | * congestion statistics |
| 1174 | */ | 1174 | */ |
| 1175 | p->reserved[0] = dd->psxmitwait_supported << 7; | 1175 | ib_set_cpi_capmask2(p, |
| 1176 | dd->psxmitwait_supported << | ||
| 1177 | (31 - IB_CLASS_PORT_INFO_RESP_TIME_FIELD_SIZE)); | ||
| 1176 | /* | 1178 | /* |
| 1177 | * Expected response time is 4.096 usec. * 2^18 == 1.073741824 sec. | 1179 | * Expected response time is 4.096 usec. * 2^18 == 1.073741824 sec. |
| 1178 | */ | 1180 | */ |
| 1179 | p->resp_time_value = 18; | 1181 | ib_set_cpi_resp_time(p, 18); |
| 1180 | 1182 | ||
| 1181 | return reply((struct ib_smp *) pmp); | 1183 | return reply((struct ib_smp *) pmp); |
| 1182 | } | 1184 | } |
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index caec8e9c4666..bab7db6fa9ab 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h | |||
| @@ -92,6 +92,8 @@ enum { | |||
| 92 | IPOIB_FLAG_UMCAST = 10, | 92 | IPOIB_FLAG_UMCAST = 10, |
| 93 | IPOIB_STOP_NEIGH_GC = 11, | 93 | IPOIB_STOP_NEIGH_GC = 11, |
| 94 | IPOIB_NEIGH_TBL_FLUSH = 12, | 94 | IPOIB_NEIGH_TBL_FLUSH = 12, |
| 95 | IPOIB_FLAG_DEV_ADDR_SET = 13, | ||
| 96 | IPOIB_FLAG_DEV_ADDR_CTRL = 14, | ||
| 95 | 97 | ||
| 96 | IPOIB_MAX_BACKOFF_SECONDS = 16, | 98 | IPOIB_MAX_BACKOFF_SECONDS = 16, |
| 97 | 99 | ||
| @@ -392,6 +394,7 @@ struct ipoib_dev_priv { | |||
| 392 | struct ipoib_ethtool_st ethtool; | 394 | struct ipoib_ethtool_st ethtool; |
| 393 | struct timer_list poll_timer; | 395 | struct timer_list poll_timer; |
| 394 | unsigned max_send_sge; | 396 | unsigned max_send_sge; |
| 397 | bool sm_fullmember_sendonly_support; | ||
| 395 | }; | 398 | }; |
| 396 | 399 | ||
| 397 | struct ipoib_ah { | 400 | struct ipoib_ah { |
| @@ -476,6 +479,7 @@ void ipoib_reap_ah(struct work_struct *work); | |||
| 476 | 479 | ||
| 477 | void ipoib_mark_paths_invalid(struct net_device *dev); | 480 | void ipoib_mark_paths_invalid(struct net_device *dev); |
| 478 | void ipoib_flush_paths(struct net_device *dev); | 481 | void ipoib_flush_paths(struct net_device *dev); |
| 482 | int ipoib_check_sm_sendonly_fullmember_support(struct ipoib_dev_priv *priv); | ||
| 479 | struct ipoib_dev_priv *ipoib_intf_alloc(const char *format); | 483 | struct ipoib_dev_priv *ipoib_intf_alloc(const char *format); |
| 480 | 484 | ||
| 481 | int ipoib_ib_dev_init(struct net_device *dev, struct ib_device *ca, int port); | 485 | int ipoib_ib_dev_init(struct net_device *dev, struct ib_device *ca, int port); |
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index da5f28c892ca..7e9a77040a24 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c | |||
| @@ -997,6 +997,106 @@ static inline int update_child_pkey(struct ipoib_dev_priv *priv) | |||
| 997 | return 0; | 997 | return 0; |
| 998 | } | 998 | } |
| 999 | 999 | ||
| 1000 | /* | ||
| 1001 | * returns true if the device address of the ipoib interface has changed and the | ||
| 1002 | * new address is a valid one (i.e in the gid table), return false otherwise. | ||
| 1003 | */ | ||
| 1004 | static bool ipoib_dev_addr_changed_valid(struct ipoib_dev_priv *priv) | ||
| 1005 | { | ||
| 1006 | union ib_gid search_gid; | ||
| 1007 | union ib_gid gid0; | ||
| 1008 | union ib_gid *netdev_gid; | ||
| 1009 | int err; | ||
| 1010 | u16 index; | ||
| 1011 | u8 port; | ||
| 1012 | bool ret = false; | ||
| 1013 | |||
| 1014 | netdev_gid = (union ib_gid *)(priv->dev->dev_addr + 4); | ||
| 1015 | if (ib_query_gid(priv->ca, priv->port, 0, &gid0, NULL)) | ||
| 1016 | return false; | ||
| 1017 | |||
| 1018 | netif_addr_lock(priv->dev); | ||
| 1019 | |||
| 1020 | /* The subnet prefix may have changed, update it now so we won't have | ||
| 1021 | * to do it later | ||
| 1022 | */ | ||
| 1023 | priv->local_gid.global.subnet_prefix = gid0.global.subnet_prefix; | ||
| 1024 | netdev_gid->global.subnet_prefix = gid0.global.subnet_prefix; | ||
| 1025 | search_gid.global.subnet_prefix = gid0.global.subnet_prefix; | ||
| 1026 | |||
| 1027 | search_gid.global.interface_id = priv->local_gid.global.interface_id; | ||
| 1028 | |||
| 1029 | netif_addr_unlock(priv->dev); | ||
| 1030 | |||
| 1031 | err = ib_find_gid(priv->ca, &search_gid, IB_GID_TYPE_IB, | ||
| 1032 | priv->dev, &port, &index); | ||
| 1033 | |||
| 1034 | netif_addr_lock(priv->dev); | ||
| 1035 | |||
| 1036 | if (search_gid.global.interface_id != | ||
| 1037 | priv->local_gid.global.interface_id) | ||
| 1038 | /* There was a change while we were looking up the gid, bail | ||
| 1039 | * here and let the next work sort this out | ||
| 1040 | */ | ||
| 1041 | goto out; | ||
| 1042 | |||
| 1043 | /* The next section of code needs some background: | ||
| 1044 | * Per IB spec the port GUID can't change if the HCA is powered on. | ||
| 1045 | * port GUID is the basis for GID at index 0 which is the basis for | ||
| 1046 | * the default device address of a ipoib interface. | ||
| 1047 | * | ||
| 1048 | * so it seems the flow should be: | ||
| 1049 | * if user_changed_dev_addr && gid in gid tbl | ||
| 1050 | * set bit dev_addr_set | ||
| 1051 | * return true | ||
| 1052 | * else | ||
| 1053 | * return false | ||
| 1054 | * | ||
| 1055 | * The issue is that there are devices that don't follow the spec, | ||
| 1056 | * they change the port GUID when the HCA is powered, so in order | ||
| 1057 | * not to break userspace applications, We need to check if the | ||
| 1058 | * user wanted to control the device address and we assume that | ||
| 1059 | * if he sets the device address back to be based on GID index 0, | ||
| 1060 | * he no longer wishs to control it. | ||
| 1061 | * | ||
| 1062 | * If the user doesn't control the the device address, | ||
| 1063 | * IPOIB_FLAG_DEV_ADDR_SET is set and ib_find_gid failed it means | ||
| 1064 | * the port GUID has changed and GID at index 0 has changed | ||
| 1065 | * so we need to change priv->local_gid and priv->dev->dev_addr | ||
| 1066 | * to reflect the new GID. | ||
| 1067 | */ | ||
| 1068 | if (!test_bit(IPOIB_FLAG_DEV_ADDR_SET, &priv->flags)) { | ||
| 1069 | if (!err && port == priv->port) { | ||
| 1070 | set_bit(IPOIB_FLAG_DEV_ADDR_SET, &priv->flags); | ||
| 1071 | if (index == 0) | ||
| 1072 | clear_bit(IPOIB_FLAG_DEV_ADDR_CTRL, | ||
| 1073 | &priv->flags); | ||
| 1074 | else | ||
| 1075 | set_bit(IPOIB_FLAG_DEV_ADDR_CTRL, &priv->flags); | ||
| 1076 | ret = true; | ||
| 1077 | } else { | ||
| 1078 | ret = false; | ||
| 1079 | } | ||
| 1080 | } else { | ||
| 1081 | if (!err && port == priv->port) { | ||
| 1082 | ret = true; | ||
| 1083 | } else { | ||
| 1084 | if (!test_bit(IPOIB_FLAG_DEV_ADDR_CTRL, &priv->flags)) { | ||
| 1085 | memcpy(&priv->local_gid, &gid0, | ||
| 1086 | sizeof(priv->local_gid)); | ||
| 1087 | memcpy(priv->dev->dev_addr + 4, &gid0, | ||
| 1088 | sizeof(priv->local_gid)); | ||
| 1089 | ret = true; | ||
| 1090 | } | ||
| 1091 | } | ||
| 1092 | } | ||
| 1093 | |||
| 1094 | out: | ||
| 1095 | netif_addr_unlock(priv->dev); | ||
| 1096 | |||
| 1097 | return ret; | ||
| 1098 | } | ||
| 1099 | |||
| 1000 | static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv, | 1100 | static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv, |
| 1001 | enum ipoib_flush_level level, | 1101 | enum ipoib_flush_level level, |
| 1002 | int nesting) | 1102 | int nesting) |
| @@ -1018,6 +1118,9 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv, | |||
| 1018 | 1118 | ||
| 1019 | if (!test_bit(IPOIB_FLAG_INITIALIZED, &priv->flags) && | 1119 | if (!test_bit(IPOIB_FLAG_INITIALIZED, &priv->flags) && |
| 1020 | level != IPOIB_FLUSH_HEAVY) { | 1120 | level != IPOIB_FLUSH_HEAVY) { |
| 1121 | /* Make sure the dev_addr is set even if not flushing */ | ||
| 1122 | if (level == IPOIB_FLUSH_LIGHT) | ||
| 1123 | ipoib_dev_addr_changed_valid(priv); | ||
| 1021 | ipoib_dbg(priv, "Not flushing - IPOIB_FLAG_INITIALIZED not set.\n"); | 1124 | ipoib_dbg(priv, "Not flushing - IPOIB_FLAG_INITIALIZED not set.\n"); |
| 1022 | return; | 1125 | return; |
| 1023 | } | 1126 | } |
| @@ -1029,7 +1132,8 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv, | |||
| 1029 | update_parent_pkey(priv); | 1132 | update_parent_pkey(priv); |
| 1030 | else | 1133 | else |
| 1031 | update_child_pkey(priv); | 1134 | update_child_pkey(priv); |
| 1032 | } | 1135 | } else if (level == IPOIB_FLUSH_LIGHT) |
| 1136 | ipoib_dev_addr_changed_valid(priv); | ||
| 1033 | ipoib_dbg(priv, "Not flushing - IPOIB_FLAG_ADMIN_UP not set.\n"); | 1137 | ipoib_dbg(priv, "Not flushing - IPOIB_FLAG_ADMIN_UP not set.\n"); |
| 1034 | return; | 1138 | return; |
| 1035 | } | 1139 | } |
| @@ -1081,7 +1185,8 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv, | |||
| 1081 | if (test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)) { | 1185 | if (test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags)) { |
| 1082 | if (level >= IPOIB_FLUSH_NORMAL) | 1186 | if (level >= IPOIB_FLUSH_NORMAL) |
| 1083 | ipoib_ib_dev_up(dev); | 1187 | ipoib_ib_dev_up(dev); |
| 1084 | ipoib_mcast_restart_task(&priv->restart_task); | 1188 | if (ipoib_dev_addr_changed_valid(priv)) |
| 1189 | ipoib_mcast_restart_task(&priv->restart_task); | ||
| 1085 | } | 1190 | } |
| 1086 | } | 1191 | } |
| 1087 | 1192 | ||
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 80807d6e5c4c..2c3fb5337bc1 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c | |||
| @@ -99,6 +99,7 @@ static struct net_device *ipoib_get_net_dev_by_params( | |||
| 99 | struct ib_device *dev, u8 port, u16 pkey, | 99 | struct ib_device *dev, u8 port, u16 pkey, |
| 100 | const union ib_gid *gid, const struct sockaddr *addr, | 100 | const union ib_gid *gid, const struct sockaddr *addr, |
| 101 | void *client_data); | 101 | void *client_data); |
| 102 | static int ipoib_set_mac(struct net_device *dev, void *addr); | ||
| 102 | 103 | ||
| 103 | static struct ib_client ipoib_client = { | 104 | static struct ib_client ipoib_client = { |
| 104 | .name = "ipoib", | 105 | .name = "ipoib", |
| @@ -117,6 +118,8 @@ int ipoib_open(struct net_device *dev) | |||
| 117 | 118 | ||
| 118 | set_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags); | 119 | set_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags); |
| 119 | 120 | ||
| 121 | priv->sm_fullmember_sendonly_support = false; | ||
| 122 | |||
| 120 | if (ipoib_ib_dev_open(dev)) { | 123 | if (ipoib_ib_dev_open(dev)) { |
| 121 | if (!test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags)) | 124 | if (!test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags)) |
| 122 | return 0; | 125 | return 0; |
| @@ -629,6 +632,77 @@ void ipoib_mark_paths_invalid(struct net_device *dev) | |||
| 629 | spin_unlock_irq(&priv->lock); | 632 | spin_unlock_irq(&priv->lock); |
| 630 | } | 633 | } |
| 631 | 634 | ||
| 635 | struct classport_info_context { | ||
| 636 | struct ipoib_dev_priv *priv; | ||
| 637 | struct completion done; | ||
| 638 | struct ib_sa_query *sa_query; | ||
| 639 | }; | ||
| 640 | |||
| 641 | static void classport_info_query_cb(int status, struct ib_class_port_info *rec, | ||
| 642 | void *context) | ||
| 643 | { | ||
| 644 | struct classport_info_context *cb_ctx = context; | ||
| 645 | struct ipoib_dev_priv *priv; | ||
| 646 | |||
| 647 | WARN_ON(!context); | ||
| 648 | |||
| 649 | priv = cb_ctx->priv; | ||
| 650 | |||
| 651 | if (status || !rec) { | ||
| 652 | pr_debug("device: %s failed query classport_info status: %d\n", | ||
| 653 | priv->dev->name, status); | ||
| 654 | /* keeps the default, will try next mcast_restart */ | ||
| 655 | priv->sm_fullmember_sendonly_support = false; | ||
| 656 | goto out; | ||
| 657 | } | ||
| 658 | |||
| 659 | if (ib_get_cpi_capmask2(rec) & | ||
| 660 | IB_SA_CAP_MASK2_SENDONLY_FULL_MEM_SUPPORT) { | ||
| 661 | pr_debug("device: %s enabled fullmember-sendonly for sendonly MCG\n", | ||
| 662 | priv->dev->name); | ||
| 663 | priv->sm_fullmember_sendonly_support = true; | ||
| 664 | } else { | ||
| 665 | pr_debug("device: %s disabled fullmember-sendonly for sendonly MCG\n", | ||
| 666 | priv->dev->name); | ||
| 667 | priv->sm_fullmember_sendonly_support = false; | ||
| 668 | } | ||
| 669 | |||
| 670 | out: | ||
| 671 | complete(&cb_ctx->done); | ||
| 672 | } | ||
| 673 | |||
| 674 | int ipoib_check_sm_sendonly_fullmember_support(struct ipoib_dev_priv *priv) | ||
| 675 | { | ||
| 676 | struct classport_info_context *callback_context; | ||
| 677 | int ret; | ||
| 678 | |||
| 679 | callback_context = kmalloc(sizeof(*callback_context), GFP_KERNEL); | ||
| 680 | if (!callback_context) | ||
| 681 | return -ENOMEM; | ||
| 682 | |||
| 683 | callback_context->priv = priv; | ||
| 684 | init_completion(&callback_context->done); | ||
| 685 | |||
| 686 | ret = ib_sa_classport_info_rec_query(&ipoib_sa_client, | ||
| 687 | priv->ca, priv->port, 3000, | ||
| 688 | GFP_KERNEL, | ||
| 689 | classport_info_query_cb, | ||
| 690 | callback_context, | ||
| 691 | &callback_context->sa_query); | ||
| 692 | if (ret < 0) { | ||
| 693 | pr_info("%s failed to send ib_sa_classport_info query, ret: %d\n", | ||
| 694 | priv->dev->name, ret); | ||
| 695 | kfree(callback_context); | ||
| 696 | return ret; | ||
| 697 | } | ||
| 698 | |||
| 699 | /* waiting for the callback to finish before returnning */ | ||
| 700 | wait_for_completion(&callback_context->done); | ||
| 701 | kfree(callback_context); | ||
| 702 | |||
| 703 | return ret; | ||
| 704 | } | ||
| 705 | |||
| 632 | void ipoib_flush_paths(struct net_device *dev) | 706 | void ipoib_flush_paths(struct net_device *dev) |
| 633 | { | 707 | { |
| 634 | struct ipoib_dev_priv *priv = netdev_priv(dev); | 708 | struct ipoib_dev_priv *priv = netdev_priv(dev); |
| @@ -1649,6 +1723,7 @@ static const struct net_device_ops ipoib_netdev_ops_pf = { | |||
| 1649 | .ndo_get_vf_config = ipoib_get_vf_config, | 1723 | .ndo_get_vf_config = ipoib_get_vf_config, |
| 1650 | .ndo_get_vf_stats = ipoib_get_vf_stats, | 1724 | .ndo_get_vf_stats = ipoib_get_vf_stats, |
| 1651 | .ndo_set_vf_guid = ipoib_set_vf_guid, | 1725 | .ndo_set_vf_guid = ipoib_set_vf_guid, |
| 1726 | .ndo_set_mac_address = ipoib_set_mac, | ||
| 1652 | }; | 1727 | }; |
| 1653 | 1728 | ||
| 1654 | static const struct net_device_ops ipoib_netdev_ops_vf = { | 1729 | static const struct net_device_ops ipoib_netdev_ops_vf = { |
| @@ -1771,6 +1846,70 @@ int ipoib_add_umcast_attr(struct net_device *dev) | |||
| 1771 | return device_create_file(&dev->dev, &dev_attr_umcast); | 1846 | return device_create_file(&dev->dev, &dev_attr_umcast); |
| 1772 | } | 1847 | } |
| 1773 | 1848 | ||
| 1849 | static void set_base_guid(struct ipoib_dev_priv *priv, union ib_gid *gid) | ||
| 1850 | { | ||
| 1851 | struct ipoib_dev_priv *child_priv; | ||
| 1852 | struct net_device *netdev = priv->dev; | ||
| 1853 | |||
| 1854 | netif_addr_lock(netdev); | ||
| 1855 | |||
| 1856 | memcpy(&priv->local_gid.global.interface_id, | ||
| 1857 | &gid->global.interface_id, | ||
| 1858 | sizeof(gid->global.interface_id)); | ||
| 1859 | memcpy(netdev->dev_addr + 4, &priv->local_gid, sizeof(priv->local_gid)); | ||
| 1860 | clear_bit(IPOIB_FLAG_DEV_ADDR_SET, &priv->flags); | ||
| 1861 | |||
| 1862 | netif_addr_unlock(netdev); | ||
| 1863 | |||
| 1864 | if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) { | ||
| 1865 | down_read(&priv->vlan_rwsem); | ||
| 1866 | list_for_each_entry(child_priv, &priv->child_intfs, list) | ||
| 1867 | set_base_guid(child_priv, gid); | ||
| 1868 | up_read(&priv->vlan_rwsem); | ||
| 1869 | } | ||
| 1870 | } | ||
| 1871 | |||
| 1872 | static int ipoib_check_lladdr(struct net_device *dev, | ||
| 1873 | struct sockaddr_storage *ss) | ||
| 1874 | { | ||
| 1875 | union ib_gid *gid = (union ib_gid *)(ss->__data + 4); | ||
| 1876 | int ret = 0; | ||
| 1877 | |||
| 1878 | netif_addr_lock(dev); | ||
| 1879 | |||
| 1880 | /* Make sure the QPN, reserved and subnet prefix match the current | ||
| 1881 | * lladdr, it also makes sure the lladdr is unicast. | ||
| 1882 | */ | ||
| 1883 | if (memcmp(dev->dev_addr, ss->__data, | ||
| 1884 | 4 + sizeof(gid->global.subnet_prefix)) || | ||
| 1885 | gid->global.interface_id == 0) | ||
| 1886 | ret = -EINVAL; | ||
| 1887 | |||
| 1888 | netif_addr_unlock(dev); | ||
| 1889 | |||
| 1890 | return ret; | ||
| 1891 | } | ||
| 1892 | |||
| 1893 | static int ipoib_set_mac(struct net_device *dev, void *addr) | ||
| 1894 | { | ||
| 1895 | struct ipoib_dev_priv *priv = netdev_priv(dev); | ||
| 1896 | struct sockaddr_storage *ss = addr; | ||
| 1897 | int ret; | ||
| 1898 | |||
| 1899 | if (!(dev->priv_flags & IFF_LIVE_ADDR_CHANGE) && netif_running(dev)) | ||
| 1900 | return -EBUSY; | ||
| 1901 | |||
| 1902 | ret = ipoib_check_lladdr(dev, ss); | ||
| 1903 | if (ret) | ||
| 1904 | return ret; | ||
| 1905 | |||
| 1906 | set_base_guid(priv, (union ib_gid *)(ss->__data + 4)); | ||
| 1907 | |||
| 1908 | queue_work(ipoib_workqueue, &priv->flush_light); | ||
| 1909 | |||
| 1910 | return 0; | ||
| 1911 | } | ||
| 1912 | |||
| 1774 | static ssize_t create_child(struct device *dev, | 1913 | static ssize_t create_child(struct device *dev, |
| 1775 | struct device_attribute *attr, | 1914 | struct device_attribute *attr, |
| 1776 | const char *buf, size_t count) | 1915 | const char *buf, size_t count) |
| @@ -1894,6 +2033,7 @@ static struct net_device *ipoib_add_port(const char *format, | |||
| 1894 | goto device_init_failed; | 2033 | goto device_init_failed; |
| 1895 | } else | 2034 | } else |
| 1896 | memcpy(priv->dev->dev_addr + 4, priv->local_gid.raw, sizeof (union ib_gid)); | 2035 | memcpy(priv->dev->dev_addr + 4, priv->local_gid.raw, sizeof (union ib_gid)); |
| 2036 | set_bit(IPOIB_FLAG_DEV_ADDR_SET, &priv->flags); | ||
| 1897 | 2037 | ||
| 1898 | result = ipoib_dev_init(priv->dev, hca, port); | 2038 | result = ipoib_dev_init(priv->dev, hca, port); |
| 1899 | if (result < 0) { | 2039 | if (result < 0) { |
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index 25889311b1e9..82fbc9442608 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c | |||
| @@ -64,6 +64,9 @@ struct ipoib_mcast_iter { | |||
| 64 | unsigned int send_only; | 64 | unsigned int send_only; |
| 65 | }; | 65 | }; |
| 66 | 66 | ||
| 67 | /* join state that allows creating mcg with sendonly member request */ | ||
| 68 | #define SENDONLY_FULLMEMBER_JOIN 8 | ||
| 69 | |||
| 67 | /* | 70 | /* |
| 68 | * This should be called with the priv->lock held | 71 | * This should be called with the priv->lock held |
| 69 | */ | 72 | */ |
| @@ -326,12 +329,23 @@ void ipoib_mcast_carrier_on_task(struct work_struct *work) | |||
| 326 | struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv, | 329 | struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv, |
| 327 | carrier_on_task); | 330 | carrier_on_task); |
| 328 | struct ib_port_attr attr; | 331 | struct ib_port_attr attr; |
| 332 | int ret; | ||
| 329 | 333 | ||
| 330 | if (ib_query_port(priv->ca, priv->port, &attr) || | 334 | if (ib_query_port(priv->ca, priv->port, &attr) || |
| 331 | attr.state != IB_PORT_ACTIVE) { | 335 | attr.state != IB_PORT_ACTIVE) { |
| 332 | ipoib_dbg(priv, "Keeping carrier off until IB port is active\n"); | 336 | ipoib_dbg(priv, "Keeping carrier off until IB port is active\n"); |
| 333 | return; | 337 | return; |
| 334 | } | 338 | } |
| 339 | /* | ||
| 340 | * Check if can send sendonly MCG's with sendonly-fullmember join state. | ||
| 341 | * It done here after the successfully join to the broadcast group, | ||
| 342 | * because the broadcast group must always be joined first and is always | ||
| 343 | * re-joined if the SM changes substantially. | ||
| 344 | */ | ||
| 345 | ret = ipoib_check_sm_sendonly_fullmember_support(priv); | ||
| 346 | if (ret < 0) | ||
| 347 | pr_debug("%s failed query sm support for sendonly-fullmember (ret: %d)\n", | ||
| 348 | priv->dev->name, ret); | ||
| 335 | 349 | ||
| 336 | /* | 350 | /* |
| 337 | * Take rtnl_lock to avoid racing with ipoib_stop() and | 351 | * Take rtnl_lock to avoid racing with ipoib_stop() and |
| @@ -515,22 +529,20 @@ static int ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast) | |||
| 515 | rec.hop_limit = priv->broadcast->mcmember.hop_limit; | 529 | rec.hop_limit = priv->broadcast->mcmember.hop_limit; |
| 516 | 530 | ||
| 517 | /* | 531 | /* |
| 518 | * Send-only IB Multicast joins do not work at the core | 532 | * Send-only IB Multicast joins work at the core IB layer but |
| 519 | * IB layer yet, so we can't use them here. However, | 533 | * require specific SM support. |
| 520 | * we are emulating an Ethernet multicast send, which | 534 | * We can use such joins here only if the current SM supports that feature. |
| 521 | * does not require a multicast subscription and will | 535 | * However, if not, we emulate an Ethernet multicast send, |
| 522 | * still send properly. The most appropriate thing to | 536 | * which does not require a multicast subscription and will |
| 537 | * still send properly. The most appropriate thing to | ||
| 523 | * do is to create the group if it doesn't exist as that | 538 | * do is to create the group if it doesn't exist as that |
| 524 | * most closely emulates the behavior, from a user space | 539 | * most closely emulates the behavior, from a user space |
| 525 | * application perspecitive, of Ethernet multicast | 540 | * application perspective, of Ethernet multicast operation. |
| 526 | * operation. For now, we do a full join, maybe later | ||
| 527 | * when the core IB layers support send only joins we | ||
| 528 | * will use them. | ||
| 529 | */ | 541 | */ |
| 530 | #if 0 | 542 | if (test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags) && |
| 531 | if (test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) | 543 | priv->sm_fullmember_sendonly_support) |
| 532 | rec.join_state = 4; | 544 | /* SM supports sendonly-fullmember, otherwise fallback to full-member */ |
| 533 | #endif | 545 | rec.join_state = SENDONLY_FULLMEMBER_JOIN; |
| 534 | } | 546 | } |
| 535 | spin_unlock_irq(&priv->lock); | 547 | spin_unlock_irq(&priv->lock); |
| 536 | 548 | ||
| @@ -570,11 +582,13 @@ void ipoib_mcast_join_task(struct work_struct *work) | |||
| 570 | return; | 582 | return; |
| 571 | } | 583 | } |
| 572 | priv->local_lid = port_attr.lid; | 584 | priv->local_lid = port_attr.lid; |
| 585 | netif_addr_lock(dev); | ||
| 573 | 586 | ||
| 574 | if (ib_query_gid(priv->ca, priv->port, 0, &priv->local_gid, NULL)) | 587 | if (!test_bit(IPOIB_FLAG_DEV_ADDR_SET, &priv->flags)) { |
| 575 | ipoib_warn(priv, "ib_query_gid() failed\n"); | 588 | netif_addr_unlock(dev); |
| 576 | else | 589 | return; |
| 577 | memcpy(priv->dev->dev_addr + 4, priv->local_gid.raw, sizeof (union ib_gid)); | 590 | } |
| 591 | netif_addr_unlock(dev); | ||
| 578 | 592 | ||
| 579 | spin_lock_irq(&priv->lock); | 593 | spin_lock_irq(&priv->lock); |
| 580 | if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) | 594 | if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) |
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c index b809c373e40e..1e7cbbaa15bd 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c | |||
| @@ -307,5 +307,8 @@ void ipoib_event(struct ib_event_handler *handler, | |||
| 307 | queue_work(ipoib_workqueue, &priv->flush_normal); | 307 | queue_work(ipoib_workqueue, &priv->flush_normal); |
| 308 | } else if (record->event == IB_EVENT_PKEY_CHANGE) { | 308 | } else if (record->event == IB_EVENT_PKEY_CHANGE) { |
| 309 | queue_work(ipoib_workqueue, &priv->flush_heavy); | 309 | queue_work(ipoib_workqueue, &priv->flush_heavy); |
| 310 | } else if (record->event == IB_EVENT_GID_CHANGE && | ||
| 311 | !test_bit(IPOIB_FLAG_DEV_ADDR_SET, &priv->flags)) { | ||
| 312 | queue_work(ipoib_workqueue, &priv->flush_light); | ||
| 310 | } | 313 | } |
| 311 | } | 314 | } |
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c index fca1a882de27..64a35595eab8 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_vlan.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_vlan.c | |||
| @@ -68,6 +68,8 @@ int __ipoib_vlan_add(struct ipoib_dev_priv *ppriv, struct ipoib_dev_priv *priv, | |||
| 68 | priv->pkey = pkey; | 68 | priv->pkey = pkey; |
| 69 | 69 | ||
| 70 | memcpy(priv->dev->dev_addr, ppriv->dev->dev_addr, INFINIBAND_ALEN); | 70 | memcpy(priv->dev->dev_addr, ppriv->dev->dev_addr, INFINIBAND_ALEN); |
| 71 | memcpy(&priv->local_gid, &ppriv->local_gid, sizeof(priv->local_gid)); | ||
| 72 | set_bit(IPOIB_FLAG_DEV_ADDR_SET, &priv->flags); | ||
| 71 | priv->dev->broadcast[8] = pkey >> 8; | 73 | priv->dev->broadcast[8] = pkey >> 8; |
| 72 | priv->dev->broadcast[9] = pkey & 0xff; | 74 | priv->dev->broadcast[9] = pkey & 0xff; |
| 73 | 75 | ||
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c index 2843f1ae75bd..887ebadd4774 100644 --- a/drivers/infiniband/ulp/srpt/ib_srpt.c +++ b/drivers/infiniband/ulp/srpt/ib_srpt.c | |||
| @@ -254,8 +254,8 @@ static void srpt_get_class_port_info(struct ib_dm_mad *mad) | |||
| 254 | memset(cif, 0, sizeof(*cif)); | 254 | memset(cif, 0, sizeof(*cif)); |
| 255 | cif->base_version = 1; | 255 | cif->base_version = 1; |
| 256 | cif->class_version = 1; | 256 | cif->class_version = 1; |
| 257 | cif->resp_time_value = 20; | ||
| 258 | 257 | ||
| 258 | ib_set_cpi_resp_time(cif, 20); | ||
| 259 | mad->mad_hdr.status = 0; | 259 | mad->mad_hdr.status = 0; |
| 260 | } | 260 | } |
| 261 | 261 | ||
diff --git a/include/rdma/ib_mad.h b/include/rdma/ib_mad.h index 37dd534cbeab..c8a773ffe23b 100644 --- a/include/rdma/ib_mad.h +++ b/include/rdma/ib_mad.h | |||
| @@ -239,12 +239,15 @@ struct ib_vendor_mad { | |||
| 239 | 239 | ||
| 240 | #define IB_MGMT_CLASSPORTINFO_ATTR_ID cpu_to_be16(0x0001) | 240 | #define IB_MGMT_CLASSPORTINFO_ATTR_ID cpu_to_be16(0x0001) |
| 241 | 241 | ||
| 242 | #define IB_CLASS_PORT_INFO_RESP_TIME_MASK 0x1F | ||
| 243 | #define IB_CLASS_PORT_INFO_RESP_TIME_FIELD_SIZE 5 | ||
| 244 | |||
| 242 | struct ib_class_port_info { | 245 | struct ib_class_port_info { |
| 243 | u8 base_version; | 246 | u8 base_version; |
| 244 | u8 class_version; | 247 | u8 class_version; |
| 245 | __be16 capability_mask; | 248 | __be16 capability_mask; |
| 246 | u8 reserved[3]; | 249 | /* 27 bits for cap_mask2, 5 bits for resp_time */ |
| 247 | u8 resp_time_value; | 250 | __be32 cap_mask2_resp_time; |
| 248 | u8 redirect_gid[16]; | 251 | u8 redirect_gid[16]; |
| 249 | __be32 redirect_tcslfl; | 252 | __be32 redirect_tcslfl; |
| 250 | __be16 redirect_lid; | 253 | __be16 redirect_lid; |
| @@ -259,6 +262,59 @@ struct ib_class_port_info { | |||
| 259 | __be32 trap_qkey; | 262 | __be32 trap_qkey; |
| 260 | }; | 263 | }; |
| 261 | 264 | ||
| 265 | /** | ||
| 266 | * ib_get_cpi_resp_time - Returns the resp_time value from | ||
| 267 | * cap_mask2_resp_time in ib_class_port_info. | ||
| 268 | * @cpi: A struct ib_class_port_info mad. | ||
| 269 | */ | ||
| 270 | static inline u8 ib_get_cpi_resp_time(struct ib_class_port_info *cpi) | ||
| 271 | { | ||
| 272 | return (u8)(be32_to_cpu(cpi->cap_mask2_resp_time) & | ||
| 273 | IB_CLASS_PORT_INFO_RESP_TIME_MASK); | ||
| 274 | } | ||
| 275 | |||
| 276 | /** | ||
| 277 | * ib_set_cpi_resptime - Sets the response time in an | ||
| 278 | * ib_class_port_info mad. | ||
| 279 | * @cpi: A struct ib_class_port_info. | ||
| 280 | * @rtime: The response time to set. | ||
| 281 | */ | ||
| 282 | static inline void ib_set_cpi_resp_time(struct ib_class_port_info *cpi, | ||
| 283 | u8 rtime) | ||
| 284 | { | ||
| 285 | cpi->cap_mask2_resp_time = | ||
| 286 | (cpi->cap_mask2_resp_time & | ||
| 287 | cpu_to_be32(~IB_CLASS_PORT_INFO_RESP_TIME_MASK)) | | ||
| 288 | cpu_to_be32(rtime & IB_CLASS_PORT_INFO_RESP_TIME_MASK); | ||
| 289 | } | ||
| 290 | |||
| 291 | /** | ||
| 292 | * ib_get_cpi_capmask2 - Returns the capmask2 value from | ||
| 293 | * cap_mask2_resp_time in ib_class_port_info. | ||
| 294 | * @cpi: A struct ib_class_port_info mad. | ||
| 295 | */ | ||
| 296 | static inline u32 ib_get_cpi_capmask2(struct ib_class_port_info *cpi) | ||
| 297 | { | ||
| 298 | return (be32_to_cpu(cpi->cap_mask2_resp_time) >> | ||
| 299 | IB_CLASS_PORT_INFO_RESP_TIME_FIELD_SIZE); | ||
| 300 | } | ||
| 301 | |||
| 302 | /** | ||
| 303 | * ib_set_cpi_capmask2 - Sets the capmask2 in an | ||
| 304 | * ib_class_port_info mad. | ||
| 305 | * @cpi: A struct ib_class_port_info. | ||
| 306 | * @capmask2: The capmask2 to set. | ||
| 307 | */ | ||
| 308 | static inline void ib_set_cpi_capmask2(struct ib_class_port_info *cpi, | ||
| 309 | u32 capmask2) | ||
| 310 | { | ||
| 311 | cpi->cap_mask2_resp_time = | ||
| 312 | (cpi->cap_mask2_resp_time & | ||
| 313 | cpu_to_be32(IB_CLASS_PORT_INFO_RESP_TIME_MASK)) | | ||
| 314 | cpu_to_be32(capmask2 << | ||
| 315 | IB_CLASS_PORT_INFO_RESP_TIME_FIELD_SIZE); | ||
| 316 | } | ||
| 317 | |||
| 262 | struct ib_mad_notice_attr { | 318 | struct ib_mad_notice_attr { |
| 263 | u8 generic_type; | 319 | u8 generic_type; |
| 264 | u8 prod_type_msb; | 320 | u8 prod_type_msb; |
diff --git a/include/rdma/ib_sa.h b/include/rdma/ib_sa.h index cdc1c81aa275..384041669489 100644 --- a/include/rdma/ib_sa.h +++ b/include/rdma/ib_sa.h | |||
| @@ -94,6 +94,8 @@ enum ib_sa_selector { | |||
| 94 | IB_SA_BEST = 3 | 94 | IB_SA_BEST = 3 |
| 95 | }; | 95 | }; |
| 96 | 96 | ||
| 97 | #define IB_SA_CAP_MASK2_SENDONLY_FULL_MEM_SUPPORT BIT(12) | ||
| 98 | |||
| 97 | /* | 99 | /* |
| 98 | * Structures for SA records are named "struct ib_sa_xxx_rec." No | 100 | * Structures for SA records are named "struct ib_sa_xxx_rec." No |
| 99 | * attempt is made to pack structures to match the physical layout of | 101 | * attempt is made to pack structures to match the physical layout of |
| @@ -439,4 +441,14 @@ int ib_sa_guid_info_rec_query(struct ib_sa_client *client, | |||
| 439 | void *context, | 441 | void *context, |
| 440 | struct ib_sa_query **sa_query); | 442 | struct ib_sa_query **sa_query); |
| 441 | 443 | ||
| 444 | /* Support get SA ClassPortInfo */ | ||
| 445 | int ib_sa_classport_info_rec_query(struct ib_sa_client *client, | ||
| 446 | struct ib_device *device, u8 port_num, | ||
| 447 | int timeout_ms, gfp_t gfp_mask, | ||
| 448 | void (*callback)(int status, | ||
| 449 | struct ib_class_port_info *resp, | ||
| 450 | void *context), | ||
| 451 | void *context, | ||
| 452 | struct ib_sa_query **sa_query); | ||
| 453 | |||
| 442 | #endif /* IB_SA_H */ | 454 | #endif /* IB_SA_H */ |
diff --git a/include/uapi/rdma/rdma_netlink.h b/include/uapi/rdma/rdma_netlink.h index 6e373d151cad..02fe8390c18f 100644 --- a/include/uapi/rdma/rdma_netlink.h +++ b/include/uapi/rdma/rdma_netlink.h | |||
| @@ -135,10 +135,12 @@ enum { | |||
| 135 | * Local service operations: | 135 | * Local service operations: |
| 136 | * RESOLVE - The client requests the local service to resolve a path. | 136 | * RESOLVE - The client requests the local service to resolve a path. |
| 137 | * SET_TIMEOUT - The local service requests the client to set the timeout. | 137 | * SET_TIMEOUT - The local service requests the client to set the timeout. |
| 138 | * IP_RESOLVE - The client requests the local service to resolve an IP to GID. | ||
| 138 | */ | 139 | */ |
| 139 | enum { | 140 | enum { |
| 140 | RDMA_NL_LS_OP_RESOLVE = 0, | 141 | RDMA_NL_LS_OP_RESOLVE = 0, |
| 141 | RDMA_NL_LS_OP_SET_TIMEOUT, | 142 | RDMA_NL_LS_OP_SET_TIMEOUT, |
| 143 | RDMA_NL_LS_OP_IP_RESOLVE, | ||
| 142 | RDMA_NL_LS_NUM_OPS | 144 | RDMA_NL_LS_NUM_OPS |
| 143 | }; | 145 | }; |
| 144 | 146 | ||
| @@ -176,6 +178,10 @@ struct rdma_ls_resolve_header { | |||
| 176 | __u8 path_use; | 178 | __u8 path_use; |
| 177 | }; | 179 | }; |
| 178 | 180 | ||
| 181 | struct rdma_ls_ip_resolve_header { | ||
| 182 | __u32 ifindex; | ||
| 183 | }; | ||
| 184 | |||
| 179 | /* Local service attribute type */ | 185 | /* Local service attribute type */ |
| 180 | #define RDMA_NLA_F_MANDATORY (1 << 13) | 186 | #define RDMA_NLA_F_MANDATORY (1 << 13) |
| 181 | #define RDMA_NLA_TYPE_MASK (~(NLA_F_NESTED | NLA_F_NET_BYTEORDER | \ | 187 | #define RDMA_NLA_TYPE_MASK (~(NLA_F_NESTED | NLA_F_NET_BYTEORDER | \ |
| @@ -193,6 +199,8 @@ struct rdma_ls_resolve_header { | |||
| 193 | * TCLASS u8 | 199 | * TCLASS u8 |
| 194 | * PKEY u16 cpu | 200 | * PKEY u16 cpu |
| 195 | * QOS_CLASS u16 cpu | 201 | * QOS_CLASS u16 cpu |
| 202 | * IPV4 u32 BE | ||
| 203 | * IPV6 u8[16] BE | ||
| 196 | */ | 204 | */ |
| 197 | enum { | 205 | enum { |
| 198 | LS_NLA_TYPE_UNSPEC = 0, | 206 | LS_NLA_TYPE_UNSPEC = 0, |
| @@ -204,6 +212,8 @@ enum { | |||
| 204 | LS_NLA_TYPE_TCLASS, | 212 | LS_NLA_TYPE_TCLASS, |
| 205 | LS_NLA_TYPE_PKEY, | 213 | LS_NLA_TYPE_PKEY, |
| 206 | LS_NLA_TYPE_QOS_CLASS, | 214 | LS_NLA_TYPE_QOS_CLASS, |
| 215 | LS_NLA_TYPE_IPV4, | ||
| 216 | LS_NLA_TYPE_IPV6, | ||
| 207 | LS_NLA_TYPE_MAX | 217 | LS_NLA_TYPE_MAX |
| 208 | }; | 218 | }; |
| 209 | 219 | ||
