History

net: Fix for_each_netdev_feature on Big endian

The features attribute is of type u64 and stored in the native endianes on the system. The for_each_set_bit() macro takes a pointer to a 32 bit array and goes over the bits in this area. On little Endian systems this also works with an u64 as the most significant bit is on the highest address, but on big endian the words are swapped. When we expect bit 15 here we get bit 47 (15 + 32). This patch converts it more or less to its own for_each_set_bit() implementation which works on 64 bit integers directly. This is then completely in host endianness and should work like expected.

Hauke Mehrtens committed 7 years ago

Commit 3b89ea91 parent 197f9ab2 files · +23 −4Browse files

Unified · Split

2 files
  1. include/linux/netdev_features.h +21 −2
  2. net/core/dev.c +2 −2
include/linux/netdev_features.h+21−2
@@ -11,6 +11,7 @@ · 10 unmodified lines
1111 #define _LINUX_NETDEV_FEATURES_H
1212
1313 #include <linux/types.h>
14+#include <asm/byteorder.h>
1415
1516 typedef u64 netdev_features_t;
1617
@@ -154,8 +155,26 @@ enum { · 137 unmodified lines
154155 #define NETIF_F_HW_TLS_TX __NETIF_F(HW_TLS_TX)
155156 #define NETIF_F_HW_TLS_RX __NETIF_F(HW_TLS_RX)
156157
157−#define for_each_netdev_feature(mask_addr, bit) \
158− for_each_set_bit(bit, (unsigned long *)mask_addr, NETDEV_FEATURE_COUNT)
158+/* Finds the next feature with the highest number of the range of start till 0.
159+ */
160+static inline int find_next_netdev_feature(u64 feature, unsigned long start)
161+{
162+ /* like BITMAP_LAST_WORD_MASK() for u64
163+ * this sets the most significant 64 - start to 0.
164+ */
165+ feature &= ~0ULL >> (-start & ((sizeof(feature) * 8) - 1));
166+
167+ return fls64(feature) - 1;
168+}
169+
170+/* This goes for the MSB to the LSB through the set feature bits,
171+ * mask_addr should be a u64 and bit an int
172+ */
173+#define for_each_netdev_feature(mask_addr, bit) \
174+ for ((bit) = find_next_netdev_feature((mask_addr), \
175+ NETDEV_FEATURE_COUNT); \
176+ (bit) >= 0; \
177+ (bit) = find_next_netdev_feature((mask_addr), (bit) - 1))
159178
160179 /* Features valid for ethtool to change */
161180 /* = all defined minus driver/device-class-related */
net/core/dev.c+2−2
@@ -8152,7 +8152,7 @@ static netdev_features_t netdev_sync_upper_features(struct net_device *lower, · 8151 unmodified lines
81528152 netdev_features_t feature;
81538153 int feature_bit;
81548154
8155− for_each_netdev_feature(&upper_disables, feature_bit) {
8155+ for_each_netdev_feature(upper_disables, feature_bit) {
81568156 feature = __NETIF_F_BIT(feature_bit);
81578157 if (!(upper->wanted_features & feature)
81588158 && (features & feature)) {
@@ -8172,7 +8172,7 @@ static void netdev_sync_lower_features(struct net_device *upper, · 13 unmodified lines
81728172 netdev_features_t feature;
81738173 int feature_bit;
81748174
8175− for_each_netdev_feature(&upper_disables, feature_bit) {
8175+ for_each_netdev_feature(upper_disables, feature_bit) {
81768176 feature = __NETIF_F_BIT(feature_bit);
81778177 if (!(features & feature) && (lower->features & feature)) {
81788178 netdev_dbg(upper, "Disabling feature %pNF on lower dev %s.\n",

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t