[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250407123714.21646-2-mpazdan@arista.com>
Date: Mon, 7 Apr 2025 12:35:38 +0000
From: Marek Pazdan <mpazdan@...sta.com>
To: linux-kernel@...r.kernel.org,
netdev@...r.kernel.org,
intel-wired-lan@...ts.osuosl.org
Cc: Tony Nguyen <anthony.l.nguyen@...el.com>,
Przemek Kitszel <przemyslaw.kitszel@...el.com>,
Andrew Lunn <andrew+netdev@...n.ch>,
"David S . Miller" <davem@...emloft.net>,
Eric Dumazet <edumazet@...gle.com>,
Jakub Kicinski <kuba@...nel.org>,
Paolo Abeni <pabeni@...hat.com>,
Simon Horman <horms@...nel.org>,
Kory Maincent <kory.maincent@...tlin.com>,
Willem de Bruijn <willemb@...gle.com>,
Alexander Lobakin <aleksander.lobakin@...el.com>,
Mina Almasry <almasrymina@...gle.com>,
Edward Cree <ecree.xilinx@...il.com>,
Daniel Zahka <daniel.zahka@...il.com>,
Jianbo Liu <jianbol@...dia.com>,
Gal Pressman <gal@...dia.com>,
Marek Pazdan <mpazdan@...sta.com>
Subject: [PATCH 2/2] ice: add qsfp transceiver reset and presence pin control
Commit f3c1c896f5a8 ("ethtool: transceiver reset and presence pin control")
adds ioctl API extension for get/set-phy-tunable so that transceiver
reset and presence pin control is enabled.
This commit adds functionality to utilize the API in ice driver.
According to E810 datasheet QSFP reset and presence pins are being
connected to SDP0 and SDP2 pins on controller host. Those pins can
be accessed using AQ commands for GPIO get/set.[O
Signed-off-by: Marek Pazdan <mpazdan@...sta.com>
---
drivers/net/ethernet/intel/ice/ice.h | 2 +
drivers/net/ethernet/intel/ice/ice_common.c | 21 ++++++
drivers/net/ethernet/intel/ice/ice_common.h | 1 +
drivers/net/ethernet/intel/ice/ice_ethtool.c | 72 ++++++++++++++++++++
drivers/net/ethernet/intel/ice/ice_main.c | 1 +
drivers/net/ethernet/intel/ice/ice_type.h | 2 +
6 files changed, 99 insertions(+)
diff --git a/drivers/net/ethernet/intel/ice/ice.h b/drivers/net/ethernet/intel/ice/ice.h
index fd083647c14a..2dbbcb20decf 100644
--- a/drivers/net/ethernet/intel/ice/ice.h
+++ b/drivers/net/ethernet/intel/ice/ice.h
@@ -106,6 +106,8 @@
#define ICE_Q_WAIT_MAX_RETRY (5 * ICE_Q_WAIT_RETRY_LIMIT)
#define ICE_MAX_LG_RSS_QS 256
#define ICE_INVAL_Q_INDEX 0xffff
+#define ICE_GPIO_QSFP0_RESET 0
+#define ICE_GPIO_QSFP0_PRESENT 2
#define ICE_MAX_RXQS_PER_TC 256 /* Used when setting VSI context per TC Rx queues */
diff --git a/drivers/net/ethernet/intel/ice/ice_common.c b/drivers/net/ethernet/intel/ice/ice_common.c
index 59df31c2c83f..2d643a7cc90f 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.c
+++ b/drivers/net/ethernet/intel/ice/ice_common.c
@@ -6096,3 +6096,24 @@ u32 ice_get_link_speed(u16 index)
return ice_aq_to_link_speed[index];
}
+
+/**
+ * ice_set_has_gpios - Sets availability of SDP GPIO pins.
+ * @hw: pointer to the HW structure
+ *
+ * This function sets availability of GPIO software defined pins
+ * (SDP) which are connected to transceiver slots and are used
+ * for transceiver control.
+ */
+bool ice_set_has_gpios(struct ice_hw *hw)
+{
+ if (hw->vendor_id != PCI_VENDOR_ID_INTEL)
+ return false;
+
+ switch (hw->device_id) {
+ case ICE_DEV_ID_E810C_QSFP:
+ return true;
+ default:
+ return false;
+ }
+}
diff --git a/drivers/net/ethernet/intel/ice/ice_common.h b/drivers/net/ethernet/intel/ice/ice_common.h
index 9b00aa0ddf10..b64629b1d60d 100644
--- a/drivers/net/ethernet/intel/ice/ice_common.h
+++ b/drivers/net/ethernet/intel/ice/ice_common.h
@@ -304,4 +304,5 @@ ice_aq_write_i2c(struct ice_hw *hw, struct ice_aqc_link_topo_addr topo_addr,
int ice_get_pca9575_handle(struct ice_hw *hw, u16 *pca9575_handle);
int ice_read_pca9575_reg(struct ice_hw *hw, u8 offset, u8 *data);
bool ice_fw_supports_report_dflt_cfg(struct ice_hw *hw);
+bool ice_set_has_gpios(struct ice_hw *hw);
#endif /* _ICE_COMMON_H_ */
diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c
index 7c2dc347e4e5..20727c582ad5 100644
--- a/drivers/net/ethernet/intel/ice/ice_ethtool.c
+++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c
@@ -4765,6 +4765,76 @@ static int ice_repr_ethtool_reset(struct net_device *dev, u32 *flags)
return ice_reset_vf(vf, ICE_VF_RESET_VFLR | ICE_VF_RESET_LOCK);
}
+static int ice_get_phy_tunable(struct net_device *netdev,
+ const struct ethtool_tunable *tuna, void *data)
+{
+ struct ice_netdev_priv *np = netdev_priv(netdev);
+ struct ice_vsi *vsi = np->vsi;
+ struct ice_pf *pf = vsi->back;
+ struct ice_hw *hw = &pf->hw;
+ u16 gpio_handle = 0; /* SOC/on-chip GPIO */
+ u8 *enabled = data;
+ bool value;
+
+ switch (tuna->id) {
+ case ETHTOOL_PHY_MODULE_RESET:
+ if (!hw->has_gpios)
+ return -EOPNOTSUPP;
+
+ if (ice_aq_get_gpio(hw, gpio_handle, ICE_GPIO_QSFP0_PRESENT,
+ &value, NULL))
+ return -EIO;
+ if (!value) {
+ *enabled = ETHTOOL_PHY_MODULE_RESET_NA;
+ } else {
+ if (ice_aq_get_gpio(hw, gpio_handle, ICE_GPIO_QSFP0_RESET,
+ &value, NULL))
+ return -EIO;
+ *enabled = value ? ETHTOOL_PHY_MODULE_RESET_ON :
+ ETHTOOL_PHY_FAST_LINK_DOWN_OFF;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int ice_set_phy_tunable(struct net_device *netdev,
+ const struct ethtool_tunable *tuna, const void *data)
+{
+ struct ice_netdev_priv *np = netdev_priv(netdev);
+ struct ice_vsi *vsi = np->vsi;
+ struct ice_pf *pf = vsi->back;
+ struct ice_hw *hw = &pf->hw;
+ u16 gpio_handle = 0; /* SOC/on-chip GPIO */
+ const u8 *enable = data;
+ bool value;
+
+ switch (tuna->id) {
+ case ETHTOOL_PHY_MODULE_RESET:
+ if (!hw->has_gpios)
+ return -EOPNOTSUPP;
+
+ if (*enable == ETHTOOL_PHY_MODULE_RESET_ON)
+ value = true;
+ else if (*enable == ETHTOOL_PHY_FAST_LINK_DOWN_OFF)
+ value = false;
+ else
+ return -EINVAL;
+
+ if (ice_aq_set_gpio(hw, gpio_handle, ICE_GPIO_QSFP0_RESET,
+ value, NULL))
+ return -EIO;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static const struct ethtool_ops ice_ethtool_ops = {
.cap_rss_ctx_supported = true,
.supported_coalesce_params = ETHTOOL_COALESCE_USECS |
@@ -4815,6 +4885,8 @@ static const struct ethtool_ops ice_ethtool_ops = {
.set_fecparam = ice_set_fecparam,
.get_module_info = ice_get_module_info,
.get_module_eeprom = ice_get_module_eeprom,
+ .get_phy_tunable = ice_get_phy_tunable,
+ .set_phy_tunable = ice_set_phy_tunable,
};
static const struct ethtool_ops ice_ethtool_safe_mode_ops = {
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c
index 049edeb60104..fa18fc965649 100644
--- a/drivers/net/ethernet/intel/ice/ice_main.c
+++ b/drivers/net/ethernet/intel/ice/ice_main.c
@@ -5294,6 +5294,7 @@ ice_probe(struct pci_dev *pdev, const struct pci_device_id __always_unused *ent)
hw->port_info = NULL;
hw->vendor_id = pdev->vendor;
hw->device_id = pdev->device;
+ hw->has_gpios = ice_set_has_gpios(hw);
pci_read_config_byte(pdev, PCI_REVISION_ID, &hw->revision_id);
hw->subsystem_vendor_id = pdev->subsystem_vendor;
hw->subsystem_device_id = pdev->subsystem_device;
diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h
index 0aab21113cc4..ff758b4b7070 100644
--- a/drivers/net/ethernet/intel/ice/ice_type.h
+++ b/drivers/net/ethernet/intel/ice/ice_type.h
@@ -896,6 +896,8 @@ struct ice_hw {
u64 debug_mask; /* bitmap for debug mask */
enum ice_mac_type mac_type;
+ bool has_gpios;
+
u16 fd_ctr_base; /* FD counter base index */
/* pci info */
--
2.47.0
Powered by blists - more mailing lists