return IXGBE_MAX_RSS_INDICES;
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                return IXGBE_MAX_RSS_INDICES_X550;
        default:
                return 0;
        board_X540,
        board_X550,
        board_X550EM_x,
+       board_x550em_a,
 };
 
 extern const struct ixgbe_info ixgbe_82598_info;
 extern const struct ixgbe_info ixgbe_X540_info;
 extern const struct ixgbe_info ixgbe_X550_info;
 extern const struct ixgbe_info ixgbe_X550EM_x_info;
+extern const struct ixgbe_info ixgbe_x550em_a_info;
 #ifdef CONFIG_IXGBE_DCB
 extern const struct dcbnl_rtnl_ops dcbnl_ops;
 #endif
 
        switch (hw->mac.type) {
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                IXGBE_WRITE_REG(hw, IXGBE_FDIRSCTPM, ~fdirtcpm);
                break;
        default:
 
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                pcie_offset = IXGBE_PCIE_MSIX_82599_CAPS;
                max_msix_count = IXGBE_MAX_MSIX_VECTORS_82599;
                break;
 
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2014 Intel Corporation.
+  Copyright(c) 1999 - 2016 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                return ixgbe_dcb_hw_config_82599(hw, pfc_en, refill, max,
                                                 bwgid, ptype, prio_tc);
        default:
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                return ixgbe_dcb_config_pfc_82599(hw, pfc_en, prio_tc);
        default:
                break;
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                ixgbe_dcb_config_rx_arbiter_82599(hw, refill, max,
                                                  bwg_id, prio_type, prio_tc);
                ixgbe_dcb_config_tx_desc_arbiter_82599(hw, refill, max,
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                ixgbe_dcb_read_rtrup2tc_82599(hw, map);
                break;
        default:
 
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2014 Intel Corporation.
+  Copyright(c) 1999 - 2016 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
                case ixgbe_mac_X540:
                case ixgbe_mac_X550:
                case ixgbe_mac_X550EM_x:
+               case ixgbe_mac_x550em_a:
                        regs_buff[35 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTL_82599(i));
                        regs_buff[43 + i] = IXGBE_READ_REG(hw, IXGBE_FCRTH_82599(i));
                        break;
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                regs_buff[830] = IXGBE_READ_REG(hw, IXGBE_RTTDCS);
                regs_buff[832] = IXGBE_READ_REG(hw, IXGBE_RTRPCS);
                for (i = 0; i < 8; i++)
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                toggle = 0x7FFFF30F;
                test = reg_test_82599;
                break;
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                reg_ctl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL);
                reg_ctl &= ~IXGBE_DMATXCTL_TE;
                IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, reg_ctl);
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                reg_data = IXGBE_READ_REG(&adapter->hw, IXGBE_DMATXCTL);
                reg_data |= IXGBE_DMATXCTL_TE;
                IXGBE_WRITE_REG(&adapter->hw, IXGBE_DMATXCTL, reg_data);
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                reg_data = IXGBE_READ_REG(hw, IXGBE_MACC);
                reg_data |= IXGBE_MACC_FLU;
                IXGBE_WRITE_REG(hw, IXGBE_MACC, reg_data);
        switch (adapter->hw.mac.type) {
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
        case ixgbe_mac_X540:
        case ixgbe_mac_82599EB:
                info->so_timestamping =
 
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2013 Intel Corporation.
+  Copyright(c) 1999 - 2016 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                if (num_tcs > 4) {
                        /*
                         * TCs    : TC0/1 TC2/3 TC4-7
 
 #define DRV_VERSION "4.2.1-k"
 const char ixgbe_driver_version[] = DRV_VERSION;
 static const char ixgbe_copyright[] =
-                               "Copyright (c) 1999-2015 Intel Corporation.";
+                               "Copyright (c) 1999-2016 Intel Corporation.";
 
 static const char ixgbe_overheat_msg[] = "Network adapter has been stopped because it has over heated. Restart the computer. If the problem persists, power off the system and replace the adapter";
 
        [board_X540]            = &ixgbe_X540_info,
        [board_X550]            = &ixgbe_X550_info,
        [board_X550EM_x]        = &ixgbe_X550EM_x_info,
+       [board_x550em_a]        = &ixgbe_x550em_a_info,
 };
 
 /* ixgbe_pci_tbl - PCI Device ID Table
        {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_KR), board_X550EM_x},
        {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_10G_T), board_X550EM_x},
        {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_X_SFP), board_X550EM_x},
+       {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_X550EM_A_SFP_N), board_x550em_a },
        /* required last entry */
        {0, }
 };
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                if (direction == -1) {
                        /* other causes */
                        msix_vector |= IXGBE_IVAR_ALLOC_VAL;
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                mask = (qmask & 0xFFFFFFFF);
                IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS_EX(0), mask);
                mask = (qmask >> 32);
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                ixgbe_set_ivar(adapter, -1, 1, v_idx);
                break;
        default:
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                /*
                 * set the WDIS bit to not clear the timer bits and cause an
                 * immediate assertion of the interrupt
                return false;
        case ixgbe_mac_82599EB:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                switch (hw->mac.ops.get_media_type(hw)) {
                case ixgbe_media_type_fiber:
                case ixgbe_media_type_fiber_qsfp:
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                mask = (qmask & 0xFFFFFFFF);
                if (mask)
                        IXGBE_WRITE_REG(hw, IXGBE_EIMS_EX(0), mask);
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                mask = (qmask & 0xFFFFFFFF);
                if (mask)
                        IXGBE_WRITE_REG(hw, IXGBE_EIMC_EX(0), mask);
                case ixgbe_mac_X540:
                case ixgbe_mac_X550:
                case ixgbe_mac_X550EM_x:
+               case ixgbe_mac_x550em_a:
                        mask |= IXGBE_EIMS_TS;
                        break;
                default:
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
-               if (adapter->hw.device_id == IXGBE_DEV_ID_X550EM_X_SFP)
+       case ixgbe_mac_x550em_a:
+               if (adapter->hw.device_id == IXGBE_DEV_ID_X550EM_X_SFP ||
+                   adapter->hw.device_id == IXGBE_DEV_ID_X550EM_A_SFP_N)
                        mask |= IXGBE_EIMS_GPI_SDP0(&adapter->hw);
                if (adapter->hw.phy.type == ixgbe_phy_x550em_ext_t)
                        mask |= IXGBE_EICR_GPI_SDP0_X540;
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                if (hw->phy.type == ixgbe_phy_x550em_ext_t &&
                    (eicr & IXGBE_EICR_GPI_SDP0_X540)) {
                        adapter->flags2 |= IXGBE_FLAG2_PHY_INTERRUPT;
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                if (eicr & IXGBE_EICR_ECC) {
                        e_info(link, "Received ECC Err, initiating reset\n");
                        adapter->flags2 |= IXGBE_FLAG2_RESET_REQUESTED;
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, 0xFFFF0000);
                IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(0), ~0);
                IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(1), ~0);
                break;
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                if (adapter->num_vfs)
                        rdrxctl |= IXGBE_RDRXCTL_PSP;
                /* fall through for older HW */
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                for (i = 0; i < adapter->num_rx_queues; i++) {
                        struct ixgbe_ring *ring = adapter->rx_ring[i];
 
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                for (i = 0; i < adapter->num_rx_queues; i++) {
                        struct ixgbe_ring *ring = adapter->rx_ring[i];
 
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
        default:
                if (adapter->flags & IXGBE_FLAG_VMDQ_ENABLED)
                        break;
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
        default:
                if (adapter->flags & IXGBE_FLAG_VMDQ_ENABLED)
                        break;
        switch (adapter->hw.mac.type) {
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                IXGBE_WRITE_REG(&adapter->hw, IXGBE_VXLANCTRL, 0);
                adapter->vxlan_port = 0;
                break;
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                dv_id = IXGBE_DV_X540(link, tc);
                break;
        default:
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                dv_id = IXGBE_LOW_DV_X540(tc);
                break;
        default:
                case ixgbe_mac_X540:
                case ixgbe_mac_X550:
                case ixgbe_mac_X550EM_x:
+               case ixgbe_mac_x550em_a:
                default:
                        IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(0), 0xFFFFFFFF);
                        IXGBE_WRITE_REG(hw, IXGBE_EIAM_EX(1), 0xFFFFFFFF);
                gpie |= IXGBE_SDP1_GPIEN_8259X | IXGBE_SDP2_GPIEN_8259X;
                break;
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                gpie |= IXGBE_SDP0_GPIEN_X540;
                break;
        default:
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL,
                                (IXGBE_READ_REG(hw, IXGBE_DMATXCTL) &
                                 ~IXGBE_DMATXCTL_TE));
                        adapter->flags2 |= IXGBE_FLAG2_TEMP_SENSOR_CAPABLE;
                break;
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
        case ixgbe_mac_X550:
 #ifdef CONFIG_IXGBE_DCA
                adapter->flags &= ~IXGBE_FLAG_DCA_CAPABLE;
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                adapter->dcb_cfg.num_tcs.pg_tcs = X540_TRAFFIC_CLASS;
                adapter->dcb_cfg.num_tcs.pfc_tcs = X540_TRAFFIC_CLASS;
                break;
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                pci_wake_from_d3(pdev, !!wufc);
                break;
        default:
                case ixgbe_mac_X540:
                case ixgbe_mac_X550:
                case ixgbe_mac_X550EM_x:
+               case ixgbe_mac_x550em_a:
                        hwstats->pxonrxc[i] +=
                                IXGBE_READ_REG(hw, IXGBE_PXONRXCNT(i));
                        break;
                if ((hw->mac.type == ixgbe_mac_82599EB) ||
                    (hw->mac.type == ixgbe_mac_X540) ||
                    (hw->mac.type == ixgbe_mac_X550) ||
-                   (hw->mac.type == ixgbe_mac_X550EM_x)) {
+                   (hw->mac.type == ixgbe_mac_X550EM_x) ||
+                   (hw->mac.type == ixgbe_mac_x550em_a)) {
                        hwstats->qbtc[i] += IXGBE_READ_REG(hw, IXGBE_QBTC_L(i));
                        IXGBE_READ_REG(hw, IXGBE_QBTC_H(i)); /* to clear */
                        hwstats->qbrc[i] += IXGBE_READ_REG(hw, IXGBE_QBRC_L(i));
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                /* OS2BMC stats are X540 and later */
                hwstats->o2bgptc += IXGBE_READ_REG(hw, IXGBE_O2BGPTC);
                hwstats->o2bspc += IXGBE_READ_REG(hw, IXGBE_O2BSPC);
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
        case ixgbe_mac_82599EB: {
                u32 mflcn = IXGBE_READ_REG(hw, IXGBE_MFLCN);
                u32 fccfg = IXGBE_READ_REG(hw, IXGBE_FCCFG);
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                IXGBE_WRITE_REG(&adapter->hw, IXGBE_WUS, ~0);
                break;
        default:
                case ixgbe_mac_X550EM_x:
                        device_id = IXGBE_DEV_ID_X550EM_X_VF;
                        break;
+               case ixgbe_mac_x550em_a:
+                       device_id = IXGBE_DEV_ID_X550EM_A_VF;
+                       break;
                default:
                        device_id = 0;
                        break;
 
        case ixgbe_mac_X540:
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                vflre = IXGBE_READ_REG(hw, IXGBE_VFLREC(reg_offset));
                break;
        default:
        if (hw->mac.type != ixgbe_mac_82599EB &&
            hw->mac.type != ixgbe_mac_X550 &&
            hw->mac.type != ixgbe_mac_X550EM_x &&
+           hw->mac.type != ixgbe_mac_x550em_a &&
            hw->mac.type != ixgbe_mac_X540)
                return;
 
 
 /*******************************************************************************
 
   Intel 10 Gigabit PCI Express Linux driver
-  Copyright(c) 1999 - 2015 Intel Corporation.
+  Copyright(c) 1999 - 2016 Intel Corporation.
 
   This program is free software; you can redistribute it and/or modify it
   under the terms and conditions of the GNU General Public License,
         */
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                /* Upper 32 bits represent billions of cycles, lower 32 bits
                 * represent cycles. However, we use timespec64_to_ns for the
                 * correct math even though the units haven't been corrected
        switch (hw->mac.type) {
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                /* enable timestamping all packets only if at least some
                 * packets were requested. Otherwise, play nice and disable
                 * timestamping
                        cc.shift = 2;
                }
                /* fallthrough */
+       case ixgbe_mac_x550em_a:
        case ixgbe_mac_X550:
                cc.read = ixgbe_ptp_read_X550;
 
                break;
        case ixgbe_mac_X550:
        case ixgbe_mac_X550EM_x:
+       case ixgbe_mac_x550em_a:
                snprintf(adapter->ptp_caps.name, 16, "%s", netdev->name);
                adapter->ptp_caps.owner = THIS_MODULE;
                adapter->ptp_caps.max_adj = 30000000;
 
 #define FW_MAX_READ_BUFFER_SIZE                1024
 #define FW_DISABLE_RXEN_CMD            0xDE
 #define FW_DISABLE_RXEN_LEN            0x1
+#define FW_PHY_MGMT_REQ_CMD            0x20
+#define FW_PHY_TOKEN_REQ_CMD           0x0A
+#define FW_PHY_TOKEN_REQ_LEN           2
+#define FW_PHY_TOKEN_REQ               0
+#define FW_PHY_TOKEN_REL               1
+#define FW_PHY_TOKEN_OK                        1
+#define FW_PHY_TOKEN_RETRY             0x80
+#define FW_PHY_TOKEN_DELAY             5       /* milliseconds */
+#define FW_PHY_TOKEN_WAIT              5       /* seconds */
+#define FW_PHY_TOKEN_RETRIES ((FW_PHY_TOKEN_WAIT * 1000) / FW_PHY_TOKEN_DELAY)
+#define FW_INT_PHY_REQ_CMD             0xB
+#define FW_INT_PHY_REQ_LEN             10
+#define FW_INT_PHY_REQ_READ            0
+#define FW_INT_PHY_REQ_WRITE           1
 
 /* Host Interface Command Structures */
 struct ixgbe_hic_hdr {
        u16 pad3;
 };
 
+struct ixgbe_hic_phy_token_req {
+       struct ixgbe_hic_hdr hdr;
+       u8 port_number;
+       u8 command_type;
+       u16 pad;
+};
+
+struct ixgbe_hic_internal_phy_req {
+       struct ixgbe_hic_hdr hdr;
+       u8 port_number;
+       u8 command_type;
+       __be16 address;
+       u16 rsv1;
+       __be32 write_data;
+       u16 pad;
+} __packed;
+
+struct ixgbe_hic_internal_phy_resp {
+       struct ixgbe_hic_hdr hdr;
+       __be32 read_data;
+};
+
 /* Transmit Descriptor - Advanced */
 union ixgbe_adv_tx_desc {
        struct {
 #define IXGBE_ERR_INVALID_ARGUMENT              -32
 #define IXGBE_ERR_HOST_INTERFACE_COMMAND        -33
 #define IXGBE_ERR_FDIR_CMD_INCOMPLETE          -38
+#define IXGBE_ERR_FW_RESP_INVALID              -39
+#define IXGBE_ERR_TOKEN_RETRY                  -40
 #define IXGBE_NOT_IMPLEMENTED                   0x7FFFFFFF
 
 #define IXGBE_FUSES0_GROUP(_i)         (0x11158 + ((_i) * 4))
 
                hw->phy.phy_semaphore_mask = IXGBE_GSSR_SHARED_I2C_SM;
                ixgbe_setup_mux_ctl(hw);
                ixgbe_check_cs4227(hw);
+               /* Fallthrough */
+       case IXGBE_DEV_ID_X550EM_A_SFP_N:
                return ixgbe_identify_module_generic(hw);
        case IXGBE_DEV_ID_X550EM_X_KX4:
                hw->phy.type = ixgbe_phy_x550em_kx4;
        return ret;
 }
 
+/**
+ * ixgbe_get_phy_token - Get the token for shared PHY access
+ * @hw: Pointer to hardware structure
+ */
+static s32 ixgbe_get_phy_token(struct ixgbe_hw *hw)
+{
+       struct ixgbe_hic_phy_token_req token_cmd;
+       s32 status;
+
+       token_cmd.hdr.cmd = FW_PHY_TOKEN_REQ_CMD;
+       token_cmd.hdr.buf_len = FW_PHY_TOKEN_REQ_LEN;
+       token_cmd.hdr.cmd_or_resp.cmd_resv = 0;
+       token_cmd.hdr.checksum = FW_DEFAULT_CHECKSUM;
+       token_cmd.port_number = hw->bus.lan_id;
+       token_cmd.command_type = FW_PHY_TOKEN_REQ;
+       token_cmd.pad = 0;
+       status = ixgbe_host_interface_command(hw, &token_cmd, sizeof(token_cmd),
+                                             IXGBE_HI_COMMAND_TIMEOUT,
+                                             true);
+       if (status)
+               return status;
+       if (token_cmd.hdr.cmd_or_resp.ret_status == FW_PHY_TOKEN_OK)
+               return 0;
+       if (token_cmd.hdr.cmd_or_resp.ret_status != FW_PHY_TOKEN_RETRY)
+               return IXGBE_ERR_FW_RESP_INVALID;
+
+       return IXGBE_ERR_TOKEN_RETRY;
+}
+
+/**
+ * ixgbe_put_phy_token - Put the token for shared PHY access
+ * @hw: Pointer to hardware structure
+ */
+static s32 ixgbe_put_phy_token(struct ixgbe_hw *hw)
+{
+       struct ixgbe_hic_phy_token_req token_cmd;
+       s32 status;
+
+       token_cmd.hdr.cmd = FW_PHY_TOKEN_REQ_CMD;
+       token_cmd.hdr.buf_len = FW_PHY_TOKEN_REQ_LEN;
+       token_cmd.hdr.cmd_or_resp.cmd_resv = 0;
+       token_cmd.hdr.checksum = FW_DEFAULT_CHECKSUM;
+       token_cmd.port_number = hw->bus.lan_id;
+       token_cmd.command_type = FW_PHY_TOKEN_REL;
+       token_cmd.pad = 0;
+       status = ixgbe_host_interface_command(hw, &token_cmd, sizeof(token_cmd),
+                                             IXGBE_HI_COMMAND_TIMEOUT,
+                                             true);
+       if (status)
+               return status;
+       if (token_cmd.hdr.cmd_or_resp.ret_status == FW_PHY_TOKEN_OK)
+               return 0;
+       return IXGBE_ERR_FW_RESP_INVALID;
+}
+
+/**
+ *  ixgbe_write_iosf_sb_reg_x550a - Write to IOSF PHY register
+ *  @hw: pointer to hardware structure
+ *  @reg_addr: 32 bit PHY register to write
+ *  @device_type: 3 bit device type
+ *  @data: Data to write to the register
+ **/
+static s32 ixgbe_write_iosf_sb_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr,
+                                        __always_unused u32 device_type,
+                                        u32 data)
+{
+       struct ixgbe_hic_internal_phy_req write_cmd;
+
+       memset(&write_cmd, 0, sizeof(write_cmd));
+       write_cmd.hdr.cmd = FW_INT_PHY_REQ_CMD;
+       write_cmd.hdr.buf_len = FW_INT_PHY_REQ_LEN;
+       write_cmd.hdr.checksum = FW_DEFAULT_CHECKSUM;
+       write_cmd.port_number = hw->bus.lan_id;
+       write_cmd.command_type = FW_INT_PHY_REQ_WRITE;
+       write_cmd.address = cpu_to_be16(reg_addr);
+       write_cmd.write_data = cpu_to_be32(data);
+
+       return ixgbe_host_interface_command(hw, &write_cmd, sizeof(write_cmd),
+                                           IXGBE_HI_COMMAND_TIMEOUT, false);
+}
+
+/**
+ *  ixgbe_read_iosf_sb_reg_x550a - Read from IOSF PHY register
+ *  @hw: pointer to hardware structure
+ *  @reg_addr: 32 bit PHY register to write
+ *  @device_type: 3 bit device type
+ *  @data: Pointer to read data from the register
+ **/
+static s32 ixgbe_read_iosf_sb_reg_x550a(struct ixgbe_hw *hw, u32 reg_addr,
+                                       __always_unused u32 device_type,
+                                       u32 *data)
+{
+       union {
+               struct ixgbe_hic_internal_phy_req cmd;
+               struct ixgbe_hic_internal_phy_resp rsp;
+       } hic;
+       s32 status;
+
+       memset(&hic, 0, sizeof(hic));
+       hic.cmd.hdr.cmd = FW_INT_PHY_REQ_CMD;
+       hic.cmd.hdr.buf_len = FW_INT_PHY_REQ_LEN;
+       hic.cmd.hdr.checksum = FW_DEFAULT_CHECKSUM;
+       hic.cmd.port_number = hw->bus.lan_id;
+       hic.cmd.command_type = FW_INT_PHY_REQ_READ;
+       hic.cmd.address = cpu_to_be16(reg_addr);
+
+       status = ixgbe_host_interface_command(hw, &hic.cmd, sizeof(hic.cmd),
+                                             IXGBE_HI_COMMAND_TIMEOUT, true);
+
+       /* Extract the register value from the response. */
+       *data = be32_to_cpu(hic.rsp.read_data);
+
+       return status;
+}
+
 /** ixgbe_read_ee_hostif_data_X550 - Read EEPROM word using a host interface
  *  command assuming that the semaphore is already obtained.
  *  @hw: pointer to hardware structure
                mac->ops.disable_tx_laser = NULL;
                mac->ops.enable_tx_laser = NULL;
                mac->ops.flap_tx_laser = NULL;
+               mac->ops.setup_mac_link = ixgbe_setup_mac_link_sfp_x550em;
                mac->ops.setup_link = ixgbe_setup_mac_link_multispeed_fiber;
                mac->ops.setup_fc = ixgbe_setup_fc_x550em;
-               mac->ops.setup_mac_link = ixgbe_setup_mac_link_sfp_x550em;
                mac->ops.set_rate_select_speed =
                                        ixgbe_set_soft_rate_select_speed;
                break;
                mac->ops.setup_link = ixgbe_setup_mac_link_t_X550em;
                mac->ops.setup_fc = ixgbe_setup_fc_generic;
                mac->ops.check_link = ixgbe_check_link_t_X550em;
+               return;
+       case ixgbe_media_type_backplane:
                break;
        default:
                mac->ops.setup_fc = ixgbe_setup_fc_x550em;
                media_type = ixgbe_media_type_backplane;
                break;
        case IXGBE_DEV_ID_X550EM_X_SFP:
+       case IXGBE_DEV_ID_X550EM_A_SFP_N:
                media_type = ixgbe_media_type_fiber;
                break;
        case IXGBE_DEV_ID_X550EM_X_1G_T:
        case IXGBE_DEV_ID_X550EM_X_10G_T:
-                media_type = ixgbe_media_type_copper;
+               media_type = ixgbe_media_type_copper;
                break;
        default:
                media_type = ixgbe_media_type_unknown;
        ixgbe_release_swfw_sync_X540(hw, mask);
 }
 
+/**
+ * ixgbe_acquire_swfw_sync_x550em_a - Acquire SWFW semaphore
+ * @hw: pointer to hardware structure
+ * @mask: Mask to specify which semaphore to acquire
+ *
+ * Acquires the SWFW semaphore and get the shared PHY token as needed
+ */
+static s32 ixgbe_acquire_swfw_sync_x550em_a(struct ixgbe_hw *hw, u32 mask)
+{
+       u32 hmask = mask & ~IXGBE_GSSR_TOKEN_SM;
+       int retries = FW_PHY_TOKEN_RETRIES;
+       s32 status;
+
+       while (--retries) {
+               status = 0;
+               if (hmask)
+                       status = ixgbe_acquire_swfw_sync_X540(hw, hmask);
+               if (status)
+                       return status;
+               if (!(mask & IXGBE_GSSR_TOKEN_SM))
+                       return 0;
+
+               status = ixgbe_get_phy_token(hw);
+               if (!status)
+                       return 0;
+               if (hmask)
+                       ixgbe_release_swfw_sync_X540(hw, hmask);
+               if (status != IXGBE_ERR_TOKEN_RETRY)
+                       return status;
+               udelay(FW_PHY_TOKEN_DELAY * 1000);
+       }
+
+       return status;
+}
+
+/**
+ * ixgbe_release_swfw_sync_x550em_a - Release SWFW semaphore
+ * @hw: pointer to hardware structure
+ * @mask: Mask to specify which semaphore to release
+ *
+ * Release the SWFW semaphore and puts the shared PHY token as needed
+ */
+static void ixgbe_release_swfw_sync_x550em_a(struct ixgbe_hw *hw, u32 mask)
+{
+       u32 hmask = mask & ~IXGBE_GSSR_TOKEN_SM;
+
+       if (mask & IXGBE_GSSR_TOKEN_SM)
+               ixgbe_put_phy_token(hw);
+
+       if (hmask)
+               ixgbe_release_swfw_sync_X540(hw, hmask);
+}
+
 #define X550_COMMON_MAC \
        .init_hw                        = &ixgbe_init_hw_generic, \
        .start_hw                       = &ixgbe_start_hw_X540, \
        .write_iosf_sb_reg      = ixgbe_write_iosf_sb_reg_x550,
 };
 
+static struct ixgbe_mac_operations mac_ops_x550em_a = {
+       X550_COMMON_MAC
+       .reset_hw               = ixgbe_reset_hw_X550em,
+       .get_media_type         = ixgbe_get_media_type_X550em,
+       .get_san_mac_addr       = NULL,
+       .get_wwn_prefix         = NULL,
+       .setup_link             = NULL, /* defined later */
+       .get_link_capabilities  = ixgbe_get_link_capabilities_X550em,
+       .get_bus_info           = ixgbe_get_bus_info_X550em,
+       .setup_sfp              = ixgbe_setup_sfp_modules_X550em,
+       .acquire_swfw_sync      = ixgbe_acquire_swfw_sync_x550em_a,
+       .release_swfw_sync      = ixgbe_release_swfw_sync_x550em_a,
+       .setup_fc               = ixgbe_setup_fc_generic,
+       .read_iosf_sb_reg       = ixgbe_read_iosf_sb_reg_x550a,
+       .write_iosf_sb_reg      = ixgbe_write_iosf_sb_reg_x550a,
+};
+
 #define X550_COMMON_EEP \
        .read                   = &ixgbe_read_ee_hostif_X550, \
        .read_buffer            = &ixgbe_read_ee_hostif_buffer_X550, \
        IXGBE_MVALS_INIT(X550EM_x)
 };
 
+static const u32 ixgbe_mvals_x550em_a[IXGBE_MVALS_IDX_LIMIT] = {
+       IXGBE_MVALS_INIT(X550EM_a)
+};
+
 const struct ixgbe_info ixgbe_X550_info = {
        .mac                    = ixgbe_mac_X550,
        .get_invariants         = &ixgbe_get_invariants_X540,
        .mbx_ops                = &mbx_ops_generic,
        .mvals                  = ixgbe_mvals_X550EM_x,
 };
+
+const struct ixgbe_info ixgbe_x550em_a_info = {
+       .mac                    = ixgbe_mac_x550em_a,
+       .get_invariants         = &ixgbe_get_invariants_X550_x,
+       .mac_ops                = &mac_ops_x550em_a,
+       .eeprom_ops             = &eeprom_ops_X550EM_x,
+       .phy_ops                = &phy_ops_X550EM_x,
+       .mbx_ops                = &mbx_ops_generic,
+       .mvals                  = ixgbe_mvals_x550em_a,
+};