Skip to content

Commit f569bb5

Browse files
maass-hamburgdkalowsk
authored andcommitted
drivers: ethernet: phy_mii: restart autoneg after phy_configure_link
make sure that autonegotiation is restarted, after changing the speeds. Also make sure to only write the changed registers, as mdio is pretty slow. Signed-off-by: Fin Maaß <f.maass@vogl-electronic.com>
1 parent b1483a6 commit f569bb5

File tree

1 file changed

+67
-18
lines changed

1 file changed

+67
-18
lines changed

drivers/ethernet/phy/phy_mii.c

Lines changed: 67 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ struct phy_mii_dev_data {
3939
struct k_work_delayable monitor_work;
4040
struct k_work_delayable autoneg_work;
4141
bool gigabit_supported;
42+
bool restart_autoneg;
4243
uint32_t autoneg_timeout;
4344
#endif
4445
};
@@ -175,16 +176,19 @@ static int update_link_state(const struct device *dev)
175176
link_up = bmsr_reg & MII_BMSR_LINK_STATUS;
176177

177178
/* If there is no change in link state don't proceed. */
178-
if (link_up == data->state.is_up) {
179+
if ((link_up == data->state.is_up) && !data->restart_autoneg) {
179180
return -EAGAIN;
180181
}
181182

182183
data->state.is_up = link_up;
183184

184-
/* If link is down, there is nothing more to be done */
185-
if (data->state.is_up == false) {
185+
if (!data->state.is_up) {
186+
data->state.speed = 0;
186187
LOG_INF("PHY (%d) is down", cfg->phy_addr);
187-
return 0;
188+
/* If not restarting auto-negotiation, just return */
189+
if (!data->restart_autoneg) {
190+
return 0;
191+
}
188192
}
189193

190194
/**
@@ -205,6 +209,8 @@ static int update_link_state(const struct device *dev)
205209
return -EIO;
206210
}
207211

212+
data->restart_autoneg = false;
213+
208214
/* We have to wait for the auto-negotiation process to complete */
209215
data->autoneg_timeout = CONFIG_PHY_AUTONEG_TIMEOUT_MS / MII_AUTONEG_POLL_INTERVAL_MS;
210216
return -EINPROGRESS;
@@ -221,6 +227,10 @@ static int check_autonegotiation_completion(const struct device *dev)
221227
uint16_t c1kt_reg = 0;
222228
uint16_t s1kt_reg = 0;
223229

230+
if (data->restart_autoneg) {
231+
return -EAGAIN;
232+
}
233+
224234
/* On some PHY chips, the BMSR bits are latched, so the first read may
225235
* show incorrect status. A second read ensures correct values.
226236
*/
@@ -280,6 +290,8 @@ static int check_autonegotiation_completion(const struct device *dev)
280290
data->state.speed = LINK_HALF_10BASE;
281291
}
282292

293+
data->state.is_up = (bmsr_reg & MII_BMSR_LINK_STATUS) != 0U;
294+
283295
LOG_INF("PHY (%d) Link speed %s Mb, %s duplex",
284296
cfg->phy_addr,
285297
PHY_LINK_IS_SPEED_1000M(data->state.speed) ? "1000" :
@@ -376,8 +388,11 @@ static int phy_mii_cfg_link(const struct device *dev,
376388
struct phy_mii_dev_data *const data = dev->data;
377389
const struct phy_mii_dev_config *const cfg = dev->config;
378390
uint16_t anar_reg;
391+
uint16_t anar_reg_old;
379392
uint16_t bmcr_reg;
380393
uint16_t c1kt_reg;
394+
uint16_t c1kt_reg_old;
395+
int ret = 0;
381396

382397
/* if there is no mdio (fixed-link) it is not supported to configure link */
383398
if (cfg->fixed) {
@@ -388,17 +403,23 @@ static int phy_mii_cfg_link(const struct device *dev,
388403
return -ENODEV;
389404
}
390405

406+
k_sem_take(&data->sem, K_FOREVER);
407+
391408
if (phy_mii_reg_read(dev, MII_ANAR, &anar_reg) < 0) {
392-
return -EIO;
409+
ret = -EIO;
410+
goto cfg_link_end;
393411
}
412+
anar_reg_old = anar_reg;
394413

395414
if (phy_mii_reg_read(dev, MII_BMCR, &bmcr_reg) < 0) {
396-
return -EIO;
415+
ret = -EIO;
416+
goto cfg_link_end;
397417
}
398418

399419
if (data->gigabit_supported) {
400420
if (phy_mii_reg_read(dev, MII_1KTCR, &c1kt_reg) < 0) {
401-
return -EIO;
421+
ret = -EIO;
422+
goto cfg_link_end;
402423
}
403424
}
404425

@@ -427,6 +448,8 @@ static int phy_mii_cfg_link(const struct device *dev,
427448
}
428449

429450
if (data->gigabit_supported) {
451+
c1kt_reg_old = c1kt_reg;
452+
430453
if (adv_speeds & LINK_FULL_1000BASE) {
431454
c1kt_reg |= MII_ADVERTISE_1000_FULL;
432455
} else {
@@ -439,22 +462,41 @@ static int phy_mii_cfg_link(const struct device *dev,
439462
c1kt_reg &= ~MII_ADVERTISE_1000_HALF;
440463
}
441464

442-
if (phy_mii_reg_write(dev, MII_1KTCR, c1kt_reg) < 0) {
443-
return -EIO;
465+
if (c1kt_reg != c1kt_reg_old) {
466+
if (phy_mii_reg_write(dev, MII_1KTCR, c1kt_reg) < 0) {
467+
ret = -EIO;
468+
goto cfg_link_end;
469+
}
470+
471+
data->restart_autoneg = true;
444472
}
445473
}
446474

447-
bmcr_reg |= MII_BMCR_AUTONEG_ENABLE;
475+
if (anar_reg != anar_reg_old) {
476+
if (phy_mii_reg_write(dev, MII_ANAR, anar_reg) < 0) {
477+
ret = -EIO;
478+
goto cfg_link_end;
479+
}
448480

449-
if (phy_mii_reg_write(dev, MII_ANAR, anar_reg) < 0) {
450-
return -EIO;
481+
data->restart_autoneg = true;
451482
}
452483

453-
if (phy_mii_reg_write(dev, MII_BMCR, bmcr_reg) < 0) {
454-
return -EIO;
484+
if ((bmcr_reg & MII_BMCR_AUTONEG_ENABLE) == 0U) {
485+
if (phy_mii_reg_write(dev, MII_BMCR, bmcr_reg | MII_BMCR_AUTONEG_ENABLE) < 0) {
486+
ret = -EIO;
487+
goto cfg_link_end;
488+
}
455489
}
456490

457-
return 0;
491+
if (data->restart_autoneg && data->state.is_up) {
492+
k_work_cancel_delayable(&data->autoneg_work);
493+
k_work_reschedule(&data->monitor_work, K_NO_WAIT);
494+
}
495+
496+
cfg_link_end:
497+
k_sem_give(&data->sem);
498+
499+
return ret;
458500
}
459501
#endif /* ANY_DYNAMIC_LINK */
460502

@@ -467,6 +509,13 @@ static int phy_mii_get_link_state(const struct device *dev,
467509

468510
memcpy(state, &data->state, sizeof(struct phy_link_state));
469511

512+
if (data->state.speed == 0) {
513+
/* If speed is 0, then link is also down, happens when autonegotiation is in
514+
* progress
515+
*/
516+
data->state.is_up = false;
517+
}
518+
470519
k_sem_give(&data->sem);
471520

472521
return 0;
@@ -558,6 +607,9 @@ static int phy_mii_initialize_dynamic_link(const struct device *dev)
558607

559608
data->gigabit_supported = is_gigabit_supported(dev);
560609

610+
k_work_init_delayable(&data->monitor_work, monitor_work_handler);
611+
k_work_init_delayable(&data->autoneg_work, autoneg_work_handler);
612+
561613
/* Advertise all speeds */
562614
phy_mii_cfg_link(dev, LINK_HALF_10BASE |
563615
LINK_FULL_10BASE |
@@ -566,9 +618,6 @@ static int phy_mii_initialize_dynamic_link(const struct device *dev)
566618
LINK_HALF_1000BASE |
567619
LINK_FULL_1000BASE);
568620

569-
k_work_init_delayable(&data->monitor_work, monitor_work_handler);
570-
k_work_init_delayable(&data->autoneg_work, autoneg_work_handler);
571-
572621
monitor_work_handler(&data->monitor_work.work);
573622

574623
return 0;

0 commit comments

Comments
 (0)