Commit cc21191b authored by Alexandra Winter's avatar Alexandra Winter Committed by Paolo Abeni
Browse files

dibs: Move data path to dibs layer



Use struct dibs_dmb instead of struct smc_dmb and move the corresponding
client tables to dibs_dev. Leave driver specific implementation details
like sba in the device drivers.

Register and unregister dmbs via dibs_dev_ops. A dmb is dedicated to a
single client, but a dibs device can have dmbs for more than one client.

Trigger dibs clients via dibs_client_ops->handle_irq(), when data is
received into a dmb. For dibs_loopback replace scheduling an smcd receive
tasklet with calling dibs_client_ops->handle_irq().

For loopback devices attach_dmb(), detach_dmb() and move_data() need to
access the dmb tables, so move those to dibs_dev_ops in this patch as well.

Remove remaining definitions of smc_loopback as they are no longer
required, now that everything is in dibs_loopback.

Note that struct ism_client and struct ism_dev are still required in smc
until a follow-on patch moves event handling to dibs. (Loopback does not
use events).

Signed-off-by: default avatarAlexandra Winter <wintera@linux.ibm.com>
Link: https://patch.msgid.link/20250918110500.1731261-14-wintera@linux.ibm.com


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 719c3b67
Loading
Loading
Loading
Loading
+257 −0
Original line number Diff line number Diff line
@@ -9,12 +9,18 @@
 *
 */

#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/dibs.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/types.h>

#include "dibs_loopback.h"

#define DIBS_LO_SUPPORT_NOCOPY	0x1
#define DIBS_DMA_ADDR_INVALID	(~(dma_addr_t)0)

static const char dibs_lo_dev_name[] = "lo";
/* global loopback device */
static struct dibs_lo_dev *lo_dev;
@@ -33,11 +39,259 @@ static int dibs_lo_query_rgid(struct dibs_dev *dibs, const uuid_t *rgid,
	return 0;
}

static int dibs_lo_max_dmbs(void)
{
	return DIBS_LO_MAX_DMBS;
}

static int dibs_lo_register_dmb(struct dibs_dev *dibs, struct dibs_dmb *dmb,
				struct dibs_client *client)
{
	struct dibs_lo_dmb_node *dmb_node, *tmp_node;
	struct dibs_lo_dev *ldev;
	unsigned long flags;
	int sba_idx, rc;

	ldev = dibs->drv_priv;
	sba_idx = dmb->idx;
	/* check space for new dmb */
	for_each_clear_bit(sba_idx, ldev->sba_idx_mask, DIBS_LO_MAX_DMBS) {
		if (!test_and_set_bit(sba_idx, ldev->sba_idx_mask))
			break;
	}
	if (sba_idx == DIBS_LO_MAX_DMBS)
		return -ENOSPC;

	dmb_node = kzalloc(sizeof(*dmb_node), GFP_KERNEL);
	if (!dmb_node) {
		rc = -ENOMEM;
		goto err_bit;
	}

	dmb_node->sba_idx = sba_idx;
	dmb_node->len = dmb->dmb_len;
	dmb_node->cpu_addr = kzalloc(dmb_node->len, GFP_KERNEL |
				     __GFP_NOWARN | __GFP_NORETRY |
				     __GFP_NOMEMALLOC);
	if (!dmb_node->cpu_addr) {
		rc = -ENOMEM;
		goto err_node;
	}
	dmb_node->dma_addr = DIBS_DMA_ADDR_INVALID;
	refcount_set(&dmb_node->refcnt, 1);

again:
	/* add new dmb into hash table */
	get_random_bytes(&dmb_node->token, sizeof(dmb_node->token));
	write_lock_bh(&ldev->dmb_ht_lock);
	hash_for_each_possible(ldev->dmb_ht, tmp_node, list, dmb_node->token) {
		if (tmp_node->token == dmb_node->token) {
			write_unlock_bh(&ldev->dmb_ht_lock);
			goto again;
		}
	}
	hash_add(ldev->dmb_ht, &dmb_node->list, dmb_node->token);
	write_unlock_bh(&ldev->dmb_ht_lock);
	atomic_inc(&ldev->dmb_cnt);

