diff --git a/drivers/net/ethernet/cavium/liquidio/lio_core.c b/drivers/net/ethernet/cavium/liquidio/lio_core.c index 08676df6cef056f26bf77af33eacc1c4fb7ac39a..796c2cbc11f6b5de044c5c465806184d5ad17825 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_core.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_core.c @@ -127,6 +127,17 @@ void liquidio_link_ctrl_cmd_completion(void *nctrl_ptr) struct octeon_device *oct = lio->oct_dev; u8 *mac; + if (nctrl->completion && nctrl->response_code) { + /* Signal whoever is interested that the response code from the + * firmware has arrived. + */ + WRITE_ONCE(*nctrl->response_code, nctrl->status); + complete(nctrl->completion); + } + + if (nctrl->status) + return; + switch (nctrl->ncmd.s.cmd) { case OCTNET_CMD_CHANGE_DEVFLAGS: case OCTNET_CMD_SET_MULTI_LIST: diff --git a/drivers/net/ethernet/cavium/liquidio/lio_main.c b/drivers/net/ethernet/cavium/liquidio/lio_main.c index fa673a1de24d57b6f947558ab47172fde6b3514b..927617cbf6a91a4c8738ffcb161eed0d61e9483d 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_main.c @@ -3499,6 +3499,8 @@ static int liquidio_set_rxcsum_command(struct net_device *netdev, int command, struct octnic_ctrl_pkt nctrl; int ret = 0; + memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt)); + nctrl.ncmd.u64 = 0; nctrl.ncmd.s.cmd = command; nctrl.ncmd.s.param1 = rx_cmd; @@ -3532,6 +3534,8 @@ static int liquidio_vxlan_port_command(struct net_device *netdev, int command, struct octnic_ctrl_pkt nctrl; int ret = 0; + memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt)); + nctrl.ncmd.u64 = 0; nctrl.ncmd.s.cmd = command; nctrl.ncmd.s.more = vxlan_cmd_bit; diff --git a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c index 174d748b592846864ee47770fab1f83e60187453..34c77821fad9f2a49d49841bef2b0c601ca402aa 100644 --- a/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c +++ b/drivers/net/ethernet/cavium/liquidio/lio_vf_main.c @@ -2484,6 +2484,8 @@ liquidio_vlan_rx_add_vid(struct net_device *netdev, struct lio *lio = GET_LIO(netdev); struct octeon_device *oct = lio->oct_dev; struct octnic_ctrl_pkt nctrl; + struct completion compl; + u16 response_code; int ret = 0; memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt)); @@ -2495,14 +2497,25 @@ liquidio_vlan_rx_add_vid(struct net_device *netdev, nctrl.wait_time = 100; nctrl.netpndev = (u64)netdev; nctrl.cb_fn = liquidio_link_ctrl_cmd_completion; + init_completion(&compl); + nctrl.completion = &compl; + nctrl.response_code = &response_code; ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl); if (ret < 0) { dev_err(&oct->pci_dev->dev, "Add VLAN filter failed in core (ret: 0x%x)\n", ret); + return -EIO; } - return ret; + if (!wait_for_completion_timeout(&compl, + msecs_to_jiffies(nctrl.wait_time))) + return -EPERM; + + if (READ_ONCE(response_code)) + return -EPERM; + + return 0; } static int @@ -2547,6 +2560,8 @@ static int liquidio_set_rxcsum_command(struct net_device *netdev, int command, struct octnic_ctrl_pkt nctrl; int ret = 0; + memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt)); + nctrl.ncmd.u64 = 0; nctrl.ncmd.s.cmd = command; nctrl.ncmd.s.param1 = rx_cmd; @@ -2579,6 +2594,8 @@ static int liquidio_vxlan_port_command(struct net_device *netdev, int command, struct octnic_ctrl_pkt nctrl; int ret = 0; + memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt)); + nctrl.ncmd.u64 = 0; nctrl.ncmd.s.cmd = command; nctrl.ncmd.s.more = vxlan_cmd_bit; diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_nic.c b/drivers/net/ethernet/cavium/liquidio/octeon_nic.c index 0243be8dd56fc32736c13cef0487514efcfe6a68..b457cf23fce6196e1f5ec5cc144644a5441d641c 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_nic.c +++ b/drivers/net/ethernet/cavium/liquidio/octeon_nic.c @@ -100,14 +100,16 @@ static void octnet_link_ctrl_callback(struct octeon_device *oct, nctrl = (struct octnic_ctrl_pkt *)sc->ctxptr; - /* Call the callback function if status is OK. - * Status is OK only if a response was expected and core returned - * success. + /* Call the callback function if status is zero (meaning OK) or status + * contains a firmware status code bigger than zero (meaning the + * firmware is reporting an error). * If no response was expected, status is OK if the command was posted * successfully. */ - if (!status && nctrl->cb_fn) + if ((!status || status > FIRMWARE_STATUS_CODE(0)) && nctrl->cb_fn) { + nctrl->status = status; nctrl->cb_fn(nctrl); + } octeon_free_soft_command(oct, sc); } diff --git a/drivers/net/ethernet/cavium/liquidio/octeon_nic.h b/drivers/net/ethernet/cavium/liquidio/octeon_nic.h index 0c7a5c9b2932d4db89066d3496b28d134a8bcedc..6480ef8634418dca43ab0a4187ee046276dac7ad 100644 --- a/drivers/net/ethernet/cavium/liquidio/octeon_nic.h +++ b/drivers/net/ethernet/cavium/liquidio/octeon_nic.h @@ -62,6 +62,10 @@ struct octnic_ctrl_pkt { /** Callback function called when the command has been fetched */ octnic_ctrl_pkt_cb_fn_t cb_fn; + + u32 status; + u16 *response_code; + struct completion *completion; }; #define MAX_UDD_SIZE(nctrl) (sizeof((nctrl)->udd))