Merge branch 'qed-ethtool-ops'
authorDavid S. Miller <davem@davemloft.net>
Tue, 1 Dec 2015 21:02:41 +0000 (16:02 -0500)
committerDavid S. Miller <davem@davemloft.net>
Tue, 1 Dec 2015 21:02:41 +0000 (16:02 -0500)
Yuval Mintz says:

====================
qede/qed: Implement various ethtool operations

This series adds several new ethtool operations to qede:
  - {get, set}_channels
  - {get, set}_ringparam
  - set_phys_id
  - nway_reset
  - {get, set}_pauseparam
As well as extending the qed APIs to support these commands.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/qlogic/qed/qed_hsi.h
drivers/net/ethernet/qlogic/qed/qed_main.c
drivers/net/ethernet/qlogic/qed/qed_mcp.c
drivers/net/ethernet/qlogic/qed/qed_mcp.h
drivers/net/ethernet/qlogic/qede/qede.h
drivers/net/ethernet/qlogic/qede/qede_ethtool.c
drivers/net/ethernet/qlogic/qede/qede_main.c
include/linux/qed/qed_if.h

index b2f8e854dfd1c4f858d00632a0ae3e827158d712..264e954675d1f390f1991b031e83779f6d7424b3 100644 (file)
@@ -3993,6 +3993,8 @@ struct public_drv_mb {
 #define DRV_MSG_CODE_PHY_CORE_WRITE             0x000e0000
 #define DRV_MSG_CODE_SET_VERSION                0x000f0000
 
+#define DRV_MSG_CODE_SET_LED_MODE               0x00200000
+
 #define DRV_MSG_SEQ_NUMBER_MASK                 0x0000ffff
 
        u32 drv_mb_param;
@@ -4044,6 +4046,10 @@ struct public_drv_mb {
 #define DRV_MB_PARAM_CFG_VF_MSIX_SB_NUM_SHIFT   8
 #define DRV_MB_PARAM_CFG_VF_MSIX_SB_NUM_MASK    0x0000FF00
 
+#define DRV_MB_PARAM_SET_LED_MODE_OPER          0x0
+#define DRV_MB_PARAM_SET_LED_MODE_ON            0x1
+#define DRV_MB_PARAM_SET_LED_MODE_OFF           0x2
+
        u32 fw_mb_header;
 #define FW_MSG_CODE_MASK                        0xffff0000
 #define FW_MSG_CODE_DRV_LOAD_ENGINE             0x10100000
index 947c7af72b25b32db163dc3ea47ca7d63db50490..6b02e113436016ca62728b82f16b9f3876d02f97 100644 (file)
@@ -1135,6 +1135,23 @@ static int qed_drain(struct qed_dev *cdev)
        return 0;
 }
 
+static int qed_set_led(struct qed_dev *cdev, enum qed_led_mode mode)
+{
+       struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev);
+       struct qed_ptt *ptt;
+       int status = 0;
+
+       ptt = qed_ptt_acquire(hwfn);
+       if (!ptt)
+               return -EAGAIN;
+
+       status = qed_mcp_set_led(hwfn, ptt, mode);
+
+       qed_ptt_release(hwfn, ptt);
+
+       return status;
+}
+
 const struct qed_common_ops qed_common_ops_pass = {
        .probe = &qed_probe,
        .remove = &qed_remove,
@@ -1155,6 +1172,7 @@ const struct qed_common_ops qed_common_ops_pass = {
        .update_msglvl = &qed_init_dp,
        .chain_alloc = &qed_chain_alloc,
        .chain_free = &qed_chain_free,
+       .set_led = &qed_set_led,
 };
 
 u32 qed_get_protocol_version(enum qed_protocol protocol)
index 20d048cdcb8821bf8d18b644be42afcb1146a2b8..ba1b1f1ef789b65381b47692c66d00a8556ba9be 100644 (file)
@@ -858,3 +858,30 @@ qed_mcp_send_drv_version(struct qed_hwfn *p_hwfn,
 
        return 0;
 }
+
+int qed_mcp_set_led(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
+                   enum qed_led_mode mode)
+{
+       u32 resp = 0, param = 0, drv_mb_param;
+       int rc;
+
+       switch (mode) {
+       case QED_LED_MODE_ON:
+               drv_mb_param = DRV_MB_PARAM_SET_LED_MODE_ON;
+               break;
+       case QED_LED_MODE_OFF:
+               drv_mb_param = DRV_MB_PARAM_SET_LED_MODE_OFF;
+               break;
+       case QED_LED_MODE_RESTORE:
+               drv_mb_param = DRV_MB_PARAM_SET_LED_MODE_OPER;
+               break;
+       default:
+               DP_NOTICE(p_hwfn, "Invalid LED mode %d\n", mode);
+               return -EINVAL;
+       }
+
+       rc = qed_mcp_cmd(p_hwfn, p_ptt, DRV_MSG_CODE_SET_LED_MODE,
+                        drv_mb_param, &resp, &param);
+
+       return rc;
+}
index dbaae586b4a728d3a3b50f76b288106875d00bff..506197d5c3dda19c6404bf8c382769f2ac64c26d 100644 (file)
@@ -224,6 +224,19 @@ qed_mcp_send_drv_version(struct qed_hwfn *p_hwfn,
                         struct qed_ptt *p_ptt,
                         struct qed_mcp_drv_version *p_ver);
 
+/**
+ * @brief Set LED status
+ *
+ *  @param p_hwfn
+ *  @param p_ptt
+ *  @param mode - LED mode
+ *
+ * @return int - 0 - operation was successful.
+ */
+int qed_mcp_set_led(struct qed_hwfn *p_hwfn,
+                   struct qed_ptt *p_ptt,
+                   enum qed_led_mode mode);
+
 /* Using hwfn number (and not pf_num) is required since in CMT mode,
  * same pf_num may be used by two different hwfn
  * TODO - this shouldn't really be in .h file, but until all fields
index ea00d5f3bab43a8c9ef8002c05c1c796a8bb4af9..7c6caf7f66122ea9452b5d131f7449a5a59a09b2 100644 (file)
@@ -116,6 +116,7 @@ struct qede_dev {
                                 (edev)->dev_info.num_tc)
 
        struct qede_fastpath            *fp_array;
+       u16                             req_rss;
        u16                             num_rss;
        u8                              num_tc;
 #define QEDE_RSS_CNT(edev)             ((edev)->num_rss)
@@ -269,13 +270,13 @@ int qede_change_mtu(struct net_device *dev, int new_mtu);
 void qede_fill_by_demand_stats(struct qede_dev *edev);
 
 #define RX_RING_SIZE_POW       13
-#define RX_RING_SIZE           BIT(RX_RING_SIZE_POW)
+#define RX_RING_SIZE           ((u16)BIT(RX_RING_SIZE_POW))
 #define NUM_RX_BDS_MAX         (RX_RING_SIZE - 1)
 #define NUM_RX_BDS_MIN         128
 #define NUM_RX_BDS_DEF         NUM_RX_BDS_MAX
 
 #define TX_RING_SIZE_POW       13
-#define TX_RING_SIZE           BIT(TX_RING_SIZE_POW)
+#define TX_RING_SIZE           ((u16)BIT(TX_RING_SIZE_POW))
 #define NUM_TX_BDS_MAX         (TX_RING_SIZE - 1)
 #define NUM_TX_BDS_MIN         128
 #define NUM_TX_BDS_DEF         NUM_TX_BDS_MAX
index 3a362476a22c66cb01a7de728875b9e67b9eb5df..e442b85c9a5e9c2582ecaee835993cd8180c29d9 100644 (file)
@@ -322,6 +322,30 @@ static void qede_set_msglevel(struct net_device *ndev, u32 level)
                                         dp_module, dp_level);
 }
 
+static int qede_nway_reset(struct net_device *dev)
+{
+       struct qede_dev *edev = netdev_priv(dev);
+       struct qed_link_output current_link;
+       struct qed_link_params link_params;
+
+       if (!netif_running(dev))
+               return 0;
+
+       memset(&current_link, 0, sizeof(current_link));
+       edev->ops->common->get_link(edev->cdev, &current_link);
+       if (!current_link.link_up)
+               return 0;
+
+       /* Toggle the link */
+       memset(&link_params, 0, sizeof(link_params));
+       link_params.link_up = false;
+       edev->ops->common->set_link(edev->cdev, &link_params);
+       link_params.link_up = true;
+       edev->ops->common->set_link(edev->cdev, &link_params);
+
+       return 0;
+}
+
 static u32 qede_get_link(struct net_device *dev)
 {
        struct qede_dev *edev = netdev_priv(dev);
@@ -333,6 +357,106 @@ static u32 qede_get_link(struct net_device *dev)
        return current_link.link_up;
 }
 
