Skip to content

Commit 2632f22

Browse files
Denis Bolotindavem330
authored andcommitted
qed: Fix blocking/unlimited SPQ entries leak
When there are no SPQ entries left in the free_pool, new entries are allocated and are added to the unlimited list. When an entry in the pool is available, the content is copied from the original entry, and the new entry is sent to the device. qed_spq_post() is not aware of that, so the additional entry is stored in the original entry as p_post_ent, which can later be returned to the pool. Signed-off-by: Denis Bolotin <denis.bolotin@cavium.com> Signed-off-by: Michal Kalderon <michal.kalderon@cavium.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 3947755 commit 2632f22

File tree

2 files changed

+33
-27
lines changed

2 files changed

+33
-27
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,9 @@ struct qed_spq_entry {
167167
enum spq_mode comp_mode;
168168
struct qed_spq_comp_cb comp_cb;
169169
struct qed_spq_comp_done comp_done; /* SPQ_MODE_EBLOCK */
170+
171+
/* Posted entry for unlimited list entry in EBLOCK mode */
172+
struct qed_spq_entry *post_ent;
170173
};
171174

172175
struct qed_eq {

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

Lines changed: 30 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,8 @@ static int qed_spq_add_entry(struct qed_hwfn *p_hwfn,
685685
/* EBLOCK responsible to free the allocated p_ent */
686686
if (p_ent->comp_mode != QED_SPQ_MODE_EBLOCK)
687687
kfree(p_ent);
688+
else
689+
p_ent->post_ent = p_en2;
688690

689691
p_ent = p_en2;
690692
}
@@ -767,6 +769,25 @@ static int qed_spq_pend_post(struct qed_hwfn *p_hwfn)
767769
SPQ_HIGH_PRI_RESERVE_DEFAULT);
768770
}
769771

772+
/* Avoid overriding of SPQ entries when getting out-of-order completions, by
773+
* marking the completions in a bitmap and increasing the chain consumer only
774+
* for the first successive completed entries.
775+
*/
776+
static void qed_spq_comp_bmap_update(struct qed_hwfn *p_hwfn, __le16 echo)
777+
{
778+
u16 pos = le16_to_cpu(echo) % SPQ_RING_SIZE;
779+
struct qed_spq *p_spq = p_hwfn->p_spq;
780+
781+
__set_bit(pos, p_spq->p_comp_bitmap);
782+
while (test_bit(p_spq->comp_bitmap_idx,
783+
p_spq->p_comp_bitmap)) {
784+
__clear_bit(p_spq->comp_bitmap_idx,
785+
p_spq->p_comp_bitmap);
786+
p_spq->comp_bitmap_idx++;
787+
qed_chain_return_produced(&p_spq->chain);
788+
}
789+
}
790+
770791
int qed_spq_post(struct qed_hwfn *p_hwfn,
771792
struct qed_spq_entry *p_ent, u8 *fw_return_code)
772793
{
@@ -824,11 +845,12 @@ int qed_spq_post(struct qed_hwfn *p_hwfn,
824845
p_ent->queue == &p_spq->unlimited_pending);
825846

826847
if (p_ent->queue == &p_spq->unlimited_pending) {
827-
/* This is an allocated p_ent which does not need to
828-
* return to pool.
829-
*/
848+
struct qed_spq_entry *p_post_ent = p_ent->post_ent;
849+
830850
kfree(p_ent);
831-
return rc;
851+
852+
/* Return the entry which was actually posted */
853+
p_ent = p_post_ent;
832854
}
833855

834856
if (rc)
@@ -842,7 +864,7 @@ int qed_spq_post(struct qed_hwfn *p_hwfn,
842864
spq_post_fail2:
843865
spin_lock_bh(&p_spq->lock);
844866
list_del(&p_ent->list);
845-
qed_chain_return_produced(&p_spq->chain);
867+
qed_spq_comp_bmap_update(p_hwfn, p_ent->elem.hdr.echo);
846868

847869
spq_post_fail:
848870
/* return to the free pool */
@@ -874,25 +896,8 @@ int qed_spq_completion(struct qed_hwfn *p_hwfn,
874896
spin_lock_bh(&p_spq->lock);
875897
list_for_each_entry_safe(p_ent, tmp, &p_spq->completion_pending, list) {
876898
if (p_ent->elem.hdr.echo == echo) {
877-
u16 pos = le16_to_cpu(echo) % SPQ_RING_SIZE;
878-
879899
list_del(&p_ent->list);
880-
881-
/* Avoid overriding of SPQ entries when getting
882-
* out-of-order completions, by marking the completions
883-
* in a bitmap and increasing the chain consumer only
884-
* for the first successive completed entries.
885-
*/
886-
__set_bit(pos, p_spq->p_comp_bitmap);
887-
888-
while (test_bit(p_spq->comp_bitmap_idx,
889-
p_spq->p_comp_bitmap)) {
890-
__clear_bit(p_spq->comp_bitmap_idx,
891-
p_spq->p_comp_bitmap);
892-
p_spq->comp_bitmap_idx++;
893-
qed_chain_return_produced(&p_spq->chain);
894-
}
895-
900+
qed_spq_comp_bmap_update(p_hwfn, echo);
896901
p_spq->comp_count++;
897902
found = p_ent;
898903
break;
@@ -931,11 +936,9 @@ int qed_spq_completion(struct qed_hwfn *p_hwfn,
931936
QED_MSG_SPQ,
932937
"Got a completion without a callback function\n");
933938

934-
if ((found->comp_mode != QED_SPQ_MODE_EBLOCK) ||
935-
(found->queue == &p_spq->unlimited_pending))
939+
if (found->comp_mode != QED_SPQ_MODE_EBLOCK)
936940
/* EBLOCK is responsible for returning its own entry into the
937-
* free list, unless it originally added the entry into the
938-
* unlimited pending list.
941+
* free list.
939942
*/
940943
qed_spq_return_entry(p_hwfn, found);
941944

0 commit comments

Comments
 (0)