162306a36Sopenharmony_ci// SPDX-License-Identifier: ISC 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2014,2017 Qualcomm Atheros, Inc. 462306a36Sopenharmony_ci * Copyright (c) 2018, The Linux Foundation. All rights reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/etherdevice.h> 862306a36Sopenharmony_ci#include <linux/pci.h> 962306a36Sopenharmony_ci#include <linux/rtnetlink.h> 1062306a36Sopenharmony_ci#include <net/cfg80211.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "wil6210.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic int 1562306a36Sopenharmony_ciwil_ethtoolops_get_coalesce(struct net_device *ndev, 1662306a36Sopenharmony_ci struct ethtool_coalesce *cp, 1762306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kernel_coal, 1862306a36Sopenharmony_ci struct netlink_ext_ack *extack) 1962306a36Sopenharmony_ci{ 2062306a36Sopenharmony_ci struct wil6210_priv *wil = ndev_to_wil(ndev); 2162306a36Sopenharmony_ci u32 tx_itr_en, tx_itr_val = 0; 2262306a36Sopenharmony_ci u32 rx_itr_en, rx_itr_val = 0; 2362306a36Sopenharmony_ci int ret; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci mutex_lock(&wil->mutex); 2662306a36Sopenharmony_ci wil_dbg_misc(wil, "ethtoolops_get_coalesce\n"); 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci ret = wil_pm_runtime_get(wil); 2962306a36Sopenharmony_ci if (ret < 0) 3062306a36Sopenharmony_ci goto out; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci tx_itr_en = wil_r(wil, RGF_DMA_ITR_TX_CNT_CTL); 3362306a36Sopenharmony_ci if (tx_itr_en & BIT_DMA_ITR_TX_CNT_CTL_EN) 3462306a36Sopenharmony_ci tx_itr_val = wil_r(wil, RGF_DMA_ITR_TX_CNT_TRSH); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci rx_itr_en = wil_r(wil, RGF_DMA_ITR_RX_CNT_CTL); 3762306a36Sopenharmony_ci if (rx_itr_en & BIT_DMA_ITR_RX_CNT_CTL_EN) 3862306a36Sopenharmony_ci rx_itr_val = wil_r(wil, RGF_DMA_ITR_RX_CNT_TRSH); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci wil_pm_runtime_put(wil); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci cp->tx_coalesce_usecs = tx_itr_val; 4362306a36Sopenharmony_ci cp->rx_coalesce_usecs = rx_itr_val; 4462306a36Sopenharmony_ci ret = 0; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ciout: 4762306a36Sopenharmony_ci mutex_unlock(&wil->mutex); 4862306a36Sopenharmony_ci return ret; 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic int 5262306a36Sopenharmony_ciwil_ethtoolops_set_coalesce(struct net_device *ndev, 5362306a36Sopenharmony_ci struct ethtool_coalesce *cp, 5462306a36Sopenharmony_ci struct kernel_ethtool_coalesce *kernel_coal, 5562306a36Sopenharmony_ci struct netlink_ext_ack *extack) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci struct wil6210_priv *wil = ndev_to_wil(ndev); 5862306a36Sopenharmony_ci struct wireless_dev *wdev = ndev->ieee80211_ptr; 5962306a36Sopenharmony_ci int ret; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci mutex_lock(&wil->mutex); 6262306a36Sopenharmony_ci wil_dbg_misc(wil, "ethtoolops_set_coalesce: rx %d usec, tx %d usec\n", 6362306a36Sopenharmony_ci cp->rx_coalesce_usecs, cp->tx_coalesce_usecs); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (wdev->iftype == NL80211_IFTYPE_MONITOR) { 6662306a36Sopenharmony_ci wil_dbg_misc(wil, "No IRQ coalescing in monitor mode\n"); 6762306a36Sopenharmony_ci ret = -EINVAL; 6862306a36Sopenharmony_ci goto out; 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci /* only @rx_coalesce_usecs and @tx_coalesce_usecs supported, 7262306a36Sopenharmony_ci * ignore other parameters 7362306a36Sopenharmony_ci */ 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci if (cp->rx_coalesce_usecs > WIL6210_ITR_TRSH_MAX || 7662306a36Sopenharmony_ci cp->tx_coalesce_usecs > WIL6210_ITR_TRSH_MAX) 7762306a36Sopenharmony_ci goto out_bad; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci wil->tx_max_burst_duration = cp->tx_coalesce_usecs; 8062306a36Sopenharmony_ci wil->rx_max_burst_duration = cp->rx_coalesce_usecs; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci ret = wil_pm_runtime_get(wil); 8362306a36Sopenharmony_ci if (ret < 0) 8462306a36Sopenharmony_ci goto out; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci wil->txrx_ops.configure_interrupt_moderation(wil); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci wil_pm_runtime_put(wil); 8962306a36Sopenharmony_ci ret = 0; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ciout: 9262306a36Sopenharmony_ci mutex_unlock(&wil->mutex); 9362306a36Sopenharmony_ci return ret; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ciout_bad: 9662306a36Sopenharmony_ci wil_dbg_misc(wil, "Unsupported coalescing params. Raw command:\n"); 9762306a36Sopenharmony_ci print_hex_dump_debug("DBG[MISC] coal ", DUMP_PREFIX_OFFSET, 16, 4, 9862306a36Sopenharmony_ci cp, sizeof(*cp), false); 9962306a36Sopenharmony_ci mutex_unlock(&wil->mutex); 10062306a36Sopenharmony_ci return -EINVAL; 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic const struct ethtool_ops wil_ethtool_ops = { 10462306a36Sopenharmony_ci .supported_coalesce_params = ETHTOOL_COALESCE_USECS, 10562306a36Sopenharmony_ci .get_drvinfo = cfg80211_get_drvinfo, 10662306a36Sopenharmony_ci .get_coalesce = wil_ethtoolops_get_coalesce, 10762306a36Sopenharmony_ci .set_coalesce = wil_ethtoolops_set_coalesce, 10862306a36Sopenharmony_ci}; 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_civoid wil_set_ethtoolops(struct net_device *ndev) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci ndev->ethtool_ops = &wil_ethtool_ops; 11362306a36Sopenharmony_ci} 114