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

Commit f1cc8094 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'bnxt_en-next'

Michael Chan says:

====================
bnxt_en: Updates for net-next.

Update to latest firmware interface, add EEE feature, unsupported SFP+
module warning, and ethtool -s improvements.

v2: Removed the GEEPROM patch and added more comments to the get_eee patch.
====================
parents 04c85bfb 29c262fe
Loading
Loading
Loading
Loading
+237 −22
Original line number Diff line number Diff line
/* Broadcom NetXtreme-C/E network driver.
 *
 * Copyright (c) 2014-2015 Broadcom Corporation
 * Copyright (c) 2014-2016 Broadcom Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
@@ -118,6 +118,12 @@ static const u16 bnxt_vf_req_snif[] = {
	HWRM_CFA_L2_FILTER_ALLOC,
};

static const u16 bnxt_async_events_arr[] = {
	HWRM_ASYNC_EVENT_CMPL_EVENT_ID_LINK_STATUS_CHANGE,
	HWRM_ASYNC_EVENT_CMPL_EVENT_ID_PF_DRVR_UNLOAD,
	HWRM_ASYNC_EVENT_CMPL_EVENT_ID_PORT_CONN_NOT_ALLOWED,
};

static bool bnxt_vf_pciid(enum board_idx idx)
{
	return (idx == BCM57304_VF || idx == BCM57404_VF);
@@ -1231,6 +1237,19 @@ static int bnxt_rx_pkt(struct bnxt *bp, struct bnxt_napi *bnapi, u32 *raw_cons,
	return rc;
}

#define BNXT_GET_EVENT_PORT(data)	\
	((data) &				\
	 HWRM_ASYNC_EVENT_CMPL_PORT_CONN_NOT_ALLOWED_EVENT_DATA1_PORT_ID_MASK)

#define BNXT_EVENT_POLICY_MASK	\
	HWRM_ASYNC_EVENT_CMPL_PORT_CONN_NOT_ALLOWED_EVENT_DATA1_ENFORCEMENT_POLICY_MASK

#define BNXT_EVENT_POLICY_SFT	\
	HWRM_ASYNC_EVENT_CMPL_PORT_CONN_NOT_ALLOWED_EVENT_DATA1_ENFORCEMENT_POLICY_SFT

#define BNXT_GET_EVENT_POLICY(data)	\
	(((data) & BNXT_EVENT_POLICY_MASK) >> BNXT_EVENT_POLICY_SFT)

static int bnxt_async_event_process(struct bnxt *bp,
				    struct hwrm_async_event_cmpl *cmpl)
{
@@ -1244,6 +1263,22 @@ static int bnxt_async_event_process(struct bnxt *bp,
	case HWRM_ASYNC_EVENT_CMPL_EVENT_ID_PF_DRVR_UNLOAD:
		set_bit(BNXT_HWRM_PF_UNLOAD_SP_EVENT, &bp->sp_event);
		break;
	case HWRM_ASYNC_EVENT_CMPL_EVENT_ID_PORT_CONN_NOT_ALLOWED: {
		u32 data1 = le32_to_cpu(cmpl->event_data1);
		u16 port_id = BNXT_GET_EVENT_PORT(data1);

		if (BNXT_VF(bp))
			break;

		if (bp->pf.port_id != port_id)
			break;

		bp->link_info.last_port_module_event =
			BNXT_GET_EVENT_POLICY(data1);

		set_bit(BNXT_HWRM_PORT_MODULE_SP_EVENT, &bp->sp_event);
		break;
	}
	default:
		netdev_err(bp->dev, "unhandled ASYNC event (id 0x%x)\n",
			   event_id);
@@ -2751,6 +2786,8 @@ static int bnxt_hwrm_func_drv_rgtr(struct bnxt *bp)
{
	struct hwrm_func_drv_rgtr_input req = {0};
	int i;
	DECLARE_BITMAP(async_events_bmap, 256);
	u32 *events = (u32 *)async_events_bmap;

	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_FUNC_DRV_RGTR, -1, -1);

@@ -2759,11 +2796,14 @@ static int bnxt_hwrm_func_drv_rgtr(struct bnxt *bp)
			    FUNC_DRV_RGTR_REQ_ENABLES_VER |
			    FUNC_DRV_RGTR_REQ_ENABLES_ASYNC_EVENT_FWD);

	/* TODO: current async event fwd bits are not defined and the firmware
	 * only checks if it is non-zero to enable async event forwarding
	 */
	req.async_event_fwd[0] |= cpu_to_le32(1);
	req.os_type = cpu_to_le16(1);
	memset(async_events_bmap, 0, sizeof(async_events_bmap));
	for (i = 0; i < ARRAY_SIZE(bnxt_async_events_arr); i++)
		__set_bit(bnxt_async_events_arr[i], async_events_bmap);

	for (i = 0; i < 8; i++)
		req.async_event_fwd[i] |= cpu_to_le32(events[i]);

	req.os_type = cpu_to_le16(FUNC_DRV_RGTR_REQ_OS_TYPE_LINUX);
	req.ver_maj = DRV_VER_MAJ;
	req.ver_min = DRV_VER_MIN;
	req.ver_upd = DRV_VER_UPD;