	dmb->idx = dmb_node->sba_idx;
	dmb->dmb_tok = dmb_node->token;
	dmb->cpu_addr = dmb_node->cpu_addr;
	dmb->dma_addr = dmb_node->dma_addr;
	dmb->dmb_len = dmb_node->len;

	spin_lock_irqsave(&dibs->lock, flags);
	dibs->dmb_clientid_arr[sba_idx] = client->id;
	spin_unlock_irqrestore(&dibs->lock, flags);

	return 0;

err_node:
	kfree(dmb_node);
err_bit:
	clear_bit(sba_idx, ldev->sba_idx_mask);
	return rc;
}

static void __dibs_lo_unregister_dmb(struct dibs_lo_dev *ldev,
				     struct dibs_lo_dmb_node *dmb_node)
{
	/* remove dmb from hash table */
	write_lock_bh(&ldev->dmb_ht_lock);
	hash_del(&dmb_node->list);
	write_unlock_bh(&ldev->dmb_ht_lock);

	clear_bit(dmb_node->sba_idx, ldev->sba_idx_mask);
	kfree(dmb_node->cpu_addr);
	kfree(dmb_node);

	if (atomic_dec_and_test(&ldev->dmb_cnt))
		wake_up(&ldev->ldev_release);
}

static int dibs_lo_unregister_dmb(struct dibs_dev *dibs, struct dibs_dmb *dmb)
{
	struct dibs_lo_dmb_node *dmb_node = NULL, *tmp_node;
	struct dibs_lo_dev *ldev;
	unsigned long flags;

	ldev = dibs->drv_priv;

	/* find dmb from hash table */
	read_lock_bh(&ldev->dmb_ht_lock);
	hash_for_each_possible(ldev->dmb_ht, tmp_node, list, dmb->dmb_tok) {
		if (tmp_node->token == dmb->dmb_tok) {
			dmb_node = tmp_node;
			break;
		}
	}
	read_unlock_bh(&ldev->dmb_ht_lock);
	if (!dmb_node)
		return -EINVAL;

	if (refcount_dec_and_test(&dmb_node->refcnt)) {
		spin_lock_irqsave(&dibs->lock, flags);
		dibs->dmb_clientid_arr[dmb_node->sba_idx] = NO_DIBS_CLIENT;
		spin_unlock_irqrestore(&dibs->lock, flags);

		__dibs_lo_unregister_dmb(ldev, dmb_node);
	}
	return 0;
}

static int dibs_lo_support_dmb_nocopy(struct dibs_dev *dibs)
{
	return DIBS_LO_SUPPORT_NOCOPY;
}

static int dibs_lo_attach_dmb(struct dibs_dev *dibs, struct dibs_dmb *dmb)
{
	struct dibs_lo_dmb_node *dmb_node = NULL, *tmp_node;
	struct dibs_lo_dev *ldev;

	ldev = dibs->drv_priv;

	/* find dmb_node according to dmb->dmb_tok */
	read_lock_bh(&ldev->dmb_ht_lock);
	hash_for_each_possible(ldev->dmb_ht, tmp_node, list, dmb->dmb_tok) {
		if (tmp_node->token == dmb->dmb_tok) {
			dmb_node = tmp_node;
			break;
		}
	}
	if (!dmb_node) {
		read_unlock_bh(&ldev->dmb_ht_lock);
		return -EINVAL;
	}
	read_unlock_bh(&ldev->dmb_ht_lock);

	if (!refcount_inc_not_zero(&dmb_node->refcnt))
		/* the dmb is being unregistered, but has
		 * not been removed from the hash table.
		 */
		return -EINVAL;

	/* provide dmb information */
	dmb->idx = dmb_node->sba_idx;
	dmb->dmb_tok = dmb_node->token;
	dmb->cpu_addr = dmb_node->cpu_addr;
	dmb->dma_addr = dmb_node->dma_addr;
	dmb->dmb_len = dmb_node->len;
	return 0;
}

