| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Huawei HiNIC PCI Express Linux driver |
|---|
| 3 | 4 | * Copyright(c) 2017 Huawei Technologies Co., Ltd |
|---|
| 4 | | - * |
|---|
| 5 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 6 | | - * under the terms and conditions of the GNU General Public License, |
|---|
| 7 | | - * version 2, as published by the Free Software Foundation. |
|---|
| 8 | | - * |
|---|
| 9 | | - * This program is distributed in the hope it will be useful, but WITHOUT |
|---|
| 10 | | - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|---|
| 11 | | - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|---|
| 12 | | - * for more details. |
|---|
| 13 | | - * |
|---|
| 14 | 5 | */ |
|---|
| 15 | 6 | |
|---|
| 16 | 7 | #include <linux/kernel.h> |
|---|
| .. | .. |
|---|
| 24 | 15 | #include <linux/io.h> |
|---|
| 25 | 16 | #include <linux/err.h> |
|---|
| 26 | 17 | |
|---|
| 18 | +#include "hinic_hw_dev.h" |
|---|
| 27 | 19 | #include "hinic_hw_if.h" |
|---|
| 28 | 20 | #include "hinic_hw_eqs.h" |
|---|
| 29 | 21 | #include "hinic_hw_wqe.h" |
|---|
| .. | .. |
|---|
| 43 | 35 | #define DB_IDX(db, db_base) \ |
|---|
| 44 | 36 | (((unsigned long)(db) - (unsigned long)(db_base)) / HINIC_DB_PAGE_SIZE) |
|---|
| 45 | 37 | |
|---|
| 38 | +#define HINIC_PAGE_SIZE_HW(pg_size) ((u8)ilog2((u32)((pg_size) >> 12))) |
|---|
| 39 | + |
|---|
| 46 | 40 | enum io_cmd { |
|---|
| 47 | 41 | IO_CMD_MODIFY_QUEUE_CTXT = 0, |
|---|
| 42 | + IO_CMD_CLEAN_QUEUE_CTXT, |
|---|
| 48 | 43 | }; |
|---|
| 49 | 44 | |
|---|
| 50 | 45 | static void init_db_area_idx(struct hinic_free_db_area *free_db_area) |
|---|
| .. | .. |
|---|
| 210 | 205 | write_rq_ctxts(func_to_io, base_qpn, num_qps)); |
|---|
| 211 | 206 | } |
|---|
| 212 | 207 | |
|---|
| 208 | +static int hinic_clean_queue_offload_ctxt(struct hinic_func_to_io *func_to_io, |
|---|
| 209 | + enum hinic_qp_ctxt_type ctxt_type) |
|---|
| 210 | +{ |
|---|
| 211 | + struct hinic_hwif *hwif = func_to_io->hwif; |
|---|
| 212 | + struct hinic_clean_queue_ctxt *ctxt_block; |
|---|
| 213 | + struct pci_dev *pdev = hwif->pdev; |
|---|
| 214 | + struct hinic_cmdq_buf cmdq_buf; |
|---|
| 215 | + u64 out_param = 0; |
|---|
| 216 | + int err; |
|---|
| 217 | + |
|---|
| 218 | + err = hinic_alloc_cmdq_buf(&func_to_io->cmdqs, &cmdq_buf); |
|---|
| 219 | + if (err) { |
|---|
| 220 | + dev_err(&pdev->dev, "Failed to allocate cmdq buf\n"); |
|---|
| 221 | + return err; |
|---|
| 222 | + } |
|---|
| 223 | + |
|---|
| 224 | + ctxt_block = cmdq_buf.buf; |
|---|
| 225 | + ctxt_block->cmdq_hdr.num_queues = func_to_io->max_qps; |
|---|
| 226 | + ctxt_block->cmdq_hdr.queue_type = ctxt_type; |
|---|
| 227 | + ctxt_block->cmdq_hdr.addr_offset = 0; |
|---|
| 228 | + |
|---|
| 229 | + /* TSO/LRO ctxt size: 0x0:0B; 0x1:160B; 0x2:200B; 0x3:240B */ |
|---|
| 230 | + ctxt_block->ctxt_size = 0x3; |
|---|
| 231 | + |
|---|
| 232 | + hinic_cpu_to_be32(ctxt_block, sizeof(*ctxt_block)); |
|---|
| 233 | + |
|---|
| 234 | + cmdq_buf.size = sizeof(*ctxt_block); |
|---|
| 235 | + |
|---|
| 236 | + err = hinic_cmdq_direct_resp(&func_to_io->cmdqs, HINIC_MOD_L2NIC, |
|---|
| 237 | + IO_CMD_CLEAN_QUEUE_CTXT, |
|---|
| 238 | + &cmdq_buf, &out_param); |
|---|
| 239 | + |
|---|
| 240 | + if (err || out_param) { |
|---|
| 241 | + dev_err(&pdev->dev, "Failed to clean offload ctxts, err: %d, out_param: 0x%llx\n", |
|---|
| 242 | + err, out_param); |
|---|
| 243 | + |
|---|
| 244 | + err = -EFAULT; |
|---|
| 245 | + } |
|---|
| 246 | + |
|---|
| 247 | + hinic_free_cmdq_buf(&func_to_io->cmdqs, &cmdq_buf); |
|---|
| 248 | + |
|---|
| 249 | + return err; |
|---|
| 250 | +} |
|---|
| 251 | + |
|---|
| 252 | +static int hinic_clean_qp_offload_ctxt(struct hinic_func_to_io *func_to_io) |
|---|
| 253 | +{ |
|---|
| 254 | + /* clean LRO/TSO context space */ |
|---|
| 255 | + return (hinic_clean_queue_offload_ctxt(func_to_io, |
|---|
| 256 | + HINIC_QP_CTXT_TYPE_SQ) || |
|---|
| 257 | + hinic_clean_queue_offload_ctxt(func_to_io, |
|---|
| 258 | + HINIC_QP_CTXT_TYPE_RQ)); |
|---|
| 259 | +} |
|---|
| 260 | + |
|---|
| 213 | 261 | /** |
|---|
| 214 | 262 | * init_qp - Initialize a Queue Pair |
|---|
| 215 | 263 | * @func_to_io: func to io channel that holds the IO components |
|---|
| .. | .. |
|---|
| 234 | 282 | |
|---|
| 235 | 283 | err = hinic_wq_allocate(&func_to_io->wqs, &func_to_io->sq_wq[q_id], |
|---|
| 236 | 284 | HINIC_SQ_WQEBB_SIZE, HINIC_SQ_PAGE_SIZE, |
|---|
| 237 | | - HINIC_SQ_DEPTH, HINIC_SQ_WQE_MAX_SIZE); |
|---|
| 285 | + func_to_io->sq_depth, HINIC_SQ_WQE_MAX_SIZE); |
|---|
| 238 | 286 | if (err) { |
|---|
| 239 | 287 | dev_err(&pdev->dev, "Failed to allocate WQ for SQ\n"); |
|---|
| 240 | 288 | return err; |
|---|
| .. | .. |
|---|
| 242 | 290 | |
|---|
| 243 | 291 | err = hinic_wq_allocate(&func_to_io->wqs, &func_to_io->rq_wq[q_id], |
|---|
| 244 | 292 | HINIC_RQ_WQEBB_SIZE, HINIC_RQ_PAGE_SIZE, |
|---|
| 245 | | - HINIC_RQ_DEPTH, HINIC_RQ_WQE_SIZE); |
|---|
| 293 | + func_to_io->rq_depth, HINIC_RQ_WQE_SIZE); |
|---|
| 246 | 294 | if (err) { |
|---|
| 247 | 295 | dev_err(&pdev->dev, "Failed to allocate WQ for RQ\n"); |
|---|
| 248 | 296 | goto err_rq_alloc; |
|---|
| .. | .. |
|---|
| 257 | 305 | |
|---|
| 258 | 306 | func_to_io->sq_db[q_id] = db_base; |
|---|
| 259 | 307 | |
|---|
| 308 | + qp->sq.qid = q_id; |
|---|
| 260 | 309 | err = hinic_init_sq(&qp->sq, hwif, &func_to_io->sq_wq[q_id], |
|---|
| 261 | 310 | sq_msix_entry, |
|---|
| 262 | 311 | CI_ADDR(func_to_io->ci_addr_base, q_id), |
|---|
| .. | .. |
|---|
| 266 | 315 | goto err_sq_init; |
|---|
| 267 | 316 | } |
|---|
| 268 | 317 | |
|---|
| 318 | + qp->rq.qid = q_id; |
|---|
| 269 | 319 | err = hinic_init_rq(&qp->rq, hwif, &func_to_io->rq_wq[q_id], |
|---|
| 270 | 320 | rq_msix_entry); |
|---|
| 271 | 321 | if (err) { |
|---|
| .. | .. |
|---|
| 313 | 363 | * @func_to_io: func to io channel that holds the IO components |
|---|
| 314 | 364 | * @base_qpn: base qp number |
|---|
| 315 | 365 | * @num_qps: number queue pairs to create |
|---|
| 316 | | - * @sq_msix_entry: msix entries for sq |
|---|
| 317 | | - * @rq_msix_entry: msix entries for rq |
|---|
| 366 | + * @sq_msix_entries: msix entries for sq |
|---|
| 367 | + * @rq_msix_entries: msix entries for rq |
|---|
| 318 | 368 | * |
|---|
| 319 | 369 | * Return 0 - Success, negative - Failure |
|---|
| 320 | 370 | **/ |
|---|
| .. | .. |
|---|
| 355 | 405 | goto err_sq_db; |
|---|
| 356 | 406 | } |
|---|
| 357 | 407 | |
|---|
| 358 | | - ci_addr_base = dma_zalloc_coherent(&pdev->dev, CI_TABLE_SIZE(num_qps), |
|---|
| 359 | | - &func_to_io->ci_dma_base, |
|---|
| 360 | | - GFP_KERNEL); |
|---|
| 408 | + ci_addr_base = dma_alloc_coherent(&pdev->dev, CI_TABLE_SIZE(num_qps), |
|---|
| 409 | + &func_to_io->ci_dma_base, |
|---|
| 410 | + GFP_KERNEL); |
|---|
| 361 | 411 | if (!ci_addr_base) { |
|---|
| 362 | 412 | dev_err(&pdev->dev, "Failed to allocate CI area\n"); |
|---|
| 363 | 413 | err = -ENOMEM; |
|---|
| .. | .. |
|---|
| 378 | 428 | err = write_qp_ctxts(func_to_io, base_qpn, num_qps); |
|---|
| 379 | 429 | if (err) { |
|---|
| 380 | 430 | dev_err(&pdev->dev, "Failed to init QP ctxts\n"); |
|---|
| 431 | + goto err_write_qp_ctxts; |
|---|
| 432 | + } |
|---|
| 433 | + |
|---|
| 434 | + err = hinic_clean_qp_offload_ctxt(func_to_io); |
|---|
| 435 | + if (err) { |
|---|
| 436 | + dev_err(&pdev->dev, "Failed to clean QP contexts space\n"); |
|---|
| 381 | 437 | goto err_write_qp_ctxts; |
|---|
| 382 | 438 | } |
|---|
| 383 | 439 | |
|---|
| .. | .. |
|---|
| 433 | 489 | devm_kfree(&pdev->dev, func_to_io->qps); |
|---|
| 434 | 490 | } |
|---|
| 435 | 491 | |
|---|
| 492 | +int hinic_set_wq_page_size(struct hinic_hwdev *hwdev, u16 func_idx, |
|---|
| 493 | + u32 page_size) |
|---|
| 494 | +{ |
|---|
| 495 | + struct hinic_wq_page_size page_size_info = {0}; |
|---|
| 496 | + u16 out_size = sizeof(page_size_info); |
|---|
| 497 | + struct hinic_pfhwdev *pfhwdev; |
|---|
| 498 | + int err; |
|---|
| 499 | + |
|---|
| 500 | + pfhwdev = container_of(hwdev, struct hinic_pfhwdev, hwdev); |
|---|
| 501 | + |
|---|
| 502 | + page_size_info.func_idx = func_idx; |
|---|
| 503 | + page_size_info.ppf_idx = HINIC_HWIF_PPF_IDX(hwdev->hwif); |
|---|
| 504 | + page_size_info.page_size = HINIC_PAGE_SIZE_HW(page_size); |
|---|
| 505 | + |
|---|
| 506 | + err = hinic_msg_to_mgmt(&pfhwdev->pf_to_mgmt, HINIC_MOD_COMM, |
|---|
| 507 | + HINIC_COMM_CMD_PAGESIZE_SET, &page_size_info, |
|---|
| 508 | + sizeof(page_size_info), &page_size_info, |
|---|
| 509 | + &out_size, HINIC_MGMT_MSG_SYNC); |
|---|
| 510 | + if (err || !out_size || page_size_info.status) { |
|---|
| 511 | + dev_err(&hwdev->hwif->pdev->dev, "Failed to set wq page size, err: %d, status: 0x%x, out_size: 0x%0x\n", |
|---|
| 512 | + err, page_size_info.status, out_size); |
|---|
| 513 | + return -EFAULT; |
|---|
| 514 | + } |
|---|
| 515 | + |
|---|
| 516 | + return 0; |
|---|
| 517 | +} |
|---|
| 518 | + |
|---|
| 436 | 519 | /** |
|---|
| 437 | 520 | * hinic_io_init - Initialize the IO components |
|---|
| 438 | 521 | * @func_to_io: func to io channel that holds the IO components |
|---|
| .. | .. |
|---|
| 455 | 538 | func_to_io->hwif = hwif; |
|---|
| 456 | 539 | func_to_io->qps = NULL; |
|---|
| 457 | 540 | func_to_io->max_qps = max_qps; |
|---|
| 541 | + func_to_io->ceqs.hwdev = func_to_io->hwdev; |
|---|
| 458 | 542 | |
|---|
| 459 | 543 | err = hinic_ceqs_init(&func_to_io->ceqs, hwif, num_ceqs, |
|---|
| 460 | 544 | HINIC_DEFAULT_CEQ_LEN, HINIC_EQ_PAGE_SIZE, |
|---|
| .. | .. |
|---|
| 490 | 574 | func_to_io->cmdq_db_area[cmdq] = db_area; |
|---|
| 491 | 575 | } |
|---|
| 492 | 576 | |
|---|
| 577 | + err = hinic_set_wq_page_size(func_to_io->hwdev, |
|---|
| 578 | + HINIC_HWIF_FUNC_IDX(hwif), |
|---|
| 579 | + HINIC_DEFAULT_WQ_PAGE_SIZE); |
|---|
| 580 | + if (err) { |
|---|
| 581 | + dev_err(&func_to_io->hwif->pdev->dev, "Failed to set wq page size\n"); |
|---|
| 582 | + goto init_wq_pg_size_err; |
|---|
| 583 | + } |
|---|
| 584 | + |
|---|
| 493 | 585 | err = hinic_init_cmdqs(&func_to_io->cmdqs, hwif, |
|---|
| 494 | 586 | func_to_io->cmdq_db_area); |
|---|
| 495 | 587 | if (err) { |
|---|
| .. | .. |
|---|
| 500 | 592 | return 0; |
|---|
| 501 | 593 | |
|---|
| 502 | 594 | err_init_cmdqs: |
|---|
| 595 | + if (!HINIC_IS_VF(func_to_io->hwif)) |
|---|
| 596 | + hinic_set_wq_page_size(func_to_io->hwdev, |
|---|
| 597 | + HINIC_HWIF_FUNC_IDX(hwif), |
|---|
| 598 | + HINIC_HW_WQ_PAGE_SIZE); |
|---|
| 599 | +init_wq_pg_size_err: |
|---|
| 503 | 600 | err_db_area: |
|---|
| 504 | 601 | for (type = HINIC_CMDQ_SYNC; type < cmdq; type++) |
|---|
| 505 | 602 | return_db_area(func_to_io, func_to_io->cmdq_db_area[type]); |
|---|
| .. | .. |
|---|
| 524 | 621 | |
|---|
| 525 | 622 | hinic_free_cmdqs(&func_to_io->cmdqs); |
|---|
| 526 | 623 | |
|---|
| 624 | + if (!HINIC_IS_VF(func_to_io->hwif)) |
|---|
| 625 | + hinic_set_wq_page_size(func_to_io->hwdev, |
|---|
| 626 | + HINIC_HWIF_FUNC_IDX(func_to_io->hwif), |
|---|
| 627 | + HINIC_HW_WQ_PAGE_SIZE); |
|---|
| 628 | + |
|---|
| 527 | 629 | for (cmdq = HINIC_CMDQ_SYNC; cmdq < HINIC_MAX_CMDQ_TYPES; cmdq++) |
|---|
| 528 | 630 | return_db_area(func_to_io, func_to_io->cmdq_db_area[cmdq]); |
|---|
| 529 | 631 | |
|---|