Commit 87a7c4b3 authored by Veerasenareddy Burru's avatar Veerasenareddy Burru Committed by David S. Miller

liquidio: fix ndo_change_mtu to always return correct status to the caller

In a scenario where the command queued to firmware get dropped or times
out, MTU change from host will not propagate to firmware. So, it is
required for host driver to wait for response from firmware or timeout
and then return correct status to caller of ndo_change_mtu.

Also moved the common code for MTU change from PF and VF driver files to
common file lio_core.c
Signed-off-by: default avatarVeerasenareddy Burru <veerasenareddy.burru@cavium.com>
Signed-off-by: default avatarFelix Manlunas <felix.manlunas@cavium.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 8b4c6ed2
...@@ -164,15 +164,6 @@ void liquidio_link_ctrl_cmd_completion(void *nctrl_ptr) ...@@ -164,15 +164,6 @@ void liquidio_link_ctrl_cmd_completion(void *nctrl_ptr)
} }
break; break;
case OCTNET_CMD_CHANGE_MTU:
/* If command is successful, change the MTU. */
netif_info(lio, probe, lio->netdev, "MTU Changed from %d to %d\n",
netdev->mtu, nctrl->ncmd.s.param1);
netdev->mtu = nctrl->ncmd.s.param1;
queue_delayed_work(lio->link_status_wq.wq,
&lio->link_status_wq.wk.work, 0);
break;
case OCTNET_CMD_GPIO_ACCESS: case OCTNET_CMD_GPIO_ACCESS:
netif_info(lio, probe, lio->netdev, "LED Flashing visual identification\n"); netif_info(lio, probe, lio->netdev, "LED Flashing visual identification\n");
...@@ -1081,3 +1072,88 @@ int octeon_setup_interrupt(struct octeon_device *oct, u32 num_ioqs) ...@@ -1081,3 +1072,88 @@ int octeon_setup_interrupt(struct octeon_device *oct, u32 num_ioqs)
} }
return 0; return 0;
} }
static void liquidio_change_mtu_completion(struct octeon_device *oct,
u32 status, void *buf)
{
struct octeon_soft_command *sc = (struct octeon_soft_command *)buf;
struct liquidio_if_cfg_context *ctx;
ctx = (struct liquidio_if_cfg_context *)sc->ctxptr;
if (status) {
dev_err(&oct->pci_dev->dev, "MTU change failed. Status: %llx\n",
CVM_CAST64(status));
WRITE_ONCE(ctx->cond, LIO_CHANGE_MTU_FAIL);
} else {
WRITE_ONCE(ctx->cond, LIO_CHANGE_MTU_SUCCESS);
}
/* This barrier is required to be sure that the response has been
* written fully before waking up the handler
*/
wmb();
wake_up_interruptible(&ctx->wc);
}
/**
* \brief Net device change_mtu
* @param netdev network device
*/
int liquidio_change_mtu(struct net_device *netdev, int new_mtu)
{
struct lio *lio = GET_LIO(netdev);
struct octeon_device *oct = lio->oct_dev;
struct liquidio_if_cfg_context *ctx;
struct octeon_soft_command *sc;
union octnet_cmd *ncmd;
int ctx_size;
int ret = 0;
ctx_size = sizeof(struct liquidio_if_cfg_context);
sc = (struct octeon_soft_command *)
octeon_alloc_soft_command(oct, OCTNET_CMD_SIZE, 16, ctx_size);
ncmd = (union octnet_cmd *)sc->virtdptr;
ctx = (struct liquidio_if_cfg_context *)sc->ctxptr;
WRITE_ONCE(ctx->cond, 0);
ctx->octeon_id = lio_get_device_id(oct);
init_waitqueue_head(&ctx->wc);
ncmd->u64 = 0;
ncmd->s.cmd = OCTNET_CMD_CHANGE_MTU;
ncmd->s.param1 = new_mtu;
octeon_swap_8B_data((u64 *)ncmd, (OCTNET_CMD_SIZE >> 3));
sc->iq_no = lio->linfo.txpciq[0].s.q_no;
octeon_prepare_soft_command(oct, sc, OPCODE_NIC,
OPCODE_NIC_CMD, 0, 0, 0);
sc->callback = liquidio_change_mtu_completion;
sc->callback_arg = sc;
sc->wait_time = 100;
ret = octeon_send_soft_command(oct, sc);
if (ret == IQ_SEND_FAILED) {
netif_info(lio, rx_err, lio->netdev, "Failed to change MTU\n");
return -EINVAL;
}
/* Sleep on a wait queue till the cond flag indicates that the
* response arrived or timed-out.
*/
if (sleep_cond(&ctx->wc, &ctx->cond) == -EINTR ||
ctx->cond == LIO_CHANGE_MTU_FAIL) {
octeon_free_soft_command(oct, sc);
return -EINVAL;
}
netdev->mtu = new_mtu;
lio->mtu = new_mtu;
octeon_free_soft_command(oct, sc);
return 0;
}
...@@ -91,20 +91,6 @@ static int octeon_console_debug_enabled(u32 console) ...@@ -91,20 +91,6 @@ static int octeon_console_debug_enabled(u32 console)
*/ */
#define LIO_SYNC_OCTEON_TIME_INTERVAL_MS 60000 #define LIO_SYNC_OCTEON_TIME_INTERVAL_MS 60000
struct liquidio_if_cfg_context {
int octeon_id;
wait_queue_head_t wc;
int cond;
};
struct liquidio_if_cfg_resp {
u64 rh;
struct liquidio_if_cfg_info cfg_info;
u64 status;
};
struct liquidio_rx_ctl_context { struct liquidio_rx_ctl_context {
int octeon_id; int octeon_id;
...@@ -841,8 +827,12 @@ static void octnet_link_status_change(struct work_struct *work) ...@@ -841,8 +827,12 @@ static void octnet_link_status_change(struct work_struct *work)
struct cavium_wk *wk = (struct cavium_wk *)work; struct cavium_wk *wk = (struct cavium_wk *)work;
struct lio *lio = (struct lio *)wk->ctxptr; struct lio *lio = (struct lio *)wk->ctxptr;
/* lio->linfo.link.s.mtu always contains max MTU of the lio interface.
* this API is invoked only when new max-MTU of the interface is
* less than current MTU.
*/
rtnl_lock(); rtnl_lock();
call_netdevice_notifiers(NETDEV_CHANGEMTU, lio->netdev); dev_set_mtu(lio->netdev, lio->linfo.link.s.mtu);
rtnl_unlock(); rtnl_unlock();
} }
...@@ -891,7 +881,11 @@ static inline void update_link_status(struct net_device *netdev, ...@@ -891,7 +881,11 @@ static inline void update_link_status(struct net_device *netdev,
{ {
struct lio *lio = GET_LIO(netdev); struct lio *lio = GET_LIO(netdev);
int changed = (lio->linfo.link.u64 != ls->u64); int changed = (lio->linfo.link.u64 != ls->u64);
int current_max_mtu = lio->linfo.link.s.mtu;
struct octeon_device *oct = lio->oct_dev;
dev_dbg(&oct->pci_dev->dev, "%s: lio->linfo.link.u64=%llx, ls->u64=%llx\n",
__func__, lio->linfo.link.u64, ls->u64);
lio->linfo.link.u64 = ls->u64; lio->linfo.link.u64 = ls->u64;
if ((lio->intf_open) && (changed)) { if ((lio->intf_open) && (changed)) {
...@@ -899,12 +893,26 @@ static inline void update_link_status(struct net_device *netdev, ...@@ -899,12 +893,26 @@ static inline void update_link_status(struct net_device *netdev,
lio->link_changes++; lio->link_changes++;
if (lio->linfo.link.s.link_up) { if (lio->linfo.link.s.link_up) {
dev_dbg(&oct->pci_dev->dev, "%s: link_up", __func__);
netif_carrier_on(netdev); netif_carrier_on(netdev);
txqs_wake(netdev); txqs_wake(netdev);
} else { } else {
dev_dbg(&oct->pci_dev->dev, "%s: link_off", __func__);
netif_carrier_off(netdev); netif_carrier_off(netdev);
stop_txq(netdev); stop_txq(netdev);
} }
if (lio->linfo.link.s.mtu != current_max_mtu) {
netif_info(lio, probe, lio->netdev, "Max MTU changed from %d to %d\n",
current_max_mtu, lio->linfo.link.s.mtu);
netdev->max_mtu = lio->linfo.link.s.mtu;
}
if (lio->linfo.link.s.mtu < netdev->mtu) {
dev_warn(&oct->pci_dev->dev,
"Current MTU is higher than new max MTU; Reducing the current mtu from %d to %d\n",
netdev->mtu, lio->linfo.link.s.mtu);
queue_delayed_work(lio->link_status_wq.wq,
&lio->link_status_wq.wk.work, 0);
}
} }
} }
...@@ -2448,38 +2456,6 @@ static struct net_device_stats *liquidio_get_stats(struct net_device *netdev) ...@@ -2448,38 +2456,6 @@ static struct net_device_stats *liquidio_get_stats(struct net_device *netdev)
return stats; return stats;
} }
/**
* \brief Net device change_mtu
* @param netdev network device
*/
static int liquidio_change_mtu(struct net_device *netdev, int new_mtu)
{
struct lio *lio = GET_LIO(netdev);
struct octeon_device *oct = lio->oct_dev;
struct octnic_ctrl_pkt nctrl;
int ret = 0;
memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt));
nctrl.ncmd.u64 = 0;
nctrl.ncmd.s.cmd = OCTNET_CMD_CHANGE_MTU;
nctrl.ncmd.s.param1 = new_mtu;
nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
nctrl.wait_time = 100;
nctrl.netpndev = (u64)netdev;
nctrl.cb_fn = liquidio_link_ctrl_cmd_completion;
ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl);
if (ret < 0) {
dev_err(&oct->pci_dev->dev, "Failed to set MTU\n");
return -1;
}
lio->mtu = new_mtu;
return 0;
}
/** /**
* \brief Handler for SIOCSHWTSTAMP ioctl * \brief Handler for SIOCSHWTSTAMP ioctl
* @param netdev network device * @param netdev network device
......
...@@ -40,20 +40,6 @@ MODULE_PARM_DESC(debug, "NETIF_MSG debug bits"); ...@@ -40,20 +40,6 @@ MODULE_PARM_DESC(debug, "NETIF_MSG debug bits");
#define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK) #define DEFAULT_MSG_ENABLE (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK)
struct liquidio_if_cfg_context {
int octeon_id;
wait_queue_head_t wc;
int cond;
};
struct liquidio_if_cfg_resp {
u64 rh;
struct liquidio_if_cfg_info cfg_info;
u64 status;
};
struct liquidio_rx_ctl_context { struct liquidio_rx_ctl_context {
int octeon_id; int octeon_id;
...@@ -564,8 +550,12 @@ static void octnet_link_status_change(struct work_struct *work) ...@@ -564,8 +550,12 @@ static void octnet_link_status_change(struct work_struct *work)
struct cavium_wk *wk = (struct cavium_wk *)work; struct cavium_wk *wk = (struct cavium_wk *)work;
struct lio *lio = (struct lio *)wk->ctxptr; struct lio *lio = (struct lio *)wk->ctxptr;
/* lio->linfo.link.s.mtu always contains max MTU of the lio interface.
* this API is invoked only when new max-MTU of the interface is
* less than current MTU.
*/
rtnl_lock(); rtnl_lock();
call_netdevice_notifiers(NETDEV_CHANGEMTU, lio->netdev); dev_set_mtu(lio->netdev, lio->linfo.link.s.mtu);
rtnl_unlock(); rtnl_unlock();
} }
...@@ -613,6 +603,7 @@ static void update_link_status(struct net_device *netdev, ...@@ -613,6 +603,7 @@ static void update_link_status(struct net_device *netdev,
union oct_link_status *ls) union oct_link_status *ls)
{ {
struct lio *lio = GET_LIO(netdev); struct lio *lio = GET_LIO(netdev);
int current_max_mtu = lio->linfo.link.s.mtu;
struct octeon_device *oct = lio->oct_dev; struct octeon_device *oct = lio->oct_dev;
if ((lio->intf_open) && (lio->linfo.link.u64 != ls->u64)) { if ((lio->intf_open) && (lio->linfo.link.u64 != ls->u64)) {
...@@ -629,18 +620,17 @@ static void update_link_status(struct net_device *netdev, ...@@ -629,18 +620,17 @@ static void update_link_status(struct net_device *netdev,
txqs_stop(netdev); txqs_stop(netdev);
} }
if (lio->linfo.link.s.mtu != netdev->max_mtu) { if (lio->linfo.link.s.mtu != current_max_mtu) {
dev_info(&oct->pci_dev->dev, "Max MTU Changed from %d to %d\n", dev_info(&oct->pci_dev->dev,
netdev->max_mtu, lio->linfo.link.s.mtu); "Max MTU Changed from %d to %d\n",
current_max_mtu, lio->linfo.link.s.mtu);
netdev->max_mtu = lio->linfo.link.s.mtu; netdev->max_mtu = lio->linfo.link.s.mtu;
} }
if (lio->linfo.link.s.mtu < netdev->mtu) { if (lio->linfo.link.s.mtu < netdev->mtu) {
dev_warn(&oct->pci_dev->dev, dev_warn(&oct->pci_dev->dev,
"PF has changed the MTU for gmx port. Reducing the mtu from %d to %d\n", "Current MTU is higher than new max MTU; Reducing the current mtu from %d to %d\n",
netdev->mtu, lio->linfo.link.s.mtu); netdev->mtu, lio->linfo.link.s.mtu);
lio->mtu = lio->linfo.link.s.mtu;
netdev->mtu = lio->linfo.link.s.mtu;
queue_delayed_work(lio->link_status_wq.wq, queue_delayed_work(lio->link_status_wq.wq,
&lio->link_status_wq.wk.work, 0); &lio->link_status_wq.wk.work, 0);
} }
...@@ -1537,41 +1527,6 @@ static struct net_device_stats *liquidio_get_stats(struct net_device *netdev) ...@@ -1537,41 +1527,6 @@ static struct net_device_stats *liquidio_get_stats(struct net_device *netdev)
return stats; return stats;
} }
/**
* \brief Net device change_mtu
* @param netdev network device
*/
static int liquidio_change_mtu(struct net_device *netdev, int new_mtu)
{
struct octnic_ctrl_pkt nctrl;
struct octeon_device *oct;
struct lio *lio;
int ret = 0;
lio = GET_LIO(netdev);
oct = lio->oct_dev;
memset(&nctrl, 0, sizeof(struct octnic_ctrl_pkt));
nctrl.ncmd.u64 = 0;
nctrl.ncmd.s.cmd = OCTNET_CMD_CHANGE_MTU;
nctrl.ncmd.s.param1 = new_mtu;
nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
nctrl.wait_time = LIO_CMD_WAIT_TM;
nctrl.netpndev = (u64)netdev;
nctrl.cb_fn = liquidio_link_ctrl_cmd_completion;
ret = octnet_send_nic_ctrl_pkt(lio->oct_dev, &nctrl);
if (ret < 0) {
dev_err(&oct->pci_dev->dev, "Failed to set MTU\n");
return -EIO;
}
lio->mtu = new_mtu;
return 0;
}
/** /**
* \brief Handler for SIOCSHWTSTAMP ioctl * \brief Handler for SIOCSHWTSTAMP ioctl
* @param netdev network device * @param netdev network device
......
...@@ -192,7 +192,8 @@ static inline void add_sg_size(struct octeon_sg_entry *sg_entry, ...@@ -192,7 +192,8 @@ static inline void add_sg_size(struct octeon_sg_entry *sg_entry,
#define OCTNET_MAX_FRM_SIZE (16000 + OCTNET_FRM_HEADER_SIZE) #define OCTNET_MAX_FRM_SIZE (16000 + OCTNET_FRM_HEADER_SIZE)
#define OCTNET_DEFAULT_FRM_SIZE (1500 + OCTNET_FRM_HEADER_SIZE) #define OCTNET_DEFAULT_MTU (1500)
#define OCTNET_DEFAULT_FRM_SIZE (OCTNET_DEFAULT_MTU + OCTNET_FRM_HEADER_SIZE)
/** NIC Commands are sent using this Octeon Input Queue */ /** NIC Commands are sent using this Octeon Input Queue */
#define OCTNET_CMD_Q 0 #define OCTNET_CMD_Q 0
......
...@@ -35,6 +35,18 @@ ...@@ -35,6 +35,18 @@
#define LIO_IFSTATE_RX_TIMESTAMP_ENABLED 0x08 #define LIO_IFSTATE_RX_TIMESTAMP_ENABLED 0x08
#define LIO_IFSTATE_RESETTING 0x10 #define LIO_IFSTATE_RESETTING 0x10
struct liquidio_if_cfg_context {
u32 octeon_id;
wait_queue_head_t wc;
int cond;
};
struct liquidio_if_cfg_resp {
u64 rh;
struct liquidio_if_cfg_info cfg_info;
u64 status;
};
struct oct_nic_stats_resp { struct oct_nic_stats_resp {
u64 rh; u64 rh;
struct oct_link_stats stats; struct oct_link_stats stats;
...@@ -184,6 +196,14 @@ int octeon_setup_interrupt(struct octeon_device *oct, u32 num_ioqs); ...@@ -184,6 +196,14 @@ int octeon_setup_interrupt(struct octeon_device *oct, u32 num_ioqs);
*/ */
void liquidio_set_ethtool_ops(struct net_device *netdev); void liquidio_set_ethtool_ops(struct net_device *netdev);
/**
* \brief Net device change_mtu
* @param netdev network device
*/
int liquidio_change_mtu(struct net_device *netdev, int new_mtu);
#define LIO_CHANGE_MTU_SUCCESS 1
#define LIO_CHANGE_MTU_FAIL 2
#define SKB_ADJ_MASK 0x3F #define SKB_ADJ_MASK 0x3F
#define SKB_ADJ (SKB_ADJ_MASK + 1) #define SKB_ADJ (SKB_ADJ_MASK + 1)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment