summaryrefslogtreecommitdiff
path: root/drivers/net/wwan
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wwan')
-rw-r--r--drivers/net/wwan/Kconfig1
-rw-r--r--drivers/net/wwan/iosm/iosm_ipc_chnl_cfg.c2
-rw-r--r--drivers/net/wwan/mhi_wwan_mbim.c8
-rw-r--r--drivers/net/wwan/t7xx/Makefile3
-rw-r--r--drivers/net/wwan/t7xx/t7xx_hif_cldma.c2
-rw-r--r--drivers/net/wwan/t7xx/t7xx_hif_dpmaif.h14
-rw-r--r--drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.c218
-rw-r--r--drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.h1
-rw-r--r--drivers/net/wwan/t7xx/t7xx_netdev.c91
-rw-r--r--drivers/net/wwan/t7xx/t7xx_netdev.h5
-rw-r--r--drivers/net/wwan/t7xx/t7xx_pci.h3
-rw-r--r--drivers/net/wwan/t7xx/t7xx_port.h9
-rw-r--r--drivers/net/wwan/t7xx/t7xx_port_proxy.c12
-rw-r--r--drivers/net/wwan/t7xx/t7xx_port_proxy.h4
-rw-r--r--drivers/net/wwan/t7xx/t7xx_port_trace.c116
-rw-r--r--drivers/net/wwan/t7xx/t7xx_port_wwan.c16
-rw-r--r--drivers/net/wwan/wwan_core.c6
17 files changed, 329 insertions, 182 deletions
diff --git a/drivers/net/wwan/Kconfig b/drivers/net/wwan/Kconfig
index ac4d73b5626f..410b0245114e 100644
--- a/drivers/net/wwan/Kconfig
+++ b/drivers/net/wwan/Kconfig
@@ -108,6 +108,7 @@ config IOSM
config MTK_T7XX
tristate "MediaTek PCIe 5G WWAN modem T7xx device"
depends on PCI
+ select RELAY if WWAN_DEBUGFS
help
Enables MediaTek PCIe based 5G WWAN modem (T7xx series) device.
Adapts WWAN framework and provides network interface like wwan0
diff --git a/drivers/net/wwan/iosm/iosm_ipc_chnl_cfg.c b/drivers/net/wwan/iosm/iosm_ipc_chnl_cfg.c
index 128c999e08bb..bcfbc6b3d617 100644
--- a/drivers/net/wwan/iosm/iosm_ipc_chnl_cfg.c
+++ b/drivers/net/wwan/iosm/iosm_ipc_chnl_cfg.c
@@ -39,7 +39,7 @@ static struct ipc_chnl_cfg modem_cfg[] = {
/* RPC - 0 */
{ IPC_MEM_CTRL_CHL_ID_1, IPC_MEM_PIPE_2, IPC_MEM_PIPE_3,
IPC_MEM_MAX_TDS_RPC, IPC_MEM_MAX_TDS_RPC,
- IPC_MEM_MAX_DL_RPC_BUF_SIZE, WWAN_PORT_UNKNOWN },
+ IPC_MEM_MAX_DL_RPC_BUF_SIZE, WWAN_PORT_XMMRPC },
/* IAT0 */
{ IPC_MEM_CTRL_CHL_ID_2, IPC_MEM_PIPE_4, IPC_MEM_PIPE_5,
IPC_MEM_MAX_TDS_AT, IPC_MEM_MAX_TDS_AT, IPC_MEM_MAX_DL_AT_BUF_SIZE,
diff --git a/drivers/net/wwan/mhi_wwan_mbim.c b/drivers/net/wwan/mhi_wwan_mbim.c
index ef70bb7c88ad..3f72ae943b29 100644
--- a/drivers/net/wwan/mhi_wwan_mbim.c
+++ b/drivers/net/wwan/mhi_wwan_mbim.c
@@ -456,19 +456,19 @@ static void mhi_mbim_ndo_get_stats64(struct net_device *ndev,
unsigned int start;
do {
- start = u64_stats_fetch_begin_irq(&link->rx_syncp);
+ start = u64_stats_fetch_begin(&link->rx_syncp);
stats->rx_packets = u64_stats_read(&link->rx_packets);
stats->rx_bytes = u64_stats_read(&link->rx_bytes);
stats->rx_errors = u64_stats_read(&link->rx_errors);
- } while (u64_stats_fetch_retry_irq(&link->rx_syncp, start));
+ } while (u64_stats_fetch_retry(&link->rx_syncp, start));
do {
- start = u64_stats_fetch_begin_irq(&link->tx_syncp);
+ start = u64_stats_fetch_begin(&link->tx_syncp);
stats->tx_packets = u64_stats_read(&link->tx_packets);
stats->tx_bytes = u64_stats_read(&link->tx_bytes);
stats->tx_errors = u64_stats_read(&link->tx_errors);
stats->tx_dropped = u64_stats_read(&link->tx_dropped);
- } while (u64_stats_fetch_retry_irq(&link->tx_syncp, start));
+ } while (u64_stats_fetch_retry(&link->tx_syncp, start));
}
static void mhi_mbim_ul_callback(struct mhi_device *mhi_dev,
diff --git a/drivers/net/wwan/t7xx/Makefile b/drivers/net/wwan/t7xx/Makefile
index dc6a7d682c15..268ff9e87e5b 100644
--- a/drivers/net/wwan/t7xx/Makefile
+++ b/drivers/net/wwan/t7xx/Makefile
@@ -18,3 +18,6 @@ mtk_t7xx-y:= t7xx_pci.o \
t7xx_hif_dpmaif_rx.o \
t7xx_dpmaif.o \
t7xx_netdev.o
+
+mtk_t7xx-$(CONFIG_WWAN_DEBUGFS) += \
+ t7xx_port_trace.o \
diff --git a/drivers/net/wwan/t7xx/t7xx_hif_cldma.c b/drivers/net/wwan/t7xx/t7xx_hif_cldma.c
index 6ff30cb8eb16..aec3a18d44bd 100644
--- a/drivers/net/wwan/t7xx/t7xx_hif_cldma.c
+++ b/drivers/net/wwan/t7xx/t7xx_hif_cldma.c
@@ -1018,6 +1018,8 @@ static int t7xx_cldma_late_init(struct cldma_ctrl *md_ctrl)
dev_err(md_ctrl->dev, "control TX ring init fail\n");
goto err_free_tx_ring;
}
+
+ md_ctrl->tx_ring[i].pkt_size = CLDMA_MTU;
}
for (j = 0; j < CLDMA_RXQ_NUM; j++) {
diff --git a/drivers/net/wwan/t7xx/t7xx_hif_dpmaif.h b/drivers/net/wwan/t7xx/t7xx_hif_dpmaif.h
index 1225ca0ed51e..0ce4505e813d 100644
--- a/drivers/net/wwan/t7xx/t7xx_hif_dpmaif.h
+++ b/drivers/net/wwan/t7xx/t7xx_hif_dpmaif.h
@@ -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 {
diff --git a/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.c b/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.c
index 91a0eb19e0d8..aa2174a10437 100644
--- a/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.c
+++ b/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.c
@@ -45,6 +45,7 @@
#include "t7xx_dpmaif.h"
#include "t7xx_hif_dpmaif.h"
#include "t7xx_hif_dpmaif_rx.h"
+#include "t7xx_netdev.h"
#include "t7xx_pci.h"
#define DPMAIF_BAT_COUNT 8192
@@ -76,43 +77,6 @@ static unsigned int t7xx_normal_pit_bid(const struct dpmaif_pit *pit_info)
return value;
}
-static int t7xx_dpmaif_net_rx_push_thread(void *arg)
-{
- struct dpmaif_rx_queue *q = arg;
- struct dpmaif_ctrl *hif_ctrl;
- struct dpmaif_callbacks *cb;
-
- hif_ctrl = q->dpmaif_ctrl;
- cb = hif_ctrl->callbacks;
-
- while (!kthread_should_stop()) {
- struct sk_buff *skb;
- unsigned long flags;
-
- if (skb_queue_empty(&q->skb_list)) {
- if (wait_event_interruptible(q->rx_wq,
- !skb_queue_empty(&q->skb_list) ||
- kthread_should_stop()))
- continue;
-
- if (kthread_should_stop())
- break;
- }
-
- spin_lock_irqsave(&q->skb_list.lock, flags);
- skb = __skb_dequeue(&q->skb_list);
- spin_unlock_irqrestore(&q->skb_list.lock, flags);
-
- if (!skb)
- continue;
-
- cb->recv_skb(hif_ctrl->t7xx_dev, skb);
- cond_resched();
- }
-
- return 0;
-}
-
static int t7xx_dpmaif_update_bat_wr_idx(struct dpmaif_ctrl *dpmaif_ctrl,
const unsigned int q_num, const unsigned int bat_cnt)
{
@@ -726,21 +690,10 @@ static int t7xx_dpmaifq_rx_notify_hw(struct dpmaif_rx_queue *rxq)
return ret;
}
-static void t7xx_dpmaif_rx_skb_enqueue(struct dpmaif_rx_queue *rxq, struct sk_buff *skb)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&rxq->skb_list.lock, flags);
- if (rxq->skb_list.qlen < rxq->skb_list_max_len)
- __skb_queue_tail(&rxq->skb_list, skb);
- else
- dev_kfree_skb_any(skb);
- spin_unlock_irqrestore(&rxq->skb_list.lock, flags);
-}
-
static void t7xx_dpmaif_rx_skb(struct dpmaif_rx_queue *rxq,
struct dpmaif_cur_rx_skb_info *skb_info)
{
+ struct dpmaif_ctrl *dpmaif_ctrl = rxq->dpmaif_ctrl;
struct sk_buff *skb = skb_info->cur_skb;
struct t7xx_skb_cb *skb_cb;
u8 netif_id;
@@ -758,11 +711,11 @@ static void t7xx_dpmaif_rx_skb(struct dpmaif_rx_queue *rxq,
skb_cb = T7XX_SKB_CB(skb);
skb_cb->netif_idx = netif_id;
skb_cb->rx_pkt_type = skb_info->pkt_type;
- t7xx_dpmaif_rx_skb_enqueue(rxq, skb);
+ dpmaif_ctrl->callbacks->recv_skb(dpmaif_ctrl->t7xx_dev->ccmni_ctlb, skb, &rxq->napi);
}
static int t7xx_dpmaif_rx_start(struct dpmaif_rx_queue *rxq, const unsigned int pit_cnt,
- const unsigned long timeout)
+ const unsigned int budget, int *once_more)
{
unsigned int cur_pit, pit_len, rx_cnt, recv_skb_cnt = 0;
struct device *dev = rxq->dpmaif_ctrl->dev;
@@ -777,13 +730,14 @@ static int t7xx_dpmaif_rx_start(struct dpmaif_rx_queue *rxq, const unsigned int
struct dpmaif_pit *pkt_info;
u32 val;
- if (!skb_info->msg_pit_received && time_after_eq(jiffies, timeout))
+ if (!skb_info->msg_pit_received && recv_skb_cnt >= budget)
break;
pkt_info = (struct dpmaif_pit *)rxq->pit_base + cur_pit;
if (t7xx_dpmaif_check_pit_seq(rxq, pkt_info)) {
dev_err_ratelimited(dev, "RXQ%u checks PIT SEQ fail\n", rxq->index);
- return -EAGAIN;
+ *once_more = 1;
+ return recv_skb_cnt;
}
val = FIELD_GET(PD_PIT_PACKET_TYPE, le32_to_cpu(pkt_info->header));
@@ -817,12 +771,7 @@ static int t7xx_dpmaif_rx_start(struct dpmaif_rx_queue *rxq, const unsigned int
}
memset(skb_info, 0, sizeof(*skb_info));
-
recv_skb_cnt++;
- if (!(recv_skb_cnt & DPMAIF_RX_PUSH_THRESHOLD_MASK)) {
- wake_up_all(&rxq->rx_wq);
- recv_skb_cnt = 0;
- }
}
}
@@ -837,16 +786,13 @@ static int t7xx_dpmaif_rx_start(struct dpmaif_rx_queue *rxq, const unsigned int
}
}
- if (recv_skb_cnt)
- wake_up_all(&rxq->rx_wq);
-
if (!ret)
ret = t7xx_dpmaifq_rx_notify_hw(rxq);
if (ret)
return ret;
- return rx_cnt;
+ return recv_skb_cnt;
}
static unsigned int t7xx_dpmaifq_poll_pit(struct dpmaif_rx_queue *rxq)
@@ -863,53 +809,30 @@ static unsigned int t7xx_dpmaifq_poll_pit(struct dpmaif_rx_queue *rxq)
return pit_cnt;
}
-static int t7xx_dpmaif_rx_data_collect(struct dpmaif_ctrl *dpmaif_ctrl,
- const unsigned int q_num, const unsigned int budget)
+static int t7xx_dpmaif_napi_rx_data_collect(struct dpmaif_ctrl *dpmaif_ctrl,
+ const unsigned int q_num,
+ const unsigned int budget, int *once_more)
{
struct dpmaif_rx_queue *rxq = &dpmaif_ctrl->rxq[q_num];
- unsigned long time_limit;
unsigned int cnt;
+ int ret = 0;
- time_limit = jiffies + msecs_to_jiffies(DPMAIF_WQ_TIME_LIMIT_MS);
-
- while ((cnt = t7xx_dpmaifq_poll_pit(rxq))) {
- unsigned int rd_cnt;
- int real_cnt;
-
- rd_cnt = min(cnt, budget);
-
- real_cnt = t7xx_dpmaif_rx_start(rxq, rd_cnt, time_limit);
- if (real_cnt < 0)
- return real_cnt;
-
- if (real_cnt < cnt)
- return -EAGAIN;
- }
-
- return 0;
-}
+ cnt = t7xx_dpmaifq_poll_pit(rxq);
+ if (!cnt)
+ return ret;
-static void t7xx_dpmaif_do_rx(struct dpmaif_ctrl *dpmaif_ctrl, struct dpmaif_rx_queue *rxq)
-{
- struct dpmaif_hw_info *hw_info = &dpmaif_ctrl->hw_info;
- int ret;
+ ret = t7xx_dpmaif_rx_start(rxq, cnt, budget, once_more);
+ if (ret < 0)
+ dev_err(dpmaif_ctrl->dev, "dlq%u rx ERR:%d\n", rxq->index, ret);
- ret = t7xx_dpmaif_rx_data_collect(dpmaif_ctrl, rxq->index, rxq->budget);
- if (ret < 0) {
- /* Try one more time */
- queue_work(rxq->worker, &rxq->dpmaif_rxq_work);
- t7xx_dpmaif_clr_ip_busy_sts(hw_info);
- } else {
- t7xx_dpmaif_clr_ip_busy_sts(hw_info);
- t7xx_dpmaif_dlq_unmask_rx_done(hw_info, rxq->index);
- }
+ return ret;
}
-static void t7xx_dpmaif_rxq_work(struct work_struct *work)
+int t7xx_dpmaif_napi_rx_poll(struct napi_struct *napi, const int budget)
{
- struct dpmaif_rx_queue *rxq = container_of(work, struct dpmaif_rx_queue, dpmaif_rxq_work);
- struct dpmaif_ctrl *dpmaif_ctrl = rxq->dpmaif_ctrl;
- int ret;
+ struct dpmaif_rx_queue *rxq = container_of(napi, struct dpmaif_rx_queue, napi);
+ struct t7xx_pci_dev *t7xx_dev = rxq->dpmaif_ctrl->t7xx_dev;
+ int ret, once_more = 0, work_done = 0;
atomic_set(&rxq->rx_processing, 1);
/* Ensure rx_processing is changed to 1 before actually begin RX flow */
@@ -917,22 +840,52 @@ static void t7xx_dpmaif_rxq_work(struct work_struct *work)
if (!rxq->que_started) {
atomic_set(&rxq->rx_processing, 0);
- dev_err(dpmaif_ctrl->dev, "Work RXQ: %d has not been started\n", rxq->index);
- return;
+ dev_err(rxq->dpmaif_ctrl->dev, "Work RXQ: %d has not been started\n", rxq->index);
+ return work_done;
}
- ret = pm_runtime_resume_and_get(dpmaif_ctrl->dev);
- if (ret < 0 && ret != -EACCES)
- return;
+ if (!rxq->sleep_lock_pending) {
+ pm_runtime_get_noresume(rxq->dpmaif_ctrl->dev);
+ t7xx_pci_disable_sleep(t7xx_dev);
+ }
- t7xx_pci_disable_sleep(dpmaif_ctrl->t7xx_dev);
- if (t7xx_pci_sleep_disable_complete(dpmaif_ctrl->t7xx_dev))
- t7xx_dpmaif_do_rx(dpmaif_ctrl, rxq);
+ ret = try_wait_for_completion(&t7xx_dev->sleep_lock_acquire);
+ if (!ret) {
+ napi_complete_done(napi, work_done);
+ rxq->sleep_lock_pending = true;
+ napi_reschedule(napi);
+ return work_done;
+ }
- t7xx_pci_enable_sleep(dpmaif_ctrl->t7xx_dev);
- pm_runtime_mark_last_busy(dpmaif_ctrl->dev);
- pm_runtime_put_autosuspend(dpmaif_ctrl->dev);
+ rxq->sleep_lock_pending = false;
+ while (work_done < budget) {
+ int each_budget = budget - work_done;
+ int rx_cnt = t7xx_dpmaif_napi_rx_data_collect(rxq->dpmaif_ctrl, rxq->index,
+ each_budget, &once_more);
+ if (rx_cnt > 0)
+ work_done += rx_cnt;
+ else
+ break;
+ }
+
+ if (once_more) {
+ napi_gro_flush(napi, false);
+ work_done = budget;
+ t7xx_dpmaif_clr_ip_busy_sts(&rxq->dpmaif_ctrl->hw_info);
+ } else if (work_done < budget) {
+ napi_complete_done(napi, work_done);
+ t7xx_dpmaif_clr_ip_busy_sts(&rxq->dpmaif_ctrl->hw_info);
+ t7xx_dpmaif_dlq_unmask_rx_done(&rxq->dpmaif_ctrl->hw_info, rxq->index);
+ } else {
+ t7xx_dpmaif_clr_ip_busy_sts(&rxq->dpmaif_ctrl->hw_info);
+ }
+
+ t7xx_pci_enable_sleep(rxq->dpmaif_ctrl->t7xx_dev);
+ pm_runtime_mark_last_busy(rxq->dpmaif_ctrl->dev);
+ pm_runtime_put_noidle(rxq->dpmaif_ctrl->dev);
atomic_set(&rxq->rx_processing, 0);
+
+ return work_done;
}
void t7xx_dpmaif_irq_rx_done(struct dpmaif_ctrl *dpmaif_ctrl, const unsigned int que_mask)
@@ -947,7 +900,7 @@ void t7xx_dpmaif_irq_rx_done(struct dpmaif_ctrl *dpmaif_ctrl, const unsigned int
}
rxq = &dpmaif_ctrl->rxq[qno];
- queue_work(rxq->worker, &rxq->dpmaif_rxq_work);
+ napi_schedule(&rxq->napi);
}
static void t7xx_dpmaif_base_free(const struct dpmaif_ctrl *dpmaif_ctrl,
@@ -1082,50 +1035,14 @@ int t7xx_dpmaif_rxq_init(struct dpmaif_rx_queue *queue)
int ret;
ret = t7xx_dpmaif_rx_alloc(queue);
- if (ret < 0) {
+ if (ret < 0)
dev_err(queue->dpmaif_ctrl->dev, "Failed to allocate RX buffers: %d\n", ret);
- return ret;
- }
-
- INIT_WORK(&queue->dpmaif_rxq_work, t7xx_dpmaif_rxq_work);
-
- queue->worker = alloc_workqueue("dpmaif_rx%d_worker",
- WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_HIGHPRI, 1, queue->index);
- if (!queue->worker) {
- ret = -ENOMEM;
- goto err_free_rx_buffer;
- }
-
- init_waitqueue_head(&queue->rx_wq);
- skb_queue_head_init(&queue->skb_list);
- queue->skb_list_max_len = queue->bat_req->pkt_buf_sz;
- queue->rx_thread = kthread_run(t7xx_dpmaif_net_rx_push_thread,
- queue, "dpmaif_rx%d_push", queue->index);
-
- ret = PTR_ERR_OR_ZERO(queue->rx_thread);
- if (ret)
- goto err_free_workqueue;
-
- return 0;
-
-err_free_workqueue:
- destroy_workqueue(queue->worker);
-
-err_free_rx_buffer:
- t7xx_dpmaif_rx_buf_free(queue);
return ret;
}
void t7xx_dpmaif_rxq_free(struct dpmaif_rx_queue *queue)
{
- if (queue->worker)
- destroy_workqueue(queue->worker);
-
- if (queue->rx_thread)
- kthread_stop(queue->rx_thread);
-
- skb_queue_purge(&queue->skb_list);
t7xx_dpmaif_rx_buf_free(queue);
}
@@ -1188,8 +1105,6 @@ void t7xx_dpmaif_rx_stop(struct dpmaif_ctrl *dpmaif_ctrl)
struct dpmaif_rx_queue *rxq = &dpmaif_ctrl->rxq[i];
int timeout, value;
- flush_work(&rxq->dpmaif_rxq_work);
-
timeout = readx_poll_timeout_atomic(atomic_read, &rxq->rx_processing, value,
!value, 0, DPMAIF_CHECK_INIT_TIMEOUT_US);
if (timeout)
@@ -1205,7 +1120,6 @@ static void t7xx_dpmaif_stop_rxq(struct dpmaif_rx_queue *rxq)
{
int cnt, j = 0;
- flush_work(&rxq->dpmaif_rxq_work);
rxq->que_started = false;
do {
diff --git a/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.h b/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.h
index 182f62dfe398..f4e1b69ad426 100644
--- a/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.h
+++ b/drivers/net/wwan/t7xx/t7xx_hif_dpmaif_rx.h
@@ -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__ */
diff --git a/drivers/net/wwan/t7xx/t7xx_netdev.c b/drivers/net/wwan/t7xx/t7xx_netdev.c
index f71d3bc3b237..494a28e386a3 100644
--- a/drivers/net/wwan/t7xx/t7xx_netdev.c
+++ b/drivers/net/wwan/t7xx/t7xx_netdev.c
@@ -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)
@@ -161,7 +207,7 @@ static void t7xx_ccmni_post_stop(struct t7xx_ccmni_ctrl *ctlb)
static void t7xx_ccmni_wwan_setup(struct net_device *dev)
{
- dev->hard_header_len += sizeof(struct ccci_header);
+ dev->needed_headroom += sizeof(struct ccci_header);
dev->mtu = ETH_DATA_LEN;
dev->max_mtu = CCMNI_MTU_MAX;
@@ -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);
}
diff --git a/drivers/net/wwan/t7xx/t7xx_netdev.h b/drivers/net/wwan/t7xx/t7xx_netdev.h
index f5ad49ca12a7..f5ed6f99a145 100644
--- a/drivers/net/wwan/t7xx/t7xx_netdev.h
+++ b/drivers/net/wwan/t7xx/t7xx_netdev.h
@@ -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);
diff --git a/drivers/net/wwan/t7xx/t7xx_pci.h b/drivers/net/wwan/t7xx/t7xx_pci.h
index 50b37056ce5a..112efa534eac 100644
--- a/drivers/net/wwan/t7xx/t7xx_pci.h
+++ b/drivers/net/wwan/t7xx/t7xx_pci.h
@@ -78,6 +78,9 @@ struct t7xx_pci_dev {
spinlock_t md_pm_lock; /* Protects PCI resource lock */
unsigned int sleep_disable_count;
struct completion sleep_lock_acquire;
+#ifdef CONFIG_WWAN_DEBUGFS
+ struct dentry *debugfs_dir;
+#endif
};
enum t7xx_pm_id {
diff --git a/drivers/net/wwan/t7xx/t7xx_port.h b/drivers/net/wwan/t7xx/t7xx_port.h
index dc4133eb433a..8ea9079af997 100644
--- a/drivers/net/wwan/t7xx/t7xx_port.h
+++ b/drivers/net/wwan/t7xx/t7xx_port.h
@@ -99,7 +99,6 @@ struct t7xx_port_conf {
struct t7xx_port {
/* Members not initialized in definition */
const struct t7xx_port_conf *port_conf;
- struct wwan_port *wwan_port;
struct t7xx_pci_dev *t7xx_dev;
struct device *dev;
u16 seq_nums[2]; /* TX/RX sequence numbers */
@@ -122,6 +121,14 @@ struct t7xx_port {
int rx_length_th;
bool chan_enable;
struct task_struct *thread;
+ union {
+ struct {
+ struct wwan_port *wwan_port;
+ } wwan;
+ struct {
+ struct rchan *relaych;
+ } log;
+ };
};
struct sk_buff *t7xx_port_alloc_skb(int payload);
diff --git a/drivers/net/wwan/t7xx/t7xx_port_proxy.c b/drivers/net/wwan/t7xx/t7xx_port_proxy.c
index d4de047ff0d4..894b1d11b2c9 100644
--- a/drivers/net/wwan/t7xx/t7xx_port_proxy.c
+++ b/drivers/net/wwan/t7xx/t7xx_port_proxy.c
@@ -70,6 +70,18 @@ static const struct t7xx_port_conf t7xx_md_port_conf[] = {
.name = "MBIM",
.port_type = WWAN_PORT_MBIM,
}, {
+#ifdef CONFIG_WWAN_DEBUGFS
+ .tx_ch = PORT_CH_MD_LOG_TX,
+ .rx_ch = PORT_CH_MD_LOG_RX,
+ .txq_index = 7,
+ .rxq_index = 7,
+ .txq_exp_index = 7,
+ .rxq_exp_index = 7,
+ .path_id = CLDMA_ID_MD,
+ .ops = &t7xx_trace_port_ops,
+ .name = "mdlog",
+ }, {
+#endif
.tx_ch = PORT_CH_CONTROL_TX,
.rx_ch = PORT_CH_CONTROL_RX,
.txq_index = Q_IDX_CTRL,
diff --git a/drivers/net/wwan/t7xx/t7xx_port_proxy.h b/drivers/net/wwan/t7xx/t7xx_port_proxy.h
index bc1ff5c6c700..81d059fbc0fb 100644
--- a/drivers/net/wwan/t7xx/t7xx_port_proxy.h
+++ b/drivers/net/wwan/t7xx/t7xx_port_proxy.h
@@ -87,6 +87,10 @@ struct ctrl_msg_header {
extern struct port_ops wwan_sub_port_ops;
extern struct port_ops ctl_port_ops;
+#ifdef CONFIG_WWAN_DEBUGFS
+extern struct port_ops t7xx_trace_port_ops;
+#endif
+
void t7xx_port_proxy_reset(struct port_proxy *port_prox);
void t7xx_port_proxy_uninit(struct port_proxy *port_prox);
int t7xx_port_proxy_init(struct t7xx_modem *md);
diff --git a/drivers/net/wwan/t7xx/t7xx_port_trace.c b/drivers/net/wwan/t7xx/t7xx_port_trace.c
new file mode 100644
index 000000000000..6a3f36385865
--- /dev/null
+++ b/drivers/net/wwan/t7xx/t7xx_port_trace.c
@@ -0,0 +1,116 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2022 Intel Corporation.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/relay.h>
+#include <linux/skbuff.h>
+#include <linux/wwan.h>
+
+#include "t7xx_port.h"
+#include "t7xx_port_proxy.h"
+#include "t7xx_state_monitor.h"
+
+#define T7XX_TRC_SUB_BUFF_SIZE 131072
+#define T7XX_TRC_N_SUB_BUFF 32
+
+static struct dentry *t7xx_trace_create_buf_file_handler(const char *filename,
+ struct dentry *parent,
+ umode_t mode,
+ struct rchan_buf *buf,
+ int *is_global)
+{
+ *is_global = 1;
+ return debugfs_create_file(filename, mode, parent, buf,
+ &relay_file_operations);
+}
+
+static int t7xx_trace_remove_buf_file_handler(struct dentry *dentry)
+{
+ debugfs_remove(dentry);
+ return 0;
+}
+
+static int t7xx_trace_subbuf_start_handler(struct rchan_buf *buf, void *subbuf,
+ void *prev_subbuf, size_t prev_padding)
+{
+ if (relay_buf_full(buf)) {
+ pr_err_ratelimited("Relay_buf full dropping traces");
+ return 0;
+ }
+
+ return 1;
+}
+
+static struct rchan_callbacks relay_callbacks = {
+ .subbuf_start = t7xx_trace_subbuf_start_handler,
+ .create_buf_file = t7xx_trace_create_buf_file_handler,
+ .remove_buf_file = t7xx_trace_remove_buf_file_handler,
+};
+
+static void t7xx_trace_port_uninit(struct t7xx_port *port)
+{
+ struct dentry *debugfs_dir = port->t7xx_dev->debugfs_dir;
+ struct rchan *relaych = port->log.relaych;
+
+ if (!relaych)
+ return;
+
+ relay_close(relaych);
+ debugfs_remove_recursive(debugfs_dir);
+}
+
+static int t7xx_trace_port_recv_skb(struct t7xx_port *port, struct sk_buff *skb)
+{
+ struct rchan *relaych = port->log.relaych;
+
+ if (!relaych)
+ return -EINVAL;
+
+ relay_write(relaych, skb->data, skb->len);
+ dev_kfree_skb(skb);
+ return 0;
+}
+
+static void t7xx_port_trace_md_state_notify(struct t7xx_port *port, unsigned int state)
+{
+ struct rchan *relaych = port->log.relaych;
+ struct dentry *debugfs_wwan_dir;
+ struct dentry *debugfs_dir;
+
+ if (state != MD_STATE_READY || relaych)
+ return;
+
+ debugfs_wwan_dir = wwan_get_debugfs_dir(port->dev);
+ if (IS_ERR(debugfs_wwan_dir))
+ return;
+
+ debugfs_dir = debugfs_create_dir(KBUILD_MODNAME, debugfs_wwan_dir);
+ if (IS_ERR_OR_NULL(debugfs_dir)) {
+ wwan_put_debugfs_dir(debugfs_wwan_dir);
+ dev_err(port->dev, "Unable to create debugfs for trace");
+ return;
+ }
+
+ relaych = relay_open("relay_ch", debugfs_dir, T7XX_TRC_SUB_BUFF_SIZE,
+ T7XX_TRC_N_SUB_BUFF, &relay_callbacks, NULL);
+ if (!relaych)
+ goto err_rm_debugfs_dir;
+
+ wwan_put_debugfs_dir(debugfs_wwan_dir);
+ port->log.relaych = relaych;
+ port->t7xx_dev->debugfs_dir = debugfs_dir;
+ return;
+
+err_rm_debugfs_dir:
+ debugfs_remove_recursive(debugfs_dir);
+ wwan_put_debugfs_dir(debugfs_wwan_dir);
+ dev_err(port->dev, "Unable to create trace port %s", port->port_conf->name);
+}
+
+struct port_ops t7xx_trace_port_ops = {
+ .recv_skb = t7xx_trace_port_recv_skb,
+ .uninit = t7xx_trace_port_uninit,
+ .md_state_notify = t7xx_port_trace_md_state_notify,
+};
diff --git a/drivers/net/wwan/t7xx/t7xx_port_wwan.c b/drivers/net/wwan/t7xx/t7xx_port_wwan.c
index 33931bfd78fd..24bd21942403 100644
--- a/drivers/net/wwan/t7xx/t7xx_port_wwan.c
+++ b/drivers/net/wwan/t7xx/t7xx_port_wwan.c
@@ -109,12 +109,12 @@ static int t7xx_port_wwan_init(struct t7xx_port *port)
static void t7xx_port_wwan_uninit(struct t7xx_port *port)
{
- if (!port->wwan_port)
+ if (!port->wwan.wwan_port)
return;
port->rx_length_th = 0;
- wwan_remove_port(port->wwan_port);
- port->wwan_port = NULL;
+ wwan_remove_port(port->wwan.wwan_port);
+ port->wwan.wwan_port = NULL;
}
static int t7xx_port_wwan_recv_skb(struct t7xx_port *port, struct sk_buff *skb)
@@ -129,7 +129,7 @@ static int t7xx_port_wwan_recv_skb(struct t7xx_port *port, struct sk_buff *skb)
return 0;
}
- wwan_port_rx(port->wwan_port, skb);
+ wwan_port_rx(port->wwan.wwan_port, skb);
return 0;
}
@@ -158,10 +158,10 @@ static void t7xx_port_wwan_md_state_notify(struct t7xx_port *port, unsigned int
if (state != MD_STATE_READY)
return;
- if (!port->wwan_port) {
- port->wwan_port = wwan_create_port(port->dev, port_conf->port_type,
- &wwan_ops, port);
- if (IS_ERR(port->wwan_port))
+ if (!port->wwan.wwan_port) {
+ port->wwan.wwan_port = wwan_create_port(port->dev, port_conf->port_type,
+ &wwan_ops, port);
+ if (IS_ERR(port->wwan.wwan_port))
dev_err(port->dev, "Unable to create WWWAN port %s", port_conf->name);
}
}
diff --git a/drivers/net/wwan/wwan_core.c b/drivers/net/wwan/wwan_core.c
index 62e9f7d6c9fe..966d0ccd2276 100644
--- a/drivers/net/wwan/wwan_core.c
+++ b/drivers/net/wwan/wwan_core.c
@@ -319,6 +319,10 @@ static const struct {
.name = "FIREHOSE",
.devsuf = "firehose",
},
+ [WWAN_PORT_XMMRPC] = {
+ .name = "XMMRPC",
+ .devsuf = "xmmrpc",
+ },
};
static ssize_t type_show(struct device *dev, struct device_attribute *attr,
@@ -1058,7 +1062,7 @@ static void wwan_create_default_link(struct wwan_device *wwandev,
goto unlock;
}
- rtnl_configure_link(dev, NULL); /* Link initialized, notify new link */
+ rtnl_configure_link(dev, NULL, 0, NULL); /* Link initialized, notify new link */
unlock:
rtnl_unlock();