@@ -107,6 +107,8 @@ struct rnp_eth_port {
struct rnp_eth_adapter *adapt;
uint8_t mac_addr[RTE_ETHER_ADDR_LEN];
struct rnp_hw *hw;
+ uint8_t rx_func_sec; /* force set io rx_func */
+ uint8_t tx_func_sec; /* force set io tx func */
struct rte_eth_dev *eth_dev;
struct rnp_port_attr attr;
/* Recvice Mac Address Record Table */
@@ -122,6 +124,13 @@ struct rnp_share_ops {
const struct rnp_mac_api *mac_api;
} __rte_cache_aligned;
+enum {
+ RNP_IO_FUNC_USE_NONE = 0,
+ RNP_IO_FUNC_USE_VEC,
+ RNP_IO_FUNC_USE_SIMPLE,
+ RNP_IO_FUNC_USE_COMMON,
+};
+
struct rnp_eth_adapter {
enum rnp_work_mode mode;
enum rnp_resource_share_m s_mode; /* Port Resource Share Policy */
@@ -135,6 +144,19 @@ struct rnp_eth_adapter {
int max_link_speed;
uint8_t num_ports; /* Cur Pf Has physical Port Num */
uint8_t lane_mask;
+
+ uint8_t rx_func_sec; /* force set io rx_func */
+ uint8_t tx_func_sec; /* force set io tx func*/
+ /*fw-update*/
+ bool do_fw_update;
+ char *fw_path;
+
+ bool loopback_en;
+ bool fw_sfp_10g_1g_auto_det;
+ int fw_force_speed_1g;
+#define FOCE_SPEED_1G_NOT_SET (-1)
+#define FOCE_SPEED_1G_DISABLED (0)
+#define FOCE_SPEED_1G_ENABLED (1)
} __rte_cache_aligned;
#define RNP_DEV_TO_PORT(eth_dev) \
@@ -6,6 +6,7 @@
#include <rte_io.h>
#include <rte_malloc.h>
#include <ethdev_driver.h>
+#include <rte_kvargs.h>
#include "rnp.h"
#include "rnp_api.h"
@@ -14,6 +15,13 @@
#include "rnp_rxtx.h"
#include "rnp_logs.h"
+#define RNP_HW_MAC_LOOPBACK_ARG "hw_loopback"
+#define RNP_FW_UPDATE "fw_update"
+#define RNP_RX_FUNC_SELECT "rx_func_sec"
+#define RNP_TX_FUNC_SELECT "tx_func_sec"
+#define RNP_FW_4X10G_10G_1G_DET "fw_4x10g_10g_1g_auto_det"
+#define RNP_FW_FORCE_SPEED_1G "fw_force_1g_speed"
+
static int
rnp_mac_rx_disable(struct rte_eth_dev *dev)
{
@@ -108,6 +116,8 @@ rnp_init_port_resource(struct rnp_eth_adapter *adapter,
struct rnp_hw *hw = &adapter->hw;
port->adapt = adapter;
+ port->rx_func_sec = adapter->rx_func_sec;
+ port->tx_func_sec = adapter->tx_func_sec;
port->s_mode = adapter->s_mode;
port->port_stopped = 1;
port->hw = hw;
@@ -443,6 +453,154 @@ rnp_special_ops_init(struct rte_eth_dev *eth_dev)
return 0;
}
+static const char *const rnp_valid_arguments[] = {
+ RNP_HW_MAC_LOOPBACK_ARG,
+ RNP_FW_UPDATE,
+ RNP_RX_FUNC_SELECT,
+ RNP_TX_FUNC_SELECT,
+ RNP_FW_4X10G_10G_1G_DET,
+ RNP_FW_FORCE_SPEED_1G,
+ NULL
+};
+
+static int
+rnp_parse_handle_devarg(const char *key, const char *value,
+ void *extra_args)
+{
+ struct rnp_eth_adapter *adapter = NULL;
+
+ if (value == NULL || extra_args == NULL)
+ return -EINVAL;
+
+ if (strcmp(key, RNP_HW_MAC_LOOPBACK_ARG) == 0) {
+ uint64_t *n = extra_args;
+ *n = (uint16_t)strtoul(value, NULL, 10);
+ if (*n > UINT16_MAX && errno == ERANGE) {
+ RNP_PMD_DRV_LOG(ERR, "invalid extra param value\n");
+ return -1;
+ }
+ } else if (strcmp(key, RNP_FW_UPDATE) == 0) {
+ adapter = (struct rnp_eth_adapter *)extra_args;
+ adapter->do_fw_update = true;
+ adapter->fw_path = strdup(value);
+ } else if (strcmp(key, RNP_FW_4X10G_10G_1G_DET) == 0) {
+ adapter = (struct rnp_eth_adapter *)extra_args;
+ if (adapter->num_ports == 2 && adapter->hw.speed == 10 * 1000) {
+ adapter->fw_sfp_10g_1g_auto_det =
+ (strcmp(value, "on") == 0) ? true : false;
+ } else {
+ adapter->fw_sfp_10g_1g_auto_det = false;
+ }
+ } else if (strcmp(key, RNP_FW_FORCE_SPEED_1G) == 0) {
+ adapter = (struct rnp_eth_adapter *)extra_args;
+ if (adapter->num_ports == 2) {
+ if (strcmp(value, "on") == 0)
+ adapter->fw_force_speed_1g = FOCE_SPEED_1G_ENABLED;
+ else if (strcmp(value, "off") == 0)
+ adapter->fw_force_speed_1g = FOCE_SPEED_1G_DISABLED;
+ }
+ } else {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+rnp_parse_io_select_func(const char *key, const char *value, void *extra_args)
+{
+ uint8_t select = RNP_IO_FUNC_USE_NONE;
+
+ RTE_SET_USED(key);
+
+ if (strcmp(value, "vec") == 0)
+ select = RNP_IO_FUNC_USE_VEC;
+ else if (strcmp(value, "simple") == 0)
+ select = RNP_IO_FUNC_USE_SIMPLE;
+ else if (strcmp(value, "common") == 0)
+ select = RNP_IO_FUNC_USE_COMMON;
+
+ *(uint8_t *)extra_args = select;
+
+ return 0;
+}
+
+static int
+rnp_parse_devargs(struct rnp_eth_adapter *adapter,
+ struct rte_devargs *devargs)
+{
+ uint8_t rx_io_func = RNP_IO_FUNC_USE_NONE;
+ uint8_t tx_io_func = RNP_IO_FUNC_USE_NONE;
+ struct rte_kvargs *kvlist;
+ bool loopback_en = false;
+ int ret = 0;
+
+ adapter->do_fw_update = false;
+ adapter->fw_sfp_10g_1g_auto_det = false;
+ adapter->fw_force_speed_1g = FOCE_SPEED_1G_NOT_SET;
+
+ if (!devargs)
+ goto def;
+
+ kvlist = rte_kvargs_parse(devargs->args, rnp_valid_arguments);
+ if (kvlist == NULL)
+ goto def;
+
+ if (rte_kvargs_count(kvlist, RNP_HW_MAC_LOOPBACK_ARG) == 1)
+ ret = rte_kvargs_process(kvlist, RNP_HW_MAC_LOOPBACK_ARG,
+ &rnp_parse_handle_devarg, &loopback_en);
+
+ if (rte_kvargs_count(kvlist, RNP_FW_4X10G_10G_1G_DET) == 1)
+ ret = rte_kvargs_process(kvlist,
+ RNP_FW_4X10G_10G_1G_DET,
+ &rnp_parse_handle_devarg,
+ adapter);
+
+ if (rte_kvargs_count(kvlist, RNP_FW_FORCE_SPEED_1G) == 1)
+ ret = rte_kvargs_process(kvlist,
+ RNP_FW_FORCE_SPEED_1G,
+ &rnp_parse_handle_devarg,
+ adapter);
+
+ if (rte_kvargs_count(kvlist, RNP_FW_UPDATE) == 1)
+ ret = rte_kvargs_process(kvlist, RNP_FW_UPDATE,
+ &rnp_parse_handle_devarg, adapter);
+ if (rte_kvargs_count(kvlist, RNP_RX_FUNC_SELECT) == 1)
+ ret = rte_kvargs_process(kvlist, RNP_RX_FUNC_SELECT,
+ &rnp_parse_io_select_func, &rx_io_func);
+ if (rte_kvargs_count(kvlist, RNP_TX_FUNC_SELECT) == 1)
+ ret = rte_kvargs_process(kvlist, RNP_TX_FUNC_SELECT,
+ &rnp_parse_io_select_func, &tx_io_func);
+ rte_kvargs_free(kvlist);
+def:
+ adapter->loopback_en = loopback_en;
+ adapter->rx_func_sec = rx_io_func;
+ adapter->tx_func_sec = tx_io_func;
+
+ return ret;
+}
+
+static int rnp_post_handle(struct rnp_eth_adapter *adapter)
+{
+ bool on = false;
+
+ if (!adapter->eth_dev)
+ return -ENOMEM;
+ if (adapter->do_fw_update && adapter->fw_path) {
+ rnp_fw_update(adapter);
+ adapter->do_fw_update = 0;
+ }
+
+ if (adapter->fw_sfp_10g_1g_auto_det)
+ return rnp_hw_set_fw_10g_1g_auto_detch(adapter->eth_dev, 1);
+
+ on = (adapter->fw_force_speed_1g == FOCE_SPEED_1G_ENABLED) ? 1 : 0;
+ if (adapter->fw_force_speed_1g != FOCE_SPEED_1G_NOT_SET)
+ return rnp_hw_set_fw_force_speed_1g(adapter->eth_dev, on);
+
+ return 0;
+}
+
static int
rnp_eth_dev_init(struct rte_eth_dev *dev)
{
@@ -492,6 +650,11 @@ rnp_eth_dev_init(struct rte_eth_dev *dev)
/* We need Use Device Id To Change The Resource Mode */
rnp_special_ops_init(dev);
port->hw = hw;
+ ret = rnp_parse_devargs(adapter, pci_dev->device.devargs);
+ if (ret) {
+ PMD_DRV_LOG(ERR, "parse_devargs failed");
+ return ret;
+ }
for (p_id = 0; p_id < adapter->num_ports; p_id++) {
/* port 0 resource has been alloced When Probe */
if (!p_id) {
@@ -517,6 +680,9 @@ rnp_eth_dev_init(struct rte_eth_dev *dev)
rnp_mac_rx_disable(eth_dev);
rnp_mac_tx_disable(eth_dev);
}
+ ret = rnp_post_handle(adapter);
+ if (ret)
+ goto eth_alloc_error;
return 0;
eth_alloc_error:
@@ -105,6 +105,27 @@ static int rnp_mbx_fw_post_req(struct rte_eth_dev *dev,
return err;
}
+static int
+rnp_mbx_write_posted_locked(struct rte_eth_dev *dev, struct mbx_fw_cmd_req *req)
+{
+ const struct rnp_mbx_api *ops = RNP_DEV_TO_MBX_OPS(dev);
+ struct rnp_hw *hw = RNP_DEV_TO_HW(dev);
+ int err = 0;
+
+ rte_spinlock_lock(&hw->fw_lock);
+
+ err = ops->write_posted(dev, (u32 *)req,
+ (req->datalen + MBX_REQ_HDR_LEN) / 4, MBX_FW);
+ if (err) {
+ RNP_PMD_LOG(ERR, "%s failed!\n", __func__);
+ goto quit;
+ }
+
+quit:
+ rte_spinlock_unlock(&hw->fw_lock);
+ return err;
+}
+
static int rnp_fw_get_capablity(struct rte_eth_dev *dev,
struct phy_abilities *abil)
{
@@ -381,3 +402,146 @@ int rnp_mbx_get_lane_stat(struct rte_eth_dev *dev)
quit:
return err;
}
+
+static int rnp_maintain_req(struct rte_eth_dev *dev,
+ int cmd,
+ int arg0,
+ int req_data_bytes,
+ int reply_bytes,
+ phys_addr_t dma_phy_addr)
+{
+ struct rnp_hw *hw = RNP_DEV_TO_HW(dev);
+ struct mbx_req_cookie *cookie = NULL;
+ struct mbx_fw_cmd_req req;
+ int err;
+
+ if (!hw->mbx.irq_enabled)
+ return -EIO;
+ cookie = rnp_memzone_reserve(hw->cookie_p_name, 0);
+ if (!cookie)
+ return -ENOMEM;
+ memset(&req, 0, sizeof(req));
+ cookie->timeout_ms = 60 * 1000; /* 60s */
+
+ build_maintain_req(&req,
+ cookie,
+ cmd,
+ arg0,
+ req_data_bytes,
+ reply_bytes,
+ dma_phy_addr & 0xffffffff,
+ (dma_phy_addr >> 32) & 0xffffffff);
+
+ err = rnp_mbx_fw_post_req(dev, &req, cookie);
+
+ return (err) ? -EIO : 0;
+}
+
+int rnp_fw_update(struct rnp_eth_adapter *adapter)
+{
+ const struct rte_memzone *rz = NULL;
+ struct maintain_req *mt;
+ FILE *file;
+ int fsz;
+#define MAX_FW_BIN_SZ (552 * 1024)
+#define FW_256KB (256 * 1024)
+
+ RNP_PMD_LOG(INFO, "%s: %s\n", __func__, adapter->fw_path);
+
+ file = fopen(adapter->fw_path, "rb");
+ if (!file) {
+ RNP_PMD_LOG(ERR,
+ "RNP: [%s] %s can't open for read\n",
+ __func__,
+ adapter->fw_path);
+ return -ENOENT;
+ }
+ /* get dma */
+ rz = rte_memzone_reserve("fw_update", MAX_FW_BIN_SZ, SOCKET_ID_ANY, 4);
+ if (rz == NULL) {
+ RNP_PMD_LOG(ERR, "RNP: [%s] not memory:%d\n", __func__,
+ MAX_FW_BIN_SZ);
+ return -EFBIG;
+ }
+ memset(rz->addr, 0xff, rz->len);
+ mt = (struct maintain_req *)rz->addr;
+
+ /* read data */
+ fsz = fread(mt->data, 1, rz->len, file);
+ if (fsz <= 0) {
+ RNP_PMD_LOG(INFO, "RNP: [%s] read failed! err:%d\n",
+ __func__, fsz);
+ return -EIO;
+ }
+ fclose(file);
+
+ if (fsz > ((256 + 4) * 1024)) {
+ printf("fw length:%d is two big. not supported!\n", fsz);
+ return -EINVAL;
+ }
+ RNP_PMD_LOG(NOTICE, "RNP: fw update ...\n");
+ fflush(stdout);
+
+ /* ==== update fw */
+ mt->magic = MAINTAIN_MAGIC;
+ mt->cmd = MT_WRITE_FLASH;
+ mt->arg0 = 1;
+ mt->req_data_bytes = (fsz > FW_256KB) ? FW_256KB : fsz;
+ mt->reply_bytes = 0;
+
+ if (rnp_maintain_req(adapter->eth_dev, mt->cmd, mt->arg0,
+ mt->req_data_bytes, mt->reply_bytes, rz->iova))
+ RNP_PMD_LOG(ERR, "maintain request failed!\n");
+ else
+ RNP_PMD_LOG(INFO, "maintail request done!\n");
+
+ /* ==== update cfg */
+ if (fsz > FW_256KB) {
+ mt->magic = MAINTAIN_MAGIC;
+ mt->cmd = MT_WRITE_FLASH;
+ mt->arg0 = 2;
+ mt->req_data_bytes = 4096;
+ mt->reply_bytes = 0;
+ memcpy(mt->data, mt->data + FW_256KB, mt->req_data_bytes);
+
+ if (rnp_maintain_req(adapter->eth_dev,
+ mt->cmd, mt->arg0, mt->req_data_bytes,
+ mt->reply_bytes, rz->iova))
+ RNP_PMD_LOG(ERR, "maintain request failed!\n");
+ else
+ RNP_PMD_LOG(INFO, "maintail request done!\n");
+ }
+
+ RNP_PMD_LOG(NOTICE, "done\n");
+ fflush(stdout);
+
+ rte_memzone_free(rz);
+
+ exit(0);
+
+ return 0;
+}
+
+static int rnp_mbx_set_dump(struct rte_eth_dev *dev, int flag)
+{
+ struct rnp_eth_port *port = RNP_DEV_TO_PORT(dev);
+ struct mbx_fw_cmd_req req;
+ int err;
+
+ memset(&req, 0, sizeof(req));
+ build_set_dump(&req, port->attr.nr_lane, flag);
+
+ err = rnp_mbx_write_posted_locked(dev, &req);
+
+ return err;
+}
+
+int rnp_hw_set_fw_10g_1g_auto_detch(struct rte_eth_dev *dev, int enable)
+{
+ return rnp_mbx_set_dump(dev, 0x01140000 | (enable & 1));
+}
+
+int rnp_hw_set_fw_force_speed_1g(struct rte_eth_dev *dev, int enable)
+{
+ return rnp_mbx_set_dump(dev, 0x01150000 | (enable & 1));
+}
@@ -16,6 +16,17 @@ struct mbx_req_cookie {
int priv_len;
char priv[RNP_MAX_SHARE_MEM];
};
+struct maintain_req {
+ int magic;
+#define MAINTAIN_MAGIC 0xa6a7a8a9
+
+ int cmd;
+ int arg0;
+ int req_data_bytes;
+ int reply_bytes;
+ char data[0];
+} __rte_packed;
+
enum GENERIC_CMD {
/* link configuration admin commands */
GET_PHY_ABALITY = 0x0601,
@@ -23,6 +34,9 @@ enum GENERIC_CMD {
RESET_PHY = 0x0603,
GET_LANE_STATUS = 0x0610,
SET_EVENT_MASK = 0x0613,
+ /* fw update */
+ FW_MAINTAIN = 0x0701,
+ SET_DUMP = 0x0a10,
};
enum link_event_mask {
@@ -211,6 +225,21 @@ struct mbx_fw_cmd_req {
struct {
int nr_lane;
} get_lane_st;
+
+ struct {
+ int cmd;
+#define MT_WRITE_FLASH 1
+ int arg0;
+ int req_bytes;
+ int reply_bytes;
+ int ddr_lo;
+ int ddr_hi;
+ } maintain;
+
+ struct {
+ int flag;
+ int nr_lane;
+ } set_dump;
};
} __rte_packed __rte_aligned(4);
@@ -284,6 +313,43 @@ build_get_lane_status_req(struct mbx_fw_cmd_req *req,
req->get_lane_st.nr_lane = nr_lane;
}
+static inline void
+build_maintain_req(struct mbx_fw_cmd_req *req,
+ void *cookie,
+ int cmd,
+ int arg0,
+ int req_bytes,
+ int reply_bytes,
+ u32 dma_phy_lo,
+ u32 dma_phy_hi)
+{
+ req->flags = 0;
+ req->opcode = FW_MAINTAIN;
+ req->datalen = sizeof(req->maintain);
+ req->cookie = cookie;
+ req->reply_lo = 0;
+ req->reply_hi = 0;
+ req->maintain.cmd = cmd;
+ req->maintain.arg0 = arg0;
+ req->maintain.req_bytes = req_bytes;
+ req->maintain.reply_bytes = reply_bytes;
+ req->maintain.ddr_lo = dma_phy_lo;
+ req->maintain.ddr_hi = dma_phy_hi;
+}
+
+static inline void
+build_set_dump(struct mbx_fw_cmd_req *req, int nr_lane, int flag)
+{
+ req->flags = 0;
+ req->opcode = SET_DUMP;
+ req->datalen = sizeof(req->set_dump);
+ req->cookie = NULL;
+ req->reply_lo = 0;
+ req->reply_hi = 0;
+ req->set_dump.flag = flag;
+ req->set_dump.nr_lane = nr_lane;
+}
+
int rnp_mbx_get_capability(struct rte_eth_dev *dev,
int *lane_mask,
int *nic_mode);
@@ -295,4 +361,7 @@ rnp_fw_get_macaddr(struct rte_eth_dev *dev,
u8 *mac_addr,
int nr_lane);
int rnp_mbx_get_lane_stat(struct rte_eth_dev *dev);
+int rnp_fw_update(struct rnp_eth_adapter *adapter);
+int rnp_hw_set_fw_10g_1g_auto_detch(struct rte_eth_dev *dev, int enable);
+int rnp_hw_set_fw_force_speed_1g(struct rte_eth_dev *dev, int enable);
#endif /* __RNP_MBX_FW_H__*/