+static void qede_get_ringparam(struct net_device *dev,
+                              struct ethtool_ringparam *ering)
+{
+       struct qede_dev *edev = netdev_priv(dev);
+
+       ering->rx_max_pending = NUM_RX_BDS_MAX;
+       ering->rx_pending = edev->q_num_rx_buffers;
+       ering->tx_max_pending = NUM_TX_BDS_MAX;
+       ering->tx_pending = edev->q_num_tx_buffers;
+}
+
+static int qede_set_ringparam(struct net_device *dev,
+                             struct ethtool_ringparam *ering)
+{
+       struct qede_dev *edev = netdev_priv(dev);
+
+       DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
+                  "Set ring params command parameters: rx_pending = %d, tx_pending = %d\n",
+                  ering->rx_pending, ering->tx_pending);
+
+       /* Validate legality of configuration */
+       if (ering->rx_pending > NUM_RX_BDS_MAX ||
+           ering->rx_pending < NUM_RX_BDS_MIN ||
+           ering->tx_pending > NUM_TX_BDS_MAX ||
+           ering->tx_pending < NUM_TX_BDS_MIN) {
+               DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
+                          "Can only support Rx Buffer size [0%08x,...,0x%08x] and Tx Buffer size [0x%08x,...,0x%08x]\n",
+                          NUM_RX_BDS_MIN, NUM_RX_BDS_MAX,
+                          NUM_TX_BDS_MIN, NUM_TX_BDS_MAX);
+               return -EINVAL;
+       }
+
+       /* Change ring size and re-load */
+       edev->q_num_rx_buffers = ering->rx_pending;
+       edev->q_num_tx_buffers = ering->tx_pending;
+
+       if (netif_running(edev->ndev))
+               qede_reload(edev, NULL, NULL);
+
+       return 0;
+}
+
+static void qede_get_pauseparam(struct net_device *dev,
+                               struct ethtool_pauseparam *epause)
+{
+       struct qede_dev *edev = netdev_priv(dev);
+       struct qed_link_output current_link;
+
+       memset(&current_link, 0, sizeof(current_link));
+       edev->ops->common->get_link(edev->cdev, &current_link);
+
+       if (current_link.pause_config & QED_LINK_PAUSE_AUTONEG_ENABLE)
+               epause->autoneg = true;
+       if (current_link.pause_config & QED_LINK_PAUSE_RX_ENABLE)
+               epause->rx_pause = true;
+       if (current_link.pause_config & QED_LINK_PAUSE_TX_ENABLE)
+               epause->tx_pause = true;
+
+       DP_VERBOSE(edev, QED_MSG_DEBUG,
+                  "ethtool_pauseparam: cmd %d  autoneg %d  rx_pause %d  tx_pause %d\n",
+                  epause->cmd, epause->autoneg, epause->rx_pause,
+                  epause->tx_pause);
+}
+
+static int qede_set_pauseparam(struct net_device *dev,
+                              struct ethtool_pauseparam *epause)
+{
+       struct qede_dev *edev = netdev_priv(dev);
+       struct qed_link_params params;
+       struct qed_link_output current_link;
+
+       if (!edev->dev_info.common.is_mf) {
+               DP_INFO(edev,
+                       "Pause parameters can not be updated in non-default mode\n");
+               return -EOPNOTSUPP;
+       }
+
+       memset(&current_link, 0, sizeof(current_link));
+       edev->ops->common->get_link(edev->cdev, &current_link);
+
+       memset(&params, 0, sizeof(params));
+       params.override_flags |= QED_LINK_OVERRIDE_PAUSE_CONFIG;
+       if (epause->autoneg) {
+               if (!(current_link.supported_caps & SUPPORTED_Autoneg)) {
+                       DP_INFO(edev, "autoneg not supported\n");
+                       return -EINVAL;
+               }
+               params.pause_config |= QED_LINK_PAUSE_AUTONEG_ENABLE;
+       }
+       if (epause->rx_pause)
+               params.pause_config |= QED_LINK_PAUSE_RX_ENABLE;
+       if (epause->tx_pause)
+               params.pause_config |= QED_LINK_PAUSE_TX_ENABLE;
+
+       params.link_up = true;
+       edev->ops->common->set_link(edev->cdev, &params);
+
+       return 0;
+}
+
 static void qede_update_mtu(struct qede_dev *edev, union qede_reload_args *args)
 {
        edev->ndev->mtu = args->mtu;
@@ -366,17 +490,104 @@ int qede_change_mtu(struct net_device *ndev, int new_mtu)
        return 0;
 }
 
