return rc;
}
+static void bnge_timer(struct timer_list *t)
+{
+ struct bnge_net *bn = timer_container_of(bn, t, timer);
+ struct bnge_dev *bd = bn->bd;
+
+ if (!netif_running(bn->netdev) ||
+ !test_bit(BNGE_STATE_OPEN, &bd->state))
+ return;
+
+ /* Periodic work added by later patches */
+
+ mod_timer(&bn->timer, jiffies + bn->current_interval);
+}
+
+static void bnge_sp_task(struct work_struct *work)
+{
+ struct bnge_net *bn = container_of(work, struct bnge_net, sp_task);
+ struct bnge_dev *bd = bn->bd;
+
+ netdev_lock(bn->netdev);
+ if (!test_bit(BNGE_STATE_OPEN, &bd->state)) {
+ netdev_unlock(bn->netdev);
+ return;
+ }
+
+ /* Event handling work added by later patches */
+
+ netdev_unlock(bn->netdev);
+}
+
static void bnge_free_nq_desc_arr(struct bnge_nq_ring_info *nqr)
{
struct bnge_ring_struct *ring = &nqr->ring_struct;
bnge_enable_int(bn);
bnge_tx_enable(bn);
+
+ mod_timer(&bn->timer, jiffies + bn->current_interval);
+
return 0;
err_free_irq:
bnge_tx_disable(bn);
clear_bit(BNGE_STATE_OPEN, &bd->state);
+
+ timer_delete_sync(&bn->timer);
bnge_shutdown_nic(bn);
bnge_disable_napi(bn);
bnge_free_all_rings_bufs(bn);
if (bd->tso_max_segs)
netif_set_tso_max_segs(netdev, bd->tso_max_segs);
+ INIT_WORK(&bn->sp_task, bnge_sp_task);
+ timer_setup(&bn->timer, bnge_timer, 0);
+ bn->current_interval = BNGE_TIMER_INTERVAL;
+
+ bn->bnge_pf_wq = alloc_ordered_workqueue("bnge_pf_wq-%s", 0,
+ dev_name(bd->dev));
+ if (!bn->bnge_pf_wq) {
+ netdev_err(netdev, "Unable to create workqueue.\n");
+ rc = -ENOMEM;
+ goto err_netdev;
+ }
+
bn->rx_ring_size = BNGE_DEFAULT_RX_RING_SIZE;
bn->tx_ring_size = BNGE_DEFAULT_TX_RING_SIZE;
bn->rx_dir = DMA_FROM_DEVICE;
rc = register_netdev(netdev);
if (rc) {
dev_err(bd->dev, "Register netdev failed rc: %d\n", rc);
- goto err_netdev;
+ goto err_free_workq;
}
return 0;
+err_free_workq:
+ destroy_workqueue(bn->bnge_pf_wq);
err_netdev:
free_netdev(netdev);
return rc;
void bnge_netdev_free(struct bnge_dev *bd)
{
struct net_device *netdev = bd->netdev;
+ struct bnge_net *bn;
+
+ bn = netdev_priv(netdev);
unregister_netdev(netdev);
+
+ timer_shutdown_sync(&bn->timer);
+ cancel_work_sync(&bn->sp_task);
+ destroy_workqueue(bn->bnge_pf_wq);
+
free_netdev(netdev);
bd->netdev = NULL;
}
#define BNGE_NQ_HDL_TYPE(hdl) (((hdl) & BNGE_NQ_HDL_TYPE_MASK) >> \
BNGE_NQ_HDL_TYPE_SHIFT)
+enum bnge_net_state {
+ BNGE_STATE_NAPI_DISABLED,
+};
+
+#define BNGE_TIMER_INTERVAL HZ
+
struct bnge_net {
struct bnge_dev *bd;
struct net_device *netdev;
u32 stats_coal_ticks;
unsigned long state;
-#define BNGE_STATE_NAPI_DISABLED 0
u32 msg_enable;
u16 max_tpa;
__be16 vxlan_port;
__be16 nge_port;
__be16 vxlan_gpe_port;
+
+ unsigned int current_interval;
+ struct timer_list timer;
+ struct workqueue_struct *bnge_pf_wq;
+ struct work_struct sp_task;
};
#define BNGE_DEFAULT_RX_RING_SIZE 511