static int dibs_lo_detach_dmb(struct dibs_dev *dibs, u64 token)
{
	struct dibs_lo_dmb_node *dmb_node = NULL, *tmp_node;
	struct dibs_lo_dev *ldev;

	ldev = dibs->drv_priv;

	/* find dmb_node according to dmb->dmb_tok */
	read_lock_bh(&ldev->dmb_ht_lock);
	hash_for_each_possible(ldev->dmb_ht, tmp_node, list, token) {
		if (tmp_node->token == token) {
			dmb_node = tmp_node;
			break;
		}
	}
	if (!dmb_node) {
		read_unlock_bh(&ldev->dmb_ht_lock);
		return -EINVAL;
	}
	read_unlock_bh(&ldev->dmb_ht_lock);

	if (refcount_dec_and_test(&dmb_node->refcnt))
		__dibs_lo_unregister_dmb(ldev, dmb_node);
	return 0;
}

static int dibs_lo_move_data(struct dibs_dev *dibs, u64 dmb_tok,
			     unsigned int idx, bool sf, unsigned int offset,
			     void *data, unsigned int size)
{
	struct dibs_lo_dmb_node *rmb_node = NULL, *tmp_node;
	struct dibs_lo_dev *ldev;
	u16 s_mask;
	u8 client_id;
	u32 sba_idx;

	ldev = dibs->drv_priv;

	read_lock_bh(&ldev->dmb_ht_lock);
	hash_for_each_possible(ldev->dmb_ht, tmp_node, list, dmb_tok) {
		if (tmp_node->token == dmb_tok) {
			rmb_node = tmp_node;
			break;
		}
	}
	if (!rmb_node) {
		read_unlock_bh(&ldev->dmb_ht_lock);
		return -EINVAL;
	}
	memcpy((char *)rmb_node->cpu_addr + offset, data, size);
	sba_idx = rmb_node->sba_idx;
	read_unlock_bh(&ldev->dmb_ht_lock);

	if (!sf)
		return 0;

	spin_lock(&dibs->lock);
	client_id = dibs->dmb_clientid_arr[sba_idx];
	s_mask = ror16(0x1000, idx);
	if (likely(client_id != NO_DIBS_CLIENT && dibs->subs[client_id]))
		dibs->subs[client_id]->ops->handle_irq(dibs, sba_idx, s_mask);
	spin_unlock(&dibs->lock);

	return 0;
}

static const struct dibs_dev_ops dibs_lo_ops = {
	.get_fabric_id = dibs_lo_get_fabric_id,
	.query_remote_gid = dibs_lo_query_rgid,
	.max_dmbs = dibs_lo_max_dmbs,
	.register_dmb = dibs_lo_register_dmb,
	.unregister_dmb = dibs_lo_unregister_dmb,
	.move_data = dibs_lo_move_data,
	.support_mmapped_rdmb = dibs_lo_support_dmb_nocopy,
	.attach_dmb = dibs_lo_attach_dmb,
	.detach_dmb = dibs_lo_detach_dmb,
};

static void dibs_lo_dev_init(struct dibs_lo_dev *ldev)
{
	rwlock_init(&ldev->dmb_ht_lock);
	hash_init(ldev->dmb_ht);
	atomic_set(&ldev->dmb_cnt, 0);
	init_waitqueue_head(&ldev->ldev_release);
}

static void dibs_lo_dev_exit(struct dibs_lo_dev *ldev)
{
	if (atomic_read(&ldev->dmb_cnt))
		wait_event(ldev->ldev_release, !atomic_read(&ldev->dmb_cnt));
}

