usnic_ib_qp_grp.c revision e3cf00d0a87f025db5855a43a67c67a41fa79fef
1/*
2 * Copyright (c) 2013, Cisco Systems, Inc. All rights reserved.
3 *
4 * This program is free software; you may redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
9 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
10 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
11 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
12 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
13 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
15 * SOFTWARE.
16 *
17 */
18#include <linux/errno.h>
19#include <linux/module.h>
20#include <linux/spinlock.h>
21
22#include "usnic_log.h"
23#include "usnic_vnic.h"
24#include "usnic_fwd.h"
25#include "usnic_uiom.h"
26#include "usnic_ib_qp_grp.h"
27#include "usnic_ib_sysfs.h"
28#include "usnic_transport.h"
29
30const char *usnic_ib_qp_grp_state_to_string(enum ib_qp_state state)
31{
32	switch (state) {
33	case IB_QPS_RESET:
34		return "Rst";
35	case IB_QPS_INIT:
36		return "Init";
37	case IB_QPS_RTR:
38		return "RTR";
39	case IB_QPS_RTS:
40		return "RTS";
41	case IB_QPS_SQD:
42		return "SQD";
43	case IB_QPS_SQE:
44		return "SQE";
45	case IB_QPS_ERR:
46		return "ERR";
47	default:
48		return "UNKOWN STATE";
49
50	}
51}
52
53int usnic_ib_qp_grp_dump_hdr(char *buf, int buf_sz)
54{
55	return scnprintf(buf, buf_sz, "|QPN\t|State\t|PID\t|VF Idx\t|Fil ID");
56}
57
58int usnic_ib_qp_grp_dump_rows(void *obj, char *buf, int buf_sz)
59{
60	struct usnic_ib_qp_grp *qp_grp = obj;
61	struct usnic_fwd_filter_hndl *default_filter_hndl;
62	if (obj) {
63		default_filter_hndl = list_first_entry(&qp_grp->filter_hndls,
64					struct usnic_fwd_filter_hndl, link);
65		return scnprintf(buf, buf_sz, "|%d\t|%s\t|%d\t|%hu\t|%d",
66					qp_grp->ibqp.qp_num,
67					usnic_ib_qp_grp_state_to_string(
68							qp_grp->state),
69					qp_grp->owner_pid,
70					usnic_vnic_get_index(qp_grp->vf->vnic),
71					default_filter_hndl->id);
72	} else {
73		return scnprintf(buf, buf_sz, "|N/A\t|N/A\t|N/A\t|N/A\t|N/A");
74	}
75}
76
77static int add_fwd_filter(struct usnic_ib_qp_grp *qp_grp,
78				struct usnic_fwd_filter *fwd_filter)
79{
80	struct usnic_fwd_filter_hndl *filter_hndl;
81	int status;
82	struct usnic_vnic_res_chunk *chunk;
83	int rq_idx;
84
85	WARN_ON(!spin_is_locked(&qp_grp->lock));
86
87	chunk = usnic_ib_qp_grp_get_chunk(qp_grp, USNIC_VNIC_RES_TYPE_RQ);
88	if (IS_ERR_OR_NULL(chunk) || chunk->cnt < 1) {
89		usnic_err("Failed to get RQ info for qp_grp %u\n",
90				qp_grp->grp_id);
91		return -EFAULT;
92	}
93
94	rq_idx = chunk->res[0]->vnic_idx;
95
96	switch (qp_grp->transport) {
97	case USNIC_TRANSPORT_ROCE_CUSTOM:
98		status = usnic_fwd_add_usnic_filter(qp_grp->ufdev,
99					usnic_vnic_get_index(qp_grp->vf->vnic),
100					rq_idx,
101					fwd_filter,
102					&filter_hndl);
103		break;
104	default:
105		usnic_err("Unable to install filter for qp_grp %u for transport %d",
106				qp_grp->grp_id, qp_grp->transport);
107		status = -EINVAL;
108	}
109
110	if (status)
111		return status;
112
113	list_add_tail(&filter_hndl->link, &qp_grp->filter_hndls);
114	return 0;
115}
116
117static int del_all_filters(struct usnic_ib_qp_grp *qp_grp)
118{
119	int err, status;
120	struct usnic_fwd_filter_hndl *filter_hndl, *tmp;
121
122	WARN_ON(!spin_is_locked(&qp_grp->lock));
123
124	status = 0;
125
126	list_for_each_entry_safe(filter_hndl, tmp,
127					&qp_grp->filter_hndls, link) {
128		list_del(&filter_hndl->link);
129		err = usnic_fwd_del_filter(filter_hndl);
130		if (err) {
131			usnic_err("Failed to delete filter %u of qp_grp %d\n",
132					filter_hndl->id, qp_grp->grp_id);
133		}
134		status |= err;
135	}
136
137	return status;
138}
139
140static int enable_qp_grp(struct usnic_ib_qp_grp *qp_grp)
141{
142
143	int status;
144	int i, vnic_idx;
145	struct usnic_vnic_res_chunk *res_chunk;
146	struct usnic_vnic_res *res;
147
148	WARN_ON(!spin_is_locked(&qp_grp->lock));
149
150	vnic_idx = usnic_vnic_get_index(qp_grp->vf->vnic);
151
152	res_chunk = usnic_ib_qp_grp_get_chunk(qp_grp, USNIC_VNIC_RES_TYPE_RQ);
153	if (IS_ERR_OR_NULL(res_chunk)) {
154		usnic_err("Unable to get %s with err %ld\n",
155			usnic_vnic_res_type_to_str(USNIC_VNIC_RES_TYPE_RQ),
156			PTR_ERR(res_chunk));
157		return res_chunk ? PTR_ERR(res_chunk) : -ENOMEM;
158	}
159
160	for (i = 0; i < res_chunk->cnt; i++) {
161		res = res_chunk->res[i];
162		status = usnic_fwd_enable_rq(qp_grp->ufdev, vnic_idx,
163						res->vnic_idx);
164		if (status) {
165			usnic_err("Failed to enable rq %d of %s:%d\n with err %d\n",
166					res->vnic_idx,
167					netdev_name(qp_grp->ufdev->netdev),
168					vnic_idx, status);
169			goto out_err;
170		}
171	}
172
173	return 0;
174
175out_err:
176	for (i--; i >= 0; i--) {
177		res = res_chunk->res[i];
178		usnic_fwd_disable_rq(qp_grp->ufdev, vnic_idx,
179					res->vnic_idx);
180	}
181
182	return status;
183}
184
185static int disable_qp_grp(struct usnic_ib_qp_grp *qp_grp)
186{
187	int i, vnic_idx;
188	struct usnic_vnic_res_chunk *res_chunk;
189	struct usnic_vnic_res *res;
190	int status = 0;
191
192	WARN_ON(!spin_is_locked(&qp_grp->lock));
193	vnic_idx = usnic_vnic_get_index(qp_grp->vf->vnic);
194
195	res_chunk = usnic_ib_qp_grp_get_chunk(qp_grp, USNIC_VNIC_RES_TYPE_RQ);
196	if (IS_ERR_OR_NULL(res_chunk)) {
197		usnic_err("Unable to get %s with err %ld\n",
198			usnic_vnic_res_type_to_str(USNIC_VNIC_RES_TYPE_RQ),
199			PTR_ERR(res_chunk));
200		return res_chunk ? PTR_ERR(res_chunk) : -ENOMEM;
201	}
202
203	for (i = 0; i < res_chunk->cnt; i++) {
204		res = res_chunk->res[i];
205		status = usnic_fwd_disable_rq(qp_grp->ufdev, vnic_idx,
206						res->vnic_idx);
207		if (status) {
208			usnic_err("Failed to disable rq %d of %s:%d\n with err %d\n",
209					res->vnic_idx,
210					netdev_name(qp_grp->ufdev->netdev),
211					vnic_idx, status);
212		}
213	}
214
215	return status;
216
217}
218
219int usnic_ib_qp_grp_modify(struct usnic_ib_qp_grp *qp_grp,
220				enum ib_qp_state new_state,
221				struct usnic_fwd_filter *fwd_filter)
222{
223	int status = 0;
224	int vnic_idx;
225	struct ib_event ib_event;
226	enum ib_qp_state old_state;
227
228	old_state = qp_grp->state;
229	vnic_idx = usnic_vnic_get_index(qp_grp->vf->vnic);
230
231	spin_lock(&qp_grp->lock);
232	switch (new_state) {
233	case IB_QPS_RESET:
234		switch (old_state) {
235		case IB_QPS_RESET:
236			/* NO-OP */
237			break;
238		case IB_QPS_INIT:
239			status = del_all_filters(qp_grp);
240			break;
241		case IB_QPS_RTR:
242		case IB_QPS_RTS:
243		case IB_QPS_ERR:
244			status = disable_qp_grp(qp_grp);
245			status &= del_all_filters(qp_grp);
246			break;
247		default:
248			status = -EINVAL;
249		}
250		break;
251	case IB_QPS_INIT:
252		switch (old_state) {
253		case IB_QPS_RESET:
254			status = add_fwd_filter(qp_grp, fwd_filter);
255			break;
256		case IB_QPS_INIT:
257			status = add_fwd_filter(qp_grp, fwd_filter);
258			break;
259		case IB_QPS_RTR:
260			status = disable_qp_grp(qp_grp);
261			break;
262		case IB_QPS_RTS:
263			status = disable_qp_grp(qp_grp);
264			break;
265		default:
266			status = -EINVAL;
267		}
268		break;
269	case IB_QPS_RTR:
270		switch (old_state) {
271		case IB_QPS_INIT:
272			status = enable_qp_grp(qp_grp);
273			break;
274		default:
275			status = -EINVAL;
276		}
277		break;
278	case IB_QPS_RTS:
279		switch (old_state) {
280		case IB_QPS_RTR:
281			/* NO-OP FOR NOW */
282			break;
283		default:
284			status = -EINVAL;
285		}
286		break;
287	case IB_QPS_ERR:
288		ib_event.device = &qp_grp->vf->pf->ib_dev;
289		ib_event.element.qp = &qp_grp->ibqp;
290		ib_event.event = IB_EVENT_QP_FATAL;
291
292		switch (old_state) {
293		case IB_QPS_RESET:
294			qp_grp->ibqp.event_handler(&ib_event,
295					qp_grp->ibqp.qp_context);
296			break;
297		case IB_QPS_INIT:
298			status = del_all_filters(qp_grp);
299			qp_grp->ibqp.event_handler(&ib_event,
300					qp_grp->ibqp.qp_context);
301			break;
302		case IB_QPS_RTR:
303		case IB_QPS_RTS:
304			status = disable_qp_grp(qp_grp);
305			status &= del_all_filters(qp_grp);
306			qp_grp->ibqp.event_handler(&ib_event,
307					qp_grp->ibqp.qp_context);
308			break;
309		default:
310			status = -EINVAL;
311		}
312		break;
313	default:
314		status = -EINVAL;
315	}
316	spin_unlock(&qp_grp->lock);
317
318	if (!status) {
319		qp_grp->state = new_state;
320		usnic_info("Transistioned %u from %s to %s",
321		qp_grp->grp_id,
322		usnic_ib_qp_grp_state_to_string(old_state),
323		usnic_ib_qp_grp_state_to_string(new_state));
324	} else {
325		usnic_err("Failed to transistion %u from %s to %s",
326		qp_grp->grp_id,
327		usnic_ib_qp_grp_state_to_string(old_state),
328		usnic_ib_qp_grp_state_to_string(new_state));
329	}
330
331	return status;
332}
333
334static struct usnic_vnic_res_chunk**
335alloc_res_chunk_list(struct usnic_vnic *vnic,
336			struct usnic_vnic_res_spec *res_spec, void *owner_obj)
337{
338	enum usnic_vnic_res_type res_type;
339	struct usnic_vnic_res_chunk **res_chunk_list;
340	int err, i, res_cnt, res_lst_sz;
341
342	for (res_lst_sz = 0;
343		res_spec->resources[res_lst_sz].type != USNIC_VNIC_RES_TYPE_EOL;
344		res_lst_sz++) {
345		/* Do Nothing */
346	}
347
348	res_chunk_list = kzalloc(sizeof(*res_chunk_list)*(res_lst_sz+1),
349					GFP_ATOMIC);
350	if (!res_chunk_list)
351		return ERR_PTR(-ENOMEM);
352
353	for (i = 0; res_spec->resources[i].type != USNIC_VNIC_RES_TYPE_EOL;
354		i++) {
355		res_type = res_spec->resources[i].type;
356		res_cnt = res_spec->resources[i].cnt;
357
358		res_chunk_list[i] = usnic_vnic_get_resources(vnic, res_type,
359					res_cnt, owner_obj);
360		if (IS_ERR_OR_NULL(res_chunk_list[i])) {
361			err = (res_chunk_list[i] ?
362					PTR_ERR(res_chunk_list[i]) : -ENOMEM);
363			usnic_err("Failed to get %s from %s with err %d\n",
364				usnic_vnic_res_type_to_str(res_type),
365				usnic_vnic_pci_name(vnic),
366				err);
367			goto out_free_res;
368		}
369	}
370
371	return res_chunk_list;
372
373out_free_res:
374	for (i--; i > 0; i--)
375		usnic_vnic_put_resources(res_chunk_list[i]);
376	kfree(res_chunk_list);
377	return ERR_PTR(err);
378}
379
380static void free_qp_grp_res(struct usnic_vnic_res_chunk **res_chunk_list)
381{
382	int i;
383	for (i = 0; res_chunk_list[i]; i++)
384		usnic_vnic_put_resources(res_chunk_list[i]);
385	kfree(res_chunk_list);
386}
387
388static int qp_grp_and_vf_bind(struct usnic_ib_vf *vf,
389				struct usnic_ib_pd *pd,
390				struct usnic_ib_qp_grp *qp_grp)
391{
392	int err;
393	struct pci_dev *pdev;
394
395	WARN_ON(!spin_is_locked(&vf->lock));
396
397	pdev = usnic_vnic_get_pdev(vf->vnic);
398	if (vf->qp_grp_ref_cnt == 0) {
399		err = usnic_uiom_attach_dev_to_pd(pd->umem_pd, &pdev->dev);
400		if (err) {
401			usnic_err("Failed to attach %s to domain\n",
402					pci_name(pdev));
403			return err;
404		}
405		vf->pd = pd;
406	}
407	vf->qp_grp_ref_cnt++;
408
409	WARN_ON(vf->pd != pd);
410	qp_grp->vf = vf;
411
412	return 0;
413}
414
415static void qp_grp_and_vf_unbind(struct usnic_ib_qp_grp *qp_grp)
416{
417	struct pci_dev *pdev;
418	struct usnic_ib_pd *pd;
419
420	WARN_ON(!spin_is_locked(&qp_grp->vf->lock));
421
422	pd = qp_grp->vf->pd;
423	pdev = usnic_vnic_get_pdev(qp_grp->vf->vnic);
424	if (--qp_grp->vf->qp_grp_ref_cnt == 0) {
425		qp_grp->vf->pd = NULL;
426		usnic_uiom_detach_dev_from_pd(pd->umem_pd, &pdev->dev);
427	}
428	qp_grp->vf = NULL;
429}
430
431static void log_spec(struct usnic_vnic_res_spec *res_spec)
432{
433	char buf[512];
434	usnic_vnic_spec_dump(buf, sizeof(buf), res_spec);
435	usnic_dbg("%s\n", buf);
436}
437
438struct usnic_ib_qp_grp *
439usnic_ib_qp_grp_create(struct usnic_fwd_dev *ufdev,
440			struct usnic_ib_vf *vf,
441			struct usnic_ib_pd *pd,
442			struct usnic_vnic_res_spec *res_spec,
443			enum usnic_transport_type transport)
444{
445	struct usnic_ib_qp_grp *qp_grp;
446	u16 port_num;
447	int err;
448
449	WARN_ON(!spin_is_locked(&vf->lock));
450
451	err = usnic_vnic_res_spec_satisfied(&min_transport_spec[transport],
452						res_spec);
453	if (err) {
454		usnic_err("Spec does not meet miniumum req for transport %d\n",
455				transport);
456		log_spec(res_spec);
457		return ERR_PTR(err);
458	}
459
460	port_num = usnic_transport_rsrv_port(transport, 0);
461	if (!port_num) {
462		usnic_err("Unable to allocate port for %s\n",
463				netdev_name(ufdev->netdev));
464		return ERR_PTR(-EINVAL);
465	}
466
467	qp_grp = kzalloc(sizeof(*qp_grp), GFP_ATOMIC);
468	if (!qp_grp) {
469		usnic_err("Unable to alloc qp_grp - Out of memory\n");
470		return NULL;
471	}
472
473	qp_grp->res_chunk_list = alloc_res_chunk_list(vf->vnic, res_spec,
474							qp_grp);
475	if (IS_ERR_OR_NULL(qp_grp->res_chunk_list)) {
476		err = qp_grp->res_chunk_list ?
477				PTR_ERR(qp_grp->res_chunk_list) : -ENOMEM;
478		usnic_err("Unable to alloc res for %d with err %d\n",
479				qp_grp->grp_id, err);
480		goto out_free_port;
481	}
482
483	INIT_LIST_HEAD(&qp_grp->filter_hndls);
484	spin_lock_init(&qp_grp->lock);
485	qp_grp->ufdev = ufdev;
486	qp_grp->transport = transport;
487	qp_grp->filters[DFLT_FILTER_IDX].transport = transport;
488	qp_grp->filters[DFLT_FILTER_IDX].port_num = port_num;
489	qp_grp->state = IB_QPS_RESET;
490	qp_grp->owner_pid = current->pid;
491
492	/* qp_num is same as default filter port_num */
493	qp_grp->ibqp.qp_num = qp_grp->filters[DFLT_FILTER_IDX].port_num;
494	qp_grp->grp_id = qp_grp->ibqp.qp_num;
495
496	err = qp_grp_and_vf_bind(vf, pd, qp_grp);
497	if (err)
498		goto out_free_port;
499
500	usnic_ib_sysfs_qpn_add(qp_grp);
501
502	return qp_grp;
503
504out_free_port:
505	kfree(qp_grp);
506	usnic_transport_unrsrv_port(transport, port_num);
507
508	return ERR_PTR(err);
509}
510
511void usnic_ib_qp_grp_destroy(struct usnic_ib_qp_grp *qp_grp)
512{
513	u16 default_port_num;
514	enum usnic_transport_type transport;
515
516	WARN_ON(qp_grp->state != IB_QPS_RESET);
517	WARN_ON(!spin_is_locked(&qp_grp->vf->lock));
518
519	transport = qp_grp->filters[DFLT_FILTER_IDX].transport;
520	default_port_num = qp_grp->filters[DFLT_FILTER_IDX].port_num;
521
522	usnic_ib_sysfs_qpn_remove(qp_grp);
523	qp_grp_and_vf_unbind(qp_grp);
524	free_qp_grp_res(qp_grp->res_chunk_list);
525	kfree(qp_grp);
526	usnic_transport_unrsrv_port(transport, default_port_num);
527}
528
529struct usnic_vnic_res_chunk*
530usnic_ib_qp_grp_get_chunk(struct usnic_ib_qp_grp *qp_grp,
531				enum usnic_vnic_res_type res_type)
532{
533	int i;
534
535	for (i = 0; qp_grp->res_chunk_list[i]; i++) {
536		if (qp_grp->res_chunk_list[i]->type == res_type)
537			return qp_grp->res_chunk_list[i];
538	}
539
540	return ERR_PTR(-EINVAL);
541}
542