net/bnxt: add device configure operation
[dpdk.git] / drivers / net / bnxt / bnxt_hwrm.c
index e187121..a2d7815 100644 (file)
@@ -36,6 +36,7 @@
 #include <rte_cycles.h>
 #include <rte_malloc.h>
 #include <rte_memzone.h>
+#include <rte_version.h>
 
 #include "bnxt.h"
 #include "bnxt_hwrm.h"
@@ -82,7 +83,7 @@ static int bnxt_hwrm_send_message_locked(struct bnxt *bp, void *msg,
                /* Sanity check on the resp->resp_len */
                rte_rmb();
                if (resp->resp_len && resp->resp_len <=
-                   bp->max_resp_len) {
+                               bp->max_resp_len) {
                        /* Last byte of resp contains the valid key */
                        valid = (uint8_t *)resp + resp->resp_len - 1;
                        if (*valid == HWRM_RESP_VALID_KEY)
@@ -178,6 +179,34 @@ int bnxt_hwrm_func_qcaps(struct bnxt *bp)
        return rc;
 }
 
+int bnxt_hwrm_func_driver_register(struct bnxt *bp, uint32_t flags,
+                                  uint32_t *vf_req_fwd)
+{
+       int rc;
+       struct hwrm_func_drv_rgtr_input req = {.req_type = 0 };
+       struct hwrm_func_drv_rgtr_output *resp = bp->hwrm_cmd_resp_addr;
+
+       if (bp->flags & BNXT_FLAG_REGISTERED)
+               return 0;
+
+       HWRM_PREP(req, FUNC_DRV_RGTR, -1, resp);
+       req.flags = flags;
+       req.enables = HWRM_FUNC_DRV_RGTR_INPUT_ENABLES_VER;
+       req.ver_maj = RTE_VER_YEAR;
+       req.ver_min = RTE_VER_MONTH;
+       req.ver_upd = RTE_VER_MINOR;
+
+       memcpy(req.vf_req_fwd, vf_req_fwd, sizeof(req.vf_req_fwd));
+
+       rc = bnxt_hwrm_send_message(bp, &req, sizeof(req));
+
+       HWRM_CHECK_RESULT;
+
+       bp->flags |= BNXT_FLAG_REGISTERED;
+
+       return rc;
+}
+
 int bnxt_hwrm_ver_get(struct bnxt *bp)
 {
        int rc = 0;
@@ -264,6 +293,82 @@ error:
        return rc;
 }
 
+int bnxt_hwrm_func_driver_unregister(struct bnxt *bp, uint32_t flags)
+{
+       int rc;
+       struct hwrm_func_drv_unrgtr_input req = {.req_type = 0 };
+       struct hwrm_func_drv_unrgtr_output *resp = bp->hwrm_cmd_resp_addr;
+
+       if (!(bp->flags & BNXT_FLAG_REGISTERED))
+               return 0;
+
+       HWRM_PREP(req, FUNC_DRV_UNRGTR, -1, resp);
+       req.flags = flags;
+
+       rc = bnxt_hwrm_send_message(bp, &req, sizeof(req));
+
+       HWRM_CHECK_RESULT;
+
+       bp->flags &= ~BNXT_FLAG_REGISTERED;
+
+       return rc;
+}
+
+static int bnxt_hwrm_port_phy_cfg(struct bnxt *bp, struct bnxt_link_info *conf)
+{
+       int rc = 0;
+       struct hwrm_port_phy_cfg_input req = {.req_type = 0};
+       struct hwrm_port_phy_cfg_output *resp = bp->hwrm_cmd_resp_addr;
+
+       HWRM_PREP(req, PORT_PHY_CFG, -1, resp);
+
+       req.flags = conf->phy_flags;
+       if (conf->link_up) {
+               req.force_link_speed = conf->link_speed;
+               /*
+                * Note, ChiMP FW 20.2.1 and 20.2.2 return an error when we set
+                * any auto mode, even "none".
+                */
+               if (req.auto_mode == HWRM_PORT_PHY_CFG_INPUT_AUTO_MODE_NONE) {
+                       req.flags |= HWRM_PORT_PHY_CFG_INPUT_FLAGS_FORCE;
+               } else {
+                       req.auto_mode = conf->auto_mode;
+                       req.enables |=
+                               HWRM_PORT_PHY_CFG_INPUT_ENABLES_AUTO_MODE;
+                       req.auto_link_speed_mask = conf->auto_link_speed_mask;
+                       req.enables |=
+                          HWRM_PORT_PHY_CFG_INPUT_ENABLES_AUTO_LINK_SPEED_MASK;
+                       req.auto_link_speed = conf->auto_link_speed;
+                       req.enables |=
+                               HWRM_PORT_PHY_CFG_INPUT_ENABLES_AUTO_LINK_SPEED;
+               }
+               req.auto_duplex = conf->duplex;
+               req.enables |= HWRM_PORT_PHY_CFG_INPUT_ENABLES_AUTO_DUPLEX;
+               req.auto_pause = conf->auto_pause;
+               /* Set force_pause if there is no auto or if there is a force */
+               if (req.auto_pause)
+                       req.enables |=
+                               HWRM_PORT_PHY_CFG_INPUT_ENABLES_AUTO_PAUSE;
+               else
+                       req.enables |=
+                               HWRM_PORT_PHY_CFG_INPUT_ENABLES_FORCE_PAUSE;
+               req.force_pause = conf->force_pause;
+               if (req.force_pause)
+                       req.enables |=
+                               HWRM_PORT_PHY_CFG_INPUT_ENABLES_FORCE_PAUSE;
+       } else {
+               req.flags &= ~HWRM_PORT_PHY_CFG_INPUT_FLAGS_RESTART_AUTONEG;
+               req.flags |= HWRM_PORT_PHY_CFG_INPUT_FLAGS_FORCE_LINK_DOWN;
+               req.force_link_speed = 0;
+       }
+
+       rc = bnxt_hwrm_send_message(bp, &req, sizeof(req));
+
+       HWRM_CHECK_RESULT;
+
+       return rc;
+}
+
 int bnxt_hwrm_queue_qportcfg(struct bnxt *bp)
 {
        int rc = 0;
@@ -322,3 +427,178 @@ int bnxt_alloc_hwrm_resources(struct bnxt *bp)
 
        return 0;
 }
+
+static uint16_t bnxt_parse_eth_link_duplex(uint32_t conf_link_speed)
+{
+       uint8_t hw_link_duplex = HWRM_PORT_PHY_CFG_INPUT_AUTO_DUPLEX_BOTH;
+
+       if ((conf_link_speed & ETH_LINK_SPEED_FIXED) == ETH_LINK_SPEED_AUTONEG)
+               return HWRM_PORT_PHY_CFG_INPUT_AUTO_DUPLEX_BOTH;
+
+       switch (conf_link_speed) {
+       case ETH_LINK_SPEED_10M_HD:
+       case ETH_LINK_SPEED_100M_HD:
+               return HWRM_PORT_PHY_CFG_INPUT_AUTO_DUPLEX_HALF;
+       }
+       return hw_link_duplex;
+}
+
+static uint16_t bnxt_parse_eth_link_speed(uint32_t conf_link_speed)
+{
+       uint16_t eth_link_speed = 0;
+
+       if ((conf_link_speed & ETH_LINK_SPEED_FIXED) == ETH_LINK_SPEED_AUTONEG)
+               return ETH_LINK_SPEED_AUTONEG;
+
+       switch (conf_link_speed & ~ETH_LINK_SPEED_FIXED) {
+       case ETH_LINK_SPEED_100M:
+       case ETH_LINK_SPEED_100M_HD:
+               eth_link_speed =
+                       HWRM_PORT_PHY_CFG_INPUT_AUTO_LINK_SPEED_MASK_10MB;
+               break;
+       case ETH_LINK_SPEED_1G:
+               eth_link_speed =
+                       HWRM_PORT_PHY_CFG_INPUT_AUTO_LINK_SPEED_MASK_1GB;
+               break;
+       case ETH_LINK_SPEED_2_5G:
+               eth_link_speed =
+                       HWRM_PORT_PHY_CFG_INPUT_AUTO_LINK_SPEED_MASK_2_5GB;
+               break;
+       case ETH_LINK_SPEED_10G:
+               eth_link_speed =
+                       HWRM_PORT_PHY_CFG_INPUT_AUTO_LINK_SPEED_MASK_10GB;
+               break;
+       case ETH_LINK_SPEED_20G:
+               eth_link_speed =
+                       HWRM_PORT_PHY_CFG_INPUT_AUTO_LINK_SPEED_MASK_20GB;
+               break;
+       case ETH_LINK_SPEED_25G:
+               eth_link_speed =
+                       HWRM_PORT_PHY_CFG_INPUT_AUTO_LINK_SPEED_MASK_25GB;
+               break;
+       case ETH_LINK_SPEED_40G:
+               eth_link_speed =
+                       HWRM_PORT_PHY_CFG_INPUT_AUTO_LINK_SPEED_MASK_40GB;
+               break;
+       case ETH_LINK_SPEED_50G:
+               eth_link_speed =
+                       HWRM_PORT_PHY_CFG_INPUT_AUTO_LINK_SPEED_MASK_50GB;
+               break;
+       default:
+               RTE_LOG(ERR, PMD,
+                       "Unsupported link speed %d; default to AUTO\n",
+                       conf_link_speed);
+               break;
+       }
+       return eth_link_speed;
+}
+
+#define BNXT_SUPPORTED_SPEEDS (ETH_LINK_SPEED_100M | ETH_LINK_SPEED_100M_HD | \
+               ETH_LINK_SPEED_1G | ETH_LINK_SPEED_2_5G | \
+               ETH_LINK_SPEED_10G | ETH_LINK_SPEED_20G | ETH_LINK_SPEED_25G | \
+               ETH_LINK_SPEED_40G | ETH_LINK_SPEED_50G)
+
+static int bnxt_valid_link_speed(uint32_t link_speed, uint8_t port_id)
+{
+       uint32_t one_speed;
+
+       if (link_speed == ETH_LINK_SPEED_AUTONEG)
+               return 0;
+
+       if (link_speed & ETH_LINK_SPEED_FIXED) {
+               one_speed = link_speed & ~ETH_LINK_SPEED_FIXED;
+
+               if (one_speed & (one_speed - 1)) {
+                       RTE_LOG(ERR, PMD,
+                               "Invalid advertised speeds (%u) for port %u\n",
+                               link_speed, port_id);
+                       return -EINVAL;
+               }
+               if ((one_speed & BNXT_SUPPORTED_SPEEDS) != one_speed) {
+                       RTE_LOG(ERR, PMD,
+                               "Unsupported advertised speed (%u) for port %u\n",
+                               link_speed, port_id);
+                       return -EINVAL;
+               }
+       } else {
+               if (!(link_speed & BNXT_SUPPORTED_SPEEDS)) {
+                       RTE_LOG(ERR, PMD,
+                               "Unsupported advertised speeds (%u) for port %u\n",
+                               link_speed, port_id);
+                       return -EINVAL;
+               }
+       }
+       return 0;
+}
+
+static uint16_t bnxt_parse_eth_link_speed_mask(uint32_t link_speed)
+{
+       uint16_t ret = 0;
+
+       if (link_speed == ETH_LINK_SPEED_AUTONEG)
+               link_speed = BNXT_SUPPORTED_SPEEDS;
+
+       if (link_speed & ETH_LINK_SPEED_100M)
+               ret |= HWRM_PORT_PHY_CFG_INPUT_AUTO_LINK_SPEED_MASK_100MB;
+       if (link_speed & ETH_LINK_SPEED_100M_HD)
+               ret |= HWRM_PORT_PHY_CFG_INPUT_AUTO_LINK_SPEED_MASK_100MB;
+       if (link_speed & ETH_LINK_SPEED_1G)
+               ret |= HWRM_PORT_PHY_CFG_INPUT_AUTO_LINK_SPEED_MASK_1GB;
+       if (link_speed & ETH_LINK_SPEED_2_5G)
+               ret |= HWRM_PORT_PHY_CFG_INPUT_AUTO_LINK_SPEED_MASK_2_5GB;
+       if (link_speed & ETH_LINK_SPEED_10G)
+               ret |= HWRM_PORT_PHY_CFG_INPUT_AUTO_LINK_SPEED_MASK_10GB;
+       if (link_speed & ETH_LINK_SPEED_20G)
+               ret |= HWRM_PORT_PHY_CFG_INPUT_AUTO_LINK_SPEED_MASK_20GB;
+       if (link_speed & ETH_LINK_SPEED_25G)
+               ret |= HWRM_PORT_PHY_CFG_INPUT_AUTO_LINK_SPEED_MASK_25GB;
+       if (link_speed & ETH_LINK_SPEED_40G)
+               ret |= HWRM_PORT_PHY_CFG_INPUT_AUTO_LINK_SPEED_MASK_40GB;
+       if (link_speed & ETH_LINK_SPEED_50G)
+               ret |= HWRM_PORT_PHY_CFG_INPUT_AUTO_LINK_SPEED_MASK_50GB;
+       return ret;
+}
+
+int bnxt_set_hwrm_link_config(struct bnxt *bp, bool link_up)
+{
+       int rc = 0;
+       struct rte_eth_conf *dev_conf = &bp->eth_dev->data->dev_conf;
+       struct bnxt_link_info link_req;
+       uint16_t speed;
+
+       rc = bnxt_valid_link_speed(dev_conf->link_speeds,
+                       bp->eth_dev->data->port_id);
+       if (rc)
+               goto error;
+
+       memset(&link_req, 0, sizeof(link_req));
+       speed = bnxt_parse_eth_link_speed(dev_conf->link_speeds);
+       link_req.link_up = link_up;
+       if (speed == 0) {
+               link_req.phy_flags =
+                               HWRM_PORT_PHY_CFG_INPUT_FLAGS_RESTART_AUTONEG;
+               link_req.auto_mode =
+                               HWRM_PORT_PHY_CFG_INPUT_AUTO_MODE_ONE_OR_BELOW;
+               link_req.auto_link_speed_mask =
+                       bnxt_parse_eth_link_speed_mask(dev_conf->link_speeds);
+               link_req.auto_link_speed =
+                               HWRM_PORT_PHY_CFG_INPUT_AUTO_LINK_SPEED_50GB;
+       } else {
+               link_req.auto_mode = HWRM_PORT_PHY_CFG_INPUT_AUTO_MODE_NONE;
+               link_req.phy_flags = HWRM_PORT_PHY_CFG_INPUT_FLAGS_FORCE |
+                       HWRM_PORT_PHY_CFG_INPUT_FLAGS_RESET_PHY;
+               link_req.link_speed = speed;
+       }
+       link_req.duplex = bnxt_parse_eth_link_duplex(dev_conf->link_speeds);
+       link_req.auto_pause = bp->link_info.auto_pause;
+       link_req.force_pause = bp->link_info.force_pause;
+
+       rc = bnxt_hwrm_port_phy_cfg(bp, &link_req);
+       if (rc) {
+               RTE_LOG(ERR, PMD,
+                       "Set link config failed with rc %d\n", rc);
+       }
+
+error:
+       return rc;
+}