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

📄 mthca_mr.c

📁 h内核
💻 C
字号:
/* * Copyright (c) 2004 Topspin Communications.  All rights reserved. * * This software is available to you under a choice of one of two * licenses.  You may choose to be licensed under the terms of the GNU * General Public License (GPL) Version 2, available from the file * COPYING in the main directory of this source tree, or the * OpenIB.org BSD license below: * *     Redistribution and use in source and binary forms, with or *     without modification, are permitted provided that the following *     conditions are met: * *      - Redistributions of source code must retain the above *        copyright notice, this list of conditions and the following *        disclaimer. * *      - Redistributions in binary form must reproduce the above *        copyright notice, this list of conditions and the following *        disclaimer in the documentation and/or other materials *        provided with the distribution. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * $Id: mthca_mr.c 1349 2004-12-16 21:09:43Z roland $ */#include <linux/slab.h>#include <linux/init.h>#include <linux/errno.h>#include "mthca_dev.h"#include "mthca_cmd.h"/* * Must be packed because mtt_seg is 64 bits but only aligned to 32 bits. */struct mthca_mpt_entry {	u32 flags;	u32 page_size;	u32 key;	u32 pd;	u64 start;	u64 length;	u32 lkey;	u32 window_count;	u32 window_count_limit;	u64 mtt_seg;	u32 reserved[3];} __attribute__((packed));#define MTHCA_MPT_FLAG_SW_OWNS       (0xfUL << 28)#define MTHCA_MPT_FLAG_MIO           (1 << 17)#define MTHCA_MPT_FLAG_BIND_ENABLE   (1 << 15)#define MTHCA_MPT_FLAG_PHYSICAL      (1 <<  9)#define MTHCA_MPT_FLAG_REGION        (1 <<  8)#define MTHCA_MTT_FLAG_PRESENT       1/* * Buddy allocator for MTT segments (currently not very efficient * since it doesn't keep a free list and just searches linearly * through the bitmaps) */static u32 mthca_alloc_mtt(struct mthca_dev *dev, int order){	int o;	int m;	u32 seg;	spin_lock(&dev->mr_table.mpt_alloc.lock);	for (o = order; o <= dev->mr_table.max_mtt_order; ++o) {		m = 1 << (dev->mr_table.max_mtt_order - o);		seg = find_first_bit(dev->mr_table.mtt_buddy[o], m);		if (seg < m)			goto found;	}	spin_unlock(&dev->mr_table.mpt_alloc.lock);	return -1; found:	clear_bit(seg, dev->mr_table.mtt_buddy[o]);	while (o > order) {		--o;		seg <<= 1;		set_bit(seg ^ 1, dev->mr_table.mtt_buddy[o]);	}	spin_unlock(&dev->mr_table.mpt_alloc.lock);	seg <<= order;	return seg;}static void mthca_free_mtt(struct mthca_dev *dev, u32 seg, int order){	seg >>= order;	spin_lock(&dev->mr_table.mpt_alloc.lock);	while (test_bit(seg ^ 1, dev->mr_table.mtt_buddy[order])) {		clear_bit(seg ^ 1, dev->mr_table.mtt_buddy[order]);		seg >>= 1;		++order;	}	set_bit(seg, dev->mr_table.mtt_buddy[order]);	spin_unlock(&dev->mr_table.mpt_alloc.lock);}int mthca_mr_alloc_notrans(struct mthca_dev *dev, u32 pd,			   u32 access, struct mthca_mr *mr){	void *mailbox;	struct mthca_mpt_entry *mpt_entry;	int err;	u8 status;	might_sleep();	mr->order = -1;	mr->ibmr.lkey = mthca_alloc(&dev->mr_table.mpt_alloc);	if (mr->ibmr.lkey == -1)		return -ENOMEM;	mr->ibmr.rkey = mr->ibmr.lkey;	mailbox = kmalloc(sizeof *mpt_entry + MTHCA_CMD_MAILBOX_EXTRA,			  GFP_KERNEL);	if (!mailbox) {		mthca_free(&dev->mr_table.mpt_alloc, mr->ibmr.lkey);		return -ENOMEM;	}	mpt_entry = MAILBOX_ALIGN(mailbox);	mpt_entry->flags = cpu_to_be32(MTHCA_MPT_FLAG_SW_OWNS     |				       MTHCA_MPT_FLAG_MIO         |				       MTHCA_MPT_FLAG_PHYSICAL    |				       MTHCA_MPT_FLAG_REGION      |				       access);	mpt_entry->page_size = 0;	mpt_entry->key       = cpu_to_be32(mr->ibmr.lkey);	mpt_entry->pd        = cpu_to_be32(pd);	mpt_entry->start     = 0;	mpt_entry->length    = ~0ULL;	memset(&mpt_entry->lkey, 0,	       sizeof *mpt_entry - offsetof(struct mthca_mpt_entry, lkey));	err = mthca_SW2HW_MPT(dev, mpt_entry,			      mr->ibmr.lkey & (dev->limits.num_mpts - 1),			      &status);	if (err)		mthca_warn(dev, "SW2HW_MPT failed (%d)\n", err);	else if (status) {		mthca_warn(dev, "SW2HW_MPT returned status 0x%02x\n",			   status);		err = -EINVAL;	}	kfree(mailbox);	return err;}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){	void *mailbox;	u64 *mtt_entry;	struct mthca_mpt_entry *mpt_entry;	int err = -ENOMEM;	u8 status;	int i;	might_sleep();	WARN_ON(buffer_size_shift >= 32);	mr->ibmr.lkey = mthca_alloc(&dev->mr_table.mpt_alloc);	if (mr->ibmr.lkey == -1)		return -ENOMEM;	mr->ibmr.rkey = mr->ibmr.lkey;	for (i = dev->limits.mtt_seg_size / 8, mr->order = 0;	     i < list_len;	     i <<= 1, ++mr->order)		; /* nothing */	mr->first_seg = mthca_alloc_mtt(dev, mr->order);	if (mr->first_seg == -1)		goto err_out_mpt_free;	/*	 * If list_len is odd, we add one more dummy entry for	 * firmware efficiency.	 */	mailbox = kmalloc(max(sizeof *mpt_entry,			      (size_t) 8 * (list_len + (list_len & 1) + 2)) +			  MTHCA_CMD_MAILBOX_EXTRA,			  GFP_KERNEL);	if (!mailbox)		goto err_out_free_mtt;	mtt_entry = MAILBOX_ALIGN(mailbox);	mtt_entry[0] = cpu_to_be64(dev->mr_table.mtt_base +				   mr->first_seg * dev->limits.mtt_seg_size);	mtt_entry[1] = 0;	for (i = 0; i < list_len; ++i)		mtt_entry[i + 2] = cpu_to_be64(buffer_list[i] |					       MTHCA_MTT_FLAG_PRESENT);	if (list_len & 1) {		mtt_entry[i + 2] = 0;		++list_len;	}	if (0) {		mthca_dbg(dev, "Dumping MPT entry\n");		for (i = 0; i < list_len + 2; ++i)			printk(KERN_ERR "[%2d] %016llx\n",			       i, (unsigned long long) be64_to_cpu(mtt_entry[i]));	}	err = mthca_WRITE_MTT(dev, mtt_entry, list_len, &status);	if (err) {		mthca_warn(dev, "WRITE_MTT failed (%d)\n", err);		goto err_out_mailbox_free;	}	if (status) {		mthca_warn(dev, "WRITE_MTT returned status 0x%02x\n",			   status);		err = -EINVAL;		goto err_out_mailbox_free;	}	mpt_entry = MAILBOX_ALIGN(mailbox);	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(buffer_size_shift - 12);	mpt_entry->key       = cpu_to_be32(mr->ibmr.lkey);	mpt_entry->pd        = cpu_to_be32(pd);	mpt_entry->start     = cpu_to_be64(iova);	mpt_entry->length    = cpu_to_be64(total_size);	memset(&mpt_entry->lkey, 0,	       sizeof *mpt_entry - offsetof(struct mthca_mpt_entry, lkey));	mpt_entry->mtt_seg   = cpu_to_be64(dev->mr_table.mtt_base +					   mr->first_seg * dev->limits.mtt_seg_size);	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(((u32 *) mpt_entry)[i]));			if ((i + 1) % 4 == 0)				printk("\n");		}	}	err = mthca_SW2HW_MPT(dev, mpt_entry,			      mr->ibmr.lkey & (dev->limits.num_mpts - 1),			      &status);	if (err)		mthca_warn(dev, "SW2HW_MPT failed (%d)\n", err);	else if (status) {		mthca_warn(dev, "SW2HW_MPT returned status 0x%02x\n",			   status);		err = -EINVAL;	}	kfree(mailbox);	return err; err_out_mailbox_free:	kfree(mailbox); err_out_free_mtt:	mthca_free_mtt(dev, mr->first_seg, mr->order); err_out_mpt_free:	mthca_free(&dev->mr_table.mpt_alloc, mr->ibmr.lkey);	return err;}void mthca_free_mr(struct mthca_dev *dev, struct mthca_mr *mr){	int err;	u8 status;	might_sleep();	err = mthca_HW2SW_MPT(dev, NULL,			      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);	if (mr->order >= 0)		mthca_free_mtt(dev, mr->first_seg, mr->order);	mthca_free(&dev->mr_table.mpt_alloc, mr->ibmr.lkey);}int __devinit mthca_init_mr_table(struct mthca_dev *dev){	int err;	int i, s;	err = mthca_alloc_init(&dev->mr_table.mpt_alloc,			       dev->limits.num_mpts,			       ~0, dev->limits.reserved_mrws);	if (err)		return err;	err = -ENOMEM;	for (i = 1, dev->mr_table.max_mtt_order = 0;	     i < dev->limits.num_mtt_segs;	     i <<= 1, ++dev->mr_table.max_mtt_order)		; /* nothing */	dev->mr_table.mtt_buddy = kmalloc((dev->mr_table.max_mtt_order + 1) *					  sizeof (long *),					  GFP_KERNEL);	if (!dev->mr_table.mtt_buddy)		goto err_out;	for (i = 0; i <= dev->mr_table.max_mtt_order; ++i)		dev->mr_table.mtt_buddy[i] = NULL;	for (i = 0; i <= dev->mr_table.max_mtt_order; ++i) {		s = BITS_TO_LONGS(1 << (dev->mr_table.max_mtt_order - i));		dev->mr_table.mtt_buddy[i] = kmalloc(s * sizeof (long),						     GFP_KERNEL);		if (!dev->mr_table.mtt_buddy[i])			goto err_out_free;		bitmap_zero(dev->mr_table.mtt_buddy[i],			    1 << (dev->mr_table.max_mtt_order - i));	}	set_bit(0, dev->mr_table.mtt_buddy[dev->mr_table.max_mtt_order]);	for (i = 0; i < dev->mr_table.max_mtt_order; ++i)		if (1 << i >= dev->limits.reserved_mtts)			break;	if (i == dev->mr_table.max_mtt_order) {		mthca_err(dev, "MTT table of order %d is "			  "too small.\n", i);		goto err_out_free;	}	(void) mthca_alloc_mtt(dev, i);	return 0; err_out_free:	for (i = 0; i <= dev->mr_table.max_mtt_order; ++i)		kfree(dev->mr_table.mtt_buddy[i]); err_out:	mthca_alloc_cleanup(&dev->mr_table.mpt_alloc);	return err;}void __devexit mthca_cleanup_mr_table(struct mthca_dev *dev){	int i;	/* XXX check if any MRs are still allocated? */	for (i = 0; i <= dev->mr_table.max_mtt_order; ++i)		kfree(dev->mr_table.mtt_buddy[i]);	kfree(dev->mr_table.mtt_buddy);	mthca_alloc_cleanup(&dev->mr_table.mpt_alloc);}

⌨️ 快捷键说明

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