|
|
1.1 ! root 1: /* ! 2: * Copyright (C) 2007 Michael Brown <[email protected]>. ! 3: * ! 4: * Based in part upon the original driver by Mellanox Technologies ! 5: * Ltd. Portions may be Copyright (c) Mellanox Technologies Ltd. ! 6: * ! 7: * This program is free software; you can redistribute it and/or ! 8: * modify it under the terms of the GNU General Public License as ! 9: * published by the Free Software Foundation; either version 2 of the ! 10: * License, or any later version. ! 11: * ! 12: * This program is distributed in the hope that it will be useful, but ! 13: * WITHOUT ANY WARRANTY; without even the implied warranty of ! 14: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 15: * General Public License for more details. ! 16: * ! 17: * You should have received a copy of the GNU General Public License ! 18: * along with this program; if not, write to the Free Software ! 19: * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ! 20: */ ! 21: ! 22: FILE_LICENCE ( GPL2_OR_LATER ); ! 23: ! 24: #include <stdint.h> ! 25: #include <stdlib.h> ! 26: #include <stdio.h> ! 27: #include <string.h> ! 28: #include <strings.h> ! 29: #include <unistd.h> ! 30: #include <errno.h> ! 31: #include <byteswap.h> ! 32: #include <ipxe/io.h> ! 33: #include <ipxe/pci.h> ! 34: #include <ipxe/malloc.h> ! 35: #include <ipxe/umalloc.h> ! 36: #include <ipxe/iobuf.h> ! 37: #include <ipxe/netdevice.h> ! 38: #include <ipxe/infiniband.h> ! 39: #include <ipxe/ib_smc.h> ! 40: #include "arbel.h" ! 41: ! 42: /** ! 43: * @file ! 44: * ! 45: * Mellanox Arbel Infiniband HCA ! 46: * ! 47: */ ! 48: ! 49: /*************************************************************************** ! 50: * ! 51: * Queue number allocation ! 52: * ! 53: *************************************************************************** ! 54: */ ! 55: ! 56: /** ! 57: * Allocate offset within usage bitmask ! 58: * ! 59: * @v bits Usage bitmask ! 60: * @v bits_len Length of usage bitmask ! 61: * @ret bit First free bit within bitmask, or negative error ! 62: */ ! 63: static int arbel_bitmask_alloc ( arbel_bitmask_t *bits, ! 64: unsigned int bits_len ) { ! 65: unsigned int bit = 0; ! 66: arbel_bitmask_t mask = 1; ! 67: ! 68: while ( bit < bits_len ) { ! 69: if ( ( mask & *bits ) == 0 ) { ! 70: *bits |= mask; ! 71: return bit; ! 72: } ! 73: bit++; ! 74: mask = ( mask << 1 ) | ( mask >> ( 8 * sizeof ( mask ) - 1 ) ); ! 75: if ( mask == 1 ) ! 76: bits++; ! 77: } ! 78: return -ENFILE; ! 79: } ! 80: ! 81: /** ! 82: * Free offset within usage bitmask ! 83: * ! 84: * @v bits Usage bitmask ! 85: * @v bit Bit within bitmask ! 86: */ ! 87: static void arbel_bitmask_free ( arbel_bitmask_t *bits, int bit ) { ! 88: arbel_bitmask_t mask; ! 89: ! 90: mask = ( 1 << ( bit % ( 8 * sizeof ( mask ) ) ) ); ! 91: bits += ( bit / ( 8 * sizeof ( mask ) ) ); ! 92: *bits &= ~mask; ! 93: } ! 94: ! 95: /*************************************************************************** ! 96: * ! 97: * HCA commands ! 98: * ! 99: *************************************************************************** ! 100: */ ! 101: ! 102: /** ! 103: * Wait for Arbel command completion ! 104: * ! 105: * @v arbel Arbel device ! 106: * @ret rc Return status code ! 107: */ ! 108: static int arbel_cmd_wait ( struct arbel *arbel, ! 109: struct arbelprm_hca_command_register *hcr ) { ! 110: unsigned int wait; ! 111: ! 112: for ( wait = ARBEL_HCR_MAX_WAIT_MS ; wait ; wait-- ) { ! 113: hcr->u.dwords[6] = ! 114: readl ( arbel->config + ARBEL_HCR_REG ( 6 ) ); ! 115: if ( MLX_GET ( hcr, go ) == 0 ) ! 116: return 0; ! 117: mdelay ( 1 ); ! 118: } ! 119: return -EBUSY; ! 120: } ! 121: ! 122: /** ! 123: * Issue HCA command ! 124: * ! 125: * @v arbel Arbel device ! 126: * @v command Command opcode, flags and input/output lengths ! 127: * @v op_mod Opcode modifier (0 if no modifier applicable) ! 128: * @v in Input parameters ! 129: * @v in_mod Input modifier (0 if no modifier applicable) ! 130: * @v out Output parameters ! 131: * @ret rc Return status code ! 132: */ ! 133: static int arbel_cmd ( struct arbel *arbel, unsigned long command, ! 134: unsigned int op_mod, const void *in, ! 135: unsigned int in_mod, void *out ) { ! 136: struct arbelprm_hca_command_register hcr; ! 137: unsigned int opcode = ARBEL_HCR_OPCODE ( command ); ! 138: size_t in_len = ARBEL_HCR_IN_LEN ( command ); ! 139: size_t out_len = ARBEL_HCR_OUT_LEN ( command ); ! 140: void *in_buffer; ! 141: void *out_buffer; ! 142: unsigned int status; ! 143: unsigned int i; ! 144: int rc; ! 145: ! 146: assert ( in_len <= ARBEL_MBOX_SIZE ); ! 147: assert ( out_len <= ARBEL_MBOX_SIZE ); ! 148: ! 149: DBGC2 ( arbel, "Arbel %p command %02x in %zx%s out %zx%s\n", ! 150: arbel, opcode, in_len, ! 151: ( ( command & ARBEL_HCR_IN_MBOX ) ? "(mbox)" : "" ), out_len, ! 152: ( ( command & ARBEL_HCR_OUT_MBOX ) ? "(mbox)" : "" ) ); ! 153: ! 154: /* Check that HCR is free */ ! 155: if ( ( rc = arbel_cmd_wait ( arbel, &hcr ) ) != 0 ) { ! 156: DBGC ( arbel, "Arbel %p command interface locked\n", arbel ); ! 157: return rc; ! 158: } ! 159: ! 160: /* Prepare HCR */ ! 161: memset ( &hcr, 0, sizeof ( hcr ) ); ! 162: in_buffer = &hcr.u.dwords[0]; ! 163: if ( in_len && ( command & ARBEL_HCR_IN_MBOX ) ) { ! 164: in_buffer = arbel->mailbox_in; ! 165: MLX_FILL_H ( &hcr, 0, in_param_h, virt_to_bus ( in_buffer ) ); ! 166: MLX_FILL_1 ( &hcr, 1, in_param_l, virt_to_bus ( in_buffer ) ); ! 167: } ! 168: memcpy ( in_buffer, in, in_len ); ! 169: MLX_FILL_1 ( &hcr, 2, input_modifier, in_mod ); ! 170: out_buffer = &hcr.u.dwords[3]; ! 171: if ( out_len && ( command & ARBEL_HCR_OUT_MBOX ) ) { ! 172: out_buffer = arbel->mailbox_out; ! 173: MLX_FILL_H ( &hcr, 3, out_param_h, ! 174: virt_to_bus ( out_buffer ) ); ! 175: MLX_FILL_1 ( &hcr, 4, out_param_l, ! 176: virt_to_bus ( out_buffer ) ); ! 177: } ! 178: MLX_FILL_3 ( &hcr, 6, ! 179: opcode, opcode, ! 180: opcode_modifier, op_mod, ! 181: go, 1 ); ! 182: DBGC ( arbel, "Arbel %p issuing command %04x\n", arbel, opcode ); ! 183: DBGC2_HDA ( arbel, virt_to_phys ( arbel->config + ARBEL_HCR_BASE ), ! 184: &hcr, sizeof ( hcr ) ); ! 185: if ( in_len && ( command & ARBEL_HCR_IN_MBOX ) ) { ! 186: DBGC2 ( arbel, "Input mailbox:\n" ); ! 187: DBGC2_HDA ( arbel, virt_to_phys ( in_buffer ), in_buffer, ! 188: ( ( in_len < 512 ) ? in_len : 512 ) ); ! 189: } ! 190: ! 191: /* Issue command */ ! 192: for ( i = 0 ; i < ( sizeof ( hcr ) / sizeof ( hcr.u.dwords[0] ) ) ; ! 193: i++ ) { ! 194: writel ( hcr.u.dwords[i], ! 195: arbel->config + ARBEL_HCR_REG ( i ) ); ! 196: barrier(); ! 197: } ! 198: ! 199: /* Wait for command completion */ ! 200: if ( ( rc = arbel_cmd_wait ( arbel, &hcr ) ) != 0 ) { ! 201: DBGC ( arbel, "Arbel %p timed out waiting for command:\n", ! 202: arbel ); ! 203: DBGC_HD ( arbel, &hcr, sizeof ( hcr ) ); ! 204: return rc; ! 205: } ! 206: ! 207: /* Check command status */ ! 208: status = MLX_GET ( &hcr, status ); ! 209: if ( status != 0 ) { ! 210: DBGC ( arbel, "Arbel %p command failed with status %02x:\n", ! 211: arbel, status ); ! 212: DBGC_HD ( arbel, &hcr, sizeof ( hcr ) ); ! 213: return -EIO; ! 214: } ! 215: ! 216: /* Read output parameters, if any */ ! 217: hcr.u.dwords[3] = readl ( arbel->config + ARBEL_HCR_REG ( 3 ) ); ! 218: hcr.u.dwords[4] = readl ( arbel->config + ARBEL_HCR_REG ( 4 ) ); ! 219: memcpy ( out, out_buffer, out_len ); ! 220: if ( out_len ) { ! 221: DBGC2 ( arbel, "Output%s:\n", ! 222: ( command & ARBEL_HCR_OUT_MBOX ) ? " mailbox" : "" ); ! 223: DBGC2_HDA ( arbel, virt_to_phys ( out_buffer ), out_buffer, ! 224: ( ( out_len < 512 ) ? out_len : 512 ) ); ! 225: } ! 226: ! 227: return 0; ! 228: } ! 229: ! 230: static inline int ! 231: arbel_cmd_query_dev_lim ( struct arbel *arbel, ! 232: struct arbelprm_query_dev_lim *dev_lim ) { ! 233: return arbel_cmd ( arbel, ! 234: ARBEL_HCR_OUT_CMD ( ARBEL_HCR_QUERY_DEV_LIM, ! 235: 1, sizeof ( *dev_lim ) ), ! 236: 0, NULL, 0, dev_lim ); ! 237: } ! 238: ! 239: static inline int ! 240: arbel_cmd_query_fw ( struct arbel *arbel, struct arbelprm_query_fw *fw ) { ! 241: return arbel_cmd ( arbel, ! 242: ARBEL_HCR_OUT_CMD ( ARBEL_HCR_QUERY_FW, ! 243: 1, sizeof ( *fw ) ), ! 244: 0, NULL, 0, fw ); ! 245: } ! 246: ! 247: static inline int ! 248: arbel_cmd_init_hca ( struct arbel *arbel, ! 249: const struct arbelprm_init_hca *init_hca ) { ! 250: return arbel_cmd ( arbel, ! 251: ARBEL_HCR_IN_CMD ( ARBEL_HCR_INIT_HCA, ! 252: 1, sizeof ( *init_hca ) ), ! 253: 0, init_hca, 0, NULL ); ! 254: } ! 255: ! 256: static inline int ! 257: arbel_cmd_close_hca ( struct arbel *arbel ) { ! 258: return arbel_cmd ( arbel, ! 259: ARBEL_HCR_VOID_CMD ( ARBEL_HCR_CLOSE_HCA ), ! 260: 0, NULL, 0, NULL ); ! 261: } ! 262: ! 263: static inline int ! 264: arbel_cmd_init_ib ( struct arbel *arbel, unsigned int port, ! 265: const struct arbelprm_init_ib *init_ib ) { ! 266: return arbel_cmd ( arbel, ! 267: ARBEL_HCR_IN_CMD ( ARBEL_HCR_INIT_IB, ! 268: 1, sizeof ( *init_ib ) ), ! 269: 0, init_ib, port, NULL ); ! 270: } ! 271: ! 272: static inline int ! 273: arbel_cmd_close_ib ( struct arbel *arbel, unsigned int port ) { ! 274: return arbel_cmd ( arbel, ! 275: ARBEL_HCR_VOID_CMD ( ARBEL_HCR_CLOSE_IB ), ! 276: 0, NULL, port, NULL ); ! 277: } ! 278: ! 279: static inline int ! 280: arbel_cmd_sw2hw_mpt ( struct arbel *arbel, unsigned int index, ! 281: const struct arbelprm_mpt *mpt ) { ! 282: return arbel_cmd ( arbel, ! 283: ARBEL_HCR_IN_CMD ( ARBEL_HCR_SW2HW_MPT, ! 284: 1, sizeof ( *mpt ) ), ! 285: 0, mpt, index, NULL ); ! 286: } ! 287: ! 288: static inline int ! 289: arbel_cmd_map_eq ( struct arbel *arbel, unsigned long index_map, ! 290: const struct arbelprm_event_mask *mask ) { ! 291: return arbel_cmd ( arbel, ! 292: ARBEL_HCR_IN_CMD ( ARBEL_HCR_MAP_EQ, ! 293: 0, sizeof ( *mask ) ), ! 294: 0, mask, index_map, NULL ); ! 295: } ! 296: ! 297: static inline int ! 298: arbel_cmd_sw2hw_eq ( struct arbel *arbel, unsigned int index, ! 299: const struct arbelprm_eqc *eqctx ) { ! 300: return arbel_cmd ( arbel, ! 301: ARBEL_HCR_IN_CMD ( ARBEL_HCR_SW2HW_EQ, ! 302: 1, sizeof ( *eqctx ) ), ! 303: 0, eqctx, index, NULL ); ! 304: } ! 305: ! 306: static inline int ! 307: arbel_cmd_hw2sw_eq ( struct arbel *arbel, unsigned int index, ! 308: struct arbelprm_eqc *eqctx ) { ! 309: return arbel_cmd ( arbel, ! 310: ARBEL_HCR_OUT_CMD ( ARBEL_HCR_HW2SW_EQ, ! 311: 1, sizeof ( *eqctx ) ), ! 312: 1, NULL, index, eqctx ); ! 313: } ! 314: ! 315: static inline int ! 316: arbel_cmd_sw2hw_cq ( struct arbel *arbel, unsigned long cqn, ! 317: const struct arbelprm_completion_queue_context *cqctx ) { ! 318: return arbel_cmd ( arbel, ! 319: ARBEL_HCR_IN_CMD ( ARBEL_HCR_SW2HW_CQ, ! 320: 1, sizeof ( *cqctx ) ), ! 321: 0, cqctx, cqn, NULL ); ! 322: } ! 323: ! 324: static inline int ! 325: arbel_cmd_hw2sw_cq ( struct arbel *arbel, unsigned long cqn, ! 326: struct arbelprm_completion_queue_context *cqctx) { ! 327: return arbel_cmd ( arbel, ! 328: ARBEL_HCR_OUT_CMD ( ARBEL_HCR_HW2SW_CQ, ! 329: 1, sizeof ( *cqctx ) ), ! 330: 0, NULL, cqn, cqctx ); ! 331: } ! 332: ! 333: static inline int ! 334: arbel_cmd_query_cq ( struct arbel *arbel, unsigned long cqn, ! 335: struct arbelprm_completion_queue_context *cqctx ) { ! 336: return arbel_cmd ( arbel, ! 337: ARBEL_HCR_OUT_CMD ( ARBEL_HCR_QUERY_CQ, ! 338: 1, sizeof ( *cqctx ) ), ! 339: 0, NULL, cqn, cqctx ); ! 340: } ! 341: ! 342: static inline int ! 343: arbel_cmd_rst2init_qpee ( struct arbel *arbel, unsigned long qpn, ! 344: const struct arbelprm_qp_ee_state_transitions *ctx ){ ! 345: return arbel_cmd ( arbel, ! 346: ARBEL_HCR_IN_CMD ( ARBEL_HCR_RST2INIT_QPEE, ! 347: 1, sizeof ( *ctx ) ), ! 348: 0, ctx, qpn, NULL ); ! 349: } ! 350: ! 351: static inline int ! 352: arbel_cmd_init2rtr_qpee ( struct arbel *arbel, unsigned long qpn, ! 353: const struct arbelprm_qp_ee_state_transitions *ctx ){ ! 354: return arbel_cmd ( arbel, ! 355: ARBEL_HCR_IN_CMD ( ARBEL_HCR_INIT2RTR_QPEE, ! 356: 1, sizeof ( *ctx ) ), ! 357: 0, ctx, qpn, NULL ); ! 358: } ! 359: ! 360: static inline int ! 361: arbel_cmd_rtr2rts_qpee ( struct arbel *arbel, unsigned long qpn, ! 362: const struct arbelprm_qp_ee_state_transitions *ctx ) { ! 363: return arbel_cmd ( arbel, ! 364: ARBEL_HCR_IN_CMD ( ARBEL_HCR_RTR2RTS_QPEE, ! 365: 1, sizeof ( *ctx ) ), ! 366: 0, ctx, qpn, NULL ); ! 367: } ! 368: ! 369: static inline int ! 370: arbel_cmd_rts2rts_qpee ( struct arbel *arbel, unsigned long qpn, ! 371: const struct arbelprm_qp_ee_state_transitions *ctx ) { ! 372: return arbel_cmd ( arbel, ! 373: ARBEL_HCR_IN_CMD ( ARBEL_HCR_RTS2RTS_QPEE, ! 374: 1, sizeof ( *ctx ) ), ! 375: 0, ctx, qpn, NULL ); ! 376: } ! 377: ! 378: static inline int ! 379: arbel_cmd_2rst_qpee ( struct arbel *arbel, unsigned long qpn ) { ! 380: return arbel_cmd ( arbel, ! 381: ARBEL_HCR_VOID_CMD ( ARBEL_HCR_2RST_QPEE ), ! 382: 0x03, NULL, qpn, NULL ); ! 383: } ! 384: ! 385: static inline int ! 386: arbel_cmd_query_qpee ( struct arbel *arbel, unsigned long qpn, ! 387: struct arbelprm_qp_ee_state_transitions *ctx ) { ! 388: return arbel_cmd ( arbel, ! 389: ARBEL_HCR_OUT_CMD ( ARBEL_HCR_QUERY_QPEE, ! 390: 1, sizeof ( *ctx ) ), ! 391: 0, NULL, qpn, ctx ); ! 392: } ! 393: ! 394: static inline int ! 395: arbel_cmd_conf_special_qp ( struct arbel *arbel, unsigned int qp_type, ! 396: unsigned long base_qpn ) { ! 397: return arbel_cmd ( arbel, ! 398: ARBEL_HCR_VOID_CMD ( ARBEL_HCR_CONF_SPECIAL_QP ), ! 399: qp_type, NULL, base_qpn, NULL ); ! 400: } ! 401: ! 402: static inline int ! 403: arbel_cmd_mad_ifc ( struct arbel *arbel, unsigned int port, ! 404: union arbelprm_mad *mad ) { ! 405: return arbel_cmd ( arbel, ! 406: ARBEL_HCR_INOUT_CMD ( ARBEL_HCR_MAD_IFC, ! 407: 1, sizeof ( *mad ), ! 408: 1, sizeof ( *mad ) ), ! 409: 0x03, mad, port, mad ); ! 410: } ! 411: ! 412: static inline int ! 413: arbel_cmd_read_mgm ( struct arbel *arbel, unsigned int index, ! 414: struct arbelprm_mgm_entry *mgm ) { ! 415: return arbel_cmd ( arbel, ! 416: ARBEL_HCR_OUT_CMD ( ARBEL_HCR_READ_MGM, ! 417: 1, sizeof ( *mgm ) ), ! 418: 0, NULL, index, mgm ); ! 419: } ! 420: ! 421: static inline int ! 422: arbel_cmd_write_mgm ( struct arbel *arbel, unsigned int index, ! 423: const struct arbelprm_mgm_entry *mgm ) { ! 424: return arbel_cmd ( arbel, ! 425: ARBEL_HCR_IN_CMD ( ARBEL_HCR_WRITE_MGM, ! 426: 1, sizeof ( *mgm ) ), ! 427: 0, mgm, index, NULL ); ! 428: } ! 429: ! 430: static inline int ! 431: arbel_cmd_mgid_hash ( struct arbel *arbel, const union ib_gid *gid, ! 432: struct arbelprm_mgm_hash *hash ) { ! 433: return arbel_cmd ( arbel, ! 434: ARBEL_HCR_INOUT_CMD ( ARBEL_HCR_MGID_HASH, ! 435: 1, sizeof ( *gid ), ! 436: 0, sizeof ( *hash ) ), ! 437: 0, gid, 0, hash ); ! 438: } ! 439: ! 440: static inline int ! 441: arbel_cmd_run_fw ( struct arbel *arbel ) { ! 442: return arbel_cmd ( arbel, ! 443: ARBEL_HCR_VOID_CMD ( ARBEL_HCR_RUN_FW ), ! 444: 0, NULL, 0, NULL ); ! 445: } ! 446: ! 447: static inline int ! 448: arbel_cmd_disable_lam ( struct arbel *arbel ) { ! 449: return arbel_cmd ( arbel, ! 450: ARBEL_HCR_VOID_CMD ( ARBEL_HCR_DISABLE_LAM ), ! 451: 0, NULL, 0, NULL ); ! 452: } ! 453: ! 454: static inline int ! 455: arbel_cmd_enable_lam ( struct arbel *arbel, struct arbelprm_access_lam *lam ) { ! 456: return arbel_cmd ( arbel, ! 457: ARBEL_HCR_OUT_CMD ( ARBEL_HCR_ENABLE_LAM, ! 458: 1, sizeof ( *lam ) ), ! 459: 1, NULL, 0, lam ); ! 460: } ! 461: ! 462: static inline int ! 463: arbel_cmd_unmap_icm ( struct arbel *arbel, unsigned int page_count, ! 464: const struct arbelprm_scalar_parameter *offset ) { ! 465: return arbel_cmd ( arbel, ! 466: ARBEL_HCR_IN_CMD ( ARBEL_HCR_UNMAP_ICM, 0, ! 467: sizeof ( *offset ) ), ! 468: 0, offset, page_count, NULL ); ! 469: } ! 470: ! 471: static inline int ! 472: arbel_cmd_map_icm ( struct arbel *arbel, ! 473: const struct arbelprm_virtual_physical_mapping *map ) { ! 474: return arbel_cmd ( arbel, ! 475: ARBEL_HCR_IN_CMD ( ARBEL_HCR_MAP_ICM, ! 476: 1, sizeof ( *map ) ), ! 477: 0, map, 1, NULL ); ! 478: } ! 479: ! 480: static inline int ! 481: arbel_cmd_unmap_icm_aux ( struct arbel *arbel ) { ! 482: return arbel_cmd ( arbel, ! 483: ARBEL_HCR_VOID_CMD ( ARBEL_HCR_UNMAP_ICM_AUX ), ! 484: 0, NULL, 0, NULL ); ! 485: } ! 486: ! 487: static inline int ! 488: arbel_cmd_map_icm_aux ( struct arbel *arbel, ! 489: const struct arbelprm_virtual_physical_mapping *map ) { ! 490: return arbel_cmd ( arbel, ! 491: ARBEL_HCR_IN_CMD ( ARBEL_HCR_MAP_ICM_AUX, ! 492: 1, sizeof ( *map ) ), ! 493: 0, map, 1, NULL ); ! 494: } ! 495: ! 496: static inline int ! 497: arbel_cmd_set_icm_size ( struct arbel *arbel, ! 498: const struct arbelprm_scalar_parameter *icm_size, ! 499: struct arbelprm_scalar_parameter *icm_aux_size ) { ! 500: return arbel_cmd ( arbel, ! 501: ARBEL_HCR_INOUT_CMD ( ARBEL_HCR_SET_ICM_SIZE, ! 502: 0, sizeof ( *icm_size ), ! 503: 0, sizeof ( *icm_aux_size ) ), ! 504: 0, icm_size, 0, icm_aux_size ); ! 505: } ! 506: ! 507: static inline int ! 508: arbel_cmd_unmap_fa ( struct arbel *arbel ) { ! 509: return arbel_cmd ( arbel, ! 510: ARBEL_HCR_VOID_CMD ( ARBEL_HCR_UNMAP_FA ), ! 511: 0, NULL, 0, NULL ); ! 512: } ! 513: ! 514: static inline int ! 515: arbel_cmd_map_fa ( struct arbel *arbel, ! 516: const struct arbelprm_virtual_physical_mapping *map ) { ! 517: return arbel_cmd ( arbel, ! 518: ARBEL_HCR_IN_CMD ( ARBEL_HCR_MAP_FA, ! 519: 1, sizeof ( *map ) ), ! 520: 0, map, 1, NULL ); ! 521: } ! 522: ! 523: /*************************************************************************** ! 524: * ! 525: * MAD operations ! 526: * ! 527: *************************************************************************** ! 528: */ ! 529: ! 530: /** ! 531: * Issue management datagram ! 532: * ! 533: * @v ibdev Infiniband device ! 534: * @v mad Management datagram ! 535: * @ret rc Return status code ! 536: */ ! 537: static int arbel_mad ( struct ib_device *ibdev, union ib_mad *mad ) { ! 538: struct arbel *arbel = ib_get_drvdata ( ibdev ); ! 539: union arbelprm_mad mad_ifc; ! 540: int rc; ! 541: ! 542: linker_assert ( sizeof ( *mad ) == sizeof ( mad_ifc.mad ), ! 543: mad_size_mismatch ); ! 544: ! 545: /* Copy in request packet */ ! 546: memcpy ( &mad_ifc.mad, mad, sizeof ( mad_ifc.mad ) ); ! 547: ! 548: /* Issue MAD */ ! 549: if ( ( rc = arbel_cmd_mad_ifc ( arbel, ibdev->port, ! 550: &mad_ifc ) ) != 0 ) { ! 551: DBGC ( arbel, "Arbel %p port %d could not issue MAD IFC: %s\n", ! 552: arbel, ibdev->port, strerror ( rc ) ); ! 553: return rc; ! 554: } ! 555: ! 556: /* Copy out reply packet */ ! 557: memcpy ( mad, &mad_ifc.mad, sizeof ( *mad ) ); ! 558: ! 559: if ( mad->hdr.status != 0 ) { ! 560: DBGC ( arbel, "Arbel %p port %d MAD IFC status %04x\n", ! 561: arbel, ibdev->port, ntohs ( mad->hdr.status ) ); ! 562: return -EIO; ! 563: } ! 564: return 0; ! 565: } ! 566: ! 567: /*************************************************************************** ! 568: * ! 569: * Completion queue operations ! 570: * ! 571: *************************************************************************** ! 572: */ ! 573: ! 574: /** ! 575: * Dump completion queue context (for debugging only) ! 576: * ! 577: * @v arbel Arbel device ! 578: * @v cq Completion queue ! 579: * @ret rc Return status code ! 580: */ ! 581: static __attribute__ (( unused )) int ! 582: arbel_dump_cqctx ( struct arbel *arbel, struct ib_completion_queue *cq ) { ! 583: struct arbelprm_completion_queue_context cqctx; ! 584: int rc; ! 585: ! 586: memset ( &cqctx, 0, sizeof ( cqctx ) ); ! 587: if ( ( rc = arbel_cmd_query_cq ( arbel, cq->cqn, &cqctx ) ) != 0 ) { ! 588: DBGC ( arbel, "Arbel %p CQN %#lx QUERY_CQ failed: %s\n", ! 589: arbel, cq->cqn, strerror ( rc ) ); ! 590: return rc; ! 591: } ! 592: DBGC ( arbel, "Arbel %p CQN %#lx context:\n", arbel, cq->cqn ); ! 593: DBGC_HDA ( arbel, 0, &cqctx, sizeof ( cqctx ) ); ! 594: ! 595: return 0; ! 596: } ! 597: ! 598: /** ! 599: * Create completion queue ! 600: * ! 601: * @v ibdev Infiniband device ! 602: * @v cq Completion queue ! 603: * @ret rc Return status code ! 604: */ ! 605: static int arbel_create_cq ( struct ib_device *ibdev, ! 606: struct ib_completion_queue *cq ) { ! 607: struct arbel *arbel = ib_get_drvdata ( ibdev ); ! 608: struct arbel_completion_queue *arbel_cq; ! 609: struct arbelprm_completion_queue_context cqctx; ! 610: struct arbelprm_cq_ci_db_record *ci_db_rec; ! 611: struct arbelprm_cq_arm_db_record *arm_db_rec; ! 612: int cqn_offset; ! 613: unsigned int i; ! 614: int rc; ! 615: ! 616: /* Find a free completion queue number */ ! 617: cqn_offset = arbel_bitmask_alloc ( arbel->cq_inuse, ARBEL_MAX_CQS ); ! 618: if ( cqn_offset < 0 ) { ! 619: DBGC ( arbel, "Arbel %p out of completion queues\n", arbel ); ! 620: rc = cqn_offset; ! 621: goto err_cqn_offset; ! 622: } ! 623: cq->cqn = ( arbel->limits.reserved_cqs + cqn_offset ); ! 624: ! 625: /* Allocate control structures */ ! 626: arbel_cq = zalloc ( sizeof ( *arbel_cq ) ); ! 627: if ( ! arbel_cq ) { ! 628: rc = -ENOMEM; ! 629: goto err_arbel_cq; ! 630: } ! 631: arbel_cq->ci_doorbell_idx = arbel_cq_ci_doorbell_idx ( arbel, cq ); ! 632: arbel_cq->arm_doorbell_idx = arbel_cq_arm_doorbell_idx ( arbel, cq ); ! 633: ! 634: /* Allocate completion queue itself */ ! 635: arbel_cq->cqe_size = ( cq->num_cqes * sizeof ( arbel_cq->cqe[0] ) ); ! 636: arbel_cq->cqe = malloc_dma ( arbel_cq->cqe_size, ! 637: sizeof ( arbel_cq->cqe[0] ) ); ! 638: if ( ! arbel_cq->cqe ) { ! 639: rc = -ENOMEM; ! 640: goto err_cqe; ! 641: } ! 642: memset ( arbel_cq->cqe, 0, arbel_cq->cqe_size ); ! 643: for ( i = 0 ; i < cq->num_cqes ; i++ ) { ! 644: MLX_FILL_1 ( &arbel_cq->cqe[i].normal, 7, owner, 1 ); ! 645: } ! 646: barrier(); ! 647: ! 648: /* Initialise doorbell records */ ! 649: ci_db_rec = &arbel->db_rec[arbel_cq->ci_doorbell_idx].cq_ci; ! 650: MLX_FILL_1 ( ci_db_rec, 0, counter, 0 ); ! 651: MLX_FILL_2 ( ci_db_rec, 1, ! 652: res, ARBEL_UAR_RES_CQ_CI, ! 653: cq_number, cq->cqn ); ! 654: arm_db_rec = &arbel->db_rec[arbel_cq->arm_doorbell_idx].cq_arm; ! 655: MLX_FILL_1 ( arm_db_rec, 0, counter, 0 ); ! 656: MLX_FILL_2 ( arm_db_rec, 1, ! 657: res, ARBEL_UAR_RES_CQ_ARM, ! 658: cq_number, cq->cqn ); ! 659: ! 660: /* Hand queue over to hardware */ ! 661: memset ( &cqctx, 0, sizeof ( cqctx ) ); ! 662: MLX_FILL_1 ( &cqctx, 0, st, 0xa /* "Event fired" */ ); ! 663: MLX_FILL_H ( &cqctx, 1, start_address_h, ! 664: virt_to_bus ( arbel_cq->cqe ) ); ! 665: MLX_FILL_1 ( &cqctx, 2, start_address_l, ! 666: virt_to_bus ( arbel_cq->cqe ) ); ! 667: MLX_FILL_2 ( &cqctx, 3, ! 668: usr_page, arbel->limits.reserved_uars, ! 669: log_cq_size, fls ( cq->num_cqes - 1 ) ); ! 670: MLX_FILL_1 ( &cqctx, 5, c_eqn, arbel->eq.eqn ); ! 671: MLX_FILL_1 ( &cqctx, 6, pd, ARBEL_GLOBAL_PD ); ! 672: MLX_FILL_1 ( &cqctx, 7, l_key, arbel->lkey ); ! 673: MLX_FILL_1 ( &cqctx, 12, cqn, cq->cqn ); ! 674: MLX_FILL_1 ( &cqctx, 13, ! 675: cq_ci_db_record, arbel_cq->ci_doorbell_idx ); ! 676: MLX_FILL_1 ( &cqctx, 14, ! 677: cq_state_db_record, arbel_cq->arm_doorbell_idx ); ! 678: if ( ( rc = arbel_cmd_sw2hw_cq ( arbel, cq->cqn, &cqctx ) ) != 0 ) { ! 679: DBGC ( arbel, "Arbel %p CQN %#lx SW2HW_CQ failed: %s\n", ! 680: arbel, cq->cqn, strerror ( rc ) ); ! 681: goto err_sw2hw_cq; ! 682: } ! 683: ! 684: DBGC ( arbel, "Arbel %p CQN %#lx ring [%08lx,%08lx), doorbell %08lx\n", ! 685: arbel, cq->cqn, virt_to_phys ( arbel_cq->cqe ), ! 686: ( virt_to_phys ( arbel_cq->cqe ) + arbel_cq->cqe_size ), ! 687: virt_to_phys ( ci_db_rec ) ); ! 688: ib_cq_set_drvdata ( cq, arbel_cq ); ! 689: return 0; ! 690: ! 691: err_sw2hw_cq: ! 692: MLX_FILL_1 ( ci_db_rec, 1, res, ARBEL_UAR_RES_NONE ); ! 693: MLX_FILL_1 ( arm_db_rec, 1, res, ARBEL_UAR_RES_NONE ); ! 694: free_dma ( arbel_cq->cqe, arbel_cq->cqe_size ); ! 695: err_cqe: ! 696: free ( arbel_cq ); ! 697: err_arbel_cq: ! 698: arbel_bitmask_free ( arbel->cq_inuse, cqn_offset ); ! 699: err_cqn_offset: ! 700: return rc; ! 701: } ! 702: ! 703: /** ! 704: * Destroy completion queue ! 705: * ! 706: * @v ibdev Infiniband device ! 707: * @v cq Completion queue ! 708: */ ! 709: static void arbel_destroy_cq ( struct ib_device *ibdev, ! 710: struct ib_completion_queue *cq ) { ! 711: struct arbel *arbel = ib_get_drvdata ( ibdev ); ! 712: struct arbel_completion_queue *arbel_cq = ib_cq_get_drvdata ( cq ); ! 713: struct arbelprm_completion_queue_context cqctx; ! 714: struct arbelprm_cq_ci_db_record *ci_db_rec; ! 715: struct arbelprm_cq_arm_db_record *arm_db_rec; ! 716: int cqn_offset; ! 717: int rc; ! 718: ! 719: /* Take ownership back from hardware */ ! 720: if ( ( rc = arbel_cmd_hw2sw_cq ( arbel, cq->cqn, &cqctx ) ) != 0 ) { ! 721: DBGC ( arbel, "Arbel %p CQN %#lx FATAL HW2SW_CQ failed: " ! 722: "%s\n", arbel, cq->cqn, strerror ( rc ) ); ! 723: /* Leak memory and return; at least we avoid corruption */ ! 724: return; ! 725: } ! 726: ! 727: /* Clear doorbell records */ ! 728: ci_db_rec = &arbel->db_rec[arbel_cq->ci_doorbell_idx].cq_ci; ! 729: arm_db_rec = &arbel->db_rec[arbel_cq->arm_doorbell_idx].cq_arm; ! 730: MLX_FILL_1 ( ci_db_rec, 1, res, ARBEL_UAR_RES_NONE ); ! 731: MLX_FILL_1 ( arm_db_rec, 1, res, ARBEL_UAR_RES_NONE ); ! 732: ! 733: /* Free memory */ ! 734: free_dma ( arbel_cq->cqe, arbel_cq->cqe_size ); ! 735: free ( arbel_cq ); ! 736: ! 737: /* Mark queue number as free */ ! 738: cqn_offset = ( cq->cqn - arbel->limits.reserved_cqs ); ! 739: arbel_bitmask_free ( arbel->cq_inuse, cqn_offset ); ! 740: ! 741: ib_cq_set_drvdata ( cq, NULL ); ! 742: } ! 743: ! 744: /*************************************************************************** ! 745: * ! 746: * Queue pair operations ! 747: * ! 748: *************************************************************************** ! 749: */ ! 750: ! 751: /** ! 752: * Assign queue pair number ! 753: * ! 754: * @v ibdev Infiniband device ! 755: * @v qp Queue pair ! 756: * @ret rc Return status code ! 757: */ ! 758: static int arbel_alloc_qpn ( struct ib_device *ibdev, ! 759: struct ib_queue_pair *qp ) { ! 760: struct arbel *arbel = ib_get_drvdata ( ibdev ); ! 761: unsigned int port_offset; ! 762: int qpn_offset; ! 763: ! 764: /* Calculate queue pair number */ ! 765: port_offset = ( ibdev->port - ARBEL_PORT_BASE ); ! 766: ! 767: switch ( qp->type ) { ! 768: case IB_QPT_SMI: ! 769: qp->qpn = ( arbel->special_qpn_base + port_offset ); ! 770: return 0; ! 771: case IB_QPT_GSI: ! 772: qp->qpn = ( arbel->special_qpn_base + 2 + port_offset ); ! 773: return 0; ! 774: case IB_QPT_UD: ! 775: /* Find a free queue pair number */ ! 776: qpn_offset = arbel_bitmask_alloc ( arbel->qp_inuse, ! 777: ARBEL_MAX_QPS ); ! 778: if ( qpn_offset < 0 ) { ! 779: DBGC ( arbel, "Arbel %p out of queue pairs\n", ! 780: arbel ); ! 781: return qpn_offset; ! 782: } ! 783: qp->qpn = ( ( random() & ARBEL_QPN_RANDOM_MASK ) | ! 784: ( arbel->qpn_base + qpn_offset ) ); ! 785: return 0; ! 786: default: ! 787: DBGC ( arbel, "Arbel %p unsupported QP type %d\n", ! 788: arbel, qp->type ); ! 789: return -ENOTSUP; ! 790: } ! 791: } ! 792: ! 793: /** ! 794: * Free queue pair number ! 795: * ! 796: * @v ibdev Infiniband device ! 797: * @v qp Queue pair ! 798: */ ! 799: static void arbel_free_qpn ( struct ib_device *ibdev, ! 800: struct ib_queue_pair *qp ) { ! 801: struct arbel *arbel = ib_get_drvdata ( ibdev ); ! 802: int qpn_offset; ! 803: ! 804: qpn_offset = ( ( qp->qpn & ~ARBEL_QPN_RANDOM_MASK ) - arbel->qpn_base ); ! 805: if ( qpn_offset >= 0 ) ! 806: arbel_bitmask_free ( arbel->qp_inuse, qpn_offset ); ! 807: } ! 808: ! 809: /** ! 810: * Calculate transmission rate ! 811: * ! 812: * @v av Address vector ! 813: * @ret arbel_rate Arbel rate ! 814: */ ! 815: static unsigned int arbel_rate ( struct ib_address_vector *av ) { ! 816: return ( ( ( av->rate >= IB_RATE_2_5 ) && ( av->rate <= IB_RATE_120 ) ) ! 817: ? ( av->rate + 5 ) : 0 ); ! 818: } ! 819: ! 820: /** Queue pair transport service type map */ ! 821: static uint8_t arbel_qp_st[] = { ! 822: [IB_QPT_SMI] = ARBEL_ST_MLX, ! 823: [IB_QPT_GSI] = ARBEL_ST_MLX, ! 824: [IB_QPT_UD] = ARBEL_ST_UD, ! 825: }; ! 826: ! 827: /** ! 828: * Dump queue pair context (for debugging only) ! 829: * ! 830: * @v arbel Arbel device ! 831: * @v qp Queue pair ! 832: * @ret rc Return status code ! 833: */ ! 834: static __attribute__ (( unused )) int ! 835: arbel_dump_qpctx ( struct arbel *arbel, struct ib_queue_pair *qp ) { ! 836: struct arbelprm_qp_ee_state_transitions qpctx; ! 837: int rc; ! 838: ! 839: memset ( &qpctx, 0, sizeof ( qpctx ) ); ! 840: if ( ( rc = arbel_cmd_query_qpee ( arbel, qp->qpn, &qpctx ) ) != 0 ) { ! 841: DBGC ( arbel, "Arbel %p QPN %#lx QUERY_QPEE failed: %s\n", ! 842: arbel, qp->qpn, strerror ( rc ) ); ! 843: return rc; ! 844: } ! 845: DBGC ( arbel, "Arbel %p QPN %#lx context:\n", arbel, qp->qpn ); ! 846: DBGC_HDA ( arbel, 0, &qpctx.u.dwords[2], ( sizeof ( qpctx ) - 8 ) ); ! 847: ! 848: return 0; ! 849: } ! 850: ! 851: /** ! 852: * Create send work queue ! 853: * ! 854: * @v arbel_send_wq Send work queue ! 855: * @v num_wqes Number of work queue entries ! 856: * @ret rc Return status code ! 857: */ ! 858: static int arbel_create_send_wq ( struct arbel_send_work_queue *arbel_send_wq, ! 859: unsigned int num_wqes ) { ! 860: union arbel_send_wqe *wqe; ! 861: union arbel_send_wqe *next_wqe; ! 862: unsigned int wqe_idx_mask; ! 863: unsigned int i; ! 864: ! 865: /* Allocate work queue */ ! 866: arbel_send_wq->wqe_size = ( num_wqes * ! 867: sizeof ( arbel_send_wq->wqe[0] ) ); ! 868: arbel_send_wq->wqe = malloc_dma ( arbel_send_wq->wqe_size, ! 869: sizeof ( arbel_send_wq->wqe[0] ) ); ! 870: if ( ! arbel_send_wq->wqe ) ! 871: return -ENOMEM; ! 872: memset ( arbel_send_wq->wqe, 0, arbel_send_wq->wqe_size ); ! 873: ! 874: /* Link work queue entries */ ! 875: wqe_idx_mask = ( num_wqes - 1 ); ! 876: for ( i = 0 ; i < num_wqes ; i++ ) { ! 877: wqe = &arbel_send_wq->wqe[i]; ! 878: next_wqe = &arbel_send_wq->wqe[ ( i + 1 ) & wqe_idx_mask ]; ! 879: MLX_FILL_1 ( &wqe->next, 0, nda_31_6, ! 880: ( virt_to_bus ( next_wqe ) >> 6 ) ); ! 881: MLX_FILL_1 ( &wqe->next, 1, always1, 1 ); ! 882: } ! 883: ! 884: return 0; ! 885: } ! 886: ! 887: /** ! 888: * Create receive work queue ! 889: * ! 890: * @v arbel_recv_wq Receive work queue ! 891: * @v num_wqes Number of work queue entries ! 892: * @ret rc Return status code ! 893: */ ! 894: static int arbel_create_recv_wq ( struct arbel_recv_work_queue *arbel_recv_wq, ! 895: unsigned int num_wqes ) { ! 896: struct arbelprm_recv_wqe *wqe; ! 897: struct arbelprm_recv_wqe *next_wqe; ! 898: unsigned int wqe_idx_mask; ! 899: size_t nds; ! 900: unsigned int i; ! 901: unsigned int j; ! 902: ! 903: /* Allocate work queue */ ! 904: arbel_recv_wq->wqe_size = ( num_wqes * ! 905: sizeof ( arbel_recv_wq->wqe[0] ) ); ! 906: arbel_recv_wq->wqe = malloc_dma ( arbel_recv_wq->wqe_size, ! 907: sizeof ( arbel_recv_wq->wqe[0] ) ); ! 908: if ( ! arbel_recv_wq->wqe ) ! 909: return -ENOMEM; ! 910: memset ( arbel_recv_wq->wqe, 0, arbel_recv_wq->wqe_size ); ! 911: ! 912: /* Link work queue entries */ ! 913: wqe_idx_mask = ( num_wqes - 1 ); ! 914: nds = ( ( offsetof ( typeof ( *wqe ), data ) + ! 915: sizeof ( wqe->data[0] ) ) >> 4 ); ! 916: for ( i = 0 ; i < num_wqes ; i++ ) { ! 917: wqe = &arbel_recv_wq->wqe[i].recv; ! 918: next_wqe = &arbel_recv_wq->wqe[( i + 1 ) & wqe_idx_mask].recv; ! 919: MLX_FILL_1 ( &wqe->next, 0, nda_31_6, ! 920: ( virt_to_bus ( next_wqe ) >> 6 ) ); ! 921: MLX_FILL_1 ( &wqe->next, 1, nds, nds ); ! 922: for ( j = 0 ; ( ( ( void * ) &wqe->data[j] ) < ! 923: ( ( void * ) ( wqe + 1 ) ) ) ; j++ ) { ! 924: MLX_FILL_1 ( &wqe->data[j], 1, ! 925: l_key, ARBEL_INVALID_LKEY ); ! 926: } ! 927: } ! 928: ! 929: return 0; ! 930: } ! 931: ! 932: /** ! 933: * Create queue pair ! 934: * ! 935: * @v ibdev Infiniband device ! 936: * @v qp Queue pair ! 937: * @ret rc Return status code ! 938: */ ! 939: static int arbel_create_qp ( struct ib_device *ibdev, ! 940: struct ib_queue_pair *qp ) { ! 941: struct arbel *arbel = ib_get_drvdata ( ibdev ); ! 942: struct arbel_queue_pair *arbel_qp; ! 943: struct arbelprm_qp_ee_state_transitions qpctx; ! 944: struct arbelprm_qp_db_record *send_db_rec; ! 945: struct arbelprm_qp_db_record *recv_db_rec; ! 946: physaddr_t send_wqe_base_adr; ! 947: physaddr_t recv_wqe_base_adr; ! 948: physaddr_t wqe_base_adr; ! 949: int rc; ! 950: ! 951: /* Calculate queue pair number */ ! 952: if ( ( rc = arbel_alloc_qpn ( ibdev, qp ) ) != 0 ) ! 953: goto err_alloc_qpn; ! 954: ! 955: /* Allocate control structures */ ! 956: arbel_qp = zalloc ( sizeof ( *arbel_qp ) ); ! 957: if ( ! arbel_qp ) { ! 958: rc = -ENOMEM; ! 959: goto err_arbel_qp; ! 960: } ! 961: arbel_qp->send.doorbell_idx = arbel_send_doorbell_idx ( arbel, qp ); ! 962: arbel_qp->recv.doorbell_idx = arbel_recv_doorbell_idx ( arbel, qp ); ! 963: ! 964: /* Create send and receive work queues */ ! 965: if ( ( rc = arbel_create_send_wq ( &arbel_qp->send, ! 966: qp->send.num_wqes ) ) != 0 ) ! 967: goto err_create_send_wq; ! 968: if ( ( rc = arbel_create_recv_wq ( &arbel_qp->recv, ! 969: qp->recv.num_wqes ) ) != 0 ) ! 970: goto err_create_recv_wq; ! 971: ! 972: /* Send and receive work queue entries must be within the same 4GB */ ! 973: send_wqe_base_adr = virt_to_bus ( arbel_qp->send.wqe ); ! 974: recv_wqe_base_adr = virt_to_bus ( arbel_qp->recv.wqe ); ! 975: if ( ( sizeof ( physaddr_t ) > sizeof ( uint32_t ) ) && ! 976: ( ( ( ( uint64_t ) send_wqe_base_adr ) >> 32 ) != ! 977: ( ( ( uint64_t ) recv_wqe_base_adr ) >> 32 ) ) ) { ! 978: DBGC ( arbel, "Arbel %p QPN %#lx cannot support send %08lx " ! 979: "recv %08lx\n", arbel, qp->qpn, ! 980: send_wqe_base_adr, recv_wqe_base_adr ); ! 981: rc = -ENOTSUP; ! 982: goto err_unsupported_address_split; ! 983: } ! 984: wqe_base_adr = send_wqe_base_adr; ! 985: ! 986: /* Initialise doorbell records */ ! 987: send_db_rec = &arbel->db_rec[arbel_qp->send.doorbell_idx].qp; ! 988: MLX_FILL_1 ( send_db_rec, 0, counter, 0 ); ! 989: MLX_FILL_2 ( send_db_rec, 1, ! 990: res, ARBEL_UAR_RES_SQ, ! 991: qp_number, qp->qpn ); ! 992: recv_db_rec = &arbel->db_rec[arbel_qp->recv.doorbell_idx].qp; ! 993: MLX_FILL_1 ( recv_db_rec, 0, counter, 0 ); ! 994: MLX_FILL_2 ( recv_db_rec, 1, ! 995: res, ARBEL_UAR_RES_RQ, ! 996: qp_number, qp->qpn ); ! 997: ! 998: /* Transition queue to INIT state */ ! 999: memset ( &qpctx, 0, sizeof ( qpctx ) ); ! 1000: MLX_FILL_3 ( &qpctx, 2, ! 1001: qpc_eec_data.de, 1, ! 1002: qpc_eec_data.pm_state, ARBEL_PM_STATE_MIGRATED, ! 1003: qpc_eec_data.st, arbel_qp_st[qp->type] ); ! 1004: MLX_FILL_4 ( &qpctx, 4, ! 1005: qpc_eec_data.log_rq_size, fls ( qp->recv.num_wqes - 1 ), ! 1006: qpc_eec_data.log_rq_stride, ! 1007: ( fls ( sizeof ( arbel_qp->recv.wqe[0] ) - 1 ) - 4 ), ! 1008: qpc_eec_data.log_sq_size, fls ( qp->send.num_wqes - 1 ), ! 1009: qpc_eec_data.log_sq_stride, ! 1010: ( fls ( sizeof ( arbel_qp->send.wqe[0] ) - 1 ) - 4 ) ); ! 1011: MLX_FILL_1 ( &qpctx, 5, ! 1012: qpc_eec_data.usr_page, arbel->limits.reserved_uars ); ! 1013: MLX_FILL_1 ( &qpctx, 10, qpc_eec_data.primary_address_path.port_number, ! 1014: ibdev->port ); ! 1015: MLX_FILL_1 ( &qpctx, 27, qpc_eec_data.pd, ARBEL_GLOBAL_PD ); ! 1016: MLX_FILL_H ( &qpctx, 28, qpc_eec_data.wqe_base_adr_h, wqe_base_adr ); ! 1017: MLX_FILL_1 ( &qpctx, 29, qpc_eec_data.wqe_lkey, arbel->lkey ); ! 1018: MLX_FILL_1 ( &qpctx, 30, qpc_eec_data.ssc, 1 ); ! 1019: MLX_FILL_1 ( &qpctx, 33, qpc_eec_data.cqn_snd, qp->send.cq->cqn ); ! 1020: MLX_FILL_1 ( &qpctx, 34, qpc_eec_data.snd_wqe_base_adr_l, ! 1021: ( send_wqe_base_adr >> 6 ) ); ! 1022: MLX_FILL_1 ( &qpctx, 35, qpc_eec_data.snd_db_record_index, ! 1023: arbel_qp->send.doorbell_idx ); ! 1024: MLX_FILL_1 ( &qpctx, 38, qpc_eec_data.rsc, 1 ); ! 1025: MLX_FILL_1 ( &qpctx, 41, qpc_eec_data.cqn_rcv, qp->recv.cq->cqn ); ! 1026: MLX_FILL_1 ( &qpctx, 42, qpc_eec_data.rcv_wqe_base_adr_l, ! 1027: ( recv_wqe_base_adr >> 6 ) ); ! 1028: MLX_FILL_1 ( &qpctx, 43, qpc_eec_data.rcv_db_record_index, ! 1029: arbel_qp->recv.doorbell_idx ); ! 1030: if ( ( rc = arbel_cmd_rst2init_qpee ( arbel, qp->qpn, &qpctx )) != 0 ){ ! 1031: DBGC ( arbel, "Arbel %p QPN %#lx RST2INIT_QPEE failed: %s\n", ! 1032: arbel, qp->qpn, strerror ( rc ) ); ! 1033: goto err_rst2init_qpee; ! 1034: } ! 1035: arbel_qp->state = ARBEL_QP_ST_INIT; ! 1036: ! 1037: DBGC ( arbel, "Arbel %p QPN %#lx send ring [%08lx,%08lx), doorbell " ! 1038: "%08lx\n", arbel, qp->qpn, virt_to_phys ( arbel_qp->send.wqe ), ! 1039: ( virt_to_phys ( arbel_qp->send.wqe ) + ! 1040: arbel_qp->send.wqe_size ), ! 1041: virt_to_phys ( send_db_rec ) ); ! 1042: DBGC ( arbel, "Arbel %p QPN %#lx receive ring [%08lx,%08lx), doorbell " ! 1043: "%08lx\n", arbel, qp->qpn, virt_to_phys ( arbel_qp->recv.wqe ), ! 1044: ( virt_to_phys ( arbel_qp->recv.wqe ) + ! 1045: arbel_qp->recv.wqe_size ), ! 1046: virt_to_phys ( recv_db_rec ) ); ! 1047: DBGC ( arbel, "Arbel %p QPN %#lx send CQN %#lx receive CQN %#lx\n", ! 1048: arbel, qp->qpn, qp->send.cq->cqn, qp->recv.cq->cqn ); ! 1049: ib_qp_set_drvdata ( qp, arbel_qp ); ! 1050: return 0; ! 1051: ! 1052: arbel_cmd_2rst_qpee ( arbel, qp->qpn ); ! 1053: err_rst2init_qpee: ! 1054: MLX_FILL_1 ( send_db_rec, 1, res, ARBEL_UAR_RES_NONE ); ! 1055: MLX_FILL_1 ( recv_db_rec, 1, res, ARBEL_UAR_RES_NONE ); ! 1056: err_unsupported_address_split: ! 1057: free_dma ( arbel_qp->recv.wqe, arbel_qp->recv.wqe_size ); ! 1058: err_create_recv_wq: ! 1059: free_dma ( arbel_qp->send.wqe, arbel_qp->send.wqe_size ); ! 1060: err_create_send_wq: ! 1061: free ( arbel_qp ); ! 1062: err_arbel_qp: ! 1063: arbel_free_qpn ( ibdev, qp ); ! 1064: err_alloc_qpn: ! 1065: return rc; ! 1066: } ! 1067: ! 1068: /** ! 1069: * Modify queue pair ! 1070: * ! 1071: * @v ibdev Infiniband device ! 1072: * @v qp Queue pair ! 1073: * @ret rc Return status code ! 1074: */ ! 1075: static int arbel_modify_qp ( struct ib_device *ibdev, ! 1076: struct ib_queue_pair *qp ) { ! 1077: struct arbel *arbel = ib_get_drvdata ( ibdev ); ! 1078: struct arbel_queue_pair *arbel_qp = ib_qp_get_drvdata ( qp ); ! 1079: struct arbelprm_qp_ee_state_transitions qpctx; ! 1080: int rc; ! 1081: ! 1082: /* Transition queue to RTR state, if applicable */ ! 1083: if ( arbel_qp->state < ARBEL_QP_ST_RTR ) { ! 1084: memset ( &qpctx, 0, sizeof ( qpctx ) ); ! 1085: MLX_FILL_2 ( &qpctx, 4, ! 1086: qpc_eec_data.mtu, ARBEL_MTU_2048, ! 1087: qpc_eec_data.msg_max, 11 /* 2^11 = 2048 */ ); ! 1088: if ( ( rc = arbel_cmd_init2rtr_qpee ( arbel, qp->qpn, ! 1089: &qpctx ) ) != 0 ) { ! 1090: DBGC ( arbel, "Arbel %p QPN %#lx INIT2RTR_QPEE failed:" ! 1091: " %s\n", arbel, qp->qpn, strerror ( rc ) ); ! 1092: return rc; ! 1093: } ! 1094: arbel_qp->state = ARBEL_QP_ST_RTR; ! 1095: } ! 1096: ! 1097: /* Transition queue to RTS state, if applicable */ ! 1098: if ( arbel_qp->state < ARBEL_QP_ST_RTS ) { ! 1099: memset ( &qpctx, 0, sizeof ( qpctx ) ); ! 1100: MLX_FILL_1 ( &qpctx, 32, ! 1101: qpc_eec_data.next_send_psn, qp->send.psn ); ! 1102: if ( ( rc = arbel_cmd_rtr2rts_qpee ( arbel, qp->qpn, ! 1103: &qpctx ) ) != 0 ) { ! 1104: DBGC ( arbel, "Arbel %p QPN %#lx RTR2RTS_QPEE failed: " ! 1105: "%s\n", arbel, qp->qpn, strerror ( rc ) ); ! 1106: return rc; ! 1107: } ! 1108: arbel_qp->state = ARBEL_QP_ST_RTS; ! 1109: } ! 1110: ! 1111: /* Update parameters in RTS state */ ! 1112: memset ( &qpctx, 0, sizeof ( qpctx ) ); ! 1113: MLX_FILL_1 ( &qpctx, 0, opt_param_mask, ARBEL_QPEE_OPT_PARAM_QKEY ); ! 1114: MLX_FILL_1 ( &qpctx, 44, qpc_eec_data.q_key, qp->qkey ); ! 1115: if ( ( rc = arbel_cmd_rts2rts_qpee ( arbel, qp->qpn, &qpctx ) ) != 0 ){ ! 1116: DBGC ( arbel, "Arbel %p QPN %#lx RTS2RTS_QPEE failed: %s\n", ! 1117: arbel, qp->qpn, strerror ( rc ) ); ! 1118: return rc; ! 1119: } ! 1120: ! 1121: return 0; ! 1122: } ! 1123: ! 1124: /** ! 1125: * Destroy queue pair ! 1126: * ! 1127: * @v ibdev Infiniband device ! 1128: * @v qp Queue pair ! 1129: */ ! 1130: static void arbel_destroy_qp ( struct ib_device *ibdev, ! 1131: struct ib_queue_pair *qp ) { ! 1132: struct arbel *arbel = ib_get_drvdata ( ibdev ); ! 1133: struct arbel_queue_pair *arbel_qp = ib_qp_get_drvdata ( qp ); ! 1134: struct arbelprm_qp_db_record *send_db_rec; ! 1135: struct arbelprm_qp_db_record *recv_db_rec; ! 1136: int rc; ! 1137: ! 1138: /* Take ownership back from hardware */ ! 1139: if ( ( rc = arbel_cmd_2rst_qpee ( arbel, qp->qpn ) ) != 0 ) { ! 1140: DBGC ( arbel, "Arbel %p QPN %#lx FATAL 2RST_QPEE failed: " ! 1141: "%s\n", arbel, qp->qpn, strerror ( rc ) ); ! 1142: /* Leak memory and return; at least we avoid corruption */ ! 1143: return; ! 1144: } ! 1145: ! 1146: /* Clear doorbell records */ ! 1147: send_db_rec = &arbel->db_rec[arbel_qp->send.doorbell_idx].qp; ! 1148: recv_db_rec = &arbel->db_rec[arbel_qp->recv.doorbell_idx].qp; ! 1149: MLX_FILL_1 ( send_db_rec, 1, res, ARBEL_UAR_RES_NONE ); ! 1150: MLX_FILL_1 ( recv_db_rec, 1, res, ARBEL_UAR_RES_NONE ); ! 1151: ! 1152: /* Free memory */ ! 1153: free_dma ( arbel_qp->send.wqe, arbel_qp->send.wqe_size ); ! 1154: free_dma ( arbel_qp->recv.wqe, arbel_qp->recv.wqe_size ); ! 1155: free ( arbel_qp ); ! 1156: ! 1157: /* Mark queue number as free */ ! 1158: arbel_free_qpn ( ibdev, qp ); ! 1159: ! 1160: ib_qp_set_drvdata ( qp, NULL ); ! 1161: } ! 1162: ! 1163: /*************************************************************************** ! 1164: * ! 1165: * Work request operations ! 1166: * ! 1167: *************************************************************************** ! 1168: */ ! 1169: ! 1170: /** ! 1171: * Ring doorbell register in UAR ! 1172: * ! 1173: * @v arbel Arbel device ! 1174: * @v db_reg Doorbell register structure ! 1175: * @v offset Address of doorbell ! 1176: */ ! 1177: static void arbel_ring_doorbell ( struct arbel *arbel, ! 1178: union arbelprm_doorbell_register *db_reg, ! 1179: unsigned int offset ) { ! 1180: ! 1181: DBGC2 ( arbel, "Arbel %p ringing doorbell %08x:%08x at %lx\n", ! 1182: arbel, ntohl ( db_reg->dword[0] ), ntohl ( db_reg->dword[1] ), ! 1183: virt_to_phys ( arbel->uar + offset ) ); ! 1184: ! 1185: barrier(); ! 1186: writel ( db_reg->dword[0], ( arbel->uar + offset + 0 ) ); ! 1187: barrier(); ! 1188: writel ( db_reg->dword[1], ( arbel->uar + offset + 4 ) ); ! 1189: } ! 1190: ! 1191: /** GID used for GID-less send work queue entries */ ! 1192: static const union ib_gid arbel_no_gid = { ! 1193: .bytes = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0 }, ! 1194: }; ! 1195: ! 1196: /** ! 1197: * Construct UD send work queue entry ! 1198: * ! 1199: * @v ibdev Infiniband device ! 1200: * @v qp Queue pair ! 1201: * @v av Address vector ! 1202: * @v iobuf I/O buffer ! 1203: * @v wqe Send work queue entry ! 1204: * @ret nds Work queue entry size ! 1205: */ ! 1206: static size_t arbel_fill_ud_send_wqe ( struct ib_device *ibdev, ! 1207: struct ib_queue_pair *qp __unused, ! 1208: struct ib_address_vector *av, ! 1209: struct io_buffer *iobuf, ! 1210: union arbel_send_wqe *wqe ) { ! 1211: struct arbel *arbel = ib_get_drvdata ( ibdev ); ! 1212: const union ib_gid *gid; ! 1213: ! 1214: /* Construct this work queue entry */ ! 1215: MLX_FILL_1 ( &wqe->ud.ctrl, 0, always1, 1 ); ! 1216: MLX_FILL_2 ( &wqe->ud.ud, 0, ! 1217: ud_address_vector.pd, ARBEL_GLOBAL_PD, ! 1218: ud_address_vector.port_number, ibdev->port ); ! 1219: MLX_FILL_2 ( &wqe->ud.ud, 1, ! 1220: ud_address_vector.rlid, av->lid, ! 1221: ud_address_vector.g, av->gid_present ); ! 1222: MLX_FILL_2 ( &wqe->ud.ud, 2, ! 1223: ud_address_vector.max_stat_rate, arbel_rate ( av ), ! 1224: ud_address_vector.msg, 3 ); ! 1225: MLX_FILL_1 ( &wqe->ud.ud, 3, ud_address_vector.sl, av->sl ); ! 1226: gid = ( av->gid_present ? &av->gid : &arbel_no_gid ); ! 1227: memcpy ( &wqe->ud.ud.u.dwords[4], gid, sizeof ( *gid ) ); ! 1228: MLX_FILL_1 ( &wqe->ud.ud, 8, destination_qp, av->qpn ); ! 1229: MLX_FILL_1 ( &wqe->ud.ud, 9, q_key, av->qkey ); ! 1230: MLX_FILL_1 ( &wqe->ud.data[0], 0, byte_count, iob_len ( iobuf ) ); ! 1231: MLX_FILL_1 ( &wqe->ud.data[0], 1, l_key, arbel->lkey ); ! 1232: MLX_FILL_H ( &wqe->ud.data[0], 2, ! 1233: local_address_h, virt_to_bus ( iobuf->data ) ); ! 1234: MLX_FILL_1 ( &wqe->ud.data[0], 3, ! 1235: local_address_l, virt_to_bus ( iobuf->data ) ); ! 1236: ! 1237: return ( offsetof ( typeof ( wqe->ud ), data[1] ) >> 4 ); ! 1238: } ! 1239: ! 1240: /** ! 1241: * Construct MLX send work queue entry ! 1242: * ! 1243: * @v ibdev Infiniband device ! 1244: * @v qp Queue pair ! 1245: * @v av Address vector ! 1246: * @v iobuf I/O buffer ! 1247: * @v wqe Send work queue entry ! 1248: * @v next Previous work queue entry's "next" field ! 1249: * @ret nds Work queue entry size ! 1250: */ ! 1251: static size_t arbel_fill_mlx_send_wqe ( struct ib_device *ibdev, ! 1252: struct ib_queue_pair *qp, ! 1253: struct ib_address_vector *av, ! 1254: struct io_buffer *iobuf, ! 1255: union arbel_send_wqe *wqe ) { ! 1256: struct arbel *arbel = ib_get_drvdata ( ibdev ); ! 1257: struct io_buffer headers; ! 1258: ! 1259: /* Construct IB headers */ ! 1260: iob_populate ( &headers, &wqe->mlx.headers, 0, ! 1261: sizeof ( wqe->mlx.headers ) ); ! 1262: iob_reserve ( &headers, sizeof ( wqe->mlx.headers ) ); ! 1263: ib_push ( ibdev, &headers, qp, iob_len ( iobuf ), av ); ! 1264: ! 1265: /* Construct this work queue entry */ ! 1266: MLX_FILL_5 ( &wqe->mlx.ctrl, 0, ! 1267: c, 1 /* generate completion */, ! 1268: icrc, 0 /* generate ICRC */, ! 1269: max_statrate, arbel_rate ( av ), ! 1270: slr, 0, ! 1271: v15, ( ( qp->ext_qpn == IB_QPN_SMI ) ? 1 : 0 ) ); ! 1272: MLX_FILL_1 ( &wqe->mlx.ctrl, 1, rlid, av->lid ); ! 1273: MLX_FILL_1 ( &wqe->mlx.data[0], 0, ! 1274: byte_count, iob_len ( &headers ) ); ! 1275: MLX_FILL_1 ( &wqe->mlx.data[0], 1, l_key, arbel->lkey ); ! 1276: MLX_FILL_H ( &wqe->mlx.data[0], 2, ! 1277: local_address_h, virt_to_bus ( headers.data ) ); ! 1278: MLX_FILL_1 ( &wqe->mlx.data[0], 3, ! 1279: local_address_l, virt_to_bus ( headers.data ) ); ! 1280: MLX_FILL_1 ( &wqe->mlx.data[1], 0, ! 1281: byte_count, ( iob_len ( iobuf ) + 4 /* ICRC */ ) ); ! 1282: MLX_FILL_1 ( &wqe->mlx.data[1], 1, l_key, arbel->lkey ); ! 1283: MLX_FILL_H ( &wqe->mlx.data[1], 2, ! 1284: local_address_h, virt_to_bus ( iobuf->data ) ); ! 1285: MLX_FILL_1 ( &wqe->mlx.data[1], 3, ! 1286: local_address_l, virt_to_bus ( iobuf->data ) ); ! 1287: ! 1288: return ( offsetof ( typeof ( wqe->mlx ), data[2] ) >> 4 ); ! 1289: } ! 1290: ! 1291: /** Work queue entry constructors */ ! 1292: static size_t ! 1293: ( * arbel_fill_send_wqe[] ) ( struct ib_device *ibdev, ! 1294: struct ib_queue_pair *qp, ! 1295: struct ib_address_vector *av, ! 1296: struct io_buffer *iobuf, ! 1297: union arbel_send_wqe *wqe ) = { ! 1298: [IB_QPT_SMI] = arbel_fill_mlx_send_wqe, ! 1299: [IB_QPT_GSI] = arbel_fill_mlx_send_wqe, ! 1300: [IB_QPT_UD] = arbel_fill_ud_send_wqe, ! 1301: }; ! 1302: ! 1303: /** ! 1304: * Post send work queue entry ! 1305: * ! 1306: * @v ibdev Infiniband device ! 1307: * @v qp Queue pair ! 1308: * @v av Address vector ! 1309: * @v iobuf I/O buffer ! 1310: * @ret rc Return status code ! 1311: */ ! 1312: static int arbel_post_send ( struct ib_device *ibdev, ! 1313: struct ib_queue_pair *qp, ! 1314: struct ib_address_vector *av, ! 1315: struct io_buffer *iobuf ) { ! 1316: struct arbel *arbel = ib_get_drvdata ( ibdev ); ! 1317: struct arbel_queue_pair *arbel_qp = ib_qp_get_drvdata ( qp ); ! 1318: struct ib_work_queue *wq = &qp->send; ! 1319: struct arbel_send_work_queue *arbel_send_wq = &arbel_qp->send; ! 1320: union arbel_send_wqe *prev_wqe; ! 1321: union arbel_send_wqe *wqe; ! 1322: struct arbelprm_qp_db_record *qp_db_rec; ! 1323: union arbelprm_doorbell_register db_reg; ! 1324: unsigned long wqe_idx_mask; ! 1325: size_t nds; ! 1326: ! 1327: /* Allocate work queue entry */ ! 1328: wqe_idx_mask = ( wq->num_wqes - 1 ); ! 1329: if ( wq->iobufs[wq->next_idx & wqe_idx_mask] ) { ! 1330: DBGC ( arbel, "Arbel %p QPN %#lx send queue full", ! 1331: arbel, qp->qpn ); ! 1332: return -ENOBUFS; ! 1333: } ! 1334: wq->iobufs[wq->next_idx & wqe_idx_mask] = iobuf; ! 1335: prev_wqe = &arbel_send_wq->wqe[(wq->next_idx - 1) & wqe_idx_mask]; ! 1336: wqe = &arbel_send_wq->wqe[wq->next_idx & wqe_idx_mask]; ! 1337: ! 1338: /* Construct work queue entry */ ! 1339: memset ( ( ( ( void * ) wqe ) + sizeof ( wqe->next ) ), 0, ! 1340: ( sizeof ( *wqe ) - sizeof ( wqe->next ) ) ); ! 1341: assert ( qp->type < ( sizeof ( arbel_fill_send_wqe ) / ! 1342: sizeof ( arbel_fill_send_wqe[0] ) ) ); ! 1343: assert ( arbel_fill_send_wqe[qp->type] != NULL ); ! 1344: nds = arbel_fill_send_wqe[qp->type] ( ibdev, qp, av, iobuf, wqe ); ! 1345: DBGCP ( arbel, "Arbel %p QPN %#lx posting send WQE %#lx:\n", ! 1346: arbel, qp->qpn, ( wq->next_idx & wqe_idx_mask ) ); ! 1347: DBGCP_HDA ( arbel, virt_to_phys ( wqe ), wqe, sizeof ( *wqe ) ); ! 1348: ! 1349: /* Update previous work queue entry's "next" field */ ! 1350: MLX_SET ( &prev_wqe->next, nopcode, ARBEL_OPCODE_SEND ); ! 1351: MLX_FILL_3 ( &prev_wqe->next, 1, ! 1352: nds, nds, ! 1353: f, 0, ! 1354: always1, 1 ); ! 1355: ! 1356: /* Update doorbell record */ ! 1357: barrier(); ! 1358: qp_db_rec = &arbel->db_rec[arbel_send_wq->doorbell_idx].qp; ! 1359: MLX_FILL_1 ( qp_db_rec, 0, ! 1360: counter, ( ( wq->next_idx + 1 ) & 0xffff ) ); ! 1361: ! 1362: /* Ring doorbell register */ ! 1363: MLX_FILL_4 ( &db_reg.send, 0, ! 1364: nopcode, ARBEL_OPCODE_SEND, ! 1365: f, 0, ! 1366: wqe_counter, ( wq->next_idx & 0xffff ), ! 1367: wqe_cnt, 1 ); ! 1368: MLX_FILL_2 ( &db_reg.send, 1, ! 1369: nds, nds, ! 1370: qpn, qp->qpn ); ! 1371: arbel_ring_doorbell ( arbel, &db_reg, ARBEL_DB_POST_SND_OFFSET ); ! 1372: ! 1373: /* Update work queue's index */ ! 1374: wq->next_idx++; ! 1375: ! 1376: return 0; ! 1377: } ! 1378: ! 1379: /** ! 1380: * Post receive work queue entry ! 1381: * ! 1382: * @v ibdev Infiniband device ! 1383: * @v qp Queue pair ! 1384: * @v iobuf I/O buffer ! 1385: * @ret rc Return status code ! 1386: */ ! 1387: static int arbel_post_recv ( struct ib_device *ibdev, ! 1388: struct ib_queue_pair *qp, ! 1389: struct io_buffer *iobuf ) { ! 1390: struct arbel *arbel = ib_get_drvdata ( ibdev ); ! 1391: struct arbel_queue_pair *arbel_qp = ib_qp_get_drvdata ( qp ); ! 1392: struct ib_work_queue *wq = &qp->recv; ! 1393: struct arbel_recv_work_queue *arbel_recv_wq = &arbel_qp->recv; ! 1394: struct arbelprm_recv_wqe *wqe; ! 1395: union arbelprm_doorbell_record *db_rec; ! 1396: unsigned int wqe_idx_mask; ! 1397: ! 1398: /* Allocate work queue entry */ ! 1399: wqe_idx_mask = ( wq->num_wqes - 1 ); ! 1400: if ( wq->iobufs[wq->next_idx & wqe_idx_mask] ) { ! 1401: DBGC ( arbel, "Arbel %p QPN %#lx receive queue full\n", ! 1402: arbel, qp->qpn ); ! 1403: return -ENOBUFS; ! 1404: } ! 1405: wq->iobufs[wq->next_idx & wqe_idx_mask] = iobuf; ! 1406: wqe = &arbel_recv_wq->wqe[wq->next_idx & wqe_idx_mask].recv; ! 1407: ! 1408: /* Construct work queue entry */ ! 1409: MLX_FILL_1 ( &wqe->data[0], 0, byte_count, iob_tailroom ( iobuf ) ); ! 1410: MLX_FILL_1 ( &wqe->data[0], 1, l_key, arbel->lkey ); ! 1411: MLX_FILL_H ( &wqe->data[0], 2, ! 1412: local_address_h, virt_to_bus ( iobuf->data ) ); ! 1413: MLX_FILL_1 ( &wqe->data[0], 3, ! 1414: local_address_l, virt_to_bus ( iobuf->data ) ); ! 1415: ! 1416: /* Update doorbell record */ ! 1417: barrier(); ! 1418: db_rec = &arbel->db_rec[arbel_recv_wq->doorbell_idx]; ! 1419: MLX_FILL_1 ( &db_rec->qp, 0, ! 1420: counter, ( ( wq->next_idx + 1 ) & 0xffff ) ); ! 1421: ! 1422: /* Update work queue's index */ ! 1423: wq->next_idx++; ! 1424: ! 1425: return 0; ! 1426: } ! 1427: ! 1428: /** ! 1429: * Handle completion ! 1430: * ! 1431: * @v ibdev Infiniband device ! 1432: * @v cq Completion queue ! 1433: * @v cqe Hardware completion queue entry ! 1434: * @ret rc Return status code ! 1435: */ ! 1436: static int arbel_complete ( struct ib_device *ibdev, ! 1437: struct ib_completion_queue *cq, ! 1438: union arbelprm_completion_entry *cqe ) { ! 1439: struct arbel *arbel = ib_get_drvdata ( ibdev ); ! 1440: struct ib_work_queue *wq; ! 1441: struct ib_queue_pair *qp; ! 1442: struct arbel_queue_pair *arbel_qp; ! 1443: struct arbel_send_work_queue *arbel_send_wq; ! 1444: struct arbel_recv_work_queue *arbel_recv_wq; ! 1445: struct arbelprm_recv_wqe *recv_wqe; ! 1446: struct io_buffer *iobuf; ! 1447: struct ib_address_vector recv_av; ! 1448: struct ib_global_route_header *grh; ! 1449: struct ib_address_vector *av; ! 1450: unsigned int opcode; ! 1451: unsigned long qpn; ! 1452: int is_send; ! 1453: unsigned long wqe_adr; ! 1454: unsigned long wqe_idx; ! 1455: size_t len; ! 1456: int rc = 0; ! 1457: ! 1458: /* Parse completion */ ! 1459: qpn = MLX_GET ( &cqe->normal, my_qpn ); ! 1460: is_send = MLX_GET ( &cqe->normal, s ); ! 1461: wqe_adr = ( MLX_GET ( &cqe->normal, wqe_adr ) << 6 ); ! 1462: opcode = MLX_GET ( &cqe->normal, opcode ); ! 1463: if ( opcode >= ARBEL_OPCODE_RECV_ERROR ) { ! 1464: /* "s" field is not valid for error opcodes */ ! 1465: is_send = ( opcode == ARBEL_OPCODE_SEND_ERROR ); ! 1466: DBGC ( arbel, "Arbel %p CQN %#lx %s QPN %#lx syndrome %#x " ! 1467: "vendor %#x\n", arbel, cq->cqn, ! 1468: ( is_send ? "send" : "recv" ), qpn, ! 1469: MLX_GET ( &cqe->error, syndrome ), ! 1470: MLX_GET ( &cqe->error, vendor_code ) ); ! 1471: DBGC_HDA ( arbel, virt_to_phys ( cqe ), cqe, sizeof ( *cqe ) ); ! 1472: rc = -EIO; ! 1473: /* Don't return immediately; propagate error to completer */ ! 1474: } ! 1475: ! 1476: /* Identify work queue */ ! 1477: wq = ib_find_wq ( cq, qpn, is_send ); ! 1478: if ( ! wq ) { ! 1479: DBGC ( arbel, "Arbel %p CQN %#lx unknown %s QPN %#lx\n", ! 1480: arbel, cq->cqn, ( is_send ? "send" : "recv" ), qpn ); ! 1481: return -EIO; ! 1482: } ! 1483: qp = wq->qp; ! 1484: arbel_qp = ib_qp_get_drvdata ( qp ); ! 1485: arbel_send_wq = &arbel_qp->send; ! 1486: arbel_recv_wq = &arbel_qp->recv; ! 1487: ! 1488: /* Identify work queue entry index */ ! 1489: if ( is_send ) { ! 1490: wqe_idx = ( ( wqe_adr - virt_to_bus ( arbel_send_wq->wqe ) ) / ! 1491: sizeof ( arbel_send_wq->wqe[0] ) ); ! 1492: assert ( wqe_idx < qp->send.num_wqes ); ! 1493: } else { ! 1494: wqe_idx = ( ( wqe_adr - virt_to_bus ( arbel_recv_wq->wqe ) ) / ! 1495: sizeof ( arbel_recv_wq->wqe[0] ) ); ! 1496: assert ( wqe_idx < qp->recv.num_wqes ); ! 1497: } ! 1498: DBGCP ( arbel, "Arbel %p CQN %#lx QPN %#lx %s WQE %#lx completed:\n", ! 1499: arbel, cq->cqn, qp->qpn, ( is_send ? "send" : "recv" ), ! 1500: wqe_idx ); ! 1501: DBGCP_HDA ( arbel, virt_to_phys ( cqe ), cqe, sizeof ( *cqe ) ); ! 1502: ! 1503: /* Identify I/O buffer */ ! 1504: iobuf = wq->iobufs[wqe_idx]; ! 1505: if ( ! iobuf ) { ! 1506: DBGC ( arbel, "Arbel %p CQN %#lx QPN %#lx empty %s WQE %#lx\n", ! 1507: arbel, cq->cqn, qp->qpn, ( is_send ? "send" : "recv" ), ! 1508: wqe_idx ); ! 1509: return -EIO; ! 1510: } ! 1511: wq->iobufs[wqe_idx] = NULL; ! 1512: ! 1513: if ( is_send ) { ! 1514: /* Hand off to completion handler */ ! 1515: ib_complete_send ( ibdev, qp, iobuf, rc ); ! 1516: } else { ! 1517: /* Set received length */ ! 1518: len = MLX_GET ( &cqe->normal, byte_cnt ); ! 1519: recv_wqe = &arbel_recv_wq->wqe[wqe_idx].recv; ! 1520: assert ( MLX_GET ( &recv_wqe->data[0], local_address_l ) == ! 1521: virt_to_bus ( iobuf->data ) ); ! 1522: assert ( MLX_GET ( &recv_wqe->data[0], byte_count ) == ! 1523: iob_tailroom ( iobuf ) ); ! 1524: MLX_FILL_1 ( &recv_wqe->data[0], 0, byte_count, 0 ); ! 1525: MLX_FILL_1 ( &recv_wqe->data[0], 1, ! 1526: l_key, ARBEL_INVALID_LKEY ); ! 1527: assert ( len <= iob_tailroom ( iobuf ) ); ! 1528: iob_put ( iobuf, len ); ! 1529: switch ( qp->type ) { ! 1530: case IB_QPT_SMI: ! 1531: case IB_QPT_GSI: ! 1532: case IB_QPT_UD: ! 1533: assert ( iob_len ( iobuf ) >= sizeof ( *grh ) ); ! 1534: grh = iobuf->data; ! 1535: iob_pull ( iobuf, sizeof ( *grh ) ); ! 1536: /* Construct address vector */ ! 1537: av = &recv_av; ! 1538: memset ( av, 0, sizeof ( *av ) ); ! 1539: av->qpn = MLX_GET ( &cqe->normal, rqpn ); ! 1540: av->lid = MLX_GET ( &cqe->normal, rlid ); ! 1541: av->sl = MLX_GET ( &cqe->normal, sl ); ! 1542: av->gid_present = MLX_GET ( &cqe->normal, g ); ! 1543: memcpy ( &av->gid, &grh->sgid, sizeof ( av->gid ) ); ! 1544: break; ! 1545: default: ! 1546: assert ( 0 ); ! 1547: return -EINVAL; ! 1548: } ! 1549: /* Hand off to completion handler */ ! 1550: ib_complete_recv ( ibdev, qp, av, iobuf, rc ); ! 1551: } ! 1552: ! 1553: return rc; ! 1554: } ! 1555: ! 1556: /** ! 1557: * Poll completion queue ! 1558: * ! 1559: * @v ibdev Infiniband device ! 1560: * @v cq Completion queue ! 1561: */ ! 1562: static void arbel_poll_cq ( struct ib_device *ibdev, ! 1563: struct ib_completion_queue *cq ) { ! 1564: struct arbel *arbel = ib_get_drvdata ( ibdev ); ! 1565: struct arbel_completion_queue *arbel_cq = ib_cq_get_drvdata ( cq ); ! 1566: struct arbelprm_cq_ci_db_record *ci_db_rec; ! 1567: union arbelprm_completion_entry *cqe; ! 1568: unsigned int cqe_idx_mask; ! 1569: int rc; ! 1570: ! 1571: while ( 1 ) { ! 1572: /* Look for completion entry */ ! 1573: cqe_idx_mask = ( cq->num_cqes - 1 ); ! 1574: cqe = &arbel_cq->cqe[cq->next_idx & cqe_idx_mask]; ! 1575: if ( MLX_GET ( &cqe->normal, owner ) != 0 ) { ! 1576: /* Entry still owned by hardware; end of poll */ ! 1577: break; ! 1578: } ! 1579: ! 1580: /* Handle completion */ ! 1581: if ( ( rc = arbel_complete ( ibdev, cq, cqe ) ) != 0 ) { ! 1582: DBGC ( arbel, "Arbel %p CQN %#lx failed to complete: " ! 1583: "%s\n", arbel, cq->cqn, strerror ( rc ) ); ! 1584: DBGC_HD ( arbel, cqe, sizeof ( *cqe ) ); ! 1585: } ! 1586: ! 1587: /* Return ownership to hardware */ ! 1588: MLX_FILL_1 ( &cqe->normal, 7, owner, 1 ); ! 1589: barrier(); ! 1590: /* Update completion queue's index */ ! 1591: cq->next_idx++; ! 1592: /* Update doorbell record */ ! 1593: ci_db_rec = &arbel->db_rec[arbel_cq->ci_doorbell_idx].cq_ci; ! 1594: MLX_FILL_1 ( ci_db_rec, 0, ! 1595: counter, ( cq->next_idx & 0xffffffffUL ) ); ! 1596: } ! 1597: } ! 1598: ! 1599: /*************************************************************************** ! 1600: * ! 1601: * Event queues ! 1602: * ! 1603: *************************************************************************** ! 1604: */ ! 1605: ! 1606: /** ! 1607: * Create event queue ! 1608: * ! 1609: * @v arbel Arbel device ! 1610: * @ret rc Return status code ! 1611: */ ! 1612: static int arbel_create_eq ( struct arbel *arbel ) { ! 1613: struct arbel_event_queue *arbel_eq = &arbel->eq; ! 1614: struct arbelprm_eqc eqctx; ! 1615: struct arbelprm_event_mask mask; ! 1616: unsigned int i; ! 1617: int rc; ! 1618: ! 1619: /* Select event queue number */ ! 1620: arbel_eq->eqn = arbel->limits.reserved_eqs; ! 1621: ! 1622: /* Calculate doorbell address */ ! 1623: arbel_eq->doorbell = ( arbel->eq_ci_doorbells + ! 1624: ARBEL_DB_EQ_OFFSET ( arbel_eq->eqn ) ); ! 1625: ! 1626: /* Allocate event queue itself */ ! 1627: arbel_eq->eqe_size = ! 1628: ( ARBEL_NUM_EQES * sizeof ( arbel_eq->eqe[0] ) ); ! 1629: arbel_eq->eqe = malloc_dma ( arbel_eq->eqe_size, ! 1630: sizeof ( arbel_eq->eqe[0] ) ); ! 1631: if ( ! arbel_eq->eqe ) { ! 1632: rc = -ENOMEM; ! 1633: goto err_eqe; ! 1634: } ! 1635: memset ( arbel_eq->eqe, 0, arbel_eq->eqe_size ); ! 1636: for ( i = 0 ; i < ARBEL_NUM_EQES ; i++ ) { ! 1637: MLX_FILL_1 ( &arbel_eq->eqe[i].generic, 7, owner, 1 ); ! 1638: } ! 1639: barrier(); ! 1640: ! 1641: /* Hand queue over to hardware */ ! 1642: memset ( &eqctx, 0, sizeof ( eqctx ) ); ! 1643: MLX_FILL_1 ( &eqctx, 0, st, 0xa /* "Fired" */ ); ! 1644: MLX_FILL_H ( &eqctx, 1, ! 1645: start_address_h, virt_to_phys ( arbel_eq->eqe ) ); ! 1646: MLX_FILL_1 ( &eqctx, 2, ! 1647: start_address_l, virt_to_phys ( arbel_eq->eqe ) ); ! 1648: MLX_FILL_1 ( &eqctx, 3, log_eq_size, fls ( ARBEL_NUM_EQES - 1 ) ); ! 1649: MLX_FILL_1 ( &eqctx, 6, pd, ARBEL_GLOBAL_PD ); ! 1650: MLX_FILL_1 ( &eqctx, 7, lkey, arbel->lkey ); ! 1651: if ( ( rc = arbel_cmd_sw2hw_eq ( arbel, arbel_eq->eqn, ! 1652: &eqctx ) ) != 0 ) { ! 1653: DBGC ( arbel, "Arbel %p EQN %#lx SW2HW_EQ failed: %s\n", ! 1654: arbel, arbel_eq->eqn, strerror ( rc ) ); ! 1655: goto err_sw2hw_eq; ! 1656: } ! 1657: ! 1658: /* Map events to this event queue */ ! 1659: memset ( &mask, 0xff, sizeof ( mask ) ); ! 1660: if ( ( rc = arbel_cmd_map_eq ( arbel, ! 1661: ( ARBEL_MAP_EQ | arbel_eq->eqn ), ! 1662: &mask ) ) != 0 ) { ! 1663: DBGC ( arbel, "Arbel %p EQN %#lx MAP_EQ failed: %s\n", ! 1664: arbel, arbel_eq->eqn, strerror ( rc ) ); ! 1665: goto err_map_eq; ! 1666: } ! 1667: ! 1668: DBGC ( arbel, "Arbel %p EQN %#lx ring [%08lx,%08lx), doorbell %08lx\n", ! 1669: arbel, arbel_eq->eqn, virt_to_phys ( arbel_eq->eqe ), ! 1670: ( virt_to_phys ( arbel_eq->eqe ) + arbel_eq->eqe_size ), ! 1671: virt_to_phys ( arbel_eq->doorbell ) ); ! 1672: return 0; ! 1673: ! 1674: err_map_eq: ! 1675: arbel_cmd_hw2sw_eq ( arbel, arbel_eq->eqn, &eqctx ); ! 1676: err_sw2hw_eq: ! 1677: free_dma ( arbel_eq->eqe, arbel_eq->eqe_size ); ! 1678: err_eqe: ! 1679: memset ( arbel_eq, 0, sizeof ( *arbel_eq ) ); ! 1680: return rc; ! 1681: } ! 1682: ! 1683: /** ! 1684: * Destroy event queue ! 1685: * ! 1686: * @v arbel Arbel device ! 1687: */ ! 1688: static void arbel_destroy_eq ( struct arbel *arbel ) { ! 1689: struct arbel_event_queue *arbel_eq = &arbel->eq; ! 1690: struct arbelprm_eqc eqctx; ! 1691: struct arbelprm_event_mask mask; ! 1692: int rc; ! 1693: ! 1694: /* Unmap events from event queue */ ! 1695: memset ( &mask, 0, sizeof ( mask ) ); ! 1696: MLX_FILL_1 ( &mask, 1, port_state_change, 1 ); ! 1697: if ( ( rc = arbel_cmd_map_eq ( arbel, ! 1698: ( ARBEL_UNMAP_EQ | arbel_eq->eqn ), ! 1699: &mask ) ) != 0 ) { ! 1700: DBGC ( arbel, "Arbel %p EQN %#lx FATAL MAP_EQ failed to " ! 1701: "unmap: %s\n", arbel, arbel_eq->eqn, strerror ( rc ) ); ! 1702: /* Continue; HCA may die but system should survive */ ! 1703: } ! 1704: ! 1705: /* Take ownership back from hardware */ ! 1706: if ( ( rc = arbel_cmd_hw2sw_eq ( arbel, arbel_eq->eqn, ! 1707: &eqctx ) ) != 0 ) { ! 1708: DBGC ( arbel, "Arbel %p EQN %#lx FATAL HW2SW_EQ failed: %s\n", ! 1709: arbel, arbel_eq->eqn, strerror ( rc ) ); ! 1710: /* Leak memory and return; at least we avoid corruption */ ! 1711: return; ! 1712: } ! 1713: ! 1714: /* Free memory */ ! 1715: free_dma ( arbel_eq->eqe, arbel_eq->eqe_size ); ! 1716: memset ( arbel_eq, 0, sizeof ( *arbel_eq ) ); ! 1717: } ! 1718: ! 1719: /** ! 1720: * Handle port state event ! 1721: * ! 1722: * @v arbel Arbel device ! 1723: * @v eqe Port state change event queue entry ! 1724: */ ! 1725: static void arbel_event_port_state_change ( struct arbel *arbel, ! 1726: union arbelprm_event_entry *eqe){ ! 1727: unsigned int port; ! 1728: int link_up; ! 1729: ! 1730: /* Get port and link status */ ! 1731: port = ( MLX_GET ( &eqe->port_state_change, data.p ) - 1 ); ! 1732: link_up = ( MLX_GET ( &eqe->generic, event_sub_type ) & 0x04 ); ! 1733: DBGC ( arbel, "Arbel %p port %d link %s\n", arbel, ( port + 1 ), ! 1734: ( link_up ? "up" : "down" ) ); ! 1735: ! 1736: /* Sanity check */ ! 1737: if ( port >= ARBEL_NUM_PORTS ) { ! 1738: DBGC ( arbel, "Arbel %p port %d does not exist!\n", ! 1739: arbel, ( port + 1 ) ); ! 1740: return; ! 1741: } ! 1742: ! 1743: /* Update MAD parameters */ ! 1744: ib_smc_update ( arbel->ibdev[port], arbel_mad ); ! 1745: } ! 1746: ! 1747: /** ! 1748: * Poll event queue ! 1749: * ! 1750: * @v ibdev Infiniband device ! 1751: */ ! 1752: static void arbel_poll_eq ( struct ib_device *ibdev ) { ! 1753: struct arbel *arbel = ib_get_drvdata ( ibdev ); ! 1754: struct arbel_event_queue *arbel_eq = &arbel->eq; ! 1755: union arbelprm_event_entry *eqe; ! 1756: union arbelprm_eq_doorbell_register db_reg; ! 1757: unsigned int eqe_idx_mask; ! 1758: unsigned int event_type; ! 1759: ! 1760: /* No event is generated upon reaching INIT, so we must poll ! 1761: * separately for link state changes while we remain DOWN. ! 1762: */ ! 1763: if ( ib_is_open ( ibdev ) && ! 1764: ( ibdev->port_state == IB_PORT_STATE_DOWN ) ) { ! 1765: ib_smc_update ( ibdev, arbel_mad ); ! 1766: } ! 1767: ! 1768: /* Poll event queue */ ! 1769: while ( 1 ) { ! 1770: /* Look for event entry */ ! 1771: eqe_idx_mask = ( ARBEL_NUM_EQES - 1 ); ! 1772: eqe = &arbel_eq->eqe[arbel_eq->next_idx & eqe_idx_mask]; ! 1773: if ( MLX_GET ( &eqe->generic, owner ) != 0 ) { ! 1774: /* Entry still owned by hardware; end of poll */ ! 1775: break; ! 1776: } ! 1777: DBGCP ( arbel, "Arbel %p EQN %#lx event:\n", ! 1778: arbel, arbel_eq->eqn ); ! 1779: DBGCP_HDA ( arbel, virt_to_phys ( eqe ), ! 1780: eqe, sizeof ( *eqe ) ); ! 1781: ! 1782: /* Handle event */ ! 1783: event_type = MLX_GET ( &eqe->generic, event_type ); ! 1784: switch ( event_type ) { ! 1785: case ARBEL_EV_PORT_STATE_CHANGE: ! 1786: arbel_event_port_state_change ( arbel, eqe ); ! 1787: break; ! 1788: default: ! 1789: DBGC ( arbel, "Arbel %p EQN %#lx unrecognised event " ! 1790: "type %#x:\n", ! 1791: arbel, arbel_eq->eqn, event_type ); ! 1792: DBGC_HDA ( arbel, virt_to_phys ( eqe ), ! 1793: eqe, sizeof ( *eqe ) ); ! 1794: break; ! 1795: } ! 1796: ! 1797: /* Return ownership to hardware */ ! 1798: MLX_FILL_1 ( &eqe->generic, 7, owner, 1 ); ! 1799: barrier(); ! 1800: ! 1801: /* Update event queue's index */ ! 1802: arbel_eq->next_idx++; ! 1803: ! 1804: /* Ring doorbell */ ! 1805: MLX_FILL_1 ( &db_reg.ci, 0, ci, arbel_eq->next_idx ); ! 1806: writel ( db_reg.dword[0], arbel_eq->doorbell ); ! 1807: } ! 1808: } ! 1809: ! 1810: /*************************************************************************** ! 1811: * ! 1812: * Infiniband link-layer operations ! 1813: * ! 1814: *************************************************************************** ! 1815: */ ! 1816: ! 1817: /** ! 1818: * Initialise Infiniband link ! 1819: * ! 1820: * @v ibdev Infiniband device ! 1821: * @ret rc Return status code ! 1822: */ ! 1823: static int arbel_open ( struct ib_device *ibdev ) { ! 1824: struct arbel *arbel = ib_get_drvdata ( ibdev ); ! 1825: struct arbelprm_init_ib init_ib; ! 1826: int rc; ! 1827: ! 1828: memset ( &init_ib, 0, sizeof ( init_ib ) ); ! 1829: MLX_FILL_3 ( &init_ib, 0, ! 1830: mtu_cap, ARBEL_MTU_2048, ! 1831: port_width_cap, 3, ! 1832: vl_cap, 1 ); ! 1833: MLX_FILL_1 ( &init_ib, 1, max_gid, 1 ); ! 1834: MLX_FILL_1 ( &init_ib, 2, max_pkey, 64 ); ! 1835: if ( ( rc = arbel_cmd_init_ib ( arbel, ibdev->port, ! 1836: &init_ib ) ) != 0 ) { ! 1837: DBGC ( arbel, "Arbel %p port %d could not intialise IB: %s\n", ! 1838: arbel, ibdev->port, strerror ( rc ) ); ! 1839: return rc; ! 1840: } ! 1841: ! 1842: /* Update MAD parameters */ ! 1843: ib_smc_update ( ibdev, arbel_mad ); ! 1844: ! 1845: return 0; ! 1846: } ! 1847: ! 1848: /** ! 1849: * Close Infiniband link ! 1850: * ! 1851: * @v ibdev Infiniband device ! 1852: */ ! 1853: static void arbel_close ( struct ib_device *ibdev ) { ! 1854: struct arbel *arbel = ib_get_drvdata ( ibdev ); ! 1855: int rc; ! 1856: ! 1857: if ( ( rc = arbel_cmd_close_ib ( arbel, ibdev->port ) ) != 0 ) { ! 1858: DBGC ( arbel, "Arbel %p port %d could not close IB: %s\n", ! 1859: arbel, ibdev->port, strerror ( rc ) ); ! 1860: /* Nothing we can do about this */ ! 1861: } ! 1862: } ! 1863: ! 1864: /** ! 1865: * Inform embedded subnet management agent of a received MAD ! 1866: * ! 1867: * @v ibdev Infiniband device ! 1868: * @v mad MAD ! 1869: * @ret rc Return status code ! 1870: */ ! 1871: static int arbel_inform_sma ( struct ib_device *ibdev, union ib_mad *mad ) { ! 1872: int rc; ! 1873: ! 1874: /* Send the MAD to the embedded SMA */ ! 1875: if ( ( rc = arbel_mad ( ibdev, mad ) ) != 0 ) ! 1876: return rc; ! 1877: ! 1878: /* Update parameters held in software */ ! 1879: ib_smc_update ( ibdev, arbel_mad ); ! 1880: ! 1881: return 0; ! 1882: } ! 1883: ! 1884: /*************************************************************************** ! 1885: * ! 1886: * Multicast group operations ! 1887: * ! 1888: *************************************************************************** ! 1889: */ ! 1890: ! 1891: /** ! 1892: * Attach to multicast group ! 1893: * ! 1894: * @v ibdev Infiniband device ! 1895: * @v qp Queue pair ! 1896: * @v gid Multicast GID ! 1897: * @ret rc Return status code ! 1898: */ ! 1899: static int arbel_mcast_attach ( struct ib_device *ibdev, ! 1900: struct ib_queue_pair *qp, ! 1901: union ib_gid *gid ) { ! 1902: struct arbel *arbel = ib_get_drvdata ( ibdev ); ! 1903: struct arbelprm_mgm_hash hash; ! 1904: struct arbelprm_mgm_entry mgm; ! 1905: unsigned int index; ! 1906: int rc; ! 1907: ! 1908: /* Generate hash table index */ ! 1909: if ( ( rc = arbel_cmd_mgid_hash ( arbel, gid, &hash ) ) != 0 ) { ! 1910: DBGC ( arbel, "Arbel %p could not hash GID: %s\n", ! 1911: arbel, strerror ( rc ) ); ! 1912: return rc; ! 1913: } ! 1914: index = MLX_GET ( &hash, hash ); ! 1915: ! 1916: /* Check for existing hash table entry */ ! 1917: if ( ( rc = arbel_cmd_read_mgm ( arbel, index, &mgm ) ) != 0 ) { ! 1918: DBGC ( arbel, "Arbel %p could not read MGM %#x: %s\n", ! 1919: arbel, index, strerror ( rc ) ); ! 1920: return rc; ! 1921: } ! 1922: if ( MLX_GET ( &mgm, mgmqp_0.qi ) != 0 ) { ! 1923: /* FIXME: this implementation allows only a single QP ! 1924: * per multicast group, and doesn't handle hash ! 1925: * collisions. Sufficient for IPoIB but may need to ! 1926: * be extended in future. ! 1927: */ ! 1928: DBGC ( arbel, "Arbel %p MGID index %#x already in use\n", ! 1929: arbel, index ); ! 1930: return -EBUSY; ! 1931: } ! 1932: ! 1933: /* Update hash table entry */ ! 1934: MLX_FILL_2 ( &mgm, 8, ! 1935: mgmqp_0.qpn_i, qp->qpn, ! 1936: mgmqp_0.qi, 1 ); ! 1937: memcpy ( &mgm.u.dwords[4], gid, sizeof ( *gid ) ); ! 1938: if ( ( rc = arbel_cmd_write_mgm ( arbel, index, &mgm ) ) != 0 ) { ! 1939: DBGC ( arbel, "Arbel %p could not write MGM %#x: %s\n", ! 1940: arbel, index, strerror ( rc ) ); ! 1941: return rc; ! 1942: } ! 1943: ! 1944: return 0; ! 1945: } ! 1946: ! 1947: /** ! 1948: * Detach from multicast group ! 1949: * ! 1950: * @v ibdev Infiniband device ! 1951: * @v qp Queue pair ! 1952: * @v gid Multicast GID ! 1953: */ ! 1954: static void arbel_mcast_detach ( struct ib_device *ibdev, ! 1955: struct ib_queue_pair *qp __unused, ! 1956: union ib_gid *gid ) { ! 1957: struct arbel *arbel = ib_get_drvdata ( ibdev ); ! 1958: struct arbelprm_mgm_hash hash; ! 1959: struct arbelprm_mgm_entry mgm; ! 1960: unsigned int index; ! 1961: int rc; ! 1962: ! 1963: /* Generate hash table index */ ! 1964: if ( ( rc = arbel_cmd_mgid_hash ( arbel, gid, &hash ) ) != 0 ) { ! 1965: DBGC ( arbel, "Arbel %p could not hash GID: %s\n", ! 1966: arbel, strerror ( rc ) ); ! 1967: return; ! 1968: } ! 1969: index = MLX_GET ( &hash, hash ); ! 1970: ! 1971: /* Clear hash table entry */ ! 1972: memset ( &mgm, 0, sizeof ( mgm ) ); ! 1973: if ( ( rc = arbel_cmd_write_mgm ( arbel, index, &mgm ) ) != 0 ) { ! 1974: DBGC ( arbel, "Arbel %p could not write MGM %#x: %s\n", ! 1975: arbel, index, strerror ( rc ) ); ! 1976: return; ! 1977: } ! 1978: } ! 1979: ! 1980: /** Arbel Infiniband operations */ ! 1981: static struct ib_device_operations arbel_ib_operations = { ! 1982: .create_cq = arbel_create_cq, ! 1983: .destroy_cq = arbel_destroy_cq, ! 1984: .create_qp = arbel_create_qp, ! 1985: .modify_qp = arbel_modify_qp, ! 1986: .destroy_qp = arbel_destroy_qp, ! 1987: .post_send = arbel_post_send, ! 1988: .post_recv = arbel_post_recv, ! 1989: .poll_cq = arbel_poll_cq, ! 1990: .poll_eq = arbel_poll_eq, ! 1991: .open = arbel_open, ! 1992: .close = arbel_close, ! 1993: .mcast_attach = arbel_mcast_attach, ! 1994: .mcast_detach = arbel_mcast_detach, ! 1995: .set_port_info = arbel_inform_sma, ! 1996: .set_pkey_table = arbel_inform_sma, ! 1997: }; ! 1998: ! 1999: /*************************************************************************** ! 2000: * ! 2001: * Firmware control ! 2002: * ! 2003: *************************************************************************** ! 2004: */ ! 2005: ! 2006: /** ! 2007: * Map virtual to physical address for firmware usage ! 2008: * ! 2009: * @v arbel Arbel device ! 2010: * @v map Mapping function ! 2011: * @v va Virtual address ! 2012: * @v pa Physical address ! 2013: * @v len Length of region ! 2014: * @ret rc Return status code ! 2015: */ ! 2016: static int arbel_map_vpm ( struct arbel *arbel, ! 2017: int ( *map ) ( struct arbel *arbel, ! 2018: const struct arbelprm_virtual_physical_mapping* ), ! 2019: uint64_t va, physaddr_t pa, size_t len ) { ! 2020: struct arbelprm_virtual_physical_mapping mapping; ! 2021: physaddr_t start; ! 2022: physaddr_t low; ! 2023: physaddr_t high; ! 2024: physaddr_t end; ! 2025: size_t size; ! 2026: int rc; ! 2027: ! 2028: /* Sanity checks */ ! 2029: assert ( ( va & ( ARBEL_PAGE_SIZE - 1 ) ) == 0 ); ! 2030: assert ( ( pa & ( ARBEL_PAGE_SIZE - 1 ) ) == 0 ); ! 2031: assert ( ( len & ( ARBEL_PAGE_SIZE - 1 ) ) == 0 ); ! 2032: ! 2033: /* Calculate starting points */ ! 2034: start = pa; ! 2035: end = ( start + len ); ! 2036: size = ( 1UL << ( fls ( start ^ end ) - 1 ) ); ! 2037: low = high = ( end & ~( size - 1 ) ); ! 2038: assert ( start < low ); ! 2039: assert ( high <= end ); ! 2040: ! 2041: /* These mappings tend to generate huge volumes of ! 2042: * uninteresting debug data, which basically makes it ! 2043: * impossible to use debugging otherwise. ! 2044: */ ! 2045: DBG_DISABLE ( DBGLVL_LOG | DBGLVL_EXTRA ); ! 2046: ! 2047: /* Map blocks in descending order of size */ ! 2048: while ( size >= ARBEL_PAGE_SIZE ) { ! 2049: ! 2050: /* Find the next candidate block */ ! 2051: if ( ( low - size ) >= start ) { ! 2052: low -= size; ! 2053: pa = low; ! 2054: } else if ( ( high + size ) <= end ) { ! 2055: pa = high; ! 2056: high += size; ! 2057: } else { ! 2058: size >>= 1; ! 2059: continue; ! 2060: } ! 2061: assert ( ( va & ( size - 1 ) ) == 0 ); ! 2062: assert ( ( pa & ( size - 1 ) ) == 0 ); ! 2063: ! 2064: /* Map this block */ ! 2065: memset ( &mapping, 0, sizeof ( mapping ) ); ! 2066: MLX_FILL_1 ( &mapping, 0, va_h, ( va >> 32 ) ); ! 2067: MLX_FILL_1 ( &mapping, 1, va_l, ( va >> 12 ) ); ! 2068: MLX_FILL_H ( &mapping, 2, pa_h, pa ); ! 2069: MLX_FILL_2 ( &mapping, 3, ! 2070: log2size, ( ( fls ( size ) - 1 ) - 12 ), ! 2071: pa_l, ( pa >> 12 ) ); ! 2072: if ( ( rc = map ( arbel, &mapping ) ) != 0 ) { ! 2073: DBG_ENABLE ( DBGLVL_LOG | DBGLVL_EXTRA ); ! 2074: DBGC ( arbel, "Arbel %p could not map %08llx+%zx to " ! 2075: "%08lx: %s\n", ! 2076: arbel, va, size, pa, strerror ( rc ) ); ! 2077: return rc; ! 2078: } ! 2079: va += size; ! 2080: } ! 2081: assert ( low == start ); ! 2082: assert ( high == end ); ! 2083: ! 2084: DBG_ENABLE ( DBGLVL_LOG | DBGLVL_EXTRA ); ! 2085: return 0; ! 2086: } ! 2087: ! 2088: /** ! 2089: * Start firmware running ! 2090: * ! 2091: * @v arbel Arbel device ! 2092: * @ret rc Return status code ! 2093: */ ! 2094: static int arbel_start_firmware ( struct arbel *arbel ) { ! 2095: struct arbelprm_query_fw fw; ! 2096: struct arbelprm_access_lam lam; ! 2097: unsigned int fw_pages; ! 2098: size_t fw_size; ! 2099: physaddr_t fw_base; ! 2100: uint64_t eq_set_ci_base_addr; ! 2101: int rc; ! 2102: ! 2103: /* Get firmware parameters */ ! 2104: if ( ( rc = arbel_cmd_query_fw ( arbel, &fw ) ) != 0 ) { ! 2105: DBGC ( arbel, "Arbel %p could not query firmware: %s\n", ! 2106: arbel, strerror ( rc ) ); ! 2107: goto err_query_fw; ! 2108: } ! 2109: DBGC ( arbel, "Arbel %p firmware version %d.%d.%d\n", arbel, ! 2110: MLX_GET ( &fw, fw_rev_major ), MLX_GET ( &fw, fw_rev_minor ), ! 2111: MLX_GET ( &fw, fw_rev_subminor ) ); ! 2112: fw_pages = MLX_GET ( &fw, fw_pages ); ! 2113: DBGC ( arbel, "Arbel %p requires %d kB for firmware\n", ! 2114: arbel, ( fw_pages * 4 ) ); ! 2115: eq_set_ci_base_addr = ! 2116: ( ( (uint64_t) MLX_GET ( &fw, eq_set_ci_base_addr_h ) << 32 ) | ! 2117: ( (uint64_t) MLX_GET ( &fw, eq_set_ci_base_addr_l ) ) ); ! 2118: arbel->eq_ci_doorbells = ioremap ( eq_set_ci_base_addr, 0x200 ); ! 2119: ! 2120: /* Enable locally-attached memory. Ignore failure; there may ! 2121: * be no attached memory. ! 2122: */ ! 2123: arbel_cmd_enable_lam ( arbel, &lam ); ! 2124: ! 2125: /* Allocate firmware pages and map firmware area */ ! 2126: fw_size = ( fw_pages * ARBEL_PAGE_SIZE ); ! 2127: arbel->firmware_area = umalloc ( fw_size ); ! 2128: if ( ! arbel->firmware_area ) { ! 2129: rc = -ENOMEM; ! 2130: goto err_alloc_fa; ! 2131: } ! 2132: fw_base = user_to_phys ( arbel->firmware_area, 0 ); ! 2133: DBGC ( arbel, "Arbel %p firmware area at [%08lx,%08lx)\n", ! 2134: arbel, fw_base, ( fw_base + fw_size ) ); ! 2135: if ( ( rc = arbel_map_vpm ( arbel, arbel_cmd_map_fa, ! 2136: 0, fw_base, fw_size ) ) != 0 ) { ! 2137: DBGC ( arbel, "Arbel %p could not map firmware: %s\n", ! 2138: arbel, strerror ( rc ) ); ! 2139: goto err_map_fa; ! 2140: } ! 2141: ! 2142: /* Start firmware */ ! 2143: if ( ( rc = arbel_cmd_run_fw ( arbel ) ) != 0 ) { ! 2144: DBGC ( arbel, "Arbel %p could not run firmware: %s\n", ! 2145: arbel, strerror ( rc ) ); ! 2146: goto err_run_fw; ! 2147: } ! 2148: ! 2149: DBGC ( arbel, "Arbel %p firmware started\n", arbel ); ! 2150: return 0; ! 2151: ! 2152: err_run_fw: ! 2153: arbel_cmd_unmap_fa ( arbel ); ! 2154: err_map_fa: ! 2155: ufree ( arbel->firmware_area ); ! 2156: arbel->firmware_area = UNULL; ! 2157: err_alloc_fa: ! 2158: err_query_fw: ! 2159: return rc; ! 2160: } ! 2161: ! 2162: /** ! 2163: * Stop firmware running ! 2164: * ! 2165: * @v arbel Arbel device ! 2166: */ ! 2167: static void arbel_stop_firmware ( struct arbel *arbel ) { ! 2168: int rc; ! 2169: ! 2170: if ( ( rc = arbel_cmd_unmap_fa ( arbel ) ) != 0 ) { ! 2171: DBGC ( arbel, "Arbel %p FATAL could not stop firmware: %s\n", ! 2172: arbel, strerror ( rc ) ); ! 2173: /* Leak memory and return; at least we avoid corruption */ ! 2174: return; ! 2175: } ! 2176: ufree ( arbel->firmware_area ); ! 2177: arbel->firmware_area = UNULL; ! 2178: } ! 2179: ! 2180: /*************************************************************************** ! 2181: * ! 2182: * Infinihost Context Memory management ! 2183: * ! 2184: *************************************************************************** ! 2185: */ ! 2186: ! 2187: /** ! 2188: * Get device limits ! 2189: * ! 2190: * @v arbel Arbel device ! 2191: * @ret rc Return status code ! 2192: */ ! 2193: static int arbel_get_limits ( struct arbel *arbel ) { ! 2194: struct arbelprm_query_dev_lim dev_lim; ! 2195: int rc; ! 2196: ! 2197: if ( ( rc = arbel_cmd_query_dev_lim ( arbel, &dev_lim ) ) != 0 ) { ! 2198: DBGC ( arbel, "Arbel %p could not get device limits: %s\n", ! 2199: arbel, strerror ( rc ) ); ! 2200: return rc; ! 2201: } ! 2202: ! 2203: arbel->limits.reserved_qps = ! 2204: ( 1 << MLX_GET ( &dev_lim, log2_rsvd_qps ) ); ! 2205: arbel->limits.qpc_entry_size = MLX_GET ( &dev_lim, qpc_entry_sz ); ! 2206: arbel->limits.eqpc_entry_size = MLX_GET ( &dev_lim, eqpc_entry_sz ); ! 2207: arbel->limits.reserved_srqs = ! 2208: ( 1 << MLX_GET ( &dev_lim, log2_rsvd_srqs ) ); ! 2209: arbel->limits.srqc_entry_size = MLX_GET ( &dev_lim, srq_entry_sz ); ! 2210: arbel->limits.reserved_ees = ! 2211: ( 1 << MLX_GET ( &dev_lim, log2_rsvd_ees ) ); ! 2212: arbel->limits.eec_entry_size = MLX_GET ( &dev_lim, eec_entry_sz ); ! 2213: arbel->limits.eeec_entry_size = MLX_GET ( &dev_lim, eeec_entry_sz ); ! 2214: arbel->limits.reserved_cqs = ! 2215: ( 1 << MLX_GET ( &dev_lim, log2_rsvd_cqs ) ); ! 2216: arbel->limits.cqc_entry_size = MLX_GET ( &dev_lim, cqc_entry_sz ); ! 2217: arbel->limits.reserved_mtts = ! 2218: ( 1 << MLX_GET ( &dev_lim, log2_rsvd_mtts ) ); ! 2219: arbel->limits.mtt_entry_size = MLX_GET ( &dev_lim, mtt_entry_sz ); ! 2220: arbel->limits.reserved_mrws = ! 2221: ( 1 << MLX_GET ( &dev_lim, log2_rsvd_mrws ) ); ! 2222: arbel->limits.mpt_entry_size = MLX_GET ( &dev_lim, mpt_entry_sz ); ! 2223: arbel->limits.reserved_rdbs = ! 2224: ( 1 << MLX_GET ( &dev_lim, log2_rsvd_rdbs ) ); ! 2225: arbel->limits.reserved_eqs = MLX_GET ( &dev_lim, num_rsvd_eqs ); ! 2226: arbel->limits.eqc_entry_size = MLX_GET ( &dev_lim, eqc_entry_sz ); ! 2227: arbel->limits.reserved_uars = MLX_GET ( &dev_lim, num_rsvd_uars ); ! 2228: arbel->limits.uar_scratch_entry_size = ! 2229: MLX_GET ( &dev_lim, uar_scratch_entry_sz ); ! 2230: ! 2231: DBGC ( arbel, "Arbel %p reserves %d x %#zx QPC, %d x %#zx EQPC, " ! 2232: "%d x %#zx SRQC\n", arbel, ! 2233: arbel->limits.reserved_qps, arbel->limits.qpc_entry_size, ! 2234: arbel->limits.reserved_qps, arbel->limits.eqpc_entry_size, ! 2235: arbel->limits.reserved_srqs, arbel->limits.srqc_entry_size ); ! 2236: DBGC ( arbel, "Arbel %p reserves %d x %#zx EEC, %d x %#zx EEEC, " ! 2237: "%d x %#zx CQC\n", arbel, ! 2238: arbel->limits.reserved_ees, arbel->limits.eec_entry_size, ! 2239: arbel->limits.reserved_ees, arbel->limits.eeec_entry_size, ! 2240: arbel->limits.reserved_cqs, arbel->limits.cqc_entry_size ); ! 2241: DBGC ( arbel, "Arbel %p reserves %d x %#zx EQC, %d x %#zx MTT, " ! 2242: "%d x %#zx MPT\n", arbel, ! 2243: arbel->limits.reserved_eqs, arbel->limits.eqc_entry_size, ! 2244: arbel->limits.reserved_mtts, arbel->limits.mtt_entry_size, ! 2245: arbel->limits.reserved_mrws, arbel->limits.mpt_entry_size ); ! 2246: DBGC ( arbel, "Arbel %p reserves %d x %#zx RDB, %d x %#zx UAR, " ! 2247: "%d x %#zx UAR scratchpad\n", arbel, ! 2248: arbel->limits.reserved_rdbs, ARBEL_RDB_ENTRY_SIZE, ! 2249: arbel->limits.reserved_uars, ARBEL_PAGE_SIZE, ! 2250: arbel->limits.reserved_uars, ! 2251: arbel->limits.uar_scratch_entry_size ); ! 2252: ! 2253: return 0; ! 2254: } ! 2255: ! 2256: /** ! 2257: * Align ICM table ! 2258: * ! 2259: * @v icm_offset Current ICM offset ! 2260: * @v len ICM table length ! 2261: * @ret icm_offset ICM offset ! 2262: */ ! 2263: static size_t icm_align ( size_t icm_offset, size_t len ) { ! 2264: ! 2265: /* Round up to a multiple of the table size */ ! 2266: assert ( len == ( 1UL << ( fls ( len ) - 1 ) ) ); ! 2267: return ( ( icm_offset + len - 1 ) & ~( len - 1 ) ); ! 2268: } ! 2269: ! 2270: /** ! 2271: * Allocate ICM ! 2272: * ! 2273: * @v arbel Arbel device ! 2274: * @v init_hca INIT_HCA structure to fill in ! 2275: * @ret rc Return status code ! 2276: */ ! 2277: static int arbel_alloc_icm ( struct arbel *arbel, ! 2278: struct arbelprm_init_hca *init_hca ) { ! 2279: struct arbelprm_scalar_parameter icm_size; ! 2280: struct arbelprm_scalar_parameter icm_aux_size; ! 2281: struct arbelprm_scalar_parameter unmap_icm; ! 2282: union arbelprm_doorbell_record *db_rec; ! 2283: size_t icm_offset = 0; ! 2284: unsigned int log_num_uars, log_num_qps, log_num_srqs, log_num_ees; ! 2285: unsigned int log_num_cqs, log_num_mtts, log_num_mpts, log_num_rdbs; ! 2286: unsigned int log_num_eqs, log_num_mcs; ! 2287: size_t len; ! 2288: physaddr_t icm_phys; ! 2289: int rc; ! 2290: ! 2291: /* Calculate number of each object type within ICM */ ! 2292: log_num_qps = fls ( arbel->limits.reserved_qps + ! 2293: ARBEL_RSVD_SPECIAL_QPS + ARBEL_MAX_QPS - 1 ); ! 2294: log_num_srqs = fls ( arbel->limits.reserved_srqs - 1 ); ! 2295: log_num_ees = fls ( arbel->limits.reserved_ees - 1 ); ! 2296: log_num_cqs = fls ( arbel->limits.reserved_cqs + ARBEL_MAX_CQS - 1 ); ! 2297: log_num_eqs = fls ( arbel->limits.reserved_eqs + ARBEL_MAX_EQS - 1 ); ! 2298: log_num_mtts = fls ( arbel->limits.reserved_mtts - 1 ); ! 2299: log_num_mpts = fls ( arbel->limits.reserved_mrws + 1 - 1 ); ! 2300: log_num_rdbs = fls ( arbel->limits.reserved_rdbs - 1 ); ! 2301: log_num_uars = fls ( arbel->limits.reserved_uars + ! 2302: 1 /* single UAR used */ - 1 ); ! 2303: log_num_mcs = ARBEL_LOG_MULTICAST_HASH_SIZE; ! 2304: ! 2305: /* Queue pair contexts */ ! 2306: len = ( ( 1 << log_num_qps ) * arbel->limits.qpc_entry_size ); ! 2307: icm_offset = icm_align ( icm_offset, len ); ! 2308: MLX_FILL_2 ( init_hca, 13, ! 2309: qpc_eec_cqc_eqc_rdb_parameters.qpc_base_addr_l, ! 2310: ( icm_offset >> 7 ), ! 2311: qpc_eec_cqc_eqc_rdb_parameters.log_num_of_qp, ! 2312: log_num_qps ); ! 2313: DBGC ( arbel, "Arbel %p ICM QPC is %d x %#zx at [%zx,%zx)\n", ! 2314: arbel, ( 1 << log_num_qps ), arbel->limits.qpc_entry_size, ! 2315: icm_offset, ( icm_offset + len ) ); ! 2316: icm_offset += len; ! 2317: ! 2318: /* Extended queue pair contexts */ ! 2319: len = ( ( 1 << log_num_qps ) * arbel->limits.eqpc_entry_size ); ! 2320: icm_offset = icm_align ( icm_offset, len ); ! 2321: MLX_FILL_1 ( init_hca, 25, ! 2322: qpc_eec_cqc_eqc_rdb_parameters.eqpc_base_addr_l, ! 2323: icm_offset ); ! 2324: DBGC ( arbel, "Arbel %p ICM EQPC is %d x %#zx at [%zx,%zx)\n", ! 2325: arbel, ( 1 << log_num_qps ), arbel->limits.eqpc_entry_size, ! 2326: icm_offset, ( icm_offset + len ) ); ! 2327: icm_offset += len; ! 2328: ! 2329: /* Completion queue contexts */ ! 2330: len = ( ( 1 << log_num_cqs ) * arbel->limits.cqc_entry_size ); ! 2331: icm_offset = icm_align ( icm_offset, len ); ! 2332: MLX_FILL_2 ( init_hca, 21, ! 2333: qpc_eec_cqc_eqc_rdb_parameters.cqc_base_addr_l, ! 2334: ( icm_offset >> 6 ), ! 2335: qpc_eec_cqc_eqc_rdb_parameters.log_num_of_cq, ! 2336: log_num_cqs ); ! 2337: DBGC ( arbel, "Arbel %p ICM CQC is %d x %#zx at [%zx,%zx)\n", ! 2338: arbel, ( 1 << log_num_cqs ), arbel->limits.cqc_entry_size, ! 2339: icm_offset, ( icm_offset + len ) ); ! 2340: icm_offset += len; ! 2341: ! 2342: /* Event queue contexts */ ! 2343: len = ( ( 1 << log_num_eqs ) * arbel->limits.eqc_entry_size ); ! 2344: icm_offset = icm_align ( icm_offset, len ); ! 2345: MLX_FILL_2 ( init_hca, 33, ! 2346: qpc_eec_cqc_eqc_rdb_parameters.eqc_base_addr_l, ! 2347: ( icm_offset >> 6 ), ! 2348: qpc_eec_cqc_eqc_rdb_parameters.log_num_eq, ! 2349: log_num_eqs ); ! 2350: DBGC ( arbel, "Arbel %p ICM EQC is %d x %#zx at [%zx,%zx)\n", ! 2351: arbel, ( 1 << log_num_eqs ), arbel->limits.eqc_entry_size, ! 2352: icm_offset, ( icm_offset + len ) ); ! 2353: icm_offset += len; ! 2354: ! 2355: /* End-to-end contexts */ ! 2356: len = ( ( 1 << log_num_ees ) * arbel->limits.eec_entry_size ); ! 2357: icm_offset = icm_align ( icm_offset, len ); ! 2358: MLX_FILL_2 ( init_hca, 17, ! 2359: qpc_eec_cqc_eqc_rdb_parameters.eec_base_addr_l, ! 2360: ( icm_offset >> 7 ), ! 2361: qpc_eec_cqc_eqc_rdb_parameters.log_num_of_ee, ! 2362: log_num_ees ); ! 2363: DBGC ( arbel, "Arbel %p ICM EEC is %d x %#zx at [%zx,%zx)\n", ! 2364: arbel, ( 1 << log_num_ees ), arbel->limits.eec_entry_size, ! 2365: icm_offset, ( icm_offset + len ) ); ! 2366: icm_offset += len; ! 2367: ! 2368: /* Shared receive queue contexts */ ! 2369: len = ( ( 1 << log_num_srqs ) * arbel->limits.srqc_entry_size ); ! 2370: icm_offset = icm_align ( icm_offset, len ); ! 2371: MLX_FILL_2 ( init_hca, 19, ! 2372: qpc_eec_cqc_eqc_rdb_parameters.srqc_base_addr_l, ! 2373: ( icm_offset >> 5 ), ! 2374: qpc_eec_cqc_eqc_rdb_parameters.log_num_of_srq, ! 2375: log_num_srqs ); ! 2376: DBGC ( arbel, "Arbel %p ICM SRQC is %d x %#zx at [%zx,%zx)\n", ! 2377: arbel, ( 1 << log_num_srqs ), arbel->limits.srqc_entry_size, ! 2378: icm_offset, ( icm_offset + len ) ); ! 2379: icm_offset += len; ! 2380: ! 2381: /* Memory protection table */ ! 2382: len = ( ( 1 << log_num_mpts ) * arbel->limits.mpt_entry_size ); ! 2383: icm_offset = icm_align ( icm_offset, len ); ! 2384: MLX_FILL_1 ( init_hca, 61, ! 2385: tpt_parameters.mpt_base_adr_l, icm_offset ); ! 2386: MLX_FILL_1 ( init_hca, 62, ! 2387: tpt_parameters.log_mpt_sz, log_num_mpts ); ! 2388: DBGC ( arbel, "Arbel %p ICM MPT is %d x %#zx at [%zx,%zx)\n", ! 2389: arbel, ( 1 << log_num_mpts ), arbel->limits.mpt_entry_size, ! 2390: icm_offset, ( icm_offset + len ) ); ! 2391: icm_offset += len; ! 2392: ! 2393: /* Remote read data base table */ ! 2394: len = ( ( 1 << log_num_rdbs ) * ARBEL_RDB_ENTRY_SIZE ); ! 2395: icm_offset = icm_align ( icm_offset, len ); ! 2396: MLX_FILL_1 ( init_hca, 37, ! 2397: qpc_eec_cqc_eqc_rdb_parameters.rdb_base_addr_l, ! 2398: icm_offset ); ! 2399: DBGC ( arbel, "Arbel %p ICM RDB is %d x %#zx at [%zx,%zx)\n", ! 2400: arbel, ( 1 << log_num_rdbs ), ARBEL_RDB_ENTRY_SIZE, ! 2401: icm_offset, ( icm_offset + len ) ); ! 2402: icm_offset += len; ! 2403: ! 2404: /* Extended end-to-end contexts */ ! 2405: len = ( ( 1 << log_num_ees ) * arbel->limits.eeec_entry_size ); ! 2406: icm_offset = icm_align ( icm_offset, len ); ! 2407: MLX_FILL_1 ( init_hca, 29, ! 2408: qpc_eec_cqc_eqc_rdb_parameters.eeec_base_addr_l, ! 2409: icm_offset ); ! 2410: DBGC ( arbel, "Arbel %p ICM EEEC is %d x %#zx at [%zx,%zx)\n", ! 2411: arbel, ( 1 << log_num_ees ), arbel->limits.eeec_entry_size, ! 2412: icm_offset, ( icm_offset + len ) ); ! 2413: icm_offset += len; ! 2414: ! 2415: /* Multicast table */ ! 2416: len = ( ( 1 << log_num_mcs ) * sizeof ( struct arbelprm_mgm_entry ) ); ! 2417: icm_offset = icm_align ( icm_offset, len ); ! 2418: MLX_FILL_1 ( init_hca, 49, ! 2419: multicast_parameters.mc_base_addr_l, icm_offset ); ! 2420: MLX_FILL_1 ( init_hca, 52, ! 2421: multicast_parameters.log_mc_table_entry_sz, ! 2422: fls ( sizeof ( struct arbelprm_mgm_entry ) - 1 ) ); ! 2423: MLX_FILL_1 ( init_hca, 53, ! 2424: multicast_parameters.mc_table_hash_sz, ! 2425: ( 1 << log_num_mcs ) ); ! 2426: MLX_FILL_1 ( init_hca, 54, ! 2427: multicast_parameters.log_mc_table_sz, ! 2428: log_num_mcs /* Only one entry per hash */ ); ! 2429: DBGC ( arbel, "Arbel %p ICM MC is %d x %#zx at [%zx,%zx)\n", arbel, ! 2430: ( 1 << log_num_mcs ), sizeof ( struct arbelprm_mgm_entry ), ! 2431: icm_offset, ( icm_offset + len ) ); ! 2432: icm_offset += len; ! 2433: ! 2434: /* Memory translation table */ ! 2435: len = ( ( 1 << log_num_mtts ) * arbel->limits.mtt_entry_size ); ! 2436: icm_offset = icm_align ( icm_offset, len ); ! 2437: MLX_FILL_1 ( init_hca, 65, ! 2438: tpt_parameters.mtt_base_addr_l, icm_offset ); ! 2439: DBGC ( arbel, "Arbel %p ICM MTT is %d x %#zx at [%zx,%zx)\n", ! 2440: arbel, ( 1 << log_num_mtts ), arbel->limits.mtt_entry_size, ! 2441: icm_offset, ( icm_offset + len ) ); ! 2442: icm_offset += len; ! 2443: ! 2444: /* User access region scratchpads */ ! 2445: len = ( ( 1 << log_num_uars ) * arbel->limits.uar_scratch_entry_size ); ! 2446: icm_offset = icm_align ( icm_offset, len ); ! 2447: MLX_FILL_1 ( init_hca, 77, ! 2448: uar_parameters.uar_scratch_base_addr_l, icm_offset ); ! 2449: DBGC ( arbel, "Arbel %p UAR scratchpad is %d x %#zx at [%zx,%zx)\n", ! 2450: arbel, ( 1 << log_num_uars ), ! 2451: arbel->limits.uar_scratch_entry_size, ! 2452: icm_offset, ( icm_offset + len ) ); ! 2453: icm_offset += len; ! 2454: ! 2455: /* Record amount of ICM to be allocated */ ! 2456: icm_offset = icm_align ( icm_offset, ARBEL_PAGE_SIZE ); ! 2457: arbel->icm_len = icm_offset; ! 2458: ! 2459: /* User access region contexts ! 2460: * ! 2461: * The reserved UAR(s) do not need to be backed by physical ! 2462: * memory, and our UAR is allocated separately; neither are ! 2463: * part of the umalloc()ed ICM block, but both contribute to ! 2464: * the total length of ICM virtual address space. ! 2465: */ ! 2466: len = ( ( 1 << log_num_uars ) * ARBEL_PAGE_SIZE ); ! 2467: icm_offset = icm_align ( icm_offset, len ); ! 2468: MLX_FILL_1 ( init_hca, 74, uar_parameters.log_max_uars, log_num_uars ); ! 2469: MLX_FILL_1 ( init_hca, 79, ! 2470: uar_parameters.uar_context_base_addr_l, icm_offset ); ! 2471: arbel->db_rec_offset = ! 2472: ( icm_offset + ! 2473: ( arbel->limits.reserved_uars * ARBEL_PAGE_SIZE ) ); ! 2474: DBGC ( arbel, "Arbel %p UAR is %d x %#zx at [%zx,%zx), doorbells " ! 2475: "[%zx,%zx)\n", arbel, ( 1 << log_num_uars ), ARBEL_PAGE_SIZE, ! 2476: icm_offset, ( icm_offset + len ), arbel->db_rec_offset, ! 2477: ( arbel->db_rec_offset + ARBEL_PAGE_SIZE ) ); ! 2478: icm_offset += len; ! 2479: ! 2480: /* Get ICM auxiliary area size */ ! 2481: memset ( &icm_size, 0, sizeof ( icm_size ) ); ! 2482: MLX_FILL_1 ( &icm_size, 1, value, arbel->icm_len ); ! 2483: if ( ( rc = arbel_cmd_set_icm_size ( arbel, &icm_size, ! 2484: &icm_aux_size ) ) != 0 ) { ! 2485: DBGC ( arbel, "Arbel %p could not set ICM size: %s\n", ! 2486: arbel, strerror ( rc ) ); ! 2487: goto err_set_icm_size; ! 2488: } ! 2489: arbel->icm_aux_len = ! 2490: ( MLX_GET ( &icm_aux_size, value ) * ARBEL_PAGE_SIZE ); ! 2491: ! 2492: /* Allocate ICM data and auxiliary area */ ! 2493: DBGC ( arbel, "Arbel %p requires %zd kB ICM and %zd kB AUX ICM\n", ! 2494: arbel, ( arbel->icm_len / 1024 ), ! 2495: ( arbel->icm_aux_len / 1024 ) ); ! 2496: arbel->icm = umalloc ( arbel->icm_len + arbel->icm_aux_len ); ! 2497: if ( ! arbel->icm ) { ! 2498: rc = -ENOMEM; ! 2499: goto err_alloc_icm; ! 2500: } ! 2501: icm_phys = user_to_phys ( arbel->icm, 0 ); ! 2502: ! 2503: /* Allocate doorbell UAR */ ! 2504: arbel->db_rec = malloc_dma ( ARBEL_PAGE_SIZE, ARBEL_PAGE_SIZE ); ! 2505: if ( ! arbel->db_rec ) { ! 2506: rc = -ENOMEM; ! 2507: goto err_alloc_doorbell; ! 2508: } ! 2509: ! 2510: /* Map ICM auxiliary area */ ! 2511: DBGC ( arbel, "Arbel %p ICM AUX at [%08lx,%08lx)\n", ! 2512: arbel, icm_phys, ( icm_phys + arbel->icm_aux_len ) ); ! 2513: if ( ( rc = arbel_map_vpm ( arbel, arbel_cmd_map_icm_aux, ! 2514: 0, icm_phys, arbel->icm_aux_len ) ) != 0 ){ ! 2515: DBGC ( arbel, "Arbel %p could not map AUX ICM: %s\n", ! 2516: arbel, strerror ( rc ) ); ! 2517: goto err_map_icm_aux; ! 2518: } ! 2519: icm_phys += arbel->icm_aux_len; ! 2520: ! 2521: /* Map ICM area */ ! 2522: DBGC ( arbel, "Arbel %p ICM at [%08lx,%08lx)\n", ! 2523: arbel, icm_phys, ( icm_phys + arbel->icm_len ) ); ! 2524: if ( ( rc = arbel_map_vpm ( arbel, arbel_cmd_map_icm, ! 2525: 0, icm_phys, arbel->icm_len ) ) != 0 ) { ! 2526: DBGC ( arbel, "Arbel %p could not map ICM: %s\n", ! 2527: arbel, strerror ( rc ) ); ! 2528: goto err_map_icm; ! 2529: } ! 2530: icm_phys += arbel->icm_len; ! 2531: ! 2532: /* Map doorbell UAR */ ! 2533: DBGC ( arbel, "Arbel %p UAR at [%08lx,%08lx)\n", ! 2534: arbel, virt_to_phys ( arbel->db_rec ), ! 2535: ( virt_to_phys ( arbel->db_rec ) + ARBEL_PAGE_SIZE ) ); ! 2536: if ( ( rc = arbel_map_vpm ( arbel, arbel_cmd_map_icm, ! 2537: arbel->db_rec_offset, ! 2538: virt_to_phys ( arbel->db_rec ), ! 2539: ARBEL_PAGE_SIZE ) ) != 0 ) { ! 2540: DBGC ( arbel, "Arbel %p could not map doorbell UAR: %s\n", ! 2541: arbel, strerror ( rc ) ); ! 2542: goto err_map_doorbell; ! 2543: } ! 2544: ! 2545: /* Initialise doorbell records */ ! 2546: memset ( arbel->db_rec, 0, ARBEL_PAGE_SIZE ); ! 2547: db_rec = &arbel->db_rec[ARBEL_GROUP_SEPARATOR_DOORBELL]; ! 2548: MLX_FILL_1 ( &db_rec->qp, 1, res, ARBEL_UAR_RES_GROUP_SEP ); ! 2549: ! 2550: return 0; ! 2551: ! 2552: memset ( &unmap_icm, 0, sizeof ( unmap_icm ) ); ! 2553: MLX_FILL_1 ( &unmap_icm, 1, value, arbel->db_rec_offset ); ! 2554: arbel_cmd_unmap_icm ( arbel, 1, &unmap_icm ); ! 2555: err_map_doorbell: ! 2556: memset ( &unmap_icm, 0, sizeof ( unmap_icm ) ); ! 2557: arbel_cmd_unmap_icm ( arbel, ( arbel->icm_len / ARBEL_PAGE_SIZE ), ! 2558: &unmap_icm ); ! 2559: err_map_icm: ! 2560: arbel_cmd_unmap_icm_aux ( arbel ); ! 2561: err_map_icm_aux: ! 2562: free_dma ( arbel->db_rec, ARBEL_PAGE_SIZE ); ! 2563: arbel->db_rec= NULL; ! 2564: err_alloc_doorbell: ! 2565: ufree ( arbel->icm ); ! 2566: arbel->icm = UNULL; ! 2567: err_alloc_icm: ! 2568: err_set_icm_size: ! 2569: return rc; ! 2570: } ! 2571: ! 2572: /** ! 2573: * Free ICM ! 2574: * ! 2575: * @v arbel Arbel device ! 2576: */ ! 2577: static void arbel_free_icm ( struct arbel *arbel ) { ! 2578: struct arbelprm_scalar_parameter unmap_icm; ! 2579: ! 2580: memset ( &unmap_icm, 0, sizeof ( unmap_icm ) ); ! 2581: MLX_FILL_1 ( &unmap_icm, 1, value, arbel->db_rec_offset ); ! 2582: arbel_cmd_unmap_icm ( arbel, 1, &unmap_icm ); ! 2583: memset ( &unmap_icm, 0, sizeof ( unmap_icm ) ); ! 2584: arbel_cmd_unmap_icm ( arbel, ( arbel->icm_len / ARBEL_PAGE_SIZE ), ! 2585: &unmap_icm ); ! 2586: arbel_cmd_unmap_icm_aux ( arbel ); ! 2587: free_dma ( arbel->db_rec, ARBEL_PAGE_SIZE ); ! 2588: arbel->db_rec = NULL; ! 2589: ufree ( arbel->icm ); ! 2590: arbel->icm = UNULL; ! 2591: } ! 2592: ! 2593: /*************************************************************************** ! 2594: * ! 2595: * PCI interface ! 2596: * ! 2597: *************************************************************************** ! 2598: */ ! 2599: ! 2600: /** ! 2601: * Set up memory protection table ! 2602: * ! 2603: * @v arbel Arbel device ! 2604: * @ret rc Return status code ! 2605: */ ! 2606: static int arbel_setup_mpt ( struct arbel *arbel ) { ! 2607: struct arbelprm_mpt mpt; ! 2608: uint32_t key; ! 2609: int rc; ! 2610: ! 2611: /* Derive key */ ! 2612: key = ( arbel->limits.reserved_mrws | ARBEL_MKEY_PREFIX ); ! 2613: arbel->lkey = ( ( key << 8 ) | ( key >> 24 ) ); ! 2614: ! 2615: /* Initialise memory protection table */ ! 2616: memset ( &mpt, 0, sizeof ( mpt ) ); ! 2617: MLX_FILL_4 ( &mpt, 0, ! 2618: r_w, 1, ! 2619: pa, 1, ! 2620: lr, 1, ! 2621: lw, 1 ); ! 2622: MLX_FILL_1 ( &mpt, 2, mem_key, key ); ! 2623: MLX_FILL_1 ( &mpt, 3, pd, ARBEL_GLOBAL_PD ); ! 2624: MLX_FILL_1 ( &mpt, 6, reg_wnd_len_h, 0xffffffffUL ); ! 2625: MLX_FILL_1 ( &mpt, 7, reg_wnd_len_l, 0xffffffffUL ); ! 2626: if ( ( rc = arbel_cmd_sw2hw_mpt ( arbel, arbel->limits.reserved_mrws, ! 2627: &mpt ) ) != 0 ) { ! 2628: DBGC ( arbel, "Arbel %p could not set up MPT: %s\n", ! 2629: arbel, strerror ( rc ) ); ! 2630: return rc; ! 2631: } ! 2632: ! 2633: return 0; ! 2634: } ! 2635: ! 2636: /** ! 2637: * Configure special queue pairs ! 2638: * ! 2639: * @v arbel Arbel device ! 2640: * @ret rc Return status code ! 2641: */ ! 2642: static int arbel_configure_special_qps ( struct arbel *arbel ) { ! 2643: unsigned int smi_qpn_base; ! 2644: unsigned int gsi_qpn_base; ! 2645: int rc; ! 2646: ! 2647: /* Special QP block must be aligned on an even number */ ! 2648: arbel->special_qpn_base = ( ( arbel->limits.reserved_qps + 1 ) & ~1 ); ! 2649: arbel->qpn_base = ( arbel->special_qpn_base + ! 2650: ARBEL_NUM_SPECIAL_QPS ); ! 2651: DBGC ( arbel, "Arbel %p special QPs at [%lx,%lx]\n", arbel, ! 2652: arbel->special_qpn_base, ( arbel->qpn_base - 1 ) ); ! 2653: smi_qpn_base = arbel->special_qpn_base; ! 2654: gsi_qpn_base = ( smi_qpn_base + 2 ); ! 2655: ! 2656: /* Issue commands to configure special QPs */ ! 2657: if ( ( rc = arbel_cmd_conf_special_qp ( arbel, 0, ! 2658: smi_qpn_base ) ) != 0 ) { ! 2659: DBGC ( arbel, "Arbel %p could not configure SMI QPs: %s\n", ! 2660: arbel, strerror ( rc ) ); ! 2661: return rc; ! 2662: } ! 2663: if ( ( rc = arbel_cmd_conf_special_qp ( arbel, 1, ! 2664: gsi_qpn_base ) ) != 0 ) { ! 2665: DBGC ( arbel, "Arbel %p could not configure GSI QPs: %s\n", ! 2666: arbel, strerror ( rc ) ); ! 2667: return rc; ! 2668: } ! 2669: ! 2670: return 0; ! 2671: } ! 2672: ! 2673: /** ! 2674: * Probe PCI device ! 2675: * ! 2676: * @v pci PCI device ! 2677: * @v id PCI ID ! 2678: * @ret rc Return status code ! 2679: */ ! 2680: static int arbel_probe ( struct pci_device *pci ) { ! 2681: struct arbel *arbel; ! 2682: struct ib_device *ibdev; ! 2683: struct arbelprm_init_hca init_hca; ! 2684: int i; ! 2685: int rc; ! 2686: ! 2687: /* Allocate Arbel device */ ! 2688: arbel = zalloc ( sizeof ( *arbel ) ); ! 2689: if ( ! arbel ) { ! 2690: rc = -ENOMEM; ! 2691: goto err_alloc_arbel; ! 2692: } ! 2693: pci_set_drvdata ( pci, arbel ); ! 2694: ! 2695: /* Allocate Infiniband devices */ ! 2696: for ( i = 0 ; i < ARBEL_NUM_PORTS ; i++ ) { ! 2697: ibdev = alloc_ibdev ( 0 ); ! 2698: if ( ! ibdev ) { ! 2699: rc = -ENOMEM; ! 2700: goto err_alloc_ibdev; ! 2701: } ! 2702: arbel->ibdev[i] = ibdev; ! 2703: ibdev->op = &arbel_ib_operations; ! 2704: ibdev->dev = &pci->dev; ! 2705: ibdev->port = ( ARBEL_PORT_BASE + i ); ! 2706: ib_set_drvdata ( ibdev, arbel ); ! 2707: } ! 2708: ! 2709: /* Fix up PCI device */ ! 2710: adjust_pci_device ( pci ); ! 2711: ! 2712: /* Get PCI BARs */ ! 2713: arbel->config = ioremap ( pci_bar_start ( pci, ARBEL_PCI_CONFIG_BAR ), ! 2714: ARBEL_PCI_CONFIG_BAR_SIZE ); ! 2715: arbel->uar = ioremap ( ( pci_bar_start ( pci, ARBEL_PCI_UAR_BAR ) + ! 2716: ARBEL_PCI_UAR_IDX * ARBEL_PCI_UAR_SIZE ), ! 2717: ARBEL_PCI_UAR_SIZE ); ! 2718: ! 2719: /* Allocate space for mailboxes */ ! 2720: arbel->mailbox_in = malloc_dma ( ARBEL_MBOX_SIZE, ARBEL_MBOX_ALIGN ); ! 2721: if ( ! arbel->mailbox_in ) { ! 2722: rc = -ENOMEM; ! 2723: goto err_mailbox_in; ! 2724: } ! 2725: arbel->mailbox_out = malloc_dma ( ARBEL_MBOX_SIZE, ARBEL_MBOX_ALIGN ); ! 2726: if ( ! arbel->mailbox_out ) { ! 2727: rc = -ENOMEM; ! 2728: goto err_mailbox_out; ! 2729: } ! 2730: ! 2731: /* Start firmware */ ! 2732: if ( ( rc = arbel_start_firmware ( arbel ) ) != 0 ) ! 2733: goto err_start_firmware; ! 2734: ! 2735: /* Get device limits */ ! 2736: if ( ( rc = arbel_get_limits ( arbel ) ) != 0 ) ! 2737: goto err_get_limits; ! 2738: ! 2739: /* Allocate ICM */ ! 2740: memset ( &init_hca, 0, sizeof ( init_hca ) ); ! 2741: if ( ( rc = arbel_alloc_icm ( arbel, &init_hca ) ) != 0 ) ! 2742: goto err_alloc_icm; ! 2743: ! 2744: /* Initialise HCA */ ! 2745: if ( ( rc = arbel_cmd_init_hca ( arbel, &init_hca ) ) != 0 ) { ! 2746: DBGC ( arbel, "Arbel %p could not initialise HCA: %s\n", ! 2747: arbel, strerror ( rc ) ); ! 2748: goto err_init_hca; ! 2749: } ! 2750: ! 2751: /* Set up memory protection */ ! 2752: if ( ( rc = arbel_setup_mpt ( arbel ) ) != 0 ) ! 2753: goto err_setup_mpt; ! 2754: ! 2755: /* Set up event queue */ ! 2756: if ( ( rc = arbel_create_eq ( arbel ) ) != 0 ) ! 2757: goto err_create_eq; ! 2758: ! 2759: /* Configure special QPs */ ! 2760: if ( ( rc = arbel_configure_special_qps ( arbel ) ) != 0 ) ! 2761: goto err_conf_special_qps; ! 2762: ! 2763: /* Initialise parameters using SMC */ ! 2764: for ( i = 0 ; i < ARBEL_NUM_PORTS ; i++ ) ! 2765: ib_smc_init ( arbel->ibdev[i], arbel_mad ); ! 2766: ! 2767: /* Register Infiniband devices */ ! 2768: for ( i = 0 ; i < ARBEL_NUM_PORTS ; i++ ) { ! 2769: if ( ( rc = register_ibdev ( arbel->ibdev[i] ) ) != 0 ) { ! 2770: DBGC ( arbel, "Arbel %p port %d could not register IB " ! 2771: "device: %s\n", arbel, ! 2772: arbel->ibdev[i]->port, strerror ( rc ) ); ! 2773: goto err_register_ibdev; ! 2774: } ! 2775: } ! 2776: ! 2777: return 0; ! 2778: ! 2779: i = ARBEL_NUM_PORTS; ! 2780: err_register_ibdev: ! 2781: for ( i-- ; i >= 0 ; i-- ) ! 2782: unregister_ibdev ( arbel->ibdev[i] ); ! 2783: err_conf_special_qps: ! 2784: arbel_destroy_eq ( arbel ); ! 2785: err_create_eq: ! 2786: err_setup_mpt: ! 2787: arbel_cmd_close_hca ( arbel ); ! 2788: err_init_hca: ! 2789: arbel_free_icm ( arbel ); ! 2790: err_alloc_icm: ! 2791: err_get_limits: ! 2792: arbel_stop_firmware ( arbel ); ! 2793: err_start_firmware: ! 2794: free_dma ( arbel->mailbox_out, ARBEL_MBOX_SIZE ); ! 2795: err_mailbox_out: ! 2796: free_dma ( arbel->mailbox_in, ARBEL_MBOX_SIZE ); ! 2797: err_mailbox_in: ! 2798: i = ARBEL_NUM_PORTS; ! 2799: err_alloc_ibdev: ! 2800: for ( i-- ; i >= 0 ; i-- ) ! 2801: ibdev_put ( arbel->ibdev[i] ); ! 2802: free ( arbel ); ! 2803: err_alloc_arbel: ! 2804: return rc; ! 2805: } ! 2806: ! 2807: /** ! 2808: * Remove PCI device ! 2809: * ! 2810: * @v pci PCI device ! 2811: */ ! 2812: static void arbel_remove ( struct pci_device *pci ) { ! 2813: struct arbel *arbel = pci_get_drvdata ( pci ); ! 2814: int i; ! 2815: ! 2816: for ( i = ( ARBEL_NUM_PORTS - 1 ) ; i >= 0 ; i-- ) ! 2817: unregister_ibdev ( arbel->ibdev[i] ); ! 2818: arbel_destroy_eq ( arbel ); ! 2819: arbel_cmd_close_hca ( arbel ); ! 2820: arbel_free_icm ( arbel ); ! 2821: arbel_stop_firmware ( arbel ); ! 2822: free_dma ( arbel->mailbox_out, ARBEL_MBOX_SIZE ); ! 2823: free_dma ( arbel->mailbox_in, ARBEL_MBOX_SIZE ); ! 2824: for ( i = ( ARBEL_NUM_PORTS - 1 ) ; i >= 0 ; i-- ) ! 2825: ibdev_put ( arbel->ibdev[i] ); ! 2826: free ( arbel ); ! 2827: } ! 2828: ! 2829: static struct pci_device_id arbel_nics[] = { ! 2830: PCI_ROM ( 0x15b3, 0x6282, "mt25218", "MT25218 HCA driver", 0 ), ! 2831: PCI_ROM ( 0x15b3, 0x6274, "mt25204", "MT25204 HCA driver", 0 ), ! 2832: }; ! 2833: ! 2834: struct pci_driver arbel_driver __pci_driver = { ! 2835: .ids = arbel_nics, ! 2836: .id_count = ( sizeof ( arbel_nics ) / sizeof ( arbel_nics[0] ) ), ! 2837: .probe = arbel_probe, ! 2838: .remove = arbel_remove, ! 2839: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.