blob: 83da92d52af624007ce02df96cce7ed91d81b02b [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",
developer2b4a0152023-04-26 16:29:53 +0800429@@ -1029,15 +1215,13 @@ void phylink_start(struct phylink *pl)
developer4e8a3fd2023-04-10 18:05:44 +0800430 /* 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);
developer2b4a0152023-04-26 16:29:53 +0800444+ phylink_resolve_flow(pl, &pl->link_config);
developer4e8a3fd2023-04-10 18:05:44 +0800445+ phylink_mac_initial_config(pl, true);
446
447 clear_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state);
448 phylink_run_resolve(pl);
449@@ -1055,10 +1238,19 @@ void phylink_start(struct phylink *pl)
450 irq = 0;
451 }
452 if (irq <= 0)
453- mod_timer(&pl->link_poll, jiffies + HZ);
454+ poll = true;
455 }
456- if ((pl->cfg_link_an_mode == MLO_AN_FIXED && pl->get_fixed_state) ||
457- (pl->cfg_link_an_mode == MLO_AN_INBAND))
458+
459+ switch (pl->cfg_link_an_mode) {
460+ case MLO_AN_FIXED:
461+ poll |= pl->config->poll_fixed_state;
462+ break;
463+ case MLO_AN_INBAND:
464+ if (pl->pcs)
465+ poll |= pl->pcs->poll;
466+ break;
467+ }
468+ if (poll)
469 mod_timer(&pl->link_poll, jiffies + HZ);
470 if (pl->phydev)
471 phy_start(pl->phydev);
472@@ -1202,7 +1394,7 @@ int phylink_ethtool_ksettings_get(struct phylink *pl,
473 if (pl->phydev)
474 break;
475
476- phylink_get_mac_state(pl, &link_state);
477+ phylink_mac_pcs_get_state(pl, &link_state);
478
479 /* The MAC is reporting the link results from its own PCS
480 * layer via in-band status. Report these as the current
481@@ -1314,7 +1506,7 @@ int phylink_ethtool_ksettings_set(struct phylink *pl,
482 if (pl->cur_link_an_mode == MLO_AN_INBAND &&
483 !test_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state)) {
484 phylink_mac_config(pl, &pl->link_config);
485- phylink_mac_an_restart(pl);
486+ phylink_mac_pcs_an_restart(pl);
487 }
488 mutex_unlock(&pl->state_mutex);
489
490@@ -1341,7 +1533,7 @@ int phylink_ethtool_nway_reset(struct phylink *pl)
491
492 if (pl->phydev)
493 ret = phy_restart_aneg(pl->phydev);
494- phylink_mac_an_restart(pl);
495+ phylink_mac_pcs_an_restart(pl);
496
497 return ret;
498 }
499@@ -1410,7 +1602,7 @@ int phylink_ethtool_set_pauseparam(struct phylink *pl,
500
501 case MLO_AN_INBAND:
502 phylink_mac_config(pl, config);
503- phylink_mac_an_restart(pl);
504+ phylink_mac_pcs_an_restart(pl);
505 break;
506 }
507 }
508@@ -1621,10 +1813,7 @@ static int phylink_mii_read(struct phylink *pl, unsigned int phy_id,
509
510 case MLO_AN_INBAND:
511 if (phy_id == 0) {
512- val = phylink_get_mac_state(pl, &state);
513- if (val < 0)
514- return val;
515-
516+ phylink_mac_pcs_get_state(pl, &state);
517 val = phylink_mii_emul_read(reg, &state);
518 }
519 break;
520diff --git a/include/linux/phylink.h b/include/linux/phylink.h
521index 8229f56..ba0f09d 100644
522--- a/include/linux/phylink.h
523+++ b/include/linux/phylink.h
524@@ -63,17 +63,23 @@ enum phylink_op_type {
525 * struct phylink_config - PHYLINK configuration structure
526 * @dev: a pointer to a struct device associated with the MAC
527 * @type: operation type of PHYLINK instance
528+ * @poll_fixed_state: if true, starts link_poll,
529+ * if MAC link is at %MLO_AN_FIXED mode.
530 */
531 struct phylink_config {
532 struct device *dev;
533 enum phylink_op_type type;
534+ bool poll_fixed_state;
535 };
536
537 /**
538 * struct phylink_mac_ops - MAC operations structure.
539 * @validate: Validate and update the link configuration.
540+ * @mac_select_pcs: Select a PCS for the interface mode.
541 * @mac_link_state: Read the current link state from the hardware.
542+ * @mac_prepare: prepare for a major reconfiguration of the interface.
543 * @mac_config: configure the MAC for the selected mode and state.
544+ * @mac_finish: finish a major reconfiguration of the interface.
545 * @mac_an_restart: restart 802.3z BaseX autonegotiation.
546 * @mac_link_down: take the link down.
547 * @mac_link_up: allow the link to come up.
548@@ -84,10 +90,16 @@ struct phylink_mac_ops {
549 void (*validate)(struct phylink_config *config,
550 unsigned long *supported,
551 struct phylink_link_state *state);
552+ struct phylink_pcs *(*mac_select_pcs)(struct phylink_config *config,
553+ phy_interface_t interface);
554 int (*mac_link_state)(struct phylink_config *config,
555 struct phylink_link_state *state);
556+ int (*mac_prepare)(struct phylink_config *config, unsigned int mode,
557+ phy_interface_t iface);
558 void (*mac_config)(struct phylink_config *config, unsigned int mode,
559 const struct phylink_link_state *state);
560+ int (*mac_finish)(struct phylink_config *config, unsigned int mode,
561+ phy_interface_t iface);
562 void (*mac_an_restart)(struct phylink_config *config);
563 void (*mac_link_down)(struct phylink_config *config, unsigned int mode,
564 phy_interface_t interface);
565@@ -126,6 +138,21 @@ struct phylink_mac_ops {
566 */
567 void validate(struct phylink_config *config, unsigned long *supported,
568 struct phylink_link_state *state);
569+/**
570+ * mac_select_pcs: Select a PCS for the interface mode.
571+ * @config: a pointer to a &struct phylink_config.
572+ * @interface: PHY interface mode for PCS
573+ *
574+ * Return the &struct phylink_pcs for the specified interface mode, or
575+ * NULL if none is required, or an error pointer on error.
576+ *
577+ * This must not modify any state. It is used to query which PCS should
578+ * be used. Phylink will use this during validation to ensure that the
579+ * configuration is valid, and when setting a configuration to internally
580+ * set the PCS that will be used.
581+ */
582+struct phylink_pcs *mac_select_pcs(struct phylink_config *config,
583+ phy_interface_t interface);
584
585 /**
586 * mac_link_state() - Read the current link state from the hardware
587@@ -141,6 +168,31 @@ void validate(struct phylink_config *config, unsigned long *supported,
588 int mac_link_state(struct phylink_config *config,
589 struct phylink_link_state *state);
590
591+/**
592+ * mac_prepare() - prepare to change the PHY interface mode
593+ * @config: a pointer to a &struct phylink_config.
594+ * @mode: one of %MLO_AN_FIXED, %MLO_AN_PHY, %MLO_AN_INBAND.
595+ * @iface: interface mode to switch to
596+ *
597+ * phylink will call this method at the beginning of a full initialisation
598+ * of the link, which includes changing the interface mode or at initial
599+ * startup time. It may be called for the current mode. The MAC driver
600+ * should perform whatever actions are required, e.g. disabling the
601+ * Serdes PHY.
602+ *
603+ * This will be the first call in the sequence:
604+ * - mac_prepare()
605+ * - mac_config()
606+ * - pcs_config()
607+ * - possible pcs_an_restart()
608+ * - mac_finish()
609+ *
610+ * Returns zero on success, or negative errno on failure which will be
611+ * reported to the kernel log.
612+ */
613+int mac_prepare(struct phylink_config *config, unsigned int mode,
614+ phy_interface_t iface);
615+
616 /**
617 * mac_config() - configure the MAC for the selected mode and state
618 * @config: a pointer to a &struct phylink_config.
619@@ -195,6 +247,23 @@ int mac_link_state(struct phylink_config *config,
620 void mac_config(struct phylink_config *config, unsigned int mode,
621 const struct phylink_link_state *state);
622
623+/**
624+ * mac_finish() - finish a to change the PHY interface mode
625+ * @config: a pointer to a &struct phylink_config.
626+ * @mode: one of %MLO_AN_FIXED, %MLO_AN_PHY, %MLO_AN_INBAND.
627+ * @iface: interface mode to switch to
628+ *
629+ * phylink will call this if it called mac_prepare() to allow the MAC to
630+ * complete any necessary steps after the MAC and PCS have been configured
631+ * for the @mode and @iface. E.g. a MAC driver may wish to re-enable the
632+ * Serdes PHY here if it was previously disabled by mac_prepare().
633+ *
634+ * Returns zero on success, or negative errno on failure which will be
635+ * reported to the kernel log.
636+ */
637+int mac_finish(struct phylink_config *config, unsigned int mode,
638+ phy_interface_t iface);
639+
640 /**
641 * mac_an_restart() - restart 802.3z BaseX autonegotiation
642 * @config: a pointer to a &struct phylink_config.
643@@ -248,6 +317,132 @@ void mac_link_up(struct phylink_config *config, struct phy_device *phy,
644 int speed, int duplex, bool tx_pause, bool rx_pause);
645 #endif
646
647+struct phylink_pcs_ops;
648+
649+/**
650+ * struct phylink_pcs - PHYLINK PCS instance
651+ * @ops: a pointer to the &struct phylink_pcs_ops structure
652+ * @poll: poll the PCS for link changes
653+ *
654+ * This structure is designed to be embedded within the PCS private data,
655+ * and will be passed between phylink and the PCS.
656+ */
657+struct phylink_pcs {
658+ const struct phylink_pcs_ops *ops;
659+ bool poll;
660+};
661+
662+/**
663+ * struct phylink_pcs_ops - MAC PCS operations structure.
664+ * @pcs_validate: validate the link configuration.
665+ * @pcs_get_state: read the current MAC PCS link state from the hardware.
666+ * @pcs_config: configure the MAC PCS for the selected mode and state.
667+ * @pcs_an_restart: restart 802.3z BaseX autonegotiation.
668+ * @pcs_link_up: program the PCS for the resolved link configuration
669+ * (where necessary).
670+ */
671+struct phylink_pcs_ops {
672+ int (*pcs_validate)(struct phylink_pcs *pcs, unsigned long *supported,
673+ const struct phylink_link_state *state);
674+ void (*pcs_get_state)(struct phylink_pcs *pcs,
675+ struct phylink_link_state *state);
676+ int (*pcs_config)(struct phylink_pcs *pcs, unsigned int mode,
677+ phy_interface_t interface,
678+ const unsigned long *advertising,
679+ bool permit_pause_to_mac);
680+ void (*pcs_an_restart)(struct phylink_pcs *pcs);
681+ void (*pcs_link_up)(struct phylink_pcs *pcs, unsigned int mode,
682+ phy_interface_t interface, int speed, int duplex);
683+};
684+
685+#if 0 /* For kernel-doc purposes only. */
686+/**
687+ * pcs_validate() - validate the link configuration.
688+ * @pcs: a pointer to a &struct phylink_pcs.
689+ * @supported: ethtool bitmask for supported link modes.
690+ * @state: a const pointer to a &struct phylink_link_state.
691+ *
692+ * Validate the interface mode, and advertising's autoneg bit, removing any
693+ * media ethtool link modes that would not be supportable from the supported
694+ * mask. Phylink will propagate the changes to the advertising mask. See the
695+ * &struct phylink_mac_ops validate() method.
696+ *
697+ * Returns -EINVAL if the interface mode/autoneg mode is not supported.
698+ * Returns non-zero positive if the link state can be supported.
699+ */
700+int pcs_validate(struct phylink_pcs *pcs, unsigned long *supported,
701+ const struct phylink_link_state *state);
702+
703+/**
704+ * pcs_get_state() - Read the current inband link state from the hardware
705+ * @pcs: a pointer to a &struct phylink_pcs.
706+ * @state: a pointer to a &struct phylink_link_state.
707+ *
708+ * Read the current inband link state from the MAC PCS, reporting the
709+ * current speed in @state->speed, duplex mode in @state->duplex, pause
710+ * mode in @state->pause using the %MLO_PAUSE_RX and %MLO_PAUSE_TX bits,
711+ * negotiation completion state in @state->an_complete, and link up state
712+ * in @state->link. If possible, @state->lp_advertising should also be
713+ * populated.
714+ *
715+ * When present, this overrides mac_pcs_get_state() in &struct
716+ * phylink_mac_ops.
717+ */
718+void pcs_get_state(struct phylink_pcs *pcs,
719+ struct phylink_link_state *state);
720+
721+/**
722+ * pcs_config() - Configure the PCS mode and advertisement
723+ * @pcs: a pointer to a &struct phylink_pcs.
724+ * @mode: one of %MLO_AN_FIXED, %MLO_AN_PHY, %MLO_AN_INBAND.
725+ * @interface: interface mode to be used
726+ * @advertising: adertisement ethtool link mode mask
727+ * @permit_pause_to_mac: permit forwarding pause resolution to MAC
728+ *
729+ * Configure the PCS for the operating mode, the interface mode, and set
730+ * the advertisement mask. @permit_pause_to_mac indicates whether the
731+ * hardware may forward the pause mode resolution to the MAC.
732+ *
733+ * When operating in %MLO_AN_INBAND, inband should always be enabled,
734+ * otherwise inband should be disabled.
735+ *
736+ * For SGMII, there is no advertisement from the MAC side, the PCS should
737+ * be programmed to acknowledge the inband word from the PHY.
738+ *
739+ * For 1000BASE-X, the advertisement should be programmed into the PCS.
740+ *
741+ * For most 10GBASE-R, there is no advertisement.
742+ */
743+int pcs_config(struct phylink_pcs *pcs, unsigned int mode,
744+ phy_interface_t interface, const unsigned long *advertising,
745+ bool permit_pause_to_mac);
746+
747+/**
748+ * pcs_an_restart() - restart 802.3z BaseX autonegotiation
749+ * @pcs: a pointer to a &struct phylink_pcs.
750+ *
751+ * When PCS ops are present, this overrides mac_an_restart() in &struct
752+ * phylink_mac_ops.
753+ */
754+void pcs_an_restart(struct phylink_pcs *pcs);
755+
756+/**
757+ * pcs_link_up() - program the PCS for the resolved link configuration
758+ * @pcs: a pointer to a &struct phylink_pcs.
759+ * @mode: link autonegotiation mode
760+ * @interface: link &typedef phy_interface_t mode
761+ * @speed: link speed
762+ * @duplex: link duplex
763+ *
764+ * This call will be made just before mac_link_up() to inform the PCS of
765+ * the resolved link parameters. For example, a PCS operating in SGMII
766+ * mode without in-band AN needs to be manually configured for the link
767+ * and duplex setting. Otherwise, this should be a no-op.
768+ */
769+void pcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
770+ phy_interface_t interface, int speed, int duplex);
771+#endif
772+
773 struct phylink *phylink_create(struct phylink_config *, struct fwnode_handle *,
774 phy_interface_t iface,
775 const struct phylink_mac_ops *ops);