| .. | .. |
|---|
| 496 | 496 | reg |= XGBE_KR_TRAINING_ENABLE; |
|---|
| 497 | 497 | reg |= XGBE_KR_TRAINING_START; |
|---|
| 498 | 498 | XMDIO_WRITE(pdata, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, reg); |
|---|
| 499 | + pdata->kr_start_time = jiffies; |
|---|
| 499 | 500 | |
|---|
| 500 | 501 | netif_dbg(pdata, link, pdata->netdev, |
|---|
| 501 | 502 | "KR training initiated\n"); |
|---|
| .. | .. |
|---|
| 632 | 633 | |
|---|
| 633 | 634 | xgbe_switch_mode(pdata); |
|---|
| 634 | 635 | |
|---|
| 636 | + pdata->an_result = XGBE_AN_READY; |
|---|
| 637 | + |
|---|
| 635 | 638 | xgbe_an_restart(pdata); |
|---|
| 636 | 639 | |
|---|
| 637 | 640 | return XGBE_AN_INCOMPAT_LINK; |
|---|
| .. | .. |
|---|
| 688 | 691 | } |
|---|
| 689 | 692 | } |
|---|
| 690 | 693 | |
|---|
| 691 | | -static void xgbe_an_isr_task(unsigned long data) |
|---|
| 694 | +static void xgbe_an_isr_task(struct tasklet_struct *t) |
|---|
| 692 | 695 | { |
|---|
| 693 | | - struct xgbe_prv_data *pdata = (struct xgbe_prv_data *)data; |
|---|
| 696 | + struct xgbe_prv_data *pdata = from_tasklet(pdata, t, tasklet_an); |
|---|
| 694 | 697 | |
|---|
| 695 | 698 | netif_dbg(pdata, intr, pdata->netdev, "AN interrupt received\n"); |
|---|
| 696 | 699 | |
|---|
| .. | .. |
|---|
| 715 | 718 | if (pdata->isr_as_tasklet) |
|---|
| 716 | 719 | tasklet_schedule(&pdata->tasklet_an); |
|---|
| 717 | 720 | else |
|---|
| 718 | | - xgbe_an_isr_task((unsigned long)pdata); |
|---|
| 721 | + xgbe_an_isr_task(&pdata->tasklet_an); |
|---|
| 719 | 722 | |
|---|
| 720 | 723 | return IRQ_HANDLED; |
|---|
| 721 | 724 | } |
|---|
| 722 | 725 | |
|---|
| 723 | 726 | static irqreturn_t xgbe_an_combined_isr(struct xgbe_prv_data *pdata) |
|---|
| 724 | 727 | { |
|---|
| 725 | | - xgbe_an_isr_task((unsigned long)pdata); |
|---|
| 728 | + xgbe_an_isr_task(&pdata->tasklet_an); |
|---|
| 726 | 729 | |
|---|
| 727 | 730 | return IRQ_HANDLED; |
|---|
| 728 | 731 | } |
|---|
| .. | .. |
|---|
| 1275 | 1278 | static void xgbe_check_link_timeout(struct xgbe_prv_data *pdata) |
|---|
| 1276 | 1279 | { |
|---|
| 1277 | 1280 | unsigned long link_timeout; |
|---|
| 1281 | + unsigned long kr_time; |
|---|
| 1282 | + int wait; |
|---|
| 1278 | 1283 | |
|---|
| 1279 | 1284 | link_timeout = pdata->link_check + (XGBE_LINK_TIMEOUT * HZ); |
|---|
| 1280 | 1285 | if (time_after(jiffies, link_timeout)) { |
|---|
| 1286 | + if ((xgbe_cur_mode(pdata) == XGBE_MODE_KR) && |
|---|
| 1287 | + pdata->phy.autoneg == AUTONEG_ENABLE) { |
|---|
| 1288 | + /* AN restart should not happen while KR training is in progress. |
|---|
| 1289 | + * The while loop ensures no AN restart during KR training, |
|---|
| 1290 | + * waits up to 500ms and AN restart is triggered only if KR |
|---|
| 1291 | + * training is failed. |
|---|
| 1292 | + */ |
|---|
| 1293 | + wait = XGBE_KR_TRAINING_WAIT_ITER; |
|---|
| 1294 | + while (wait--) { |
|---|
| 1295 | + kr_time = pdata->kr_start_time + |
|---|
| 1296 | + msecs_to_jiffies(XGBE_AN_MS_TIMEOUT); |
|---|
| 1297 | + if (time_after(jiffies, kr_time)) |
|---|
| 1298 | + break; |
|---|
| 1299 | + /* AN restart is not required, if AN result is COMPLETE */ |
|---|
| 1300 | + if (pdata->an_result == XGBE_AN_COMPLETE) |
|---|
| 1301 | + return; |
|---|
| 1302 | + usleep_range(10000, 11000); |
|---|
| 1303 | + } |
|---|
| 1304 | + } |
|---|
| 1281 | 1305 | netif_dbg(pdata, link, pdata->netdev, "AN link timeout\n"); |
|---|
| 1282 | 1306 | xgbe_phy_config_aneg(pdata); |
|---|
| 1283 | 1307 | } |
|---|
| .. | .. |
|---|
| 1288 | 1312 | return pdata->phy_if.phy_impl.an_outcome(pdata); |
|---|
| 1289 | 1313 | } |
|---|
| 1290 | 1314 | |
|---|
| 1291 | | -static void xgbe_phy_status_result(struct xgbe_prv_data *pdata) |
|---|
| 1315 | +static bool xgbe_phy_status_result(struct xgbe_prv_data *pdata) |
|---|
| 1292 | 1316 | { |
|---|
| 1293 | 1317 | struct ethtool_link_ksettings *lks = &pdata->phy.lks; |
|---|
| 1294 | 1318 | enum xgbe_mode mode; |
|---|
| .. | .. |
|---|
| 1323 | 1347 | |
|---|
| 1324 | 1348 | pdata->phy.duplex = DUPLEX_FULL; |
|---|
| 1325 | 1349 | |
|---|
| 1326 | | - if (xgbe_set_mode(pdata, mode) && pdata->an_again) |
|---|
| 1350 | + if (!xgbe_set_mode(pdata, mode)) |
|---|
| 1351 | + return false; |
|---|
| 1352 | + |
|---|
| 1353 | + if (pdata->an_again) |
|---|
| 1327 | 1354 | xgbe_phy_reconfig_aneg(pdata); |
|---|
| 1355 | + |
|---|
| 1356 | + return true; |
|---|
| 1328 | 1357 | } |
|---|
| 1329 | 1358 | |
|---|
| 1330 | 1359 | static void xgbe_phy_status(struct xgbe_prv_data *pdata) |
|---|
| .. | .. |
|---|
| 1354 | 1383 | return; |
|---|
| 1355 | 1384 | } |
|---|
| 1356 | 1385 | |
|---|
| 1357 | | - xgbe_phy_status_result(pdata); |
|---|
| 1386 | + if (xgbe_phy_status_result(pdata)) |
|---|
| 1387 | + return; |
|---|
| 1358 | 1388 | |
|---|
| 1359 | 1389 | if (test_bit(XGBE_LINK_INIT, &pdata->dev_state)) |
|---|
| 1360 | 1390 | clear_bit(XGBE_LINK_INIT, &pdata->dev_state); |
|---|
| .. | .. |
|---|
| 1390 | 1420 | /* Disable auto-negotiation */ |
|---|
| 1391 | 1421 | xgbe_an_disable_all(pdata); |
|---|
| 1392 | 1422 | |
|---|
| 1393 | | - if (pdata->dev_irq != pdata->an_irq) |
|---|
| 1423 | + if (pdata->dev_irq != pdata->an_irq) { |
|---|
| 1394 | 1424 | devm_free_irq(pdata->dev, pdata->an_irq, pdata); |
|---|
| 1425 | + tasklet_kill(&pdata->tasklet_an); |
|---|
| 1426 | + } |
|---|
| 1395 | 1427 | |
|---|
| 1396 | 1428 | pdata->phy_if.phy_impl.stop(pdata); |
|---|
| 1397 | 1429 | |
|---|
| .. | .. |
|---|
| 1413 | 1445 | |
|---|
| 1414 | 1446 | /* If we have a separate AN irq, enable it */ |
|---|
| 1415 | 1447 | if (pdata->dev_irq != pdata->an_irq) { |
|---|
| 1416 | | - tasklet_init(&pdata->tasklet_an, xgbe_an_isr_task, |
|---|
| 1417 | | - (unsigned long)pdata); |
|---|
| 1448 | + tasklet_setup(&pdata->tasklet_an, xgbe_an_isr_task); |
|---|
| 1418 | 1449 | |
|---|
| 1419 | 1450 | ret = devm_request_irq(pdata->dev, pdata->an_irq, |
|---|
| 1420 | 1451 | xgbe_an_isr, 0, pdata->an_name, |
|---|