static void xgbe_an37_state_machine(struct xgbe_prv_data *pdata) { enum xgbe_an cur_state = pdata->an_state; if (!pdata->an_int) return; if (pdata->an_int & XGBE_AN_CL37_INT_CMPLT) { pdata->an_state = XGBE_AN_COMPLETE; pdata->an_int &= ~XGBE_AN_CL37_INT_CMPLT; /* If SGMII is enabled, check the link status */ if ((pdata->an_mode == XGBE_AN_MODE_CL37_SGMII) && !(pdata->an_status & XGBE_SGMII_AN_LINK_STATUS)) pdata->an_state = XGBE_AN_NO_LINK; } netif_dbg(pdata, link, pdata->netdev, "CL37 AN %s\n", xgbe_state_as_string(pdata->an_state)); cur_state = pdata->an_state; switch (pdata->an_state) { case XGBE_AN_READY: break; case XGBE_AN_COMPLETE: netif_dbg(pdata, link, pdata->netdev, "Auto negotiation successful\n"); break; case XGBE_AN_NO_LINK: break; default: pdata->an_state = XGBE_AN_ERROR; } if (pdata->an_state == XGBE_AN_ERROR) { netdev_err(pdata->netdev, "error during auto-negotiation, state=%u\n", cur_state); pdata->an_int = 0; xgbe_an37_clear_interrupts(pdata); } if (pdata->an_state >= XGBE_AN_COMPLETE) { pdata->an_result = pdata->an_state; pdata->an_state = XGBE_AN_READY; netif_dbg(pdata, link, pdata->netdev, "CL37 AN result: %s\n", xgbe_state_as_string(pdata->an_result)); } xgbe_an37_enable_interrupts(pdata); }
static void xgbe_an73_state_machine(struct xgbe_prv_data *pdata) { enum xgbe_an cur_state = pdata->an_state; if (!pdata->an_int) return; next_int: if (pdata->an_int & XGBE_AN_CL73_PG_RCV) { pdata->an_state = XGBE_AN_PAGE_RECEIVED; pdata->an_int &= ~XGBE_AN_CL73_PG_RCV; } else if (pdata->an_int & XGBE_AN_CL73_INC_LINK) { pdata->an_state = XGBE_AN_INCOMPAT_LINK; pdata->an_int &= ~XGBE_AN_CL73_INC_LINK; } else if (pdata->an_int & XGBE_AN_CL73_INT_CMPLT) { pdata->an_state = XGBE_AN_COMPLETE; pdata->an_int &= ~XGBE_AN_CL73_INT_CMPLT; } else { pdata->an_state = XGBE_AN_ERROR; } again: netif_dbg(pdata, link, pdata->netdev, "CL73 AN %s\n", xgbe_state_as_string(pdata->an_state)); cur_state = pdata->an_state; switch (pdata->an_state) { case XGBE_AN_READY: pdata->an_supported = 0; break; case XGBE_AN_PAGE_RECEIVED: pdata->an_state = xgbe_an73_page_received(pdata); pdata->an_supported++; break; case XGBE_AN_INCOMPAT_LINK: pdata->an_supported = 0; pdata->parallel_detect = 0; pdata->an_state = xgbe_an73_incompat_link(pdata); break; case XGBE_AN_COMPLETE: pdata->parallel_detect = pdata->an_supported ? 0 : 1; netif_dbg(pdata, link, pdata->netdev, "%s successful\n", pdata->an_supported ? "Auto negotiation" : "Parallel detection"); break; case XGBE_AN_NO_LINK: break; default: pdata->an_state = XGBE_AN_ERROR; } if (pdata->an_state == XGBE_AN_NO_LINK) { pdata->an_int = 0; xgbe_an73_clear_interrupts(pdata); } else if (pdata->an_state == XGBE_AN_ERROR) { netdev_err(pdata->netdev, "error during auto-negotiation, state=%u\n", cur_state); pdata->an_int = 0; xgbe_an73_clear_interrupts(pdata); } if (pdata->an_state >= XGBE_AN_COMPLETE) { pdata->an_result = pdata->an_state; pdata->an_state = XGBE_AN_READY; pdata->kr_state = XGBE_RX_BPA; pdata->kx_state = XGBE_RX_BPA; pdata->an_start = 0; netif_dbg(pdata, link, pdata->netdev, "CL73 AN result: %s\n", xgbe_state_as_string(pdata->an_result)); } if (cur_state != pdata->an_state) goto again; if (pdata->an_int) goto next_int; xgbe_an73_enable_interrupts(pdata); }
static void xgbe_an_state_machine(struct work_struct *work) { struct xgbe_prv_data *pdata = container_of(work, struct xgbe_prv_data, an_work); enum xgbe_an cur_state = pdata->an_state; unsigned int int_reg, int_mask; mutex_lock(&pdata->an_mutex); /* Read the interrupt */ int_reg = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_INT); if (!int_reg) goto out; next_int: if (int_reg & XGBE_AN_PG_RCV) { pdata->an_state = XGBE_AN_PAGE_RECEIVED; int_mask = XGBE_AN_PG_RCV; } else if (int_reg & XGBE_AN_INC_LINK) { pdata->an_state = XGBE_AN_INCOMPAT_LINK; int_mask = XGBE_AN_INC_LINK; } else if (int_reg & XGBE_AN_INT_CMPLT) { pdata->an_state = XGBE_AN_COMPLETE; int_mask = XGBE_AN_INT_CMPLT; } else { pdata->an_state = XGBE_AN_ERROR; int_mask = 0; } /* Clear the interrupt to be processed */ int_reg &= ~int_mask; XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, int_reg); pdata->an_result = pdata->an_state; again: netif_dbg(pdata, link, pdata->netdev, "AN %s\n", xgbe_state_as_string(pdata->an_state)); cur_state = pdata->an_state; switch (pdata->an_state) { case XGBE_AN_READY: pdata->an_supported = 0; break; case XGBE_AN_PAGE_RECEIVED: pdata->an_state = xgbe_an_page_received(pdata); pdata->an_supported++; break; case XGBE_AN_INCOMPAT_LINK: pdata->an_supported = 0; pdata->parallel_detect = 0; pdata->an_state = xgbe_an_incompat_link(pdata); break; case XGBE_AN_COMPLETE: pdata->parallel_detect = pdata->an_supported ? 0 : 1; netif_dbg(pdata, link, pdata->netdev, "%s successful\n", pdata->an_supported ? "Auto negotiation" : "Parallel detection"); break; case XGBE_AN_NO_LINK: break; default: pdata->an_state = XGBE_AN_ERROR; } if (pdata->an_state == XGBE_AN_NO_LINK) { int_reg = 0; XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0); } else if (pdata->an_state == XGBE_AN_ERROR) { netdev_err(pdata->netdev, "error during auto-negotiation, state=%u\n", cur_state); int_reg = 0; XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0); } if (pdata->an_state >= XGBE_AN_COMPLETE) { pdata->an_result = pdata->an_state; pdata->an_state = XGBE_AN_READY; pdata->kr_state = XGBE_RX_BPA; pdata->kx_state = XGBE_RX_BPA; pdata->an_start = 0; netif_dbg(pdata, link, pdata->netdev, "AN result: %s\n", xgbe_state_as_string(pdata->an_result)); } if (cur_state != pdata->an_state) goto again; if (int_reg) goto next_int; out: enable_irq(pdata->an_irq); mutex_unlock(&pdata->an_mutex); }
static void xgbe_an_state_machine(struct work_struct *work) { struct xgbe_prv_data *pdata = container_of(work, struct xgbe_prv_data, an_work); enum xgbe_an cur_state = pdata->an_state; mutex_lock(&pdata->an_mutex); if (!pdata->an_int) goto out; next_int: if (pdata->an_int & XGBE_AN_PG_RCV) { pdata->an_state = XGBE_AN_PAGE_RECEIVED; pdata->an_int &= ~XGBE_AN_PG_RCV; } else if (pdata->an_int & XGBE_AN_INC_LINK) { pdata->an_state = XGBE_AN_INCOMPAT_LINK; pdata->an_int &= ~XGBE_AN_INC_LINK; } else if (pdata->an_int & XGBE_AN_INT_CMPLT) { pdata->an_state = XGBE_AN_COMPLETE; pdata->an_int &= ~XGBE_AN_INT_CMPLT; } else { pdata->an_state = XGBE_AN_ERROR; } pdata->an_result = pdata->an_state; again: netif_dbg(pdata, link, pdata->netdev, "AN %s\n", xgbe_state_as_string(pdata->an_state)); cur_state = pdata->an_state; switch (pdata->an_state) { case XGBE_AN_READY: pdata->an_supported = 0; break; case XGBE_AN_PAGE_RECEIVED: pdata->an_state = xgbe_an_page_received(pdata); pdata->an_supported++; break; case XGBE_AN_INCOMPAT_LINK: pdata->an_supported = 0; pdata->parallel_detect = 0; pdata->an_state = xgbe_an_incompat_link(pdata); break; case XGBE_AN_COMPLETE: pdata->parallel_detect = pdata->an_supported ? 0 : 1; netif_dbg(pdata, link, pdata->netdev, "%s successful\n", pdata->an_supported ? "Auto negotiation" : "Parallel detection"); break; case XGBE_AN_NO_LINK: break; default: pdata->an_state = XGBE_AN_ERROR; } if (pdata->an_state == XGBE_AN_NO_LINK) { pdata->an_int = 0; XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0); } else if (pdata->an_state == XGBE_AN_ERROR) { netdev_err(pdata->netdev, "error during auto-negotiation, state=%u\n", cur_state); pdata->an_int = 0; XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0); } if (pdata->an_state >= XGBE_AN_COMPLETE) { pdata->an_result = pdata->an_state; pdata->an_state = XGBE_AN_READY; pdata->kr_state = XGBE_RX_BPA; pdata->kx_state = XGBE_RX_BPA; pdata->an_start = 0; netif_dbg(pdata, link, pdata->netdev, "AN result: %s\n", xgbe_state_as_string(pdata->an_result)); } if (cur_state != pdata->an_state) goto again; if (pdata->an_int) goto next_int; out: /* Enable AN interrupts on the way out */ XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, XGBE_AN_INT_MASK); mutex_unlock(&pdata->an_mutex); }