@@ -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
@@ -155,13 +160,8 @@ static int update_link_state(const struct device *dev)
155
160
struct phy_mii_dev_data * const data = dev -> data ;
156
161
bool link_up ;
157
162
158
- uint16_t anar_reg = 0 ;
159
163
uint16_t bmcr_reg = 0 ;
160
164
uint16_t bmsr_reg = 0 ;
161
- uint16_t anlpar_reg = 0 ;
162
- uint16_t c1kt_reg = 0 ;
163
- uint16_t s1kt_reg = 0 ;
164
- uint32_t timeout = CONFIG_PHY_AUTONEG_TIMEOUT_MS / 100 ;
165
165
166
166
if (phy_mii_reg_read (dev , MII_BMSR , & bmsr_reg ) < 0 ) {
167
167
return - EIO ;
@@ -188,11 +188,6 @@ static int update_link_state(const struct device *dev)
188
188
LOG_DBG ("PHY (%d) Starting MII PHY auto-negotiate sequence" ,
189
189
cfg -> phy_addr );
190
190
191
- /* Read PHY default advertising parameters */
192
- if (phy_mii_reg_read (dev , MII_ANAR , & anar_reg ) < 0 ) {
193
- return - EIO ;
194
- }
195
-
196
191
/* Configure and start auto-negotiation process */
197
192
if (phy_mii_reg_read (dev , MII_BMCR , & bmcr_reg ) < 0 ) {
198
193
return - EIO ;
@@ -205,15 +200,21 @@ static int update_link_state(const struct device *dev)
205
200
return - EIO ;
206
201
}
207
202
208
- /* Wait for the auto-negotiation process to complete */
209
- do {
210
- if (timeout -- == 0U ) {
211
- LOG_DBG ("PHY (%d) auto-negotiate timedout" ,
212
- cfg -> phy_addr );
213
- return - ETIMEDOUT ;
214
- }
203
+ /* We have to wait for the auto-negotiation process to complete */
204
+ data -> autoneg_timeout = CONFIG_PHY_AUTONEG_TIMEOUT_MS / MII_AUTONEG_POLL_INTERVAL_MS ;
205
+ return - EINPROGRESS ;
206
+ }
215
207
216
- k_sleep (K_MSEC (100 ));
208
+ static int check_autonegotiation_completion (const struct device * dev )
209
+ {
210
+ const struct phy_mii_dev_config * const cfg = dev -> config ;
211
+ struct phy_mii_dev_data * const data = dev -> data ;
212
+
213
+ uint16_t anar_reg = 0 ;
214
+ uint16_t bmsr_reg = 0 ;
215
+ uint16_t anlpar_reg = 0 ;
216
+ uint16_t c1kt_reg = 0 ;
217
+ uint16_t s1kt_reg = 0 ;
217
218
218
219
/* On some PHY chips, the BMSR bits are latched, so the first read may
219
220
* show incorrect status. A second read ensures correct values.
@@ -226,11 +227,24 @@ static int update_link_state(const struct device *dev)
226
227
if (phy_mii_reg_read (dev , MII_BMSR , & bmsr_reg ) < 0 ) {
227
228
return - EIO ;
228
229
}
229
- } while (!(bmsr_reg & MII_BMSR_AUTONEG_COMPLETE ));
230
+
231
+ if (!(bmsr_reg & MII_BMSR_AUTONEG_COMPLETE )) {
232
+ if (data -> autoneg_timeout -- == 0U ) {
233
+ LOG_DBG ("PHY (%d) auto-negotiate timedout" ,
234
+ cfg -> phy_addr );
235
+ return - ETIMEDOUT ;
236
+ }
237
+ return - EINPROGRESS ;
238
+ }
230
239
231
240
LOG_DBG ("PHY (%d) auto-negotiate sequence completed" ,
232
241
cfg -> phy_addr );
233
242
243
+ /* Read PHY default advertising parameters */
244
+ if (phy_mii_reg_read (dev , MII_ANAR , & anar_reg ) < 0 ) {
245
+ return - EIO ;
246
+ }
247
+
234
248
/** Read peer device capability */
235
249
if (phy_mii_reg_read (dev , MII_ANLPAR , & anlpar_reg ) < 0 ) {
236
250
return - EIO ;
@@ -293,7 +307,12 @@ static void monitor_work_handler(struct k_work *work)
293
307
const struct device * dev = data -> dev ;
294
308
int rc ;
295
309
296
- k_sem_take (& data -> sem , K_FOREVER );
310
+ if (k_sem_take (& data -> sem , K_NO_WAIT ) != 0 ) {
311
+ /* Try again soon */
312
+ k_work_reschedule (& data -> monitor_work ,
313
+ K_MSEC (MII_AUTONEG_POLL_INTERVAL_MS ));
314
+ return ;
315
+ }
297
316
298
317
rc = update_link_state (dev );
299
318
@@ -304,9 +323,50 @@ static void monitor_work_handler(struct k_work *work)
304
323
invoke_link_cb (dev );
305
324
}
306
325
326
+ if (rc == - EINPROGRESS ) {
327
+ /* Check for autonegotiation completion */
328
+ k_work_reschedule (& data -> autoneg_work ,
329
+ K_MSEC (MII_AUTONEG_POLL_INTERVAL_MS ));
330
+ } else {
307
331
/* Submit delayed work */
308
332
k_work_reschedule (& data -> monitor_work ,
309
333
K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
334
+ }
335
+ }
336
+
337
+ static void autoneg_work_handler (struct k_work * work )
338
+ {
339
+ struct k_work_delayable * dwork = k_work_delayable_from_work (work );
340
+ struct phy_mii_dev_data * const data =
341
+ CONTAINER_OF (dwork , struct phy_mii_dev_data , autoneg_work );
342
+ const struct device * dev = data -> dev ;
343
+ int rc ;
344
+
345
+ if (k_sem_take (& data -> sem , K_NO_WAIT ) != 0 ) {
346
+ /* Try again soon */
347
+ k_work_reschedule (& data -> autoneg_work ,
348
+ K_MSEC (MII_AUTONEG_POLL_INTERVAL_MS ));
349
+ return ;
350
+ }
351
+
352
+ rc = check_autonegotiation_completion (dev );
353
+
354
+ k_sem_give (& data -> sem );
355
+
356
+ /* If link state has changed and a callback is set, invoke callback */
357
+ if (rc == 0 ) {
358
+ invoke_link_cb (dev );
359
+ }
360
+
361
+ if (rc == - EINPROGRESS ) {
362
+ /* Check again soon */
363
+ k_work_reschedule (& data -> autoneg_work ,
364
+ K_MSEC (MII_AUTONEG_POLL_INTERVAL_MS ));
365
+ } else {
366
+ /* Schedule the next monitoring call */
367
+ k_work_reschedule (& data -> monitor_work ,
368
+ K_MSEC (CONFIG_PHY_MONITOR_PERIOD ));
369
+ }
310
370
}
311
371
312
372
static int phy_mii_read (const struct device * dev , uint16_t reg_addr ,
@@ -499,6 +559,8 @@ static int phy_mii_initialize(const struct device *dev)
499
559
500
560
k_work_init_delayable (& data -> monitor_work ,
501
561
monitor_work_handler );
562
+ k_work_init_delayable (& data -> autoneg_work ,
563
+ autoneg_work_handler );
502
564
503
565
monitor_work_handler (& data -> monitor_work .work );
504
566
}
0 commit comments