⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mthca_mr.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 2 页
字号:
			   status);		err = -EINVAL;		goto err_out_mailbox;	}	mthca_free_mailbox(dev, mailbox);	return err;err_out_mailbox:	mthca_free_mailbox(dev, mailbox);err_out_table:	mthca_table_put(dev, dev->mr_table.mpt_table, key);err_out_mpt_free:	mthca_free(&dev->mr_table.mpt_alloc, key);	return err;}int mthca_mr_alloc_notrans(struct mthca_dev *dev, u32 pd,			   u32 access, struct mthca_mr *mr){	mr->mtt = NULL;	return mthca_mr_alloc(dev, pd, 12, 0, ~0ULL, access, mr);}int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,			u64 *buffer_list, int buffer_size_shift,			int list_len, u64 iova, u64 total_size,			u32 access, struct mthca_mr *mr){	int err;	mr->mtt = mthca_alloc_mtt(dev, list_len);	if (IS_ERR(mr->mtt))		return PTR_ERR(mr->mtt);	err = mthca_write_mtt(dev, mr->mtt, 0, buffer_list, list_len);	if (err) {		mthca_free_mtt(dev, mr->mtt);		return err;	}	err = mthca_mr_alloc(dev, pd, buffer_size_shift, iova,			     total_size, access, mr);	if (err)		mthca_free_mtt(dev, mr->mtt);	return err;}/* Free mr or fmr */static void mthca_free_region(struct mthca_dev *dev, u32 lkey){	mthca_table_put(dev, dev->mr_table.mpt_table,			key_to_hw_index(dev, lkey));	mthca_free(&dev->mr_table.mpt_alloc, key_to_hw_index(dev, lkey));}void mthca_free_mr(struct mthca_dev *dev, struct mthca_mr *mr){	int err;	u8 status;	err = mthca_HW2SW_MPT(dev, NULL,			      key_to_hw_index(dev, mr->ibmr.lkey) &			      (dev->limits.num_mpts - 1),			      &status);	if (err)		mthca_warn(dev, "HW2SW_MPT failed (%d)\n", err);	else if (status)		mthca_warn(dev, "HW2SW_MPT returned status 0x%02x\n",			   status);	mthca_free_region(dev, mr->ibmr.lkey);	mthca_free_mtt(dev, mr->mtt);}int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,		    u32 access, struct mthca_fmr *mr){	struct mthca_mpt_entry *mpt_entry;	struct mthca_mailbox *mailbox;	u64 mtt_seg;	u32 key, idx;	u8 status;	int list_len = mr->attr.max_pages;	int err = -ENOMEM;	int i;	if (mr->attr.page_shift < 12 || mr->attr.page_shift >= 32)		return -EINVAL;	/* For Arbel, all MTTs must fit in the same page. */	if (mthca_is_memfree(dev) &&	    mr->attr.max_pages * sizeof *mr->mem.arbel.mtts > PAGE_SIZE)		return -EINVAL;	mr->maps = 0;	key = mthca_alloc(&dev->mr_table.mpt_alloc);	if (key == -1)		return -ENOMEM;	key = adjust_key(dev, key);	idx = key & (dev->limits.num_mpts - 1);	mr->ibmr.rkey = mr->ibmr.lkey = hw_index_to_key(dev, key);	if (mthca_is_memfree(dev)) {		err = mthca_table_get(dev, dev->mr_table.mpt_table, key);		if (err)			goto err_out_mpt_free;		mr->mem.arbel.mpt = mthca_table_find(dev->mr_table.mpt_table, key, NULL);		BUG_ON(!mr->mem.arbel.mpt);	} else		mr->mem.tavor.mpt = dev->mr_table.tavor_fmr.mpt_base +			sizeof *(mr->mem.tavor.mpt) * idx;	mr->mtt = __mthca_alloc_mtt(dev, list_len, dev->mr_table.fmr_mtt_buddy);	if (IS_ERR(mr->mtt))		goto err_out_table;	mtt_seg = mr->mtt->first_seg * MTHCA_MTT_SEG_SIZE;	if (mthca_is_memfree(dev)) {		mr->mem.arbel.mtts = mthca_table_find(dev->mr_table.mtt_table,						      mr->mtt->first_seg,						      &mr->mem.arbel.dma_handle);		BUG_ON(!mr->mem.arbel.mtts);	} else		mr->mem.tavor.mtts = dev->mr_table.tavor_fmr.mtt_base + mtt_seg;	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);	if (IS_ERR(mailbox))		goto err_out_free_mtt;	mpt_entry = mailbox->buf;	mpt_entry->flags = cpu_to_be32(MTHCA_MPT_FLAG_SW_OWNS     |				       MTHCA_MPT_FLAG_MIO         |				       MTHCA_MPT_FLAG_REGION      |				       access);	mpt_entry->page_size = cpu_to_be32(mr->attr.page_shift - 12);	mpt_entry->key       = cpu_to_be32(key);	mpt_entry->pd        = cpu_to_be32(pd);	memset(&mpt_entry->start, 0,	       sizeof *mpt_entry - offsetof(struct mthca_mpt_entry, start));	mpt_entry->mtt_seg   = cpu_to_be64(dev->mr_table.mtt_base + mtt_seg);	if (0) {		mthca_dbg(dev, "Dumping MPT entry %08x:\n", mr->ibmr.lkey);		for (i = 0; i < sizeof (struct mthca_mpt_entry) / 4; ++i) {			if (i % 4 == 0)				printk("[%02x] ", i * 4);			printk(" %08x", be32_to_cpu(((__be32 *) mpt_entry)[i]));			if ((i + 1) % 4 == 0)				printk("\n");		}	}	err = mthca_SW2HW_MPT(dev, mailbox,			      key & (dev->limits.num_mpts - 1),			      &status);	if (err) {		mthca_warn(dev, "SW2HW_MPT failed (%d)\n", err);		goto err_out_mailbox_free;	}	if (status) {		mthca_warn(dev, "SW2HW_MPT returned status 0x%02x\n",			   status);		err = -EINVAL;		goto err_out_mailbox_free;	}	mthca_free_mailbox(dev, mailbox);	return 0;err_out_mailbox_free:	mthca_free_mailbox(dev, mailbox);err_out_free_mtt:	mthca_free_mtt(dev, mr->mtt);err_out_table:	mthca_table_put(dev, dev->mr_table.mpt_table, key);err_out_mpt_free:	mthca_free(&dev->mr_table.mpt_alloc, mr->ibmr.lkey);	return err;}int mthca_free_fmr(struct mthca_dev *dev, struct mthca_fmr *fmr){	if (fmr->maps)		return -EBUSY;	mthca_free_region(dev, fmr->ibmr.lkey);	mthca_free_mtt(dev, fmr->mtt);	return 0;}static inline int mthca_check_fmr(struct mthca_fmr *fmr, u64 *page_list,				  int list_len, u64 iova){	int i, page_mask;	if (list_len > fmr->attr.max_pages)		return -EINVAL;	page_mask = (1 << fmr->attr.page_shift) - 1;	/* We are getting page lists, so va must be page aligned. */	if (iova & page_mask)		return -EINVAL;	/* Trust the user not to pass misaligned data in page_list */	if (0)		for (i = 0; i < list_len; ++i) {			if (page_list[i] & ~page_mask)				return -EINVAL;		}	if (fmr->maps >= fmr->attr.max_maps)		return -EINVAL;	return 0;}int mthca_tavor_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list,			     int list_len, u64 iova){	struct mthca_fmr *fmr = to_mfmr(ibfmr);	struct mthca_dev *dev = to_mdev(ibfmr->device);	struct mthca_mpt_entry mpt_entry;	u32 key;	int i, err;	err = mthca_check_fmr(fmr, page_list, list_len, iova);	if (err)		return err;	++fmr->maps;	key = tavor_key_to_hw_index(fmr->ibmr.lkey);	key += dev->limits.num_mpts;	fmr->ibmr.lkey = fmr->ibmr.rkey = tavor_hw_index_to_key(key);	writeb(MTHCA_MPT_STATUS_SW, fmr->mem.tavor.mpt);	for (i = 0; i < list_len; ++i) {		__be64 mtt_entry = cpu_to_be64(page_list[i] |					       MTHCA_MTT_FLAG_PRESENT);		mthca_write64_raw(mtt_entry, fmr->mem.tavor.mtts + i);	}	mpt_entry.lkey   = cpu_to_be32(key);	mpt_entry.length = cpu_to_be64(list_len * (1ull << fmr->attr.page_shift));	mpt_entry.start  = cpu_to_be64(iova);	__raw_writel((__force u32) mpt_entry.lkey, &fmr->mem.tavor.mpt->key);	memcpy_toio(&fmr->mem.tavor.mpt->start, &mpt_entry.start,		    offsetof(struct mthca_mpt_entry, window_count) -		    offsetof(struct mthca_mpt_entry, start));	writeb(MTHCA_MPT_STATUS_HW, fmr->mem.tavor.mpt);	return 0;}int mthca_arbel_map_phys_fmr(struct ib_fmr *ibfmr, u64 *page_list,			     int list_len, u64 iova){	struct mthca_fmr *fmr = to_mfmr(ibfmr);	struct mthca_dev *dev = to_mdev(ibfmr->device);	u32 key;	int i, err;	err = mthca_check_fmr(fmr, page_list, list_len, iova);	if (err)		return err;	++fmr->maps;	key = arbel_key_to_hw_index(fmr->ibmr.lkey);	if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT)		key += SINAI_FMR_KEY_INC;	else		key += dev->limits.num_mpts;	fmr->ibmr.lkey = fmr->ibmr.rkey = arbel_hw_index_to_key(key);	*(u8 *) fmr->mem.arbel.mpt = MTHCA_MPT_STATUS_SW;	wmb();	for (i = 0; i < list_len; ++i)		fmr->mem.arbel.mtts[i] = cpu_to_be64(page_list[i] |						     MTHCA_MTT_FLAG_PRESENT);	dma_sync_single(&dev->pdev->dev, fmr->mem.arbel.dma_handle,			list_len * sizeof(u64), DMA_TO_DEVICE);	fmr->mem.arbel.mpt->key    = cpu_to_be32(key);	fmr->mem.arbel.mpt->lkey   = cpu_to_be32(key);	fmr->mem.arbel.mpt->length = cpu_to_be64(list_len * (1ull << fmr->attr.page_shift));	fmr->mem.arbel.mpt->start  = cpu_to_be64(iova);	wmb();	*(u8 *) fmr->mem.arbel.mpt = MTHCA_MPT_STATUS_HW;	wmb();	return 0;}void mthca_tavor_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr){	u32 key;	if (!fmr->maps)		return;	key = tavor_key_to_hw_index(fmr->ibmr.lkey);	key &= dev->limits.num_mpts - 1;	fmr->ibmr.lkey = fmr->ibmr.rkey = tavor_hw_index_to_key(key);	fmr->maps = 0;	writeb(MTHCA_MPT_STATUS_SW, fmr->mem.tavor.mpt);}void mthca_arbel_fmr_unmap(struct mthca_dev *dev, struct mthca_fmr *fmr){	u32 key;	if (!fmr->maps)		return;	key = arbel_key_to_hw_index(fmr->ibmr.lkey);	key &= dev->limits.num_mpts - 1;	key = adjust_key(dev, key);	fmr->ibmr.lkey = fmr->ibmr.rkey = arbel_hw_index_to_key(key);	fmr->maps = 0;	*(u8 *) fmr->mem.arbel.mpt = MTHCA_MPT_STATUS_SW;}int mthca_init_mr_table(struct mthca_dev *dev){	unsigned long addr;	int mpts, mtts, err, i;	err = mthca_alloc_init(&dev->mr_table.mpt_alloc,			       dev->limits.num_mpts,			       ~0, dev->limits.reserved_mrws);	if (err)		return err;	if (!mthca_is_memfree(dev) &&	    (dev->mthca_flags & MTHCA_FLAG_DDR_HIDDEN))		dev->limits.fmr_reserved_mtts = 0;	else		dev->mthca_flags |= MTHCA_FLAG_FMR;	if (dev->mthca_flags & MTHCA_FLAG_SINAI_OPT)		mthca_dbg(dev, "Memory key throughput optimization activated.\n");	err = mthca_buddy_init(&dev->mr_table.mtt_buddy,			       fls(dev->limits.num_mtt_segs - 1));	if (err)		goto err_mtt_buddy;	dev->mr_table.tavor_fmr.mpt_base = NULL;	dev->mr_table.tavor_fmr.mtt_base = NULL;	if (dev->limits.fmr_reserved_mtts) {		i = fls(dev->limits.fmr_reserved_mtts - 1);		if (i >= 31) {			mthca_warn(dev, "Unable to reserve 2^31 FMR MTTs.\n");			err = -EINVAL;			goto err_fmr_mpt;		}		mpts = mtts = 1 << i;	} else {		mtts = dev->limits.num_mtt_segs;		mpts = dev->limits.num_mpts;	}	if (!mthca_is_memfree(dev) &&	    (dev->mthca_flags & MTHCA_FLAG_FMR)) {		addr = pci_resource_start(dev->pdev, 4) +			((pci_resource_len(dev->pdev, 4) - 1) &			 dev->mr_table.mpt_base);		dev->mr_table.tavor_fmr.mpt_base =			ioremap(addr, mpts * sizeof(struct mthca_mpt_entry));		if (!dev->mr_table.tavor_fmr.mpt_base) {			mthca_warn(dev, "MPT ioremap for FMR failed.\n");			err = -ENOMEM;			goto err_fmr_mpt;		}		addr = pci_resource_start(dev->pdev, 4) +			((pci_resource_len(dev->pdev, 4) - 1) &			 dev->mr_table.mtt_base);		dev->mr_table.tavor_fmr.mtt_base =			ioremap(addr, mtts * MTHCA_MTT_SEG_SIZE);		if (!dev->mr_table.tavor_fmr.mtt_base) {			mthca_warn(dev, "MTT ioremap for FMR failed.\n");			err = -ENOMEM;			goto err_fmr_mtt;		}	}	if (dev->limits.fmr_reserved_mtts) {		err = mthca_buddy_init(&dev->mr_table.tavor_fmr.mtt_buddy, fls(mtts - 1));		if (err)			goto err_fmr_mtt_buddy;		/* Prevent regular MRs from using FMR keys */		err = mthca_buddy_alloc(&dev->mr_table.mtt_buddy, fls(mtts - 1));		if (err)			goto err_reserve_fmr;		dev->mr_table.fmr_mtt_buddy =			&dev->mr_table.tavor_fmr.mtt_buddy;	} else		dev->mr_table.fmr_mtt_buddy = &dev->mr_table.mtt_buddy;	/* FMR table is always the first, take reserved MTTs out of there */	if (dev->limits.reserved_mtts) {		i = fls(dev->limits.reserved_mtts - 1);		if (mthca_alloc_mtt_range(dev, i,					  dev->mr_table.fmr_mtt_buddy) == -1) {			mthca_warn(dev, "MTT table of order %d is too small.\n",				  dev->mr_table.fmr_mtt_buddy->max_order);			err = -ENOMEM;			goto err_reserve_mtts;		}	}	return 0;err_reserve_mtts:err_reserve_fmr:	if (dev->limits.fmr_reserved_mtts)		mthca_buddy_cleanup(&dev->mr_table.tavor_fmr.mtt_buddy);err_fmr_mtt_buddy:	if (dev->mr_table.tavor_fmr.mtt_base)		iounmap(dev->mr_table.tavor_fmr.mtt_base);err_fmr_mtt:	if (dev->mr_table.tavor_fmr.mpt_base)		iounmap(dev->mr_table.tavor_fmr.mpt_base);err_fmr_mpt:	mthca_buddy_cleanup(&dev->mr_table.mtt_buddy);err_mtt_buddy:	mthca_alloc_cleanup(&dev->mr_table.mpt_alloc);	return err;}void mthca_cleanup_mr_table(struct mthca_dev *dev){	/* XXX check if any MRs are still allocated? */	if (dev->limits.fmr_reserved_mtts)		mthca_buddy_cleanup(&dev->mr_table.tavor_fmr.mtt_buddy);	mthca_buddy_cleanup(&dev->mr_table.mtt_buddy);	if (dev->mr_table.tavor_fmr.mtt_base)		iounmap(dev->mr_table.tavor_fmr.mtt_base);	if (dev->mr_table.tavor_fmr.mpt_base)		iounmap(dev->mr_table.tavor_fmr.mpt_base);	mthca_alloc_cleanup(&dev->mr_table.mpt_alloc);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -