1 // SPDX-License-Identifier: ISC
2 /*
3  * Copyright (c) 2014,2017 Qualcomm Atheros, Inc.
4  * Copyright (c) 2018, The Linux Foundation. All rights reserved.
5  */
6 
7 #include <linux/etherdevice.h>
8 #include <linux/pci.h>
9 #include <linux/rtnetlink.h>
10 #include <net/cfg80211.h>
11 
12 #include "wil6210.h"
13 
14 static int wil_ethtoolops_begin(struct net_device *ndev)
15 {
16 	struct wil6210_priv *wil = ndev_to_wil(ndev);
17 
18 	mutex_lock(&wil->mutex);
19 
20 	wil_dbg_misc(wil, "ethtoolops_begin\n");
21 
22 	return 0;
23 }
24 
25 static void wil_ethtoolops_complete(struct net_device *ndev)
26 {
27 	struct wil6210_priv *wil = ndev_to_wil(ndev);
28 
29 	wil_dbg_misc(wil, "ethtoolops_complete\n");
30 
31 	mutex_unlock(&wil->mutex);
32 }
33 
34 static int wil_ethtoolops_get_coalesce(struct net_device *ndev,
35 				       struct ethtool_coalesce *cp)
36 {
37 	struct wil6210_priv *wil = ndev_to_wil(ndev);
38 	u32 tx_itr_en, tx_itr_val = 0;
39 	u32 rx_itr_en, rx_itr_val = 0;
40 	int ret;
41 
42 	wil_dbg_misc(wil, "ethtoolops_get_coalesce\n");
43 
44 	ret = wil_pm_runtime_get(wil);
45 	if (ret < 0)
46 		return ret;
47 
48 	tx_itr_en = wil_r(wil, RGF_DMA_ITR_TX_CNT_CTL);
49 	if (tx_itr_en & BIT_DMA_ITR_TX_CNT_CTL_EN)
50 		tx_itr_val = wil_r(wil, RGF_DMA_ITR_TX_CNT_TRSH);
51 
52 	rx_itr_en = wil_r(wil, RGF_DMA_ITR_RX_CNT_CTL);
53 	if (rx_itr_en & BIT_DMA_ITR_RX_CNT_CTL_EN)
54 		rx_itr_val = wil_r(wil, RGF_DMA_ITR_RX_CNT_TRSH);
55 
56 	wil_pm_runtime_put(wil);
57 
58 	cp->tx_coalesce_usecs = tx_itr_val;
59 	cp->rx_coalesce_usecs = rx_itr_val;
60 	return 0;
61 }
62 
63 static int wil_ethtoolops_set_coalesce(struct net_device *ndev,
64 				       struct ethtool_coalesce *cp)
65 {
66 	struct wil6210_priv *wil = ndev_to_wil(ndev);
67 	struct wireless_dev *wdev = ndev->ieee80211_ptr;
68 	int ret;
69 
70 	wil_dbg_misc(wil, "ethtoolops_set_coalesce: rx %d usec, tx %d usec\n",
71 		     cp->rx_coalesce_usecs, cp->tx_coalesce_usecs);
72 
73 	if (wdev->iftype == NL80211_IFTYPE_MONITOR) {
74 		wil_dbg_misc(wil, "No IRQ coalescing in monitor mode\n");
75 		return -EINVAL;
76 	}
77 
78 	/* only @rx_coalesce_usecs and @tx_coalesce_usecs supported,
79 	 * ignore other parameters
80 	 */
81 
82 	if (cp->rx_coalesce_usecs > WIL6210_ITR_TRSH_MAX ||
83 	    cp->tx_coalesce_usecs > WIL6210_ITR_TRSH_MAX)
84 		goto out_bad;
85 
86 	wil->tx_max_burst_duration = cp->tx_coalesce_usecs;
87 	wil->rx_max_burst_duration = cp->rx_coalesce_usecs;
88 
89 	ret = wil_pm_runtime_get(wil);
90 	if (ret < 0)
91 		return ret;
92 
93 	wil->txrx_ops.configure_interrupt_moderation(wil);
94 
95 	wil_pm_runtime_put(wil);
96 
97 	return 0;
98 
99 out_bad:
100 	wil_dbg_misc(wil, "Unsupported coalescing params. Raw command:\n");
101 	print_hex_dump_debug("DBG[MISC] coal ", DUMP_PREFIX_OFFSET, 16, 4,
102 			     cp, sizeof(*cp), false);
103 	return -EINVAL;
104 }
105 
106 static const struct ethtool_ops wil_ethtool_ops = {
107 	.begin		= wil_ethtoolops_begin,
108 	.complete	= wil_ethtoolops_complete,
109 	.get_drvinfo	= cfg80211_get_drvinfo,
110 	.get_coalesce	= wil_ethtoolops_get_coalesce,
111 	.set_coalesce	= wil_ethtoolops_set_coalesce,
112 };
113 
114 void wil_set_ethtoolops(struct net_device *ndev)
115 {
116 	ndev->ethtool_ops = &wil_ethtool_ops;
117 }
118