diff options
| author | Bryan O'Sullivan <bos@pathscale.com> | 2006-03-29 18:23:38 -0500 |
|---|---|---|
| committer | Roland Dreier <rolandd@cisco.com> | 2006-03-31 16:14:21 -0500 |
| commit | 6522108f19a998a5ded4d0c4d0f9eb9736398e31 (patch) | |
| tree | 675eb475939abf9889edf7b76a49e383b7c6e7e5 | |
| parent | e28c00ad67164dba688c1d19c208c5fb554465f2 (diff) | |
IB/ipath: infiniband verbs support
The ipath_verbs.c file implements the driver-specific components of the
kernel's Infiniband verbs layer.
Signed-off-by: Bryan O'Sullivan <bos@pathscale.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
| -rw-r--r-- | drivers/infiniband/hw/ipath/ipath_verbs.c | 1222 | ||||
| -rw-r--r-- | drivers/infiniband/hw/ipath/ipath_verbs_mcast.c | 333 |
2 files changed, 1555 insertions, 0 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c new file mode 100644 index 000000000000..9f27fd35cdbb --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_verbs.c | |||
| @@ -0,0 +1,1222 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved. | ||
| 3 | * | ||
| 4 | * This software is available to you under a choice of one of two | ||
| 5 | * licenses. You may choose to be licensed under the terms of the GNU | ||
| 6 | * General Public License (GPL) Version 2, available from the file | ||
| 7 | * COPYING in the main directory of this source tree, or the | ||
| 8 | * OpenIB.org BSD license below: | ||
| 9 | * | ||
| 10 | * Redistribution and use in source and binary forms, with or | ||
| 11 | * without modification, are permitted provided that the following | ||
| 12 | * conditions are met: | ||
| 13 | * | ||
| 14 | * - Redistributions of source code must retain the above | ||
| 15 | * copyright notice, this list of conditions and the following | ||
| 16 | * disclaimer. | ||
| 17 | * | ||
| 18 | * - Redistributions in binary form must reproduce the above | ||
| 19 | * copyright notice, this list of conditions and the following | ||
| 20 | * disclaimer in the documentation and/or other materials | ||
| 21 | * provided with the distribution. | ||
| 22 | * | ||
| 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
| 24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
| 25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
| 26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
| 27 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
| 28 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
| 29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 30 | * SOFTWARE. | ||
| 31 | */ | ||
| 32 | |||
| 33 | #include <rdma/ib_mad.h> | ||
| 34 | #include <rdma/ib_user_verbs.h> | ||
| 35 | #include <linux/utsname.h> | ||
| 36 | |||
| 37 | #include "ipath_kernel.h" | ||
| 38 | #include "ipath_verbs.h" | ||
| 39 | #include "ips_common.h" | ||
| 40 | |||
| 41 | /* Not static, because we don't want the compiler removing it */ | ||
| 42 | const char ipath_verbs_version[] = "ipath_verbs " IPATH_IDSTR; | ||
| 43 | |||
| 44 | unsigned int ib_ipath_qp_table_size = 251; | ||
| 45 | module_param_named(qp_table_size, ib_ipath_qp_table_size, uint, S_IRUGO); | ||
| 46 | MODULE_PARM_DESC(qp_table_size, "QP table size"); | ||
| 47 | |||
| 48 | unsigned int ib_ipath_lkey_table_size = 12; | ||
| 49 | module_param_named(lkey_table_size, ib_ipath_lkey_table_size, uint, | ||
| 50 | S_IRUGO); | ||
| 51 | MODULE_PARM_DESC(lkey_table_size, | ||
| 52 | "LKEY table size in bits (2^n, 1 <= n <= 23)"); | ||
| 53 | |||
| 54 | unsigned int ib_ipath_debug; /* debug mask */ | ||
| 55 | module_param_named(debug, ib_ipath_debug, uint, S_IWUSR | S_IRUGO); | ||
| 56 | MODULE_PARM_DESC(debug, "Verbs debug mask"); | ||
| 57 | |||
| 58 | MODULE_LICENSE("GPL"); | ||
| 59 | MODULE_AUTHOR("PathScale <support@pathscale.com>"); | ||
| 60 | MODULE_DESCRIPTION("Pathscale InfiniPath driver"); | ||
| 61 | |||
| 62 | const int ib_ipath_state_ops[IB_QPS_ERR + 1] = { | ||
| 63 | [IB_QPS_RESET] = 0, | ||
| 64 | [IB_QPS_INIT] = IPATH_POST_RECV_OK, | ||
| 65 | [IB_QPS_RTR] = IPATH_POST_RECV_OK | IPATH_PROCESS_RECV_OK, | ||
| 66 | [IB_QPS_RTS] = IPATH_POST_RECV_OK | IPATH_PROCESS_RECV_OK | | ||
| 67 | IPATH_POST_SEND_OK | IPATH_PROCESS_SEND_OK, | ||
| 68 | [IB_QPS_SQD] = IPATH_POST_RECV_OK | IPATH_PROCESS_RECV_OK | | ||
| 69 | IPATH_POST_SEND_OK, | ||
| 70 | [IB_QPS_SQE] = IPATH_POST_RECV_OK | IPATH_PROCESS_RECV_OK, | ||
| 71 | [IB_QPS_ERR] = 0, | ||
| 72 | }; | ||
| 73 | |||
| 74 | /* | ||
| 75 | * Translate ib_wr_opcode into ib_wc_opcode. | ||
| 76 | */ | ||
| 77 | const enum ib_wc_opcode ib_ipath_wc_opcode[] = { | ||
| 78 | [IB_WR_RDMA_WRITE] = IB_WC_RDMA_WRITE, | ||
| 79 | [IB_WR_RDMA_WRITE_WITH_IMM] = IB_WC_RDMA_WRITE, | ||
| 80 | [IB_WR_SEND] = IB_WC_SEND, | ||
| 81 | [IB_WR_SEND_WITH_IMM] = IB_WC_SEND, | ||
| 82 | [IB_WR_RDMA_READ] = IB_WC_RDMA_READ, | ||
| 83 | [IB_WR_ATOMIC_CMP_AND_SWP] = IB_WC_COMP_SWAP, | ||
| 84 | [IB_WR_ATOMIC_FETCH_AND_ADD] = IB_WC_FETCH_ADD | ||
| 85 | }; | ||
| 86 | |||
| 87 | /* | ||
| 88 | * System image GUID. | ||
| 89 | */ | ||
| 90 | __be64 sys_image_guid; | ||
| 91 | |||
| 92 | /** | ||
| 93 | * ipath_copy_sge - copy data to SGE memory | ||
| 94 | * @ss: the SGE state | ||
| 95 | * @data: the data to copy | ||
| 96 | * @length: the length of the data | ||
| 97 | */ | ||
| 98 | void ipath_copy_sge(struct ipath_sge_state *ss, void *data, u32 length) | ||
| 99 | { | ||
| 100 | struct ipath_sge *sge = &ss->sge; | ||
| 101 | |||
| 102 | while (length) { | ||
| 103 | u32 len = sge->length; | ||
| 104 | |||
| 105 | BUG_ON(len == 0); | ||
| 106 | if (len > length) | ||
| 107 | len = length; | ||
| 108 | memcpy(sge->vaddr, data, len); | ||
| 109 | sge->vaddr += len; | ||
| 110 | sge->length -= len; | ||
| 111 | sge->sge_length -= len; | ||
| 112 | if (sge->sge_length == 0) { | ||
| 113 | if (--ss->num_sge) | ||
| 114 | *sge = *ss->sg_list++; | ||
| 115 | } else if (sge->length == 0 && sge->mr != NULL) { | ||
| 116 | if (++sge->n >= IPATH_SEGSZ) { | ||
| 117 | if (++sge->m >= sge->mr->mapsz) | ||
| 118 | break; | ||
| 119 | sge->n = 0; | ||
| 120 | } | ||
| 121 | sge->vaddr = | ||
| 122 | sge->mr->map[sge->m]->segs[sge->n].vaddr; | ||
| 123 | sge->length = | ||
| 124 | sge->mr->map[sge->m]->segs[sge->n].length; | ||
| 125 | } | ||
| 126 | data += len; | ||
| 127 | length -= len; | ||
| 128 | } | ||
| 129 | } | ||
| 130 | |||
| 131 | /** | ||
| 132 | * ipath_skip_sge - skip over SGE memory - XXX almost dup of prev func | ||
| 133 | * @ss: the SGE state | ||
| 134 | * @length: the number of bytes to skip | ||
| 135 | */ | ||
| 136 | void ipath_skip_sge(struct ipath_sge_state *ss, u32 length) | ||
| 137 | { | ||
| 138 | struct ipath_sge *sge = &ss->sge; | ||
| 139 | |||
| 140 | while (length > sge->sge_length) { | ||
| 141 | length -= sge->sge_length; | ||
| 142 | ss->sge = *ss->sg_list++; | ||
| 143 | } | ||
| 144 | while (length) { | ||
| 145 | u32 len = sge->length; | ||
| 146 | |||
| 147 | BUG_ON(len == 0); | ||
| 148 | if (len > length) | ||
| 149 | len = length; | ||
| 150 | sge->vaddr += len; | ||
| 151 | sge->length -= len; | ||
| 152 | sge->sge_length -= len; | ||
| 153 | if (sge->sge_length == 0) { | ||
| 154 | if (--ss->num_sge) | ||
| 155 | *sge = *ss->sg_list++; | ||
| 156 | } else if (sge->length == 0 && sge->mr != NULL) { | ||
| 157 | if (++sge->n >= IPATH_SEGSZ) { | ||
| 158 | if (++sge->m >= sge->mr->mapsz) | ||
| 159 | break; | ||
| 160 | sge->n = 0; | ||
| 161 | } | ||
| 162 | sge->vaddr = | ||
| 163 | sge->mr->map[sge->m]->segs[sge->n].vaddr; | ||
| 164 | sge->length = | ||
| 165 | sge->mr->map[sge->m]->segs[sge->n].length; | ||
| 166 | } | ||
| 167 | length -= len; | ||
| 168 | } | ||
| 169 | } | ||
| 170 | |||
| 171 | /** | ||
| 172 | * ipath_post_send - post a send on a QP | ||
| 173 | * @ibqp: the QP to post the send on | ||
| 174 | * @wr: the list of work requests to post | ||
| 175 | * @bad_wr: the first bad WR is put here | ||
| 176 | * | ||
| 177 | * This may be called from interrupt context. | ||
| 178 | */ | ||
| 179 | static int ipath_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr, | ||
| 180 | struct ib_send_wr **bad_wr) | ||
| 181 | { | ||
| 182 | struct ipath_qp *qp = to_iqp(ibqp); | ||
| 183 | int err = 0; | ||
| 184 | |||
| 185 | /* Check that state is OK to post send. */ | ||
| 186 | if (!(ib_ipath_state_ops[qp->state] & IPATH_POST_SEND_OK)) { | ||
| 187 | *bad_wr = wr; | ||
| 188 | err = -EINVAL; | ||
| 189 | goto bail; | ||
| 190 | } | ||
| 191 | |||
| 192 | for (; wr; wr = wr->next) { | ||
| 193 | switch (qp->ibqp.qp_type) { | ||
| 194 | case IB_QPT_UC: | ||
| 195 | case IB_QPT_RC: | ||
| 196 | err = ipath_post_rc_send(qp, wr); | ||
| 197 | break; | ||
| 198 | |||
| 199 | case IB_QPT_SMI: | ||
| 200 | case IB_QPT_GSI: | ||
| 201 | case IB_QPT_UD: | ||
| 202 | err = ipath_post_ud_send(qp, wr); | ||
| 203 | break; | ||
| 204 | |||
| 205 | default: | ||
| 206 | err = -EINVAL; | ||
| 207 | } | ||
| 208 | if (err) { | ||
| 209 | *bad_wr = wr; | ||
| 210 | break; | ||
| 211 | } | ||
| 212 | } | ||
| 213 | |||
| 214 | bail: | ||
| 215 | return err; | ||
| 216 | } | ||
| 217 | |||
| 218 | /** | ||
| 219 | * ipath_post_receive - post a receive on a QP | ||
| 220 | * @ibqp: the QP to post the receive on | ||
| 221 | * @wr: the WR to post | ||
| 222 | * @bad_wr: the first bad WR is put here | ||
| 223 | * | ||
| 224 | * This may be called from interrupt context. | ||
| 225 | */ | ||
| 226 | static int ipath_post_receive(struct ib_qp *ibqp, struct ib_recv_wr *wr, | ||
| 227 | struct ib_recv_wr **bad_wr) | ||
| 228 | { | ||
| 229 | struct ipath_qp *qp = to_iqp(ibqp); | ||
| 230 | unsigned long flags; | ||
| 231 | int ret; | ||
| 232 | |||
| 233 | /* Check that state is OK to post receive. */ | ||
| 234 | if (!(ib_ipath_state_ops[qp->state] & IPATH_POST_RECV_OK)) { | ||
| 235 | *bad_wr = wr; | ||
| 236 | ret = -EINVAL; | ||
| 237 | goto bail; | ||
| 238 | } | ||
| 239 | |||
| 240 | for (; wr; wr = wr->next) { | ||
| 241 | struct ipath_rwqe *wqe; | ||
| 242 | u32 next; | ||
| 243 | int i, j; | ||
| 244 | |||
| 245 | if (wr->num_sge > qp->r_rq.max_sge) { | ||
| 246 | *bad_wr = wr; | ||
| 247 | ret = -ENOMEM; | ||
| 248 | goto bail; | ||
| 249 | } | ||
| 250 | |||
| 251 | spin_lock_irqsave(&qp->r_rq.lock, flags); | ||
| 252 | next = qp->r_rq.head + 1; | ||
| 253 | if (next >= qp->r_rq.size) | ||
| 254 | next = 0; | ||
| 255 | if (next == qp->r_rq.tail) { | ||
| 256 | spin_unlock_irqrestore(&qp->r_rq.lock, flags); | ||
| 257 | *bad_wr = wr; | ||
| 258 | ret = -ENOMEM; | ||
| 259 | goto bail; | ||
| 260 | } | ||
| 261 | |||
| 262 | wqe = get_rwqe_ptr(&qp->r_rq, qp->r_rq.head); | ||
| 263 | wqe->wr_id = wr->wr_id; | ||
| 264 | wqe->sg_list[0].mr = NULL; | ||
| 265 | wqe->sg_list[0].vaddr = NULL; | ||
| 266 | wqe->sg_list[0].length = 0; | ||
| 267 | wqe->sg_list[0].sge_length = 0; | ||
| 268 | wqe->length = 0; | ||
| 269 | for (i = 0, j = 0; i < wr->num_sge; i++) { | ||
| 270 | /* Check LKEY */ | ||
| 271 | if (to_ipd(qp->ibqp.pd)->user && | ||
| 272 | wr->sg_list[i].lkey == 0) { | ||
| 273 | spin_unlock_irqrestore(&qp->r_rq.lock, | ||
| 274 | flags); | ||
| 275 | *bad_wr = wr; | ||
| 276 | ret = -EINVAL; | ||
| 277 | goto bail; | ||
| 278 | } | ||
| 279 | if (wr->sg_list[i].length == 0) | ||
| 280 | continue; | ||
| 281 | if (!ipath_lkey_ok( | ||
| 282 | &to_idev(qp->ibqp.device)->lk_table, | ||
| 283 | &wqe->sg_list[j], &wr->sg_list[i], | ||
| 284 | IB_ACCESS_LOCAL_WRITE)) { | ||
| 285 | spin_unlock_irqrestore(&qp->r_rq.lock, | ||
| 286 | flags); | ||
| 287 | *bad_wr = wr; | ||
| 288 | ret = -EINVAL; | ||
| 289 | goto bail; | ||
| 290 | } | ||
| 291 | wqe->length += wr->sg_list[i].length; | ||
| 292 | j++; | ||
| 293 | } | ||
| 294 | wqe->num_sge = j; | ||
| 295 | qp->r_rq.head = next; | ||
| 296 | spin_unlock_irqrestore(&qp->r_rq.lock, flags); | ||
| 297 | } | ||
| 298 | ret = 0; | ||
| 299 | |||
| 300 | bail: | ||
| 301 | return ret; | ||
| 302 | } | ||
| 303 | |||
| 304 | /** | ||
| 305 | * ipath_qp_rcv - processing an incoming packet on a QP | ||
| 306 | * @dev: the device the packet came on | ||
| 307 | * @hdr: the packet header | ||
| 308 | * @has_grh: true if the packet has a GRH | ||
| 309 | * @data: the packet data | ||
| 310 | * @tlen: the packet length | ||
| 311 | * @qp: the QP the packet came on | ||
| 312 | * | ||
| 313 | * This is called from ipath_ib_rcv() to process an incoming packet | ||
| 314 | * for the given QP. | ||
| 315 | * Called at interrupt level. | ||
| 316 | */ | ||
| 317 | static void ipath_qp_rcv(struct ipath_ibdev *dev, | ||
| 318 | struct ipath_ib_header *hdr, int has_grh, | ||
| 319 | void *data, u32 tlen, struct ipath_qp *qp) | ||
| 320 | { | ||
| 321 | /* Check for valid receive state. */ | ||
| 322 | if (!(ib_ipath_state_ops[qp->state] & IPATH_PROCESS_RECV_OK)) { | ||
| 323 | dev->n_pkt_drops++; | ||
| 324 | return; | ||
| 325 | } | ||
| 326 | |||
| 327 | switch (qp->ibqp.qp_type) { | ||
| 328 | case IB_QPT_SMI: | ||
| 329 | case IB_QPT_GSI: | ||
| 330 | case IB_QPT_UD: | ||
| 331 | ipath_ud_rcv(dev, hdr, has_grh, data, tlen, qp); | ||
| 332 | break; | ||
| 333 | |||
| 334 | case IB_QPT_RC: | ||
| 335 | ipath_rc_rcv(dev, hdr, has_grh, data, tlen, qp); | ||
| 336 | break; | ||
| 337 | |||
| 338 | case IB_QPT_UC: | ||
| 339 | ipath_uc_rcv(dev, hdr, has_grh, data, tlen, qp); | ||
| 340 | break; | ||
| 341 | |||
| 342 | default: | ||
| 343 | break; | ||
| 344 | } | ||
| 345 | } | ||
| 346 | |||
| 347 | /** | ||
| 348 | * ipath_ib_rcv - process and incoming packet | ||
| 349 | * @arg: the device pointer | ||
| 350 | * @rhdr: the header of the packet | ||
| 351 | * @data: the packet data | ||
| 352 | * @tlen: the packet length | ||
| 353 | * | ||
| 354 | * This is called from ipath_kreceive() to process an incoming packet at | ||
| 355 | * interrupt level. Tlen is the length of the header + data + CRC in bytes. | ||
| 356 | */ | ||
| 357 | static void ipath_ib_rcv(void *arg, void *rhdr, void *data, u32 tlen) | ||
| 358 | { | ||
| 359 | struct ipath_ibdev *dev = (struct ipath_ibdev *) arg; | ||
| 360 | struct ipath_ib_header *hdr = rhdr; | ||
| 361 | struct ipath_other_headers *ohdr; | ||
| 362 | struct ipath_qp *qp; | ||
| 363 | u32 qp_num; | ||
| 364 | int lnh; | ||
| 365 | u8 opcode; | ||
| 366 | u16 lid; | ||
| 367 | |||
| 368 | if (unlikely(dev == NULL)) | ||
| 369 | goto bail; | ||
| 370 | |||
| 371 | if (unlikely(tlen < 24)) { /* LRH+BTH+CRC */ | ||
| 372 | dev->rcv_errors++; | ||
| 373 | goto bail; | ||
| 374 | } | ||
| 375 | |||
| 376 | /* Check for a valid destination LID (see ch. 7.11.1). */ | ||
| 377 | lid = be16_to_cpu(hdr->lrh[1]); | ||
| 378 | if (lid < IPS_MULTICAST_LID_BASE) { | ||
| 379 | lid &= ~((1 << (dev->mkeyprot_resv_lmc & 7)) - 1); | ||
| 380 | if (unlikely(lid != ipath_layer_get_lid(dev->dd))) { | ||
| 381 | dev->rcv_errors++; | ||
| 382 | goto bail; | ||
| 383 | } | ||
| 384 | } | ||
| 385 | |||
| 386 | /* Check for GRH */ | ||
| 387 | lnh = be16_to_cpu(hdr->lrh[0]) & 3; | ||
| 388 | if (lnh == IPS_LRH_BTH) | ||
| 389 | ohdr = &hdr->u.oth; | ||
| 390 | else if (lnh == IPS_LRH_GRH) | ||
| 391 | ohdr = &hdr->u.l.oth; | ||
| 392 | else { | ||
| 393 | dev->rcv_errors++; | ||
| 394 | goto bail; | ||
| 395 | } | ||
| 396 | |||
| 397 | opcode = be32_to_cpu(ohdr->bth[0]) >> 24; | ||
| 398 | dev->opstats[opcode].n_bytes += tlen; | ||
| 399 | dev->opstats[opcode].n_packets++; | ||
| 400 | |||
| 401 | /* Get the destination QP number. */ | ||
| 402 | qp_num = be32_to_cpu(ohdr->bth[1]) & IPS_QPN_MASK; | ||
| 403 | if (qp_num == IPS_MULTICAST_QPN) { | ||
| 404 | struct ipath_mcast *mcast; | ||
| 405 | struct ipath_mcast_qp *p; | ||
| 406 | |||
| 407 | mcast = ipath_mcast_find(&hdr->u.l.grh.dgid); | ||
| 408 | if (mcast == NULL) { | ||
| 409 | dev->n_pkt_drops++; | ||
| 410 | goto bail; | ||
| 411 | } | ||
| 412 | dev->n_multicast_rcv++; | ||
| 413 | list_for_each_entry_rcu(p, &mcast->qp_list, list) | ||
| 414 | ipath_qp_rcv(dev, hdr, lnh == IPS_LRH_GRH, data, | ||
| 415 | tlen, p->qp); | ||
| 416 | /* | ||
| 417 | * Notify ipath_multicast_detach() if it is waiting for us | ||
| 418 | * to finish. | ||
| 419 | */ | ||
| 420 | if (atomic_dec_return(&mcast->refcount) <= 1) | ||
| 421 | wake_up(&mcast->wait); | ||
| 422 | } else { | ||
| 423 | qp = ipath_lookup_qpn(&dev->qp_table, qp_num); | ||
| 424 | if (qp) { | ||
| 425 | dev->n_unicast_rcv++; | ||
| 426 | ipath_qp_rcv(dev, hdr, lnh == IPS_LRH_GRH, data, | ||
| 427 | tlen, qp); | ||
| 428 | /* | ||
| 429 | * Notify ipath_destroy_qp() if it is waiting | ||
| 430 | * for us to finish. | ||
| 431 | */ | ||
| 432 | if (atomic_dec_and_test(&qp->refcount)) | ||
| 433 | wake_up(&qp->wait); | ||
| 434 | } else | ||
| 435 | dev->n_pkt_drops++; | ||
| 436 | } | ||
| 437 | |||
| 438 | bail:; | ||
| 439 | } | ||
| 440 | |||
| 441 | /** | ||
| 442 | * ipath_ib_timer - verbs timer | ||
| 443 | * @arg: the device pointer | ||
| 444 | * | ||
| 445 | * This is called from ipath_do_rcv_timer() at interrupt level to check for | ||
| 446 | * QPs which need retransmits and to collect performance numbers. | ||
| 447 | */ | ||
| 448 | static void ipath_ib_timer(void *arg) | ||
| 449 | { | ||
| 450 | struct ipath_ibdev *dev = (struct ipath_ibdev *) arg; | ||
| 451 | struct ipath_qp *resend = NULL; | ||
| 452 | struct ipath_qp *rnr = NULL; | ||
| 453 | struct list_head *last; | ||
| 454 | struct ipath_qp *qp; | ||
| 455 | unsigned long flags; | ||
| 456 | |||
| 457 | if (dev == NULL) | ||
| 458 | return; | ||
| 459 | |||
| 460 | spin_lock_irqsave(&dev->pending_lock, flags); | ||
| 461 | /* Start filling the next pending queue. */ | ||
| 462 | if (++dev->pending_index >= ARRAY_SIZE(dev->pending)) | ||
| 463 | dev->pending_index = 0; | ||
| 464 | /* Save any requests still in the new queue, they have timed out. */ | ||
| 465 | last = &dev->pending[dev->pending_index]; | ||
| 466 | while (!list_empty(last)) { | ||
| 467 | qp = list_entry(last->next, struct ipath_qp, timerwait); | ||
| 468 | if (last->next == LIST_POISON1 || | ||
| 469 | last->next != &qp->timerwait || | ||
| 470 | qp->timerwait.prev != last) { | ||
| 471 | INIT_LIST_HEAD(last); | ||
| 472 | } else { | ||
| 473 | list_del(&qp->timerwait); | ||
| 474 | qp->timerwait.prev = (struct list_head *) resend; | ||
| 475 | resend = qp; | ||
| 476 | atomic_inc(&qp->refcount); | ||
| 477 | } | ||
| 478 | } | ||
| 479 | last = &dev->rnrwait; | ||
| 480 | if (!list_empty(last)) { | ||
| 481 | qp = list_entry(last->next, struct ipath_qp, timerwait); | ||
| 482 | if (--qp->s_rnr_timeout == 0) { | ||
| 483 | do { | ||
| 484 | if (last->next == LIST_POISON1 || | ||
| 485 | last->next != &qp->timerwait || | ||
| 486 | qp->timerwait.prev != last) { | ||
| 487 | INIT_LIST_HEAD(last); | ||
| 488 | break; | ||
| 489 | } | ||
| 490 | list_del(&qp->timerwait); | ||
| 491 | qp->timerwait.prev = | ||
| 492 | (struct list_head *) rnr; | ||
| 493 | rnr = qp; | ||
| 494 | if (list_empty(last)) | ||
| 495 | break; | ||
| 496 | qp = list_entry(last->next, struct ipath_qp, | ||
| 497 | timerwait); | ||
| 498 | } while (qp->s_rnr_timeout == 0); | ||
| 499 | } | ||
| 500 | } | ||
| 501 | /* | ||
| 502 | * We should only be in the started state if pma_sample_start != 0 | ||
| 503 | */ | ||
| 504 | if (dev->pma_sample_status == IB_PMA_SAMPLE_STATUS_STARTED && | ||
| 505 | --dev->pma_sample_start == 0) { | ||
| 506 | dev->pma_sample_status = IB_PMA_SAMPLE_STATUS_RUNNING; | ||
| 507 | ipath_layer_snapshot_counters(dev->dd, &dev->ipath_sword, | ||
| 508 | &dev->ipath_rword, | ||
| 509 | &dev->ipath_spkts, | ||
| 510 | &dev->ipath_rpkts, | ||
| 511 | &dev->ipath_xmit_wait); | ||
| 512 | } | ||
| 513 | if (dev->pma_sample_status == IB_PMA_SAMPLE_STATUS_RUNNING) { | ||
| 514 | if (dev->pma_sample_interval == 0) { | ||
| 515 | u64 ta, tb, tc, td, te; | ||
| 516 | |||
| 517 | dev->pma_sample_status = IB_PMA_SAMPLE_STATUS_DONE; | ||
| 518 | ipath_layer_snapshot_counters(dev->dd, &ta, &tb, | ||
| 519 | &tc, &td, &te); | ||
| 520 | |||
| 521 | dev->ipath_sword = ta - dev->ipath_sword; | ||
| 522 | dev->ipath_rword = tb - dev->ipath_rword; | ||
| 523 | dev->ipath_spkts = tc - dev->ipath_spkts; | ||
| 524 | dev->ipath_rpkts = td - dev->ipath_rpkts; | ||
| 525 | dev->ipath_xmit_wait = te - dev->ipath_xmit_wait; | ||
| 526 | } | ||
| 527 | else | ||
| 528 | dev->pma_sample_interval--; | ||
| 529 | } | ||
| 530 | spin_unlock_irqrestore(&dev->pending_lock, flags); | ||
| 531 | |||
| 532 | /* XXX What if timer fires again while this is running? */ | ||
| 533 | for (qp = resend; qp != NULL; | ||
| 534 | qp = (struct ipath_qp *) qp->timerwait.prev) { | ||
| 535 | struct ib_wc wc; | ||
| 536 | |||
| 537 | spin_lock_irqsave(&qp->s_lock, flags); | ||
| 538 | if (qp->s_last != qp->s_tail && qp->state == IB_QPS_RTS) { | ||
| 539 | dev->n_timeouts++; | ||
| 540 | ipath_restart_rc(qp, qp->s_last_psn + 1, &wc); | ||
| 541 | } | ||
| 542 | spin_unlock_irqrestore(&qp->s_lock, flags); | ||
| 543 | |||
| 544 | /* Notify ipath_destroy_qp() if it is waiting. */ | ||
| 545 | if (atomic_dec_and_test(&qp->refcount)) | ||
| 546 | wake_up(&qp->wait); | ||
| 547 | } | ||
| 548 | for (qp = rnr; qp != NULL; | ||
| 549 | qp = (struct ipath_qp *) qp->timerwait.prev) | ||
| 550 | tasklet_hi_schedule(&qp->s_task); | ||
| 551 | } | ||
| 552 | |||
| 553 | /** | ||
| 554 | * ipath_ib_piobufavail - callback when a PIO buffer is available | ||
| 555 | * @arg: the device pointer | ||
| 556 | * | ||
| 557 | * This is called from ipath_intr() at interrupt level when a PIO buffer is | ||
| 558 | * available after ipath_verbs_send() returned an error that no buffers were | ||
| 559 | * available. Return 0 if we consumed all the PIO buffers and we still have | ||
| 560 | * QPs waiting for buffers (for now, just do a tasklet_hi_schedule and | ||
| 561 | * return one). | ||
| 562 | */ | ||
| 563 | static int ipath_ib_piobufavail(void *arg) | ||
| 564 | { | ||
| 565 | struct ipath_ibdev *dev = (struct ipath_ibdev *) arg; | ||
| 566 | struct ipath_qp *qp; | ||
| 567 | unsigned long flags; | ||
| 568 | |||
| 569 | if (dev == NULL) | ||
| 570 | goto bail; | ||
| 571 | |||
| 572 | spin_lock_irqsave(&dev->pending_lock, flags); | ||
| 573 | while (!list_empty(&dev->piowait)) { | ||
| 574 | qp = list_entry(dev->piowait.next, struct ipath_qp, | ||
| 575 | piowait); | ||
| 576 | list_del(&qp->piowait); | ||
| 577 | tasklet_hi_schedule(&qp->s_task); | ||
| 578 | } | ||
| 579 | spin_unlock_irqrestore(&dev->pending_lock, flags); | ||
| 580 | |||
| 581 | bail: | ||
| 582 | return 1; | ||
| 583 | } | ||
| 584 | |||
| 585 | static int ipath_query_device(struct ib_device *ibdev, | ||
| 586 | struct ib_device_attr *props) | ||
| 587 | { | ||
| 588 | struct ipath_ibdev *dev = to_idev(ibdev); | ||
| 589 | u32 vendor, boardrev, majrev, minrev; | ||
| 590 | |||
| 591 | memset(props, 0, sizeof(*props)); | ||
| 592 | |||
| 593 | props->device_cap_flags = IB_DEVICE_BAD_PKEY_CNTR | | ||
| 594 | IB_DEVICE_BAD_QKEY_CNTR | IB_DEVICE_SHUTDOWN_PORT | | ||
| 595 | IB_DEVICE_SYS_IMAGE_GUID; | ||
| 596 | ipath_layer_query_device(dev->dd, &vendor, &boardrev, | ||
| 597 | &majrev, &minrev); | ||
| 598 | props->vendor_id = vendor; | ||
| 599 | props->vendor_part_id = boardrev; | ||
| 600 | props->hw_ver = boardrev << 16 | majrev << 8 | minrev; | ||
| 601 | |||
| 602 | props->sys_image_guid = dev->sys_image_guid; | ||
| 603 | |||
| 604 | props->max_mr_size = ~0ull; | ||
| 605 | props->max_qp = 0xffff; | ||
| 606 | props->max_qp_wr = 0xffff; | ||
| 607 | props->max_sge = 255; | ||
| 608 | props->max_cq = 0xffff; | ||
| 609 | props->max_cqe = 0xffff; | ||
| 610 | props->max_mr = 0xffff; | ||
| 611 | props->max_pd = 0xffff; | ||
| 612 | props->max_qp_rd_atom = 1; | ||
| 613 | props->max_qp_init_rd_atom = 1; | ||
| 614 | /* props->max_res_rd_atom */ | ||
| 615 | props->max_srq = 0xffff; | ||
| 616 | props->max_srq_wr = 0xffff; | ||
| 617 | props->max_srq_sge = 255; | ||
| 618 | /* props->local_ca_ack_delay */ | ||
| 619 | props->atomic_cap = IB_ATOMIC_HCA; | ||
| 620 | props->max_pkeys = ipath_layer_get_npkeys(dev->dd); | ||
| 621 | props->max_mcast_grp = 0xffff; | ||
| 622 | props->max_mcast_qp_attach = 0xffff; | ||
| 623 | props->max_total_mcast_qp_attach = props->max_mcast_qp_attach * | ||
| 624 | props->max_mcast_grp; | ||
| 625 | |||
| 626 | return 0; | ||
| 627 | } | ||
| 628 | |||
| 629 | const u8 ipath_cvt_physportstate[16] = { | ||
| 630 | [INFINIPATH_IBCS_LT_STATE_DISABLED] = 3, | ||
| 631 | [INFINIPATH_IBCS_LT_STATE_LINKUP] = 5, | ||
| 632 | [INFINIPATH_IBCS_LT_STATE_POLLACTIVE] = 2, | ||
| 633 | [INFINIPATH_IBCS_LT_STATE_POLLQUIET] = 2, | ||
| 634 | [INFINIPATH_IBCS_LT_STATE_SLEEPDELAY] = 1, | ||
| 635 | [INFINIPATH_IBCS_LT_STATE_SLEEPQUIET] = 1, | ||
| 636 | [INFINIPATH_IBCS_LT_STATE_CFGDEBOUNCE] = 4, | ||
| 637 | [INFINIPATH_IBCS_LT_STATE_CFGRCVFCFG] = 4, | ||
| 638 | [INFINIPATH_IBCS_LT_STATE_CFGWAITRMT] = 4, | ||
| 639 | [INFINIPATH_IBCS_LT_STATE_CFGIDLE] = 4, | ||
| 640 | [INFINIPATH_IBCS_LT_STATE_RECOVERRETRAIN] = 6, | ||
| 641 | [INFINIPATH_IBCS_LT_STATE_RECOVERWAITRMT] = 6, | ||
| 642 | [INFINIPATH_IBCS_LT_STATE_RECOVERIDLE] = 6, | ||
| 643 | }; | ||
| 644 | |||
| 645 | static int ipath_query_port(struct ib_device *ibdev, | ||
| 646 | u8 port, struct ib_port_attr *props) | ||
| 647 | { | ||
| 648 | struct ipath_ibdev *dev = to_idev(ibdev); | ||
| 649 | enum ib_mtu mtu; | ||
| 650 | u16 lid = ipath_layer_get_lid(dev->dd); | ||
| 651 | u64 ibcstat; | ||
| 652 | |||
| 653 | memset(props, 0, sizeof(*props)); | ||
| 654 | props->lid = lid ? lid : __constant_be16_to_cpu(IB_LID_PERMISSIVE); | ||
| 655 | props->lmc = dev->mkeyprot_resv_lmc & 7; | ||
| 656 | props->sm_lid = dev->sm_lid; | ||
| 657 | props->sm_sl = dev->sm_sl; | ||
| 658 | ibcstat = ipath_layer_get_lastibcstat(dev->dd); | ||
| 659 | props->state = ((ibcstat >> 4) & 0x3) + 1; | ||
| 660 | /* See phys_state_show() */ | ||
| 661 | props->phys_state = ipath_cvt_physportstate[ | ||
| 662 | ipath_layer_get_lastibcstat(dev->dd) & 0xf]; | ||
| 663 | props->port_cap_flags = dev->port_cap_flags; | ||
| 664 | props->gid_tbl_len = 1; | ||
| 665 | props->max_msg_sz = 4096; | ||
| 666 | props->pkey_tbl_len = ipath_layer_get_npkeys(dev->dd); | ||
| 667 | props->bad_pkey_cntr = ipath_layer_get_cr_errpkey(dev->dd) - | ||
| 668 | dev->n_pkey_violations; | ||
| 669 | props->qkey_viol_cntr = dev->qkey_violations; | ||
| 670 | props->active_width = IB_WIDTH_4X; | ||
| 671 | /* See rate_show() */ | ||
| 672 | props->active_speed = 1; /* Regular 10Mbs speed. */ | ||
| 673 | props->max_vl_num = 1; /* VLCap = VL0 */ | ||
| 674 | props->init_type_reply = 0; | ||
| 675 | |||
| 676 | props->max_mtu = IB_MTU_4096; | ||
| 677 | switch (ipath_layer_get_ibmtu(dev->dd)) { | ||
| 678 | case 4096: | ||
| 679 | mtu = IB_MTU_4096; | ||
| 680 | break; | ||
| 681 | case 2048: | ||
| 682 | mtu = IB_MTU_2048; | ||
| 683 | break; | ||
| 684 | case 1024: | ||
| 685 | mtu = IB_MTU_1024; | ||
| 686 | break; | ||
| 687 | case 512: | ||
| 688 | mtu = IB_MTU_512; | ||
| 689 | break; | ||
| 690 | case 256: | ||
| 691 | mtu = IB_MTU_256; | ||
| 692 | break; | ||
| 693 | default: | ||
| 694 | mtu = IB_MTU_2048; | ||
| 695 | } | ||
| 696 | props->active_mtu = mtu; | ||
| 697 | props->subnet_timeout = dev->subnet_timeout; | ||
| 698 | |||
| 699 | return 0; | ||
| 700 | } | ||
| 701 | |||
| 702 | static int ipath_modify_device(struct ib_device *device, | ||
| 703 | int device_modify_mask, | ||
| 704 | struct ib_device_modify *device_modify) | ||
| 705 | { | ||
| 706 | int ret; | ||
| 707 | |||
| 708 | if (device_modify_mask & ~(IB_DEVICE_MODIFY_SYS_IMAGE_GUID | | ||
| 709 | IB_DEVICE_MODIFY_NODE_DESC)) { | ||
| 710 | ret = -EOPNOTSUPP; | ||
| 711 | goto bail; | ||
| 712 | } | ||
| 713 | |||
| 714 | if (device_modify_mask & IB_DEVICE_MODIFY_NODE_DESC) | ||
| 715 | memcpy(device->node_desc, device_modify->node_desc, 64); | ||
| 716 | |||
| 717 | if (device_modify_mask & IB_DEVICE_MODIFY_SYS_IMAGE_GUID) | ||
| 718 | to_idev(device)->sys_image_guid = | ||
| 719 | cpu_to_be64(device_modify->sys_image_guid); | ||
| 720 | |||
| 721 | ret = 0; | ||
| 722 | |||
| 723 | bail: | ||
| 724 | return ret; | ||
| 725 | } | ||
| 726 | |||
| 727 | static int ipath_modify_port(struct ib_device *ibdev, | ||
| 728 | u8 port, int port_modify_mask, | ||
| 729 | struct ib_port_modify *props) | ||
| 730 | { | ||
| 731 | struct ipath_ibdev *dev = to_idev(ibdev); | ||
| 732 | |||
| 733 | dev->port_cap_flags |= props->set_port_cap_mask; | ||
| 734 | dev->port_cap_flags &= ~props->clr_port_cap_mask; | ||
| 735 | if (port_modify_mask & IB_PORT_SHUTDOWN) | ||
| 736 | ipath_layer_set_linkstate(dev->dd, IPATH_IB_LINKDOWN); | ||
| 737 | if (port_modify_mask & IB_PORT_RESET_QKEY_CNTR) | ||
| 738 | dev->qkey_violations = 0; | ||
| 739 | return 0; | ||
| 740 | } | ||
| 741 | |||
| 742 | static int ipath_query_gid(struct ib_device *ibdev, u8 port, | ||
| 743 | int index, union ib_gid *gid) | ||
| 744 | { | ||
| 745 | struct ipath_ibdev *dev = to_idev(ibdev); | ||
| 746 | int ret; | ||
| 747 | |||
| 748 | if (index >= 1) { | ||
| 749 | ret = -EINVAL; | ||
| 750 | goto bail; | ||
| 751 | } | ||
| 752 | gid->global.subnet_prefix = dev->gid_prefix; | ||
| 753 | gid->global.interface_id = ipath_layer_get_guid(dev->dd); | ||
| 754 | |||
| 755 | ret = 0; | ||
| 756 | |||
| 757 | bail: | ||
| 758 | return ret; | ||
| 759 | } | ||
| 760 | |||
| 761 | static struct ib_pd *ipath_alloc_pd(struct ib_device *ibdev, | ||
| 762 | struct ib_ucontext *context, | ||
| 763 | struct ib_udata *udata) | ||
| 764 | { | ||
| 765 | struct ipath_pd *pd; | ||
| 766 | struct ib_pd *ret; | ||
| 767 | |||
| 768 | pd = kmalloc(sizeof *pd, GFP_KERNEL); | ||
| 769 | if (!pd) { | ||
| 770 | ret = ERR_PTR(-ENOMEM); | ||
| 771 | goto bail; | ||
| 772 | } | ||
| 773 | |||
| 774 | /* ib_alloc_pd() will initialize pd->ibpd. */ | ||
| 775 | pd->user = udata != NULL; | ||
| 776 | |||
| 777 | ret = &pd->ibpd; | ||
| 778 | |||
| 779 | bail: | ||
| 780 | return ret; | ||
| 781 | } | ||
| 782 | |||
| 783 | static int ipath_dealloc_pd(struct ib_pd *ibpd) | ||
| 784 | { | ||
| 785 | struct ipath_pd *pd = to_ipd(ibpd); | ||
| 786 | |||
| 787 | kfree(pd); | ||
| 788 | |||
| 789 | return 0; | ||
| 790 | } | ||
| 791 | |||
| 792 | /** | ||
| 793 | * ipath_create_ah - create an address handle | ||
| 794 | * @pd: the protection domain | ||
| 795 | * @ah_attr: the attributes of the AH | ||
| 796 | * | ||
| 797 | * This may be called from interrupt context. | ||
| 798 | */ | ||
| 799 | static struct ib_ah *ipath_create_ah(struct ib_pd *pd, | ||
| 800 | struct ib_ah_attr *ah_attr) | ||
| 801 | { | ||
| 802 | struct ipath_ah *ah; | ||
| 803 | struct ib_ah *ret; | ||
| 804 | |||
| 805 | /* A multicast address requires a GRH (see ch. 8.4.1). */ | ||
| 806 | if (ah_attr->dlid >= IPS_MULTICAST_LID_BASE && | ||
| 807 | ah_attr->dlid != IPS_PERMISSIVE_LID && | ||
| 808 | !(ah_attr->ah_flags & IB_AH_GRH)) { | ||
| 809 | ret = ERR_PTR(-EINVAL); | ||
| 810 | goto bail; | ||
| 811 | } | ||
| 812 | |||
| 813 | ah = kmalloc(sizeof *ah, GFP_ATOMIC); | ||
| 814 | if (!ah) { | ||
| 815 | ret = ERR_PTR(-ENOMEM); | ||
| 816 | goto bail; | ||
| 817 | } | ||
| 818 | |||
| 819 | /* ib_create_ah() will initialize ah->ibah. */ | ||
| 820 | ah->attr = *ah_attr; | ||
| 821 | |||
| 822 | ret = &ah->ibah; | ||
| 823 | |||
| 824 | bail: | ||
| 825 | return ret; | ||
| 826 | } | ||
| 827 | |||
| 828 | /** | ||
| 829 | * ipath_destroy_ah - destroy an address handle | ||
| 830 | * @ibah: the AH to destroy | ||
| 831 | * | ||
| 832 | * This may be called from interrupt context. | ||
| 833 | */ | ||
| 834 | static int ipath_destroy_ah(struct ib_ah *ibah) | ||
| 835 | { | ||
| 836 | struct ipath_ah *ah = to_iah(ibah); | ||
| 837 | |||
| 838 | kfree(ah); | ||
| 839 | |||
| 840 | return 0; | ||
| 841 | } | ||
| 842 | |||
| 843 | static int ipath_query_ah(struct ib_ah *ibah, struct ib_ah_attr *ah_attr) | ||
| 844 | { | ||
| 845 | struct ipath_ah *ah = to_iah(ibah); | ||
| 846 | |||
| 847 | *ah_attr = ah->attr; | ||
| 848 | |||
| 849 | return 0; | ||
| 850 | } | ||
| 851 | |||
| 852 | static int ipath_query_pkey(struct ib_device *ibdev, u8 port, u16 index, | ||
| 853 | u16 *pkey) | ||
| 854 | { | ||
| 855 | struct ipath_ibdev *dev = to_idev(ibdev); | ||
| 856 | int ret; | ||
| 857 | |||
| 858 | if (index >= ipath_layer_get_npkeys(dev->dd)) { | ||
| 859 | ret = -EINVAL; | ||
| 860 | goto bail; | ||
| 861 | } | ||
| 862 | |||
| 863 | *pkey = ipath_layer_get_pkey(dev->dd, index); | ||
| 864 | ret = 0; | ||
| 865 | |||
| 866 | bail: | ||
| 867 | return ret; | ||
| 868 | } | ||
| 869 | |||
| 870 | |||
| 871 | /** | ||
| 872 | * ipath_alloc_ucontext - allocate a ucontest | ||
| 873 | * @ibdev: the infiniband device | ||
| 874 | * @udata: not used by the InfiniPath driver | ||
| 875 | */ | ||
| 876 | |||
| 877 | static struct ib_ucontext *ipath_alloc_ucontext(struct ib_device *ibdev, | ||
| 878 | struct ib_udata *udata) | ||
| 879 | { | ||
| 880 | struct ipath_ucontext *context; | ||
| 881 | struct ib_ucontext *ret; | ||
| 882 | |||
| 883 | context = kmalloc(sizeof *context, GFP_KERNEL); | ||
| 884 | if (!context) { | ||
| 885 | ret = ERR_PTR(-ENOMEM); | ||
| 886 | goto bail; | ||
| 887 | } | ||
| 888 | |||
| 889 | ret = &context->ibucontext; | ||
| 890 | |||
| 891 | bail: | ||
| 892 | return ret; | ||
| 893 | } | ||
| 894 | |||
| 895 | static int ipath_dealloc_ucontext(struct ib_ucontext *context) | ||
| 896 | { | ||
| 897 | kfree(to_iucontext(context)); | ||
| 898 | return 0; | ||
| 899 | } | ||
| 900 | |||
| 901 | static int ipath_verbs_register_sysfs(struct ib_device *dev); | ||
| 902 | |||
| 903 | /** | ||
| 904 | * ipath_register_ib_device - register our device with the infiniband core | ||
| 905 | * @unit: the device number to register | ||
| 906 | * @dd: the device data structure | ||
| 907 | * Return the allocated ipath_ibdev pointer or NULL on error. | ||
| 908 | */ | ||
| 909 | static void *ipath_register_ib_device(int unit, struct ipath_devdata *dd) | ||
| 910 | { | ||
| 911 | struct ipath_ibdev *idev; | ||
| 912 | struct ib_device *dev; | ||
| 913 | int ret; | ||
| 914 | |||
| 915 | idev = (struct ipath_ibdev *)ib_alloc_device(sizeof *idev); | ||
| 916 | if (idev == NULL) | ||
| 917 | goto bail; | ||
| 918 | |||
| 919 | dev = &idev->ibdev; | ||
| 920 | |||
| 921 | /* Only need to initialize non-zero fields. */ | ||
| 922 | spin_lock_init(&idev->qp_table.lock); | ||
| 923 | spin_lock_init(&idev->lk_table.lock); | ||
| 924 | idev->sm_lid = __constant_be16_to_cpu(IB_LID_PERMISSIVE); | ||
| 925 | /* Set the prefix to the default value (see ch. 4.1.1) */ | ||
| 926 | idev->gid_prefix = __constant_cpu_to_be64(0xfe80000000000000ULL); | ||
| 927 | |||
| 928 | ret = ipath_init_qp_table(idev, ib_ipath_qp_table_size); | ||
| 929 | if (ret) | ||
| 930 | goto err_qp; | ||
| 931 | |||
| 932 | /* | ||
| 933 | * The top ib_ipath_lkey_table_size bits are used to index the | ||
| 934 | * table. The lower 8 bits can be owned by the user (copied from | ||
| 935 | * the LKEY). The remaining bits act as a generation number or tag. | ||
| 936 | */ | ||
| 937 | idev->lk_table.max = 1 << ib_ipath_lkey_table_size; | ||
| 938 | idev->lk_table.table = kzalloc(idev->lk_table.max * | ||
| 939 | sizeof(*idev->lk_table.table), | ||
| 940 | GFP_KERNEL); | ||
| 941 | if (idev->lk_table.table == NULL) { | ||
| 942 | ret = -ENOMEM; | ||
| 943 | goto err_lk; | ||
| 944 | } | ||
| 945 | spin_lock_init(&idev->pending_lock); | ||
| 946 | INIT_LIST_HEAD(&idev->pending[0]); | ||
| 947 | INIT_LIST_HEAD(&idev->pending[1]); | ||
| 948 | INIT_LIST_HEAD(&idev->pending[2]); | ||
| 949 | INIT_LIST_HEAD(&idev->piowait); | ||
| 950 | INIT_LIST_HEAD(&idev->rnrwait); | ||
| 951 | idev->pending_index = 0; | ||
| 952 | idev->port_cap_flags = | ||
| 953 | IB_PORT_SYS_IMAGE_GUID_SUP | IB_PORT_CLIENT_REG_SUP; | ||
| 954 | idev->pma_counter_select[0] = IB_PMA_PORT_XMIT_DATA; | ||
| 955 | idev->pma_counter_select[1] = IB_PMA_PORT_RCV_DATA; | ||
| 956 | idev->pma_counter_select[2] = IB_PMA_PORT_XMIT_PKTS; | ||
| 957 | idev->pma_counter_select[3] = IB_PMA_PORT_RCV_PKTS; | ||
| 958 | idev->pma_counter_select[5] = IB_PMA_PORT_XMIT_WAIT; | ||
| 959 | idev->link_width_enabled = 3; /* 1x or 4x */ | ||
| 960 | |||
| 961 | /* | ||
| 962 | * The system image GUID is supposed to be the same for all | ||
| 963 | * IB HCAs in a single system but since there can be other | ||
| 964 | * device types in the system, we can't be sure this is unique. | ||
| 965 | */ | ||
| 966 | if (!sys_image_guid) | ||
| 967 | sys_image_guid = ipath_layer_get_guid(dd); | ||
| 968 | idev->sys_image_guid = sys_image_guid; | ||
| 969 | idev->ib_unit = unit; | ||
| 970 | idev->dd = dd; | ||
| 971 | |||
| 972 | strlcpy(dev->name, "ipath%d", IB_DEVICE_NAME_MAX); | ||
| 973 | dev->node_guid = ipath_layer_get_guid(dd); | ||
| 974 | dev->uverbs_abi_ver = IPATH_UVERBS_ABI_VERSION; | ||
| 975 | dev->uverbs_cmd_mask = | ||
| 976 | (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) | | ||
| 977 | (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) | | ||
| 978 | (1ull << IB_USER_VERBS_CMD_QUERY_PORT) | | ||
| 979 | (1ull << IB_USER_VERBS_CMD_ALLOC_PD) | | ||
| 980 | (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) | | ||
| 981 | (1ull << IB_USER_VERBS_CMD_CREATE_AH) | | ||
| 982 | (1ull << IB_USER_VERBS_CMD_DESTROY_AH) | | ||
| 983 | (1ull << IB_USER_VERBS_CMD_QUERY_AH) | | ||
| 984 | (1ull << IB_USER_VERBS_CMD_REG_MR) | | ||
| 985 | (1ull << IB_USER_VERBS_CMD_DEREG_MR) | | ||
| 986 | (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) | | ||
| 987 | (1ull << IB_USER_VERBS_CMD_CREATE_CQ) | | ||
| 988 | (1ull << IB_USER_VERBS_CMD_RESIZE_CQ) | | ||
| 989 | (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) | | ||
| 990 | (1ull << IB_USER_VERBS_CMD_POLL_CQ) | | ||
| 991 | (1ull << IB_USER_VERBS_CMD_REQ_NOTIFY_CQ) | | ||
| 992 | (1ull << IB_USER_VERBS_CMD_CREATE_QP) | | ||
| 993 | (1ull << IB_USER_VERBS_CMD_QUERY_QP) | | ||
| 994 | (1ull << IB_USER_VERBS_CMD_MODIFY_QP) | | ||
| 995 | (1ull << IB_USER_VERBS_CMD_DESTROY_QP) | | ||
| 996 | (1ull << IB_USER_VERBS_CMD_POST_SEND) | | ||
| 997 | (1ull << IB_USER_VERBS_CMD_POST_RECV) | | ||
| 998 | (1ull << IB_USER_VERBS_CMD_ATTACH_MCAST) | | ||
| 999 | (1ull << IB_USER_VERBS_CMD_DETACH_MCAST) | | ||
| 1000 | (1ull << IB_USER_VERBS_CMD_CREATE_SRQ) | | ||
| 1001 | (1ull << IB_USER_VERBS_CMD_MODIFY_SRQ) | | ||
| 1002 | (1ull << IB_USER_VERBS_CMD_QUERY_SRQ) | | ||
| 1003 | (1ull << IB_USER_VERBS_CMD_DESTROY_SRQ) | | ||
| 1004 | (1ull << IB_USER_VERBS_CMD_POST_SRQ_RECV); | ||
| 1005 | dev->node_type = IB_NODE_CA; | ||
| 1006 | dev->phys_port_cnt = 1; | ||
| 1007 | dev->dma_device = ipath_layer_get_device(dd); | ||
| 1008 | dev->class_dev.dev = dev->dma_device; | ||
| 1009 | dev->query_device = ipath_query_device; | ||
| 1010 | dev->modify_device = ipath_modify_device; | ||
| 1011 | dev->query_port = ipath_query_port; | ||
| 1012 | dev->modify_port = ipath_modify_port; | ||
| 1013 | dev->query_pkey = ipath_query_pkey; | ||
| 1014 | dev->query_gid = ipath_query_gid; | ||
| 1015 | dev->alloc_ucontext = ipath_alloc_ucontext; | ||
| 1016 | dev->dealloc_ucontext = ipath_dealloc_ucontext; | ||
| 1017 | dev->alloc_pd = ipath_alloc_pd; | ||
| 1018 | dev->dealloc_pd = ipath_dealloc_pd; | ||
| 1019 | dev->create_ah = ipath_create_ah; | ||
| 1020 | dev->destroy_ah = ipath_destroy_ah; | ||
| 1021 | dev->query_ah = ipath_query_ah; | ||
| 1022 | dev->create_srq = ipath_create_srq; | ||
| 1023 | dev->modify_srq = ipath_modify_srq; | ||
| 1024 | dev->query_srq = ipath_query_srq; | ||
| 1025 | dev->destroy_srq = ipath_destroy_srq; | ||
| 1026 | dev->create_qp = ipath_create_qp; | ||
| 1027 | dev->modify_qp = ipath_modify_qp; | ||
| 1028 | dev->query_qp = ipath_query_qp; | ||
| 1029 | dev->destroy_qp = ipath_destroy_qp; | ||
| 1030 | dev->post_send = ipath_post_send; | ||
| 1031 | dev->post_recv = ipath_post_receive; | ||
| 1032 | dev->post_srq_recv = ipath_post_srq_receive; | ||
| 1033 | dev->create_cq = ipath_create_cq; | ||
| 1034 | dev->destroy_cq = ipath_destroy_cq; | ||
| 1035 | dev->resize_cq = ipath_resize_cq; | ||
| 1036 | dev->poll_cq = ipath_poll_cq; | ||
| 1037 | dev->req_notify_cq = ipath_req_notify_cq; | ||
| 1038 | dev->get_dma_mr = ipath_get_dma_mr; | ||
| 1039 | dev->reg_phys_mr = ipath_reg_phys_mr; | ||
| 1040 | dev->reg_user_mr = ipath_reg_user_mr; | ||
| 1041 | dev->dereg_mr = ipath_dereg_mr; | ||
| 1042 | dev->alloc_fmr = ipath_alloc_fmr; | ||
| 1043 | dev->map_phys_fmr = ipath_map_phys_fmr; | ||
| 1044 | dev->unmap_fmr = ipath_unmap_fmr; | ||
| 1045 | dev->dealloc_fmr = ipath_dealloc_fmr; | ||
| 1046 | dev->attach_mcast = ipath_multicast_attach; | ||
| 1047 | dev->detach_mcast = ipath_multicast_detach; | ||
| 1048 | dev->process_mad = ipath_process_mad; | ||
| 1049 | |||
| 1050 | snprintf(dev->node_desc, sizeof(dev->node_desc), | ||
| 1051 | IPATH_IDSTR " %s kernel_SMA", system_utsname.nodename); | ||
| 1052 | |||
| 1053 | ret = ib_register_device(dev); | ||
| 1054 | if (ret) | ||
| 1055 | goto err_reg; | ||
| 1056 | |||
| 1057 | if (ipath_verbs_register_sysfs(dev)) | ||
| 1058 | goto err_class; | ||
| 1059 | |||
| 1060 | ipath_layer_enable_timer(dd); | ||
| 1061 | |||
| 1062 | goto bail; | ||
| 1063 | |||
| 1064 | err_class: | ||
| 1065 | ib_unregister_device(dev); | ||
| 1066 | err_reg: | ||
| 1067 | kfree(idev->lk_table.table); | ||
| 1068 | err_lk: | ||
| 1069 | kfree(idev->qp_table.table); | ||
| 1070 | err_qp: | ||
| 1071 | ib_dealloc_device(dev); | ||
| 1072 | _VERBS_ERROR("ib_ipath%d cannot register verbs (%d)!\n", | ||
| 1073 | unit, -ret); | ||
| 1074 | idev = NULL; | ||
| 1075 | |||
| 1076 | bail: | ||
| 1077 | return idev; | ||
| 1078 | } | ||
| 1079 | |||
| 1080 | static void ipath_unregister_ib_device(void *arg) | ||
| 1081 | { | ||
| 1082 | struct ipath_ibdev *dev = (struct ipath_ibdev *) arg; | ||
| 1083 | struct ib_device *ibdev = &dev->ibdev; | ||
| 1084 | |||
| 1085 | ipath_layer_disable_timer(dev->dd); | ||
| 1086 | |||
| 1087 | ib_unregister_device(ibdev); | ||
| 1088 | |||
| 1089 | if (!list_empty(&dev->pending[0]) || | ||
| 1090 | !list_empty(&dev->pending[1]) || | ||
| 1091 | !list_empty(&dev->pending[2])) | ||
| 1092 | _VERBS_ERROR("ipath%d pending list not empty!\n", | ||
| 1093 | dev->ib_unit); | ||
| 1094 | if (!list_empty(&dev->piowait)) | ||
| 1095 | _VERBS_ERROR("ipath%d piowait list not empty!\n", | ||
| 1096 | dev->ib_unit); | ||
| 1097 | if (!list_empty(&dev->rnrwait)) | ||
| 1098 | _VERBS_ERROR("ipath%d rnrwait list not empty!\n", | ||
| 1099 | dev->ib_unit); | ||
| 1100 | if (!ipath_mcast_tree_empty()) | ||
| 1101 | _VERBS_ERROR("ipath%d multicast table memory leak!\n", | ||
| 1102 | dev->ib_unit); | ||
| 1103 | /* | ||
| 1104 | * Note that ipath_unregister_ib_device() can be called before all | ||
| 1105 | * the QPs are destroyed! | ||
| 1106 | */ | ||
| 1107 | ipath_free_all_qps(&dev->qp_table); | ||
| 1108 | kfree(dev->qp_table.table); | ||
| 1109 | kfree(dev->lk_table.table); | ||
| 1110 | ib_dealloc_device(ibdev); | ||
| 1111 | } | ||
| 1112 | |||
| 1113 | int __init ipath_verbs_init(void) | ||
| 1114 | { | ||
| 1115 | return ipath_verbs_register(ipath_register_ib_device, | ||
| 1116 | ipath_unregister_ib_device, | ||
| 1117 | ipath_ib_piobufavail, ipath_ib_rcv, | ||
| 1118 | ipath_ib_timer); | ||
| 1119 | } | ||
| 1120 | |||
| 1121 | void __exit ipath_verbs_cleanup(void) | ||
| 1122 | { | ||
| 1123 | ipath_verbs_unregister(); | ||
| 1124 | } | ||
| 1125 | |||
| 1126 | static ssize_t show_rev(struct class_device *cdev, char *buf) | ||
| 1127 | { | ||
| 1128 | struct ipath_ibdev *dev = | ||
| 1129 | container_of(cdev, struct ipath_ibdev, ibdev.class_dev); | ||
| 1130 | int vendor, boardrev, majrev, minrev; | ||
| 1131 | |||
| 1132 | ipath_layer_query_device(dev->dd, &vendor, &boardrev, | ||
| 1133 | &majrev, &minrev); | ||
| 1134 | return sprintf(buf, "%d.%d\n", majrev, minrev); | ||
| 1135 | } | ||
| 1136 | |||
| 1137 | static ssize_t show_hca(struct class_device *cdev, char *buf) | ||
| 1138 | { | ||
| 1139 | struct ipath_ibdev *dev = | ||
| 1140 | container_of(cdev, struct ipath_ibdev, ibdev.class_dev); | ||
| 1141 | int ret; | ||
| 1142 | |||
| 1143 | ret = ipath_layer_get_boardname(dev->dd, buf, 128); | ||
| 1144 | if (ret < 0) | ||
| 1145 | goto bail; | ||
| 1146 | strcat(buf, "\n"); | ||
| 1147 | ret = strlen(buf); | ||
| 1148 | |||
| 1149 | bail: | ||
| 1150 | return ret; | ||
| 1151 | } | ||
| 1152 | |||
| 1153 | static ssize_t show_stats(struct class_device *cdev, char *buf) | ||
| 1154 | { | ||
| 1155 | struct ipath_ibdev *dev = | ||
| 1156 | container_of(cdev, struct ipath_ibdev, ibdev.class_dev); | ||
| 1157 | int i; | ||
| 1158 | int len; | ||
| 1159 | |||
| 1160 | len = sprintf(buf, | ||
| 1161 | "RC resends %d\n" | ||
| 1162 | "RC QACKs %d\n" | ||
| 1163 | "RC ACKs %d\n" | ||
| 1164 | "RC SEQ NAKs %d\n" | ||
| 1165 | "RC RDMA seq %d\n" | ||
| 1166 | "RC RNR NAKs %d\n" | ||
| 1167 | "RC OTH NAKs %d\n" | ||
| 1168 | "RC timeouts %d\n" | ||
| 1169 | "RC RDMA dup %d\n" | ||
| 1170 | "piobuf wait %d\n" | ||
| 1171 | "no piobuf %d\n" | ||
| 1172 | "PKT drops %d\n" | ||
| 1173 | "WQE errs %d\n", | ||
| 1174 | dev->n_rc_resends, dev->n_rc_qacks, dev->n_rc_acks, | ||
| 1175 | dev->n_seq_naks, dev->n_rdma_seq, dev->n_rnr_naks, | ||
| 1176 | dev->n_other_naks, dev->n_timeouts, | ||
| 1177 | dev->n_rdma_dup_busy, dev->n_piowait, | ||
| 1178 | dev->n_no_piobuf, dev->n_pkt_drops, dev->n_wqe_errs); | ||
| 1179 | for (i = 0; i < ARRAY_SIZE(dev->opstats); i++) { | ||
| 1180 | const struct ipath_opcode_stats *si = &dev->opstats[i]; | ||
| 1181 | |||
| 1182 | if (!si->n_packets && !si->n_bytes) | ||
| 1183 | continue; | ||
| 1184 | len += sprintf(buf + len, "%02x %llu/%llu\n", i, | ||
| 1185 | (unsigned long long) si->n_packets, | ||
| 1186 | (unsigned long long) si->n_bytes); | ||
| 1187 | } | ||
| 1188 | return len; | ||
| 1189 | } | ||
| 1190 | |||
| 1191 | static CLASS_DEVICE_ATTR(hw_rev, S_IRUGO, show_rev, NULL); | ||
| 1192 | static CLASS_DEVICE_ATTR(hca_type, S_IRUGO, show_hca, NULL); | ||
| 1193 | static CLASS_DEVICE_ATTR(board_id, S_IRUGO, show_hca, NULL); | ||
| 1194 | static CLASS_DEVICE_ATTR(stats, S_IRUGO, show_stats, NULL); | ||
| 1195 | |||
| 1196 | static struct class_device_attribute *ipath_class_attributes[] = { | ||
| 1197 | &class_device_attr_hw_rev, | ||
| 1198 | &class_device_attr_hca_type, | ||
| 1199 | &class_device_attr_board_id, | ||
| 1200 | &class_device_attr_stats | ||
| 1201 | }; | ||
| 1202 | |||
| 1203 | static int ipath_verbs_register_sysfs(struct ib_device *dev) | ||
| 1204 | { | ||
| 1205 | int i; | ||
| 1206 | int ret; | ||
| 1207 | |||
| 1208 | for (i = 0; i < ARRAY_SIZE(ipath_class_attributes); ++i) | ||
| 1209 | if (class_device_create_file(&dev->class_dev, | ||
| 1210 | ipath_class_attributes[i])) { | ||
| 1211 | ret = 1; | ||
| 1212 | goto bail; | ||
| 1213 | } | ||
| 1214 | |||
| 1215 | ret = 0; | ||
| 1216 | |||
| 1217 | bail: | ||
| 1218 | return ret; | ||
| 1219 | } | ||
| 1220 | |||
| 1221 | module_init(ipath_verbs_init); | ||
| 1222 | module_exit(ipath_verbs_cleanup); | ||
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c b/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c new file mode 100644 index 000000000000..10b31d2c4f20 --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_verbs_mcast.c | |||
| @@ -0,0 +1,333 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved. | ||
| 3 | * | ||
| 4 | * This software is available to you under a choice of one of two | ||
| 5 | * licenses. You may choose to be licensed under the terms of the GNU | ||
| 6 | * General Public License (GPL) Version 2, available from the file | ||
| 7 | * COPYING in the main directory of this source tree, or the | ||
| 8 | * OpenIB.org BSD license below: | ||
| 9 | * | ||
| 10 | * Redistribution and use in source and binary forms, with or | ||
| 11 | * without modification, are permitted provided that the following | ||
| 12 | * conditions are met: | ||
| 13 | * | ||
| 14 | * - Redistributions of source code must retain the above | ||
| 15 | * copyright notice, this list of conditions and the following | ||
| 16 | * disclaimer. | ||
| 17 | * | ||
| 18 | * - Redistributions in binary form must reproduce the above | ||
| 19 | * copyright notice, this list of conditions and the following | ||
| 20 | * disclaimer in the documentation and/or other materials | ||
| 21 | * provided with the distribution. | ||
| 22 | * | ||
| 23 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
| 24 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
| 25 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
| 26 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
| 27 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
| 28 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
| 29 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| 30 | * SOFTWARE. | ||
| 31 | */ | ||
| 32 | |||
| 33 | #include <linux/list.h> | ||
| 34 | #include <linux/rcupdate.h> | ||
| 35 | |||
| 36 | #include "ipath_verbs.h" | ||
| 37 | |||
| 38 | /* | ||
| 39 | * Global table of GID to attached QPs. | ||
| 40 | * The table is global to all ipath devices since a send from one QP/device | ||
| 41 | * needs to be locally routed to any locally attached QPs on the same | ||
| 42 | * or different device. | ||
| 43 | */ | ||
| 44 | static struct rb_root mcast_tree; | ||
| 45 | static DEFINE_SPINLOCK(mcast_lock); | ||
| 46 | |||
| 47 | /** | ||
| 48 | * ipath_mcast_qp_alloc - alloc a struct to link a QP to mcast GID struct | ||
| 49 | * @qp: the QP to link | ||
| 50 | */ | ||
| 51 | static struct ipath_mcast_qp *ipath_mcast_qp_alloc(struct ipath_qp *qp) | ||
| 52 | { | ||
| 53 | struct ipath_mcast_qp *mqp; | ||
| 54 | |||
| 55 | mqp = kmalloc(sizeof *mqp, GFP_KERNEL); | ||
| 56 | if (!mqp) | ||
| 57 | goto bail; | ||
| 58 | |||
| 59 | mqp->qp = qp; | ||
| 60 | atomic_inc(&qp->refcount); | ||
| 61 | |||
| 62 | bail: | ||
| 63 | return mqp; | ||
| 64 | } | ||
| 65 | |||
| 66 | static void ipath_mcast_qp_free(struct ipath_mcast_qp *mqp) | ||
| 67 | { | ||
| 68 | struct ipath_qp *qp = mqp->qp; | ||
| 69 | |||
| 70 | /* Notify ipath_destroy_qp() if it is waiting. */ | ||
| 71 | if (atomic_dec_and_test(&qp->refcount)) | ||
| 72 | wake_up(&qp->wait); | ||
| 73 | |||
| 74 | kfree(mqp); | ||
| 75 | } | ||
| 76 | |||
| 77 | /** | ||
| 78 | * ipath_mcast_alloc - allocate the multicast GID structure | ||
| 79 | * @mgid: the multicast GID | ||
| 80 | * | ||
| 81 | * A list of QPs will be attached to this structure. | ||
| 82 | */ | ||
| 83 | static struct ipath_mcast *ipath_mcast_alloc(union ib_gid *mgid) | ||
| 84 | { | ||
| 85 | struct ipath_mcast *mcast; | ||
| 86 | |||
| 87 | mcast = kmalloc(sizeof *mcast, GFP_KERNEL); | ||
| 88 | if (!mcast) | ||
| 89 | goto bail; | ||
| 90 | |||
| 91 | mcast->mgid = *mgid; | ||
| 92 | INIT_LIST_HEAD(&mcast->qp_list); | ||
| 93 | init_waitqueue_head(&mcast->wait); | ||
| 94 | atomic_set(&mcast->refcount, 0); | ||
| 95 | |||
| 96 | bail: | ||
| 97 | return mcast; | ||
| 98 | } | ||
| 99 | |||
| 100 | static void ipath_mcast_free(struct ipath_mcast *mcast) | ||
| 101 | { | ||
| 102 | struct ipath_mcast_qp *p, *tmp; | ||
| 103 | |||
| 104 | list_for_each_entry_safe(p, tmp, &mcast->qp_list, list) | ||
| 105 | ipath_mcast_qp_free(p); | ||
| 106 | |||
| 107 | kfree(mcast); | ||
| 108 | } | ||
| 109 | |||
| 110 | /** | ||
| 111 | * ipath_mcast_find - search the global table for the given multicast GID | ||
| 112 | * @mgid: the multicast GID to search for | ||
| 113 | * | ||
| 114 | * Returns NULL if not found. | ||
| 115 | * | ||
| 116 | * The caller is responsible for decrementing the reference count if found. | ||
| 117 | */ | ||
| 118 | struct ipath_mcast *ipath_mcast_find(union ib_gid *mgid) | ||
| 119 | { | ||
| 120 | struct rb_node *n; | ||
| 121 | unsigned long flags; | ||
| 122 | struct ipath_mcast *mcast; | ||
| 123 | |||
| 124 | spin_lock_irqsave(&mcast_lock, flags); | ||
| 125 | n = mcast_tree.rb_node; | ||
| 126 | while (n) { | ||
| 127 | int ret; | ||
| 128 | |||
| 129 | mcast = rb_entry(n, struct ipath_mcast, rb_node); | ||
| 130 | |||
| 131 | ret = memcmp(mgid->raw, mcast->mgid.raw, | ||
| 132 | sizeof(union ib_gid)); | ||
| 133 | if (ret < 0) | ||
| 134 | n = n->rb_left; | ||
| 135 | else if (ret > 0) | ||
| 136 | n = n->rb_right; | ||
| 137 | else { | ||
| 138 | atomic_inc(&mcast->refcount); | ||
| 139 | spin_unlock_irqrestore(&mcast_lock, flags); | ||
| 140 | goto bail; | ||
| 141 | } | ||
| 142 | } | ||
| 143 | spin_unlock_irqrestore(&mcast_lock, flags); | ||
| 144 | |||
| 145 | mcast = NULL; | ||
| 146 | |||
| 147 | bail: | ||
| 148 | return mcast; | ||
| 149 | } | ||
| 150 | |||
| 151 | /** | ||
| 152 | * ipath_mcast_add - insert mcast GID into table and attach QP struct | ||
| 153 | * @mcast: the mcast GID table | ||
| 154 | * @mqp: the QP to attach | ||
| 155 | * | ||
| 156 | * Return zero if both were added. Return EEXIST if the GID was already in | ||
| 157 | * the table but the QP was added. Return ESRCH if the QP was already | ||
| 158 | * attached and neither structure was added. | ||
| 159 | */ | ||
| 160 | static int ipath_mcast_add(struct ipath_mcast *mcast, | ||
| 161 | struct ipath_mcast_qp *mqp) | ||
| 162 | { | ||
| 163 | struct rb_node **n = &mcast_tree.rb_node; | ||
| 164 | struct rb_node *pn = NULL; | ||
| 165 | unsigned long flags; | ||
| 166 | int ret; | ||
| 167 | |||
| 168 | spin_lock_irqsave(&mcast_lock, flags); | ||
| 169 | |||
| 170 | while (*n) { | ||
| 171 | struct ipath_mcast *tmcast; | ||
| 172 | struct ipath_mcast_qp *p; | ||
| 173 | |||
| 174 | pn = *n; | ||
| 175 | tmcast = rb_entry(pn, struct ipath_mcast, rb_node); | ||
| 176 | |||
| 177 | ret = memcmp(mcast->mgid.raw, tmcast->mgid.raw, | ||
| 178 | sizeof(union ib_gid)); | ||
| 179 | if (ret < 0) { | ||
| 180 | n = &pn->rb_left; | ||
| 181 | continue; | ||
| 182 | } | ||
| 183 | if (ret > 0) { | ||
| 184 | n = &pn->rb_right; | ||
| 185 | continue; | ||
| 186 | } | ||
| 187 | |||
| 188 | /* Search the QP list to see if this is already there. */ | ||
| 189 | list_for_each_entry_rcu(p, &tmcast->qp_list, list) { | ||
| 190 | if (p->qp == mqp->qp) { | ||
| 191 | spin_unlock_irqrestore(&mcast_lock, flags); | ||
| 192 | ret = ESRCH; | ||
| 193 | goto bail; | ||
| 194 | } | ||
| 195 | } | ||
| 196 | list_add_tail_rcu(&mqp->list, &tmcast->qp_list); | ||
| 197 | spin_unlock_irqrestore(&mcast_lock, flags); | ||
| 198 | ret = EEXIST; | ||
| 199 | goto bail; | ||
| 200 | } | ||
| 201 | |||
| 202 | list_add_tail_rcu(&mqp->list, &mcast->qp_list); | ||
| 203 | |||
| 204 | atomic_inc(&mcast->refcount); | ||
| 205 | rb_link_node(&mcast->rb_node, pn, n); | ||
| 206 | rb_insert_color(&mcast->rb_node, &mcast_tree); | ||
| 207 | |||
| 208 | spin_unlock_irqrestore(&mcast_lock, flags); | ||
| 209 | |||
| 210 | ret = 0; | ||
| 211 | |||
| 212 | bail: | ||
| 213 | return ret; | ||
| 214 | } | ||
| 215 | |||
| 216 | int ipath_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) | ||
| 217 | { | ||
| 218 | struct ipath_qp *qp = to_iqp(ibqp); | ||
| 219 | struct ipath_mcast *mcast; | ||
| 220 | struct ipath_mcast_qp *mqp; | ||
| 221 | int ret; | ||
| 222 | |||
| 223 | /* | ||
| 224 | * Allocate data structures since its better to do this outside of | ||
| 225 | * spin locks and it will most likely be needed. | ||
| 226 | */ | ||
| 227 | mcast = ipath_mcast_alloc(gid); | ||
| 228 | if (mcast == NULL) { | ||
| 229 | ret = -ENOMEM; | ||
| 230 | goto bail; | ||
| 231 | } | ||
| 232 | mqp = ipath_mcast_qp_alloc(qp); | ||
| 233 | if (mqp == NULL) { | ||
| 234 | ipath_mcast_free(mcast); | ||
| 235 | ret = -ENOMEM; | ||
| 236 | goto bail; | ||
| 237 | } | ||
| 238 | switch (ipath_mcast_add(mcast, mqp)) { | ||
| 239 | case ESRCH: | ||
| 240 | /* Neither was used: can't attach the same QP twice. */ | ||
| 241 | ipath_mcast_qp_free(mqp); | ||
| 242 | ipath_mcast_free(mcast); | ||
| 243 | ret = -EINVAL; | ||
| 244 | goto bail; | ||
| 245 | case EEXIST: /* The mcast wasn't used */ | ||
| 246 | ipath_mcast_free(mcast); | ||
| 247 | break; | ||
| 248 | default: | ||
| 249 | break; | ||
| 250 | } | ||
| 251 | |||
| 252 | ret = 0; | ||
| 253 | |||
| 254 | bail: | ||
| 255 | return ret; | ||
| 256 | } | ||
| 257 | |||
| 258 | int ipath_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) | ||
| 259 | { | ||
| 260 | struct ipath_qp *qp = to_iqp(ibqp); | ||
| 261 | struct ipath_mcast *mcast = NULL; | ||
| 262 | struct ipath_mcast_qp *p, *tmp; | ||
| 263 | struct rb_node *n; | ||
| 264 | unsigned long flags; | ||
| 265 | int last = 0; | ||
| 266 | int ret; | ||
| 267 | |||
| 268 | spin_lock_irqsave(&mcast_lock, flags); | ||
| 269 | |||
| 270 | /* Find the GID in the mcast table. */ | ||
| 271 | n = mcast_tree.rb_node; | ||
| 272 | while (1) { | ||
| 273 | if (n == NULL) { | ||
| 274 | spin_unlock_irqrestore(&mcast_lock, flags); | ||
| 275 | ret = 0; | ||
| 276 | goto bail; | ||
| 277 | } | ||
| 278 | |||
| 279 | mcast = rb_entry(n, struct ipath_mcast, rb_node); | ||
| 280 | ret = memcmp(gid->raw, mcast->mgid.raw, | ||
| 281 | sizeof(union ib_gid)); | ||
| 282 | if (ret < 0) | ||
| 283 | n = n->rb_left; | ||
| 284 | else if (ret > 0) | ||
| 285 | n = n->rb_right; | ||
| 286 | else | ||
| 287 | break; | ||
| 288 | } | ||
| 289 | |||
| 290 | /* Search the QP list. */ | ||
| 291 | list_for_each_entry_safe(p, tmp, &mcast->qp_list, list) { | ||
| 292 | if (p->qp != qp) | ||
| 293 | continue; | ||
| 294 | /* | ||
| 295 | * We found it, so remove it, but don't poison the forward | ||
| 296 | * link until we are sure there are no list walkers. | ||
| 297 | */ | ||
| 298 | list_del_rcu(&p->list); | ||
| 299 | |||
| 300 | /* If this was the last attached QP, remove the GID too. */ | ||
| 301 | if (list_empty(&mcast->qp_list)) { | ||
| 302 | rb_erase(&mcast->rb_node, &mcast_tree); | ||
| 303 | last = 1; | ||
| 304 | } | ||
| 305 | break; | ||
| 306 | } | ||
| 307 | |||
| 308 | spin_unlock_irqrestore(&mcast_lock, flags); | ||
| 309 | |||
| 310 | if (p) { | ||
| 311 | /* | ||
| 312 | * Wait for any list walkers to finish before freeing the | ||
| 313 | * list element. | ||
| 314 | */ | ||
| 315 | wait_event(mcast->wait, atomic_read(&mcast->refcount) <= 1); | ||
| 316 | ipath_mcast_qp_free(p); | ||
| 317 | } | ||
| 318 | if (last) { | ||
| 319 | atomic_dec(&mcast->refcount); | ||
| 320 | wait_event(mcast->wait, !atomic_read(&mcast->refcount)); | ||
| 321 | ipath_mcast_free(mcast); | ||
| 322 | } | ||
| 323 | |||
| 324 | ret = 0; | ||
| 325 | |||
| 326 | bail: | ||
| 327 | return ret; | ||
| 328 | } | ||
| 329 | |||
| 330 | int ipath_mcast_tree_empty(void) | ||
| 331 | { | ||
| 332 | return mcast_tree.rb_node == NULL; | ||
| 333 | } | ||
