Skip to content

Commit

Permalink
ibmvnic: Report actual backing device speed and duplex values
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Murilo Fossa Vicentini authored and David S. Miller committed Mar 19, 2019
1 parent c55c8ed commit f8d6ae0
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 17 deletions.
93 changes: 81 additions & 12 deletions drivers/net/ethernet/ibm/ibmvnic.c
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -4278,6 +4276,73 @@ static void handle_query_cap_rsp(union ibmvnic_crq *crq,
}
}

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)
{
Expand Down Expand Up @@ -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);
Expand Down
18 changes: 13 additions & 5 deletions drivers/net/ethernet/ibm/ibmvnic.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit f8d6ae0

Please sign in to comment.