if (base->duplex != DUPLEX_FULL)
                return -EINVAL;
 
-       if (!(lc->pcaps & FW_PORT_CAP32_ANEG)) {
-               /* PHY offers a single speed.  See if that's what's
-                * being requested.
-                */
-               if (base->autoneg == AUTONEG_DISABLE &&
-                   (lc->pcaps & speed_to_fw_caps(base->speed)))
-                       return 0;
-               return -EINVAL;
-       }
-
        old_lc = *lc;
-       if (base->autoneg == AUTONEG_DISABLE) {
+       if (!(lc->pcaps & FW_PORT_CAP32_ANEG) ||
+           base->autoneg == AUTONEG_DISABLE) {
                fw_caps = speed_to_fw_caps(base->speed);
 
-               if (!(lc->pcaps & fw_caps))
+               /* Must only specify a single speed which must be supported
+                * as part of the Physical Port Capabilities.
+                */
+               if ((fw_caps & (fw_caps - 1)) != 0 ||
+                   !(lc->pcaps & fw_caps))
                        return -EINVAL;
+
                lc->speed_caps = fw_caps;
-               lc->acaps = 0;
+               lc->acaps = fw_caps;
        } else {
                fw_caps =
                         lmm_to_fw_caps(link_ksettings->link_modes.advertising);
 
        fw_port_cap32_t fw_fc, cc_fec, fw_fec, rcap;
        struct fw_port_cmd cmd;
        unsigned int fw_mdi;
+       int ret;
 
        fw_mdi = (FW_PORT_CAP32_MDI_V(FW_PORT_CAP32_MDI_AUTO) & lc->pcaps);
        /* Convert driver coding of Pause Frame Flow Control settings into the
                rcap = lc->acaps | fw_fc | fw_fec | fw_mdi;
        }
 
+       if (rcap & ~lc->pcaps) {
+               dev_err(adapter->pdev_dev,
+                       "Requested Port Capabilities %#x exceed Physical Port Capabilities %#x\n",
+                       rcap, lc->pcaps);
+               return -EINVAL;
+       }
+
        /* And send that on to the Firmware ...
         */
        memset(&cmd, 0, sizeof(cmd));
                cpu_to_be32(FW_PORT_CMD_ACTION_V(fw_caps == FW_CAPS16
                                                 ? FW_PORT_ACTION_L1_CFG
                                                 : FW_PORT_ACTION_L1_CFG32) |
-                           FW_LEN16(cmd));
+                                                FW_LEN16(cmd));
        if (fw_caps == FW_CAPS16)
                cmd.u.l1cfg.rcap = cpu_to_be32(fwcaps32_to_caps16(rcap));
        else
                cmd.u.l1cfg32.rcap32 = cpu_to_be32(rcap);
-       return t4_wr_mbox_meat_timeout(adapter, mbox, &cmd, sizeof(cmd), NULL,
-                                      sleep_ok, timeout);
+
+       ret = t4_wr_mbox_meat_timeout(adapter, mbox, &cmd, sizeof(cmd), NULL,
+                                     sleep_ok, timeout);
+       if (ret) {
+               dev_err(adapter->pdev_dev,
+                       "Requested Port Capabilities %#x rejected, error %d\n",
+                       rcap, -ret);
+               return ret;
+       }
+       return ret;
 }
 
 /**
                lc->lpacaps = lpacaps;
                lc->acaps = acaps & ADVERT_MASK;
 
-               if (lc->acaps & FW_PORT_CAP32_ANEG) {
+               if (!(lc->acaps & FW_PORT_CAP32_ANEG)) {
+                       lc->autoneg = AUTONEG_DISABLE;
+               } else if (lc->acaps & FW_PORT_CAP32_ANEG) {
                        lc->autoneg = AUTONEG_ENABLE;
                } else {
                        /* When Autoneg is disabled, user needs to set
        lc->requested_fec = FEC_AUTO;
        lc->fec = fwcap_to_cc_fec(lc->def_acaps);
 
+       /* If the Port is capable of Auto-Negtotiation, initialize it as
+        * "enabled" and copy over all of the Physical Port Capabilities
+        * to the Advertised Port Capabilities.  Otherwise mark it as
+        * Auto-Negotiate disabled and select the highest supported speed
+        * for the link.  Note parallel structure in t4_link_l1cfg_core()
+        * and t4_handle_get_port_info().
+        */
        if (lc->pcaps & FW_PORT_CAP32_ANEG) {
                lc->acaps = lc->pcaps & ADVERT_MASK;
                lc->autoneg = AUTONEG_ENABLE;
        } else {
                lc->acaps = 0;
                lc->autoneg = AUTONEG_DISABLE;
+               lc->speed_caps = fwcap_to_fwspeed(acaps);
        }
 }
 
 
        return 0;
 }
 
+/**
+ *      fwcap_to_fwspeed - return highest speed in Port Capabilities
+ *      @acaps: advertised Port Capabilities
+ *
+ *      Get the highest speed for the port from the advertised Port
+ *      Capabilities.  It will be either the highest speed from the list of
+ *      speeds or whatever user has set using ethtool.
+ */
+static fw_port_cap32_t fwcap_to_fwspeed(fw_port_cap32_t acaps)
+{
+       #define TEST_SPEED_RETURN(__caps_speed) \
+               do { \
+                       if (acaps & FW_PORT_CAP32_SPEED_##__caps_speed) \
+                               return FW_PORT_CAP32_SPEED_##__caps_speed; \
+               } while (0)
+
+       TEST_SPEED_RETURN(400G);
+       TEST_SPEED_RETURN(200G);
+       TEST_SPEED_RETURN(100G);
+       TEST_SPEED_RETURN(50G);
+       TEST_SPEED_RETURN(40G);
+       TEST_SPEED_RETURN(25G);
+       TEST_SPEED_RETURN(10G);
+       TEST_SPEED_RETURN(1G);
+       TEST_SPEED_RETURN(100M);
+
+       #undef TEST_SPEED_RETURN
+       return 0;
+}
+
 /*
  *     init_link_config - initialize a link's SW state
  *     @lc: structure holding the link state
        lc->requested_fec = FEC_AUTO;
        lc->fec = lc->auto_fec;
 
+       /* If the Port is capable of Auto-Negtotiation, initialize it as
+        * "enabled" and copy over all of the Physical Port Capabilities
+        * to the Advertised Port Capabilities.  Otherwise mark it as
+        * Auto-Negotiate disabled and select the highest supported speed
+        * for the link.  Note parallel structure in t4_link_l1cfg_core()
+        * and t4_handle_get_port_info().
+        */
        if (lc->pcaps & FW_PORT_CAP32_ANEG) {
                lc->acaps = acaps & ADVERT_MASK;
                lc->autoneg = AUTONEG_ENABLE;
        } else {
                lc->acaps = 0;
                lc->autoneg = AUTONEG_DISABLE;
+               lc->speed_caps = fwcap_to_fwspeed(acaps);
        }
 }
 
                lc->lpacaps = lpacaps;
                lc->acaps = acaps & ADVERT_MASK;
 
-               if (lc->acaps & FW_PORT_CAP32_ANEG) {
+               /* If we're not physically capable of Auto-Negotiation, note
+                * this as Auto-Negotiation disabled.  Otherwise, we track
+                * what Auto-Negotiation settings we have.  Note parallel
+                * structure in init_link_config().
+                */
+               if (!(lc->pcaps & FW_PORT_CAP32_ANEG)) {
+                       lc->autoneg = AUTONEG_DISABLE;
+               } else if (lc->acaps & FW_PORT_CAP32_ANEG) {
                        lc->autoneg = AUTONEG_ENABLE;
                } else {
                        /* When Autoneg is disabled, user needs to set