Skip to content

Commit 95d2f25

Browse files
author
Paolo Abeni
committed
Merge branch 'fbnic-fw-ipc-mailbox-fixes'
Alexander Duyck says: ==================== fbnic: FW IPC Mailbox fixes This series is meant to address a number of issues that have been found in the FW IPC mailbox over the past several months. The main issues addressed are: 1. Resolve a potential race between host and FW during initialization that can cause the FW to only have the lower 32b of an address. 2. Block the FW from issuing DMA requests after we have closed the mailbox and before we have started issuing requests on it. 3. Fix races in the IRQ handlers that can cause the IRQ to unmask itself if it is being processed while we are trying to disable it. 4. Cleanup the Tx flush logic so that we actually lock down the Tx path before we start flushing it instead of letting it free run while we are shutting it down. 5. Fix several memory leaks that could occur if we failed initialization. 6. Cleanup the mailbox completion if we are flushing Tx since we are no longer processing Rx. 7. Move several allocations out of a potential IRQ/atomic context. There have been a few optimizations we also picked up since then. Rather than split them out I just folded them into these diffs. They mostly address minor issues such as how long it takes to initialize and/or fail so I thought they could probably go in with the rest of the patches. They consist of: 1. Do not sleep more than 20ms waiting on FW to respond as the 200ms value likely originated from simulation/emulation testing. 2. Use jiffies to determine timeout instead of sleep * attempts for better accuracy. Reviewed-by: Jakub Kicinski <kuba@kernel.org> ==================== Link: https://patch.msgid.link/174654659243.499179.11194817277075480209.stgit@ahduyck-xeon-server.home.arpa Signed-off-by: Paolo Abeni <pabeni@redhat.com>
2 parents bdc6470 + ce2fa1d commit 95d2f25

File tree

7 files changed

+231
-143
lines changed

7 files changed

+231
-143
lines changed

drivers/net/ethernet/meta/fbnic/fbnic.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,14 +154,14 @@ struct fbnic_dev *fbnic_devlink_alloc(struct pci_dev *pdev);
154154
void fbnic_devlink_register(struct fbnic_dev *fbd);
155155
void fbnic_devlink_unregister(struct fbnic_dev *fbd);
156156

157-
int fbnic_fw_enable_mbx(struct fbnic_dev *fbd);
158-
void fbnic_fw_disable_mbx(struct fbnic_dev *fbd);
157+
int fbnic_fw_request_mbx(struct fbnic_dev *fbd);
158+
void fbnic_fw_free_mbx(struct fbnic_dev *fbd);
159159

160160
void fbnic_hwmon_register(struct fbnic_dev *fbd);
161161
void fbnic_hwmon_unregister(struct fbnic_dev *fbd);
162162

163-
int fbnic_pcs_irq_enable(struct fbnic_dev *fbd);
164-
void fbnic_pcs_irq_disable(struct fbnic_dev *fbd);
163+
int fbnic_pcs_request_irq(struct fbnic_dev *fbd);
164+
void fbnic_pcs_free_irq(struct fbnic_dev *fbd);
165165