@@ -3726,7 +3766,7 @@ int bnxt_hwrm_func_qcaps(struct bnxt *bp)

		pf->fw_fid = le16_to_cpu(resp->fid);
		pf->port_id = le16_to_cpu(resp->port_id);
		memcpy(pf->mac_addr, resp->perm_mac_address, ETH_ALEN);
		memcpy(pf->mac_addr, resp->mac_address, ETH_ALEN);
		memcpy(bp->dev->dev_addr, pf->mac_addr, ETH_ALEN);
		pf->max_rsscos_ctxs = le16_to_cpu(resp->max_rsscos_ctx);
		pf->max_cp_rings = le16_to_cpu(resp->max_cmpl_rings);
@@ -3751,7 +3791,7 @@ int bnxt_hwrm_func_qcaps(struct bnxt *bp)
		struct bnxt_vf_info *vf = &bp->vf;

		vf->fw_fid = le16_to_cpu(resp->fid);
		memcpy(vf->mac_addr, resp->perm_mac_address, ETH_ALEN);
		memcpy(vf->mac_addr, resp->mac_address, ETH_ALEN);
		if (is_valid_ether_addr(vf->mac_addr))
			/* overwrite netdev dev_adr with admin VF MAC */
			memcpy(bp->dev->dev_addr, vf->mac_addr, ETH_ALEN);
@@ -3842,6 +3882,8 @@ static int bnxt_hwrm_ver_get(struct bnxt *bp)

	memcpy(&bp->ver_resp, resp, sizeof(struct hwrm_ver_get_output));

	bp->hwrm_spec_code = resp->hwrm_intf_maj << 16 |
			     resp->hwrm_intf_min << 8 | resp->hwrm_intf_upd;
	if (resp->hwrm_intf_maj < 1) {
		netdev_warn(bp->dev, "HWRM interface %d.%d.%d is older than 1.0.0.\n",
			    resp->hwrm_intf_maj, resp->hwrm_intf_min,
@@ -4486,12 +4528,49 @@ static void bnxt_report_link(struct bnxt *bp)
		speed = bnxt_fw_to_ethtool_speed(bp->link_info.link_speed);
		netdev_info(bp->dev, "NIC Link is Up, %d Mbps %s duplex, Flow control: %s\n",
			    speed, duplex, flow_ctrl);
		if (bp->flags & BNXT_FLAG_EEE_CAP)
			netdev_info(bp->dev, "EEE is %s\n",
				    bp->eee.eee_active ? "active" :
							 "not active");
	} else {
		netif_carrier_off(bp->dev);
		netdev_err(bp->dev, "NIC Link is Down\n");
	}
}

static int bnxt_hwrm_phy_qcaps(struct bnxt *bp)
{
	int rc = 0;
	struct hwrm_port_phy_qcaps_input req = {0};
	struct hwrm_port_phy_qcaps_output *resp = bp->hwrm_cmd_resp_addr;

	if (bp->hwrm_spec_code < 0x10201)
		return 0;

	bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_PHY_QCAPS, -1, -1);

	mutex_lock(&bp->hwrm_cmd_lock);
	rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
	if (rc)
		goto hwrm_phy_qcaps_exit;

	if (resp->eee_supported & PORT_PHY_QCAPS_RESP_EEE_SUPPORTED) {
		struct ethtool_eee *eee = &bp->eee;
		u16 fw_speeds = le16_to_cpu(resp->supported_speeds_eee_mode);

		bp->flags |= BNXT_FLAG_EEE_CAP;
		eee->supported = _bnxt_fw_to_ethtool_adv_spds(fw_speeds, 0);
		bp->lpi_tmr_lo = le32_to_cpu(resp->tx_lpi_timer_low) &
				 PORT_PHY_QCAPS_RESP_TX_LPI_TIMER_LOW_MASK;
		bp->lpi_tmr_hi = le32_to_cpu(resp->valid_tx_lpi_timer_high) &
				 PORT_PHY_QCAPS_RESP_TX_LPI_TIMER_HIGH_MASK;
	}

hwrm_phy_qcaps_exit:
	mutex_unlock(&bp->hwrm_cmd_lock);
	return rc;
}

