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