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

📄 mthca_mr.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 2004 Topspin Communications.  All rights reserved. * Copyright (c) 2005 Mellanox Technologies. 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"#include "mthca_memfree.h"struct mthca_mtt {	struct mthca_buddy *buddy;	int                 order;	u32                 first_seg;};/* * Must be packed because mtt_seg is 64 bits but only aligned to 32 bits. */struct mthca_mpt_entry {	__be32 flags;	__be32 page_size;	__be32 key;	__be32 pd;	__be64 start;	__be64 length;	__be32 lkey;	__be32 window_count;	__be32 window_count_limit;	__be64 mtt_seg;	__be32 mtt_sz;		/* Arbel only */	u32    reserved[2];} __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#define MTHCA_MPT_STATUS_SW 0xF0#define MTHCA_MPT_STATUS_HW 0x00/* * 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_buddy_alloc(struct mthca_buddy *buddy, int order){	int o;	int m;	u32 seg;	spin_lock(&buddy->lock);	for (o = order; o <= buddy->max_order; ++o) {		m = 1 << (buddy->max_order - o);		seg = find_first_bit(buddy->bits[o], m);		if (seg < m)			goto found;	}	spin_unlock(&buddy->lock);	return -1; found:	clear_bit(seg, buddy->bits[o]);	while (o > order) {		--o;		seg <<= 1;		set_bit(seg ^ 1, buddy->bits[o]);	}	spin_unlock(&buddy->lock);	seg <<= order;	return seg;}static void mthca_buddy_free(struct mthca_buddy *buddy, u32 seg, int order){	seg >>= order;	spin_lock(&buddy->lock);	while (test_bit(seg ^ 1, buddy->bits[order])) {		clear_bit(seg ^ 1, buddy->bits[order]);		seg >>= 1;		++order;	}	set_bit(seg, buddy->bits[order]);	spin_unlock(&buddy->lock);}static int __devinit mthca_buddy_init(struct mthca_buddy *buddy, int max_order){	int i, s;	buddy->max_order = max_order;	spin_lock_init(&buddy->lock);	buddy->bits = kzalloc((buddy->max_order + 1) * sizeof (long *),			      GFP_KERNEL);	if (!buddy->bits)		goto err_out;	for (i = 0; i <= buddy->max_order; ++i) {		s = BITS_TO_LONGS(1 << (buddy->max_order - i));		buddy->bits[i] = kmalloc(s * sizeof (long), GFP_KERNEL);		if (!buddy->bits[i])			goto err_out_free;		bitmap_zero(buddy->bits[i],			    1 << (buddy->max_order - i));	}	set_bit(0, buddy->bits[buddy->max_order]);	return 0;err_out_free:	for (i = 0; i <= buddy->max_order; ++i)		kfree(buddy->bits[i]);	kfree(buddy->bits);err_out:	return -ENOMEM;}static void __devexit mthca_buddy_cleanup(struct mthca_buddy *buddy){	int i;	for (i = 0; i <= buddy->max_order; ++i)		kfree(buddy->bits[i]);	kfree(buddy->bits);}static u32 mthca_alloc_mtt_range(struct mthca_dev *dev, int order,				 struct mthca_buddy *buddy){	u32 seg = mthca_buddy_alloc(buddy, order);	if (seg == -1)		return -1;	if (mthca_is_memfree(dev))		if (mthca_table_get_range(dev, dev->mr_table.mtt_table, seg,					  seg + (1 << order) - 1)) {			mthca_buddy_free(buddy, seg, order);			seg = -1;		}	return seg;}static struct mthca_mtt *__mthca_alloc_mtt(struct mthca_dev *dev, int size,					   struct mthca_buddy *buddy){	struct mthca_mtt *mtt;	int i;	if (size <= 0)		return ERR_PTR(-EINVAL);	mtt = kmalloc(sizeof *mtt, GFP_KERNEL);	if (!mtt)		return ERR_PTR(-ENOMEM);	mtt->buddy = buddy;	mtt->order = 0;	for (i = MTHCA_MTT_SEG_SIZE / 8; i < size; i <<= 1)		++mtt->order;	mtt->first_seg = mthca_alloc_mtt_range(dev, mtt->order, buddy);	if (mtt->first_seg == -1) {		kfree(mtt);		return ERR_PTR(-ENOMEM);	}	return mtt;}struct mthca_mtt *mthca_alloc_mtt(struct mthca_dev *dev, int size){	return __mthca_alloc_mtt(dev, size, &dev->mr_table.mtt_buddy);}void mthca_free_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt){	if (!mtt)		return;	mthca_buddy_free(mtt->buddy, mtt->first_seg, mtt->order);	mthca_table_put_range(dev, dev->mr_table.mtt_table,			      mtt->first_seg,			      mtt->first_seg + (1 << mtt->order) - 1);	kfree(mtt);}int mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt,		    int start_index, u64 *buffer_list, int list_len){	struct mthca_mailbox *mailbox;	__be64 *mtt_entry;	int err = 0;	u8 status;	int i;	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);	if (IS_ERR(mailbox))		return PTR_ERR(mailbox);	mtt_entry = mailbox->buf;	while (list_len > 0) {		mtt_entry[0] = cpu_to_be64(dev->mr_table.mtt_base +					   mtt->first_seg * MTHCA_MTT_SEG_SIZE +					   start_index * 8);		mtt_entry[1] = 0;		for (i = 0; i < list_len && i < MTHCA_MAILBOX_SIZE / 8 - 2; ++i)			mtt_entry[i + 2] = cpu_to_be64(buffer_list[i] |						       MTHCA_MTT_FLAG_PRESENT);		/*		 * If we have an odd number of entries to write, add		 * one more dummy entry for firmware efficiency.		 */		if (i & 1)			mtt_entry[i + 2] = 0;		err = mthca_WRITE_MTT(dev, mailbox, (i + 1) & ~1, &status);		if (err) {			mthca_warn(dev, "WRITE_MTT failed (%d)\n", err);			goto out;		}		if (status) {			mthca_warn(dev, "WRITE_MTT returned status 0x%02x\n",				   status);			err = -EINVAL;			goto out;		}		list_len    -= i;		start_index += i;		buffer_list += i;	}out:	mthca_free_mailbox(dev, mailbox);	return err;}static inline u32 tavor_hw_index_to_key(u32 ind){	return ind;}static inline u32 tavor_key_to_hw_index(u32 key){	return key;}static inline u32 arbel_hw_index_to_key(u32 ind){	return (ind >> 24) | (ind << 8);}static inline u32 arbel_key_to_hw_index(u32 key){	return (key << 24) | (key >> 8);}static inline u32 hw_index_to_key(struct mthca_dev *dev, u32 ind){	if (mthca_is_memfree(dev))		return arbel_hw_index_to_key(ind);	else		return tavor_hw_index_to_key(ind);}static inline u32 key_to_hw_index(struct mthca_dev *dev, u32 key){	if (mthca_is_memfree(dev))		return arbel_key_to_hw_index(key);	else		return tavor_key_to_hw_index(key);}int mthca_mr_alloc(struct mthca_dev *dev, u32 pd, int buffer_size_shift,		   u64 iova, u64 total_size, u32 access, struct mthca_mr *mr){	struct mthca_mailbox *mailbox;	struct mthca_mpt_entry *mpt_entry;	u32 key;	int i;	int err;	u8 status;	might_sleep();	WARN_ON(buffer_size_shift >= 32);	key = mthca_alloc(&dev->mr_table.mpt_alloc);	if (key == -1)		return -ENOMEM;	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;	}	mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);	if (IS_ERR(mailbox)) {		err = PTR_ERR(mailbox);		goto err_out_table;	}	mpt_entry = mailbox->buf;	mpt_entry->flags = cpu_to_be32(MTHCA_MPT_FLAG_SW_OWNS     |				       MTHCA_MPT_FLAG_MIO         |				       MTHCA_MPT_FLAG_REGION      |				       access);	if (!mr->mtt)		mpt_entry->flags |= cpu_to_be32(MTHCA_MPT_FLAG_PHYSICAL);	mpt_entry->page_size = cpu_to_be32(buffer_size_shift - 12);	mpt_entry->key       = cpu_to_be32(key);	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));	if (mr->mtt)		mpt_entry->mtt_seg =			cpu_to_be64(dev->mr_table.mtt_base +				    mr->mtt->first_seg * MTHCA_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(((__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;	} else if (status) {		mthca_warn(dev, "SW2HW_MPT returned status 0x%02x\n",			   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;

⌨️ 快捷键说明

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