+static void qede_get_channels(struct net_device *dev,
+                             struct ethtool_channels *channels)
+{
+       struct qede_dev *edev = netdev_priv(dev);
+
+       channels->max_combined = QEDE_MAX_RSS_CNT(edev);
+       channels->combined_count = QEDE_RSS_CNT(edev);
+}
+
+static int qede_set_channels(struct net_device *dev,
+                            struct ethtool_channels *channels)
+{
+       struct qede_dev *edev = netdev_priv(dev);
+
+       DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
+                  "set-channels command parameters: rx = %d, tx = %d, other = %d, combined = %d\n",
+                  channels->rx_count, channels->tx_count,
+                  channels->other_count, channels->combined_count);
+
+       /* We don't support separate rx / tx, nor `other' channels. */
+       if (channels->rx_count || channels->tx_count ||
+           channels->other_count || (channels->combined_count == 0) ||
+           (channels->combined_count > QEDE_MAX_RSS_CNT(edev))) {
+               DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
+                          "command parameters not supported\n");
+               return -EINVAL;
+       }
+
+       /* Check if there was a change in the active parameters */
+       if (channels->combined_count == QEDE_RSS_CNT(edev)) {
+               DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
+                          "No change in active parameters\n");
+               return 0;
+       }
+
+       /* We need the number of queues to be divisible between the hwfns */
+       if (channels->combined_count % edev->dev_info.common.num_hwfns) {
+               DP_VERBOSE(edev, (NETIF_MSG_IFUP | NETIF_MSG_IFDOWN),
+                          "Number of channels must be divisable by %04x\n",
+                          edev->dev_info.common.num_hwfns);
+               return -EINVAL;
+       }
+
+       /* Set number of queues and reload if necessary */
+       edev->req_rss = channels->combined_count;
+       if (netif_running(dev))
+               qede_reload(edev, NULL, NULL);
+
+       return 0;
+}
+
+static int qede_set_phys_id(struct net_device *dev,
+                           enum ethtool_phys_id_state state)
+{
+       struct qede_dev *edev = netdev_priv(dev);
+       u8 led_state = 0;
+
+       switch (state) {
+       case ETHTOOL_ID_ACTIVE:
+               return 1;       /* cycle on/off once per second */
+
+       case ETHTOOL_ID_ON:
+               led_state = QED_LED_MODE_ON;
+               break;
+
+       case ETHTOOL_ID_OFF:
+               led_state = QED_LED_MODE_OFF;
+               break;
+
+       case ETHTOOL_ID_INACTIVE:
+               led_state = QED_LED_MODE_RESTORE;
+               break;
+       }
+
+       edev->ops->common->set_led(edev->cdev, led_state);
+
+       return 0;
+}
+
 static const struct ethtool_ops qede_ethtool_ops = {
        .get_settings = qede_get_settings,
        .set_settings = qede_set_settings,
        .get_drvinfo = qede_get_drvinfo,
        .get_msglevel = qede_get_msglevel,
        .set_msglevel = qede_set_msglevel,
+       .nway_reset = qede_nway_reset,
        .get_link = qede_get_link,
+       .get_ringparam = qede_get_ringparam,
+       .set_ringparam = qede_set_ringparam,
+       .get_pauseparam = qede_get_pauseparam,
+       .set_pauseparam = qede_set_pauseparam,
        .get_strings = qede_get_strings,
+       .set_phys_id = qede_set_phys_id,
        .get_ethtool_stats = qede_get_ethtool_stats,
        .get_sset_count = qede_get_sset_count,
 
+       .get_channels = qede_get_channels,
+       .set_channels = qede_set_channels,
 };
 
 void qede_set_ethtool_ops(struct net_device *dev)
