Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f8d6ae0d authored by Murilo Fossa Vicentini's avatar Murilo Fossa Vicentini Committed by David S. Miller
Browse files

ibmvnic: Report actual backing device speed and duplex values



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: default avatarAbdul Haleem <abdhalee@linux.vnet.ibm.com>
Signed-off-by: default avatarMurilo Fossa Vicentini <muvic@linux.ibm.com>
Reviewed-by: default avatarMauro S. M. Rodrigues <maurosr@linux.vnet.ibm.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent c55c8eda
Loading
Loading
Loading
Loading
+81 −12
Original line number Diff line number Diff line
@@ -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 @@ 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)
{
@@ -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);
+13 −5
Original line number Diff line number Diff line
@@ -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;