Initialize link status handler Signed-off-by: Dong Yibo --- drivers/net/ethernet/mucse/rnpgbe/rnpgbe.h | 55 ++++++- .../net/ethernet/mucse/rnpgbe/rnpgbe_chip.c | 19 +++ .../net/ethernet/mucse/rnpgbe/rnpgbe_main.c | 138 +++++++++++++++- .../net/ethernet/mucse/rnpgbe/rnpgbe_mbx.h | 1 + .../net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.c | 147 ++++++++++++++++++ .../net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.h | 1 + 6 files changed, 359 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe.h b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe.h index c049952f41e8..5ca2ec73bbe7 100644 --- a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe.h +++ b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe.h @@ -25,6 +25,15 @@ enum rnpgbe_hw_type { rnpgbe_hw_unknow, }; +enum speed_enum { + speed_10, + speed_100, + speed_1000, + speed_10000, + speed_25000, + speed_40000, +}; + struct mucse_dma_info { u8 __iomem *dma_base_addr; u8 __iomem *dma_ring_addr; @@ -120,6 +129,31 @@ struct mucse_mbx_operations { bool enable); }; +/* Flow Control Settings */ +enum mucse_fc_mode { + mucse_fc_none = 0, + mucse_fc_rx_pause, + mucse_fc_tx_pause, + mucse_fc_full, + mucse_fc_default +}; + +#define PAUSE_TX (0x1) +#define PAUSE_RX (0x2) +#define PAUSE_AUTO (0x10) +#define ASYM_PAUSE BIT(11) +#define SYM_PAUSE BIT(10) + +#define M_MAX_TRAFFIC_CLASS (4) +/* Flow control parameters */ +struct mucse_fc_info { + u32 high_water[M_MAX_TRAFFIC_CLASS]; + u32 low_water[M_MAX_TRAFFIC_CLASS]; + u16 pause_time; + enum mucse_fc_mode current_mode; + enum mucse_fc_mode requested_mode; +}; + struct mucse_mbx_stats { u32 msgs_tx; u32 msgs_rx; @@ -185,6 +219,8 @@ struct mucse_hw_operations { void (*set_irq_mode)(struct mucse_hw *hw, bool legacy); void (*set_mbx_link_event)(struct mucse_hw *hw, int enable); void (*set_mbx_ifup)(struct mucse_hw *hw, int enable); + void (*check_link)(struct mucse_hw *hw, u32 *speed, bool *link_up, + bool *duplex); }; enum { @@ -223,6 +259,7 @@ struct mucse_hw { struct mucse_dma_info dma; struct mucse_eth_info eth; struct mucse_mac_info mac; + struct mucse_fc_info fc; struct mucse_mbx_info mbx; struct mucse_addr_filter_info addr_ctrl; #define M_NET_FEATURE_SG ((u32)(1 << 0)) @@ -253,13 +290,17 @@ struct mucse_hw { u16 max_msix_vectors; int nr_lane; struct lldp_status lldp_status; + int speed; + u32 duplex; + u32 tp_mdx; int link; u8 addr[ETH_ALEN]; u8 perm_addr[ETH_ALEN]; }; enum mucse_state_t { - __MMUCSE_TESTING, + __MUCSE_TESTING, + __MUCSE_RESETTING, __MUCSE_DOWN, __MUCSE_SERVICE_SCHED, __MUCSE_PTP_TX_IN_PROGRESS, @@ -547,6 +588,7 @@ struct mucse { u32 priv_flags; #define M_PRIV_FLAG_TX_COALESCE ((u32)(1 << 25)) #define M_PRIV_FLAG_RX_COALESCE ((u32)(1 << 26)) +#define M_PRIV_FLAG_LLDP ((u32)(1 << 27)) struct mucse_ring *tx_ring[MAX_TX_QUEUES] ____cacheline_aligned_in_smp; int tx_ring_item_count; int num_tx_queues; @@ -565,6 +607,9 @@ struct mucse { u16 rx_frames; u16 tx_frames; u16 tx_usecs; + bool link_up; + u32 link_speed; + bool duplex; unsigned long state; unsigned long link_check_timeout; struct timer_list service_timer; @@ -613,9 +658,17 @@ static inline unsigned int mucse_rx_bufsz(struct mucse_ring *ring) #define M_PKT_TIMEOUT (30) #define M_RX_PKT_POLL_BUDGET (64) +#define M_LINK_SPEED_UNKNOWN 0 +#define M_LINK_SPEED_10_FULL BIT(2) +#define M_LINK_SPEED_100_FULL BIT(3) +#define M_LINK_SPEED_1GB_FULL BIT(4) + +#define M_TRY_LINK_TIMEOUT (4 * HZ) + #define m_rd_reg(reg) readl((void *)(reg)) #define m_wr_reg(reg, val) writel((val), (void *)(reg)) #define hw_wr32(hw, reg, val) m_wr_reg((hw)->hw_addr + (reg), (val)) +#define hw_rd32(hw, reg) m_rd_reg((hw)->hw_addr + (reg)) #define dma_wr32(dma, reg, val) m_wr_reg((dma)->dma_base_addr + (reg), (val)) #define dma_rd32(dma, reg) m_rd_reg((dma)->dma_base_addr + (reg)) #define eth_wr32(eth, reg, val) m_wr_reg((eth)->eth_base_addr + (reg), (val)) diff --git a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_chip.c b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_chip.c index 7cc9134952bf..cb2448f497fe 100644 --- a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_chip.c +++ b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_chip.c @@ -300,6 +300,24 @@ static void rnpgbe_set_mbx_ifup_hw_ops_n500(struct mucse_hw *hw, mucse_mbx_ifup_down(hw, enable); } +static void rnpgbe_check_mac_link_hw_ops_n500(struct mucse_hw *hw, + u32 *speed, + bool *link_up, + bool *duplex) +{ + if (hw->speed == 10) + *speed = M_LINK_SPEED_10_FULL; + else if (hw->speed == 100) + *speed = M_LINK_SPEED_100_FULL; + else if (hw->speed == 1000) + *speed = M_LINK_SPEED_1GB_FULL; + else + *speed = M_LINK_SPEED_UNKNOWN; + + *link_up = !!hw->link; + *duplex = !!hw->duplex; +} + static struct mucse_hw_operations hw_ops_n500 = { .init_hw = &rnpgbe_init_hw_ops_n500, .reset_hw = &rnpgbe_reset_hw_ops_n500, @@ -311,6 +329,7 @@ static struct mucse_hw_operations hw_ops_n500 = { .set_irq_mode = &rnpgbe_set_irq_mode_n500, .set_mbx_link_event = &rnpgbe_set_mbx_link_event_hw_ops_n500, .set_mbx_ifup = &rnpgbe_set_mbx_ifup_hw_ops_n500, + .check_link = &rnpgbe_check_mac_link_hw_ops_n500, }; /** diff --git a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_main.c b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_main.c index 01cff0a780ff..c2f53af3de09 100644 --- a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_main.c +++ b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_main.c @@ -84,12 +84,144 @@ static void rnpgbe_service_timer(struct timer_list *t) rnpgbe_service_event_schedule(mucse); } +static void rnpgbe_service_event_complete(struct mucse *mucse) +{ + /* flush memory to make sure state is correct before next watchdog */ + smp_mb__before_atomic(); + clear_bit(__MUCSE_SERVICE_SCHED, &mucse->state); +} + +/** + * rnpgbe_watchdog_update_link - update the link status + * @mucse: pointer to the device adapter structure + **/ +static void rnpgbe_watchdog_update_link(struct mucse *mucse) +{ + struct mucse_hw *hw = &mucse->hw; + u32 link_speed = mucse->link_speed; + bool link_up; + bool duplex; + bool flow_rx = true, flow_tx = true; + + if (!(mucse->flags & M_FLAG_NEED_LINK_UPDATE)) + return; + + if (hw->ops.check_link) { + hw->ops.check_link(hw, &link_speed, &link_up, &duplex); + } else { + /* always assume link is up, if no check link function */ + link_speed = M_LINK_SPEED_1GB_FULL; + link_up = true; + } + + if (link_up || time_after(jiffies, (mucse->link_check_timeout + + M_TRY_LINK_TIMEOUT))) { + mucse->flags &= ~M_FLAG_NEED_LINK_UPDATE; + } + mucse->link_up = link_up; + mucse->link_speed = link_speed; + mucse->duplex = duplex; + + switch (hw->fc.current_mode) { + case mucse_fc_none: + flow_rx = false; + flow_tx = false; + break; + case mucse_fc_tx_pause: + flow_rx = false; + flow_tx = true; + + break; + case mucse_fc_rx_pause: + flow_rx = true; + flow_tx = false; + break; + + case mucse_fc_full: + flow_rx = true; + flow_tx = true; + break; + default: + flow_rx = false; + flow_tx = false; + } + + if (mucse->link_up) { + e_info(drv, "NIC Link is Up %s, %s Duplex, Flow Control: %s\n", + (link_speed == M_LINK_SPEED_1GB_FULL ? "1000 Mbps" : + (link_speed == M_LINK_SPEED_100_FULL ? "100 Mbps" : + (link_speed == M_LINK_SPEED_10_FULL ? "10 Mbps" : + "unknown speed"))), + ((duplex) ? "Full" : "Half"), + ((flow_rx && flow_tx) ? "RX/TX" : + (flow_rx ? "RX" : (flow_tx ? "TX" : "None")))); + } +} + +/** + * rnpgbe_watchdog_link_is_up - update netif_carrier status and + * print link up message + * @mucse: pointer to the device adapter structure + **/ +static void rnpgbe_watchdog_link_is_up(struct mucse *mucse) +{ + struct net_device *netdev = mucse->netdev; + + /* only continue if link was previously down */ + if (netif_carrier_ok(netdev)) + return; + netif_carrier_on(netdev); + netif_tx_wake_all_queues(netdev); +} + +/** + * rnpgbe_watchdog_link_is_down - update netif_carrier status and + * print link down message + * @mucse: pointer to the adapter structure + **/ +static void rnpgbe_watchdog_link_is_down(struct mucse *mucse) +{ + struct net_device *netdev = mucse->netdev; + + mucse->link_up = false; + mucse->link_speed = 0; + /* only continue if link was up previously */ + if (!netif_carrier_ok(netdev)) + return; + e_info(drv, "NIC Link is Down\n"); + netif_carrier_off(netdev); + netif_tx_stop_all_queues(netdev); +} + +/** + * rnpgbe_watchdog_subtask - check and bring link up + * @mucse: pointer to the device adapter structure + **/ +static void rnpgbe_watchdog_subtask(struct mucse *mucse) +{ + /* if interface is down do nothing */ + /* should do link status if in sriov */ + if (test_bit(__MUCSE_DOWN, &mucse->state) || + test_bit(__MUCSE_RESETTING, &mucse->state)) + return; + + rnpgbe_watchdog_update_link(mucse); + if (mucse->link_up) + rnpgbe_watchdog_link_is_up(mucse); + else + rnpgbe_watchdog_link_is_down(mucse); +} + /** * rnpgbe_service_task - manages and runs subtasks * @work: pointer to work_struct containing our data **/ static void rnpgbe_service_task(struct work_struct *work) { + struct mucse *mucse = container_of(work, struct mucse, service_task); + + rnpgbe_watchdog_subtask(mucse); + rnpgbe_service_event_complete(mucse); } int rnpgbe_poll(struct napi_struct *napi, int budget) @@ -255,7 +387,7 @@ static int rnpgbe_open(struct net_device *netdev) int err; /* disallow open during test */ - if (test_bit(__MMUCSE_TESTING, &mucse->state)) + if (test_bit(__MUCSE_TESTING, &mucse->state)) return -EBUSY; netif_carrier_off(netdev); @@ -271,6 +403,8 @@ static int rnpgbe_open(struct net_device *netdev) if (err) goto err_set_queues; rnpgbe_up_complete(mucse); + + return 0; err_req_irq: rnpgbe_free_txrx(mucse); err_set_queues: @@ -387,6 +521,8 @@ static irqreturn_t rnpgbe_msix_other(int irq, void *data) struct mucse *mucse = (struct mucse *)data; set_bit(__MUCSE_IN_IRQ, &mucse->state); + /* handle fw req and ack */ + rnpgbe_fw_msg_handler(mucse); clear_bit(__MUCSE_IN_IRQ, &mucse->state); return IRQ_HANDLED; diff --git a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx.h b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx.h index fbb154051313..666896de1f9f 100644 --- a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx.h +++ b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx.h @@ -8,6 +8,7 @@ #define MUCSE_ERR_MBX -100 /* 14 words */ #define MUCSE_VFMAILBOX_SIZE 14 +#define MUCSE_FW_MAILBOX_SIZE MUCSE_VFMAILBOX_SIZE /* ================ PF <--> VF mailbox ================ */ #define SHARE_MEM_BYTES 64 static inline u32 PF_VF_SHM(struct mucse_mbx_info *mbx, int vf) diff --git a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.c b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.c index fc6c0dbfff84..066bf450cf59 100644 --- a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.c +++ b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.c @@ -501,3 +501,150 @@ int mucse_mbx_ifup_down(struct mucse_hw *hw, int up) return err; } + +static void rnpgbe_link_stat_mark(struct mucse_hw *hw, int up) +{ + u32 v; + struct mucse *mucse = (struct mucse *)hw->back; + + v = hw_rd32(hw, DMA_DUMY); + v &= ~(0x0f000f11); + v |= 0xa0000000; + if (up) { + v |= BIT(0); + switch (hw->speed) { + case 10: + v |= (speed_10 << 8); + break; + case 100: + v |= (speed_100 << 8); + break; + case 1000: + v |= (speed_1000 << 8); + break; + case 10000: + v |= (speed_10000 << 8); + break; + case 25000: + v |= (speed_25000 << 8); + break; + case 40000: + v |= (speed_40000 << 8); + break; + } + v |= (hw->duplex << 4); + v |= (hw->fc.current_mode << 24); + } else { + v &= ~BIT(0); + } + /* we should update lldp_status */ + if (hw->fw_version >= 0x00010500) { + if (mucse->priv_flags & M_PRIV_FLAG_LLDP) + v |= BIT(6); + else + v &= (~BIT(6)); + } + hw_wr32(hw, DMA_DUMY, v); +} + +static int rnpgbe_mbx_fw_reply_handler(struct mucse *adapter, + struct mbx_fw_cmd_reply *reply) +{ + struct mbx_req_cookie *cookie; + + cookie = reply->cookie; + if (!cookie || cookie->magic != COOKIE_MAGIC) + return -EIO; + + if (cookie->priv_len > 0) + memcpy(cookie->priv, reply->data, cookie->priv_len); + + cookie->done = 1; + + if (reply->flags & FLAGS_ERR) + cookie->errcode = reply->error_code; + else + cookie->errcode = 0; + wake_up_interruptible(&cookie->wait); + return 0; +} + +static int rnpgbe_mbx_fw_req_handler(struct mucse *mucse, + struct mbx_fw_cmd_req *req) +{ + struct mucse_hw *hw = &mucse->hw; + + switch (req->opcode) { + case LINK_STATUS_EVENT: + if (req->link_stat.lane_status) + hw->link = 1; + else + hw->link = 0; + if (hw->hw_type == rnpgbe_hw_n500 || + hw->hw_type == rnpgbe_hw_n210 || + hw->hw_type == rnpgbe_hw_n210L) { + /* fw_version more than 0.1.5.0 can up lldp_status */ + if (hw->fw_version >= 0x00010500) { + if (req->link_stat.st[0].lldp_status) + mucse->priv_flags |= M_PRIV_FLAG_LLDP; + else + mucse->priv_flags &= (~M_PRIV_FLAG_LLDP); + } + } + if (req->link_stat.port_st_magic == SPEED_VALID_MAGIC) { + hw->speed = req->link_stat.st[0].speed; + hw->duplex = req->link_stat.st[0].duplex; + if (hw->hw_type == rnpgbe_hw_n500 || + hw->hw_type == rnpgbe_hw_n210 || + hw->hw_type == rnpgbe_hw_n210L) { + hw->fc.current_mode = + req->link_stat.st[0].pause; + hw->tp_mdx = req->link_stat.st[0].tp_mdx; + } + } + if (req->link_stat.lane_status) + rnpgbe_link_stat_mark(hw, 1); + else + rnpgbe_link_stat_mark(hw, 0); + + mucse->flags |= M_FLAG_NEED_LINK_UPDATE; + break; + } + return 0; +} + +static int rnpgbe_rcv_msg_from_fw(struct mucse *mucse) +{ + u32 msgbuf[MUCSE_FW_MAILBOX_SIZE]; + struct mucse_hw *hw = &mucse->hw; + s32 retval; + + retval = mucse_read_mbx(hw, msgbuf, MUCSE_FW_MAILBOX_SIZE, MBX_FW); + if (retval) + return retval; + /* this is a message we already processed, do nothing */ + if (((unsigned short *)msgbuf)[0] & FLAGS_DD) { + return rnpgbe_mbx_fw_reply_handler(mucse, + (struct mbx_fw_cmd_reply *)msgbuf); + } else { + return rnpgbe_mbx_fw_req_handler(mucse, + (struct mbx_fw_cmd_req *)msgbuf); + } +} + +static void rnpgbe_rcv_ack_from_fw(struct mucse *mucse) +{ + /* do-nothing */ +} + +int rnpgbe_fw_msg_handler(struct mucse *mucse) +{ + /* check fw-req */ + if (!mucse_check_for_msg(&mucse->hw, MBX_FW)) + rnpgbe_rcv_msg_from_fw(mucse); + /* process any acks */ + if (!mucse_check_for_ack(&mucse->hw, MBX_FW)) + rnpgbe_rcv_ack_from_fw(mucse); + + return 0; +} diff --git a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.h b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.h index cd5a98acd983..2700eebf5873 100644 --- a/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.h +++ b/drivers/net/ethernet/mucse/rnpgbe/rnpgbe_mbx_fw.h @@ -647,4 +647,5 @@ int mucse_fw_get_macaddr(struct mucse_hw *hw, int pfvfnum, u8 *mac_addr, int nr_lane); int mucse_mbx_link_event_enable(struct mucse_hw *hw, int enable); int mucse_mbx_ifup_down(struct mucse_hw *hw, int up); +int rnpgbe_fw_msg_handler(struct mucse *mucse); #endif /* _RNPGBE_MBX_FW_H */ -- 2.25.1