tools: mkimage: provide dtc path during build
[openwrt/openwrt.git] / target / linux / mvebu / patches-4.9 / 406-net-phy-improve-phylib-correctness-for-non-autoneg-s.patch
1 From: Russell King <rmk+kernel@armlinux.org.uk>
2 Date: Thu, 5 Jan 2017 16:32:14 +0000
3 Subject: [PATCH] net: phy: improve phylib correctness for non-autoneg
4 settings
5
6 phylib has some undesirable behaviour when forcing a link mode through
7 ethtool. phylib uses this code:
8
9 idx = phy_find_valid(phy_find_setting(phydev->speed, phydev->duplex),
10 features);
11
12 to find an index in the settings table. phy_find_setting() starts at
13 index 0, and scans upwards looking for an exact speed and duplex match.
14 When it doesn't find it, it returns MAX_NUM_SETTINGS - 1, which is
15 10baseT-Half duplex.
16
17 phy_find_valid() then scans from the point (and effectively only checks
18 one entry) before bailing out, returning MAX_NUM_SETTINGS - 1.
19
20 phy_sanitize_settings() then sets ->speed to SPEED_10 and ->duplex to
21 DUPLEX_HALF whether or not 10baseT-Half is supported or not. This goes
22 against all the comments against these functions, and 10baseT-Half may
23 not even be supported by the hardware.
24
25 Rework these functions, introducing a new method of scanning the table.
26 There are two modes of lookup that phylib wants: exact, and inexact.
27
28 - in exact mode, we return either an exact match or failure
29 - in inexact mode, we return an exact match if it exists, a match at
30 the highest speed that is not greater than the requested speed
31 (ignoring duplex), or failing that, the lowest supported speed, or
32 failure.
33
34 The biggest difference is that we always check whether the entry is
35 supported before further consideration, so all unsupported entries are
36 not considered as candidates.
37
38 This results in arguably saner behaviour, better matches the comments,
39 and is probably what users would expect.
40
41 This becomes important as ethernet speeds increase, PHYs exist which do
42 not support the 10Mbit speeds, and half-duplex is likely to become
43 obsolete - it's already not even an option on 10Gbit and faster links.
44
45 Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
46 ---
47
48 --- a/drivers/net/phy/phy.c
49 +++ b/drivers/net/phy/phy.c
50 @@ -160,7 +160,9 @@ struct phy_setting {
51 u32 setting;
52 };
53
54 -/* A mapping of all SUPPORTED settings to speed/duplex */
55 +/* A mapping of all SUPPORTED settings to speed/duplex. This table
56 + * must be grouped by speed and sorted in descending match priority
57 + * - iow, descending speed. */
58 static const struct phy_setting settings[] = {
59 {
60 .speed = SPEED_10000,
61 @@ -219,45 +221,70 @@ static const struct phy_setting settings
62 },
63 };
64
65 -#define MAX_NUM_SETTINGS ARRAY_SIZE(settings)
66 -
67 /**
68 - * phy_find_setting - find a PHY settings array entry that matches speed & duplex
69 + * phy_lookup_setting - lookup a PHY setting
70 * @speed: speed to match
71 * @duplex: duplex to match
72 + * @feature: allowed link modes
73 + * @exact: an exact match is required
74 + *
75 + * Search the settings array for a setting that matches the speed and
76 + * duplex, and which is supported.
77 + *
78 + * If @exact is unset, either an exact match or %NULL for no match will
79 + * be returned.
80 *
81 - * Description: Searches the settings array for the setting which
82 - * matches the desired speed and duplex, and returns the index
83 - * of that setting. Returns the index of the last setting if
84 - * none of the others match.
85 + * If @exact is set, an exact match, the fastest supported setting at
86 + * or below the specified speed, the slowest supported setting, or if
87 + * they all fail, %NULL will be returned.
88 */
89 -static inline unsigned int phy_find_setting(int speed, int duplex)
90 +static const struct phy_setting *
91 +phy_lookup_setting(int speed, int duplex, u32 features, bool exact)
92 {
93 - unsigned int idx = 0;
94 + const struct phy_setting *p, *match = NULL, *last = NULL;
95 + int i;
96
97 - while (idx < ARRAY_SIZE(settings) &&
98 - (settings[idx].speed != speed || settings[idx].duplex != duplex))
99 - idx++;
100 + for (i = 0, p = settings; i < ARRAY_SIZE(settings); i++, p++) {
101 + if (p->setting & features) {
102 + last = p;
103 + if (p->speed == speed && p->duplex == duplex) {
104 + /* Exact match for speed and duplex */
105 + match = p;
106 + break;
107 + } else if (!exact) {
108 + if (!match && p->speed <= speed)
109 + /* Candidate */
110 + match = p;
111 +
112 + if (p->speed < speed)
113 + break;
114 + }
115 + }
116 + }
117
118 - return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1;
119 + if (!match && !exact)
120 + match = last;
121 +
122 + return match;
123 }
124
125 /**
126 - * phy_find_valid - find a PHY setting that matches the requested features mask
127 - * @idx: The first index in settings[] to search
128 - * @features: A mask of the valid settings
129 + * phy_find_valid - find a PHY setting that matches the requested parameters
130 + * @speed: desired speed
131 + * @duplex: desired duplex
132 + * @supported: mask of supported link modes
133 *
134 - * Description: Returns the index of the first valid setting less
135 - * than or equal to the one pointed to by idx, as determined by
136 - * the mask in features. Returns the index of the last setting
137 - * if nothing else matches.
138 + * Locate a supported phy setting that is, in priority order:
139 + * - an exact match for the specified speed and duplex mode
140 + * - a match for the specified speed, or slower speed
141 + * - the slowest supported speed
142 + * Returns the matched phy_setting entry, or %NULL if no supported phy
143 + * settings were found.
144 */
145 -static inline unsigned int phy_find_valid(unsigned int idx, u32 features)
146 +static const struct phy_setting *
147 +phy_find_valid(int speed, int duplex, u32 supported)
148 {
149 - while (idx < MAX_NUM_SETTINGS && !(settings[idx].setting & features))
150 - idx++;
151 -
152 - return idx < MAX_NUM_SETTINGS ? idx : MAX_NUM_SETTINGS - 1;
153 + return phy_lookup_setting(speed, duplex, supported, false);
154 }
155
156 /**
157 @@ -271,12 +298,7 @@ static inline unsigned int phy_find_vali
158 */
159 static inline bool phy_check_valid(int speed, int duplex, u32 features)
160 {
161 - unsigned int idx;
162 -
163 - idx = phy_find_valid(phy_find_setting(speed, duplex), features);
164 -
165 - return settings[idx].speed == speed && settings[idx].duplex == duplex &&
166 - (settings[idx].setting & features);
167 + return !!phy_lookup_setting(speed, duplex, features, true);
168 }
169
170 /**
171 @@ -289,18 +311,22 @@ static inline bool phy_check_valid(int s
172 */
173 static void phy_sanitize_settings(struct phy_device *phydev)
174 {
175 + const struct phy_setting *setting;
176 u32 features = phydev->supported;
177 - unsigned int idx;
178
179 /* Sanitize settings based on PHY capabilities */
180 if ((features & SUPPORTED_Autoneg) == 0)
181 phydev->autoneg = AUTONEG_DISABLE;
182
183 - idx = phy_find_valid(phy_find_setting(phydev->speed, phydev->duplex),
184 - features);
185 -
186 - phydev->speed = settings[idx].speed;
187 - phydev->duplex = settings[idx].duplex;
188 + setting = phy_find_valid(phydev->speed, phydev->duplex, features);
189 + if (setting) {
190 + phydev->speed = setting->speed;
191 + phydev->duplex = setting->duplex;
192 + } else {
193 + /* We failed to find anything (no supported speeds?) */
194 + phydev->speed = SPEED_UNKNOWN;
195 + phydev->duplex = DUPLEX_UNKNOWN;
196 + }
197 }
198
199 /**