@@ -5,6 +5,9 @@
#ifndef _RNP_ETH_REGS_H
#define _RNP_ETH_REGS_H
+#define RNP_ETH_TX_FIFO_STATE _ETH_(0x0330)
+#define RNP_ETH_TX_FIFO_EMPT(lane) ((1 << (lane)) | (1 << ((lane) + 4)))
+
#define RNP_E_ENG_BYPASS _ETH_(0x8000)
#define RNP_E_VXLAN_PARSE_EN _ETH_(0x8004)
#define RNP_E_FILTER_EN _ETH_(0x801c)
@@ -107,6 +107,25 @@ rnp_build_lane_evet_mask(struct rnp_mbx_fw_cmd_req *req,
arg->event_en = req_arg->param2;
}
+static void
+rnp_build_ifup_down(struct rnp_mbx_fw_cmd_req *req,
+ struct rnp_fw_req_arg *req_arg,
+ void *cookie)
+{
+ struct rnp_ifup_down_req *arg =
+ (struct rnp_ifup_down_req *)req->data;
+
+ req->flags = 0;
+ req->opcode = RNP_IFUP_DOWN;
+ req->datalen = sizeof(*arg);
+ req->cookie = cookie;
+ req->reply_lo = 0;
+ req->reply_hi = 0;
+
+ arg->nr_lane = req_arg->param0;
+ arg->up = req_arg->param1;
+}
+
int rnp_build_fwcmd_req(struct rnp_mbx_fw_cmd_req *req,
struct rnp_fw_req_arg *arg,
void *cookie)
@@ -132,6 +151,9 @@ int rnp_build_fwcmd_req(struct rnp_mbx_fw_cmd_req *req,
case RNP_SET_LANE_EVENT_EN:
rnp_build_lane_evet_mask(req, arg, cookie);
break;
+ case RNP_IFUP_DOWN:
+ rnp_build_ifup_down(req, arg, cookie);
+ break;
default:
err = -EOPNOTSUPP;
}
@@ -309,6 +309,12 @@ struct rnp_link_stat_req {
struct rnp_port_stat states[RNP_MAX_PORT_OF_PF];
};
+struct rnp_ifup_down_req {
+ u32 nr_lane;
+ u32 up;
+ u8 rsvd[24];
+};
+
struct rnp_mbx_fw_cmd_req {
u16 flags;
u16 opcode;
@@ -464,3 +464,36 @@ rnp_rcv_msg_from_fw(struct rnp_eth_adapter *adapter, u32 *msgbuf)
return 0;
}
+
+static void rnp_link_stat_reset(struct rnp_hw *hw, u16 lane)
+{
+ u32 state;
+
+ spin_lock(&hw->link_sync);
+ state = RNP_E_REG_RD(hw, RNP_FW_LINK_SYNC);
+ state &= ~RNP_LINK_MAGIC_MASK;
+ state |= RNP_LINK_MAGIC_CODE;
+ state &= ~RTE_BIT32(lane);
+
+ RNP_E_REG_WR(hw, RNP_FW_LINK_SYNC, state);
+ rte_spinlock_unlock(&hw->link_sync);
+}
+
+int rnp_mbx_fw_ifup_down(struct rnp_eth_port *port, bool up)
+{
+ u16 nr_lane = port->attr.nr_lane;
+ struct rnp_hw *hw = port->hw;
+ struct rnp_fw_req_arg arg;
+ int err;
+
+ memset(&arg, 0, sizeof(arg));
+ arg.opcode = RNP_IFUP_DOWN;
+ arg.param0 = nr_lane;
+ arg.param1 = up;
+
+ err = rnp_fw_send_norep_cmd(port, &arg);
+ /* force firmware send irq event to dpdk */
+ if (!err && up)
+ rnp_link_stat_reset(hw, nr_lane);
+ return err;
+}
@@ -19,5 +19,6 @@ int rnp_fw_init(struct rnp_hw *hw);
int rnp_rcv_msg_from_fw(struct rnp_eth_adapter *adapter, u32 *msgbuf);
int rnp_fw_mbx_ifup_down(struct rnp_eth_port *port, int up);
int rnp_mbx_fw_lane_link_event_en(struct rnp_eth_port *port, bool en);
+int rnp_mbx_fw_ifup_down(struct rnp_eth_port *port, bool up);
#endif /* _RNP_MBX_FW_H_ */
@@ -326,6 +326,7 @@ static int rnp_dev_start(struct rte_eth_dev *eth_dev)
rnp_mbx_fw_lane_link_event_en(port, lsc);
if (!lsc)
rnp_run_link_poll_task(port);
+ rnp_dev_set_link_up(eth_dev);
/* enable eth rx flow */
RNP_RX_ETH_ENABLE(hw, lane);
port->port_stopped = 0;
@@ -411,6 +412,7 @@ static int rnp_dev_stop(struct rte_eth_dev *eth_dev)
/* clear the recorded link status */
memset(&link, 0, sizeof(link));
rte_eth_linkstatus_set(eth_dev, &link);
+ rnp_dev_set_link_down(eth_dev);
rnp_disable_all_tx_queue(eth_dev);
rnp_disable_all_rx_queue(eth_dev);
rnp_mac_tx_disable(eth_dev);
@@ -647,6 +649,8 @@ static const struct eth_dev_ops rnp_eth_dev_ops = {
.rss_hash_conf_get = rnp_dev_rss_hash_conf_get,
/* link impl */
.link_update = rnp_dev_link_update,
+ .dev_set_link_up = rnp_dev_set_link_up,
+ .dev_set_link_down = rnp_dev_set_link_down,
};
static void
@@ -338,3 +338,102 @@ rnp_cancel_link_poll_task(struct rnp_eth_port *port)
{
rte_eal_alarm_cancel(rnp_dev_link_task, port->eth_dev);
}
+
+int rnp_dev_set_link_up(struct rte_eth_dev *eth_dev)
+{
+ struct rnp_eth_port *port = RNP_DEV_TO_PORT(eth_dev);
+ uint16_t nr_lane = port->attr.nr_lane;
+ struct rnp_hw *hw = port->hw;
+ struct rnp_rx_queue *rxq;
+ uint16_t timeout;
+ uint16_t index;
+ uint32_t state;
+ uint16_t idx;
+ int ret = 0;
+
+ PMD_INIT_FUNC_TRACE();
+
+ if (port->attr.link_ready)
+ return 0;
+ /* Cur link-state Is Down Verity The Rx Dma Queue State Is Empty */
+ if (!port->attr.link_ready) {
+ for (idx = 0; idx < eth_dev->data->nb_rx_queues; idx++) {
+ rxq = eth_dev->data->rx_queues[idx];
+ if (!rxq)
+ continue;
+ index = rxq->attr.index;
+ timeout = 0;
+ do {
+ if (!RNP_E_REG_RD(hw, RNP_RXQ_READY(index)))
+ break;
+ rte_delay_us(10);
+ timeout++;
+ } while (timeout < 1000);
+ }
+ }
+ ret = rnp_mbx_fw_ifup_down(port, TRUE);
+ if (ret) {
+ RNP_PMD_WARN("port[%d] is set linkup failed",
+ eth_dev->data->port_id);
+ return ret;
+ }
+ timeout = 0;
+ do {
+ rte_io_rmb();
+ state = RNP_E_REG_RD(hw, RNP_FW_LINK_SYNC);
+ if (state & RTE_BIT32(nr_lane))
+ break;
+ timeout++;
+ rte_delay_us(10);
+ } while (timeout < 100);
+
+ return ret;
+}
+
+int rnp_dev_set_link_down(struct rte_eth_dev *eth_dev)
+{
+ struct rnp_eth_port *port = RNP_DEV_TO_PORT(eth_dev);
+ uint16_t nr_lane = port->attr.nr_lane;
+ struct rnp_hw *hw = port->hw;
+ struct rnp_tx_queue *txq;
+ uint32_t timeout = 0;
+ uint32_t check_v;
+ uint32_t state;
+ uint16_t idx;
+
+ PMD_INIT_FUNC_TRACE();
+ RNP_RX_ETH_DISABLE(hw, nr_lane);
+ for (idx = 0; idx < eth_dev->data->nb_tx_queues; idx++) {
+ txq = eth_dev->data->tx_queues[idx];
+ if (!txq)
+ continue;
+ txq->tx_link = false;
+ }
+ /* 2 Check eth tx fifo empty state */
+ do {
+ state = RNP_E_REG_RD(hw, RNP_ETH_TX_FIFO_STATE);
+ check_v = RNP_ETH_TX_FIFO_EMPT(nr_lane);
+ state &= check_v;
+ if (state == check_v)
+ break;
+ rte_delay_us(10);
+ timeout++;
+ if (timeout >= 1000) {
+ RNP_PMD_WARN("lane[%d] isn't empty of link-down action",
+ nr_lane);
+ break;
+ }
+ } while (1);
+ /* 3 Tell Firmware Do Link-down Event Work */
+ rnp_mbx_fw_ifup_down(port, FALSE);
+ /* 4 Wait For Link-Down that Firmware Do done */
+ timeout = 0;
+ do {
+ if (!port->attr.link_ready)
+ break;
+ rte_delay_us(10);
+ timeout++;
+ } while (timeout < 2000);
+
+ return 0;
+}
@@ -32,5 +32,7 @@ int rnp_dev_link_update(struct rte_eth_dev *eth_dev,
int wait_to_complete);
void rnp_run_link_poll_task(struct rnp_eth_port *port);
void rnp_cancel_link_poll_task(struct rnp_eth_port *port);
+int rnp_dev_set_link_up(struct rte_eth_dev *eth_dev);
+int rnp_dev_set_link_down(struct rte_eth_dev *eth_dev);
#endif /* _RNP_LINK_H_ */