blob: 8f298c399cc956687ce749332935dc99e9698a1a [file] [log] [blame]
developer5d148cb2023-06-02 13:08:11 +08001From 45878f8001b0ad75c5497a999a43b5901c1e03a6 Mon Sep 17 00:00:00 2001
2From: Sam Shih <sam.shih@mediatek.com>
3Date: Fri, 2 Jun 2023 13:06:01 +0800
4Subject: [PATCH]
5 [backport-networking-drivers][999-1710-net-phy-add-phylink-pcs-support.patch]
6
7---
8 drivers/net/phy/phylink.c | 306 ++++++++++++++++++++++++++++++--------
9 include/linux/phylink.h | 195 ++++++++++++++++++++++++
10 2 files changed, 443 insertions(+), 58 deletions(-)
11
developer4e8a3fd2023-04-10 18:05:44 +080012diff --git a/drivers/net/phy/phylink.c b/drivers/net/phy/phylink.c
developer5d148cb2023-06-02 13:08:11 +080013index 67f34ed4c..9c76517ea 100644
developer4e8a3fd2023-04-10 18:05:44 +080014--- a/drivers/net/phy/phylink.c
15+++ b/drivers/net/phy/phylink.c
16@@ -40,8 +40,9 @@ enum {
17 struct phylink {
18 /* private: */
19 struct net_device *netdev;
20- const struct phylink_mac_ops *ops;
21+ const struct phylink_mac_ops *mac_ops;
22 struct phylink_config *config;
23+ struct phylink_pcs *pcs;
24 struct device *dev;
25 unsigned int old_link_state:1;
26
27@@ -70,6 +71,7 @@ struct phylink {
28 struct work_struct resolve;
29
30 bool mac_link_dropped;
31+ bool using_mac_select_pcs;
32
33 struct sfp_bus *sfp_bus;
34 bool sfp_may_have_phy;
35@@ -153,14 +155,60 @@ static const char *phylink_an_mode_str(unsigned int mode)
36 return mode < ARRAY_SIZE(modestr) ? modestr[mode] : "unknown";
37 }
38
39-static int phylink_validate(struct phylink *pl, unsigned long *supported,
40- struct phylink_link_state *state)
41+static int phylink_validate_mac_and_pcs(struct phylink *pl,
42+ unsigned long *supported,
43+ struct phylink_link_state *state)
44 {
45- pl->ops->validate(pl->config, supported, state);
46+ struct phylink_pcs *pcs;
47+ int ret;
48+
49+ /* Get the PCS for this interface mode */
50+ if (pl->using_mac_select_pcs) {
51+ pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface);
52+ if (IS_ERR(pcs))
53+ return PTR_ERR(pcs);
54+ } else {
55+ pcs = pl->pcs;
56+ }
57+
58+ if (pcs) {
59+ /* The PCS, if present, must be setup before phylink_create()
60+ * has been called. If the ops is not initialised, print an
61+ * error and backtrace rather than oopsing the kernel.
62+ */
63+ if (!pcs->ops) {
64+ phylink_err(pl, "interface %s: uninitialised PCS\n",
65+ phy_modes(state->interface));
66+ dump_stack();
67+ return -EINVAL;
68+ }
69+
70+ /* Validate the link parameters with the PCS */
71+ if (pcs->ops->pcs_validate) {
72+ ret = pcs->ops->pcs_validate(pcs, supported, state);
73+ if (ret < 0 || phylink_is_empty_linkmode(supported))
74+ return -EINVAL;
75+
76+ /* Ensure the advertising mask is a subset of the
77+ * supported mask.
78+ */
79+ linkmode_and(state->advertising, state->advertising,
80+ supported);
81+ }
82+ }
83+
84+ /* Then validate the link parameters with the MAC */
85+ pl->mac_ops->validate(pl->config, supported, state);
86
87 return phylink_is_empty_linkmode(supported) ? -EINVAL : 0;
88 }
89
90+static int phylink_validate(struct phylink *pl, unsigned long *supported,
91+ struct phylink_link_state *state)
92+{
93+ return phylink_validate_mac_and_pcs(pl, supported, state);
94+}
95+
96 static int phylink_parse_fixedlink(struct phylink *pl,
97 struct fwnode_handle *fwnode)
98 {
99@@ -338,6 +386,18 @@ static int phylink_parse_mode(struct phylink *pl, struct fwnode_handle *fwnode)
100 return 0;
101 }
102
103+static void phylink_pcs_poll_stop(struct phylink *pl)
104+{
105+ if (pl->cfg_link_an_mode == MLO_AN_INBAND)
106+ del_timer(&pl->link_poll);
107+}
108+
109+static void phylink_pcs_poll_start(struct phylink *pl)
110+{
111+ if (pl->pcs && pl->pcs->poll && pl->cfg_link_an_mode == MLO_AN_INBAND)
112+ mod_timer(&pl->link_poll, jiffies + HZ);
113+}
114+
115 static void phylink_mac_config(struct phylink *pl,
116 const struct phylink_link_state *state)
117 {
118@@ -350,37 +410,113 @@ static void phylink_mac_config(struct phylink *pl,
119 __ETHTOOL_LINK_MODE_MASK_NBITS, state->advertising,
120 state->pause, state->link, state->an_enabled);
121
122- pl->ops->mac_config(pl->config, pl->cur_link_an_mode, state);
123+ pl->mac_ops->mac_config(pl->config, pl->cur_link_an_mode, state);
124 }
125
126-static void phylink_mac_config_up(struct phylink *pl,
127- const struct phylink_link_state *state)
128+static void phylink_mac_pcs_an_restart(struct phylink *pl)
129 {
130- if (state->link)
131- phylink_mac_config(pl, state);
132+ if (pl->link_config.an_enabled &&
133+ phy_interface_mode_is_8023z(pl->link_config.interface) &&
134+ phylink_autoneg_inband(pl->cur_link_an_mode)) {
135+ if (pl->pcs)
136+ pl->pcs->ops->pcs_an_restart(pl->pcs);
137+ else if (pl->mac_ops->mac_an_restart)
138+ pl->mac_ops->mac_an_restart(pl->config);
139+ }
140 }
141
142-static void phylink_mac_an_restart(struct phylink *pl)
143+static void phylink_major_config(struct phylink *pl, bool restart,
144+ const struct phylink_link_state *state)
145 {
146- if (pl->link_config.an_enabled &&
147- phy_interface_mode_is_8023z(pl->link_config.interface))
148- pl->ops->mac_an_restart(pl->config);
149+ struct phylink_pcs *pcs = NULL;
150+ bool pcs_changed = false;
151+ int err;
152+
153+ phylink_dbg(pl, "major config %s\n", phy_modes(state->interface));
154+
155+ if (pl->using_mac_select_pcs) {
156+ pcs = pl->mac_ops->mac_select_pcs(pl->config, state->interface);
157+ if (IS_ERR(pcs)) {
158+ phylink_err(pl,
159+ "mac_select_pcs unexpectedly failed: %pe\n",
160+ pcs);
161+ return;
162+ }
163+
164+ pcs_changed = pcs && pl->pcs != pcs;
165+ }
166+
167+ phylink_pcs_poll_stop(pl);
168+
169+ if (pl->mac_ops->mac_prepare) {
170+ err = pl->mac_ops->mac_prepare(pl->config, pl->cur_link_an_mode,
171+ state->interface);
172+ if (err < 0) {
173+ phylink_err(pl, "mac_prepare failed: %pe\n",
174+ ERR_PTR(err));
175+ return;
176+ }
177+ }
178+
179+ /* If we have a new PCS, switch to the new PCS after preparing the MAC
180+ * for the change.
181+ */
182+ if (pcs_changed)
183+ pl->pcs = pcs;
184+
185+ phylink_mac_config(pl, state);
186+
187+ if (pl->pcs) {
188+ err = pl->pcs->ops->pcs_config(pl->pcs, pl->cur_link_an_mode,
189+ state->interface,
190+ state->advertising,
191+ !!(pl->link_config.pause &
192+ MLO_PAUSE_AN));
193+ if (err < 0)
194+ phylink_err(pl, "pcs_config failed: %pe\n",
195+ ERR_PTR(err));
196+ if (err > 0)
197+ restart = true;
198+ }
199+ if (restart)
200+ phylink_mac_pcs_an_restart(pl);
201+
202+ if (pl->mac_ops->mac_finish) {
203+ err = pl->mac_ops->mac_finish(pl->config, pl->cur_link_an_mode,
204+ state->interface);
205+ if (err < 0)
206+ phylink_err(pl, "mac_finish failed: %pe\n",
207+ ERR_PTR(err));
208+ }
209+
210+ phylink_pcs_poll_start(pl);
211 }
212
213-static int phylink_get_mac_state(struct phylink *pl, struct phylink_link_state *state)
214+static void phylink_mac_pcs_get_state(struct phylink *pl,
215+ struct phylink_link_state *state)
216 {
217-
218 linkmode_copy(state->advertising, pl->link_config.advertising);
219 linkmode_zero(state->lp_advertising);
220 state->interface = pl->link_config.interface;
221 state->an_enabled = pl->link_config.an_enabled;
222- state->speed = SPEED_UNKNOWN;
223- state->duplex = DUPLEX_UNKNOWN;
224- state->pause = MLO_PAUSE_NONE;
225+ if (state->an_enabled) {
226+ state->speed = SPEED_UNKNOWN;
227+ state->duplex = DUPLEX_UNKNOWN;
228+ state->pause = MLO_PAUSE_NONE;
229+ } else {
230+ state->speed = pl->link_config.speed;
231+ state->duplex = pl->link_config.duplex;
232+ state->pause = pl->link_config.pause;
233+ }
234 state->an_complete = 0;
235 state->link = 1;
236
237- return pl->ops->mac_link_state(pl->config, state);
238+ if (pl->pcs)
239+ pl->pcs->ops->pcs_get_state(pl->pcs, state);
240+ else if (pl->mac_ops->mac_link_state)
241+ pl->mac_ops->mac_link_state(pl->config, state);
242+ else
243+ state->link = 0;
244 }
245
246 /* The fixed state is... fixed except for the link state,
247@@ -395,6 +531,34 @@ static void phylink_get_fixed_state(struct phylink *pl, struct phylink_link_stat
248 state->link = !!gpiod_get_value_cansleep(pl->link_gpio);
249 }
250
251+static void phylink_mac_initial_config(struct phylink *pl, bool force_restart)
252+{
253+ struct phylink_link_state link_state;
254+
255+ switch (pl->cur_link_an_mode) {
256+ case MLO_AN_PHY:
257+ link_state = pl->phy_state;
258+ break;
259+
260+ case MLO_AN_FIXED:
261+ phylink_get_fixed_state(pl, &link_state);
262+ break;
263+
264+ case MLO_AN_INBAND:
265+ link_state = pl->link_config;
266+ if (link_state.interface == PHY_INTERFACE_MODE_SGMII)
267+ link_state.pause = MLO_PAUSE_NONE;
268+ break;
269+
270+ default: /* can't happen */
271+ return;
272+ }
273+
274+ link_state.link = false;
275+
276+ phylink_major_config(pl, force_restart, &link_state);
277+}
278+
279 /* Flow control is resolved according to our and the link partners
280 * advertisements using the following drawn from the 802.3 specs:
281 * Local device Link partner
282@@ -445,17 +609,25 @@ static const char *phylink_pause_to_str(int pause)
283 }
284 }
285
286-static void phylink_mac_link_up(struct phylink *pl,
287- struct phylink_link_state link_state)
288+static void phylink_link_up(struct phylink *pl,
289+ struct phylink_link_state link_state)
290 {
291 struct net_device *ndev = pl->netdev;
292+ int speed, duplex;
293+
294+ speed = link_state.speed;
295+ duplex = link_state.duplex;
296
297 pl->cur_interface = link_state.interface;
298- pl->ops->mac_link_up(pl->config, pl->phydev,
299- pl->cur_link_an_mode, pl->cur_interface,
300- link_state.speed, link_state.duplex,
301- !!(link_state.pause & MLO_PAUSE_TX),
302- !!(link_state.pause & MLO_PAUSE_RX));
303+
304+ if (pl->pcs && pl->pcs->ops->pcs_link_up)
305+ pl->pcs->ops->pcs_link_up(pl->pcs, pl->cur_link_an_mode,
306+ pl->cur_interface, speed, duplex);
307+
308+ pl->mac_ops->mac_link_up(pl->config, pl->phydev, pl->cur_link_an_mode,
309+ pl->cur_interface, speed, duplex,
310+ !!(link_state.pause & MLO_PAUSE_TX),
311+ !!(link_state.pause & MLO_PAUSE_RX));
312
313 if (ndev)
314 netif_carrier_on(ndev);
315@@ -467,14 +639,14 @@ static void phylink_mac_link_up(struct phylink *pl,
316 phylink_pause_to_str(link_state.pause));
317 }
318
319-static void phylink_mac_link_down(struct phylink *pl)
320+static void phylink_link_down(struct phylink *pl)
321 {
322 struct net_device *ndev = pl->netdev;
323
324 if (ndev)
325 netif_carrier_off(ndev);
326- pl->ops->mac_link_down(pl->config, pl->cur_link_an_mode,
327- pl->cur_interface);
328+ pl->mac_ops->mac_link_down(pl->config, pl->cur_link_an_mode,
329+ pl->cur_interface);
330 phylink_info(pl, "Link is Down\n");
331 }
332
333@@ -513,7 +685,7 @@ static void phylink_resolve(struct work_struct *w)
334 break;
335
336 case MLO_AN_INBAND:
337- phylink_get_mac_state(pl, &link_state);
338+ phylink_mac_pcs_get_state(pl, &link_state);
339
340 /* The PCS may have a latching link-fail indicator.
341 * If the link was up, bring the link down and
342@@ -524,8 +696,8 @@ static void phylink_resolve(struct work_struct *w)
343 if (cur_link_state)
344 retrigger = true;
345 else
346- phylink_get_mac_state(pl,
347- &link_state);
348+ phylink_mac_pcs_get_state(pl,
349+ &link_state);
350 }
351
352 /* If we have a phy, the "up" state is the union of
353@@ -564,12 +736,17 @@ static void phylink_resolve(struct work_struct *w)
354 * then reconfigure.
355 */
356 if (cur_link_state) {
357- phylink_mac_link_down(pl);
358+ phylink_link_down(pl);
359 cur_link_state = false;
360 }
361- phylink_mac_config(pl, &link_state);
362+ phylink_major_config(pl, false, &link_state);
363 pl->link_config.interface = link_state.interface;
364- } else {
365+ } else if (!pl->pcs) {
366+ /* The interface remains unchanged, only the speed,
367+ * duplex or pause settings have changed. Call the
368+ * old mac_config() method to configure the MAC/PCS
369+ * only if we do not have a legacy MAC driver.
370+ */
371 phylink_mac_config(pl, &link_state);
372 }
373 }
374@@ -577,9 +754,9 @@ static void phylink_resolve(struct work_struct *w)
375 if (link_state.link != cur_link_state) {
376 pl->old_link_state = link_state.link;
377 if (!link_state.link)
378- phylink_mac_link_down(pl);
379+ phylink_link_down(pl);
380 else
381- phylink_mac_link_up(pl, link_state);
382+ phylink_link_up(pl, link_state);
383 }
384 if (!link_state.link && retrigger) {
385 pl->mac_link_dropped = false;
386@@ -643,7 +820,7 @@ static int phylink_register_sfp(struct phylink *pl,
387 * @fwnode: a pointer to a &struct fwnode_handle describing the network
388 * interface
389 * @iface: the desired link mode defined by &typedef phy_interface_t
390- * @ops: a pointer to a &struct phylink_mac_ops for the MAC.
391+ * @mac_ops: a pointer to a &struct phylink_mac_ops for the MAC.
392 *
393 * Create a new phylink instance, and parse the link parameters found in @np.
394 * This will parse in-band modes, fixed-link or SFP configuration.
395@@ -656,11 +833,17 @@ static int phylink_register_sfp(struct phylink *pl,
396 struct phylink *phylink_create(struct phylink_config *config,
397 struct fwnode_handle *fwnode,
398 phy_interface_t iface,
399- const struct phylink_mac_ops *ops)
400+ const struct phylink_mac_ops *mac_ops)
401 {
402+ bool using_mac_select_pcs = false;
403 struct phylink *pl;
404 int ret;
405
406+ if (mac_ops->mac_select_pcs &&
407+ mac_ops->mac_select_pcs(config, PHY_INTERFACE_MODE_NA) !=
408+ ERR_PTR(-EOPNOTSUPP))
409+ using_mac_select_pcs = true;
410+
411 pl = kzalloc(sizeof(*pl), GFP_KERNEL);
412 if (!pl)
413 return ERR_PTR(-ENOMEM);
414@@ -678,6 +861,7 @@ struct phylink *phylink_create(struct phylink_config *config,
415 return ERR_PTR(-EINVAL);
416 }
417
418+ pl->using_mac_select_pcs = using_mac_select_pcs;
419 pl->phy_state.interface = iface;
420 pl->link_interface = iface;
421 if (iface == PHY_INTERFACE_MODE_MOCA)
422@@ -689,7 +873,7 @@ struct phylink *phylink_create(struct phylink_config *config,
423 pl->link_config.speed = SPEED_UNKNOWN;
424 pl->link_config.duplex = DUPLEX_UNKNOWN;
425 pl->link_config.an_enabled = true;
426- pl->ops = ops;
427+ pl->mac_ops = mac_ops;
428 __set_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state);
429 timer_setup(&pl->link_poll, phylink_fixed_poll, 0);
430
431@@ -1016,6 +1200,8 @@ static irqreturn_t phylink_link_handler(int irq, void *data)
432 */
433 void phylink_start(struct phylink *pl)
434 {
435+ bool poll = false;
436+
437 ASSERT_RTNL();
438
439 phylink_info(pl, "configuring for %s/%s link mode\n",
developer2b4a0152023-04-26 16:29:53 +0800440@@ -1029,15 +1215,13 @@ void phylink_start(struct phylink *pl)
developer4e8a3fd2023-04-10 18:05:44 +0800441 /* Apply the link configuration to the MAC when starting. This allows
442 * a fixed-link to start with the correct parameters, and also
443 * ensures that we set the appropriate advertisement for Serdes links.
444- */
445- phylink_resolve_flow(pl, &pl->link_config);
446- phylink_mac_config(pl, &pl->link_config);
447-
448- /* Restart autonegotiation if using 802.3z to ensure that the link
449+ *
450+ * Restart autonegotiation if using 802.3z to ensure that the link
451 * parameters are properly negotiated. This is necessary for DSA
452 * switches using 802.3z negotiation to ensure they see our modes.
453 */
454- phylink_mac_an_restart(pl);
developer2b4a0152023-04-26 16:29:53 +0800455+ phylink_resolve_flow(pl, &pl->link_config);
developer4e8a3fd2023-04-10 18:05:44 +0800456+ phylink_mac_initial_config(pl, true);
457
458 clear_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state);
459 phylink_run_resolve(pl);
developer5d148cb2023-06-02 13:08:11 +0800460@@ -1055,10 +1239,19 @@ void phylink_start(struct phylink *pl)
developer4e8a3fd2023-04-10 18:05:44 +0800461 irq = 0;
462 }
463 if (irq <= 0)
464- mod_timer(&pl->link_poll, jiffies + HZ);
465+ poll = true;
466 }
467- if ((pl->cfg_link_an_mode == MLO_AN_FIXED && pl->get_fixed_state) ||
468- (pl->cfg_link_an_mode == MLO_AN_INBAND))
469+
470+ switch (pl->cfg_link_an_mode) {
471+ case MLO_AN_FIXED:
472+ poll |= pl->config->poll_fixed_state;
473+ break;
474+ case MLO_AN_INBAND:
475+ if (pl->pcs)
476+ poll |= pl->pcs->poll;
477+ break;
478+ }
479+ if (poll)
480 mod_timer(&pl->link_poll, jiffies + HZ);
481 if (pl->phydev)
482 phy_start(pl->phydev);
developer5d148cb2023-06-02 13:08:11 +0800483@@ -1202,7 +1395,7 @@ int phylink_ethtool_ksettings_get(struct phylink *pl,
developer4e8a3fd2023-04-10 18:05:44 +0800484 if (pl->phydev)
485 break;
486
487- phylink_get_mac_state(pl, &link_state);
488+ phylink_mac_pcs_get_state(pl, &link_state);
489
490 /* The MAC is reporting the link results from its own PCS
491 * layer via in-band status. Report these as the current
developer5d148cb2023-06-02 13:08:11 +0800492@@ -1314,7 +1507,7 @@ int phylink_ethtool_ksettings_set(struct phylink *pl,
developer4e8a3fd2023-04-10 18:05:44 +0800493 if (pl->cur_link_an_mode == MLO_AN_INBAND &&
494 !test_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state)) {
495 phylink_mac_config(pl, &pl->link_config);
496- phylink_mac_an_restart(pl);
497+ phylink_mac_pcs_an_restart(pl);
498 }
499 mutex_unlock(&pl->state_mutex);
500
developer5d148cb2023-06-02 13:08:11 +0800501@@ -1341,7 +1534,7 @@ int phylink_ethtool_nway_reset(struct phylink *pl)
developer4e8a3fd2023-04-10 18:05:44 +0800502
503 if (pl->phydev)
504 ret = phy_restart_aneg(pl->phydev);
505- phylink_mac_an_restart(pl);
506+ phylink_mac_pcs_an_restart(pl);
507
508 return ret;
509 }
developer5d148cb2023-06-02 13:08:11 +0800510@@ -1410,7 +1603,7 @@ int phylink_ethtool_set_pauseparam(struct phylink *pl,
developer4e8a3fd2023-04-10 18:05:44 +0800511
512 case MLO_AN_INBAND:
513 phylink_mac_config(pl, config);
514- phylink_mac_an_restart(pl);
515+ phylink_mac_pcs_an_restart(pl);
516 break;
517 }
518 }
developer5d148cb2023-06-02 13:08:11 +0800519@@ -1621,10 +1814,7 @@ static int phylink_mii_read(struct phylink *pl, unsigned int phy_id,
developer4e8a3fd2023-04-10 18:05:44 +0800520
521 case MLO_AN_INBAND:
522 if (phy_id == 0) {
523- val = phylink_get_mac_state(pl, &state);
524- if (val < 0)
525- return val;
526-
527+ phylink_mac_pcs_get_state(pl, &state);
528 val = phylink_mii_emul_read(reg, &state);
529 }
530 break;
developer5d148cb2023-06-02 13:08:11 +0800531@@ -1820,7 +2010,7 @@ static int phylink_sfp_config(struct phylink *pl, u8 mode,
developer8900c0a2023-05-09 10:37:33 +0800532
533 if (changed && !test_bit(PHYLINK_DISABLE_STOPPED,
534 &pl->phylink_disable_state))
535- phylink_mac_config(pl, &pl->link_config);
536+ phylink_mac_initial_config(pl, false);
537
538 return ret;
539 }
developer4e8a3fd2023-04-10 18:05:44 +0800540diff --git a/include/linux/phylink.h b/include/linux/phylink.h
developer5d148cb2023-06-02 13:08:11 +0800541index 8229f56a1..ba0f09d02 100644
developer4e8a3fd2023-04-10 18:05:44 +0800542--- a/include/linux/phylink.h
543+++ b/include/linux/phylink.h
544@@ -63,17 +63,23 @@ enum phylink_op_type {
545 * struct phylink_config - PHYLINK configuration structure
546 * @dev: a pointer to a struct device associated with the MAC
547 * @type: operation type of PHYLINK instance
548+ * @poll_fixed_state: if true, starts link_poll,
549+ * if MAC link is at %MLO_AN_FIXED mode.
550 */
551 struct phylink_config {
552 struct device *dev;
553 enum phylink_op_type type;
554+ bool poll_fixed_state;
555 };
556
557 /**
558 * struct phylink_mac_ops - MAC operations structure.
559 * @validate: Validate and update the link configuration.
560+ * @mac_select_pcs: Select a PCS for the interface mode.
561 * @mac_link_state: Read the current link state from the hardware.
562+ * @mac_prepare: prepare for a major reconfiguration of the interface.
563 * @mac_config: configure the MAC for the selected mode and state.
564+ * @mac_finish: finish a major reconfiguration of the interface.
565 * @mac_an_restart: restart 802.3z BaseX autonegotiation.
566 * @mac_link_down: take the link down.
567 * @mac_link_up: allow the link to come up.
568@@ -84,10 +90,16 @@ struct phylink_mac_ops {
569 void (*validate)(struct phylink_config *config,
570 unsigned long *supported,
571 struct phylink_link_state *state);
572+ struct phylink_pcs *(*mac_select_pcs)(struct phylink_config *config,
573+ phy_interface_t interface);
574 int (*mac_link_state)(struct phylink_config *config,
575 struct phylink_link_state *state);
576+ int (*mac_prepare)(struct phylink_config *config, unsigned int mode,
577+ phy_interface_t iface);
578 void (*mac_config)(struct phylink_config *config, unsigned int mode,
579 const struct phylink_link_state *state);
580+ int (*mac_finish)(struct phylink_config *config, unsigned int mode,
581+ phy_interface_t iface);
582 void (*mac_an_restart)(struct phylink_config *config);
583 void (*mac_link_down)(struct phylink_config *config, unsigned int mode,
584 phy_interface_t interface);
585@@ -126,6 +138,21 @@ struct phylink_mac_ops {
586 */
587 void validate(struct phylink_config *config, unsigned long *supported,
588 struct phylink_link_state *state);
589+/**
590+ * mac_select_pcs: Select a PCS for the interface mode.
591+ * @config: a pointer to a &struct phylink_config.
592+ * @interface: PHY interface mode for PCS
593+ *
594+ * Return the &struct phylink_pcs for the specified interface mode, or
595+ * NULL if none is required, or an error pointer on error.
596+ *
597+ * This must not modify any state. It is used to query which PCS should
598+ * be used. Phylink will use this during validation to ensure that the
599+ * configuration is valid, and when setting a configuration to internally
600+ * set the PCS that will be used.
601+ */
602+struct phylink_pcs *mac_select_pcs(struct phylink_config *config,
603+ phy_interface_t interface);
604
605 /**
606 * mac_link_state() - Read the current link state from the hardware
607@@ -141,6 +168,31 @@ void validate(struct phylink_config *config, unsigned long *supported,
608 int mac_link_state(struct phylink_config *config,
609 struct phylink_link_state *state);
610
611+/**
612+ * mac_prepare() - prepare to change the PHY interface mode
613+ * @config: a pointer to a &struct phylink_config.
614+ * @mode: one of %MLO_AN_FIXED, %MLO_AN_PHY, %MLO_AN_INBAND.
615+ * @iface: interface mode to switch to
616+ *
617+ * phylink will call this method at the beginning of a full initialisation
618+ * of the link, which includes changing the interface mode or at initial
619+ * startup time. It may be called for the current mode. The MAC driver
620+ * should perform whatever actions are required, e.g. disabling the
621+ * Serdes PHY.
622+ *
623+ * This will be the first call in the sequence:
624+ * - mac_prepare()
625+ * - mac_config()
626+ * - pcs_config()
627+ * - possible pcs_an_restart()
628+ * - mac_finish()
629+ *
630+ * Returns zero on success, or negative errno on failure which will be
631+ * reported to the kernel log.
632+ */
633+int mac_prepare(struct phylink_config *config, unsigned int mode,
634+ phy_interface_t iface);
635+
636 /**
637 * mac_config() - configure the MAC for the selected mode and state
638 * @config: a pointer to a &struct phylink_config.
639@@ -195,6 +247,23 @@ int mac_link_state(struct phylink_config *config,
640 void mac_config(struct phylink_config *config, unsigned int mode,
641 const struct phylink_link_state *state);
642
643+/**
644+ * mac_finish() - finish a to change the PHY interface mode
645+ * @config: a pointer to a &struct phylink_config.
646+ * @mode: one of %MLO_AN_FIXED, %MLO_AN_PHY, %MLO_AN_INBAND.
647+ * @iface: interface mode to switch to
648+ *
649+ * phylink will call this if it called mac_prepare() to allow the MAC to
650+ * complete any necessary steps after the MAC and PCS have been configured
651+ * for the @mode and @iface. E.g. a MAC driver may wish to re-enable the
652+ * Serdes PHY here if it was previously disabled by mac_prepare().
653+ *
654+ * Returns zero on success, or negative errno on failure which will be
655+ * reported to the kernel log.
656+ */
657+int mac_finish(struct phylink_config *config, unsigned int mode,
658+ phy_interface_t iface);
659+
660 /**
661 * mac_an_restart() - restart 802.3z BaseX autonegotiation
662 * @config: a pointer to a &struct phylink_config.
663@@ -248,6 +317,132 @@ void mac_link_up(struct phylink_config *config, struct phy_device *phy,
664 int speed, int duplex, bool tx_pause, bool rx_pause);
665 #endif
666
667+struct phylink_pcs_ops;
668+
669+/**
670+ * struct phylink_pcs - PHYLINK PCS instance
671+ * @ops: a pointer to the &struct phylink_pcs_ops structure
672+ * @poll: poll the PCS for link changes
673+ *
674+ * This structure is designed to be embedded within the PCS private data,
675+ * and will be passed between phylink and the PCS.
676+ */
677+struct phylink_pcs {
678+ const struct phylink_pcs_ops *ops;
679+ bool poll;
680+};
681+
682+/**
683+ * struct phylink_pcs_ops - MAC PCS operations structure.
684+ * @pcs_validate: validate the link configuration.
685+ * @pcs_get_state: read the current MAC PCS link state from the hardware.
686+ * @pcs_config: configure the MAC PCS for the selected mode and state.
687+ * @pcs_an_restart: restart 802.3z BaseX autonegotiation.
688+ * @pcs_link_up: program the PCS for the resolved link configuration
689+ * (where necessary).
690+ */
691+struct phylink_pcs_ops {
692+ int (*pcs_validate)(struct phylink_pcs *pcs, unsigned long *supported,
693+ const struct phylink_link_state *state);
694+ void (*pcs_get_state)(struct phylink_pcs *pcs,
695+ struct phylink_link_state *state);
696+ int (*pcs_config)(struct phylink_pcs *pcs, unsigned int mode,
697+ phy_interface_t interface,
698+ const unsigned long *advertising,
699+ bool permit_pause_to_mac);
700+ void (*pcs_an_restart)(struct phylink_pcs *pcs);
701+ void (*pcs_link_up)(struct phylink_pcs *pcs, unsigned int mode,
702+ phy_interface_t interface, int speed, int duplex);
703+};
704+
705+#if 0 /* For kernel-doc purposes only. */
706+/**
707+ * pcs_validate() - validate the link configuration.
708+ * @pcs: a pointer to a &struct phylink_pcs.
709+ * @supported: ethtool bitmask for supported link modes.
710+ * @state: a const pointer to a &struct phylink_link_state.
711+ *
712+ * Validate the interface mode, and advertising's autoneg bit, removing any
713+ * media ethtool link modes that would not be supportable from the supported
714+ * mask. Phylink will propagate the changes to the advertising mask. See the
715+ * &struct phylink_mac_ops validate() method.
716+ *
717+ * Returns -EINVAL if the interface mode/autoneg mode is not supported.
718+ * Returns non-zero positive if the link state can be supported.
719+ */
720+int pcs_validate(struct phylink_pcs *pcs, unsigned long *supported,
721+ const struct phylink_link_state *state);
722+
723+/**
724+ * pcs_get_state() - Read the current inband link state from the hardware
725+ * @pcs: a pointer to a &struct phylink_pcs.
726+ * @state: a pointer to a &struct phylink_link_state.
727+ *
728+ * Read the current inband link state from the MAC PCS, reporting the
729+ * current speed in @state->speed, duplex mode in @state->duplex, pause
730+ * mode in @state->pause using the %MLO_PAUSE_RX and %MLO_PAUSE_TX bits,
731+ * negotiation completion state in @state->an_complete, and link up state
732+ * in @state->link. If possible, @state->lp_advertising should also be
733+ * populated.
734+ *
735+ * When present, this overrides mac_pcs_get_state() in &struct
736+ * phylink_mac_ops.
737+ */
738+void pcs_get_state(struct phylink_pcs *pcs,
739+ struct phylink_link_state *state);
740+
741+/**
742+ * pcs_config() - Configure the PCS mode and advertisement
743+ * @pcs: a pointer to a &struct phylink_pcs.
744+ * @mode: one of %MLO_AN_FIXED, %MLO_AN_PHY, %MLO_AN_INBAND.
745+ * @interface: interface mode to be used
746+ * @advertising: adertisement ethtool link mode mask
747+ * @permit_pause_to_mac: permit forwarding pause resolution to MAC
748+ *
749+ * Configure the PCS for the operating mode, the interface mode, and set
750+ * the advertisement mask. @permit_pause_to_mac indicates whether the
751+ * hardware may forward the pause mode resolution to the MAC.
752+ *
753+ * When operating in %MLO_AN_INBAND, inband should always be enabled,
754+ * otherwise inband should be disabled.
755+ *
756+ * For SGMII, there is no advertisement from the MAC side, the PCS should
757+ * be programmed to acknowledge the inband word from the PHY.
758+ *
759+ * For 1000BASE-X, the advertisement should be programmed into the PCS.
760+ *
761+ * For most 10GBASE-R, there is no advertisement.
762+ */
763+int pcs_config(struct phylink_pcs *pcs, unsigned int mode,
764+ phy_interface_t interface, const unsigned long *advertising,
765+ bool permit_pause_to_mac);
766+
767+/**
768+ * pcs_an_restart() - restart 802.3z BaseX autonegotiation
769+ * @pcs: a pointer to a &struct phylink_pcs.
770+ *
771+ * When PCS ops are present, this overrides mac_an_restart() in &struct
772+ * phylink_mac_ops.
773+ */
774+void pcs_an_restart(struct phylink_pcs *pcs);
775+
776+/**
777+ * pcs_link_up() - program the PCS for the resolved link configuration
778+ * @pcs: a pointer to a &struct phylink_pcs.
779+ * @mode: link autonegotiation mode
780+ * @interface: link &typedef phy_interface_t mode
781+ * @speed: link speed
782+ * @duplex: link duplex
783+ *
784+ * This call will be made just before mac_link_up() to inform the PCS of
785+ * the resolved link parameters. For example, a PCS operating in SGMII
786+ * mode without in-band AN needs to be manually configured for the link
787+ * and duplex setting. Otherwise, this should be a no-op.
788+ */
789+void pcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
790+ phy_interface_t interface, int speed, int duplex);
791+#endif
792+
793 struct phylink *phylink_create(struct phylink_config *, struct fwnode_handle *,
794 phy_interface_t iface,
795 const struct phylink_mac_ops *ops);
developer5d148cb2023-06-02 13:08:11 +0800796--
7972.34.1
798