]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/sfc/xfp_phy.c
sfc: Added checks for heap allocation failure
[linux-2.6-omap-h63xx.git] / drivers / net / sfc / xfp_phy.c
index 66dd5bf1eaa90dec3a0883dc5914b1642b5e6a53..f3684ad28887b66648d1592e248f1beac81e7d06 100644 (file)
                           MDIO_MMDREG_DEVS0_PMAPMD |   \
                           MDIO_MMDREG_DEVS0_PHYXS)
 
+#define XFP_LOOPBACKS ((1 << LOOPBACK_PCS) |           \
+                      (1 << LOOPBACK_PMAPMD) |         \
+                      (1 << LOOPBACK_NETWORK))
+
 /****************************************************************************/
 /* Quake-specific MDIO registers */
 #define MDIO_QUAKE_LED0_REG    (0xD006)
@@ -35,6 +39,10 @@ void xfp_set_led(struct efx_nic *p, int led, int mode)
                            mode);
 }
 
+struct xfp_phy_data {
+       int tx_disabled;
+};
+
 #define XFP_MAX_RESET_TIME 500
 #define XFP_RESET_WAIT 10
 
@@ -72,18 +80,33 @@ static int xfp_reset_phy(struct efx_nic *efx)
 
 static int xfp_phy_init(struct efx_nic *efx)
 {
+       struct xfp_phy_data *phy_data;
        u32 devid = mdio_clause45_read_id(efx, MDIO_MMD_PHYXS);
        int rc;
 
+       phy_data = kzalloc(sizeof(struct xfp_phy_data), GFP_KERNEL);
+       if (!phy_data)
+               return -ENOMEM;
+       efx->phy_data = phy_data;
+
        EFX_INFO(efx, "XFP: PHY ID reg %x (OUI %x model %x revision"
                 " %x)\n", devid, MDIO_ID_OUI(devid), MDIO_ID_MODEL(devid),
                 MDIO_ID_REV(devid));
 
+       phy_data->tx_disabled = efx->tx_disabled;
+
        rc = xfp_reset_phy(efx);
 
        EFX_INFO(efx, "XFP: PHY init %s.\n",
                 rc ? "failed" : "successful");
+       if (rc < 0)
+               goto fail;
 
+       return 0;
+
+ fail:
+       kfree(efx->phy_data);
+       efx->phy_data = NULL;
        return rc;
 }
 
@@ -110,6 +133,16 @@ static int xfp_phy_check_hw(struct efx_nic *efx)
 
 static void xfp_phy_reconfigure(struct efx_nic *efx)
 {
+       struct xfp_phy_data *phy_data = efx->phy_data;
+
+       /* Reset the PHY when moving from tx off to tx on */
+       if (phy_data->tx_disabled && !efx->tx_disabled)
+               xfp_reset_phy(efx);
+
+       mdio_clause45_transmit_disable(efx);
+       mdio_clause45_phy_reconfigure(efx);
+
+       phy_data->tx_disabled = efx->tx_disabled;
        efx->link_up = xfp_link_ok(efx);
        efx->link_options = GM_LPA_10000FULL;
 }
@@ -119,6 +152,10 @@ static void xfp_phy_fini(struct efx_nic *efx)
 {
        /* Clobber the LED if it was blinking */
        efx->board_info.blink(efx, 0);
+
+       /* Free the context block */
+       kfree(efx->phy_data);
+       efx->phy_data = NULL;
 }
 
 struct efx_phy_operations falcon_xfp_phy_ops = {
@@ -129,4 +166,5 @@ struct efx_phy_operations falcon_xfp_phy_ops = {
        .clear_interrupt = xfp_phy_clear_interrupt,
        .reset_xaui      = efx_port_dummy_op_void,
        .mmds            = XFP_REQUIRED_DEVS,
+       .loopbacks       = XFP_LOOPBACKS,
 };