cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

qed_ooo.c (12576B)


      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 (unlikely(idx >= p_ooo_info->max_num_archipelagos))
     30		return NULL;
     31
     32	p_archipelago = &p_ooo_info->p_archipelagos_mem[idx];
     33
     34	if (unlikely(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 (unlikely(!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 (unlikely(!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 (unlikely(!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 (unlikely(!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 (unlikely(!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 (unlikely(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 (unlikely(!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 (unlikely(!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}