1219820Sjeff/* 2219820Sjeff * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. 3219820Sjeff * Copyright (c) 2006 Cisco Systems. All rights reserved. 4219820Sjeff * 5219820Sjeff * This software is available to you under a choice of one of two 6219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 7219820Sjeff * General Public License (GPL) Version 2, available from the file 8219820Sjeff * COPYING in the main directory of this source tree, or the 9219820Sjeff * OpenIB.org BSD license below: 10219820Sjeff * 11219820Sjeff * Redistribution and use in source and binary forms, with or 12219820Sjeff * without modification, are permitted provided that the following 13219820Sjeff * conditions are met: 14219820Sjeff * 15219820Sjeff * - Redistributions of source code must retain the above 16219820Sjeff * copyright notice, this list of conditions and the following 17219820Sjeff * disclaimer. 18219820Sjeff * 19219820Sjeff * - Redistributions in binary form must reproduce the above 20219820Sjeff * copyright notice, this list of conditions and the following 21219820Sjeff * disclaimer in the documentation and/or other materials 22219820Sjeff * provided with the distribution. 23219820Sjeff * 24219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31219820Sjeff * SOFTWARE. 32219820Sjeff */ 33219820Sjeff 34219820Sjeff#if HAVE_CONFIG_H 35219820Sjeff# include <config.h> 36219820Sjeff#endif /* HAVE_CONFIG_H */ 37219820Sjeff 38219820Sjeff#include <stdio.h> 39219820Sjeff#include <stdlib.h> 40219820Sjeff#include <unistd.h> 41219820Sjeff#include <errno.h> 42219820Sjeff#include <sys/mman.h> 43219820Sjeff#include <pthread.h> 44219820Sjeff#include <string.h> 45219820Sjeff 46219820Sjeff#ifndef HAVE_IBV_REGISTER_DRIVER 47219820Sjeff#include <sysfs/libsysfs.h> 48219820Sjeff#endif 49219820Sjeff 50219820Sjeff#ifndef HAVE_IBV_READ_SYSFS_FILE 51219820Sjeff#include <sys/types.h> 52219820Sjeff#include <sys/stat.h> 53219820Sjeff#include <fcntl.h> 54219820Sjeff#endif 55219820Sjeff 56219820Sjeff#include "mthca.h" 57219820Sjeff#include "mthca-abi.h" 58219820Sjeff 59219820Sjeff#ifndef PCI_VENDOR_ID_MELLANOX 60219820Sjeff#define PCI_VENDOR_ID_MELLANOX 0x15b3 61219820Sjeff#endif 62219820Sjeff 63219820Sjeff#ifndef PCI_DEVICE_ID_MELLANOX_TAVOR 64219820Sjeff#define PCI_DEVICE_ID_MELLANOX_TAVOR 0x5a44 65219820Sjeff#endif 66219820Sjeff 67219820Sjeff#ifndef PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT 68219820Sjeff#define PCI_DEVICE_ID_MELLANOX_ARBEL_COMPAT 0x6278 69219820Sjeff#endif 70219820Sjeff 71219820Sjeff#ifndef PCI_DEVICE_ID_MELLANOX_ARBEL 72219820Sjeff#define PCI_DEVICE_ID_MELLANOX_ARBEL 0x6282 73219820Sjeff#endif 74219820Sjeff 75219820Sjeff#ifndef PCI_DEVICE_ID_MELLANOX_SINAI_OLD 76219820Sjeff#define PCI_DEVICE_ID_MELLANOX_SINAI_OLD 0x5e8c 77219820Sjeff#endif 78219820Sjeff 79219820Sjeff#ifndef PCI_DEVICE_ID_MELLANOX_SINAI 80219820Sjeff#define PCI_DEVICE_ID_MELLANOX_SINAI 0x6274 81219820Sjeff#endif 82219820Sjeff 83219820Sjeff#ifndef PCI_VENDOR_ID_TOPSPIN 84219820Sjeff#define PCI_VENDOR_ID_TOPSPIN 0x1867 85219820Sjeff#endif 86219820Sjeff 87219820Sjeff#define HCA(v, d, t) \ 88219820Sjeff { .vendor = PCI_VENDOR_ID_##v, \ 89219820Sjeff .device = PCI_DEVICE_ID_MELLANOX_##d, \ 90219820Sjeff .type = MTHCA_##t } 91219820Sjeff 92219820Sjeffstruct { 93219820Sjeff unsigned vendor; 94219820Sjeff unsigned device; 95219820Sjeff enum mthca_hca_type type; 96219820Sjeff} hca_table[] = { 97219820Sjeff HCA(MELLANOX, TAVOR, TAVOR), 98219820Sjeff HCA(MELLANOX, ARBEL_COMPAT, TAVOR), 99219820Sjeff HCA(MELLANOX, ARBEL, ARBEL), 100219820Sjeff HCA(MELLANOX, SINAI_OLD, ARBEL), 101219820Sjeff HCA(MELLANOX, SINAI, ARBEL), 102219820Sjeff HCA(TOPSPIN, TAVOR, TAVOR), 103219820Sjeff HCA(TOPSPIN, ARBEL_COMPAT, TAVOR), 104219820Sjeff HCA(TOPSPIN, ARBEL, ARBEL), 105219820Sjeff HCA(TOPSPIN, SINAI_OLD, ARBEL), 106219820Sjeff HCA(TOPSPIN, SINAI, ARBEL), 107219820Sjeff}; 108219820Sjeff 109219820Sjeffstatic struct ibv_context_ops mthca_ctx_ops = { 110219820Sjeff .query_device = mthca_query_device, 111219820Sjeff .query_port = mthca_query_port, 112219820Sjeff .alloc_pd = mthca_alloc_pd, 113219820Sjeff .dealloc_pd = mthca_free_pd, 114219820Sjeff .reg_mr = mthca_reg_mr, 115219820Sjeff .dereg_mr = mthca_dereg_mr, 116219820Sjeff .create_cq = mthca_create_cq, 117219820Sjeff .poll_cq = mthca_poll_cq, 118219820Sjeff .resize_cq = mthca_resize_cq, 119219820Sjeff .destroy_cq = mthca_destroy_cq, 120219820Sjeff .create_srq = mthca_create_srq, 121219820Sjeff .modify_srq = mthca_modify_srq, 122219820Sjeff .query_srq = mthca_query_srq, 123219820Sjeff .destroy_srq = mthca_destroy_srq, 124219820Sjeff .create_qp = mthca_create_qp, 125219820Sjeff .query_qp = mthca_query_qp, 126219820Sjeff .modify_qp = mthca_modify_qp, 127219820Sjeff .destroy_qp = mthca_destroy_qp, 128219820Sjeff .create_ah = mthca_create_ah, 129219820Sjeff .destroy_ah = mthca_destroy_ah, 130219820Sjeff .attach_mcast = mthca_attach_mcast, 131219820Sjeff .detach_mcast = mthca_detach_mcast 132219820Sjeff}; 133219820Sjeff 134219820Sjeffstatic struct ibv_context *mthca_alloc_context(struct ibv_device *ibdev, int cmd_fd) 135219820Sjeff{ 136219820Sjeff struct mthca_context *context; 137219820Sjeff struct ibv_get_context cmd; 138219820Sjeff struct mthca_alloc_ucontext_resp resp; 139219820Sjeff int i; 140219820Sjeff 141219820Sjeff context = calloc(1, sizeof *context); 142219820Sjeff if (!context) 143219820Sjeff return NULL; 144219820Sjeff 145219820Sjeff context->ibv_ctx.cmd_fd = cmd_fd; 146219820Sjeff 147219820Sjeff if (ibv_cmd_get_context(&context->ibv_ctx, &cmd, sizeof cmd, 148219820Sjeff &resp.ibv_resp, sizeof resp)) 149219820Sjeff goto err_free; 150219820Sjeff 151219820Sjeff context->num_qps = resp.qp_tab_size; 152219820Sjeff context->qp_table_shift = ffs(context->num_qps) - 1 - MTHCA_QP_TABLE_BITS; 153219820Sjeff context->qp_table_mask = (1 << context->qp_table_shift) - 1; 154219820Sjeff 155219820Sjeff /* 156219820Sjeff * Need to set ibv_ctx.device because mthca_is_memfree() will 157219820Sjeff * look at it to figure out the HCA type. 158219820Sjeff */ 159219820Sjeff context->ibv_ctx.device = ibdev; 160219820Sjeff 161219820Sjeff if (mthca_is_memfree(&context->ibv_ctx)) { 162219820Sjeff context->db_tab = mthca_alloc_db_tab(resp.uarc_size); 163219820Sjeff if (!context->db_tab) 164219820Sjeff goto err_free; 165219820Sjeff } else 166219820Sjeff context->db_tab = NULL; 167219820Sjeff 168219820Sjeff pthread_mutex_init(&context->qp_table_mutex, NULL); 169219820Sjeff for (i = 0; i < MTHCA_QP_TABLE_SIZE; ++i) 170219820Sjeff context->qp_table[i].refcnt = 0; 171219820Sjeff 172219820Sjeff context->uar = mmap(NULL, to_mdev(ibdev)->page_size, PROT_WRITE, 173219820Sjeff MAP_SHARED, cmd_fd, 0); 174219820Sjeff if (context->uar == MAP_FAILED) 175219820Sjeff goto err_db_tab; 176219820Sjeff 177219820Sjeff pthread_spin_init(&context->uar_lock, PTHREAD_PROCESS_PRIVATE); 178219820Sjeff 179219820Sjeff context->pd = mthca_alloc_pd(&context->ibv_ctx); 180219820Sjeff if (!context->pd) 181219820Sjeff goto err_unmap; 182219820Sjeff 183219820Sjeff context->pd->context = &context->ibv_ctx; 184219820Sjeff 185219820Sjeff context->ibv_ctx.ops = mthca_ctx_ops; 186219820Sjeff 187219820Sjeff if (mthca_is_memfree(&context->ibv_ctx)) { 188219820Sjeff context->ibv_ctx.ops.req_notify_cq = mthca_arbel_arm_cq; 189219820Sjeff context->ibv_ctx.ops.cq_event = mthca_arbel_cq_event; 190219820Sjeff context->ibv_ctx.ops.post_send = mthca_arbel_post_send; 191219820Sjeff context->ibv_ctx.ops.post_recv = mthca_arbel_post_recv; 192219820Sjeff context->ibv_ctx.ops.post_srq_recv = mthca_arbel_post_srq_recv; 193219820Sjeff } else { 194219820Sjeff context->ibv_ctx.ops.req_notify_cq = mthca_tavor_arm_cq; 195219820Sjeff context->ibv_ctx.ops.cq_event = NULL; 196219820Sjeff context->ibv_ctx.ops.post_send = mthca_tavor_post_send; 197219820Sjeff context->ibv_ctx.ops.post_recv = mthca_tavor_post_recv; 198219820Sjeff context->ibv_ctx.ops.post_srq_recv = mthca_tavor_post_srq_recv; 199219820Sjeff } 200219820Sjeff 201219820Sjeff return &context->ibv_ctx; 202219820Sjeff 203219820Sjefferr_unmap: 204219820Sjeff munmap(context->uar, to_mdev(ibdev)->page_size); 205219820Sjeff 206219820Sjefferr_db_tab: 207219820Sjeff mthca_free_db_tab(context->db_tab); 208219820Sjeff 209219820Sjefferr_free: 210219820Sjeff free(context); 211219820Sjeff return NULL; 212219820Sjeff} 213219820Sjeff 214219820Sjeffstatic void mthca_free_context(struct ibv_context *ibctx) 215219820Sjeff{ 216219820Sjeff struct mthca_context *context = to_mctx(ibctx); 217219820Sjeff 218219820Sjeff mthca_free_pd(context->pd); 219219820Sjeff munmap(context->uar, to_mdev(ibctx->device)->page_size); 220219820Sjeff mthca_free_db_tab(context->db_tab); 221219820Sjeff free(context); 222219820Sjeff} 223219820Sjeff 224219820Sjeffstatic struct ibv_device_ops mthca_dev_ops = { 225219820Sjeff .alloc_context = mthca_alloc_context, 226219820Sjeff .free_context = mthca_free_context 227219820Sjeff}; 228219820Sjeff 229219820Sjeff/* 230219820Sjeff * Keep a private implementation of HAVE_IBV_READ_SYSFS_FILE to handle 231219820Sjeff * old versions of libibverbs that didn't implement it. This can be 232219820Sjeff * removed when libibverbs 1.0.3 or newer is available "everywhere." 233219820Sjeff */ 234219820Sjeff#ifndef HAVE_IBV_READ_SYSFS_FILE 235219820Sjeffstatic int ibv_read_sysfs_file(const char *dir, const char *file, 236219820Sjeff char *buf, size_t size) 237219820Sjeff{ 238219820Sjeff char path[256]; 239219820Sjeff int fd; 240219820Sjeff int len; 241219820Sjeff 242219820Sjeff snprintf(path, sizeof path, "%s/%s", dir, file); 243219820Sjeff 244219820Sjeff fd = open(path, O_RDONLY); 245219820Sjeff if (fd < 0) 246219820Sjeff return -1; 247219820Sjeff 248219820Sjeff len = read(fd, buf, size); 249219820Sjeff 250219820Sjeff close(fd); 251219820Sjeff 252219820Sjeff if (len > 0 && buf[len - 1] == '\n') 253219820Sjeff buf[--len] = '\0'; 254219820Sjeff 255219820Sjeff return len; 256219820Sjeff} 257219820Sjeff#endif /* HAVE_IBV_READ_SYSFS_FILE */ 258219820Sjeff 259219820Sjeffstatic struct ibv_device *mthca_driver_init(const char *uverbs_sys_path, 260219820Sjeff int abi_version) 261219820Sjeff{ 262219820Sjeff char value[8]; 263219820Sjeff struct mthca_device *dev; 264219820Sjeff unsigned vendor, device; 265219820Sjeff int i; 266219820Sjeff 267219820Sjeff if (ibv_read_sysfs_file(uverbs_sys_path, "device/vendor", 268219820Sjeff value, sizeof value) < 0) 269219820Sjeff return NULL; 270219820Sjeff sscanf(value, "%i", &vendor); 271219820Sjeff 272219820Sjeff if (ibv_read_sysfs_file(uverbs_sys_path, "device/device", 273219820Sjeff value, sizeof value) < 0) 274219820Sjeff return NULL; 275219820Sjeff sscanf(value, "%i", &device); 276219820Sjeff 277219820Sjeff for (i = 0; i < sizeof hca_table / sizeof hca_table[0]; ++i) 278219820Sjeff if (vendor == hca_table[i].vendor && 279219820Sjeff device == hca_table[i].device) 280219820Sjeff goto found; 281219820Sjeff 282219820Sjeff return NULL; 283219820Sjeff 284219820Sjefffound: 285219820Sjeff if (abi_version > MTHCA_UVERBS_ABI_VERSION) { 286219820Sjeff fprintf(stderr, PFX "Fatal: ABI version %d of %s is too new (expected %d)\n", 287219820Sjeff abi_version, uverbs_sys_path, MTHCA_UVERBS_ABI_VERSION); 288219820Sjeff return NULL; 289219820Sjeff } 290219820Sjeff 291219820Sjeff dev = malloc(sizeof *dev); 292219820Sjeff if (!dev) { 293219820Sjeff fprintf(stderr, PFX "Fatal: couldn't allocate device for %s\n", 294219820Sjeff uverbs_sys_path); 295219820Sjeff return NULL; 296219820Sjeff } 297219820Sjeff 298219820Sjeff dev->ibv_dev.ops = mthca_dev_ops; 299219820Sjeff dev->hca_type = hca_table[i].type; 300219820Sjeff dev->page_size = sysconf(_SC_PAGESIZE); 301219820Sjeff 302219820Sjeff return &dev->ibv_dev; 303219820Sjeff} 304219820Sjeff 305219820Sjeff#ifdef HAVE_IBV_REGISTER_DRIVER 306219820Sjeffstatic __attribute__((constructor)) void mthca_register_driver(void) 307219820Sjeff{ 308219820Sjeff ibv_register_driver("mthca", mthca_driver_init); 309219820Sjeff} 310219820Sjeff#else 311219820Sjeff/* 312219820Sjeff * Export the old libsysfs sysfs_class_device-based driver entry point 313219820Sjeff * if libibverbs does not export an ibv_register_driver() function. 314219820Sjeff */ 315219820Sjeffstruct ibv_device *openib_driver_init(struct sysfs_class_device *sysdev) 316219820Sjeff{ 317219820Sjeff int abi_ver = 0; 318219820Sjeff char value[8]; 319219820Sjeff 320219820Sjeff if (ibv_read_sysfs_file(sysdev->path, "abi_version", 321219820Sjeff value, sizeof value) > 0) 322219820Sjeff abi_ver = strtol(value, NULL, 10); 323219820Sjeff 324219820Sjeff return mthca_driver_init(sysdev->path, abi_ver); 325219820Sjeff} 326219820Sjeff#endif /* HAVE_IBV_REGISTER_DRIVER */ 327