Commit 5545b7b9 authored by Haijun Liu's avatar Haijun Liu Committed by David S. Miller

net: wwan: t7xx: Add NAPI support

Replace the work queue based RX flow with a NAPI implementation
Remove rx_thread and dpmaif_rxq_work.
Enable GRO on RX path.
Introduce dummy network device. its responsibility is
    - Binds one NAPI object for each DL HW queue and acts as
      the agent of all those network devices.
    - Use NAPI object to poll DL packets.
    - Helps to dispatch each packet to the network interface.
Signed-off-by: default avatarHaijun Liu <haijun.liu@mediatek.com>
Co-developed-by: default avatarSreehari Kancharla <sreehari.kancharla@linux.intel.com>
Signed-off-by: default avatarSreehari Kancharla <sreehari.kancharla@linux.intel.com>
Signed-off-by: default avatarChandrashekar Devegowda <chandrashekar.devegowda@intel.com>
Acked-by: default avatarRicardo Martinez <ricardo.martinez@linux.intel.com>
Acked-by: default avatarM Chetan Kumar <m.chetan.kumar@linux.intel.com>
Reviewed-by: default avatarIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent c053d7b6
......@@ -20,6 +20,7 @@
#include <linux/bitmap.h>
#include <linux/mm_types.h>
#include <linux/netdevice.h>
#include <linux/sched.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
......@@ -109,20 +110,14 @@ struct dpmaif_rx_queue {
struct dpmaif_bat_request *bat_req;
struct dpmaif_bat_request *bat_frag;
wait_queue_head_t rx_wq;
struct task_struct *rx_thread;
struct sk_buff_head skb_list;
unsigned int skb_list_max_len;
struct workqueue_struct *worker;
struct work_struct dpmaif_rxq_work;
atomic_t rx_processing;
struct dpmaif_ctrl *dpmaif_ctrl;
unsigned int expect_pit_seq;
unsigned int pit_remain_release_cnt;
struct dpmaif_cur_rx_skb_info rx_data_info;
struct napi_struct napi;
bool sleep_lock_pending;
};
struct dpmaif_tx_queue {
......@@ -168,7 +163,8 @@ enum dpmaif_txq_state {
struct dpmaif_callbacks {
void (*state_notify)(struct t7xx_pci_dev *t7xx_dev,
enum dpmaif_txq_state state, int txq_number);
void (*recv_skb)(struct t7xx_pci_dev *t7xx_dev, struct sk_buff *skb);
void (*recv_skb)(struct t7xx_ccmni_ctrl *ccmni_ctlb, struct sk_buff *skb,
struct napi_struct *napi);
};
struct dpmaif_ctrl {
......
This diff is collapsed.
......@@ -112,5 +112,6 @@ int t7xx_dpmaif_bat_alloc(const struct dpmaif_ctrl *dpmaif_ctrl, struct dpmaif_b
const enum bat_type buf_type);
void t7xx_dpmaif_bat_free(const struct dpmaif_ctrl *dpmaif_ctrl,
struct dpmaif_bat_request *bat_req);
int t7xx_dpmaif_napi_rx_poll(struct napi_struct *napi, const int budget);
#endif /* __T7XX_HIF_DPMA_RX_H__ */
......@@ -22,6 +22,7 @@
#include <linux/gfp.h>
#include <linux/if_arp.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/netdev_features.h>
......@@ -29,6 +30,7 @@
#include <linux/skbuff.h>
#include <linux/types.h>
#include <linux/wwan.h>
#include <net/ipv6.h>
#include <net/pkt_sched.h>
#include "t7xx_hif_dpmaif_rx.h"
......@@ -39,13 +41,47 @@
#include "t7xx_state_monitor.h"
#define IP_MUX_SESSION_DEFAULT 0
#define SBD_PACKET_TYPE_MASK GENMASK(7, 4)
static void t7xx_ccmni_enable_napi(struct t7xx_ccmni_ctrl *ctlb)
{
int i;
if (ctlb->is_napi_en)
return;
for (i = 0; i < RXQ_NUM; i++) {
napi_enable(ctlb->napi[i]);
napi_schedule(ctlb->napi[i]);
}
ctlb->is_napi_en = true;
}
static void t7xx_ccmni_disable_napi(struct t7xx_ccmni_ctrl *ctlb)
{
int i;
if (!ctlb->is_napi_en)
return;
for (i = 0; i < RXQ_NUM; i++) {
napi_synchronize(ctlb->napi[i]);
napi_disable(ctlb->napi[i]);
}
ctlb->is_napi_en = false;
}
static int t7xx_ccmni_open(struct net_device *dev)
{
struct t7xx_ccmni *ccmni = wwan_netdev_drvpriv(dev);
struct t7xx_ccmni_ctrl *ccmni_ctl = ccmni->ctlb;
netif_carrier_on(dev);
netif_tx_start_all_queues(dev);
if (!atomic_fetch_inc(&ccmni_ctl->napi_usr_refcnt))
t7xx_ccmni_enable_napi(ccmni_ctl);
atomic_inc(&ccmni->usage);
return 0;
}
......@@ -53,8 +89,12 @@ static int t7xx_ccmni_open(struct net_device *dev)
static int t7xx_ccmni_close(struct net_device *dev)
{
struct t7xx_ccmni *ccmni = wwan_netdev_drvpriv(dev);
struct t7xx_ccmni_ctrl *ccmni_ctl = ccmni->ctlb;
atomic_dec(&ccmni->usage);
if (atomic_dec_and_test(&ccmni_ctl->napi_usr_refcnt))
t7xx_ccmni_disable_napi(ccmni_ctl);
netif_carrier_off(dev);
netif_tx_disable(dev);
return 0;
......@@ -127,6 +167,9 @@ static void t7xx_ccmni_start(struct t7xx_ccmni_ctrl *ctlb)
netif_carrier_on(ccmni->dev);
}
}
if (atomic_read(&ctlb->napi_usr_refcnt))
t7xx_ccmni_enable_napi(ctlb);
}
static void t7xx_ccmni_pre_stop(struct t7xx_ccmni_ctrl *ctlb)
......@@ -149,6 +192,9 @@ static void t7xx_ccmni_post_stop(struct t7xx_ccmni_ctrl *ctlb)
struct t7xx_ccmni *ccmni;
int i;
if (atomic_read(&ctlb->napi_usr_refcnt))
t7xx_ccmni_disable_napi(ctlb);
for (i = 0; i < ctlb->nic_dev_num; i++) {
ccmni = ctlb->ccmni_inst[i];
if (!ccmni)
......@@ -183,6 +229,9 @@ static void t7xx_ccmni_wwan_setup(struct net_device *dev)
dev->features |= NETIF_F_RXCSUM;
dev->hw_features |= NETIF_F_RXCSUM;
dev->features |= NETIF_F_GRO;
dev->hw_features |= NETIF_F_GRO;
dev->needs_free_netdev = true;
dev->type = ARPHRD_NONE;
......@@ -190,6 +239,34 @@ static void t7xx_ccmni_wwan_setup(struct net_device *dev)
dev->netdev_ops = &ccmni_netdev_ops;
}
static void t7xx_init_netdev_napi(struct t7xx_ccmni_ctrl *ctlb)
{
int i;
/* one HW, but shared with multiple net devices,
* so add a dummy device for NAPI.
*/
init_dummy_netdev(&ctlb->dummy_dev);
atomic_set(&ctlb->napi_usr_refcnt, 0);
ctlb->is_napi_en = false;
for (i = 0; i < RXQ_NUM; i++) {
ctlb->napi[i] = &ctlb->hif_ctrl->rxq[i].napi;
netif_napi_add_weight(&ctlb->dummy_dev, ctlb->napi[i], t7xx_dpmaif_napi_rx_poll,
NIC_NAPI_POLL_BUDGET);
}
}
static void t7xx_uninit_netdev_napi(struct t7xx_ccmni_ctrl *ctlb)
{
int i;
for (i = 0; i < RXQ_NUM; i++) {
netif_napi_del(ctlb->napi[i]);
ctlb->napi[i] = NULL;
}
}
static int t7xx_ccmni_wwan_newlink(void *ctxt, struct net_device *dev, u32 if_id,
struct netlink_ext_ack *extack)
{
......@@ -311,7 +388,8 @@ static void init_md_status_notifier(struct t7xx_pci_dev *t7xx_dev)
t7xx_fsm_notifier_register(t7xx_dev->md, md_status_notifier);
}
static void t7xx_ccmni_recv_skb(struct t7xx_pci_dev *t7xx_dev, struct sk_buff *skb)
static void t7xx_ccmni_recv_skb(struct t7xx_ccmni_ctrl *ccmni_ctlb, struct sk_buff *skb,
struct napi_struct *napi)
{
struct t7xx_skb_cb *skb_cb;
struct net_device *net_dev;
......@@ -321,23 +399,22 @@ static void t7xx_ccmni_recv_skb(struct t7xx_pci_dev *t7xx_dev, struct sk_buff *s
skb_cb = T7XX_SKB_CB(skb);
netif_id = skb_cb->netif_idx;
ccmni = t7xx_dev->ccmni_ctlb->ccmni_inst[netif_id];
ccmni = ccmni_ctlb->ccmni_inst[netif_id];
if (!ccmni) {
dev_kfree_skb(skb);
return;
}
net_dev = ccmni->dev;
skb->dev = net_dev;
pkt_type = skb_cb->rx_pkt_type;
skb->dev = net_dev;
if (pkt_type == PKT_TYPE_IP6)
skb->protocol = htons(ETH_P_IPV6);
else
skb->protocol = htons(ETH_P_IP);
skb_len = skb->len;
netif_rx(skb);
napi_gro_receive(napi, skb);
net_dev->stats.rx_packets++;
net_dev->stats.rx_bytes += skb_len;
}
......@@ -404,6 +481,7 @@ int t7xx_ccmni_init(struct t7xx_pci_dev *t7xx_dev)
if (!ctlb->hif_ctrl)
return -ENOMEM;
t7xx_init_netdev_napi(ctlb);
init_md_status_notifier(t7xx_dev);
return 0;
}
......@@ -419,5 +497,6 @@ void t7xx_ccmni_exit(struct t7xx_pci_dev *t7xx_dev)
ctlb->wwan_is_registered = false;
}
t7xx_uninit_netdev_napi(ctlb);
t7xx_dpmaif_hif_exit(ctlb->hif_ctrl);
}
......@@ -30,6 +30,7 @@
#define CCMNI_NETDEV_WDT_TO (1 * HZ)
#define CCMNI_MTU_MAX 3000
#define NIC_NAPI_POLL_BUDGET 128
struct t7xx_ccmni {
u8 index;
......@@ -47,6 +48,10 @@ struct t7xx_ccmni_ctrl {
unsigned int md_sta;
struct t7xx_fsm_notifier md_status_notify;
bool wwan_is_registered;
struct net_device dummy_dev;
struct napi_struct *napi[RXQ_NUM];
atomic_t napi_usr_refcnt;
bool is_napi_en;
};
int t7xx_ccmni_init(struct t7xx_pci_dev *t7xx_dev);
......
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