1 /* 2 * Copyright (c) 2014,2017 Qualcomm Atheros, Inc. 3 * Copyright (c) 2018, The Linux Foundation. All rights reserved. 4 * 5 * Permission to use, copy, modify, and/or distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <linux/etherdevice.h> 19 #include <linux/pci.h> 20 #include <linux/rtnetlink.h> 21 #include <net/cfg80211.h> 22 23 #include "wil6210.h" 24 25 static int wil_ethtoolops_begin(struct net_device *ndev) 26 { 27 struct wil6210_priv *wil = ndev_to_wil(ndev); 28 29 mutex_lock(&wil->mutex); 30 31 wil_dbg_misc(wil, "ethtoolops_begin\n"); 32 33 return 0; 34 } 35 36 static void wil_ethtoolops_complete(struct net_device *ndev) 37 { 38 struct wil6210_priv *wil = ndev_to_wil(ndev); 39 40 wil_dbg_misc(wil, "ethtoolops_complete\n"); 41 42 mutex_unlock(&wil->mutex); 43 } 44 45 static int wil_ethtoolops_get_coalesce(struct net_device *ndev, 46 struct ethtool_coalesce *cp) 47 { 48 struct wil6210_priv *wil = ndev_to_wil(ndev); 49 u32 tx_itr_en, tx_itr_val = 0; 50 u32 rx_itr_en, rx_itr_val = 0; 51 int ret; 52 53 wil_dbg_misc(wil, "ethtoolops_get_coalesce\n"); 54 55 ret = wil_pm_runtime_get(wil); 56 if (ret < 0) 57 return ret; 58 59 tx_itr_en = wil_r(wil, RGF_DMA_ITR_TX_CNT_CTL); 60 if (tx_itr_en & BIT_DMA_ITR_TX_CNT_CTL_EN) 61 tx_itr_val = wil_r(wil, RGF_DMA_ITR_TX_CNT_TRSH); 62 63 rx_itr_en = wil_r(wil, RGF_DMA_ITR_RX_CNT_CTL); 64 if (rx_itr_en & BIT_DMA_ITR_RX_CNT_CTL_EN) 65 rx_itr_val = wil_r(wil, RGF_DMA_ITR_RX_CNT_TRSH); 66 67 wil_pm_runtime_put(wil); 68 69 cp->tx_coalesce_usecs = tx_itr_val; 70 cp->rx_coalesce_usecs = rx_itr_val; 71 return 0; 72 } 73 74 static int wil_ethtoolops_set_coalesce(struct net_device *ndev, 75 struct ethtool_coalesce *cp) 76 { 77 struct wil6210_priv *wil = ndev_to_wil(ndev); 78 struct wireless_dev *wdev = ndev->ieee80211_ptr; 79 int ret; 80 81 wil_dbg_misc(wil, "ethtoolops_set_coalesce: rx %d usec, tx %d usec\n", 82 cp->rx_coalesce_usecs, cp->tx_coalesce_usecs); 83 84 if (wdev->iftype == NL80211_IFTYPE_MONITOR) { 85 wil_dbg_misc(wil, "No IRQ coalescing in monitor mode\n"); 86 return -EINVAL; 87 } 88 89 /* only @rx_coalesce_usecs and @tx_coalesce_usecs supported, 90 * ignore other parameters 91 */ 92 93 if (cp->rx_coalesce_usecs > WIL6210_ITR_TRSH_MAX || 94 cp->tx_coalesce_usecs > WIL6210_ITR_TRSH_MAX) 95 goto out_bad; 96 97 wil->tx_max_burst_duration = cp->tx_coalesce_usecs; 98 wil->rx_max_burst_duration = cp->rx_coalesce_usecs; 99 100 ret = wil_pm_runtime_get(wil); 101 if (ret < 0) 102 return ret; 103 104 wil->txrx_ops.configure_interrupt_moderation(wil); 105 106 wil_pm_runtime_put(wil); 107 108 return 0; 109 110 out_bad: 111 wil_dbg_misc(wil, "Unsupported coalescing params. Raw command:\n"); 112 print_hex_dump_debug("DBG[MISC] coal ", DUMP_PREFIX_OFFSET, 16, 4, 113 cp, sizeof(*cp), false); 114 return -EINVAL; 115 } 116 117 static const struct ethtool_ops wil_ethtool_ops = { 118 .begin = wil_ethtoolops_begin, 119 .complete = wil_ethtoolops_complete, 120 .get_drvinfo = cfg80211_get_drvinfo, 121 .get_coalesce = wil_ethtoolops_get_coalesce, 122 .set_coalesce = wil_ethtoolops_set_coalesce, 123 }; 124 125 void wil_set_ethtoolops(struct net_device *ndev) 126 { 127 ndev->ethtool_ops = &wil_ethtool_ops; 128 } 129