+
+ *poolpp = pool;
+
+ return 0;
+}
+
+static int
+kiblnd_dev_get_attr(kib_dev_t *ibdev)
+{
+ struct ib_device_attr *attr;
+ int rc;
+
+ /* XXX here should be HCA's page shift/size/mask in the future? */
+ ibdev->ibd_page_shift = PAGE_SHIFT;
+ ibdev->ibd_page_size = 1 << PAGE_SHIFT;
+ ibdev->ibd_page_mask = ~((__u64)ibdev->ibd_page_size - 1);
+
+ LIBCFS_ALLOC(attr, sizeof(*attr));
+ if (attr == NULL) {
+ CERROR("Out of memory\n");
+ return -ENOMEM;
+ }
+
+ rc = ib_query_device(ibdev->ibd_cmid->device, attr);
+ if (rc == 0)
+ ibdev->ibd_mr_size = attr->max_mr_size;
+
+ LIBCFS_FREE(attr, sizeof(*attr));
+
+ if (rc != 0) {
+ CERROR("Failed to query IB device: %d\n", rc);
+ return rc;
+ }
+
+#ifdef HAVE_OFED_TRANSPORT_IWARP
+ /* XXX We can't trust this value returned by Chelsio driver, it's wrong
+ * and we have reported the bug, remove these in the future when Chelsio
+ * bug got fixed. */
+ if (rdma_node_get_transport(ibdev->ibd_cmid->device->node_type) ==
+ RDMA_TRANSPORT_IWARP)
+ ibdev->ibd_mr_size = (1ULL << 32) - 1;
+#endif
+
+ if (ibdev->ibd_mr_size == ~0ULL) {
+ ibdev->ibd_mr_shift = 64;
+ return 0;
+ }
+
+ for (ibdev->ibd_mr_shift = 0;
+ ibdev->ibd_mr_shift < 64; ibdev->ibd_mr_shift ++) {
+ if (ibdev->ibd_mr_size == (1ULL << ibdev->ibd_mr_shift) ||
+ ibdev->ibd_mr_size == (1ULL << ibdev->ibd_mr_shift) - 1)
+ return 0;
+ }
+
+ CERROR("Invalid mr size: "LPX64"\n", ibdev->ibd_mr_size);
+ return -EINVAL;
+}
+
+int
+kiblnd_dev_setup(kib_dev_t *ibdev)
+{
+ struct ib_mr *mr;
+ int i;
+ int rc;
+ __u64 mm_size;
+ __u64 mr_size;
+ int acflags = IB_ACCESS_LOCAL_WRITE |
+ IB_ACCESS_REMOTE_WRITE;
+
+ rc = kiblnd_dev_get_attr(ibdev);
+ if (rc != 0)
+ return rc;
+
+ if (ibdev->ibd_mr_shift == 64) {
+ LIBCFS_ALLOC(ibdev->ibd_mrs, 1 * sizeof(*ibdev->ibd_mrs));
+ if (ibdev->ibd_mrs == NULL) {
+ CERROR("Failed to allocate MRs table\n");
+ return -ENOMEM;
+ }
+
+ ibdev->ibd_mrs[0] = NULL;
+ ibdev->ibd_nmrs = 1;
+
+ mr = ib_get_dma_mr(ibdev->ibd_pd, acflags);
+ if (IS_ERR(mr)) {
+ CERROR("Failed ib_get_dma_mr : %ld\n", PTR_ERR(mr));
+ kiblnd_dev_cleanup(ibdev);
+ return PTR_ERR(mr);
+ }
+
+ ibdev->ibd_mrs[0] = mr;
+
+ goto out;
+ }
+
+ mr_size = (1ULL << ibdev->ibd_mr_shift);
+ mm_size = (unsigned long)high_memory - PAGE_OFFSET;
+
+ ibdev->ibd_nmrs = (int)((mm_size + mr_size - 1) >> ibdev->ibd_mr_shift);
+
+ if (ibdev->ibd_mr_shift < 32 || ibdev->ibd_nmrs > 1024) {
+ /* it's 4T..., assume we will re-code at that time */
+ CERROR("Can't support memory size: x"LPX64
+ " with MR size: x"LPX64"\n", mm_size, mr_size);
+ return -EINVAL;
+ }
+
+ /* create an array of MRs to cover all memory */
+ LIBCFS_ALLOC(ibdev->ibd_mrs, sizeof(*ibdev->ibd_mrs) * ibdev->ibd_nmrs);
+ if (ibdev->ibd_mrs == NULL) {
+ CERROR("Failed to allocate MRs' table\n");
+ return -ENOMEM;
+ }
+
+ memset(ibdev->ibd_mrs, 0, sizeof(*ibdev->ibd_mrs) * ibdev->ibd_nmrs);
+
+ for (i = 0; i < ibdev->ibd_nmrs; i++) {
+ struct ib_phys_buf ipb;
+ __u64 iova;
+
+ ipb.size = ibdev->ibd_mr_size;
+ ipb.addr = i * mr_size;
+ iova = ipb.addr;
+
+ mr = ib_reg_phys_mr(ibdev->ibd_pd, &ipb, 1, acflags, &iova);
+ if (IS_ERR(mr)) {
+ CERROR("Failed ib_reg_phys_mr addr "LPX64
+ " size "LPX64" : %ld\n",
+ ipb.addr, ipb.size, PTR_ERR(mr));
+ kiblnd_dev_cleanup(ibdev);
+ return PTR_ERR(mr);
+ }
+
+ LASSERT (iova == ipb.addr);
+
+ ibdev->ibd_mrs[i] = mr;
+ }
+
+out:
+ CDEBUG(D_CONSOLE, "Register global MR array, MR size: "
+ LPX64", array size: %d\n",
+ ibdev->ibd_mr_size, ibdev->ibd_nmrs);
+
+ list_add_tail(&ibdev->ibd_list,
+ &kiblnd_data.kib_devs);
+ return 0;
+}
+
+void
+kiblnd_destroy_dev (kib_dev_t *dev)
+{
+ LASSERT (dev->ibd_nnets == 0);
+
+ if (!list_empty(&dev->ibd_list)) /* on kib_devs? */
+ list_del_init(&dev->ibd_list);
+
+ kiblnd_dev_cleanup(dev);
+
+ if (dev->ibd_pd != NULL)
+ ib_dealloc_pd(dev->ibd_pd);
+
+ if (dev->ibd_cmid != NULL)
+ rdma_destroy_id(dev->ibd_cmid);
+
+ LIBCFS_FREE(dev, sizeof(*dev));