static int bnxt_update_link(struct bnxt *bp, bool chng_link_state)
{
	int rc = 0;
@@ -4523,7 +4602,6 @@ static int bnxt_update_link(struct bnxt *bp, bool chng_link_state)
	else
		link_info->link_speed = 0;
	link_info->force_link_speed = le16_to_cpu(resp->force_link_speed);
	link_info->auto_link_speed = le16_to_cpu(resp->auto_link_speed);
	link_info->support_speeds = le16_to_cpu(resp->support_speeds);
	link_info->auto_link_speeds = le16_to_cpu(resp->auto_link_speed_mask);
	link_info->lp_auto_link_speeds =
@@ -4533,9 +4611,45 @@ static int bnxt_update_link(struct bnxt *bp, bool chng_link_state)
	link_info->phy_ver[1] = resp->phy_min;
	link_info->phy_ver[2] = resp->phy_bld;
	link_info->media_type = resp->media_type;
	link_info->transceiver = resp->transceiver_type;
	link_info->phy_addr = resp->phy_addr;
	link_info->transceiver = resp->xcvr_pkg_type;
	link_info->phy_addr = resp->eee_config_phy_addr &
			      PORT_PHY_QCFG_RESP_PHY_ADDR_MASK;

	if (bp->flags & BNXT_FLAG_EEE_CAP) {
		struct ethtool_eee *eee = &bp->eee;
		u16 fw_speeds;

		eee->eee_active = 0;
		if (resp->eee_config_phy_addr &
		    PORT_PHY_QCFG_RESP_EEE_CONFIG_EEE_ACTIVE) {
			eee->eee_active = 1;
			fw_speeds = le16_to_cpu(
				resp->link_partner_adv_eee_link_speed_mask);
			eee->lp_advertised =
				_bnxt_fw_to_ethtool_adv_spds(fw_speeds, 0);
		}

		/* Pull initial EEE config */
		if (!chng_link_state) {
			if (resp->eee_config_phy_addr &
			    PORT_PHY_QCFG_RESP_EEE_CONFIG_EEE_ENABLED)
				eee->eee_enabled = 1;

			fw_speeds = le16_to_cpu(resp->adv_eee_link_speed_mask);
			eee->advertised =
				_bnxt_fw_to_ethtool_adv_spds(fw_speeds, 0);

			if (resp->eee_config_phy_addr &
			    PORT_PHY_QCFG_RESP_EEE_CONFIG_EEE_TX_LPI) {
				__le32 tmr;

				eee->tx_lpi_enabled = 1;
				tmr = resp->xcvr_identifier_type_tx_lpi_timer;
				eee->tx_lpi_timer = le32_to_cpu(tmr) &
					PORT_PHY_QCFG_RESP_TX_LPI_TIMER_MASK;
			}
		}
	}
	/* TODO: need to add more logic to report VF link */
	if (chng_link_state) {
		if (link_info->phy_link_status == BNXT_LINK_LINK)
@@ -4556,6 +4670,9 @@ static void
bnxt_hwrm_set_pause_common(struct bnxt *bp, struct hwrm_port_phy_cfg_input *req)
{
	if (bp->link_info.autoneg & BNXT_AUTONEG_FLOW_CTRL) {
		if (bp->hwrm_spec_code >= 0x10201)
			req->auto_pause =
				PORT_PHY_CFG_REQ_AUTO_PAUSE_AUTONEG_PAUSE;
		if (bp->link_info.req_flow_ctrl & BNXT_LINK_PAUSE_RX)
			req->auto_pause |= PORT_PHY_CFG_REQ_AUTO_PAUSE_RX;
		if (bp->link_info.req_flow_ctrl & BNXT_LINK_PAUSE_TX)
@@ -4569,6 +4686,11 @@ bnxt_hwrm_set_pause_common(struct bnxt *bp, struct hwrm_port_phy_cfg_input *req)
			req->force_pause |= PORT_PHY_CFG_REQ_FORCE_PAUSE_TX;
		req->enables |=
			cpu_to_le32(PORT_PHY_CFG_REQ_ENABLES_FORCE_PAUSE);
		if (bp->hwrm_spec_code >= 0x10201) {
			req->auto_pause = req->force_pause;
			req->enables |= cpu_to_le32(
				PORT_PHY_CFG_REQ_ENABLES_AUTO_PAUSE);
		}
	}
}

@@ -4581,7 +4703,7 @@ static void bnxt_hwrm_set_link_common(struct bnxt *bp,

	if (autoneg & BNXT_AUTONEG_SPEED) {
		req->auto_mode |=
			PORT_PHY_CFG_REQ_AUTO_MODE_MASK;
			PORT_PHY_CFG_REQ_AUTO_MODE_SPEED_MASK;

		req->enables |= cpu_to_le32(
			PORT_PHY_CFG_REQ_ENABLES_AUTO_LINK_SPEED_MASK);
@@ -4595,9 +4717,6 @@ static void bnxt_hwrm_set_link_common(struct bnxt *bp,
		req->flags |= cpu_to_le32(PORT_PHY_CFG_REQ_FLAGS_FORCE);
	}

	/* currently don't support half duplex */
	req->auto_duplex = PORT_PHY_CFG_REQ_AUTO_DUPLEX_FULL;
	req->enables |= cpu_to_le32(PORT_PHY_CFG_REQ_ENABLES_AUTO_DUPLEX);
	/* tell chimp that the setting takes effect immediately */
	req->flags |= cpu_to_le32(PORT_PHY_CFG_REQ_FLAGS_RESET_PHY);
}
@@ -4632,7 +4751,30 @@ int bnxt_hwrm_set_pause(struct bnxt *bp)
	return rc;
}

int bnxt_hwrm_set_link_setting(struct bnxt *bp, bool set_pause)
static void bnxt_hwrm_set_eee(struct bnxt *bp,
			      struct hwrm_port_phy_cfg_input *req)
{
	struct ethtool_eee *eee = &bp->eee;

	if (eee->eee_enabled) {
		u16 eee_speeds;
		u32 flags = PORT_PHY_CFG_REQ_FLAGS_EEE_ENABLE;

		if (eee->tx_lpi_enabled)
			flags |= PORT_PHY_CFG_REQ_FLAGS_EEE_TX_LPI_ENABLE;
		else
			flags |= PORT_PHY_CFG_REQ_FLAGS_EEE_TX_LPI_DISABLE;

		req->flags |= cpu_to_le32(flags);
		eee_speeds = bnxt_get_fw_auto_link_speeds(eee->advertised);
		req->eee_link_speed_mask = cpu_to_le16(eee_speeds);
		req->tx_lpi_timer = cpu_to_le32(eee->tx_lpi_timer);
	} else {
		req->flags |= cpu_to_le32(PORT_PHY_CFG_REQ_FLAGS_EEE_DISABLE);
	}
}

int bnxt_hwrm_set_link_setting(struct bnxt *bp, bool set_pause, bool set_eee)
{
	struct hwrm_port_phy_cfg_input req = {0};

@@ -4641,14 +4783,42 @@ int bnxt_hwrm_set_link_setting(struct bnxt *bp, bool set_pause)
		bnxt_hwrm_set_pause_common(bp, &req);

	bnxt_hwrm_set_link_common(bp, &req);

	if (set_eee)
		bnxt_hwrm_set_eee(bp, &req);
	return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
}

static bool bnxt_eee_config_ok(struct bnxt *bp)
{
	struct ethtool_eee *eee = &bp->eee;
	struct bnxt_link_info *link_info = &bp->link_info;

	if (!(bp->flags & BNXT_FLAG_EEE_CAP))
		return true;

	if (eee->eee_enabled) {
		u32 advertising =
			_bnxt_fw_to_ethtool_adv_spds(link_info->advertising, 0);

		if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) {
			eee->eee_enabled = 0;
			return false;
		}
		if (eee->advertised & ~advertising) {
			eee->advertised = advertising & eee->supported;
			return false;
		}
	}
	return true;
}

static int bnxt_update_phy_setting(struct bnxt *bp)
{
	int rc;
	bool update_link = false;
	bool update_pause = false;
	bool update_eee = false;
	struct bnxt_link_info *link_info = &bp->link_info;

	rc = bnxt_update_link(bp, true);
@@ -4658,7 +4828,8 @@ static int bnxt_update_phy_setting(struct bnxt *bp)
		return rc;
	}
	if ((link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) &&
	    link_info->auto_pause_setting != link_info->req_flow_ctrl)
	    (link_info->auto_pause_setting & BNXT_LINK_PAUSE_BOTH) !=
	    link_info->req_flow_ctrl)
		update_pause = true;
	if (!(link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL) &&
	    link_info->force_pause_setting != link_info->req_flow_ctrl)
