All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Bernard Metzler" <BMT-OA+xvbQnYDHMbYB6QlFGEg@public.gmane.org>
To: Leon Romanovsky <leon-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Subject: Re: [PATCH v2 03/13] Attach/detach SoftiWarp to/from network and RDMA subsystem
Date: Sat, 14 Oct 2017 01:28:43 +0000	[thread overview]
Message-ID: <OF406E95F8.33CF80BB-ON002581B9.00073D6F-002581B9.00081F69@notes.na.collabserv.com> (raw)
In-Reply-To: <20171008130342.GV25829-U/DQcQFIOTAAJjI8aNfphQ@public.gmane.org>

-----Leon Romanovsky <leon-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> wrote: -----

>To: Bernard Metzler <bmt-OA+xvbQnYDHMbYB6QlFGEg@public.gmane.org>
>From: Leon Romanovsky <leon-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
>Date: 10/08/2017 03:03PM
>Cc: linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
>Subject: Re: [PATCH v2 03/13] Attach/detach SoftiWarp to/from network
>and RDMA subsystem
>
>On Fri, Oct 06, 2017 at 08:28:43AM -0400, Bernard Metzler wrote:
>> Signed-off-by: Bernard Metzler <bmt-OA+xvbQnYDHMbYB6QlFGEg@public.gmane.org>
>> ---
>>  drivers/infiniband/sw/siw/siw_main.c | 752
>+++++++++++++++++++++++++++++++++++
>>  1 file changed, 752 insertions(+)
>>  create mode 100644 drivers/infiniband/sw/siw/siw_main.c
>>
>> diff --git a/drivers/infiniband/sw/siw/siw_main.c
>b/drivers/infiniband/sw/siw/siw_main.c
>> new file mode 100644
>> index 000000000000..5a054c6becaa
>> --- /dev/null
>> +++ b/drivers/infiniband/sw/siw/siw_main.c
>> @@ -0,0 +1,752 @@
>> +/*
>> + * Software iWARP device driver for Linux
>> + *
>> + * Authors: Bernard Metzler <bmt-OA+xvbQnYDHMbYB6QlFGEg@public.gmane.org>
>> + *
>> + * Copyright (c) 2008-2017, IBM Corporation
>> + *
>> + * 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
>> + * 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.
>> + *
>> + *   - Neither the name of IBM nor the names of its contributors
>may be
>> + *     used to endorse or promote products derived from this
>software without
>> + *     specific prior written permission.
>> + *
>> + * 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.
>> + */
>> +
>> +#include <linux/init.h>
>> +#include <linux/errno.h>
>> +#include <linux/netdevice.h>
>> +#include <linux/inetdevice.h>
>> +#include <net/net_namespace.h>
>> +#include <linux/rtnetlink.h>
>> +#include <linux/if_arp.h>
>> +#include <linux/list.h>
>> +#include <linux/kernel.h>
>> +#include <linux/dma-mapping.h>
>> +
>> +#include <rdma/ib_verbs.h>
>> +#include <rdma/ib_smi.h>
>> +#include <rdma/ib_user_verbs.h>
>> +
>> +#include "siw.h"
>> +#include "siw_obj.h"
>> +#include "siw_cm.h"
>> +#include "siw_verbs.h"
>> +#include <linux/kthread.h>
>> +
>> +
>> +MODULE_AUTHOR("Bernard Metzler");
>> +MODULE_DESCRIPTION("Software iWARP Driver");
>> +MODULE_LICENSE("Dual BSD/GPL");
>> +MODULE_VERSION("0.2");
>
>No module versions please, it is useless.

Okay.

