linux/drivers/net/ethernet/qlogic/qed/qed_ooo.c
<<
>>
Prefs
   1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
   2/* QLogic qed NIC Driver
   3 * Copyright (c) 2015-2017  QLogic Corporation
   4 * Copyright (c) 2019-2020 Marvell International Ltd.
   5 */
   6
   7#include <linux/types.h>
   8#include <linux/dma-mapping.h>
   9#include <linux/kernel.h>
  10#include <linux/list.h>
  11#include <linux/pci.h>
  12#include <linux/slab.h>
  13#include <linux/string.h>
  14#include "qed.h"
  15#include "qed_iscsi.h"
  16#include "qed_ll2.h"
  17#include "qed_ooo.h"
  18#include "qed_cxt.h"
  19#include "qed_nvmetcp.h"
  20static struct qed_ooo_archipelago
  21*qed_ooo_seek_archipelago(struct qed_hwfn *p_hwfn,
  22                          struct qed_ooo_info
  23                          *p_ooo_info,
  24                          u32 cid)
  25{
  26        u32 idx = (cid & 0xffff) - p_ooo_info->cid_base;
  27        struct qed_ooo_archipelago *p_archipelago;
  28
  29        if (idx >= p_ooo_info->max_num_archipelagos)
  30                return NULL;
  31
  32        p_archipelago = &p_ooo_info->p_archipelagos_mem[idx];
  33
  34        if (list_empty(&p_archipelago->isles_list))
  35                return NULL;
  36
  37        return p_archipelago;
  38}
  39
  40static struct qed_ooo_isle *qed_ooo_seek_isle(struct qed_hwfn *p_hwfn,
  41                                              struct qed_ooo_info *p_ooo_info,
  42                                              u32 cid, u8 isle)
  43{
  44        struct qed_ooo_archipelago *p_archipelago = NULL;
  45        struct qed_ooo_isle *p_isle = NULL;
  46        u8 the_num_of_isle = 1;
  47
  48        p_archipelago = qed_ooo_seek_archipelago(p_hwfn, p_ooo_info, cid);
  49        if (!p_archipelago) {
  50                DP_NOTICE(p_hwfn,
  51                          "Connection %d is not found in OOO list\n", cid);
  52                return NULL;
  53        }
  54
  55        list_for_each_entry(p_isle, &p_archipelago->isles_list, list_entry) {
  56                if (the_num_of_isle == isle)
  57                        return p_isle;
  58                the_num_of_isle++;
  59        }
  60
  61        return NULL;
  62}
  63
  64void qed_ooo_save_history_entry(struct qed_hwfn *p_hwfn,
  65                                struct qed_ooo_info *p_ooo_info,
  66                                struct ooo_opaque *p_cqe)
  67{
  68        struct qed_ooo_history *p_history = &p_ooo_info->ooo_history;
  69
  70        if (p_history->head_idx == p_history->num_of_cqes)
  71                p_history->head_idx = 0;
  72        p_history->p_cqes[p_history->head_idx] = *p_cqe;
  73        p_history->head_idx++;
  74}
  75
  76int qed_ooo_alloc(struct qed_hwfn *p_hwfn)
  77{
  78        u16 max_num_archipelagos = 0, cid_base;
  79        struct qed_ooo_info *p_ooo_info;
  80        enum protocol_type proto;
  81        u16 max_num_isles = 0;
  82        u32 i;
  83
  84        switch (p_hwfn->hw_info.personality) {
  85        case QED_PCI_ISCSI:
  86        case QED_PCI_NVMETCP:
  87                proto = PROTOCOLID_TCP_ULP;
  88                break;
  89        case QED_PCI_ETH_RDMA:
  90        case QED_PCI_ETH_IWARP:
  91                proto = PROTOCOLID_IWARP;
  92                break;
  93        default:
  94                DP_NOTICE(p_hwfn,
  95                          "Failed to allocate qed_ooo_info: unknown personality\n");
  96                return -EINVAL;
  97        }
  98
  99        max_num_archipelagos = (u16)qed_cxt_get_proto_cid_count(p_hwfn, proto,
 100                                                                NULL);
 101        max_num_isles = QED_MAX_NUM_ISLES + max_num_archipelagos;
 102        cid_base = (u16)qed_cxt_get_proto_cid_start(p_hwfn, proto);
 103
 104        if (!max_num_archipelagos) {
 105                DP_NOTICE(p_hwfn,
 106                          "Failed to allocate qed_ooo_info: unknown amount of connections\n");
 107                return -EINVAL;
 108        }
 109
 110        p_ooo_info = kzalloc(sizeof(*p_ooo_info), GFP_KERNEL);
 111        if (!p_ooo_info)
 112                return -ENOMEM;
 113
 114        p_ooo_info->cid_base = cid_base;
 115        p_ooo_info->max_num_archipelagos = max_num_archipelagos;
 116
 117        INIT_LIST_HEAD(&p_ooo_info->free_buffers_list);
 118        INIT_LIST_HEAD(&p_ooo_info->ready_buffers_list);
 119        INIT_LIST_HEAD(&p_ooo_info->free_isles_list);
 120
 121        p_ooo_info->p_isles_mem = kcalloc(max_num_isles,
 122                                          sizeof(struct qed_ooo_isle),
 123                                          GFP_KERNEL);
 124        if (!p_ooo_info->p_isles_mem)
 125                goto no_isles_mem;
 126
 127        for (i = 0; i < max_num_isles; i++) {
 128                INIT_LIST_HEAD(&p_ooo_info->p_isles_mem[i].buffers_list);
 129                list_add_tail(&p_ooo_info->p_isles_mem[i].list_entry,
 130                              &p_ooo_info->free_isles_list);
 131        }
 132
 133        p_ooo_info->p_archipelagos_mem =
 134                                kcalloc(max_num_archipelagos,
 135                                        sizeof(struct qed_ooo_archipelago),
 136                                        GFP_KERNEL);
 137        if (!p_ooo_info->p_archipelagos_mem)
 138                goto no_archipelagos_mem;
 139
 140        for (i = 0; i < max_num_archipelagos; i++)
 141                INIT_LIST_HEAD(&p_ooo_info->p_archipelagos_mem[i].isles_list);
 142
 143        p_ooo_info->ooo_history.p_cqes =
 144                                kcalloc(QED_MAX_NUM_OOO_HISTORY_ENTRIES,
 145                                        sizeof(struct ooo_opaque),
 146                                        GFP_KERNEL);
 147        if (!p_ooo_info->ooo_history.p_cqes)
 148                goto no_history_mem;
 149
 150        p_ooo_info->ooo_history.num_of_cqes = QED_MAX_NUM_OOO_HISTORY_ENTRIES;
 151
 152        p_hwfn->p_ooo_info = p_ooo_info;
 153        return 0;
 154
 155no_history_mem:
 156        kfree(p_ooo_info->p_archipelagos_mem);
 157no_archipelagos_mem:
 158        kfree(p_ooo_info->p_isles_mem);
 159no_isles_mem:
 160        kfree(p_ooo_info);
 161        return -ENOMEM;
 162}
 163
 164void qed_ooo_release_connection_isles(struct qed_hwfn *p_hwfn,
 165                                      struct qed_ooo_info *p_ooo_info, u32 cid)
 166{
 167        struct qed_ooo_archipelago *p_archipelago;
 168        struct qed_ooo_buffer *p_buffer;
 169        struct qed_ooo_isle *p_isle;
 170
 171        p_archipelago = qed_ooo_seek_archipelago(p_hwfn, p_ooo_info, cid);
 172        if (!p_archipelago)
 173                return;
 174
 175        while (!list_empty(&p_archipelago->isles_list)) {
 176                p_isle = list_first_entry(&p_archipelago->isles_list,
 177                                          struct qed_ooo_isle, list_entry);
 178
 179                list_del(&p_isle->list_entry);
 180
 181                while (!list_empty(&p_isle->buffers_list)) {
 182                        p_buffer = list_first_entry(&p_isle->buffers_list,
 183                                                    struct qed_ooo_buffer,
 184                                                    list_entry);
 185
 186                        if (!p_buffer)
 187                                break;
 188
 189                        list_move_tail(&p_buffer->list_entry,
 190                                       &p_ooo_info->free_buffers_list);
 191                }
 192                list_add_tail(&p_isle->list_entry,
 193                              &p_ooo_info->free_isles_list);
 194        }
 195}
 196
 197void qed_ooo_release_all_isles(struct qed_hwfn *p_hwfn,
 198                               struct qed_ooo_info *p_ooo_info)
 199{
 200        struct qed_ooo_archipelago *p_archipelago;
 201        struct qed_ooo_buffer *p_buffer;
 202        struct qed_ooo_isle *p_isle;
 203        u32 i;
 204
 205        for (i = 0; i < p_ooo_info->max_num_archipelagos; i++) {
 206                p_archipelago = &(p_ooo_info->p_archipelagos_mem[i]);
 207
 208                while (!list_empty(&p_archipelago->isles_list)) {
 209                        p_isle = list_first_entry(&p_archipelago->isles_list,
 210                                                  struct qed_ooo_isle,
 211                                                  list_entry);
 212
 213                        list_del(&p_isle->list_entry);
 214
 215                        while (!list_empty(&p_isle->buffers_list)) {
 216                                p_buffer =
 217                                    list_first_entry(&p_isle->buffers_list,
 218                                                     struct qed_ooo_buffer,
 219                                                     list_entry);
 220
 221                                if (!p_buffer)
 222                                        break;
 223
 224                                list_move_tail(&p_buffer->list_entry,
 225                                               &p_ooo_info->free_buffers_list);
 226                        }
 227                        list_add_tail(&p_isle->list_entry,
 228                                      &p_ooo_info->free_isles_list);
 229                }
 230        }
 231        if (!list_empty(&p_ooo_info->ready_buffers_list))
 232                list_splice_tail_init(&p_ooo_info->ready_buffers_list,
 233                                      &p_ooo_info->free_buffers_list);
 234}
 235
 236void qed_ooo_setup(struct qed_hwfn *p_hwfn)
 237{
 238        qed_ooo_release_all_isles(p_hwfn, p_hwfn->p_ooo_info);
 239        memset(p_hwfn->p_ooo_info->ooo_history.p_cqes, 0,
 240               p_hwfn->p_ooo_info->ooo_history.num_of_cqes *
 241               sizeof(struct ooo_opaque));
 242        p_hwfn->p_ooo_info->ooo_history.head_idx = 0;
 243}
 244
 245void qed_ooo_free(struct qed_hwfn *p_hwfn)
 246{
 247        struct qed_ooo_info *p_ooo_info  = p_hwfn->p_ooo_info;
 248        struct qed_ooo_buffer *p_buffer;
 249
 250        if (!p_ooo_info)
 251                return;
 252
 253        qed_ooo_release_all_isles(p_hwfn, p_ooo_info);
 254        while (!list_empty(&p_ooo_info->free_buffers_list)) {
 255                p_buffer = list_first_entry(&p_ooo_info->free_buffers_list,
 256                                            struct qed_ooo_buffer, list_entry);
 257
 258                if (!p_buffer)
 259                        break;
 260
 261                list_del(&p_buffer->list_entry);
 262                dma_free_coherent(&p_hwfn->cdev->pdev->dev,
 263                                  p_buffer->rx_buffer_size,
 264                                  p_buffer->rx_buffer_virt_addr,
 265                                  p_buffer->rx_buffer_phys_addr);
 266                kfree(p_buffer);
 267        }
 268
 269        kfree(p_ooo_info->p_isles_mem);
 270        kfree(p_ooo_info->p_archipelagos_mem);
 271        kfree(p_ooo_info->ooo_history.p_cqes);
 272        kfree(p_ooo_info);
 273        p_hwfn->p_ooo_info = NULL;
 274}
 275
 276void qed_ooo_put_free_buffer(struct qed_hwfn *p_hwfn,
 277                             struct qed_ooo_info *p_ooo_info,
 278                             struct qed_ooo_buffer *p_buffer)
 279{
 280        list_add_tail(&p_buffer->list_entry, &p_ooo_info->free_buffers_list);
 281}
 282
 283struct qed_ooo_buffer *qed_ooo_get_free_buffer(struct qed_hwfn *p_hwfn,
 284                                               struct qed_ooo_info *p_ooo_info)
 285{
 286        struct qed_ooo_buffer *p_buffer = NULL;
 287
 288        if (!list_empty(&p_ooo_info->free_buffers_list)) {
 289                p_buffer = list_first_entry(&p_ooo_info->free_buffers_list,
 290                                            struct qed_ooo_buffer, list_entry);
 291
 292                list_del(&p_buffer->list_entry);
 293        }
 294
 295        return p_buffer;
 296}
 297
 298void qed_ooo_put_ready_buffer(struct qed_hwfn *p_hwfn,
 299                              struct qed_ooo_info *p_ooo_info,
 300                              struct qed_ooo_buffer *p_buffer, u8 on_tail)
 301{
 302        if (on_tail)
 303                list_add_tail(&p_buffer->list_entry,
 304                              &p_ooo_info->ready_buffers_list);
 305        else
 306                list_add(&p_buffer->list_entry,
 307                         &p_ooo_info->ready_buffers_list);
 308}
 309
 310struct qed_ooo_buffer *qed_ooo_get_ready_buffer(struct qed_hwfn *p_hwfn,
 311                                                struct qed_ooo_info *p_ooo_info)
 312{
 313        struct qed_ooo_buffer *p_buffer = NULL;
 314
 315        if (!list_empty(&p_ooo_info->ready_buffers_list)) {
 316                p_buffer = list_first_entry(&p_ooo_info->ready_buffers_list,
 317                                            struct qed_ooo_buffer, list_entry);
 318
 319                list_del(&p_buffer->list_entry);
 320        }
 321
 322        return p_buffer;
 323}
 324
 325void qed_ooo_delete_isles(struct qed_hwfn *p_hwfn,
 326                          struct qed_ooo_info *p_ooo_info,
 327                          u32 cid, u8 drop_isle, u8 drop_size)
 328{
 329        struct qed_ooo_isle *p_isle = NULL;
 330        u8 isle_idx;
 331
 332        for (isle_idx = 0; isle_idx < drop_size; isle_idx++) {
 333                p_isle = qed_ooo_seek_isle(p_hwfn, p_ooo_info, cid, drop_isle);
 334                if (!p_isle) {
 335                        DP_NOTICE(p_hwfn,
 336                                  "Isle %d is not found(cid %d)\n",
 337                                  drop_isle, cid);
 338                        return;
 339                }
 340                if (list_empty(&p_isle->buffers_list))
 341                        DP_NOTICE(p_hwfn,
 342                                  "Isle %d is empty(cid %d)\n", drop_isle, cid);
 343                else
 344                        list_splice_tail_init(&p_isle->buffers_list,
 345                                              &p_ooo_info->free_buffers_list);
 346
 347                list_del(&p_isle->list_entry);
 348                p_ooo_info->cur_isles_number--;
 349                list_add(&p_isle->list_entry, &p_ooo_info->free_isles_list);
 350        }
 351}
 352
 353void qed_ooo_add_new_isle(struct qed_hwfn *p_hwfn,
 354                          struct qed_ooo_info *p_ooo_info,
 355                          u32 cid, u8 ooo_isle,
 356                          struct qed_ooo_buffer *p_buffer)
 357{
 358        struct qed_ooo_archipelago *p_archipelago = NULL;
 359        struct qed_ooo_isle *p_prev_isle = NULL;
 360        struct qed_ooo_isle *p_isle = NULL;
 361
 362        if (ooo_isle > 1) {
 363                p_prev_isle = qed_ooo_seek_isle(p_hwfn,
 364                                                p_ooo_info, cid, ooo_isle - 1);
 365                if (!p_prev_isle) {
 366                        DP_NOTICE(p_hwfn,
 367                                  "Isle %d is not found(cid %d)\n",
 368                                  ooo_isle - 1, cid);
 369                        return;
 370                }
 371        }
 372        p_archipelago = qed_ooo_seek_archipelago(p_hwfn, p_ooo_info, cid);
 373        if (!p_archipelago && (ooo_isle != 1)) {
 374                DP_NOTICE(p_hwfn,
 375                          "Connection %d is not found in OOO list\n", cid);
 376                return;
 377        }
 378
 379        if (!list_empty(&p_ooo_info->free_isles_list)) {
 380                p_isle = list_first_entry(&p_ooo_info->free_isles_list,
 381                                          struct qed_ooo_isle, list_entry);
 382
 383                list_del(&p_isle->list_entry);
 384                if (!list_empty(&p_isle->buffers_list)) {
 385                        DP_NOTICE(p_hwfn, "Free isle is not empty\n");
 386                        INIT_LIST_HEAD(&p_isle->buffers_list);
 387                }
 388        } else {
 389                DP_NOTICE(p_hwfn, "No more free isles\n");
 390                return;
 391        }
 392
 393        if (!p_archipelago) {
 394                u32 idx = (cid & 0xffff) - p_ooo_info->cid_base;
 395
 396                p_archipelago = &p_ooo_info->p_archipelagos_mem[idx];
 397        }
 398
 399        list_add(&p_buffer->list_entry, &p_isle->buffers_list);
 400        p_ooo_info->cur_isles_number++;
 401        p_ooo_info->gen_isles_number++;
 402
 403        if (p_ooo_info->cur_isles_number > p_ooo_info->max_isles_number)
 404                p_ooo_info->max_isles_number = p_ooo_info->cur_isles_number;
 405
 406        if (!p_prev_isle)
 407                list_add(&p_isle->list_entry, &p_archipelago->isles_list);
 408        else
 409                list_add(&p_isle->list_entry, &p_prev_isle->list_entry);
 410}
 411
 412void qed_ooo_add_new_buffer(struct qed_hwfn *p_hwfn,
 413                            struct qed_ooo_info *p_ooo_info,
 414                            u32 cid,
 415                            u8 ooo_isle,
 416                            struct qed_ooo_buffer *p_buffer, u8 buffer_side)
 417{
 418        struct qed_ooo_isle *p_isle = NULL;
 419
 420        p_isle = qed_ooo_seek_isle(p_hwfn, p_ooo_info, cid, ooo_isle);
 421        if (!p_isle) {
 422                DP_NOTICE(p_hwfn,
 423                          "Isle %d is not found(cid %d)\n", ooo_isle, cid);
 424                return;
 425        }
 426
 427        if (buffer_side == QED_OOO_LEFT_BUF)
 428                list_add(&p_buffer->list_entry, &p_isle->buffers_list);
 429        else
 430                list_add_tail(&p_buffer->list_entry, &p_isle->buffers_list);
 431}
 432
 433void qed_ooo_join_isles(struct qed_hwfn *p_hwfn,
 434                        struct qed_ooo_info *p_ooo_info, u32 cid, u8 left_isle)
 435{
 436        struct qed_ooo_isle *p_right_isle = NULL;
 437        struct qed_ooo_isle *p_left_isle = NULL;
 438
 439        p_right_isle = qed_ooo_seek_isle(p_hwfn, p_ooo_info, cid,
 440                                         left_isle + 1);
 441        if (!p_right_isle) {
 442                DP_NOTICE(p_hwfn,
 443                          "Right isle %d is not found(cid %d)\n",
 444                          left_isle + 1, cid);
 445                return;
 446        }
 447
 448        list_del(&p_right_isle->list_entry);
 449        p_ooo_info->cur_isles_number--;
 450        if (left_isle) {
 451                p_left_isle = qed_ooo_seek_isle(p_hwfn, p_ooo_info, cid,
 452                                                left_isle);
 453                if (!p_left_isle) {
 454                        DP_NOTICE(p_hwfn,
 455                                  "Left isle %d is not found(cid %d)\n",
 456                                  left_isle, cid);
 457                        return;
 458                }
 459                list_splice_tail_init(&p_right_isle->buffers_list,
 460                                      &p_left_isle->buffers_list);
 461        } else {
 462                list_splice_tail_init(&p_right_isle->buffers_list,
 463                                      &p_ooo_info->ready_buffers_list);
 464        }
 465        list_add_tail(&p_right_isle->list_entry, &p_ooo_info->free_isles_list);
 466}
 467