@@ -4677,8 +4848,11 @@ static int bnxt_update_phy_setting(struct bnxt *bp)
			update_link = true;
	}

	if (!bnxt_eee_config_ok(bp))
		update_eee = true;

	if (update_link)
		rc = bnxt_hwrm_set_link_setting(bp, update_pause);
		rc = bnxt_hwrm_set_link_setting(bp, update_pause, update_eee);
	else if (update_pause)
		rc = bnxt_hwrm_set_pause(bp);
	if (rc) {
@@ -5303,6 +5477,28 @@ static void bnxt_timer(unsigned long data)
	mod_timer(&bp->timer, jiffies + bp->current_interval);
}

static void bnxt_port_module_event(struct bnxt *bp)
{
	struct bnxt_link_info *link_info = &bp->link_info;
	struct hwrm_port_phy_qcfg_output *resp = &link_info->phy_qcfg_resp;

	if (bnxt_update_link(bp, true))
		return;

	if (link_info->last_port_module_event != 0) {
		netdev_warn(bp->dev, "Unqualified SFP+ module detected on port %d\n",
			    bp->pf.port_id);
		if (bp->hwrm_spec_code >= 0x10201) {
			netdev_warn(bp->dev, "Module part number %s\n",
				    resp->phy_vendor_partnumber);
		}
	}
	if (link_info->last_port_module_event == 1)
		netdev_warn(bp->dev, "TX is disabled\n");
	if (link_info->last_port_module_event == 3)
		netdev_warn(bp->dev, "Shutdown SFP+ module\n");
}

