blob: 99e41416d791d75d4bb24c703f030fb880bee73d [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;
developer8900c0a2023-05-09 10:37:33 +0800520@@ -2010,7 +2010,7 @@ static int phylink_sfp_config(struct phylink *pl, u8 mode,
521
522 if (changed && !test_bit(PHYLINK_DISABLE_STOPPED,
523 &pl->phylink_disable_state))
524- phylink_mac_config(pl, &pl->link_config);
525+ phylink_mac_initial_config(pl, false);
526
527 return ret;
528 }
developer4e8a3fd2023-04-10 18:05:44 +0800529diff --git a/include/linux/phylink.h b/include/linux/phylink.h
530index 8229f56..ba0f09d 100644
531--- a/include/linux/phylink.h
532+++ b/include/linux/phylink.h
533@@ -63,17 +63,23 @@ enum phylink_op_type {
534 * struct phylink_config - PHYLINK configuration structure
535 * @dev: a pointer to a struct device associated with the MAC
536 * @type: operation type of PHYLINK instance
537+ * @poll_fixed_state: if true, starts link_poll,
538+ * if MAC link is at %MLO_AN_FIXED mode.
539 */
540 struct phylink_config {
541 struct device *dev;
542 enum phylink_op_type type;
543+ bool poll_fixed_state;
544 };
545
546 /**
547 * struct phylink_mac_ops - MAC operations structure.
548 * @validate: Validate and update the link configuration.
549+ * @mac_select_pcs: Select a PCS for the interface mode.
550 * @mac_link_state: Read the current link state from the hardware.
551+ * @mac_prepare: prepare for a major reconfiguration of the interface.
552 * @mac_config: configure the MAC for the selected mode and state.
553+ * @mac_finish: finish a major reconfiguration of the interface.
554 * @mac_an_restart: restart 802.3z BaseX autonegotiation.
555 * @mac_link_down: take the link down.
556 * @mac_link_up: allow the link to come up.
557@@ -84,10 +90,16 @@ struct phylink_mac_ops {
558 void (*validate)(struct phylink_config *config,
559 unsigned long *supported,
560 struct phylink_link_state *state);
561+ struct phylink_pcs *(*mac_select_pcs)(struct phylink_config *config,
562+ phy_interface_t interface);
563 int (*mac_link_state)(struct phylink_config *config,
564 struct phylink_link_state *state);
565+ int (*mac_prepare)(struct phylink_config *config, unsigned int mode,
566+ phy_interface_t iface);
567 void (*mac_config)(struct phylink_config *config, unsigned int mode,
568 const struct phylink_link_state *state);
569+ int (*mac_finish)(struct phylink_config *config, unsigned int mode,
570+ phy_interface_t iface);
571 void (*mac_an_restart)(struct phylink_config *config);
572 void (*mac_link_down)(struct phylink_config *config, unsigned int mode,
573 phy_interface_t interface);
574@@ -126,6 +138,21 @@ struct phylink_mac_ops {
575 */
576 void validate(struct phylink_config *config, unsigned long *supported,
577 struct phylink_link_state *state);
578+/**
579+ * mac_select_pcs: Select a PCS for the interface mode.
580+ * @config: a pointer to a &struct phylink_config.
581+ * @interface: PHY interface mode for PCS
582+ *
583+ * Return the &struct phylink_pcs for the specified interface mode, or
584+ * NULL if none is required, or an error pointer on error.
585+ *
586+ * This must not modify any state. It is used to query which PCS should
587+ * be used. Phylink will use this during validation to ensure that the
588+ * configuration is valid, and when setting a configuration to internally
589+ * set the PCS that will be used.
590+ */
591+struct phylink_pcs *mac_select_pcs(struct phylink_config *config,
592+ phy_interface_t interface);
593
594 /**
595 * mac_link_state() - Read the current link state from the hardware
596@@ -141,6 +168,31 @@ void validate(struct phylink_config *config, unsigned long *supported,
597 int mac_link_state(struct phylink_config *config,
598 struct phylink_link_state *state);
599
600+/**
601+ * mac_prepare() - prepare to change the PHY interface mode
602+ * @config: a pointer to a &struct phylink_config.
603+ * @mode: one of %MLO_AN_FIXED, %MLO_AN_PHY, %MLO_AN_INBAND.
604+ * @iface: interface mode to switch to
605+ *
606+ * phylink will call this method at the beginning of a full initialisation
607+ * of the link, which includes changing the interface mode or at initial
608+ * startup time. It may be called for the current mode. The MAC driver
609+ * should perform whatever actions are required, e.g. disabling the
610+ * Serdes PHY.
611+ *
612+ * This will be the first call in the sequence:
613+ * - mac_prepare()
614+ * - mac_config()
615+ * - pcs_config()
616+ * - possible pcs_an_restart()
617+ * - mac_finish()
618+ *
619+ * Returns zero on success, or negative errno on failure which will be
620+ * reported to the kernel log.
621+ */
622+int mac_prepare(struct phylink_config *config, unsigned int mode,
623+ phy_interface_t iface);
624+
625 /**
626 * mac_config() - configure the MAC for the selected mode and state
627 * @config: a pointer to a &struct phylink_config.
628@@ -195,6 +247,23 @@ int mac_link_state(struct phylink_config *config,
629 void mac_config(struct phylink_config *config, unsigned int mode,
630 const struct phylink_link_state *state);
631
632+/**
633+ * mac_finish() - finish a to change the PHY interface mode
634+ * @config: a pointer to a &struct phylink_config.
635+ * @mode: one of %MLO_AN_FIXED, %MLO_AN_PHY, %MLO_AN_INBAND.
636+ * @iface: interface mode to switch to
637+ *
638+ * phylink will call this if it called mac_prepare() to allow the MAC to
639+ * complete any necessary steps after the MAC and PCS have been configured
640+ * for the @mode and @iface. E.g. a MAC driver may wish to re-enable the
641+ * Serdes PHY here if it was previously disabled by mac_prepare().
642+ *
643+ * Returns zero on success, or negative errno on failure which will be
644+ * reported to the kernel log.
645+ */
646+int mac_finish(struct phylink_config *config, unsigned int mode,
647+ phy_interface_t iface);
648+
649 /**
650 * mac_an_restart() - restart 802.3z BaseX autonegotiation
651 * @config: a pointer to a &struct phylink_config.
652@@ -248,6 +317,132 @@ void mac_link_up(struct phylink_config *config, struct phy_device *phy,
653 int speed, int duplex, bool tx_pause, bool rx_pause);
654 #endif
655
656+struct phylink_pcs_ops;
657+
658+/**
659+ * struct phylink_pcs - PHYLINK PCS instance
660+ * @ops: a pointer to the &struct phylink_pcs_ops structure
661+ * @poll: poll the PCS for link changes
662+ *
663+ * This structure is designed to be embedded within the PCS private data,
664+ * and will be passed between phylink and the PCS.
665+ */
666+struct phylink_pcs {
667+ const struct phylink_pcs_ops *ops;
668+ bool poll;
669+};
670+
671+/**
672+ * struct phylink_pcs_ops - MAC PCS operations structure.
673+ * @pcs_validate: validate the link configuration.
674+ * @pcs_get_state: read the current MAC PCS link state from the hardware.
675+ * @pcs_config: configure the MAC PCS for the selected mode and state.
676+ * @pcs_an_restart: restart 802.3z BaseX autonegotiation.
677+ * @pcs_link_up: program the PCS for the resolved link configuration
678+ * (where necessary).
679+ */
680+struct phylink_pcs_ops {
681+ int (*pcs_validate)(struct phylink_pcs *pcs, unsigned long *supported,
682+ const struct phylink_link_state *state);
683+ void (*pcs_get_state)(struct phylink_pcs *pcs,
684+ struct phylink_link_state *state);
685+ int (*pcs_config)(struct phylink_pcs *pcs, unsigned int mode,
686+ phy_interface_t interface,
687+ const unsigned long *advertising,
688+ bool permit_pause_to_mac);
689+ void (*pcs_an_restart)(struct phylink_pcs *pcs);
690+ void (*pcs_link_up)(struct phylink_pcs *pcs, unsigned int mode,
691+ phy_interface_t interface, int speed, int duplex);
692+};
693+
694+#if 0 /* For kernel-doc purposes only. */
695+/**
696+ * pcs_validate() - validate the link configuration.
697+ * @pcs: a pointer to a &struct phylink_pcs.
698+ * @supported: ethtool bitmask for supported link modes.
699+ * @state: a const pointer to a &struct phylink_link_state.
700+ *
701+ * Validate the interface mode, and advertising's autoneg bit, removing any
702+ * media ethtool link modes that would not be supportable from the supported
703+ * mask. Phylink will propagate the changes to the advertising mask. See the
704+ * &struct phylink_mac_ops validate() method.
705+ *
706+ * Returns -EINVAL if the interface mode/autoneg mode is not supported.
707+ * Returns non-zero positive if the link state can be supported.
708+ */
709+int pcs_validate(struct phylink_pcs *pcs, unsigned long *supported,
710+ const struct phylink_link_state *state);
711+
712+/**
713+ * pcs_get_state() - Read the current inband link state from the hardware
714+ * @pcs: a pointer to a &struct phylink_pcs.
715+ * @state: a pointer to a &struct phylink_link_state.
716+ *
717+ * Read the current inband link state from the MAC PCS, reporting the
718+ * current speed in @state->speed, duplex mode in @state->duplex, pause
719+ * mode in @state->pause using the %MLO_PAUSE_RX and %MLO_PAUSE_TX bits,
720+ * negotiation completion state in @state->an_complete, and link up state
721+ * in @state->link. If possible, @state->lp_advertising should also be
722+ * populated.
723+ *
724+ * When present, this overrides mac_pcs_get_state() in &struct
725+ * phylink_mac_ops.
726+ */
727+void pcs_get_state(struct phylink_pcs *pcs,
728+ struct phylink_link_state *state);
729+
730+/**
731+ * pcs_config() - Configure the PCS mode and advertisement
732+ * @pcs: a pointer to a &struct phylink_pcs.
733+ * @mode: one of %MLO_AN_FIXED, %MLO_AN_PHY, %MLO_AN_INBAND.
734+ * @interface: interface mode to be used
735+ * @advertising: adertisement ethtool link mode mask
736+ * @permit_pause_to_mac: permit forwarding pause resolution to MAC
737+ *
738+ * Configure the PCS for the operating mode, the interface mode, and set
739+ * the advertisement mask. @permit_pause_to_mac indicates whether the
740+ * hardware may forward the pause mode resolution to the MAC.
741+ *
742+ * When operating in %MLO_AN_INBAND, inband should always be enabled,
743+ * otherwise inband should be disabled.
744+ *
745+ * For SGMII, there is no advertisement from the MAC side, the PCS should
746+ * be programmed to acknowledge the inband word from the PHY.
747+ *
748+ * For 1000BASE-X, the advertisement should be programmed into the PCS.
749+ *
750+ * For most 10GBASE-R, there is no advertisement.
751+ */
752+int pcs_config(struct phylink_pcs *pcs, unsigned int mode,
753+ phy_interface_t interface, const unsigned long *advertising,
754+ bool permit_pause_to_mac);
755+
756+/**
757+ * pcs_an_restart() - restart 802.3z BaseX autonegotiation
758+ * @pcs: a pointer to a &struct phylink_pcs.
759+ *
760+ * When PCS ops are present, this overrides mac_an_restart() in &struct
761+ * phylink_mac_ops.
762+ */
763+void pcs_an_restart(struct phylink_pcs *pcs);
764+
765+/**
766+ * pcs_link_up() - program the PCS for the resolved link configuration
767+ * @pcs: a pointer to a &struct phylink_pcs.
768+ * @mode: link autonegotiation mode
769+ * @interface: link &typedef phy_interface_t mode
770+ * @speed: link speed
771+ * @duplex: link duplex
772+ *
773+ * This call will be made just before mac_link_up() to inform the PCS of
774+ * the resolved link parameters. For example, a PCS operating in SGMII
775+ * mode without in-band AN needs to be manually configured for the link
776+ * and duplex setting. Otherwise, this should be a no-op.
777+ */
778+void pcs_link_up(struct phylink_pcs *pcs, unsigned int mode,
779+ phy_interface_t interface, int speed, int duplex);
780+#endif
781+
782 struct phylink *phylink_create(struct phylink_config *, struct fwnode_handle *,
783 phy_interface_t iface,
784 const struct phylink_mac_ops *ops);