liquidio: allocate RX buffers in OOM conditions in PF and VF

Add workqueue that is periodically run to try to allocate RX buffers in OOM
conditions in PF and VF.

Signed-off-by: Satanand Burla <satananda.burla@cavium.com>
Signed-off-by: Felix Manlunas <felix.manlunas@cavium.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Satanand Burla 2017-03-22 11:31:13 -07:00 committed by David S. Miller
parent 3426bd7277
commit 031d4f1210
7 changed files with 103 additions and 0 deletions

View File

@ -43,6 +43,8 @@ struct octeon_cn23xx_pf {
struct octeon_config *conf;
};
#define CN23XX_SLI_DEF_BP 0x40
int setup_cn23xx_octeon_pf_device(struct octeon_device *oct);
int validate_cn23xx_pf_config_info(struct octeon_device *oct,

View File

@ -26,6 +26,9 @@
#include "octeon_main.h"
#include "octeon_network.h"
/* OOM task polling interval */
#define LIO_OOM_POLL_INTERVAL_MS 250
int liquidio_set_feature(struct net_device *netdev, int cmd, u16 param1)
{
struct lio *lio = GET_LIO(netdev);
@ -293,3 +296,56 @@ void octeon_pf_changed_vf_macaddr(struct octeon_device *oct, u8 *mac)
* the PF did that already
*/
}
static void octnet_poll_check_rxq_oom_status(struct work_struct *work)
{
struct cavium_wk *wk = (struct cavium_wk *)work;
struct lio *lio = (struct lio *)wk->ctxptr;
struct octeon_device *oct = lio->oct_dev;
struct octeon_droq *droq;
int q, q_no = 0;
if (ifstate_check(lio, LIO_IFSTATE_RUNNING)) {
for (q = 0; q < lio->linfo.num_rxpciq; q++) {
q_no = lio->linfo.rxpciq[q].s.q_no;
droq = oct->droq[q_no];
if (!droq)
continue;
octeon_droq_check_oom(droq);
}
}
queue_delayed_work(lio->rxq_status_wq.wq,
&lio->rxq_status_wq.wk.work,
msecs_to_jiffies(LIO_OOM_POLL_INTERVAL_MS));
}
int setup_rx_oom_poll_fn(struct net_device *netdev)
{
struct lio *lio = GET_LIO(netdev);
struct octeon_device *oct = lio->oct_dev;
lio->rxq_status_wq.wq = alloc_workqueue("rxq-oom-status",
WQ_MEM_RECLAIM, 0);
if (!lio->rxq_status_wq.wq) {
dev_err(&oct->pci_dev->dev, "unable to create cavium rxq oom status wq\n");
return -ENOMEM;
}
INIT_DELAYED_WORK(&lio->rxq_status_wq.wk.work,
octnet_poll_check_rxq_oom_status);
lio->rxq_status_wq.wk.ctxptr = lio;
queue_delayed_work(lio->rxq_status_wq.wq,
&lio->rxq_status_wq.wk.work,
msecs_to_jiffies(LIO_OOM_POLL_INTERVAL_MS));
return 0;
}
void cleanup_rx_oom_poll_fn(struct net_device *netdev)
{
struct lio *lio = GET_LIO(netdev);
if (lio->rxq_status_wq.wq) {
cancel_delayed_work_sync(&lio->rxq_status_wq.wk.work);
flush_workqueue(lio->rxq_status_wq.wq);
destroy_workqueue(lio->rxq_status_wq.wq);
}
}

View File

@ -1673,6 +1673,8 @@ static void liquidio_destroy_nic_device(struct octeon_device *oct, int ifidx)
cleanup_link_status_change_wq(netdev);
cleanup_rx_oom_poll_fn(netdev);
delete_glists(lio);
free_netdev(netdev);
@ -4147,6 +4149,9 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
if (setup_link_status_change_wq(netdev))
goto setup_nic_dev_fail;
if (setup_rx_oom_poll_fn(netdev))
goto setup_nic_dev_fail;
/* Register the network device with the OS */
if (register_netdev(netdev)) {
dev_err(&octeon_dev->pci_dev->dev, "Device registration failed\n");

View File

@ -1155,6 +1155,8 @@ static void liquidio_destroy_nic_device(struct octeon_device *oct, int ifidx)
if (atomic_read(&lio->ifstate) & LIO_IFSTATE_REGISTERED)
unregister_netdev(netdev);
cleanup_rx_oom_poll_fn(netdev);
cleanup_link_status_change_wq(netdev);
delete_glists(lio);
@ -2995,6 +2997,9 @@ static int setup_nic_devices(struct octeon_device *octeon_dev)
if (setup_link_status_change_wq(netdev))
goto setup_nic_dev_fail;
if (setup_rx_oom_poll_fn(netdev))
goto setup_nic_dev_fail;
/* Register the network device with the OS */
if (register_netdev(netdev)) {
dev_err(&octeon_dev->pci_dev->dev, "Device registration failed\n");

View File

@ -513,6 +513,32 @@ octeon_droq_refill(struct octeon_device *octeon_dev, struct octeon_droq *droq)
return desc_refilled;
}
/** check if we can allocate packets to get out of oom.
* @param droq - Droq being checked.
* @return does not return anything
*/
void octeon_droq_check_oom(struct octeon_droq *droq)
{
int desc_refilled;
struct octeon_device *oct = droq->oct_dev;
if (readl(droq->pkts_credit_reg) <= CN23XX_SLI_DEF_BP) {
spin_lock_bh(&droq->lock);
desc_refilled = octeon_droq_refill(oct, droq);
if (desc_refilled) {
/* Flush the droq descriptor data to memory to be sure
* that when we update the credits the data in memory
* is accurate.
*/
wmb();
writel(desc_refilled, droq->pkts_credit_reg);
/* make sure mmio write completes */
mmiowb();
}
spin_unlock_bh(&droq->lock);
}
}
static inline u32
octeon_droq_get_bufcount(u32 buf_size, u32 total_len)
{

View File

@ -426,4 +426,6 @@ int octeon_droq_process_packets(struct octeon_device *oct,
int octeon_process_droq_poll_cmd(struct octeon_device *oct, u32 q_no,
int cmd, u32 arg);
void octeon_droq_check_oom(struct octeon_droq *droq);
#endif /*__OCTEON_DROQ_H__ */

View File

@ -129,6 +129,9 @@ struct lio {
/* work queue for txq status */
struct cavium_wq txq_status_wq;
/* work queue for rxq oom status */
struct cavium_wq rxq_status_wq;
/* work queue for link status */
struct cavium_wq link_status_wq;
@ -152,6 +155,10 @@ struct lio {
*/
int liquidio_set_feature(struct net_device *netdev, int cmd, u16 param1);
int setup_rx_oom_poll_fn(struct net_device *netdev);
void cleanup_rx_oom_poll_fn(struct net_device *netdev);
/**
* \brief Link control command completion callback
* @param nctrl_ptr pointer to control packet structure