static void bnxt_cfg_ntp_filters(struct bnxt *);

static void bnxt_sp_task(struct work_struct *work)
@@ -5350,6 +5546,9 @@ static void bnxt_sp_task(struct work_struct *work)
		rtnl_unlock();
	}

	if (test_and_clear_bit(BNXT_HWRM_PORT_MODULE_SP_EVENT, &bp->sp_event))
		bnxt_port_module_event(bp);

	if (test_and_clear_bit(BNXT_PERIODIC_STATS_SP_EVENT, &bp->sp_event))
		bnxt_hwrm_port_qstats(bp);

@@ -5818,6 +6017,13 @@ static int bnxt_probe_phy(struct bnxt *bp)
	int rc = 0;
	struct bnxt_link_info *link_info = &bp->link_info;

	rc = bnxt_hwrm_phy_qcaps(bp);
	if (rc) {
		netdev_err(bp->dev, "Probe phy can't get phy capabilities (rc: %x)\n",
			   rc);
		return rc;
	}

	rc = bnxt_update_link(bp, false);
	if (rc) {
		netdev_err(bp->dev, "Probe phy can't update link (rc: %x)\n",
@@ -5827,15 +6033,24 @@ static int bnxt_probe_phy(struct bnxt *bp)

	/*initialize the ethool setting copy with NVM settings */
	if (BNXT_AUTO_MODE(link_info->auto_mode)) {
		link_info->autoneg = BNXT_AUTONEG_SPEED |
				     BNXT_AUTONEG_FLOW_CTRL;
		link_info->autoneg = BNXT_AUTONEG_SPEED;
		if (bp->hwrm_spec_code >= 0x10201) {
			if (link_info->auto_pause_setting &
			    PORT_PHY_CFG_REQ_AUTO_PAUSE_AUTONEG_PAUSE)
				link_info->autoneg |= BNXT_AUTONEG_FLOW_CTRL;
		} else {
			link_info->autoneg |= BNXT_AUTONEG_FLOW_CTRL;
		}
		link_info->advertising = link_info->auto_link_speeds;
		link_info->req_flow_ctrl = link_info->auto_pause_setting;
	} else {
		link_info->req_link_speed = link_info->force_link_speed;
		link_info->req_duplex = link_info->duplex_setting;
		link_info->req_flow_ctrl = link_info->force_pause_setting;
	}
	if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL)
		link_info->req_flow_ctrl =
			link_info->auto_pause_setting & BNXT_LINK_PAUSE_BOTH;
	else
		link_info->req_flow_ctrl = link_info->force_pause_setting;
	return rc;
}

+12 −5
Original line number Diff line number Diff line
/* Broadcom NetXtreme-C/E network driver.
 *
 * Copyright (c) 2014-2015 Broadcom Corporation
 * Copyright (c) 2014-2016 Broadcom Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
@@ -11,7 +11,7 @@
#define BNXT_H

#define DRV_MODULE_NAME		"bnxt_en"
#define DRV_MODULE_VERSION	"1.0.0"
#define DRV_MODULE_VERSION	"1.2.0"

#define DRV_VER_MAJ	1
#define DRV_VER_MIN	0
@@ -788,7 +788,7 @@ struct bnxt_link_info {
#define BNXT_LINK_AUTO_ALLSPDS	PORT_PHY_QCFG_RESP_AUTO_MODE_ALL_SPEEDS
#define BNXT_LINK_AUTO_ONESPD	PORT_PHY_QCFG_RESP_AUTO_MODE_ONE_SPEED
#define BNXT_LINK_AUTO_ONEORBELOW PORT_PHY_QCFG_RESP_AUTO_MODE_ONE_OR_BELOW
#define BNXT_LINK_AUTO_MSK	PORT_PHY_QCFG_RESP_AUTO_MODE_MASK
#define BNXT_LINK_AUTO_MSK	PORT_PHY_QCFG_RESP_AUTO_MODE_SPEED_MASK
#define PHY_VER_LEN		3
	u8			phy_ver[PHY_VER_LEN];
	u16			link_speed;
@@ -813,7 +813,6 @@ struct bnxt_link_info {
#define BNXT_LINK_SPEED_MSK_40GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_40GB
#define BNXT_LINK_SPEED_MSK_50GB PORT_PHY_QCFG_RESP_SUPPORT_SPEEDS_50GB
	u16			lp_auto_link_speeds;
	u16			auto_link_speed;
	u16			force_link_speed;
	u32			preemphasis;

@@ -826,6 +825,8 @@ struct bnxt_link_info {
	u16			req_link_speed;
	u32			advertising;
	bool			force_link_chng;

	u8			last_port_module_event;
	/* a copy of phy_qcfg output used to report link
	 * info to VF
	 */
