Skip to content

Commit 76a9a36

Browse files
Tomer Tayardavem330
authored andcommitted
qed: fix handling of concurrent ramrods.
Concurrent non-blocking slowpath ramrods can be completed out-of-order on the completion chain. Recycling completed elements, while previously sent elements are still completion pending, can lead to overriding of active elements on the chain. Furthermore, sending pending slowpath ramrods currently lacks the update of the chain element physical pointer. This patch: * Ensures that ramrods are sent to the FW with consecutive echo values. * Handles out-of-order completions by freeing only first successive completed entries. * Updates the chain element physical pointer when copying a pending element into a free element for sending. Signed-off-by: Tomer Tayar <Tomer.Tayar@qlogic.com> Signed-off-by: Manish Chopra <manish.chopra@qlogic.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 4639d60 commit 76a9a36

File tree

3 files changed

+56
-17
lines changed

3 files changed

+56
-17
lines changed

drivers/net/ethernet/qlogic/qed/qed_sp.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,12 @@ struct qed_spq {
124124
dma_addr_t p_phys;
125125
struct qed_spq_entry *p_virt;
126126

127-
/* Used as index for completions (returns on EQ by FW) */
128-
u16 echo_idx;
127+
#define SPQ_RING_SIZE \
128+
(CORE_SPQE_PAGE_SIZE_BYTES / sizeof(struct slow_path_element))
129+
130+
/* Bitmap for handling out-of-order completions */
131+
DECLARE_BITMAP(p_comp_bitmap, SPQ_RING_SIZE);
132+
u8 comp_bitmap_idx;
129133

130134
/* Statistics */
131135
u32 unlimited_pending_count;

drivers/net/ethernet/qlogic/qed/qed_spq.c

Lines changed: 48 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,6 @@ static int
112112
qed_spq_fill_entry(struct qed_hwfn *p_hwfn,
113113
struct qed_spq_entry *p_ent)
114114
{
115-
p_ent->elem.hdr.echo = 0;
116-
p_hwfn->p_spq->echo_idx++;
117115
p_ent->flags = 0;
118116

119117
switch (p_ent->comp_mode) {
@@ -195,10 +193,12 @@ static int qed_spq_hw_post(struct qed_hwfn *p_hwfn,
195193
struct qed_spq *p_spq,
196194
struct qed_spq_entry *p_ent)
197195
{
198-
struct qed_chain *p_chain = &p_hwfn->p_spq->chain;
196+
struct qed_chain *p_chain = &p_hwfn->p_spq->chain;
197+
u16 echo = qed_chain_get_prod_idx(p_chain);
199198
struct slow_path_element *elem;
200199
struct core_db_data db;
201200

201+
p_ent->elem.hdr.echo = cpu_to_le16(echo);
202202
elem = qed_chain_produce(p_chain);
203203
if (!elem) {
204204
DP_NOTICE(p_hwfn, "Failed to produce from SPQ chain\n");
@@ -437,7 +437,9 @@ void qed_spq_setup(struct qed_hwfn *p_hwfn)
437437
p_spq->comp_count = 0;
438438
p_spq->comp_sent_count = 0;
439439
p_spq->unlimited_pending_count = 0;
440-
p_spq->echo_idx = 0;
440+
441+
bitmap_zero(p_spq->p_comp_bitmap, SPQ_RING_SIZE);
442+
p_spq->comp_bitmap_idx = 0;
441443

442444
/* SPQ cid, cannot fail */
443445
qed_cxt_acquire_cid(p_hwfn, PROTOCOLID_CORE, &p_spq->cid);
@@ -582,26 +584,32 @@ qed_spq_add_entry(struct qed_hwfn *p_hwfn,
582584
struct qed_spq *p_spq = p_hwfn->p_spq;
583585

584586
if (p_ent->queue == &p_spq->unlimited_pending) {
585-
struct qed_spq_entry *p_en2;
586587

587588
if (list_empty(&p_spq->free_pool)) {
588589
list_add_tail(&p_ent->list, &p_spq->unlimited_pending);
589590
p_spq->unlimited_pending_count++;
590591

591592
return 0;
592-
}
593+
} else {
594+
struct qed_spq_entry *p_en2;
593595

594-
p_en2 = list_first_entry(&p_spq->free_pool,
595-
struct qed_spq_entry,
596-
list);
597-
list_del(&p_en2->list);
596+
p_en2 = list_first_entry(&p_spq->free_pool,
597+
struct qed_spq_entry,
598+
list);
599+
list_del(&p_en2->list);
600+
601+
/* Copy the ring element physical pointer to the new
602+
* entry, since we are about to override the entire ring
603+
* entry and don't want to lose the pointer.
604+
*/
605+
p_ent->elem.data_ptr = p_en2->elem.data_ptr;
598606

599-
/* Strcut assignment */
600-
*p_en2 = *p_ent;
607+
*p_en2 = *p_ent;
601608

602-
kfree(p_ent);
609+
kfree(p_ent);
603610

604-
p_ent = p_en2;
611+
p_ent = p_en2;
612+
}
605613
}
606614

607615
/* entry is to be placed in 'pending' queue */
@@ -777,13 +785,38 @@ int qed_spq_completion(struct qed_hwfn *p_hwfn,
777785
list_for_each_entry_safe(p_ent, tmp, &p_spq->completion_pending,
778786
list) {
779787
if (p_ent->elem.hdr.echo == echo) {
788+
u16 pos = le16_to_cpu(echo) % SPQ_RING_SIZE;
789+
780790
list_del(&p_ent->list);
781791

782-
qed_chain_return_produced(&p_spq->chain);
792+
/* Avoid overriding of SPQ entries when getting
793+
* out-of-order completions, by marking the completions
794+
* in a bitmap and increasing the chain consumer only
795+
* for the first successive completed entries.
796+
*/
797+
bitmap_set(p_spq->p_comp_bitmap, pos, SPQ_RING_SIZE);
798+
799+
while (test_bit(p_spq->comp_bitmap_idx,
800+
p_spq->p_comp_bitmap)) {
801+
bitmap_clear(p_spq->p_comp_bitmap,
802+
p_spq->comp_bitmap_idx,
803+
SPQ_RING_SIZE);
804+
p_spq->comp_bitmap_idx++;
805+
qed_chain_return_produced(&p_spq->chain);
806+
}
807+
783808
p_spq->comp_count++;
784809
found = p_ent;
785810
break;
786811
}
812+
813+
/* This is relatively uncommon - depends on scenarios
814+
* which have mutliple per-PF sent ramrods.
815+
*/
816+
DP_VERBOSE(p_hwfn, QED_MSG_SPQ,
817+
"Got completion for echo %04x - doesn't match echo %04x in completion pending list\n",
818+
le16_to_cpu(echo),
819+
le16_to_cpu(p_ent->elem.hdr.echo));
787820
}
788821

789822
/* Release lock before callback, as callback may post

include/linux/qed/common_hsi.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#ifndef __COMMON_HSI__
1010
#define __COMMON_HSI__
1111

12+
#define CORE_SPQE_PAGE_SIZE_BYTES 4096
13+
1214
#define FW_MAJOR_VERSION 8
1315
#define FW_MINOR_VERSION 4
1416
#define FW_REVISION_VERSION 2

0 commit comments

Comments
 (0)