1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(C) 2021 Marvell.
3 */
4
5 #include "cnxk_ethdev.h"
6
7 void
cnxk_nix_toggle_flag_link_cfg(struct cnxk_eth_dev * dev,bool set)8 cnxk_nix_toggle_flag_link_cfg(struct cnxk_eth_dev *dev, bool set)
9 {
10 if (set)
11 dev->flags |= CNXK_LINK_CFG_IN_PROGRESS_F;
12 else
13 dev->flags &= ~CNXK_LINK_CFG_IN_PROGRESS_F;
14
15 /* Update link info for LBK */
16 if (!set && roc_nix_is_lbk(&dev->nix)) {
17 struct rte_eth_link link;
18
19 link.link_status = RTE_ETH_LINK_UP;
20 link.link_speed = RTE_ETH_SPEED_NUM_100G;
21 link.link_autoneg = RTE_ETH_LINK_FIXED;
22 link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
23 rte_eth_linkstatus_set(dev->eth_dev, &link);
24 }
25
26 rte_wmb();
27 }
28
29 static inline int
nix_wait_for_link_cfg(struct cnxk_eth_dev * dev)30 nix_wait_for_link_cfg(struct cnxk_eth_dev *dev)
31 {
32 uint16_t wait = 1000;
33
34 do {
35 rte_atomic_thread_fence(__ATOMIC_ACQUIRE);
36 if (!(dev->flags & CNXK_LINK_CFG_IN_PROGRESS_F))
37 break;
38 wait--;
39 rte_delay_ms(1);
40 } while (wait);
41
42 return wait ? 0 : -1;
43 }
44
45 static void
nix_link_status_print(struct rte_eth_dev * eth_dev,struct rte_eth_link * link)46 nix_link_status_print(struct rte_eth_dev *eth_dev, struct rte_eth_link *link)
47 {
48 if (link && link->link_status)
49 plt_info("Port %d: Link Up - speed %u Mbps - %s",
50 (int)(eth_dev->data->port_id),
51 (uint32_t)link->link_speed,
52 link->link_duplex == RTE_ETH_LINK_FULL_DUPLEX
53 ? "full-duplex"
54 : "half-duplex");
55 else
56 plt_info("Port %d: Link Down", (int)(eth_dev->data->port_id));
57 }
58
59 void
cnxk_eth_dev_link_status_get_cb(struct roc_nix * nix,struct roc_nix_link_info * link)60 cnxk_eth_dev_link_status_get_cb(struct roc_nix *nix,
61 struct roc_nix_link_info *link)
62 {
63 struct cnxk_eth_dev *dev = (struct cnxk_eth_dev *)nix;
64 struct rte_eth_link eth_link;
65 struct rte_eth_dev *eth_dev;
66
67 if (!link || !nix)
68 return;
69
70 eth_dev = dev->eth_dev;
71 if (!eth_dev)
72 return;
73
74 rte_eth_linkstatus_get(eth_dev, ð_link);
75
76 link->status = eth_link.link_status;
77 link->speed = eth_link.link_speed;
78 link->autoneg = eth_link.link_autoneg;
79 link->full_duplex = eth_link.link_duplex;
80 }
81
82 void
cnxk_eth_dev_link_status_cb(struct roc_nix * nix,struct roc_nix_link_info * link)83 cnxk_eth_dev_link_status_cb(struct roc_nix *nix, struct roc_nix_link_info *link)
84 {
85 struct cnxk_eth_dev *dev = (struct cnxk_eth_dev *)nix;
86 struct rte_eth_link eth_link;
87 struct rte_eth_dev *eth_dev;
88
89 if (!link || !nix)
90 return;
91
92 eth_dev = dev->eth_dev;
93 if (!eth_dev || !eth_dev->data->dev_conf.intr_conf.lsc)
94 return;
95
96 if (nix_wait_for_link_cfg(dev)) {
97 plt_err("Timeout waiting for link_cfg to complete");
98 return;
99 }
100
101 eth_link.link_status = link->status;
102 eth_link.link_speed = link->speed;
103 eth_link.link_autoneg = RTE_ETH_LINK_AUTONEG;
104 eth_link.link_duplex = link->full_duplex;
105
106 /* Print link info */
107 nix_link_status_print(eth_dev, ð_link);
108
109 /* Update link info */
110 rte_eth_linkstatus_set(eth_dev, ð_link);
111
112 /* Set the flag and execute application callbacks */
113 rte_eth_dev_callback_process(eth_dev, RTE_ETH_EVENT_INTR_LSC, NULL);
114 }
115
116 int
cnxk_nix_link_update(struct rte_eth_dev * eth_dev,int wait_to_complete)117 cnxk_nix_link_update(struct rte_eth_dev *eth_dev, int wait_to_complete)
118 {
119 struct cnxk_eth_dev *dev = cnxk_eth_pmd_priv(eth_dev);
120 struct roc_nix_link_info info;
121 struct rte_eth_link link;
122 int rc;
123
124 RTE_SET_USED(wait_to_complete);
125 memset(&link, 0, sizeof(struct rte_eth_link));
126
127 if (!eth_dev->data->dev_started || roc_nix_is_sdp(&dev->nix))
128 return 0;
129
130 if (roc_nix_is_lbk(&dev->nix)) {
131 link.link_status = RTE_ETH_LINK_UP;
132 link.link_speed = RTE_ETH_SPEED_NUM_100G;
133 link.link_autoneg = RTE_ETH_LINK_FIXED;
134 link.link_duplex = RTE_ETH_LINK_FULL_DUPLEX;
135 } else {
136 rc = roc_nix_mac_link_info_get(&dev->nix, &info);
137 if (rc)
138 return rc;
139 link.link_status = info.status;
140 link.link_speed = info.speed;
141 link.link_autoneg = RTE_ETH_LINK_AUTONEG;
142 if (info.full_duplex)
143 link.link_duplex = info.full_duplex;
144 }
145
146 return rte_eth_linkstatus_set(eth_dev, &link);
147 }
148