@@ -875,6 +876,7 @@ struct bnxt {
	#define BNXT_FLAG_RFS		0x100
	#define BNXT_FLAG_SHARED_RINGS	0x200
	#define BNXT_FLAG_PORT_STATS	0x400
	#define BNXT_FLAG_EEE_CAP	0x1000

	#define BNXT_FLAG_ALL_CONFIG_FEATS (BNXT_FLAG_TPA |		\
					    BNXT_FLAG_RFS |		\
@@ -940,6 +942,7 @@ struct bnxt {

	u32			msg_enable;

	u32			hwrm_spec_code;
	u16			hwrm_cmd_seq;
	u32			hwrm_intr_seq_id;
	void			*hwrm_cmd_resp_addr;
@@ -991,6 +994,7 @@ struct bnxt {
#define BNXT_RST_RING_SP_EVENT		7
#define BNXT_HWRM_PF_UNLOAD_SP_EVENT	8
#define BNXT_PERIODIC_STATS_SP_EVENT	9
#define BNXT_HWRM_PORT_MODULE_SP_EVENT	10

	struct bnxt_pf_info	pf;
#ifdef CONFIG_BNXT_SRIOV
@@ -1011,6 +1015,9 @@ struct bnxt {
	int			ntp_fltr_count;

	struct bnxt_link_info	link_info;
	struct ethtool_eee	eee;
	u32			lpi_tmr_lo;
	u32			lpi_tmr_hi;
};

#ifdef CONFIG_NET_RX_BUSY_POLL
@@ -1108,7 +1115,7 @@ int hwrm_send_message_silent(struct bnxt *, void *, u32, int);
int bnxt_hwrm_set_coal(struct bnxt *);
int bnxt_hwrm_func_qcaps(struct bnxt *);
int bnxt_hwrm_set_pause(struct bnxt *);
int bnxt_hwrm_set_link_setting(struct bnxt *, bool);
int bnxt_hwrm_set_link_setting(struct bnxt *, bool, bool);
int bnxt_open_nic(struct bnxt *, bool, bool);
int bnxt_close_nic(struct bnxt *, bool, bool);
int bnxt_get_max_rings(struct bnxt *, int *, int *, bool);
+136 −29
Original line number Diff line number Diff line
/* Broadcom NetXtreme-C/E network driver.
 *
 * Copyright (c) 2014-2015 Broadcom Corporation
 * Copyright (c) 2014-2016 Broadcom Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
@@ -597,7 +597,7 @@ static void bnxt_get_drvinfo(struct net_device *dev,
	kfree(pkglog);
}

static u32 _bnxt_fw_to_ethtool_adv_spds(u16 fw_speeds, u8 fw_pause)
u32 _bnxt_fw_to_ethtool_adv_spds(u16 fw_speeds, u8 fw_pause)
{
	u32 speed_mask = 0;

@@ -698,10 +698,23 @@ static int bnxt_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
		if (link_info->phy_link_status == BNXT_LINK_LINK)
			cmd->lp_advertising =
				bnxt_fw_to_ethtool_lp_adv(link_info);
		ethtool_speed = bnxt_fw_to_ethtool_speed(link_info->link_speed);
		if (!netif_carrier_ok(dev))
			cmd->duplex = DUPLEX_UNKNOWN;
		else if (link_info->duplex & BNXT_LINK_DUPLEX_FULL)
			cmd->duplex = DUPLEX_FULL;
		else
			cmd->duplex = DUPLEX_HALF;
	} else {
		cmd->autoneg = AUTONEG_DISABLE;
		cmd->advertising = 0;
		ethtool_speed =
			bnxt_fw_to_ethtool_speed(link_info->req_link_speed);
		cmd->duplex = DUPLEX_HALF;
		if (link_info->req_duplex == BNXT_LINK_DUPLEX_FULL)
			cmd->duplex = DUPLEX_FULL;
	}
	ethtool_cmd_speed_set(cmd, ethtool_speed);

	cmd->port = PORT_NONE;
	if (link_info->media_type == PORT_PHY_QCFG_RESP_MEDIA_TYPE_TP) {
@@ -719,16 +732,8 @@ static int bnxt_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
			cmd->port = PORT_FIBRE;
	}

	if (link_info->phy_link_status == BNXT_LINK_LINK) {
		if (link_info->duplex & BNXT_LINK_DUPLEX_FULL)
			cmd->duplex = DUPLEX_FULL;
	} else {
		cmd->duplex = DUPLEX_UNKNOWN;
	}
	ethtool_speed = bnxt_fw_to_ethtool_speed(link_info->link_speed);
	ethtool_cmd_speed_set(cmd, ethtool_speed);
	if (link_info->transceiver ==
		PORT_PHY_QCFG_RESP_TRANSCEIVER_TYPE_XCVR_INTERNAL)
	    PORT_PHY_QCFG_RESP_XCVR_PKG_TYPE_XCVR_INTERNAL)
		cmd->transceiver = XCVR_INTERNAL;
	else
		cmd->transceiver = XCVR_EXTERNAL;
@@ -739,31 +744,52 @@ static int bnxt_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)

static u32 bnxt_get_fw_speed(struct net_device *dev, u16 ethtool_speed)
{
	struct bnxt *bp = netdev_priv(dev);
	struct bnxt_link_info *link_info = &bp->link_info;
	u16 support_spds = link_info->support_speeds;
	u32 fw_speed = 0;

	switch (ethtool_speed) {
	case SPEED_100:
		return PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_100MB;
		if (support_spds & BNXT_LINK_SPEED_MSK_100MB)
			fw_speed = PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_100MB;
		break;
	case SPEED_1000:
		return PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_1GB;
		if (support_spds & BNXT_LINK_SPEED_MSK_1GB)
			fw_speed = PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_1GB;
		break;
	case SPEED_2500:
		return PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_2_5GB;
		if (support_spds & BNXT_LINK_SPEED_MSK_2_5GB)
			fw_speed = PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_2_5GB;
		break;
	case SPEED_10000:
		return PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_10GB;
		if (support_spds & BNXT_LINK_SPEED_MSK_10GB)
			fw_speed = PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_10GB;
		break;
	case SPEED_20000:
		return PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_20GB;
		if (support_spds & BNXT_LINK_SPEED_MSK_20GB)
			fw_speed = PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_20GB;
		break;
	case SPEED_25000:
		return PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_25GB;
		if (support_spds & BNXT_LINK_SPEED_MSK_25GB)
			fw_speed = PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_25GB;
		break;
	case SPEED_40000:
		return PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_40GB;
		if (support_spds & BNXT_LINK_SPEED_MSK_40GB)
			fw_speed = PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_40GB;
		break;
	case SPEED_50000:
		return PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_50GB;
		if (support_spds & BNXT_LINK_SPEED_MSK_50GB)
			fw_speed = PORT_PHY_CFG_REQ_AUTO_LINK_SPEED_50GB;
		break;
	default:
		netdev_err(dev, "unsupported speed!\n");
		break;
	}
	return 0;
	return fw_speed;
}

static u16 bnxt_get_fw_auto_link_speeds(u32 advertising)
u16 bnxt_get_fw_auto_link_speeds(u32 advertising)
{
	u16 fw_speed_mask = 0;

@@ -823,6 +849,8 @@ static int bnxt_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
		 */
		set_pause = true;
	} else {
		u16 fw_speed;

		/* TODO: currently don't support half duplex */
		if (cmd->duplex == DUPLEX_HALF) {
			netdev_err(dev, "HALF DUPLEX is not supported!\n");
@@ -833,14 +861,19 @@ static int bnxt_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
		if (cmd->duplex == DUPLEX_UNKNOWN)
			cmd->duplex = DUPLEX_FULL;
		speed = ethtool_cmd_speed(cmd);
		link_info->req_link_speed = bnxt_get_fw_speed(dev, speed);
		fw_speed = bnxt_get_fw_speed(dev, speed);
		if (!fw_speed) {
			rc = -EINVAL;
			goto set_setting_exit;
		}
		link_info->req_link_speed = fw_speed;
		link_info->req_duplex = BNXT_LINK_DUPLEX_FULL;
		link_info->autoneg = 0;
		link_info->advertising = 0;
	}

	if (netif_running(dev))
		rc = bnxt_hwrm_set_link_setting(bp, set_pause);
		rc = bnxt_hwrm_set_link_setting(bp, set_pause, false);

set_setting_exit:
	return rc;
@@ -874,7 +907,9 @@ static int bnxt_set_pauseparam(struct net_device *dev,
			return -EINVAL;

		link_info->autoneg |= BNXT_AUTONEG_FLOW_CTRL;
		link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_BOTH;
		if (bp->hwrm_spec_code >= 0x10201)
			link_info->req_flow_ctrl =
				PORT_PHY_CFG_REQ_AUTO_PAUSE_AUTONEG_PAUSE;
	} else {
		/* when transition from auto pause to force pause,
		 * force a link change
@@ -882,17 +917,13 @@ static int bnxt_set_pauseparam(struct net_device *dev,
		if (link_info->autoneg & BNXT_AUTONEG_FLOW_CTRL)
			link_info->force_link_chng = true;
		link_info->autoneg &= ~BNXT_AUTONEG_FLOW_CTRL;
		link_info->req_flow_ctrl &= ~BNXT_LINK_PAUSE_BOTH;
		link_info->req_flow_ctrl = 0;
	}
	if (epause->rx_pause)
		link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_RX;
	else
		link_info->req_flow_ctrl &= ~BNXT_LINK_PAUSE_RX;

	if (epause->tx_pause)
		link_info->req_flow_ctrl |= BNXT_LINK_PAUSE_TX;
	else
		link_info->req_flow_ctrl &= ~BNXT_LINK_PAUSE_TX;

	if (netif_running(dev))
		rc = bnxt_hwrm_set_pause(bp);
@@ -1381,6 +1412,80 @@ static int bnxt_set_eeprom(struct net_device *dev,
				eeprom->len);
}

static int bnxt_set_eee(struct net_device *dev, struct ethtool_eee *edata)
{
	struct bnxt *bp = netdev_priv(dev);
	struct ethtool_eee *eee = &bp->eee;
	struct bnxt_link_info *link_info = &bp->link_info;
	u32 advertising =
		 _bnxt_fw_to_ethtool_adv_spds(link_info->advertising, 0);
	int rc = 0;

	if (BNXT_VF(bp))
		return 0;

	if (!(bp->flags & BNXT_FLAG_EEE_CAP))
		return -EOPNOTSUPP;

	if (!edata->eee_enabled)
		goto eee_ok;

	if (!(link_info->autoneg & BNXT_AUTONEG_SPEED)) {
		netdev_warn(dev, "EEE requires autoneg\n");
		return -EINVAL;
	}
	if (edata->tx_lpi_enabled) {
		if (bp->lpi_tmr_hi && (edata->tx_lpi_timer > bp->lpi_tmr_hi ||
				       edata->tx_lpi_timer < bp->lpi_tmr_lo)) {
			netdev_warn(dev, "Valid LPI timer range is %d and %d microsecs\n",
				    bp->lpi_tmr_lo, bp->lpi_tmr_hi);
			return -EINVAL;
		} else if (!bp->lpi_tmr_hi) {
			edata->tx_lpi_timer = eee->tx_lpi_timer;
		}
	}
	if (!edata->advertised) {
		edata->advertised = advertising & eee->supported;
	} else if (edata->advertised & ~advertising) {
		netdev_warn(dev, "EEE advertised %x must be a subset of autoneg advertised speeds %x\n",
			    edata->advertised, advertising);
		return -EINVAL;
	}

	eee->advertised = edata->advertised;
	eee->tx_lpi_enabled = edata->tx_lpi_enabled;
	eee->tx_lpi_timer = edata->tx_lpi_timer;
eee_ok:
	eee->eee_enabled = edata->eee_enabled;

	if (netif_running(dev))
		rc = bnxt_hwrm_set_link_setting(bp, false, true);

	return rc;
}

static int bnxt_get_eee(struct net_device *dev, struct ethtool_eee *edata)
{
	struct bnxt *bp = netdev_priv(dev);

	if (!(bp->flags & BNXT_FLAG_EEE_CAP))
		return -EOPNOTSUPP;

	*edata = bp->eee;
	if (!bp->eee.eee_enabled) {
		/* Preserve tx_lpi_timer so that the last value will be used
		 * by default when it is re-enabled.
		 */
		edata->advertised = 0;
		edata->tx_lpi_enabled = 0;
	}

	if (!bp->eee.eee_active)
		edata->lp_advertised = 0;

	return 0;
}

const struct ethtool_ops bnxt_ethtool_ops = {
	.get_settings		= bnxt_get_settings,
	.set_settings		= bnxt_set_settings,
@@ -1409,4 +1514,6 @@ const struct ethtool_ops bnxt_ethtool_ops = {
	.get_eeprom             = bnxt_get_eeprom,
	.set_eeprom		= bnxt_set_eeprom,
	.get_link		= bnxt_get_link,
	.get_eee		= bnxt_get_eee,
	.set_eee		= bnxt_set_eee,
};
+3 −1
Original line number Diff line number Diff line
/* Broadcom NetXtreme-C/E network driver.
 *
 * Copyright (c) 2014-2015 Broadcom Corporation
 * Copyright (c) 2014-2016 Broadcom Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
@@ -12,6 +12,8 @@

extern const struct ethtool_ops bnxt_ethtool_ops;

u32 _bnxt_fw_to_ethtool_adv_spds(u16, u8);
u32 bnxt_fw_to_ethtool_speed(u16);
u16 bnxt_get_fw_auto_link_speeds(u32);

#endif
+1 −1
Original line number Diff line number Diff line
/* Broadcom NetXtreme-C/E network driver.
 *
 * Copyright (c) 2014-2015 Broadcom Corporation
 * Copyright (c) 2014-2016 Broadcom Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
Loading