index f4657a2e730aa424ff2a372a8b3e6557b9434f52..6237f10b5119faae8c6149bae8b6eea31f607deb 100644 (file)
@@ -1502,8 +1502,11 @@ static int qede_set_num_queues(struct qede_dev *edev)
        u16 rss_num;
 
        /* Setup queues according to possible resources*/
-       rss_num = netif_get_num_default_rss_queues() *
-                 edev->dev_info.common.num_hwfns;
+       if (edev->req_rss)
+               rss_num = edev->req_rss;
+       else
+               rss_num = netif_get_num_default_rss_queues() *
+                         edev->dev_info.common.num_hwfns;
 
        rss_num = min_t(u16, QEDE_MAX_RSS_CNT(edev), rss_num);
 
index dc9a1353f9710566c656d91ff10057a81a1f9e88..d4a32e87818049101ae21b16f4c55ed3ab8b0fce 100644 (file)
 #include <linux/qed/common_hsi.h>
 #include <linux/qed/qed_chain.h>
 
+enum qed_led_mode {
+       QED_LED_MODE_OFF,
+       QED_LED_MODE_ON,
+       QED_LED_MODE_RESTORE
+};
+
 #define DIRECT_REG_WR(reg_addr, val) writel((u32)val, \
                                            (void __iomem *)(reg_addr))
 
@@ -252,6 +258,17 @@ struct qed_common_ops {
 
        void            (*chain_free)(struct qed_dev *cdev,
                                      struct qed_chain *p_chain);
+
+/**
+ * @brief set_led - Configure LED mode
+ *
+ * @param cdev
+ * @param mode - LED mode
+ *
+ * @return 0 on success, error otherwise.
+ */
+       int (*set_led)(struct qed_dev *cdev,
+                      enum qed_led_mode mode);
 };
 
 /**
This page took 0.036857 seconds and 5 git commands to generate.