From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-yw1-f171.google.com (mail-yw1-f171.google.com [209.85.128.171]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id F0D263FFAD8 for ; Mon, 27 Apr 2026 20:59:51 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.171 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777323594; cv=none; b=brCIirBqLSMN/CQOux5XbNyL6HqSiW+TYEKNzPzGnzrPcKesfmqdkI21ZPycvsoVFTcAAj0jr8HmiBUPdR3F6zBvoMRsdE6h89mlX1xX5g5uPoprqL0rHhgdB9xfGaALsSHHXLTpFlb75iLY4vH9Fko0fCoEa0TbwlxU16+8Mso= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777323594; c=relaxed/simple; bh=T8j9eotcWVWo4HMzwY+nJE5ckP5eTodFyffIwLxlKDA=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=q/b+LSoQFn3j3oz5ee8ffyXgrVTmPfohurZtCzh0GM3yNSxkACQwOJ4acspx4wQsrzN6i9SQArsql6430Sm7V1Ds2/Z092zCB9BVLdhxiG2lg5Pw4zW+peued7Kur98rTlKoi6ATOTH42n69whl6hPV8hoCpm9yeGs/nnSOD8d0= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=XIEeEwTI; arc=none smtp.client-ip=209.85.128.171 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="XIEeEwTI" Received: by mail-yw1-f171.google.com with SMTP id 00721157ae682-79a74765703so99885707b3.3 for ; Mon, 27 Apr 2026 13:59:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1777323590; x=1777928390; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=Y90erLgpJzp5pcD4oJdjl1uzgncCBbxWXvu4GrKeDyU=; b=XIEeEwTI87RpK+dOifgibvR/UYx42HHsKzF9L2S8mTEA+sTD8Sl/XCHpRBKc60WZn7 FA9Hq+ld6WvKJVWT6fvkc20DWFcXoKvRP02a0w1ZO0k36unx205x5kdhkxmZcT035O4O yBjRpv961Ygha3hOLZu7XWq0UxdGNK99I3H6A4Ds2mBYrdvf7A5kiuMoLBsQcQqs89sZ VY053zB0XJfU0vEwDEjYyfuUCQ/VdGX1Ob1t86ECv029EBUEmrTgMjI8CVnX6H8LifPw 7dyoOdkiIuDHp+63lfAMR4WMfPlubAzYDxK3G5AI/GQxl0rj+rWyo/1YgACYrnmmRXtw MAVQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777323590; x=1777928390; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=Y90erLgpJzp5pcD4oJdjl1uzgncCBbxWXvu4GrKeDyU=; b=S/TMStVdM/S9PQEvYp5i2BOS1WcDkBjtbIyJvvX1YFyc++uDTi+en8hdwLwPytlkOn WCW232td4CkZdEQHt3wHuMZziWSBF6uuNQVAJ4i2H6N+DeJSDNYrInRzoelEsdBwt/XP WDm2TzYDNO2ySnxeREgsDlVGy9sL8ohKABk3CsnsYidaiCOBEbIjy+u8XMJoKsaJnWmM zjzMB88VhBTuSfq6ZFi1EdY7ipoXSqz+mwgtHSUYQGZGN3bwvdnAA3njNB2Ea3ZgaD6g kq+nl4KzWu9AOSQd1lgMCJHjQ5wgR9Lu7U/Q85Ho7a+WEj3eZ5sWQ1jCxbAPzHXo7jDK X6pQ== X-Forwarded-Encrypted: i=1; AFNElJ9LtRZlgcXWWE7sdrf2FdBJ5tQpOcxOtDR58uLc5pASFIDbkDW6BchzI0jTmP25IePeuM4Bg8ge+JWuXUk=@vger.kernel.org X-Gm-Message-State: AOJu0YwO93maLbcjW8zKSFUG0oHxCT842MxJDnedayiGpIlpakPOt193 M1V85R4AmTAVRt/FYjJGax7BEDxj+MIIj/l1DRylUBr+lhwoGZGDzW8N X-Gm-Gg: AeBDieuEV+O98PJFZrtVRUAApbYqnybn3FfW2A3OhePOcqfH8suhkpVJsl88YnDEdMD oIN00bbqzCHe/ABuXiJUOxe9Oz/B7Rb+SQ3UkoqnjguVQFfBdU7mjhRtnZ+ndpxbIudkLl7PP/s 8PNI5MVsTdYGNf3htqjeoykkFmoTtWtHBnMbSGmOOAbEFs+0hLJE0HBtr3Tl+8vPtjKSxUGuLJW +yhUoWTW4vBrPfl/LlpuASDZyClkr1UFe7zc4nxZMv4UYkrtpWyEDMgj0HZr3l04AIbT6V1fkob Nh/T4h1MAbEZkvdYoAac9IPi8QN44CiFrTwqMg/xcJrIKTyBfLCZYfKKzNJRnvXgQ8oJR8OqxpD z9Knaz8JHKsbAgQgxnPIPbWR1I2Quznm9mQO/d0ljp4hcO4Ctc0cyYKvt9CdA7+Ca+s2WdM/ipR NSOYkPVKe86a0BuXoFX8npK2OobHAoXljnqi7CmcmVEOiwf9zC2z+SYw== X-Received: by 2002:a05:690c:c512:b0:7ba:ee75:f115 with SMTP id 00721157ae682-7bcf4fc4fcamr2613427b3.4.1777323590345; Mon, 27 Apr 2026 13:59:50 -0700 (PDT) Received: from localhost.localdomain ([2804:d59:7f1c:1e00:6632:a8ff:fea4:c8d3]) by smtp.gmail.com with ESMTPSA id 00721157ae682-7bcf05e6149sm2324407b3.11.2026.04.27.13.59.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 27 Apr 2026 13:59:49 -0700 (PDT) From: Gustavo Arantes To: Heiner Kallweit , nic_swsd@realtek.com Cc: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Javen Xu , netdev@vger.kernel.org, linux-kernel@vger.kernel.org, Gustavo Arantes Subject: [PATCH net-next v2] r8169: expose software counters through netdev qstats Date: Mon, 27 Apr 2026 17:59:31 -0300 Message-ID: <20260427205931.5884-1-dev.gustavoa@gmail.com> X-Mailer: git-send-email 2.54.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit r8169 maintains synchronized per-CPU software counters for packet and byte accounting and exposes them through ndo_get_stats64(), but userspace using the structured netdev qstats API cannot retrieve them from this driver. Expose the same counters through netdev_stat_ops. r8169 has a single Rx and Tx queue, so report the accumulated counters on queue 0. Use zero base stats so device-scope qstats are derived from the queue counters and match the packet and byte values reported through RTNL. This does not add new accounting and does not touch the data path. It only makes the existing counters available through the common qstats interface, which lets generic userspace tooling query r8169 the same way it queries other drivers with qstats support. Signed-off-by: Gustavo Arantes --- v2: - Submit again now that net-next has reopened. - Expand commit message to explain the qstats userspace benefit. Tested on a Realtek RTL8111/8168/8211/8411 PCIe Gigabit Ethernet controller using the r8169 driver. v1: https://lore.kernel.org/netdev/20260418021232.5425-1-dev.gustavoa@gmail.com/ drivers/net/ethernet/realtek/r8169_main.c | 70 +++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index 791277e750ba..9d833b446383 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -5175,6 +5175,75 @@ rtl8169_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) pm_runtime_put_noidle(&pdev->dev); } +static void rtl8169_fetch_sw_stats(struct net_device *dev, + struct netdev_queue_stats_rx *rx, + struct netdev_queue_stats_tx *tx) +{ + const struct pcpu_sw_netstats *stats; + unsigned int start; + int cpu; + + for_each_possible_cpu(cpu) { + u64 rx_packets, rx_bytes, tx_packets, tx_bytes; + + stats = per_cpu_ptr(dev->tstats, cpu); + do { + start = u64_stats_fetch_begin(&stats->syncp); + rx_packets = u64_stats_read(&stats->rx_packets); + rx_bytes = u64_stats_read(&stats->rx_bytes); + tx_packets = u64_stats_read(&stats->tx_packets); + tx_bytes = u64_stats_read(&stats->tx_bytes); + } while (u64_stats_fetch_retry(&stats->syncp, start)); + + rx->packets += rx_packets; + rx->bytes += rx_bytes; + tx->packets += tx_packets; + tx->bytes += tx_bytes; + } +} + +static void rtl8169_get_queue_stats_rx(struct net_device *dev, int idx, + struct netdev_queue_stats_rx *rx) +{ + struct netdev_queue_stats_tx tx = {}; + + if (idx) + return; + + rx->packets = 0; + rx->bytes = 0; + rtl8169_fetch_sw_stats(dev, rx, &tx); +} + +static void rtl8169_get_queue_stats_tx(struct net_device *dev, int idx, + struct netdev_queue_stats_tx *tx) +{ + struct netdev_queue_stats_rx rx = {}; + + if (idx) + return; + + tx->packets = 0; + tx->bytes = 0; + rtl8169_fetch_sw_stats(dev, &rx, tx); +} + +static void rtl8169_get_base_stats(struct net_device *dev, + struct netdev_queue_stats_rx *rx, + struct netdev_queue_stats_tx *tx) +{ + rx->packets = 0; + rx->bytes = 0; + tx->packets = 0; + tx->bytes = 0; +} + +static const struct netdev_stat_ops rtl8169_stat_ops = { + .get_queue_stats_rx = rtl8169_get_queue_stats_rx, + .get_queue_stats_tx = rtl8169_get_queue_stats_tx, + .get_base_stats = rtl8169_get_base_stats, +}; + static void rtl8169_net_suspend(struct rtl8169_private *tp) { netif_device_detach(tp->dev); @@ -5615,6 +5684,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) SET_NETDEV_DEV(dev, &pdev->dev); dev->netdev_ops = &rtl_netdev_ops; + dev->stat_ops = &rtl8169_stat_ops; tp = netdev_priv(dev); tp->dev = dev; tp->pci_dev = pdev; -- 2.54.0