static int dibs_lo_dev_probe(void)
{
	struct dibs_lo_dev *ldev;
@@ -56,6 +310,7 @@ static int dibs_lo_dev_probe(void)

	ldev->dibs = dibs;
	dibs->drv_priv = ldev;
	dibs_lo_dev_init(ldev);
	uuid_gen(&dibs->gid);
	dibs->ops = &dibs_lo_ops;

@@ -69,6 +324,7 @@ static int dibs_lo_dev_probe(void)
	return 0;

err_reg:
	kfree(dibs->dmb_clientid_arr);
	/* pairs with dibs_dev_alloc() */
	put_device(&dibs->dev);
	kfree(ldev);
@@ -82,6 +338,7 @@ static void dibs_lo_dev_remove(void)
		return;

	dibs_dev_del(lo_dev->dibs);
	dibs_lo_dev_exit(lo_dev);
	/* pairs with dibs_dev_alloc() */
	put_device(&lo_dev->dibs->dev);
	kfree(lo_dev);
+19 −0
Original line number Diff line number Diff line
@@ -13,13 +13,32 @@
#define _DIBS_LOOPBACK_H

#include <linux/dibs.h>
#include <linux/hashtable.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/wait.h>

#if IS_ENABLED(CONFIG_DIBS_LO)
#define DIBS_LO_DMBS_HASH_BITS	12
#define DIBS_LO_MAX_DMBS	5000

struct dibs_lo_dmb_node {
	struct hlist_node list;
	u64 token;
	u32 len;
	u32 sba_idx;
	void *cpu_addr;
	dma_addr_t dma_addr;
	refcount_t refcnt;
};

struct dibs_lo_dev {
	struct dibs_dev *dibs;
	atomic_t dmb_cnt;
	rwlock_t dmb_ht_lock;
	DECLARE_BITMAP(sba_idx_mask, DIBS_LO_MAX_DMBS);
	DECLARE_HASHTABLE(dmb_ht, DIBS_LO_DMBS_HASH_BITS);
	wait_queue_head_t ldev_release;
};

int dibs_loopback_init(void);
+54 −2
Original line number Diff line number Diff line
@@ -36,6 +36,16 @@ static struct dibs_dev_list dibs_dev_list = {
	.mutex = __MUTEX_INITIALIZER(dibs_dev_list.mutex),
};

static void dibs_setup_forwarding(struct dibs_client *client,
				  struct dibs_dev *dibs)
{
	unsigned long flags;

	spin_lock_irqsave(&dibs->lock, flags);
	dibs->subs[client->id] = client;
	spin_unlock_irqrestore(&dibs->lock, flags);
}

int dibs_register_client(struct dibs_client *client)
{
	struct dibs_dev *dibs;
@@ -60,6 +70,7 @@ int dibs_register_client(struct dibs_client *client)
		list_for_each_entry(dibs, &dibs_dev_list.list, list) {
			dibs->priv[i] = NULL;
			client->ops->add_dev(dibs);
			dibs_setup_forwarding(client, dibs);
		}
	}
	mutex_unlock(&dibs_dev_list.mutex);
@@ -71,10 +82,25 @@ EXPORT_SYMBOL_GPL(dibs_register_client);
int dibs_unregister_client(struct dibs_client *client)
{
	struct dibs_dev *dibs;
	unsigned long flags;
	int max_dmbs;
	int rc = 0;

	mutex_lock(&dibs_dev_list.mutex);
	list_for_each_entry(dibs, &dibs_dev_list.list, list) {
		spin_lock_irqsave(&dibs->lock, flags);
		max_dmbs = dibs->ops->max_dmbs();
		for (int i = 0; i < max_dmbs; ++i) {
			if (dibs->dmb_clientid_arr[i] == client->id) {
				WARN(1, "%s: attempt to unregister '%s' with registered dmb(s)\n",
				     __func__, client->name);
				rc = -EBUSY;
				goto err_reg_dmb;
			}
		}
		/* Stop forwarding IRQs */
		dibs->subs[client->id] = NULL;
		spin_unlock_irqrestore(&dibs->lock, flags);
		clients[client->id]->ops->del_dev(dibs);
		dibs->priv[client->id] = NULL;
	}
@@ -87,6 +113,11 @@ int dibs_unregister_client(struct dibs_client *client)

	mutex_unlock(&dibs_dev_list.mutex);
	return rc;

err_reg_dmb:
	spin_unlock_irqrestore(&dibs->lock, flags);
	mutex_unlock(&dibs_dev_list.mutex);
	return rc;
}
EXPORT_SYMBOL_GPL(dibs_unregister_client);

@@ -150,11 +181,19 @@ static const struct attribute_group dibs_dev_attr_group = {

int dibs_dev_add(struct dibs_dev *dibs)
{
	int max_dmbs;
	int i, ret;

	max_dmbs = dibs->ops->max_dmbs();
	spin_lock_init(&dibs->lock);
	dibs->dmb_clientid_arr = kzalloc(max_dmbs, GFP_KERNEL);
	if (!dibs->dmb_clientid_arr)
		return -ENOMEM;
	memset(dibs->dmb_clientid_arr, NO_DIBS_CLIENT, max_dmbs);

	ret = device_add(&dibs->dev);
	if (ret)
		return ret;
		goto free_client_arr;

	ret = sysfs_create_group(&dibs->dev.kobj, &dibs_dev_attr_group);
	if (ret) {
@@ -164,8 +203,10 @@ int dibs_dev_add(struct dibs_dev *dibs)
	mutex_lock(&dibs_dev_list.mutex);
	mutex_lock(&clients_lock);
	for (i = 0; i < max_client; ++i) {
		if (clients[i])
		if (clients[i]) {
			clients[i]->ops->add_dev(dibs);
			dibs_setup_forwarding(clients[i], dibs);
		}
	}
	mutex_unlock(&clients_lock);
	list_add(&dibs->list, &dibs_dev_list.list);
@@ -175,6 +216,8 @@ int dibs_dev_add(struct dibs_dev *dibs)

err_device_del:
	device_del(&dibs->dev);
free_client_arr:
	kfree(dibs->dmb_clientid_arr);
	return ret;

}
@@ -182,8 +225,16 @@ EXPORT_SYMBOL_GPL(dibs_dev_add);

void dibs_dev_del(struct dibs_dev *dibs)
{
	unsigned long flags;
	int i;

	sysfs_remove_group(&dibs->dev.kobj, &dibs_dev_attr_group);

	spin_lock_irqsave(&dibs->lock, flags);
	for (i = 0; i < MAX_DIBS_CLIENTS; ++i)
		dibs->subs[i] = NULL;
	spin_unlock_irqrestore(&dibs->lock, flags);

	mutex_lock(&dibs_dev_list.mutex);
	mutex_lock(&clients_lock);
	for (i = 0; i < max_client; ++i) {
@@ -195,6 +246,7 @@ void dibs_dev_del(struct dibs_dev *dibs)
	mutex_unlock(&dibs_dev_list.mutex);

	device_del(&dibs->dev);
	kfree(dibs->dmb_clientid_arr);
}
EXPORT_SYMBOL_GPL(dibs_dev_del);

+49 −72
Original line number Diff line number Diff line
@@ -98,14 +98,6 @@ int ism_unregister_client(struct ism_client *client)
		spin_lock_irqsave(&ism->lock, flags);
		/* Stop forwarding IRQs and events */
		ism->subs[client->id] = NULL;
		for (int i = 0; i < ISM_NR_DMBS; ++i) {
			if (ism->sba_client_arr[i] == client->id) {
				WARN(1, "%s: attempt to unregister '%s' with registered dmb(s)\n",
				     __func__, client->name);
				rc = -EBUSY;
				goto err_reg_dmb;
			}
		}
		spin_unlock_irqrestore(&ism->lock, flags);
	}
	mutex_unlock(&ism_dev_list.mutex);
@@ -116,11 +108,6 @@ int ism_unregister_client(struct ism_client *client)
		max_client--;
	mutex_unlock(&clients_lock);
	return rc;

err_reg_dmb:
	spin_unlock_irqrestore(&ism->lock, flags);
	mutex_unlock(&ism_dev_list.mutex);
	return rc;
}
EXPORT_SYMBOL_GPL(ism_unregister_client);

@@ -308,15 +295,20 @@ static int ism_query_rgid(struct dibs_dev *dibs, const uuid_t *rgid,
	return ism_cmd(ism, &cmd);
}

static void ism_free_dmb(struct ism_dev *ism, struct ism_dmb *dmb)
static int ism_max_dmbs(void)
{
	return ISM_NR_DMBS;
}

static void ism_free_dmb(struct ism_dev *ism, struct dibs_dmb *dmb)
{
	clear_bit(dmb->sba_idx, ism->sba_bitmap);
	clear_bit(dmb->idx, ism->sba_bitmap);
	dma_unmap_page(&ism->pdev->dev, dmb->dma_addr, dmb->dmb_len,
		       DMA_FROM_DEVICE);
	folio_put(virt_to_folio(dmb->cpu_addr));
}

static int ism_alloc_dmb(struct ism_dev *ism, struct ism_dmb *dmb)
static int ism_alloc_dmb(struct ism_dev *ism, struct dibs_dmb *dmb)
{
	struct folio *folio;
	unsigned long bit;
@@ -325,16 +317,16 @@ static int ism_alloc_dmb(struct ism_dev *ism, struct ism_dmb *dmb)
	if (PAGE_ALIGN(dmb->dmb_len) > dma_get_max_seg_size(&ism->pdev->dev))
		return -EINVAL;

	if (!dmb->sba_idx) {
	if (!dmb->idx) {
		bit = find_next_zero_bit(ism->sba_bitmap, ISM_NR_DMBS,
					 ISM_DMB_BIT_OFFSET);
		if (bit == ISM_NR_DMBS)
			return -ENOSPC;

		dmb->sba_idx = bit;
		dmb->idx = bit;
	}
	if (dmb->sba_idx < ISM_DMB_BIT_OFFSET ||
	    test_and_set_bit(dmb->sba_idx, ism->sba_bitmap))
	if (dmb->idx < ISM_DMB_BIT_OFFSET ||
	    test_and_set_bit(dmb->idx, ism->sba_bitmap))
		return -EINVAL;

	folio = folio_alloc(GFP_KERNEL | __GFP_NOWARN | __GFP_NOMEMALLOC |
@@ -359,13 +351,14 @@ static int ism_alloc_dmb(struct ism_dev *ism, struct ism_dmb *dmb)
out_free:
	kfree(dmb->cpu_addr);
out_bit:
	clear_bit(dmb->sba_idx, ism->sba_bitmap);
	clear_bit(dmb->idx, ism->sba_bitmap);
	return rc;
}

int ism_register_dmb(struct ism_dev *ism, struct ism_dmb *dmb,
		     struct ism_client *client)
static int ism_register_dmb(struct dibs_dev *dibs, struct dibs_dmb *dmb,
			    struct dibs_client *client)
{
	struct ism_dev *ism = dibs->drv_priv;
	union ism_reg_dmb cmd;
	unsigned long flags;
	int ret;
@@ -380,10 +373,10 @@ int ism_register_dmb(struct ism_dev *ism, struct ism_dmb *dmb,

	cmd.request.dmb = dmb->dma_addr;
	cmd.request.dmb_len = dmb->dmb_len;
	cmd.request.sba_idx = dmb->sba_idx;
	cmd.request.sba_idx = dmb->idx;
	cmd.request.vlan_valid = dmb->vlan_valid;
	cmd.request.vlan_id = dmb->vlan_id;
	cmd.request.rgid = dmb->rgid;
	memcpy(&cmd.request.rgid, &dmb->rgid, sizeof(u64));

	ret = ism_cmd(ism, &cmd);
	if (ret) {
@@ -391,16 +384,16 @@ int ism_register_dmb(struct ism_dev *ism, struct ism_dmb *dmb,
		goto out;
	}
	dmb->dmb_tok = cmd.response.dmb_tok;
	spin_lock_irqsave(&ism->lock, flags);
	ism->sba_client_arr[dmb->sba_idx - ISM_DMB_BIT_OFFSET] = client->id;
	spin_unlock_irqrestore(&ism->lock, flags);
	spin_lock_irqsave(&dibs->lock, flags);
	dibs->dmb_clientid_arr[dmb->idx - ISM_DMB_BIT_OFFSET] = client->id;
	spin_unlock_irqrestore(&dibs->lock, flags);
out:
	return ret;
}
EXPORT_SYMBOL_GPL(ism_register_dmb);

int ism_unregister_dmb(struct ism_dev *ism, struct ism_dmb *dmb)
static int ism_unregister_dmb(struct dibs_dev *dibs, struct dibs_dmb *dmb)
{
	struct ism_dev *ism = dibs->drv_priv;
	union ism_unreg_dmb cmd;
	unsigned long flags;
	int ret;
@@ -411,9 +404,9 @@ int ism_unregister_dmb(struct ism_dev *ism, struct ism_dmb *dmb)

	cmd.request.dmb_tok = dmb->dmb_tok;

	spin_lock_irqsave(&ism->lock, flags);
	ism->sba_client_arr[dmb->sba_idx - ISM_DMB_BIT_OFFSET] = NO_CLIENT;
	spin_unlock_irqrestore(&ism->lock, flags);
	spin_lock_irqsave(&dibs->lock, flags);
	dibs->dmb_clientid_arr[dmb->idx - ISM_DMB_BIT_OFFSET] = NO_DIBS_CLIENT;
	spin_unlock_irqrestore(&dibs->lock, flags);

	ret = ism_cmd(ism, &cmd);
	if (ret && ret != ISM_ERROR)
@@ -423,7 +416,6 @@ int ism_unregister_dmb(struct ism_dev *ism, struct ism_dmb *dmb)
out:
	return ret;
}
EXPORT_SYMBOL_GPL(ism_unregister_dmb);

static int ism_add_vlan_id(struct dibs_dev *dibs, u64 vlan_id)
{
@@ -459,9 +451,11 @@ static unsigned int max_bytes(unsigned int start, unsigned int len,
	return min(boundary - (start & (boundary - 1)), len);
}

int ism_move(struct ism_dev *ism, u64 dmb_tok, unsigned int idx, bool sf,
	     unsigned int offset, void *data, unsigned int size)
static int ism_move(struct dibs_dev *dibs, u64 dmb_tok, unsigned int idx,
		    bool sf, unsigned int offset, void *data,
		    unsigned int size)
{
	struct ism_dev *ism = dibs->drv_priv;
	unsigned int bytes;
	u64 dmb_req;
	int ret;
@@ -482,7 +476,6 @@ int ism_move(struct ism_dev *ism, u64 dmb_tok, unsigned int idx, bool sf,

	return 0;
}
EXPORT_SYMBOL_GPL(ism_move);

static u16 ism_get_chid(struct dibs_dev *dibs)
{
@@ -518,14 +511,17 @@ static irqreturn_t ism_handle_irq(int irq, void *data)
{
	struct ism_dev *ism = data;
	unsigned long bit, end;
	struct dibs_dev *dibs;
	unsigned long *bv;
	u16 dmbemask;
	u8 client_id;

	dibs = ism->dibs;

	bv = (void *) &ism->sba->dmb_bits[ISM_DMB_WORD_OFFSET];
	end = sizeof(ism->sba->dmb_bits) * BITS_PER_BYTE - ISM_DMB_BIT_OFFSET;

	spin_lock(&ism->lock);
	spin_lock(&dibs->lock);
	ism->sba->s = 0;
	barrier();
	for (bit = 0;;) {
@@ -537,10 +533,13 @@ static irqreturn_t ism_handle_irq(int irq, void *data)
		dmbemask = ism->sba->dmbe_mask[bit + ISM_DMB_BIT_OFFSET];
		ism->sba->dmbe_mask[bit + ISM_DMB_BIT_OFFSET] = 0;
		barrier();
		client_id = ism->sba_client_arr[bit];
		if (unlikely(client_id == NO_CLIENT || !ism->subs[client_id]))
		client_id = dibs->dmb_clientid_arr[bit];
		if (unlikely(client_id == NO_DIBS_CLIENT ||
			     !dibs->subs[client_id]))
			continue;
		ism->subs[client_id]->handle_irq(ism, bit + ISM_DMB_BIT_OFFSET, dmbemask);
		dibs->subs[client_id]->ops->handle_irq(dibs,
						       bit + ISM_DMB_BIT_OFFSET,
						       dmbemask);
	}

	if (ism->sba->e) {
@@ -548,13 +547,17 @@ static irqreturn_t ism_handle_irq(int irq, void *data)
		barrier();
		ism_handle_event(ism);
	}
	spin_unlock(&ism->lock);
	spin_unlock(&dibs->lock);
	return IRQ_HANDLED;
}

static const struct dibs_dev_ops ism_ops = {
	.get_fabric_id = ism_get_chid,
	.query_remote_gid = ism_query_rgid,
	.max_dmbs = ism_max_dmbs,
	.register_dmb = ism_register_dmb,
	.unregister_dmb = ism_unregister_dmb,
	.move_data = ism_move,
	.add_vlan_id = ism_add_vlan_id,
	.del_vlan_id = ism_del_vlan_id,
};
@@ -568,15 +571,10 @@ static int ism_dev_init(struct ism_dev *ism)
	if (ret <= 0)
		goto out;

	ism->sba_client_arr = kzalloc(ISM_NR_DMBS, GFP_KERNEL);
	if (!ism->sba_client_arr)
		goto free_vectors;
	memset(ism->sba_client_arr, NO_CLIENT, ISM_NR_DMBS);

	ret = request_irq(pci_irq_vector(pdev, 0), ism_handle_irq, 0,
			  pci_name(pdev), ism);
	if (ret)
		goto free_client_arr;
		goto free_vectors;

	ret = register_sba(ism);
	if (ret)
@@ -605,8 +603,6 @@ static int ism_dev_init(struct ism_dev *ism)
	unregister_sba(ism);
free_irq:
	free_irq(pci_irq_vector(pdev, 0), ism);
free_client_arr:
	kfree(ism->sba_client_arr);
free_vectors:
	pci_free_irq_vectors(pdev);
out:
@@ -629,7 +625,6 @@ static void ism_dev_exit(struct ism_dev *ism)
	unregister_ieq(ism);
	unregister_sba(ism);
	free_irq(pci_irq_vector(pdev, 0), ism);
	kfree(ism->sba_client_arr);
	pci_free_irq_vectors(pdev);
	list_del_init(&ism->list);
	mutex_unlock(&ism_dev_list.mutex);
@@ -677,6 +672,9 @@ static int ism_probe(struct pci_dev *pdev, const struct pci_device_id *id)
	dibs->drv_priv = ism;
	dibs->ops = &ism_ops;

	/* enable ism device, but any interrupts and events will be ignored
	 * before dibs_dev_add() adds it to any clients.
	 */
	ret = ism_dev_init(ism);
	if (ret)
		goto err_dibs;
@@ -766,17 +764,6 @@ module_exit(ism_exit);
/*************************** SMC-D Implementation *****************************/

#if IS_ENABLED(CONFIG_SMC)
static int smcd_register_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb,
			     void *client)
{
	return ism_register_dmb(smcd->priv, (struct ism_dmb *)dmb, client);
}

static int smcd_unregister_dmb(struct smcd_dev *smcd, struct smcd_dmb *dmb)
{
	return ism_unregister_dmb(smcd->priv, (struct ism_dmb *)dmb);
}

static int ism_signal_ieq(struct ism_dev *ism, u64 rgid, u32 trigger_irq,
			  u32 event_code, u64 info)
{
@@ -801,18 +788,8 @@ static int smcd_signal_ieq(struct smcd_dev *smcd, struct smcd_gid *rgid,
			      trigger_irq, event_code, info);
}

static int smcd_move(struct smcd_dev *smcd, u64 dmb_tok, unsigned int idx,
		     bool sf, unsigned int offset, void *data,
		     unsigned int size)
{
	return ism_move(smcd->priv, dmb_tok, idx, sf, offset, data, size);
}

static const struct smcd_ops ism_smcd_ops = {
	.register_dmb = smcd_register_dmb,
	.unregister_dmb = smcd_unregister_dmb,
	.signal_event = smcd_signal_ieq,
	.move_data = smcd_move,
};

const struct smcd_ops *ism_get_smcd_ops(void)
+177 −0

File changed.

Preview size limit exceeded, changes collapsed.

Loading