>
>> +
>> +#define SIW_MAX_IF 12
>> +static int if_cnt;
>> +static char *iface_list[SIW_MAX_IF] = {[0 ... (SIW_MAX_IF-1)] =
>'\0'};
>> +module_param_array(iface_list, charp, &if_cnt, 0444);
>> +MODULE_PARM_DESC(iface_list, "Interface list siw attaches to if
>present");
>> +
>> +static bool loopback_enabled = 1;
>> +module_param(loopback_enabled, bool, 0644);
>> +MODULE_PARM_DESC(loopback_enabled, "enable_loopback");
>> +
>> +LIST_HEAD(siw_devlist);
>> +
>> +static int cpu_cnt;
>> +static char *tx_cpu_list[MAX_CPU] = {[0 ... (MAX_CPU-1)] = '\0'};
>> +module_param_array(tx_cpu_list, charp, &cpu_cnt, 0444);
>> +MODULE_PARM_DESC(tx_cpu_list, "List of CPUs siw TX thread shall be
>bound to");
>
>No module parameters please.
OK. Would you have a pointer which sheds some light on that
rule? Thank you!

>
>> +
>> +int default_tx_cpu = -1;
>> +struct task_struct *qp_tx_thread[MAX_CPU];
>> +struct crypto_shash *siw_crypto_shash;
>> +
>> +static ssize_t show_sw_version(struct device *dev,
>> +			       struct device_attribute *attr, char *buf)
>> +{
>> +	struct siw_dev *sdev = container_of(dev, struct siw_dev,
>ofa_dev.dev);
>
>Please remove "ofa_*" from this code, upstream has nothing to do with
>OFA.
OK, sure.
That came from the fact it felt wired to write an iWarp driver
and use ib_*. Shall we stick to history and name those things ib
even if we have now 4 transports, or can we come up with something
more generic? ofa obviously is not a good idea.

>
>> +
>> +	return sprintf(buf, "%x\n", sdev->attrs.version);
>> +}
>> +
>> +static DEVICE_ATTR(sw_version, 0444, show_sw_version, NULL);
>
>Why do you need? Does "rdma dev" work for you?

siw over time went through several versions with different
user interfaces (I added memory mapping to SQ/RQ/CQ late,
changed the WQE structure, etc. I wanted to make sure the
kernel module talks to the right user library.
>
>> +
>> +static struct device_attribute *siw_dev_attributes[] = {
>> +	&dev_attr_sw_version
>> +};
>> +
>> +static void siw_device_release(struct device *dev)
>> +{
>> +	pr_info("%s device released\n", dev_name(dev));
>> +}
>> +
>> +static struct device siw_generic_dma_device = {
>> +	.dma_ops		= &siw_dma_generic_ops,
>> +	.init_name		= "software-rdma-v2",
>> +	.release		= siw_device_release
>> +};
>> +
>> +static struct bus_type siw_bus = {
>> +	.name = "siw",
>> +};
>> +
>> +static int siw_modify_port(struct ib_device *ofa_dev, u8 port, int
>mask,
>> +			   struct ib_port_modify *props)
>> +{
>> +	return -EOPNOTSUPP;
>> +}
>
>The proper error code is ENOSYS and if the function is not
>implemented,
>it shouldn't be set.

I think checkpatch didnt like ENOSYS. I will see
and fix accordingly.
>
>> +
>> +
>> +static void siw_device_register(struct siw_dev *sdev)
>> +{
>> +	struct ib_device *ofa_dev = &sdev->ofa_dev;
>
>It is Linux kernel code and not OFED.

Got it.
>
>> +	int rv, i;
>> +	static int dev_id = 1;
>> +
>> +	rv = ib_register_device(ofa_dev, NULL);
>> +	if (rv) {
>> +		dprint(DBG_DM|DBG_ON, " %s: ib register error: rv=%d\n",
>> +			ofa_dev->name, rv);
>> +		return;
>> +	}
>> +
>> +	for (i = 0; i < ARRAY_SIZE(siw_dev_attributes); ++i) {
>> +		rv = device_create_file(&ofa_dev->dev, siw_dev_attributes[i]);
>> +		if (rv) {
>> +			dprint(DBG_DM|DBG_ON, " %s: create file error: rv=%d\n",
>> +				ofa_dev->name, rv);
>> +			ib_unregister_device(ofa_dev);
>> +			return;
>> +		}
>> +	}
>> +	siw_debugfs_add_device(sdev);
>> +
>> +	sdev->attrs.vendor_part_id = dev_id++;
>> +
>> +	dprint(DBG_DM, ": '%s' at '%s',
>HWaddr=%02x.%02x.%02x.%02x.%02x.%02x\n",
>> +		ofa_dev->name, sdev->netdev->name,
>> +		*(u8 *)sdev->netdev->dev_addr,
>> +		*((u8 *)sdev->netdev->dev_addr + 1),
>> +		*((u8 *)sdev->netdev->dev_addr + 2),
>> +		*((u8 *)sdev->netdev->dev_addr + 3),
>> +		*((u8 *)sdev->netdev->dev_addr + 4),
>> +		*((u8 *)sdev->netdev->dev_addr + 5));
>> +
>> +	sdev->is_registered = 1;
>> +}
>> +
>> +static void siw_device_deregister(struct siw_dev *sdev)
>> +{
>> +	int i;
>> +
>> +	siw_debugfs_del_device(sdev);
>> +
>> +	if (sdev->is_registered) {
>> +
>> +		dprint(DBG_DM, ": deregister %s at %s\n", sdev->ofa_dev.name,
>> +			sdev->netdev->name);
>> +
>> +		for (i = 0; i < ARRAY_SIZE(siw_dev_attributes); ++i)
>> +			device_remove_file(&sdev->ofa_dev.dev,
>> +					   siw_dev_attributes[i]);
>> +
>> +		ib_unregister_device(&sdev->ofa_dev);
>> +	}
>> +	if (atomic_read(&sdev->num_ctx) || atomic_read(&sdev->num_srq) ||
>> +	    atomic_read(&sdev->num_mem) || atomic_read(&sdev->num_cep) ||
>> +	    atomic_read(&sdev->num_qp) || atomic_read(&sdev->num_cq) ||
>> +	    atomic_read(&sdev->num_pd)) {
>> +		pr_warn("SIW at %s: orphaned resources!\n", sdev->netdev->name);
>> +		pr_warn("CTX %d, SRQ %d, QP %d, CQ %d, MEM %d, CEP %d, PD %d\n",
>> +			atomic_read(&sdev->num_ctx),
>> +			atomic_read(&sdev->num_srq),
>> +			atomic_read(&sdev->num_qp),
>> +			atomic_read(&sdev->num_cq),
>> +			atomic_read(&sdev->num_mem),
>> +			atomic_read(&sdev->num_cep),
>> +			atomic_read(&sdev->num_pd));
>> +	}
>> +	i = 0;
>> +
>> +	while (!list_empty(&sdev->cep_list)) {
>> +		struct siw_cep *cep = list_entry(sdev->cep_list.next,
>> +						 struct siw_cep, devq);
>> +		list_del(&cep->devq);
>> +		dprint(DBG_ON, ": Free CEP (0x%p), state: %d\n",
>> +			cep, cep->state);
>> +		kfree(cep);
>> +		i++;
>> +	}
>> +	if (i)
>> +		pr_warn("%s: free'd %d CEPs\n", __func__, i);
>> +
>> +	sdev->is_registered = 0;
>> +}
>> +
>> +static void siw_device_destroy(struct siw_dev *sdev)
>> +{
>> +	dprint(DBG_DM, ": destroy siw device at %s\n",
>sdev->netdev->name);
>> +
>> +	siw_idr_release(sdev);
>> +	kfree(sdev->ofa_dev.iwcm);
>> +	dev_put(sdev->netdev);
>> +	ib_dealloc_device(&sdev->ofa_dev);
>> +}
>> +
>> +
>> +static int siw_match_iflist(struct net_device *dev)
>> +{
>> +	int i;
>> +
>> +	if (if_cnt == 0)
>
>No need to be explicit with "== 0".

OK

>
>> +		return 1;
>> +
>> +	if_cnt = min_t(int, SIW_MAX_IF, if_cnt);
>> +
>> +	for (i = 0; i < if_cnt; i++)
>> +		if (!strcmp(iface_list[i], dev->name))
>> +			return 1;
>> +	return 0;
>> +}
>> +
>> +static struct siw_dev *siw_dev_from_netdev(struct net_device *dev)
>> +{
>> +	if (!list_empty(&siw_devlist)) {
>> +		struct list_head *pos;
>> +
>> +		list_for_each(pos, &siw_devlist) {
>> +			struct siw_dev *sdev =
>> +				list_entry(pos, struct siw_dev, list);
>> +			if (sdev->netdev == dev)
>> +				return sdev;
>> +		}
>> +	}
>> +	return NULL;
>> +}
>> +
>> +static int siw_tx_qualified(int cpu)
>> +{
>> +	int i;
>> +
>> +	if (cpu_cnt == 0)
>> +		return 1;
>> +
>> +	for (i = 0; i < cpu_cnt; i++) {
>> +		int new_cpu;
>> +
>> +		if (kstrtoint(tx_cpu_list[i], 0, &new_cpu))
>> +			continue;
>> +		if (cpu == new_cpu)
>> +			return 1;
>> +	}
>> +	return 0;
>> +}
>> +
>> +static int siw_create_tx_threads(int max_threads, int
>check_qualified)
>> +{
>> +	int cpu, rv, assigned = 0;
>> +
>> +	if (max_threads < 0 || max_threads > MAX_CPU)
>> +		return 0;
>> +
>> +	for_each_online_cpu(cpu) {
>> +		if (siw_tx_qualified(cpu)) {
>> +			qp_tx_thread[cpu] =
>> +				kthread_create(siw_run_sq,
>> +					(unsigned long *)(long)cpu,
>> +					"qp_tx_thread/%d", cpu);
>
>You should have very good reasons to create kernel threads and
>especially for each online CPU.
>

Yes. As I wrote in my cover letter, I am not sure the current TX code is
optimal. I started with work queues and found those to introduce
lots of delay. I have to rethink.

>> +			kthread_bind(qp_tx_thread[cpu], cpu);
>> +			if (IS_ERR(qp_tx_thread)) {
>> +				rv = PTR_ERR(qp_tx_thread);
>> +				qp_tx_thread[cpu] = NULL;
>> +				pr_info("Binding TX thread to CPU %d failed",
>> +					cpu);
>> +				break;
>> +			}
>> +			wake_up_process(qp_tx_thread[cpu]);
>> +			assigned++;
>> +			if (default_tx_cpu < 0)
>> +				default_tx_cpu = cpu;
>> +			if (assigned >= max_threads)
>> +				break;
>> +		}
>> +	}
>> +	return assigned;
>> +}
>> +
>> +static int siw_dev_qualified(struct net_device *netdev)
>> +{
>> +	if (!siw_match_iflist(netdev)) {
>> +		dprint(DBG_DM, ": %s (not selected)\n",
>> +			netdev->name);
>> +		return 0;
>> +	}
>> +	/*
>> +	 * Additional hardware support can be added here
>> +	 * (e.g. ARPHRD_FDDI, ARPHRD_ATM, ...) - see
>> +	 * <linux/if_arp.h> for type identifiers.
>> +	 */
>> +	if (netdev->type == ARPHRD_ETHER ||
>> +	    netdev->type == ARPHRD_IEEE802 ||
>> +	    netdev->type == ARPHRD_INFINIBAND ||
>> +	    (netdev->type == ARPHRD_LOOPBACK && loopback_enabled))
>> +		return 1;
>> +
>> +	return 0;
>> +}
>> +
>> +static void siw_verbs_sq_flush(struct ib_qp *ofa_qp)
>> +{
>> +	struct siw_qp *qp = siw_qp_ofa2siw(ofa_qp);
>> +
>> +	down_write(&qp->state_lock);
>> +	siw_sq_flush(qp);
>> +	up_write(&qp->state_lock);
>> +}
>> +
>> +static void siw_verbs_rq_flush(struct ib_qp *ofa_qp)
>> +{
>> +	struct siw_qp *qp = siw_qp_ofa2siw(ofa_qp);
>> +
>> +	down_write(&qp->state_lock);
>> +	siw_rq_flush(qp);
>> +	up_write(&qp->state_lock);
>> +}
>> +
>> +static struct ib_ah *siw_create_ah(struct ib_pd *pd, struct
>rdma_ah_attr *attr,
>> +				   struct ib_udata *udata)
>> +{
>> +	return ERR_PTR(-EOPNOTSUPP);
>> +}
>> +
>> +static int siw_destroy_ah(struct ib_ah *ah)
>> +{
>> +	return -EOPNOTSUPP;
>> +}
>> +
>
>ENOSYS for both.
>
>> +
>> +static struct siw_dev *siw_device_create(struct net_device
>*netdev)
>> +{
>> +	struct siw_dev *sdev = (struct siw_dev
>*)ib_alloc_device(sizeof(*sdev));
>> +	struct ib_device *ofa_dev;
>> +
>> +	if (!sdev)
>> +		goto out;
>> +
>> +	ofa_dev = &sdev->ofa_dev;
>> +
>> +	ofa_dev->iwcm = kmalloc(sizeof(struct iw_cm_verbs), GFP_KERNEL);
>> +	if (!ofa_dev->iwcm) {
>> +		ib_dealloc_device(ofa_dev);
>> +		sdev = NULL;
>> +		goto out;
>> +	}
>> +
>> +	sdev->netdev = netdev;
>> +	list_add_tail(&sdev->list, &siw_devlist);
>> +
>> +	strcpy(ofa_dev->name, SIW_IBDEV_PREFIX);
>> +	strlcpy(ofa_dev->name + strlen(SIW_IBDEV_PREFIX), netdev->name,
>> +		IB_DEVICE_NAME_MAX - strlen(SIW_IBDEV_PREFIX));
>> +
>> +	memset(&ofa_dev->node_guid, 0, sizeof(ofa_dev->node_guid));
>> +	if (netdev->type != ARPHRD_LOOPBACK)
>> +		memcpy(&ofa_dev->node_guid, netdev->dev_addr, 6);
>> +	else {
>> +		/*
>> +		 * The loopback device does not have a HW address,
>> +		 * but connection mangagement lib expects gid != 0
>> +		 */
>> +		size_t gidlen = min_t(size_t, strlen(ofa_dev->name), 6);
>> +
>> +		memcpy(&ofa_dev->node_guid, ofa_dev->name, gidlen);
>> +	}
>> +	ofa_dev->owner = THIS_MODULE;
>> +
>> +	ofa_dev->uverbs_cmd_mask =
>> +	    (1ull << IB_USER_VERBS_CMD_GET_CONTEXT) |
>> +	    (1ull << IB_USER_VERBS_CMD_QUERY_DEVICE) |
>> +	    (1ull << IB_USER_VERBS_CMD_QUERY_PORT) |
>> +	    (1ull << IB_USER_VERBS_CMD_ALLOC_PD) |
>> +	    (1ull << IB_USER_VERBS_CMD_DEALLOC_PD) |
>> +	    (1ull << IB_USER_VERBS_CMD_REG_MR) |
>> +	    (1ull << IB_USER_VERBS_CMD_DEREG_MR) |
>> +	    (1ull << IB_USER_VERBS_CMD_CREATE_COMP_CHANNEL) |
>> +	    (1ull << IB_USER_VERBS_CMD_CREATE_CQ) |
>> +	    (1ull << IB_USER_VERBS_CMD_POLL_CQ) |
>> +	    (1ull << IB_USER_VERBS_CMD_REQ_NOTIFY_CQ) |
>> +	    (1ull << IB_USER_VERBS_CMD_DESTROY_CQ) |
>> +	    (1ull << IB_USER_VERBS_CMD_CREATE_QP) |
>> +	    (1ull << IB_USER_VERBS_CMD_QUERY_QP) |
>> +	    (1ull << IB_USER_VERBS_CMD_MODIFY_QP) |
>> +	    (1ull << IB_USER_VERBS_CMD_DESTROY_QP) |
>> +	    (1ull << IB_USER_VERBS_CMD_POST_SEND) |
>> +	    (1ull << IB_USER_VERBS_CMD_POST_RECV) |
>> +	    (1ull << IB_USER_VERBS_CMD_CREATE_SRQ) |
>> +	    (1ull << IB_USER_VERBS_CMD_MODIFY_SRQ) |
>> +	    (1ull << IB_USER_VERBS_CMD_QUERY_SRQ) |
>> +	    (1ull << IB_USER_VERBS_CMD_DESTROY_SRQ) |
>> +	    (1ull << IB_USER_VERBS_CMD_REG_MR) |
>> +	    (1ull << IB_USER_VERBS_CMD_DEREG_MR) |
>> +	    (1ull << IB_USER_VERBS_CMD_POST_SRQ_RECV);
>> +
>> +	ofa_dev->node_type = RDMA_NODE_RNIC;
>> +	memcpy(ofa_dev->node_desc, SIW_NODE_DESC_COMMON,
>> +	       sizeof(SIW_NODE_DESC_COMMON));
>> +
>> +	/*
>> +	 * Current model (one-to-one device association):
>> +	 * One Softiwarp device per net_device or, equivalently,
>> +	 * per physical port.
>> +	 */
>> +	ofa_dev->phys_port_cnt = 1;
>> +
>> +	ofa_dev->num_comp_vectors = num_possible_cpus();
>> +	ofa_dev->dev.parent = &siw_generic_dma_device;
>> +	ofa_dev->query_device = siw_query_device;
>> +	ofa_dev->query_port = siw_query_port;
>> +	ofa_dev->get_port_immutable = siw_get_port_immutable;
>> +	ofa_dev->query_qp = siw_query_qp;
>> +	ofa_dev->modify_port = siw_modify_port;
>> +	ofa_dev->query_pkey = siw_query_pkey;
>> +	ofa_dev->query_gid = siw_query_gid;
>> +	ofa_dev->alloc_ucontext = siw_alloc_ucontext;
>> +	ofa_dev->dealloc_ucontext = siw_dealloc_ucontext;
>> +	ofa_dev->mmap = siw_mmap;
>> +	ofa_dev->alloc_pd = siw_alloc_pd;
>> +	ofa_dev->dealloc_pd = siw_dealloc_pd;
>> +	ofa_dev->create_ah = siw_create_ah;
>> +	ofa_dev->destroy_ah = siw_destroy_ah;
>> +	ofa_dev->create_qp = siw_create_qp;
>> +	ofa_dev->modify_qp = siw_verbs_modify_qp;
>> +	ofa_dev->destroy_qp = siw_destroy_qp;
>> +	ofa_dev->create_cq = siw_create_cq;
>> +	ofa_dev->destroy_cq = siw_destroy_cq;
>> +	ofa_dev->resize_cq = NULL;
>
>No need to set NULL.

Yes, thanks. 
>
>> +	ofa_dev->poll_cq = siw_poll_cq;
>> +	ofa_dev->get_dma_mr = siw_get_dma_mr;
>> +	ofa_dev->reg_user_mr = siw_reg_user_mr;
>> +	ofa_dev->dereg_mr = siw_dereg_mr;
>> +	ofa_dev->alloc_mr = siw_alloc_mr;
>> +	ofa_dev->map_mr_sg = siw_map_mr_sg;
>> +	ofa_dev->dealloc_mw = NULL;
>> +
>> +	ofa_dev->create_srq = siw_create_srq;
>> +	ofa_dev->modify_srq = siw_modify_srq;
>> +	ofa_dev->query_srq = siw_query_srq;
>> +	ofa_dev->destroy_srq = siw_destroy_srq;
>> +	ofa_dev->post_srq_recv = siw_post_srq_recv;
>> +
>> +	ofa_dev->attach_mcast = NULL;
>> +	ofa_dev->detach_mcast = NULL;
>> +	ofa_dev->process_mad = siw_no_mad;
>> +
>> +	ofa_dev->req_notify_cq = siw_req_notify_cq;
>> +	ofa_dev->post_send = siw_post_send;
>> +	ofa_dev->post_recv = siw_post_receive;
>> +
>> +	ofa_dev->drain_sq = siw_verbs_sq_flush;
>> +	ofa_dev->drain_rq = siw_verbs_rq_flush;
>> +
>> +	ofa_dev->dev.dma_ops = &dma_virt_ops;
>> +
>> +	ofa_dev->iwcm->connect = siw_connect;
>> +	ofa_dev->iwcm->accept = siw_accept;
>> +	ofa_dev->iwcm->reject = siw_reject;
>> +	ofa_dev->iwcm->create_listen = siw_create_listen;
>> +	ofa_dev->iwcm->destroy_listen = siw_destroy_listen;
>> +	ofa_dev->iwcm->add_ref = siw_qp_get_ref;
>> +	ofa_dev->iwcm->rem_ref = siw_qp_put_ref;
>> +	ofa_dev->iwcm->get_qp = siw_get_ofaqp;
>> +
>> +	sdev->attrs.version = VERSION_ID_SOFTIWARP;
>> +	sdev->attrs.vendor_id = SIW_VENDOR_ID;
>> +	sdev->attrs.vendor_part_id = SIW_VENDORT_PART_ID;
>> +	sdev->attrs.sw_version = VERSION_ID_SOFTIWARP;
>> +	sdev->attrs.max_qp = SIW_MAX_QP;
>> +	sdev->attrs.max_qp_wr = SIW_MAX_QP_WR;
>> +	sdev->attrs.max_ord = SIW_MAX_ORD_QP;
>> +	sdev->attrs.max_ird = SIW_MAX_IRD_QP;
>> +	sdev->attrs.cap_flags = IB_DEVICE_MEM_MGT_EXTENSIONS;
>> +	sdev->attrs.max_sge = SIW_MAX_SGE;
>> +	sdev->attrs.max_sge_rd = SIW_MAX_SGE_RD;
>> +	sdev->attrs.max_cq = SIW_MAX_CQ;
>> +	sdev->attrs.max_cqe = SIW_MAX_CQE;
>> +	sdev->attrs.max_mr = SIW_MAX_MR;
>> +	sdev->attrs.max_mr_size = rlimit(RLIMIT_MEMLOCK);
>> +	sdev->attrs.max_pd = SIW_MAX_PD;
>> +	sdev->attrs.max_mw = SIW_MAX_MW;
>> +	sdev->attrs.max_fmr = SIW_MAX_FMR;
>> +	sdev->attrs.max_srq = SIW_MAX_SRQ;
>> +	sdev->attrs.max_srq_wr = SIW_MAX_SRQ_WR;
>> +	sdev->attrs.max_srq_sge = SIW_MAX_SGE;
>> +
>> +	siw_idr_init(sdev);
>> +	INIT_LIST_HEAD(&sdev->cep_list);
>> +	INIT_LIST_HEAD(&sdev->qp_list);
>> +
>> +	atomic_set(&sdev->num_ctx, 0);
>> +	atomic_set(&sdev->num_srq, 0);
>> +	atomic_set(&sdev->num_qp, 0);
>> +	atomic_set(&sdev->num_cq, 0);
>> +	atomic_set(&sdev->num_mem, 0);
>> +	atomic_set(&sdev->num_pd, 0);
>> +	atomic_set(&sdev->num_cep, 0);
>> +
>> +	sdev->is_registered = 0;
>> +out:
>> +	if (sdev)
>> +		dev_hold(netdev);
>> +
>> +	return sdev;
>> +}
>> +
>> +
>> +
>> +static int siw_netdev_event(struct notifier_block *nb, unsigned
>long event,
>> +			    void *arg)
>> +{
>> +	struct net_device	*netdev = netdev_notifier_info_to_dev(arg);
>> +	struct in_device	*in_dev;
>> +	struct siw_dev		*sdev;
>> +
>> +	dprint(DBG_DM, " (dev=%s): Event %lu\n", netdev->name, event);
>> +
>> +	if (dev_net(netdev) != &init_net)
>> +		goto done;
>> +
>> +	sdev = siw_dev_from_netdev(netdev);
>> +
>> +	switch (event) {
>> +
>> +	case NETDEV_UP:
>> +		if (!sdev)
>> +			break;
>> +
>> +		if (sdev->is_registered) {
>> +			sdev->state = IB_PORT_ACTIVE;
>> +			siw_port_event(sdev, 1, IB_EVENT_PORT_ACTIVE);
>> +			break;
>> +		}
>> +
>> +		in_dev = in_dev_get(netdev);
>> +		if (!in_dev) {
>> +			dprint(DBG_DM, ": %s: no in_dev\n", netdev->name);
>> +			sdev->state = IB_PORT_INIT;
>> +			break;
>> +		}
>> +
>> +		if (in_dev->ifa_list) {
>> +			sdev->state = IB_PORT_ACTIVE;
>> +			siw_device_register(sdev);
>> +		} else {
>> +			dprint(DBG_DM, ": %s: no ifa\n", netdev->name);
>> +			sdev->state = IB_PORT_INIT;
>> +		}
>> +		in_dev_put(in_dev);
>> +
>> +		break;
>> +
>> +	case NETDEV_DOWN:
>> +		if (sdev && sdev->is_registered) {
>> +			sdev->state = IB_PORT_DOWN;
>> +			siw_port_event(sdev, 1, IB_EVENT_PORT_ERR);
>> +			break;
>> +		}
>> +		break;
>> +
>> +	case NETDEV_REGISTER:
>> +		if (!sdev) {
>> +			if (!siw_dev_qualified(netdev))
>> +				break;
>> +
>> +			sdev = siw_device_create(netdev);
>> +			if (sdev) {
>> +				sdev->state = IB_PORT_INIT;
>> +				dprint(DBG_DM, ": new siw device for %s\n",
>> +					netdev->name);
>> +			}
>> +		}
>> +		break;
>> +
>> +	case NETDEV_UNREGISTER:
>> +		if (sdev) {
>> +			if (sdev->is_registered)
>> +				siw_device_deregister(sdev);
>> +			list_del(&sdev->list);
>> +			siw_device_destroy(sdev);
>> +		}
>> +		break;
>> +
>> +	case NETDEV_CHANGEADDR:
>> +		if (sdev->is_registered)
>> +			siw_port_event(sdev, 1, IB_EVENT_LID_CHANGE);
>> +
>> +		break;
>> +	/*
>> +	 * Todo: Below netdev events are currently not handled.
>> +	 */
>> +	case NETDEV_CHANGEMTU:
>> +	case NETDEV_GOING_DOWN:
>> +	case NETDEV_CHANGE:
>> +
>> +		break;
>> +
>> +	default:
>> +		break;
>> +	}
>> +done:
>> +	return NOTIFY_OK;
>> +}
>> +
>> +static struct notifier_block siw_netdev_nb = {
>> +	.notifier_call = siw_netdev_event,
>> +};
>> +
>> +/*
>> + * siw_init_module - Initialize Softiwarp module and register with
>netdev
>> + *                   subsystem to create Softiwarp devices per
>net_device
>> + */
>> +static __init int siw_init_module(void)
>> +{
>> +	int rv;
>> +	int nr_cpu;
>> +
>> +	if (SENDPAGE_THRESH < SIW_MAX_INLINE) {
>> +		pr_info("siw: sendpage threshold too small: %u\n",
>> +			(int)SENDPAGE_THRESH);
>> +		rv = EINVAL;
>> +		goto out;
>> +	}
>> +	/*
>> +	 * The xprtrdma module needs at least some rudimentary bus to set
>> +	 * some devices path MTU.
>> +	 */
>> +	rv = bus_register(&siw_bus);
>
>bus register for the driver? no way.

OK. I will have to rework that part.

>
>> +	if (rv)
>> +		goto out_nobus;
>> +
>> +	siw_generic_dma_device.bus = &siw_bus;
>> +
>> +	rv = device_register(&siw_generic_dma_device);
>> +	if (rv)
>> +		goto out;
>> +
>> +	rv = siw_cm_init();
>> +	if (rv)
>> +		goto out_unregister;
>> +
>> +	if (DPRINT_MASK)
>> +		siw_debug_init();
>> +
>> +	/*
>> +	 * Allocate CRC SHASH object. Fail loading siw only, if CRC is
>> +	 * required by kernel module
>> +	 */
>> +	siw_crypto_shash = crypto_alloc_shash("crc32c", 0, 0);
>> +	if (IS_ERR(siw_crypto_shash)) {
>> +		pr_info("siw: Loading CRC32c failed: %ld\n",
>> +			PTR_ERR(siw_crypto_shash));
>> +		siw_crypto_shash = NULL;
>> +		if (mpa_crc_required == true)
>> +			goto out_unregister;
>> +	}
>> +	rv = register_netdevice_notifier(&siw_netdev_nb);
>> +	if (rv) {
>> +		siw_debugfs_delete();
>> +		goto out_unregister;
>> +	}
>> +	for (nr_cpu = 0; nr_cpu < MAX_CPU; nr_cpu++)
>> +		qp_tx_thread[nr_cpu] = NULL;
>> +
>> +	if (siw_create_tx_threads(MAX_CPU, 1) == 0) {
>> +		pr_info("Try starting default TX thread\n");
>> +		if (siw_create_tx_threads(1, 0) == 0) {
>> +			pr_info("Could not start any TX thread\n");
>> +			goto out_unregister;
>> +		}
>> +	}
>> +	pr_info("SoftiWARP attached\n");
>> +	return 0;
>> +
>> +out_unregister:
>> +	for (nr_cpu = 0; nr_cpu < MAX_CPU; nr_cpu++) {
>> +		if (qp_tx_thread[nr_cpu]) {
>> +			siw_stop_tx_thread(nr_cpu);
>> +			qp_tx_thread[nr_cpu] = NULL;
>> +		}
>> +	}
>> +	device_unregister(&siw_generic_dma_device);
>> +
>> +	if (siw_crypto_shash)
>> +		crypto_free_shash(siw_crypto_shash);
>> +out:
>> +	bus_unregister(&siw_bus);
>> +out_nobus:
>> +	pr_info("SoftIWARP attach failed. Error: %d\n", rv);
>> +	siw_cm_exit();
>> +
>> +	return rv;
>> +}
>> +
>> +
>> +static void __exit siw_exit_module(void)
>> +{
>> +	int nr_cpu;
>> +
>> +	for (nr_cpu = 0; nr_cpu < MAX_CPU; nr_cpu++) {
>> +		if (qp_tx_thread[nr_cpu]) {
>> +			siw_stop_tx_thread(nr_cpu);
>> +			qp_tx_thread[nr_cpu] = NULL;
>> +		}
>> +	}
>> +	unregister_netdevice_notifier(&siw_netdev_nb);
>> +
>> +	siw_cm_exit();
>> +
>> +	while (!list_empty(&siw_devlist)) {
>> +		struct siw_dev  *sdev =
>> +			list_entry(siw_devlist.next, struct siw_dev, list);
>> +		list_del(&sdev->list);
>> +		if (sdev->is_registered)
>> +			siw_device_deregister(sdev);
>> +
>> +		siw_device_destroy(sdev);
>> +	}
>> +	if (siw_crypto_shash)
>> +		crypto_free_shash(siw_crypto_shash);
>> +
>> +	siw_debugfs_delete();
>> +
>> +	device_unregister(&siw_generic_dma_device);
>> +
>> +	bus_unregister(&siw_bus);
>> +
>> +	pr_info("SoftiWARP detached\n");
>> +}
>> +
>> +module_init(siw_init_module);
>> +module_exit(siw_exit_module);
>> --
>> 2.13.6
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe
>linux-rdma" in
>> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
[attachment "signature.asc" removed by Bernard Metzler/Zurich/IBM]

--
To unsubscribe from this list: send the line "unsubscribe linux-rdma" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

  parent reply	other threads:[~2017-10-14  1:28 UTC|newest]

Thread overview: 79+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-10-06 12:28 [PATCH v2 00/13] Request for Comments on SoftiWarp Bernard Metzler
     [not found] ` <20171006122853.16310-1-bmt-OA+xvbQnYDHMbYB6QlFGEg@public.gmane.org>
2017-10-06 12:28   ` [PATCH v2 01/13] iWARP wire packet format definition Bernard Metzler
     [not found]     ` <20171006122853.16310-2-bmt-OA+xvbQnYDHMbYB6QlFGEg@public.gmane.org>
2017-10-06 15:28       ` Bart Van Assche
2017-10-08 12:35       ` Leon Romanovsky
2017-10-12 14:16       ` Dennis Dalessandro
2017-10-19 16:34       ` Steve Wise
2017-10-06 12:28   ` [PATCH v2 02/13] Main SoftiWarp include file Bernard Metzler
     [not found]     ` <20171006122853.16310-3-bmt-OA+xvbQnYDHMbYB6QlFGEg@public.gmane.org>
2017-10-19 16:39       ` Steve Wise
2017-10-06 12:28   ` [PATCH v2 03/13] Attach/detach SoftiWarp to/from network and RDMA subsystem Bernard Metzler
     [not found]     ` <20171006122853.16310-4-bmt-OA+xvbQnYDHMbYB6QlFGEg@public.gmane.org>
2017-10-08 13:03       ` Leon Romanovsky
2017-10-12 14:33       ` Dennis Dalessandro
2017-10-19 16:53       ` Steve Wise
2017-10-23 15:42         ` Jason Gunthorpe
     [not found]     ` <20171008130342.GV25829-U/DQcQFIOTAAJjI8aNfphQ@public.gmane.org>
2017-10-14  1:28       ` Bernard Metzler [this message]
     [not found]         ` <OF406E95F8.33CF80BB-ON002581B9.00073D6F-002581B9.00081F69-8eTO7WVQ4XIsd+ienQ86orlN3bxYEBpz@public.gmane.org>
2017-10-14  6:41           ` Leon Romanovsky
     [not found]             ` <20171014064132.GT2106-U/DQcQFIOTAAJjI8aNfphQ@public.gmane.org>
2017-10-14  8:21               ` Leon Romanovsky
2017-12-22 11:29               ` Bernard Metzler
     [not found]                 ` <OF663C0801.8471532E-ON002581FE.003B73D6-002581FE.003F2369-8eTO7WVQ4XIsd+ienQ86orlN3bxYEBpz@public.gmane.org>
2017-12-25 10:12                   ` Leon Romanovsky
2018-01-02 21:37                   ` Jason Gunthorpe
     [not found]                     ` <20180102213706.GB19027-uk2M96/98Pc@public.gmane.org>
2018-01-03  5:25                       ` Leon Romanovsky
     [not found]                         ` <20180103052529.GI10145-U/DQcQFIOTAAJjI8aNfphQ@public.gmane.org>
2018-01-03 15:52                           ` Jason Gunthorpe
     [not found]                             ` <20180103155225.GA11348-uk2M96/98Pc@public.gmane.org>
2018-01-03 17:31                               ` Leon Romanovsky
     [not found]                                 ` <20180103173105.GX10145-U/DQcQFIOTAAJjI8aNfphQ@public.gmane.org>
2018-01-03 17:36                                   ` Jason Gunthorpe
     [not found]                                 ` <20180103173658.GE11348-uk2M96/98Pc@public.gmane.org>
2018-01-04 15:05                                   ` Bernard Metzler
     [not found]                                     ` <OF156C6886.C5A736C2-ON0025820B.005235C2-0025820B.0052EF8F-8eTO7WVQ4XIsd+ienQ86orlN3bxYEBpz@public.gmane.org>
2018-01-04 18:21                                       ` Jason Gunthorpe
     [not found]                                     ` <20180104182108.GR11348-uk2M96/98Pc@public.gmane.org>
2018-01-09 16:58                                       ` Bernard Metzler
     [not found]                                         ` <OF38355950.8A86F33F-ON00258210.005B3539-00258210.005D4AA4-8eTO7WVQ4XIsd+ienQ86orlN3bxYEBpz@public.gmane.org>
2018-01-09 17:08                                           ` Jason Gunthorpe
2017-11-08 16:46       ` Bernard Metzler
     [not found]         ` <OF14995472.9A0A4CF8-ON002581D2.005950C6-002581D2.005C2475-8eTO7WVQ4XIsd+ienQ86orlN3bxYEBpz@public.gmane.org>
2017-11-09  8:46           ` Leon Romanovsky
     [not found]         ` <20171109084610.GB18825-U/DQcQFIOTAAJjI8aNfphQ@public.gmane.org>
2017-11-09 14:43           ` Bernard Metzler
     [not found]             ` <OFCB0BDB52.EB9864CE-ON002581D3.004282CC-002581D3.0050E7A2-8eTO7WVQ4XIsd+ienQ86orlN3bxYEBpz@public.gmane.org>
2017-11-09 17:47               ` Leon Romanovsky
2017-10-06 12:28   ` [PATCH v2 04/13] SoftiWarp object management Bernard Metzler
     [not found]     ` <20171006122853.16310-5-bmt-OA+xvbQnYDHMbYB6QlFGEg@public.gmane.org>
2017-10-08 12:28       ` Leon Romanovsky
     [not found]         ` <20171008122839.GS25829-U/DQcQFIOTAAJjI8aNfphQ@public.gmane.org>
2017-10-13  1:01           ` Doug Ledford
2017-10-14  1:07           ` Bernard Metzler
     [not found]         ` <a82cc3b1-af27-c1de-afb1-a8edea4baed2-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
2017-10-14  0:34           ` Bernard Metzler
2017-10-06 12:28   ` [PATCH v2 05/13] SoftiWarp application interface Bernard Metzler
     [not found]     ` <20171006122853.16310-6-bmt-OA+xvbQnYDHMbYB6QlFGEg@public.gmane.org>
2017-10-08 13:17       ` Leon Romanovsky
2017-10-09  7:51       ` Yanjun Zhu
     [not found]         ` <108c5ddc-1390-c28e-d97e-68d4d0f49e1c-QHcLZuEGTsvQT0dZR+AlfA@public.gmane.org>
2017-10-09  8:05           ` Yanjun Zhu
2017-10-12 14:42       ` Dennis Dalessandro
2017-10-19 17:22       ` Steve Wise
2017-10-20 13:30       ` Shiraz Saleem
     [not found]     ` <20171020133013.GC11604-GOXS9JX10wfOxmVO0tvppfooFf0ArEBIu+b9c/7xato@public.gmane.org>
2017-10-25 14:17       ` Bernard Metzler
2017-10-06 12:28   ` [PATCH v2 06/13] SoftiWarp connection management Bernard Metzler
     [not found]     ` <20171006122853.16310-7-bmt-OA+xvbQnYDHMbYB6QlFGEg@public.gmane.org>
2017-10-06 14:59       ` Parav Pandit
     [not found]         ` <VI1PR0502MB300889B173AC42BD1ADF6F92D1710-o1MPJYiShExKsLr+rGaxW8DSnupUy6xnnBOFsp37pqbUKgpGm//BTAC/G2K4zDHf@public.gmane.org>
2017-10-06 15:32           ` Bart Van Assche
     [not found]             ` <1507303945.2602.9.camel-Sjgp3cTcYWE@public.gmane.org>
2017-10-06 16:04               ` Parav Pandit
     [not found]             ` <VI1PR0502MB3008D5916D814D77776C395ED1710-o1MPJYiShExKsLr+rGaxW8DSnupUy6xnnBOFsp37pqbUKgpGm//BTAC/G2K4zDHf@public.gmane.org>
2017-10-14  0:56               ` Bernard Metzler
2017-10-12 15:27       ` Dennis Dalessandro
2017-10-19 17:28       ` Steve Wise
2017-10-20 12:49       ` Shiraz Saleem
     [not found]     ` <20171020124944.GA11604-GOXS9JX10wfOxmVO0tvppfooFf0ArEBIu+b9c/7xato@public.gmane.org>
2017-10-25 14:01       ` Bernard Metzler
2017-10-06 12:28   ` [PATCH v2 07/13] SoftiWarp application buffer management Bernard Metzler
     [not found]     ` <20171006122853.16310-8-bmt-OA+xvbQnYDHMbYB6QlFGEg@public.gmane.org>
2017-10-12 17:40       ` Dennis Dalessandro
2017-10-06 12:28   ` [PATCH v2 08/13] SoftiWarp Queue Pair methods Bernard Metzler
     [not found]     ` <20171006122853.16310-9-bmt-OA+xvbQnYDHMbYB6QlFGEg@public.gmane.org>
2017-10-08 13:11       ` Leon Romanovsky
2017-10-09  8:58       ` Yanjun Zhu
2017-10-19 17:40       ` Steve Wise
2017-10-06 12:28   ` [PATCH v2 09/13] SoftiWarp transmit path Bernard Metzler
     [not found]     ` <20171006122853.16310-10-bmt-OA+xvbQnYDHMbYB6QlFGEg@public.gmane.org>
2017-10-08 13:06       ` Leon Romanovsky
2017-10-11 12:54       ` Sagi Grimberg
2017-10-19 17:46       ` Steve Wise
2017-10-06 12:28   ` [PATCH v2 10/13] SoftiWarp receive path Bernard Metzler
2017-10-06 12:28   ` [PATCH v2 11/13] SoftiWarp Completion Queue methods Bernard Metzler
     [not found]     ` <20171006122853.16310-12-bmt-OA+xvbQnYDHMbYB6QlFGEg@public.gmane.org>
2017-10-20 12:58       ` Shiraz Saleem
     [not found]     ` <20171020125836.GB11604-GOXS9JX10wfOxmVO0tvppfooFf0ArEBIu+b9c/7xato@public.gmane.org>
2017-10-25 13:51       ` Bernard Metzler
2017-10-06 12:28   ` [PATCH v2 12/13] SoftiWarp debugging code Bernard Metzler
     [not found]     ` <20171006122853.16310-13-bmt-OA+xvbQnYDHMbYB6QlFGEg@public.gmane.org>
2017-10-08 12:39       ` Leon Romanovsky
     [not found]     ` <20171008123950.GU25829-U/DQcQFIOTAAJjI8aNfphQ@public.gmane.org>
2017-10-14  1:08       ` Bernard Metzler
2017-10-06 12:28   ` [PATCH v2 13/13] Add SoftiWarp to kernel build environment Bernard Metzler
2017-10-08 12:31   ` [PATCH v2 00/13] Request for Comments on SoftiWarp Christoph Hellwig
     [not found]     ` <20171008123128.GA28815-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org>
2017-10-08 12:32       ` Christoph Hellwig
     [not found]     ` <20171008123240.GA31066-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org>
2017-10-12 22:27       ` Bernard Metzler
2017-10-12 18:05   ` Dennis Dalessandro
     [not found]     ` <dd0e915d-2ab7-9912-b000-bcca1acee256-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
2017-10-12 18:35       ` Bart Van Assche
2017-10-20 13:45   ` Shiraz Saleem
     [not found]     ` <20171020134501.GD11604-GOXS9JX10wfOxmVO0tvppfooFf0ArEBIu+b9c/7xato@public.gmane.org>
2017-10-20 16:25       ` Leon Romanovsky
     [not found]     ` <20171020162521.GA2106-U/DQcQFIOTAAJjI8aNfphQ@public.gmane.org>
2017-10-25 15:43       ` Bernard Metzler

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=OF406E95F8.33CF80BB-ON002581B9.00073D6F-002581B9.00081F69@notes.na.collabserv.com \
    --to=bmt-oa+xvbqnydhmbyb6qlfgeg@public.gmane.org \
    --cc=leon-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org \
    --cc=linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.