@@ -31,16 +31,21 @@ struct phy_mii_dev_data {
31
31
phy_callback_t cb ;
32
32
void * cb_data ;
33
33
struct k_work_delayable monitor_work ;
34
+ struct k_work_delayable autoneg_work ;
34
35
struct phy_link_state state ;
35
36
struct k_sem sem ;
36
37
bool gigabit_supported ;
38
+ uint32_t autoneg_timeout ;
37
39
};
38
40
39
41
/* Offset to align capabilities bits of 1000BASE-T Control and Status regs */
40
42
#define MII_1KSTSR_OFFSET 2
41
43
42
44
#define MII_INVALID_PHY_ID UINT32_MAX
43
45
46
+ /* How often to poll auto-negotiation status while waiting for it to complete */
47
+ #define MII_AUTONEG_POLL_INTERVAL_MS 100
48
+
44
49
static int phy_mii_get_link_state (const struct device * dev ,
45
50
struct phy_link_state * state );
46
51
@@ -145,13 +150,8 @@ static int update_link_state(const struct device *dev)
145
150
struct phy_mii_dev_data * const data = dev -> data ;
146
151
bool link_up ;
147
152
148
- uint16_t anar_reg = 0 ;
149
153
uint16_t bmcr_reg = 0 ;
150
154
uint16_t bmsr_reg = 0 ;
151
- uint16_t anlpar_reg = 0 ;
152
- uint16_t c1kt_reg = 0 ;
153
- uint16_t s1kt_reg = 0 ;
154
- uint32_t timeout = CONFIG_PHY_AUTONEG_TIMEOUT_MS / 100 ;
155
155
156
156
if (phy_mii_reg_read (dev , MII_BMSR , & bmsr_reg ) < 0 ) {
157
157
return - EIO ;
@@ -178,11 +178,6 @@ static int update_link_state(const struct device *dev)
178
178
LOG_DBG ("PHY (%d) Starting MII PHY auto-negotiate sequence" ,
179
179
cfg -> phy_addr );
180
180
181
- /* Read PHY default advertising parameters */
182
- if (phy_mii_reg_read (dev , MII_ANAR , & anar_reg ) < 0 ) {
183
- return - EIO ;
184
- }
185
-
186
181
/* Configure and start auto-negotiation process */
187
182
if (phy_mii_reg_read (dev , MII_BMCR , & bmcr_reg ) < 0 ) {
188
183
return - EIO ;
@@ -195,32 +190,51 @@ static int update_link_state(const struct device *dev)
195
190
return - EIO ;
196
191
}
197
192
198
- /* Wait for the auto-negotiation process to complete */
199
- do {
200
- if (timeout -- == 0U ) {
201
- LOG_DBG ("PHY (%d) auto-negotiate timedout" ,
202
- cfg -> phy_addr );
203
- return - ETIMEDOUT ;
204
- }
193
+ /* We have to wait for the auto-negotiation process to complete */
194
+ data -> autoneg_timeout = CONFIG_PHY_AUTONEG_TIMEOUT_MS / MII_AUTONEG_POLL_INTERVAL_MS ;
195
+ return - EINPROGRESS ;
196
+ }
205
197
206
- k_sleep (K_MSEC (100 ));
198
+ static int check_autonegotiation_completion (const struct device * dev )
199
+ {
200
+ const struct phy_mii_dev_config * const cfg = dev -> config ;
201
+ struct phy_mii_dev_data * const data = dev -> data ;
207
202
208
- /* On some PHY chips, the BMSR bits are latched, so the first read may
209
- * show incorrect status. A second read ensures correct values.
210
- */
211
- if (phy_mii_reg_read (dev , MII_BMSR , & bmsr_reg ) < 0 ) {
212
- return - EIO ;
213
- }
203
+ uint16_t anar_reg = 0 ;
204
+ uint16_t bmsr_reg = 0 ;
205
+ uint16_t anlpar_reg = 0 ;
206
+ uint16_t c1kt_reg = 0 ;
207
+ uint16_t s1kt_reg = 0 ;
214
208
215
- /* Second read, clears the latched bits and gives the correct status */
216
- if (phy_mii_reg_read (dev , MII_BMSR , & bmsr_reg ) < 0 ) {
217
- return - EIO ;
209
+ /* On some PHY chips, the BMSR bits are latched, so the first read may
210
+ * show incorrect status. A second read ensures correct values.
211
+ */
212
+ if (phy_mii_reg_read (dev , MII_BMSR , & bmsr_reg ) < 0 ) {
213
+ return - EIO ;
214
+ }
215
+
216
+ /* Second read, clears the latched bits and gives the correct status */
217
+ if (phy_mii_reg_read (dev , MII_BMSR , & bmsr_reg ) < 0 ) {
218
+ return - EIO ;
219
+ }
220
+
221
+ if (!(bmsr_reg & MII_BMSR_AUTONEG_COMPLETE )) {
222
+ if (data -> autoneg_timeout -- == 0U ) {
223
+ LOG_DBG ("PHY (%d) auto-negotiate timedout" ,
224
+ cfg -> phy_addr );
225
+ return - ETIMEDOUT ;
218
226
}
219
- } while (!(bmsr_reg & MII_BMSR_AUTONEG_COMPLETE ));
227
+ return - EINPROGRESS ;
228
+ }
220
229
221
230
LOG_DBG ("PHY (%d) auto-negotiate sequence completed" ,
222
231
cfg -> phy_addr );
223
232
233
+ /* Read PHY default advertising parameters */
234
+ if (phy_mii_reg_read (dev , MII_ANAR , & anar_reg ) < 0 ) {
235
+ return - EIO ;
236
+ }
237
+
224
238
/** Read peer device capability */
225
239
if (phy_mii_reg_read (dev , MII_ANLPAR , & anlpar_reg ) < 0 ) {
226
240
return - EIO ;
@@ -283,7 +297,12 @@ static void monitor_work_handler(struct k_work *work)
283
297
const struct device * dev = data -> dev ;
284
298
int rc ;
285
299
286
- k_sem_take (& data -> sem , K_FOREVER );
300
+ if (k_sem_take (& data -> sem , K_NO_WAIT ) != 0 ) {
301
+ /* Try again soon */
302
+ k_work_reschedule (& data -> monitor_work ,
303
+ K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
304
+ return ;
305
+ }
287
306
288
307
rc = update_link_state (dev );
289
308
@@ -294,9 +313,50 @@ static void monitor_work_handler(struct k_work *work)
294
313
invoke_link_cb (dev );
295
314
}
296
315
297
- /* Submit delayed work */
298
- k_work_reschedule (& data -> monitor_work ,
299
- K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
316
+ if (rc == - EINPROGRESS ) {
317
+ /* Check for autonegotiation completion */
318
+ k_work_reschedule (& data -> autoneg_work ,
319
+ K_MSEC (MII_AUTONEG_POLL_INTERVAL_MS ));
320
+ } else {
321
+ /* Submit delayed work */
322
+ k_work_reschedule (& data -> monitor_work ,
323
+ K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
324
+ }
325
+ }
326
+
327
+ static void autoneg_work_handler (struct k_work * work )
328
+ {
329
+ struct k_work_delayable * dwork = k_work_delayable_from_work (work );
330
+ struct phy_mii_dev_data * const data =
331
+ CONTAINER_OF (dwork , struct phy_mii_dev_data , autoneg_work );
332
+ const struct device * dev = data -> dev ;
333
+ int rc ;
334
+
335
+ if (k_sem_take (& data -> sem , K_NO_WAIT ) != 0 ) {
336
+ /* Try again soon */
337
+ k_work_reschedule (& data -> autoneg_work ,
338
+ K_MSEC (MII_AUTONEG_POLL_INTERVAL_MS ));
339
+ return ;
340
+ }
341
+
342
+ rc = check_autonegotiation_completion (dev );
343
+
344
+ k_sem_give (& data -> sem );
345
+
346
+ /* If link state has changed and a callback is set, invoke callback */
347
+ if (rc == 0 ) {
348
+ invoke_link_cb (dev );
349
+ }
350
+
351
+ if (rc == - EINPROGRESS ) {
352
+ /* Check again soon */
353
+ k_work_reschedule (& data -> autoneg_work ,
354
+ K_MSEC (MII_AUTONEG_POLL_INTERVAL_MS ));
355
+ } else {
356
+ /* Schedule the next monitoring call */
357
+ k_work_reschedule (& data -> monitor_work ,
358
+ K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
359
+ }
300
360
}
301
361
302
362
static int phy_mii_read (const struct device * dev , uint16_t reg_addr ,
@@ -479,6 +539,8 @@ static int phy_mii_initialize(const struct device *dev)
479
539
480
540
k_work_init_delayable (& data -> monitor_work ,
481
541
monitor_work_handler );
542
+ k_work_init_delayable (& data -> autoneg_work ,
543
+ autoneg_work_handler );
482
544
483
545
monitor_work_handler (& data -> monitor_work .work );
484
546
}
0 commit comments