Add get/set implenentation for ethtool's module management signal
API.
Examples:
ethtool --get-module-mgmt-signal eth16 type reset
reset: low

ethtool --get-module-mgmt-signal eth16 type int
reset: low

ethtool --get-module-mgmt-signal eth16 type present
reset: high

sudo ethtool --set-module-mgmt-signal eth16 type reset value high
ethtool --get-module-mgmt-signal eth16 type reset
reset: high

sudo ethtool --set-module-mgmt-signal eth16 type reset value low
ethtool --get-module-mgmt-signal eth16 type reset
reset: low

Ice driver gets link event notification when module gets restarted.
There is 'ice_handle_link_event' which handles the notification and
updates link status information.

Signed-off-by: Marek Pazdan <[email protected]>
---
 drivers/net/ethernet/intel/ice/ice.h         |  6 ++
 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 | 94 ++++++++++++++++++++
 drivers/net/ethernet/intel/ice/ice_main.c    |  1 +
 drivers/net/ethernet/intel/ice/ice_type.h    |  2 +-
 6 files changed, 124 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/intel/ice/ice.h 
b/drivers/net/ethernet/intel/ice/ice.h
index fd083647c14a..3b95a69140e8 100644
--- a/drivers/net/ethernet/intel/ice/ice.h
+++ b/drivers/net/ethernet/intel/ice/ice.h
@@ -195,6 +195,12 @@
 
 #define ice_pf_src_tmr_owned(pf) 
((pf)->hw.func_caps.ts_func_info.src_tmr_owned)
 
+enum ice_mgmt_pin {
+       ICE_MGMT_PIN_RESET = 0,
+       ICE_MGMT_PIN_INT,
+       ICE_MGMT_PIN_PRESENT
+};
+
 enum ice_feature {
        ICE_F_DSCP,
        ICE_F_PHY_RCLK,
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..bf6a803729d4 100644
--- a/drivers/net/ethernet/intel/ice/ice_ethtool.c
+++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c
@@ -3848,6 +3848,96 @@ ice_get_channels(struct net_device *dev, struct 
ethtool_channels *ch)
        ch->max_other = ch->other_count;
 }
 
+/**
+ * ice_get_module_mgmt_signal - get module management signal status
+ * @dev: network interface device structure
+ * @params: ethtool module management signal params
+ * @extack: extended ACK from the Netlink message
+ *
+ * Returns -EIO if AQ command for GPIO get failed, otherwise
+ * returns 0 and current status of requested signal in params.
+ */
+static int
+ice_get_module_mgmt_signal(struct net_device *dev,
+                          struct ethtool_module_mgmt_params *params,
+                          struct netlink_ext_ack *extack)
+{
+       struct ice_netdev_priv *np = netdev_priv(dev);
+       struct ice_pf *pf = np->vsi->back;
+       struct ice_hw *hw = &pf->hw;
+       u16 gpio_handle = 0; /* SOC/on-chip GPIO */
+       bool value;
+       int ret = 0;
+
+       if (hw->has_module_mgmt_gpio) {
+               switch (params->type) {
+               case ETHTOOL_MODULE_MGMT_RESET:
+                       ret = ice_aq_get_gpio(hw, gpio_handle,
+                                             ICE_MGMT_PIN_RESET, &value, NULL);
+                       break;
+               case ETHTOOL_MODULE_MGMT_INT:
+                       ret = ice_aq_get_gpio(hw, gpio_handle,
+                                             ICE_MGMT_PIN_INT, &value, NULL);
+                       break;
+               case ETHTOOL_MODULE_MGMT_PRESENT:
+                       ret = ice_aq_get_gpio(hw, gpio_handle,
+                                             ICE_MGMT_PIN_PRESENT, &value, 
NULL);
+                       break;
+               default:
+                       dev_dbg(ice_pf_to_dev(pf), "Incorrect management signal 
requested: %d\n",
+                               params->type);
+                       return -EINVAL;
+               }
+       } else {
+               return -EOPNOTSUPP;
+       }
+
+       if (ret == 0) {
+               params->value = value ? ETHTOOL_MODULE_MGMT_SIGNAL_HIGH :
+                       ETHTOOL_MODULE_MGMT_SIGNAL_LOW;
+       }
+       return ret;
+}
+
+/**
+ * ice_set_module_mgmt_signal - set module management signal config
+ * @dev: network interface device structure
+ * @params: ethtool module management signal params
+ * @extack: extended ACK from the Netlink message
+ *
+ * Returns -EIO if AQ command for GPIO set failed, otherwise
+ * returns 0.
+ */
+static int
+ice_set_module_mgmt_signal(struct net_device *dev,
+                          const struct ethtool_module_mgmt_params *params,
+                          struct netlink_ext_ack *extack)
+{
+       struct ice_netdev_priv *np = netdev_priv(dev);
+       struct ice_pf *pf = np->vsi->back;
+       struct ice_hw *hw = &pf->hw;
+       u16 gpio_handle = 0; /* SOC/on-chip GPIO */
+       bool value = params->value == ETHTOOL_MODULE_MGMT_SIGNAL_HIGH ? true : 
false;
+       int ret = 0;
+
+       if (hw->has_module_mgmt_gpio) {
+               switch (params->type) {
+               case ETHTOOL_MODULE_MGMT_RESET:
+                       ret = ice_aq_set_gpio(hw, gpio_handle,
+                                             ICE_MGMT_PIN_RESET, value, NULL);
+                       break;
+               default:
+                       dev_dbg(ice_pf_to_dev(pf), "Incorrect management signal 
requested: %d\n",
+                               params->type);
+                       return -EINVAL;
+               }
+       } else {
+               return -EOPNOTSUPP;
+       }
+
+       return ret;
+}
+
 /**
  * ice_get_valid_rss_size - return valid number of RSS queues
  * @hw: pointer to the HW structure
@@ -4815,6 +4905,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_module_mgmt_signal = ice_get_module_mgmt_signal,
+       .set_module_mgmt_signal = ice_set_module_mgmt_signal,
 };
 
 static const struct ethtool_ops ice_ethtool_safe_mode_ops = {
@@ -4837,6 +4929,8 @@ static const struct ethtool_ops ice_ethtool_safe_mode_ops 
= {
        .set_ringparam          = ice_set_ringparam,
        .nway_reset             = ice_nway_reset,
        .get_channels           = ice_get_channels,
+       .get_module_mgmt_signal = ice_get_module_mgmt_signal,
+       .set_module_mgmt_signal = ice_set_module_mgmt_signal,
 };
 
 /**
diff --git a/drivers/net/ethernet/intel/ice/ice_main.c 
b/drivers/net/ethernet/intel/ice/ice_main.c
index d390157b59fe..02b9809561e1 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_module_mgmt_gpio = 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..e88075ae4c8a 100644
--- a/drivers/net/ethernet/intel/ice/ice_type.h
+++ b/drivers/net/ethernet/intel/ice/ice_type.h
@@ -895,7 +895,7 @@ struct ice_hw {
        u32 psm_clk_freq;
        u64 debug_mask;         /* bitmap for debug mask */
        enum ice_mac_type mac_type;
-
+       bool has_module_mgmt_gpio;      /* has GPIO for module management */
        u16 fd_ctr_base;        /* FD counter base index */
 
        /* pci info */
-- 
2.45.2

Reply via email to