ibmvnic: Report actual backing device speed and duplex values
authorMurilo Fossa Vicentini <muvic@linux.ibm.com>
Tue, 19 Mar 2019 13:28:51 +0000 (10:28 -0300)
committerDavid S. Miller <davem@davemloft.net>
Tue, 19 Mar 2019 21:07:18 +0000 (14:07 -0700)
The ibmvnic driver currently reports a fixed value for both speed and
duplex settings regardless of the actual backing device that is being
used. By adding support to the QUERY_PHYS_PARMS command defined by the
PAPR+ we can query the current physical port state and report the proper
values for these feilds.

Reported-by: Abdul Haleem <abdhalee@linux.vnet.ibm.com>
Signed-off-by: Murilo Fossa Vicentini <muvic@linux.ibm.com>
Reviewed-by: Mauro S. M. Rodrigues <maurosr@linux.vnet.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/ibm/ibmvnic.c
drivers/net/ethernet/ibm/ibmvnic.h

index 5ecbb1adcf3b9d45fa756af5682245933aa06eb3..25b8e04ef11a78178030e954e51110580c73a92c 100644 (file)
@@ -120,6 +120,7 @@ static int ibmvnic_reset_init(struct ibmvnic_adapter *);
 static void release_crq_queue(struct ibmvnic_adapter *);
 static int __ibmvnic_set_mac(struct net_device *netdev, struct sockaddr *p);
 static int init_crq_queue(struct ibmvnic_adapter *adapter);
+static int send_query_phys_parms(struct ibmvnic_adapter *adapter);
 
 struct ibmvnic_stat {
        char name[ETH_GSTRING_LEN];
@@ -2278,23 +2279,20 @@ static const struct net_device_ops ibmvnic_netdev_ops = {
 static int ibmvnic_get_link_ksettings(struct net_device *netdev,
                                      struct ethtool_link_ksettings *cmd)
 {
-       u32 supported, advertising;
+       struct ibmvnic_adapter *adapter = netdev_priv(netdev);
+       int rc;
 
-       supported = (SUPPORTED_1000baseT_Full | SUPPORTED_Autoneg |
-                         SUPPORTED_FIBRE);
-       advertising = (ADVERTISED_1000baseT_Full | ADVERTISED_Autoneg |
-                           ADVERTISED_FIBRE);
-       cmd->base.speed = SPEED_1000;
-       cmd->base.duplex = DUPLEX_FULL;
+       rc = send_query_phys_parms(adapter);
+       if (rc) {
+               adapter->speed = SPEED_UNKNOWN;
+               adapter->duplex = DUPLEX_UNKNOWN;
+       }
+       cmd->base.speed = adapter->speed;
+       cmd->base.duplex = adapter->duplex;
        cmd->base.port = PORT_FIBRE;
        cmd->base.phy_address = 0;
        cmd->base.autoneg = AUTONEG_ENABLE;
 
-       ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
-                                               supported);
-       ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
-                                               advertising);
-
        return 0;
 }
 
@@ -4278,6 +4276,73 @@ out:
        }
 }
 
+static int send_query_phys_parms(struct ibmvnic_adapter *adapter)
+{
+       union ibmvnic_crq crq;
+       int rc;
+
+       memset(&crq, 0, sizeof(crq));
+       crq.query_phys_parms.first = IBMVNIC_CRQ_CMD;
+       crq.query_phys_parms.cmd = QUERY_PHYS_PARMS;
+       init_completion(&adapter->fw_done);
+       rc = ibmvnic_send_crq(adapter, &crq);
+       if (rc)
+               return rc;
+       wait_for_completion(&adapter->fw_done);
+       return adapter->fw_done_rc ? -EIO : 0;
+}
+
+static int handle_query_phys_parms_rsp(union ibmvnic_crq *crq,
+                                      struct ibmvnic_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+       int rc;
+
+       rc = crq->query_phys_parms_rsp.rc.code;
+       if (rc) {
+               netdev_err(netdev, "Error %d in QUERY_PHYS_PARMS\n", rc);
+               return rc;
+       }
+       switch (cpu_to_be32(crq->query_phys_parms_rsp.speed)) {
+       case IBMVNIC_10MBPS:
+               adapter->speed = SPEED_10;
+               break;
+       case IBMVNIC_100MBPS:
+               adapter->speed = SPEED_100;
+               break;
+       case IBMVNIC_1GBPS:
+               adapter->speed = SPEED_1000;
+               break;
+       case IBMVNIC_10GBP:
+               adapter->speed = SPEED_10000;
+               break;
+       case IBMVNIC_25GBPS:
+               adapter->speed = SPEED_25000;
+               break;
+       case IBMVNIC_40GBPS:
+               adapter->speed = SPEED_40000;
+               break;
+       case IBMVNIC_50GBPS:
+               adapter->speed = SPEED_50000;
+               break;
+       case IBMVNIC_100GBPS:
+               adapter->speed = SPEED_100000;
+               break;
+       default:
+               netdev_warn(netdev, "Unknown speed 0x%08x\n",
+                           cpu_to_be32(crq->query_phys_parms_rsp.speed));
+               adapter->speed = SPEED_UNKNOWN;
+       }
+       if (crq->query_phys_parms_rsp.flags1 & IBMVNIC_FULL_DUPLEX)
+               adapter->duplex = DUPLEX_FULL;
+       else if (crq->query_phys_parms_rsp.flags1 & IBMVNIC_HALF_DUPLEX)
+               adapter->duplex = DUPLEX_HALF;
+       else
+               adapter->duplex = DUPLEX_UNKNOWN;
+
+       return rc;
+}
+
 static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
                               struct ibmvnic_adapter *adapter)
 {
@@ -4426,6 +4491,10 @@ static void ibmvnic_handle_crq(union ibmvnic_crq *crq,
        case GET_VPD_RSP:
                handle_vpd_rsp(crq, adapter);
                break;
+       case QUERY_PHYS_PARMS_RSP:
+               adapter->fw_done_rc = handle_query_phys_parms_rsp(crq, adapter);
+               complete(&adapter->fw_done);
+               break;
        default:
                netdev_err(netdev, "Got an invalid cmd type 0x%02x\n",
                           gen_crq->cmd);
index f2018dbebfa527684a2dd8f91aeedfd1413d7fa1..d5260a2067083f87eb1cfe9936a4d656d517c9c9 100644 (file)
@@ -377,11 +377,16 @@ struct ibmvnic_phys_parms {
        u8 flags2;
 #define IBMVNIC_LOGICAL_LNK_ACTIVE 0x80
        __be32 speed;
-#define IBMVNIC_AUTONEG                0x80
-#define IBMVNIC_10MBPS         0x40
-#define IBMVNIC_100MBPS                0x20
-#define IBMVNIC_1GBPS          0x10
-#define IBMVNIC_10GBPS         0x08
+#define IBMVNIC_AUTONEG                0x80000000
+#define IBMVNIC_10MBPS         0x40000000
+#define IBMVNIC_100MBPS                0x20000000
+#define IBMVNIC_1GBPS          0x10000000
+#define IBMVNIC_10GBP          0x08000000
+#define IBMVNIC_40GBPS         0x04000000
+#define IBMVNIC_100GBPS                0x02000000
+#define IBMVNIC_25GBPS         0x01000000
+#define IBMVNIC_50GBPS         0x00800000
+#define IBMVNIC_200GBPS                0x00400000
        __be32 mtu;
        struct ibmvnic_rc rc;
 } __packed __aligned(8);
@@ -999,6 +1004,9 @@ struct ibmvnic_adapter {
        int phys_link_state;
        int logical_link_state;
 
+       u32 speed;
+       u8 duplex;
+
        /* login data */
        struct ibmvnic_login_buffer *login_buf;
        dma_addr_t login_buf_token;