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