166166
void fbnic_napi_name_irqs(struct fbnic_dev *fbd);
167167
int fbnic_napi_request_irq(struct fbnic_dev *fbd,

drivers/net/ethernet/meta/fbnic/fbnic_csr.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -796,8 +796,10 @@ enum {
796796
/* PUL User Registers */
797797
#define FBNIC_CSR_START_PUL_USER 0x31000 /* CSR section delimiter */
798798
#define FBNIC_PUL_OB_TLP_HDR_AW_CFG 0x3103d /* 0xc40f4 */
799+
#define FBNIC_PUL_OB_TLP_HDR_AW_CFG_FLUSH CSR_BIT(19)
799800
#define FBNIC_PUL_OB_TLP_HDR_AW_CFG_BME CSR_BIT(18)
800801
#define FBNIC_PUL_OB_TLP_HDR_AR_CFG 0x3103e /* 0xc40f8 */
802+
#define FBNIC_PUL_OB_TLP_HDR_AR_CFG_FLUSH CSR_BIT(19)
801803
#define FBNIC_PUL_OB_TLP_HDR_AR_CFG_BME CSR_BIT(18)
802804
#define FBNIC_PUL_USER_OB_RD_TLP_CNT_31_0 \
803805
0x3106e /* 0xc41b8 */

drivers/net/ethernet/meta/fbnic/fbnic_fw.c

Lines changed: 119 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,29 @@ static void __fbnic_mbx_wr_desc(struct fbnic_dev *fbd, int mbx_idx,
1717
{
1818
u32 desc_offset = FBNIC_IPC_MBX(mbx_idx, desc_idx);
1919

20+
/* Write the upper 32b and then the lower 32b. Doing this the
21+
* FW can then read lower, upper, lower to verify that the state
22+
* of the descriptor wasn't changed mid-transaction.
23+
*/
2024
fw_wr32(fbd, desc_offset + 1, upper_32_bits(desc));
2125
fw_wrfl(fbd);
2226
fw_wr32(fbd, desc_offset, lower_32_bits(desc));
2327
}
2428

29+
static void __fbnic_mbx_invalidate_desc(struct fbnic_dev *fbd, int mbx_idx,
30+
int desc_idx, u32 desc)
31+
{
32+
u32 desc_offset = FBNIC_IPC_MBX(mbx_idx, desc_idx);
33+
34+
/* For initialization we write the lower 32b of the descriptor first.
35+
* This way we can set the state to mark it invalid before we clear the
36+
* upper 32b.
37+
*/
38+
fw_wr32(fbd, desc_offset, desc);
39+
fw_wrfl(fbd);
40+
fw_wr32(fbd, desc_offset + 1, 0);
41+
}
42+
2543
static u64 __fbnic_mbx_rd_desc(struct fbnic_dev *fbd, int mbx_idx, int desc_idx)
2644
{
2745
u32 desc_offset = FBNIC_IPC_MBX(mbx_idx, desc_idx);
@@ -33,29 +51,41 @@ static u64 __fbnic_mbx_rd_desc(struct fbnic_dev *fbd, int mbx_idx, int desc_idx)
3351
return desc;
3452
}
3553

36-
static void fbnic_mbx_init_desc_ring(struct fbnic_dev *fbd, int mbx_idx)
54+
static void fbnic_mbx_reset_desc_ring(struct fbnic_dev *fbd, int mbx_idx)
3755
{
3856
int desc_idx;
3957

58+
/* Disable DMA transactions from the device,
59+
* and flush any transactions triggered during cleaning
60+
*/
61+
switch (mbx_idx) {
62+
case FBNIC_IPC_MBX_RX_IDX:
63+
wr32(fbd, FBNIC_PUL_OB_TLP_HDR_AW_CFG,
64+
FBNIC_PUL_OB_TLP_HDR_AW_CFG_FLUSH);
65+
break;
66+
case FBNIC_IPC_MBX_TX_IDX:
67+
wr32(fbd, FBNIC_PUL_OB_TLP_HDR_AR_CFG,
68+
FBNIC_PUL_OB_TLP_HDR_AR_CFG_FLUSH);
69+
break;
70+
}
71+
72+
wrfl(fbd);
73+
4074
/* Initialize first descriptor to all 0s. Doing this gives us a
4175
* solid stop for the firmware to hit when it is done looping
4276
* through the ring.
4377
*/
44-
__fbnic_mbx_wr_desc(fbd, mbx_idx, 0, 0);
45-
46-
fw_wrfl(fbd);
78+
__fbnic_mbx_invalidate_desc(fbd, mbx_idx, 0, 0);
4779

4880
/* We then fill the rest of the ring starting at the end and moving
4981
* back toward descriptor 0 with skip descriptors that have no
5082
* length nor address, and tell the firmware that they can skip
5183
* them and just move past them to the one we initialized to 0.
5284
*/
53-
for (desc_idx = FBNIC_IPC_MBX_DESC_LEN; --desc_idx;) {
54-
__fbnic_mbx_wr_desc(fbd, mbx_idx, desc_idx,
55-
FBNIC_IPC_MBX_DESC_FW_CMPL |
56-
FBNIC_IPC_MBX_DESC_HOST_CMPL);
57-
fw_wrfl(fbd);
58-
}
85+
for (desc_idx = FBNIC_IPC_MBX_DESC_LEN; --desc_idx;)
86+
__fbnic_mbx_invalidate_desc(fbd, mbx_idx, desc_idx,
87+
FBNIC_IPC_MBX_DESC_FW_CMPL |
88+
FBNIC_IPC_MBX_DESC_HOST_CMPL);
5989
}
6090

6191
void fbnic_mbx_init(struct fbnic_dev *fbd)
@@ -76,7 +106,7 @@ void fbnic_mbx_init(struct fbnic_dev *fbd)
76106
wr32(fbd, FBNIC_INTR_CLEAR(0), 1u << FBNIC_FW_MSIX_ENTRY);
77107

78108
for (i = 0; i < FBNIC_IPC_MBX_INDICES; i++)
79-
fbnic_mbx_init_desc_ring(fbd, i);
109+
fbnic_mbx_reset_desc_ring(fbd, i);
80110
}
81111

82112
static int fbnic_mbx_map_msg(struct fbnic_dev *fbd, int mbx_idx,
@@ -141,7 +171,7 @@ static void fbnic_mbx_clean_desc_ring(struct fbnic_dev *fbd, int mbx_idx)
141171
{
142172
int i;
143173

144-
fbnic_mbx_init_desc_ring(fbd, mbx_idx);
174+
fbnic_mbx_reset_desc_ring(fbd, mbx_idx);
145175

146176
for (i = FBNIC_IPC_MBX_DESC_LEN; i--;)
147177
fbnic_mbx_unmap_and_free_msg(fbd, mbx_idx, i);
@@ -322,67 +352,41 @@ static int fbnic_fw_xmit_simple_msg(struct fbnic_dev *fbd, u32 msg_type)
322352
return err;
323353
}
324354

325-
/**
326-
* fbnic_fw_xmit_cap_msg - Allocate and populate a FW capabilities message
327-
* @fbd: FBNIC device structure
328-
*
329-
* Return: NULL on failure to allocate, error pointer on error, or pointer
330-
* to new TLV test message.
331-
*
332-
* Sends a single TLV header indicating the host wants the firmware to
333-
* confirm the capabilities and version.
334-
**/
335-
static int fbnic_fw_xmit_cap_msg(struct fbnic_dev *fbd)
336-
{
337-
int err = fbnic_fw_xmit_simple_msg(fbd, FBNIC_TLV_MSG_ID_HOST_CAP_REQ);
338-
339-
/* Return 0 if we are not calling this on ASIC */
340-
return (err == -EOPNOTSUPP) ? 0 : err;
341-
}
342-
343-
static void fbnic_mbx_postinit_desc_ring(struct fbnic_dev *fbd, int mbx_idx)
355+
static void fbnic_mbx_init_desc_ring(struct fbnic_dev *fbd, int mbx_idx)
344356
{
345357
struct fbnic_fw_mbx *mbx = &fbd->mbx[mbx_idx];
346358

347-
/* This is a one time init, so just exit if it is completed */
348-
if (mbx->ready)
349-
return;
350-
351359
mbx->ready = true;
352360

353361
switch (mbx_idx) {
354362
case FBNIC_IPC_MBX_RX_IDX:
363+
/* Enable DMA writes from the device */
364+
wr32(fbd, FBNIC_PUL_OB_TLP_HDR_AW_CFG,
365+
FBNIC_PUL_OB_TLP_HDR_AW_CFG_BME);
366+
355367
/* Make sure we have a page for the FW to write to */
356368
fbnic_mbx_alloc_rx_msgs(fbd);
357369
break;
358370
case FBNIC_IPC_MBX_TX_IDX:
359-
/* Force version to 1 if we successfully requested an update
360-
* from the firmware. This should be overwritten once we get
361-
* the actual version from the firmware in the capabilities
362-
* request message.
363-
*/
364-
if (!fbnic_fw_xmit_cap_msg(fbd) &&
365-
!fbd->fw_cap.running.mgmt.version)
366-
fbd->fw_cap.running.mgmt.version = 1;
371+
/* Enable DMA reads from the device */
372+
wr32(fbd, FBNIC_PUL_OB_TLP_HDR_AR_CFG,
373+
FBNIC_PUL_OB_TLP_HDR_AR_CFG_BME);
367374
break;
368375
}
369376
}
370377

371-
static void fbnic_mbx_postinit(struct fbnic_dev *fbd)
378+
static bool fbnic_mbx_event(struct fbnic_dev *fbd)
372379
{
373-
int i;
374-
375-
/* We only need to do this on the first interrupt following init.
380+
/* We only need to do this on the first interrupt following reset.
376381
* this primes the mailbox so that we will have cleared all the
377382
* skip descriptors.
378383
*/
379384
if (!(rd32(fbd, FBNIC_INTR_STATUS(0)) & (1u << FBNIC_FW_MSIX_ENTRY)))
380-
return;
385+
return false;
381386

382387
wr32(fbd, FBNIC_INTR_CLEAR(0), 1u << FBNIC_FW_MSIX_ENTRY);
383388

384-
for (i = 0; i < FBNIC_IPC_MBX_INDICES; i++)
385-
fbnic_mbx_postinit_desc_ring(fbd, i);
389+
return true;
386390
}
387391

388392
/**
@@ -859,68 +863,105 @@ static void fbnic_mbx_process_rx_msgs(struct fbnic_dev *fbd)
859863

860864
void fbnic_mbx_poll(struct fbnic_dev *fbd)
861865
{
862-
fbnic_mbx_postinit(fbd);
866+
fbnic_mbx_event(fbd);
863867

864868
fbnic_mbx_process_tx_msgs(fbd);
865869
fbnic_mbx_process_rx_msgs(fbd);
866870
}
867871

868872
int fbnic_mbx_poll_tx_ready(struct fbnic_dev *fbd)
869873
{
870-
struct fbnic_fw_mbx *tx_mbx;
871-
int attempts = 50;
874+
unsigned long timeout = jiffies + 10 * HZ + 1;
875+
int err, i;
872876

873-
/* Immediate fail if BAR4 isn't there */
874-
if (!fbnic_fw_present(fbd))
875-
return -ENODEV;
877+
do {
878+
if (!time_is_after_jiffies(timeout))
879+
return -ETIMEDOUT;
876880

877-
tx_mbx = &fbd->mbx[FBNIC_IPC_MBX_TX_IDX];
878-
while (!tx_mbx->ready && --attempts) {
879881
/* Force the firmware to trigger an interrupt response to
880882
* avoid the mailbox getting stuck closed if the interrupt
881883
* is reset.
882884
*/
883-
fbnic_mbx_init_desc_ring(fbd, FBNIC_IPC_MBX_TX_IDX);
885+
fbnic_mbx_reset_desc_ring(fbd, FBNIC_IPC_MBX_TX_IDX);
884886

885-
msleep(200);
887+
/* Immediate fail if BAR4 went away */
888+
if (!fbnic_fw_present(fbd))
889+
return -ENODEV;
886890

887-
fbnic_mbx_poll(fbd);
888-
}
891+
msleep(20);
892+
} while (!fbnic_mbx_event(fbd));
893+
894+
/* FW has shown signs of life. Enable DMA and start Tx/Rx */
895+
for (i = 0; i < FBNIC_IPC_MBX_INDICES; i++)
896+
fbnic_mbx_init_desc_ring(fbd, i);
897+
898+
/* Request an update from the firmware. This should overwrite
899+
* mgmt.version once we get the actual version from the firmware
900+
* in the capabilities request message.
901+
*/
902+
err = fbnic_fw_xmit_simple_msg(fbd, FBNIC_TLV_MSG_ID_HOST_CAP_REQ);
903+
if (err)
904+
goto clean_mbx;
905+
906+
/* Use "1" to indicate we entered the state waiting for a response */
907+
fbd->fw_cap.running.mgmt.version = 1;
908+
909+
return 0;
910+
clean_mbx:
911+
/* Cleanup Rx buffers and disable mailbox */
912+
fbnic_mbx_clean(fbd);
913+
return err;
914+
}
915+
916+
static void __fbnic_fw_evict_cmpl(struct fbnic_fw_completion *cmpl_data)
917+
{
918+
cmpl_data->result = -EPIPE;
919+
complete(&cmpl_data->done);
920+
}
889921

890-
return attempts ? 0 : -ETIMEDOUT;
922+
static void fbnic_mbx_evict_all_cmpl(struct fbnic_dev *fbd)
923+
{
924+
if (fbd->cmpl_data) {
925+
__fbnic_fw_evict_cmpl(fbd->cmpl_data);
926+
fbd->cmpl_data = NULL;
927+
}
891928
}
892929

893930
void fbnic_mbx_flush_tx(struct fbnic_dev *fbd)
894931
{
932+
unsigned long timeout = jiffies + 10 * HZ + 1;
895933
struct fbnic_fw_mbx *tx_mbx;
896-
int attempts = 50;
897-
u8 count = 0;
898-
899-
/* Nothing to do if there is no mailbox */
900-
if (!fbnic_fw_present(fbd))
901-
return;
934+
u8 tail;
902935

903936
/* Record current Rx stats */
904937
tx_mbx = &fbd->mbx[FBNIC_IPC_MBX_TX_IDX];
905938

906-
/* Nothing to do if mailbox never got to ready */
907-
if (!tx_mbx->ready)
908-
return;
939+
spin_lock_irq(&fbd->fw_tx_lock);
940+
941+
/* Clear ready to prevent any further attempts to transmit */
942+
tx_mbx->ready = false;
943+
944+
/* Read tail to determine the last tail state for the ring */
945+
tail = tx_mbx->tail;
946+
947+
/* Flush any completions as we are no longer processing Rx */
948+
fbnic_mbx_evict_all_cmpl(fbd);
949+
950+
spin_unlock_irq(&fbd->fw_tx_lock);
909951

910952
/* Give firmware time to process packet,
911-
* we will wait up to 10 seconds which is 50 waits of 200ms.
953+
* we will wait up to 10 seconds which is 500 waits of 20ms.
912954
*/
913955
do {
914956
u8 head = tx_mbx->head;
915957

916-
if (head == tx_mbx->tail)
958+
/* Tx ring is empty once head == tail */
959+
if (head == tail)
917960
break;
918961

919-
msleep(200);
962+
msleep(20);
920963
fbnic_mbx_process_tx_msgs(fbd);
921-
922-
count += (tx_mbx->head - head) % FBNIC_IPC_MBX_DESC_LEN;
923-
} while (count < FBNIC_IPC_MBX_DESC_LEN && --attempts);
964+
} while (time_is_after_jiffies(timeout));
924965
}
925966

926967
void fbnic_get_fw_ver_commit_str(struct fbnic_dev *fbd, char *fw_version,

0 commit comments

Comments
 (0)