static int xgbe_read_mmd_regs(struct xgbe_prv_data *pdata, int prtad,
                              int mmd_reg)
 {
+       unsigned long flags;
        unsigned int mmd_address;
        int mmd_data;
 
         * register offsets must therefore be adjusted by left shifting the
         * offset 2 bits and reading 32 bits of data.
         */
-       mutex_lock(&pdata->xpcs_mutex);
+       spin_lock_irqsave(&pdata->xpcs_lock, flags);
        XPCS_IOWRITE(pdata, PCS_MMD_SELECT << 2, mmd_address >> 8);
        mmd_data = XPCS_IOREAD(pdata, (mmd_address & 0xff) << 2);
-       mutex_unlock(&pdata->xpcs_mutex);
+       spin_unlock_irqrestore(&pdata->xpcs_lock, flags);
 
        return mmd_data;
 }
                                int mmd_reg, int mmd_data)
 {
        unsigned int mmd_address;
+       unsigned long flags;
 
        if (mmd_reg & MII_ADDR_C45)
                mmd_address = mmd_reg & ~MII_ADDR_C45;
         * register offsets must therefore be adjusted by left shifting the
         * offset 2 bits and reading 32 bits of data.
         */
-       mutex_lock(&pdata->xpcs_mutex);
+       spin_lock_irqsave(&pdata->xpcs_lock, flags);
        XPCS_IOWRITE(pdata, PCS_MMD_SELECT << 2, mmd_address >> 8);
        XPCS_IOWRITE(pdata, (mmd_address & 0xff) << 2, mmd_data);
-       mutex_unlock(&pdata->xpcs_mutex);
+       spin_unlock_irqrestore(&pdata->xpcs_lock, flags);
 }
 
 static int xgbe_tx_complete(struct xgbe_ring_desc *rdesc)
 
  *
  * License 1: GPLv2
  *
- * Copyright (c) 2014 Advanced Micro Devices, Inc.
+ * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
  *
  * This file is free software; you may copy, redistribute and/or modify
  * it under the terms of the GNU General Public License as published by
  *
  * License 2: Modified BSD
  *
- * Copyright (c) 2014 Advanced Micro Devices, Inc.
+ * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
        platform_set_drvdata(pdev, netdev);
 
        spin_lock_init(&pdata->lock);
-       mutex_init(&pdata->xpcs_mutex);
+       spin_lock_init(&pdata->xpcs_lock);
        mutex_init(&pdata->rss_mutex);
        spin_lock_init(&pdata->tstamp_lock);
 
 
  *
  * License 1: GPLv2
  *
- * Copyright (c) 2014 Advanced Micro Devices, Inc.
+ * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
  *
  * This file is free software; you may copy, redistribute and/or modify
  * it under the terms of the GNU General Public License as published by
  *
  * License 2: Modified BSD
  *
- * Copyright (c) 2014 Advanced Micro Devices, Inc.
+ * Copyright (c) 2014-2016 Advanced Micro Devices, Inc.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 
        netif_dbg(pdata, intr, pdata->netdev, "AN interrupt received\n");
 
-       /* Interrupt reason must be read and cleared outside of IRQ context */
-       disable_irq_nosync(pdata->an_irq);
+       /* Disable AN interrupts */
+       XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK, 0);
+
+       /* Save the interrupt(s) that fired */
+       pdata->an_int = XMDIO_READ(pdata, MDIO_MMD_AN, MDIO_AN_INT);
 
-       queue_work(pdata->an_workqueue, &pdata->an_irq_work);
+       if (pdata->an_int) {
+               /* Clear the interrupt(s) that fired and process them */
+               XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, ~pdata->an_int);
+
+               queue_work(pdata->an_workqueue, &pdata->an_irq_work);
+       } else {
+               /* Enable AN interrupts */
+               XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INTMASK,
+                           XGBE_AN_INT_MASK);
+       }
 
        return IRQ_HANDLED;
 }
                                                   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)
+       if (!pdata->an_int)
                goto out;
 
 next_int:
-       if (int_reg & XGBE_AN_PG_RCV) {
+       if (pdata->an_int & 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_int &= ~XGBE_AN_PG_RCV;
+       } else if (pdata->an_int & 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_int &= ~XGBE_AN_INC_LINK;
+       } else if (pdata->an_int & XGBE_AN_INT_CMPLT) {
                pdata->an_state = XGBE_AN_COMPLETE;
-               int_mask = XGBE_AN_INT_CMPLT;
+               pdata->an_int &= ~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:
        }
 
        if (pdata->an_state == XGBE_AN_NO_LINK) {
-               int_reg = 0;
+               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);
 
-               int_reg = 0;
+               pdata->an_int = 0;
                XMDIO_WRITE(pdata, MDIO_MMD_AN, MDIO_AN_INT, 0);
        }
 
        if (cur_state != pdata->an_state)
                goto again;
 
-       if (int_reg)
+       if (pdata->an_int)
                goto next_int;
 
 out:
-       enable_irq(pdata->an_irq);
+       /* 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);
 }