1457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2ce0aa27fSRussell King #include <linux/export.h>
3ce0aa27fSRussell King #include <linux/kref.h>
4ce0aa27fSRussell King #include <linux/list.h>
5ce0aa27fSRussell King #include <linux/mutex.h>
6ce0aa27fSRussell King #include <linux/phylink.h>
72203cbf2SRussell King #include <linux/property.h>
8ce0aa27fSRussell King #include <linux/rtnetlink.h>
9ce0aa27fSRussell King #include <linux/slab.h>
10ce0aa27fSRussell King
11ce0aa27fSRussell King #include "sfp.h"
12ce0aa27fSRussell King
130a6fcd3fSRussell King /**
140a6fcd3fSRussell King * struct sfp_bus - internal representation of a sfp bus
150a6fcd3fSRussell King */
16ce0aa27fSRussell King struct sfp_bus {
170a6fcd3fSRussell King /* private: */
18ce0aa27fSRussell King struct kref kref;
19ce0aa27fSRussell King struct list_head node;
20850a8d2dSRussell King (Oracle) const struct fwnode_handle *fwnode;
21ce0aa27fSRussell King
22ce0aa27fSRussell King const struct sfp_socket_ops *socket_ops;
23ce0aa27fSRussell King struct device *sfp_dev;
24ce0aa27fSRussell King struct sfp *sfp;
25b34bb2cbSRussell King const struct sfp_quirk *sfp_quirk;
26ce0aa27fSRussell King
27ce0aa27fSRussell King const struct sfp_upstream_ops *upstream_ops;
28ce0aa27fSRussell King void *upstream;
29ce0aa27fSRussell King struct phy_device *phydev;
30ce0aa27fSRussell King
31ce0aa27fSRussell King bool registered;
32ce0aa27fSRussell King bool started;
33ce0aa27fSRussell King };
34ce0aa27fSRussell King
350a6fcd3fSRussell King /**
360a6fcd3fSRussell King * sfp_parse_port() - Parse the EEPROM base ID, setting the port type
370a6fcd3fSRussell King * @bus: a pointer to the &struct sfp_bus structure for the sfp module
380a6fcd3fSRussell King * @id: a pointer to the module's &struct sfp_eeprom_id
390a6fcd3fSRussell King * @support: optional pointer to an array of unsigned long for the
400a6fcd3fSRussell King * ethtool support mask
410a6fcd3fSRussell King *
420a6fcd3fSRussell King * Parse the EEPROM identification given in @id, and return one of
430a6fcd3fSRussell King * %PORT_TP, %PORT_FIBRE or %PORT_OTHER. If @support is non-%NULL,
440a6fcd3fSRussell King * also set the ethtool %ETHTOOL_LINK_MODE_xxx_BIT corresponding with
450a6fcd3fSRussell King * the connector type.
460a6fcd3fSRussell King *
470a6fcd3fSRussell King * If the port type is not known, returns %PORT_OTHER.
480a6fcd3fSRussell King */
sfp_parse_port(struct sfp_bus * bus,const struct sfp_eeprom_id * id,unsigned long * support)49ce0aa27fSRussell King int sfp_parse_port(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
50ce0aa27fSRussell King unsigned long *support)
51ce0aa27fSRussell King {
52ce0aa27fSRussell King int port;
53ce0aa27fSRussell King
54ce0aa27fSRussell King /* port is the physical connector, set this from the connector field. */
55ce0aa27fSRussell King switch (id->base.connector) {
560fbd26a9SRussell King case SFF8024_CONNECTOR_SC:
570fbd26a9SRussell King case SFF8024_CONNECTOR_FIBERJACK:
580fbd26a9SRussell King case SFF8024_CONNECTOR_LC:
590fbd26a9SRussell King case SFF8024_CONNECTOR_MT_RJ:
600fbd26a9SRussell King case SFF8024_CONNECTOR_MU:
610fbd26a9SRussell King case SFF8024_CONNECTOR_OPTICAL_PIGTAIL:
620fbd26a9SRussell King case SFF8024_CONNECTOR_MPO_1X12:
630fbd26a9SRussell King case SFF8024_CONNECTOR_MPO_2X16:
64ce0aa27fSRussell King port = PORT_FIBRE;
65ce0aa27fSRussell King break;
66ce0aa27fSRussell King
670fbd26a9SRussell King case SFF8024_CONNECTOR_RJ45:
68ce0aa27fSRussell King port = PORT_TP;
69ce0aa27fSRussell King break;
70ce0aa27fSRussell King
710fbd26a9SRussell King case SFF8024_CONNECTOR_COPPER_PIGTAIL:
72f10fcbcfSRussell King port = PORT_DA;
73f10fcbcfSRussell King break;
74f10fcbcfSRussell King
750fbd26a9SRussell King case SFF8024_CONNECTOR_UNSPEC:
76ce0aa27fSRussell King if (id->base.e1000_base_t) {
77ce0aa27fSRussell King port = PORT_TP;
78ce0aa27fSRussell King break;
79ce0aa27fSRussell King }
80df561f66SGustavo A. R. Silva fallthrough;
810fbd26a9SRussell King case SFF8024_CONNECTOR_SG: /* guess */
820fbd26a9SRussell King case SFF8024_CONNECTOR_HSSDC_II:
830fbd26a9SRussell King case SFF8024_CONNECTOR_NOSEPARATE:
840fbd26a9SRussell King case SFF8024_CONNECTOR_MXC_2X16:
85ce0aa27fSRussell King port = PORT_OTHER;
86ce0aa27fSRussell King break;
87ce0aa27fSRussell King default:
88ce0aa27fSRussell King dev_warn(bus->sfp_dev, "SFP: unknown connector id 0x%02x\n",
89ce0aa27fSRussell King id->base.connector);
90ce0aa27fSRussell King port = PORT_OTHER;
91ce0aa27fSRussell King break;
92ce0aa27fSRussell King }
93ce0aa27fSRussell King
94f10fcbcfSRussell King if (support) {
95f10fcbcfSRussell King switch (port) {
96f10fcbcfSRussell King case PORT_FIBRE:
97f10fcbcfSRussell King phylink_set(support, FIBRE);
98f10fcbcfSRussell King break;
99f10fcbcfSRussell King
100f10fcbcfSRussell King case PORT_TP:
101f10fcbcfSRussell King phylink_set(support, TP);
102f10fcbcfSRussell King break;
103f10fcbcfSRussell King }
104f10fcbcfSRussell King }
105f10fcbcfSRussell King
106ce0aa27fSRussell King return port;
107ce0aa27fSRussell King }
108ce0aa27fSRussell King EXPORT_SYMBOL_GPL(sfp_parse_port);
109ce0aa27fSRussell King
1100a6fcd3fSRussell King /**
11152c95600SRussell King * sfp_may_have_phy() - indicate whether the module may have a PHY
11252c95600SRussell King * @bus: a pointer to the &struct sfp_bus structure for the sfp module
11352c95600SRussell King * @id: a pointer to the module's &struct sfp_eeprom_id
11452c95600SRussell King *
11552c95600SRussell King * Parse the EEPROM identification given in @id, and return whether
11652c95600SRussell King * this module may have a PHY.
11752c95600SRussell King */
sfp_may_have_phy(struct sfp_bus * bus,const struct sfp_eeprom_id * id)11852c95600SRussell King bool sfp_may_have_phy(struct sfp_bus *bus, const struct sfp_eeprom_id *id)
11952c95600SRussell King {
12052c95600SRussell King if (id->base.e1000_base_t)
12152c95600SRussell King return true;
12252c95600SRussell King
12352c95600SRussell King if (id->base.phys_id != SFF8024_ID_DWDM_SFP) {
12452c95600SRussell King switch (id->base.extended_cc) {
12552c95600SRussell King case SFF8024_ECC_10GBASE_T_SFI:
12652c95600SRussell King case SFF8024_ECC_10GBASE_T_SR:
12752c95600SRussell King case SFF8024_ECC_5GBASE_T:
12852c95600SRussell King case SFF8024_ECC_2_5GBASE_T:
12952c95600SRussell King return true;
13052c95600SRussell King }
13152c95600SRussell King }
13252c95600SRussell King
13352c95600SRussell King return false;
13452c95600SRussell King }
13552c95600SRussell King EXPORT_SYMBOL_GPL(sfp_may_have_phy);
13652c95600SRussell King
13752c95600SRussell King /**
1380a6fcd3fSRussell King * sfp_parse_support() - Parse the eeprom id for supported link modes
1390a6fcd3fSRussell King * @bus: a pointer to the &struct sfp_bus structure for the sfp module
1400a6fcd3fSRussell King * @id: a pointer to the module's &struct sfp_eeprom_id
1410a6fcd3fSRussell King * @support: pointer to an array of unsigned long for the ethtool support mask
142fd580c98SRussell King * @interfaces: pointer to an array of unsigned long for phy interface modes
143fd580c98SRussell King * mask
1440a6fcd3fSRussell King *
1450a6fcd3fSRussell King * Parse the EEPROM identification information and derive the supported
1460a6fcd3fSRussell King * ethtool link modes for the module.
1470a6fcd3fSRussell King */
sfp_parse_support(struct sfp_bus * bus,const struct sfp_eeprom_id * id,unsigned long * support,unsigned long * interfaces)148ce0aa27fSRussell King void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
149fd580c98SRussell King unsigned long *support, unsigned long *interfaces)
150ce0aa27fSRussell King {
1519962acf7SRussell King unsigned int br_min, br_nom, br_max;
15203145864SRussell King __ETHTOOL_DECLARE_LINK_MODE_MASK(modes) = { 0, };
153ce0aa27fSRussell King
1549962acf7SRussell King /* Decode the bitrate information to MBd */
1559962acf7SRussell King br_min = br_nom = br_max = 0;
1569962acf7SRussell King if (id->base.br_nominal) {
1579962acf7SRussell King if (id->base.br_nominal != 255) {
1589962acf7SRussell King br_nom = id->base.br_nominal * 100;
15952c5cd1bSAntoine Tenart br_min = br_nom - id->base.br_nominal * id->ext.br_min;
1609962acf7SRussell King br_max = br_nom + id->base.br_nominal * id->ext.br_max;
1619962acf7SRussell King } else if (id->ext.br_max) {
1629962acf7SRussell King br_nom = 250 * id->ext.br_max;
1639962acf7SRussell King br_max = br_nom + br_nom * id->ext.br_min / 100;
1649962acf7SRussell King br_min = br_nom - br_nom * id->ext.br_min / 100;
1659962acf7SRussell King }
1662b999ba8SAntoine Tenart
1672b999ba8SAntoine Tenart /* When using passive cables, in case neither BR,min nor BR,max
1682b999ba8SAntoine Tenart * are specified, set br_min to 0 as the nominal value is then
1692b999ba8SAntoine Tenart * used as the maximum.
1702b999ba8SAntoine Tenart */
1712b999ba8SAntoine Tenart if (br_min == br_max && id->base.sfp_ct_passive)
1722b999ba8SAntoine Tenart br_min = 0;
1739962acf7SRussell King }
1749962acf7SRussell King
175ce0aa27fSRussell King /* Set ethtool support from the compliance fields. */
176fd580c98SRussell King if (id->base.e10g_base_sr) {
17703145864SRussell King phylink_set(modes, 10000baseSR_Full);
178fd580c98SRussell King __set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
179fd580c98SRussell King }
180fd580c98SRussell King if (id->base.e10g_base_lr) {
18103145864SRussell King phylink_set(modes, 10000baseLR_Full);
182fd580c98SRussell King __set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
183fd580c98SRussell King }
184fd580c98SRussell King if (id->base.e10g_base_lrm) {
18503145864SRussell King phylink_set(modes, 10000baseLRM_Full);
186fd580c98SRussell King __set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
187fd580c98SRussell King }
188fd580c98SRussell King if (id->base.e10g_base_er) {
18903145864SRussell King phylink_set(modes, 10000baseER_Full);
190fd580c98SRussell King __set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
191fd580c98SRussell King }
192ce0aa27fSRussell King if (id->base.e1000_base_sx ||
193ce0aa27fSRussell King id->base.e1000_base_lx ||
194fd580c98SRussell King id->base.e1000_base_cx) {
19503145864SRussell King phylink_set(modes, 1000baseX_Full);
196fd580c98SRussell King __set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces);
197fd580c98SRussell King }
198ce0aa27fSRussell King if (id->base.e1000_base_t) {
19903145864SRussell King phylink_set(modes, 1000baseT_Half);
20003145864SRussell King phylink_set(modes, 1000baseT_Full);
201fd580c98SRussell King __set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces);
202fd580c98SRussell King __set_bit(PHY_INTERFACE_MODE_SGMII, interfaces);
203ce0aa27fSRussell King }
204ce0aa27fSRussell King
2059962acf7SRussell King /* 1000Base-PX or 1000Base-BX10 */
2069962acf7SRussell King if ((id->base.e_base_px || id->base.e_base_bx10) &&
207fd580c98SRussell King br_min <= 1300 && br_max >= 1200) {
208d7f7e001SBaruch Siach phylink_set(modes, 1000baseX_Full);
209fd580c98SRussell King __set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces);
210fd580c98SRussell King }
2119962acf7SRussell King
2126e12f35cSBjarni Jonasson /* 100Base-FX, 100Base-LX, 100Base-PX, 100Base-BX10 */
213fd580c98SRussell King if (id->base.e100_base_fx || id->base.e100_base_lx) {
2146e12f35cSBjarni Jonasson phylink_set(modes, 100baseFX_Full);
215fd580c98SRussell King __set_bit(PHY_INTERFACE_MODE_100BASEX, interfaces);
216fd580c98SRussell King }
217fd580c98SRussell King if ((id->base.e_base_px || id->base.e_base_bx10) && br_nom == 100) {
2186e12f35cSBjarni Jonasson phylink_set(modes, 100baseFX_Full);
219fd580c98SRussell King __set_bit(PHY_INTERFACE_MODE_100BASEX, interfaces);
220fd580c98SRussell King }
2216e12f35cSBjarni Jonasson
222f10fcbcfSRussell King /* For active or passive cables, select the link modes
223f10fcbcfSRussell King * based on the bit rates and the cable compliance bytes.
224f10fcbcfSRussell King */
225f10fcbcfSRussell King if ((id->base.sfp_ct_passive || id->base.sfp_ct_active) && br_nom) {
226f10fcbcfSRussell King /* This may look odd, but some manufacturers use 12000MBd */
227fd580c98SRussell King if (br_min <= 12000 && br_max >= 10300) {
22803145864SRussell King phylink_set(modes, 10000baseCR_Full);
229fd580c98SRussell King __set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
230fd580c98SRussell King }
231fd580c98SRussell King if (br_min <= 3200 && br_max >= 3100) {
23203145864SRussell King phylink_set(modes, 2500baseX_Full);
233fd580c98SRussell King __set_bit(PHY_INTERFACE_MODE_2500BASEX, interfaces);
234fd580c98SRussell King }
235fd580c98SRussell King if (br_min <= 1300 && br_max >= 1200) {
23603145864SRussell King phylink_set(modes, 1000baseX_Full);
237fd580c98SRussell King __set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces);
238fd580c98SRussell King }
239f10fcbcfSRussell King }
240f10fcbcfSRussell King if (id->base.sfp_ct_passive) {
241fd580c98SRussell King if (id->base.passive.sff8431_app_e) {
24203145864SRussell King phylink_set(modes, 10000baseCR_Full);
243fd580c98SRussell King __set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
244fd580c98SRussell King }
245f10fcbcfSRussell King }
246f10fcbcfSRussell King if (id->base.sfp_ct_active) {
247f10fcbcfSRussell King if (id->base.active.sff8431_app_e ||
248f10fcbcfSRussell King id->base.active.sff8431_lim) {
24903145864SRussell King phylink_set(modes, 10000baseCR_Full);
250fd580c98SRussell King __set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
251f10fcbcfSRussell King }
252f10fcbcfSRussell King }
253f10fcbcfSRussell King
254ce0aa27fSRussell King switch (id->base.extended_cc) {
2550fbd26a9SRussell King case SFF8024_ECC_UNSPEC:
256ce0aa27fSRussell King break;
257db1a6ad7SJosua Mayer case SFF8024_ECC_100G_25GAUI_C2M_AOC:
258db1a6ad7SJosua Mayer if (br_min <= 28000 && br_max >= 25000) {
259db1a6ad7SJosua Mayer /* 25GBASE-R, possibly with FEC */
260db1a6ad7SJosua Mayer __set_bit(PHY_INTERFACE_MODE_25GBASER, interfaces);
261db1a6ad7SJosua Mayer /* There is currently no link mode for 25000base
262db1a6ad7SJosua Mayer * with unspecified range, reuse SR.
263db1a6ad7SJosua Mayer */
264db1a6ad7SJosua Mayer phylink_set(modes, 25000baseSR_Full);
265db1a6ad7SJosua Mayer }
266db1a6ad7SJosua Mayer break;
2670fbd26a9SRussell King case SFF8024_ECC_100GBASE_SR4_25GBASE_SR:
26803145864SRussell King phylink_set(modes, 100000baseSR4_Full);
26903145864SRussell King phylink_set(modes, 25000baseSR_Full);
2705b4c189dSMarek Behún __set_bit(PHY_INTERFACE_MODE_25GBASER, interfaces);
271ce0aa27fSRussell King break;
2720fbd26a9SRussell King case SFF8024_ECC_100GBASE_LR4_25GBASE_LR:
2730fbd26a9SRussell King case SFF8024_ECC_100GBASE_ER4_25GBASE_ER:
27403145864SRussell King phylink_set(modes, 100000baseLR4_ER4_Full);
275ce0aa27fSRussell King break;
2760fbd26a9SRussell King case SFF8024_ECC_100GBASE_CR4:
27703145864SRussell King phylink_set(modes, 100000baseCR4_Full);
278df561f66SGustavo A. R. Silva fallthrough;
2790fbd26a9SRussell King case SFF8024_ECC_25GBASE_CR_S:
2800fbd26a9SRussell King case SFF8024_ECC_25GBASE_CR_N:
28103145864SRussell King phylink_set(modes, 25000baseCR_Full);
2825b4c189dSMarek Behún __set_bit(PHY_INTERFACE_MODE_25GBASER, interfaces);
283ce0aa27fSRussell King break;
2840fbd26a9SRussell King case SFF8024_ECC_10GBASE_T_SFI:
2850fbd26a9SRussell King case SFF8024_ECC_10GBASE_T_SR:
2860fbd26a9SRussell King phylink_set(modes, 10000baseT_Full);
287fd580c98SRussell King __set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
2880fbd26a9SRussell King break;
2890fbd26a9SRussell King case SFF8024_ECC_5GBASE_T:
2900fbd26a9SRussell King phylink_set(modes, 5000baseT_Full);
2915b4c189dSMarek Behún __set_bit(PHY_INTERFACE_MODE_5GBASER, interfaces);
2920fbd26a9SRussell King break;
2930fbd26a9SRussell King case SFF8024_ECC_2_5GBASE_T:
2940fbd26a9SRussell King phylink_set(modes, 2500baseT_Full);
295fd580c98SRussell King __set_bit(PHY_INTERFACE_MODE_2500BASEX, interfaces);
2960fbd26a9SRussell King break;
297ce0aa27fSRussell King default:
298ce0aa27fSRussell King dev_warn(bus->sfp_dev,
299ce0aa27fSRussell King "Unknown/unsupported extended compliance code: 0x%02x\n",
300ce0aa27fSRussell King id->base.extended_cc);
301ce0aa27fSRussell King break;
302ce0aa27fSRussell King }
303ce0aa27fSRussell King
304ce0aa27fSRussell King /* For fibre channel SFP, derive possible BaseX modes */
305ce0aa27fSRussell King if (id->base.fc_speed_100 ||
306ce0aa27fSRussell King id->base.fc_speed_200 ||
307ce0aa27fSRussell King id->base.fc_speed_400) {
308fd580c98SRussell King if (id->base.br_nominal >= 31) {
30903145864SRussell King phylink_set(modes, 2500baseX_Full);
310fd580c98SRussell King __set_bit(PHY_INTERFACE_MODE_2500BASEX, interfaces);
311fd580c98SRussell King }
312fd580c98SRussell King if (id->base.br_nominal >= 12) {
31303145864SRussell King phylink_set(modes, 1000baseX_Full);
314fd580c98SRussell King __set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces);
315fd580c98SRussell King }
316ce0aa27fSRussell King }
31703145864SRussell King
31803145864SRussell King /* If we haven't discovered any modes that this module supports, try
3197a77233eSRussell King * the bitrate to determine supported modes. Some BiDi modules (eg,
3207a77233eSRussell King * 1310nm/1550nm) are not 1000BASE-BX compliant due to the differing
3217a77233eSRussell King * wavelengths, so do not set any transceiver bits.
322a006dbf0SRussell King *
323a006dbf0SRussell King * Do the same for modules supporting 2500BASE-X. Note that some
324a006dbf0SRussell King * modules use 2500Mbaud rather than 3100 or 3200Mbaud for
325a006dbf0SRussell King * 2500BASE-X, so we allow some slack here.
32603145864SRussell King */
327a006dbf0SRussell King if (bitmap_empty(modes, __ETHTOOL_LINK_MODE_MASK_NBITS) && br_nom) {
328fd580c98SRussell King if (br_min <= 1300 && br_max >= 1200) {
32903145864SRussell King phylink_set(modes, 1000baseX_Full);
330fd580c98SRussell King __set_bit(PHY_INTERFACE_MODE_1000BASEX, interfaces);
331fd580c98SRussell King }
332fd580c98SRussell King if (br_min <= 3200 && br_max >= 2500) {
333a006dbf0SRussell King phylink_set(modes, 2500baseX_Full);
334fd580c98SRussell King __set_bit(PHY_INTERFACE_MODE_2500BASEX, interfaces);
335fd580c98SRussell King }
33603145864SRussell King }
33703145864SRussell King
338*9399baa0SRussell King (Oracle) phylink_set(modes, Autoneg);
339*9399baa0SRussell King (Oracle) phylink_set(modes, Pause);
340*9399baa0SRussell King (Oracle) phylink_set(modes, Asym_Pause);
341*9399baa0SRussell King (Oracle)
34273472c83SRussell King (Oracle) if (bus->sfp_quirk && bus->sfp_quirk->modes)
343fd580c98SRussell King bus->sfp_quirk->modes(id, modes, interfaces);
344b34bb2cbSRussell King
3454973056cSSean Anderson linkmode_or(support, support, modes);
346ce0aa27fSRussell King }
347ce0aa27fSRussell King EXPORT_SYMBOL_GPL(sfp_parse_support);
348ce0aa27fSRussell King
349a9c79364SRussell King /**
350a9c79364SRussell King * sfp_select_interface() - Select appropriate phy_interface_t mode
351a9c79364SRussell King * @bus: a pointer to the &struct sfp_bus structure for the sfp module
352a9c79364SRussell King * @link_modes: ethtool link modes mask
353a9c79364SRussell King *
354a4516c70SRussell King * Derive the phy_interface_t mode for the SFP module from the link
355a4516c70SRussell King * modes mask.
356a9c79364SRussell King */
sfp_select_interface(struct sfp_bus * bus,unsigned long * link_modes)357a9c79364SRussell King phy_interface_t sfp_select_interface(struct sfp_bus *bus,
358a9c79364SRussell King unsigned long *link_modes)
359a9c79364SRussell King {
360452d2c6fSSteen Hegelund if (phylink_test(link_modes, 25000baseCR_Full) ||
361452d2c6fSSteen Hegelund phylink_test(link_modes, 25000baseKR_Full) ||
362452d2c6fSSteen Hegelund phylink_test(link_modes, 25000baseSR_Full))
363452d2c6fSSteen Hegelund return PHY_INTERFACE_MODE_25GBASER;
364452d2c6fSSteen Hegelund
365a9c79364SRussell King if (phylink_test(link_modes, 10000baseCR_Full) ||
366a9c79364SRussell King phylink_test(link_modes, 10000baseSR_Full) ||
367a9c79364SRussell King phylink_test(link_modes, 10000baseLR_Full) ||
368a9c79364SRussell King phylink_test(link_modes, 10000baseLRM_Full) ||
3690fbd26a9SRussell King phylink_test(link_modes, 10000baseER_Full) ||
3700fbd26a9SRussell King phylink_test(link_modes, 10000baseT_Full))
371e0f909bcSRussell King return PHY_INTERFACE_MODE_10GBASER;
372a9c79364SRussell King
373cfb971deSMarek Behún if (phylink_test(link_modes, 5000baseT_Full))
374cfb971deSMarek Behún return PHY_INTERFACE_MODE_5GBASER;
375cfb971deSMarek Behún
376a9c79364SRussell King if (phylink_test(link_modes, 2500baseX_Full))
377a9c79364SRussell King return PHY_INTERFACE_MODE_2500BASEX;
378a9c79364SRussell King
379a4516c70SRussell King if (phylink_test(link_modes, 1000baseT_Half) ||
380a4516c70SRussell King phylink_test(link_modes, 1000baseT_Full))
381a9c79364SRussell King return PHY_INTERFACE_MODE_SGMII;
382a9c79364SRussell King
383a9c79364SRussell King if (phylink_test(link_modes, 1000baseX_Full))
384a9c79364SRussell King return PHY_INTERFACE_MODE_1000BASEX;
385a9c79364SRussell King
3866e12f35cSBjarni Jonasson if (phylink_test(link_modes, 100baseFX_Full))
3876e12f35cSBjarni Jonasson return PHY_INTERFACE_MODE_100BASEX;
3886e12f35cSBjarni Jonasson
389a9c79364SRussell King dev_warn(bus->sfp_dev, "Unable to ascertain link mode\n");
390a9c79364SRussell King
391a9c79364SRussell King return PHY_INTERFACE_MODE_NA;
392a9c79364SRussell King }
393a9c79364SRussell King EXPORT_SYMBOL_GPL(sfp_select_interface);
394a9c79364SRussell King
395ce0aa27fSRussell King static LIST_HEAD(sfp_buses);
396ce0aa27fSRussell King static DEFINE_MUTEX(sfp_mutex);
397ce0aa27fSRussell King
sfp_get_upstream_ops(struct sfp_bus * bus)398ce0aa27fSRussell King static const struct sfp_upstream_ops *sfp_get_upstream_ops(struct sfp_bus *bus)
399ce0aa27fSRussell King {
400ce0aa27fSRussell King return bus->registered ? bus->upstream_ops : NULL;
401ce0aa27fSRussell King }
402ce0aa27fSRussell King
sfp_bus_get(const struct fwnode_handle * fwnode)403850a8d2dSRussell King (Oracle) static struct sfp_bus *sfp_bus_get(const struct fwnode_handle *fwnode)
404ce0aa27fSRussell King {
405ce0aa27fSRussell King struct sfp_bus *sfp, *new, *found = NULL;
406ce0aa27fSRussell King
407ce0aa27fSRussell King new = kzalloc(sizeof(*new), GFP_KERNEL);
408ce0aa27fSRussell King
409ce0aa27fSRussell King mutex_lock(&sfp_mutex);
410ce0aa27fSRussell King
411ce0aa27fSRussell King list_for_each_entry(sfp, &sfp_buses, node) {
412c19bb000SRussell King if (sfp->fwnode == fwnode) {
413ce0aa27fSRussell King kref_get(&sfp->kref);
414ce0aa27fSRussell King found = sfp;
415ce0aa27fSRussell King break;
416ce0aa27fSRussell King }
417ce0aa27fSRussell King }
418ce0aa27fSRussell King
419ce0aa27fSRussell King if (!found && new) {
420ce0aa27fSRussell King kref_init(&new->kref);
421c19bb000SRussell King new->fwnode = fwnode;
422ce0aa27fSRussell King list_add(&new->node, &sfp_buses);
423ce0aa27fSRussell King found = new;
424ce0aa27fSRussell King new = NULL;
425ce0aa27fSRussell King }
426ce0aa27fSRussell King
427ce0aa27fSRussell King mutex_unlock(&sfp_mutex);
428ce0aa27fSRussell King
429ce0aa27fSRussell King kfree(new);
430ce0aa27fSRussell King
431ce0aa27fSRussell King return found;
432ce0aa27fSRussell King }
433ce0aa27fSRussell King
sfp_bus_release(struct kref * kref)434b6e67d6dSRussell King static void sfp_bus_release(struct kref *kref)
435ce0aa27fSRussell King {
436ce0aa27fSRussell King struct sfp_bus *bus = container_of(kref, struct sfp_bus, kref);
437ce0aa27fSRussell King
438ce0aa27fSRussell King list_del(&bus->node);
439ce0aa27fSRussell King mutex_unlock(&sfp_mutex);
440ce0aa27fSRussell King kfree(bus);
441ce0aa27fSRussell King }
442ce0aa27fSRussell King
443727b3668SRussell King /**
444727b3668SRussell King * sfp_bus_put() - put a reference on the &struct sfp_bus
4452fca4ac9SRussell King * @bus: the &struct sfp_bus found via sfp_bus_find_fwnode()
446727b3668SRussell King *
447727b3668SRussell King * Put a reference on the &struct sfp_bus and free the underlying structure
448727b3668SRussell King * if this was the last reference.
449727b3668SRussell King */
sfp_bus_put(struct sfp_bus * bus)450727b3668SRussell King void sfp_bus_put(struct sfp_bus *bus)
451ce0aa27fSRussell King {
452727b3668SRussell King if (bus)
453ce0aa27fSRussell King kref_put_mutex(&bus->kref, sfp_bus_release, &sfp_mutex);
454ce0aa27fSRussell King }
455727b3668SRussell King EXPORT_SYMBOL_GPL(sfp_bus_put);
456ce0aa27fSRussell King
sfp_register_bus(struct sfp_bus * bus)457ce0aa27fSRussell King static int sfp_register_bus(struct sfp_bus *bus)
458ce0aa27fSRussell King {
459ce0aa27fSRussell King const struct sfp_upstream_ops *ops = bus->upstream_ops;
460ce0aa27fSRussell King int ret;
461ce0aa27fSRussell King
462ce0aa27fSRussell King if (ops) {
463ce0aa27fSRussell King if (ops->link_down)
464ce0aa27fSRussell King ops->link_down(bus->upstream);
465ce0aa27fSRussell King if (ops->connect_phy && bus->phydev) {
466ce0aa27fSRussell King ret = ops->connect_phy(bus->upstream, bus->phydev);
467ce0aa27fSRussell King if (ret)
468ce0aa27fSRussell King return ret;
469ce0aa27fSRussell King }
470ce0aa27fSRussell King }
471727b3668SRussell King bus->registered = true;
472b5bfc21aSRussell King bus->socket_ops->attach(bus->sfp);
473ce0aa27fSRussell King if (bus->started)
474ce0aa27fSRussell King bus->socket_ops->start(bus->sfp);
475320587e6SRussell King bus->upstream_ops->attach(bus->upstream, bus);
476ce0aa27fSRussell King return 0;
477ce0aa27fSRussell King }
478ce0aa27fSRussell King
sfp_unregister_bus(struct sfp_bus * bus)479ce0aa27fSRussell King static void sfp_unregister_bus(struct sfp_bus *bus)
480ce0aa27fSRussell King {
481ce0aa27fSRussell King const struct sfp_upstream_ops *ops = bus->upstream_ops;
482ce0aa27fSRussell King
483ce0aa27fSRussell King if (bus->registered) {
484320587e6SRussell King bus->upstream_ops->detach(bus->upstream, bus);
485ce0aa27fSRussell King if (bus->started)
486ce0aa27fSRussell King bus->socket_ops->stop(bus->sfp);
487b5bfc21aSRussell King bus->socket_ops->detach(bus->sfp);
488ce0aa27fSRussell King if (bus->phydev && ops && ops->disconnect_phy)
489ce0aa27fSRussell King ops->disconnect_phy(bus->upstream);
490ce0aa27fSRussell King }
491ce0aa27fSRussell King bus->registered = false;
492ce0aa27fSRussell King }
493ce0aa27fSRussell King
4940a6fcd3fSRussell King /**
4950a6fcd3fSRussell King * sfp_get_module_info() - Get the ethtool_modinfo for a SFP module
4960a6fcd3fSRussell King * @bus: a pointer to the &struct sfp_bus structure for the sfp module
4970a6fcd3fSRussell King * @modinfo: a &struct ethtool_modinfo
4980a6fcd3fSRussell King *
4990a6fcd3fSRussell King * Fill in the type and eeprom_len parameters in @modinfo for a module on
5000a6fcd3fSRussell King * the sfp bus specified by @bus.
5010a6fcd3fSRussell King *
5020a6fcd3fSRussell King * Returns 0 on success or a negative errno number.
5030a6fcd3fSRussell King */
sfp_get_module_info(struct sfp_bus * bus,struct ethtool_modinfo * modinfo)504ce0aa27fSRussell King int sfp_get_module_info(struct sfp_bus *bus, struct ethtool_modinfo *modinfo)
505ce0aa27fSRussell King {
506ce0aa27fSRussell King return bus->socket_ops->module_info(bus->sfp, modinfo);
507ce0aa27fSRussell King }
508ce0aa27fSRussell King EXPORT_SYMBOL_GPL(sfp_get_module_info);
509ce0aa27fSRussell King
5100a6fcd3fSRussell King /**
5110a6fcd3fSRussell King * sfp_get_module_eeprom() - Read the SFP module EEPROM
5120a6fcd3fSRussell King * @bus: a pointer to the &struct sfp_bus structure for the sfp module
5130a6fcd3fSRussell King * @ee: a &struct ethtool_eeprom
5140a6fcd3fSRussell King * @data: buffer to contain the EEPROM data (must be at least @ee->len bytes)
5150a6fcd3fSRussell King *
5160a6fcd3fSRussell King * Read the EEPROM as specified by the supplied @ee. See the documentation
5170a6fcd3fSRussell King * for &struct ethtool_eeprom for the region to be read.
5180a6fcd3fSRussell King *
5190a6fcd3fSRussell King * Returns 0 on success or a negative errno number.
5200a6fcd3fSRussell King */
sfp_get_module_eeprom(struct sfp_bus * bus,struct ethtool_eeprom * ee,u8 * data)521ce0aa27fSRussell King int sfp_get_module_eeprom(struct sfp_bus *bus, struct ethtool_eeprom *ee,
522ce0aa27fSRussell King u8 *data)
523ce0aa27fSRussell King {
524ce0aa27fSRussell King return bus->socket_ops->module_eeprom(bus->sfp, ee, data);
525ce0aa27fSRussell King }
526ce0aa27fSRussell King EXPORT_SYMBOL_GPL(sfp_get_module_eeprom);
527ce0aa27fSRussell King
5280a6fcd3fSRussell King /**
529d740513fSAndrew Lunn * sfp_get_module_eeprom_by_page() - Read a page from the SFP module EEPROM
530d740513fSAndrew Lunn * @bus: a pointer to the &struct sfp_bus structure for the sfp module
531d740513fSAndrew Lunn * @page: a &struct ethtool_module_eeprom
532d740513fSAndrew Lunn * @extack: extack for reporting problems
533d740513fSAndrew Lunn *
534d740513fSAndrew Lunn * Read an EEPROM page as specified by the supplied @page. See the
535d740513fSAndrew Lunn * documentation for &struct ethtool_module_eeprom for the page to be read.
536d740513fSAndrew Lunn *
537d740513fSAndrew Lunn * Returns 0 on success or a negative errno number. More error
538d740513fSAndrew Lunn * information might be provided via extack
539d740513fSAndrew Lunn */
sfp_get_module_eeprom_by_page(struct sfp_bus * bus,const struct ethtool_module_eeprom * page,struct netlink_ext_ack * extack)540d740513fSAndrew Lunn int sfp_get_module_eeprom_by_page(struct sfp_bus *bus,
541d740513fSAndrew Lunn const struct ethtool_module_eeprom *page,
542d740513fSAndrew Lunn struct netlink_ext_ack *extack)
543d740513fSAndrew Lunn {
544d740513fSAndrew Lunn return bus->socket_ops->module_eeprom_by_page(bus->sfp, page, extack);
545d740513fSAndrew Lunn }
546d740513fSAndrew Lunn EXPORT_SYMBOL_GPL(sfp_get_module_eeprom_by_page);
547d740513fSAndrew Lunn
548d740513fSAndrew Lunn /**
5490a6fcd3fSRussell King * sfp_upstream_start() - Inform the SFP that the network device is up
5500a6fcd3fSRussell King * @bus: a pointer to the &struct sfp_bus structure for the sfp module
5510a6fcd3fSRussell King *
5520a6fcd3fSRussell King * Inform the SFP socket that the network device is now up, so that the
5530a6fcd3fSRussell King * module can be enabled by allowing TX_DISABLE to be deasserted. This
5540a6fcd3fSRussell King * should be called from the network device driver's &struct net_device_ops
5550a6fcd3fSRussell King * ndo_open() method.
5560a6fcd3fSRussell King */
sfp_upstream_start(struct sfp_bus * bus)557ce0aa27fSRussell King void sfp_upstream_start(struct sfp_bus *bus)
558ce0aa27fSRussell King {
559ce0aa27fSRussell King if (bus->registered)
560ce0aa27fSRussell King bus->socket_ops->start(bus->sfp);
561ce0aa27fSRussell King bus->started = true;
562ce0aa27fSRussell King }
563ce0aa27fSRussell King EXPORT_SYMBOL_GPL(sfp_upstream_start);
564ce0aa27fSRussell King
5650a6fcd3fSRussell King /**
5660a6fcd3fSRussell King * sfp_upstream_stop() - Inform the SFP that the network device is down
5670a6fcd3fSRussell King * @bus: a pointer to the &struct sfp_bus structure for the sfp module
5680a6fcd3fSRussell King *
5690a6fcd3fSRussell King * Inform the SFP socket that the network device is now up, so that the
5700a6fcd3fSRussell King * module can be disabled by asserting TX_DISABLE, disabling the laser
5710a6fcd3fSRussell King * in optical modules. This should be called from the network device
5720a6fcd3fSRussell King * driver's &struct net_device_ops ndo_stop() method.
5730a6fcd3fSRussell King */
sfp_upstream_stop(struct sfp_bus * bus)574ce0aa27fSRussell King void sfp_upstream_stop(struct sfp_bus *bus)
575ce0aa27fSRussell King {
576ce0aa27fSRussell King if (bus->registered)
577ce0aa27fSRussell King bus->socket_ops->stop(bus->sfp);
578ce0aa27fSRussell King bus->started = false;
579ce0aa27fSRussell King }
580ce0aa27fSRussell King EXPORT_SYMBOL_GPL(sfp_upstream_stop);
581ce0aa27fSRussell King
sfp_upstream_clear(struct sfp_bus * bus)582f20a4c46SRussell King static void sfp_upstream_clear(struct sfp_bus *bus)
583f20a4c46SRussell King {
584f20a4c46SRussell King bus->upstream_ops = NULL;
585f20a4c46SRussell King bus->upstream = NULL;
586f20a4c46SRussell King }
587f20a4c46SRussell King
5880a6fcd3fSRussell King /**
589dc185822SRussell King (Oracle) * sfp_upstream_set_signal_rate() - set data signalling rate
590dc185822SRussell King (Oracle) * @bus: a pointer to the &struct sfp_bus structure for the sfp module
591dc185822SRussell King (Oracle) * @rate_kbd: signalling rate in units of 1000 baud
592dc185822SRussell King (Oracle) *
593dc185822SRussell King (Oracle) * Configure the rate select settings on the SFP module for the signalling
594dc185822SRussell King (Oracle) * rate (not the same as the data rate).
595dc185822SRussell King (Oracle) *
596dc185822SRussell King (Oracle) * Locks that may be held:
597dc185822SRussell King (Oracle) * Phylink's state_mutex
598dc185822SRussell King (Oracle) * rtnl lock
599dc185822SRussell King (Oracle) * SFP's sm_mutex
600dc185822SRussell King (Oracle) */
sfp_upstream_set_signal_rate(struct sfp_bus * bus,unsigned int rate_kbd)601dc185822SRussell King (Oracle) void sfp_upstream_set_signal_rate(struct sfp_bus *bus, unsigned int rate_kbd)
602dc185822SRussell King (Oracle) {
603dc185822SRussell King (Oracle) if (bus->registered)
604dc185822SRussell King (Oracle) bus->socket_ops->set_signal_rate(bus->sfp, rate_kbd);
605dc185822SRussell King (Oracle) }
606dc185822SRussell King (Oracle) EXPORT_SYMBOL_GPL(sfp_upstream_set_signal_rate);
607dc185822SRussell King (Oracle)
608dc185822SRussell King (Oracle) /**
609727b3668SRussell King * sfp_bus_find_fwnode() - parse and locate the SFP bus from fwnode
6102203cbf2SRussell King * @fwnode: firmware node for the parent device (MAC or PHY)
6110a6fcd3fSRussell King *
612727b3668SRussell King * Parse the parent device's firmware node for a SFP bus, and locate
613727b3668SRussell King * the sfp_bus structure, incrementing its reference count. This must
614727b3668SRussell King * be put via sfp_bus_put() when done.
6150a6fcd3fSRussell King *
6166497ca07SMauro Carvalho Chehab * Returns:
6176497ca07SMauro Carvalho Chehab * - on success, a pointer to the sfp_bus structure,
6186497ca07SMauro Carvalho Chehab * - %NULL if no SFP is specified,
6196497ca07SMauro Carvalho Chehab * - on failure, an error pointer value:
6206497ca07SMauro Carvalho Chehab *
6216497ca07SMauro Carvalho Chehab * - corresponding to the errors detailed for
6222203cbf2SRussell King * fwnode_property_get_reference_args().
6236497ca07SMauro Carvalho Chehab * - %-ENOMEM if we failed to allocate the bus.
6246497ca07SMauro Carvalho Chehab * - an error from the upstream's connect_phy() method.
6250a6fcd3fSRussell King */
sfp_bus_find_fwnode(const struct fwnode_handle * fwnode)626a90ac762SRussell King (Oracle) struct sfp_bus *sfp_bus_find_fwnode(const struct fwnode_handle *fwnode)
627ce0aa27fSRussell King {
6282203cbf2SRussell King struct fwnode_reference_args ref;
6292203cbf2SRussell King struct sfp_bus *bus;
6302203cbf2SRussell King int ret;
631ce0aa27fSRussell King
6322203cbf2SRussell King ret = fwnode_property_get_reference_args(fwnode, "sfp", NULL,
6332203cbf2SRussell King 0, 0, &ref);
6342203cbf2SRussell King if (ret == -ENOENT)
6352203cbf2SRussell King return NULL;
6362203cbf2SRussell King else if (ret < 0)
6372203cbf2SRussell King return ERR_PTR(ret);
6382203cbf2SRussell King
6392148927eSMarek Behún if (!fwnode_device_is_available(ref.fwnode)) {
6402148927eSMarek Behún fwnode_handle_put(ref.fwnode);
6412148927eSMarek Behún return NULL;
6422148927eSMarek Behún }
6432148927eSMarek Behún
6442203cbf2SRussell King bus = sfp_bus_get(ref.fwnode);
6452203cbf2SRussell King fwnode_handle_put(ref.fwnode);
6462203cbf2SRussell King if (!bus)
6472203cbf2SRussell King return ERR_PTR(-ENOMEM);
6482203cbf2SRussell King
649727b3668SRussell King return bus;
650727b3668SRussell King }
651727b3668SRussell King EXPORT_SYMBOL_GPL(sfp_bus_find_fwnode);
652727b3668SRussell King
653727b3668SRussell King /**
654727b3668SRussell King * sfp_bus_add_upstream() - parse and register the neighbouring device
655727b3668SRussell King * @bus: the &struct sfp_bus found via sfp_bus_find_fwnode()
656727b3668SRussell King * @upstream: the upstream private data
657727b3668SRussell King * @ops: the upstream's &struct sfp_upstream_ops
658727b3668SRussell King *
659727b3668SRussell King * Add upstream driver for the SFP bus, and if the bus is complete, register
660727b3668SRussell King * the SFP bus using sfp_register_upstream(). This takes a reference on the
661727b3668SRussell King * bus, so it is safe to put the bus after this call.
662727b3668SRussell King *
6636497ca07SMauro Carvalho Chehab * Returns:
6646497ca07SMauro Carvalho Chehab * - on success, a pointer to the sfp_bus structure,
6656497ca07SMauro Carvalho Chehab * - %NULL if no SFP is specified,
6666497ca07SMauro Carvalho Chehab * - on failure, an error pointer value:
6676497ca07SMauro Carvalho Chehab *
6686497ca07SMauro Carvalho Chehab * - corresponding to the errors detailed for
669727b3668SRussell King * fwnode_property_get_reference_args().
6706497ca07SMauro Carvalho Chehab * - %-ENOMEM if we failed to allocate the bus.
6716497ca07SMauro Carvalho Chehab * - an error from the upstream's connect_phy() method.
672727b3668SRussell King */
sfp_bus_add_upstream(struct sfp_bus * bus,void * upstream,const struct sfp_upstream_ops * ops)673727b3668SRussell King int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream,
674727b3668SRussell King const struct sfp_upstream_ops *ops)
675727b3668SRussell King {
676727b3668SRussell King int ret;
677727b3668SRussell King
678727b3668SRussell King /* If no bus, return success */
679727b3668SRussell King if (!bus)
680727b3668SRussell King return 0;
681727b3668SRussell King
682ce0aa27fSRussell King rtnl_lock();
683727b3668SRussell King kref_get(&bus->kref);
684ce0aa27fSRussell King bus->upstream_ops = ops;
685ce0aa27fSRussell King bus->upstream = upstream;
686ce0aa27fSRussell King
687f20a4c46SRussell King if (bus->sfp) {
688ce0aa27fSRussell King ret = sfp_register_bus(bus);
689f20a4c46SRussell King if (ret)
690f20a4c46SRussell King sfp_upstream_clear(bus);
6912203cbf2SRussell King } else {
6922203cbf2SRussell King ret = 0;
693f20a4c46SRussell King }
694ce0aa27fSRussell King rtnl_unlock();
695ce0aa27fSRussell King
696727b3668SRussell King if (ret)
697ce0aa27fSRussell King sfp_bus_put(bus);
698ce0aa27fSRussell King
699727b3668SRussell King return ret;
700ce0aa27fSRussell King }
701727b3668SRussell King EXPORT_SYMBOL_GPL(sfp_bus_add_upstream);
702ce0aa27fSRussell King
7030a6fcd3fSRussell King /**
704727b3668SRussell King * sfp_bus_del_upstream() - Delete a sfp bus
7050a6fcd3fSRussell King * @bus: a pointer to the &struct sfp_bus structure for the sfp module
7060a6fcd3fSRussell King *
707727b3668SRussell King * Delete a previously registered upstream connection for the SFP
708727b3668SRussell King * module. @bus should have been added by sfp_bus_add_upstream().
7090a6fcd3fSRussell King */
sfp_bus_del_upstream(struct sfp_bus * bus)710727b3668SRussell King void sfp_bus_del_upstream(struct sfp_bus *bus)
711ce0aa27fSRussell King {
712727b3668SRussell King if (bus) {
713ce0aa27fSRussell King rtnl_lock();
7140b2122e4SRussell King if (bus->sfp)
715ce0aa27fSRussell King sfp_unregister_bus(bus);
716f20a4c46SRussell King sfp_upstream_clear(bus);
717ce0aa27fSRussell King rtnl_unlock();
718ce0aa27fSRussell King
719ce0aa27fSRussell King sfp_bus_put(bus);
720ce0aa27fSRussell King }
721727b3668SRussell King }
722727b3668SRussell King EXPORT_SYMBOL_GPL(sfp_bus_del_upstream);
723ce0aa27fSRussell King
724ce0aa27fSRussell King /* Socket driver entry points */
sfp_add_phy(struct sfp_bus * bus,struct phy_device * phydev)725ce0aa27fSRussell King int sfp_add_phy(struct sfp_bus *bus, struct phy_device *phydev)
726ce0aa27fSRussell King {
727ce0aa27fSRussell King const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus);
728ce0aa27fSRussell King int ret = 0;
729ce0aa27fSRussell King
730ce0aa27fSRussell King if (ops && ops->connect_phy)
731ce0aa27fSRussell King ret = ops->connect_phy(bus->upstream, phydev);
732ce0aa27fSRussell King
733ce0aa27fSRussell King if (ret == 0)
734ce0aa27fSRussell King bus->phydev = phydev;
735ce0aa27fSRussell King
736ce0aa27fSRussell King return ret;
737ce0aa27fSRussell King }
738ce0aa27fSRussell King EXPORT_SYMBOL_GPL(sfp_add_phy);
739ce0aa27fSRussell King
sfp_remove_phy(struct sfp_bus * bus)740ce0aa27fSRussell King void sfp_remove_phy(struct sfp_bus *bus)
741ce0aa27fSRussell King {
742ce0aa27fSRussell King const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus);
743ce0aa27fSRussell King
744ce0aa27fSRussell King if (ops && ops->disconnect_phy)
745ce0aa27fSRussell King ops->disconnect_phy(bus->upstream);
746ce0aa27fSRussell King bus->phydev = NULL;
747ce0aa27fSRussell King }
748ce0aa27fSRussell King EXPORT_SYMBOL_GPL(sfp_remove_phy);
749ce0aa27fSRussell King
sfp_link_up(struct sfp_bus * bus)750ce0aa27fSRussell King void sfp_link_up(struct sfp_bus *bus)
751ce0aa27fSRussell King {
752ce0aa27fSRussell King const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus);
753ce0aa27fSRussell King
754ce0aa27fSRussell King if (ops && ops->link_up)
755ce0aa27fSRussell King ops->link_up(bus->upstream);
756ce0aa27fSRussell King }
757ce0aa27fSRussell King EXPORT_SYMBOL_GPL(sfp_link_up);
758ce0aa27fSRussell King
sfp_link_down(struct sfp_bus * bus)759ce0aa27fSRussell King void sfp_link_down(struct sfp_bus *bus)
760ce0aa27fSRussell King {
761ce0aa27fSRussell King const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus);
762ce0aa27fSRussell King
763ce0aa27fSRussell King if (ops && ops->link_down)
764ce0aa27fSRussell King ops->link_down(bus->upstream);
765ce0aa27fSRussell King }
766ce0aa27fSRussell King EXPORT_SYMBOL_GPL(sfp_link_down);
767ce0aa27fSRussell King
sfp_module_insert(struct sfp_bus * bus,const struct sfp_eeprom_id * id,const struct sfp_quirk * quirk)76823571c7bSRussell King (Oracle) int sfp_module_insert(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
76923571c7bSRussell King (Oracle) const struct sfp_quirk *quirk)
770ce0aa27fSRussell King {
771ce0aa27fSRussell King const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus);
772ce0aa27fSRussell King int ret = 0;
773ce0aa27fSRussell King
77423571c7bSRussell King (Oracle) bus->sfp_quirk = quirk;
775b34bb2cbSRussell King
776ce0aa27fSRussell King if (ops && ops->module_insert)
777ce0aa27fSRussell King ret = ops->module_insert(bus->upstream, id);
778ce0aa27fSRussell King
779ce0aa27fSRussell King return ret;
780ce0aa27fSRussell King }
781ce0aa27fSRussell King EXPORT_SYMBOL_GPL(sfp_module_insert);
782ce0aa27fSRussell King
sfp_module_remove(struct sfp_bus * bus)783ce0aa27fSRussell King void sfp_module_remove(struct sfp_bus *bus)
784ce0aa27fSRussell King {
785ce0aa27fSRussell King const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus);
786ce0aa27fSRussell King
787ce0aa27fSRussell King if (ops && ops->module_remove)
788ce0aa27fSRussell King ops->module_remove(bus->upstream);
789b34bb2cbSRussell King
790b34bb2cbSRussell King bus->sfp_quirk = NULL;
791ce0aa27fSRussell King }
792ce0aa27fSRussell King EXPORT_SYMBOL_GPL(sfp_module_remove);
793ce0aa27fSRussell King
sfp_module_start(struct sfp_bus * bus)79474c551caSRussell King int sfp_module_start(struct sfp_bus *bus)
79574c551caSRussell King {
79674c551caSRussell King const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus);
79774c551caSRussell King int ret = 0;
79874c551caSRussell King
79974c551caSRussell King if (ops && ops->module_start)
80074c551caSRussell King ret = ops->module_start(bus->upstream);
80174c551caSRussell King
80274c551caSRussell King return ret;
80374c551caSRussell King }
80474c551caSRussell King EXPORT_SYMBOL_GPL(sfp_module_start);
80574c551caSRussell King
sfp_module_stop(struct sfp_bus * bus)80674c551caSRussell King void sfp_module_stop(struct sfp_bus *bus)
80774c551caSRussell King {
80874c551caSRussell King const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus);
80974c551caSRussell King
81074c551caSRussell King if (ops && ops->module_stop)
81174c551caSRussell King ops->module_stop(bus->upstream);
81274c551caSRussell King }
81374c551caSRussell King EXPORT_SYMBOL_GPL(sfp_module_stop);
81474c551caSRussell King
sfp_socket_clear(struct sfp_bus * bus)815f20a4c46SRussell King static void sfp_socket_clear(struct sfp_bus *bus)
816f20a4c46SRussell King {
817f20a4c46SRussell King bus->sfp_dev = NULL;
818f20a4c46SRussell King bus->sfp = NULL;
819f20a4c46SRussell King bus->socket_ops = NULL;
820f20a4c46SRussell King }
821f20a4c46SRussell King
sfp_register_socket(struct device * dev,struct sfp * sfp,const struct sfp_socket_ops * ops)822ce0aa27fSRussell King struct sfp_bus *sfp_register_socket(struct device *dev, struct sfp *sfp,
823ce0aa27fSRussell King const struct sfp_socket_ops *ops)
824ce0aa27fSRussell King {
825c19bb000SRussell King struct sfp_bus *bus = sfp_bus_get(dev->fwnode);
826ce0aa27fSRussell King int ret = 0;
827ce0aa27fSRussell King
828ce0aa27fSRussell King if (bus) {
829ce0aa27fSRussell King rtnl_lock();
830ce0aa27fSRussell King bus->sfp_dev = dev;
831ce0aa27fSRussell King bus->sfp = sfp;
832ce0aa27fSRussell King bus->socket_ops = ops;
833ce0aa27fSRussell King
83454f70b3bSRussell King if (bus->upstream_ops) {
835ce0aa27fSRussell King ret = sfp_register_bus(bus);
836f20a4c46SRussell King if (ret)
837f20a4c46SRussell King sfp_socket_clear(bus);
838f20a4c46SRussell King }
839ce0aa27fSRussell King rtnl_unlock();
840ce0aa27fSRussell King }
841ce0aa27fSRussell King
842ce0aa27fSRussell King if (ret) {
843ce0aa27fSRussell King sfp_bus_put(bus);
844ce0aa27fSRussell King bus = NULL;
845ce0aa27fSRussell King }
846ce0aa27fSRussell King
847ce0aa27fSRussell King return bus;
848ce0aa27fSRussell King }
849ce0aa27fSRussell King EXPORT_SYMBOL_GPL(sfp_register_socket);
850ce0aa27fSRussell King
sfp_unregister_socket(struct sfp_bus * bus)851ce0aa27fSRussell King void sfp_unregister_socket(struct sfp_bus *bus)
852ce0aa27fSRussell King {
853ce0aa27fSRussell King rtnl_lock();
85454f70b3bSRussell King if (bus->upstream_ops)
855ce0aa27fSRussell King sfp_unregister_bus(bus);
856f20a4c46SRussell King sfp_socket_clear(bus);
857ce0aa27fSRussell King rtnl_unlock();
858ce0aa27fSRussell King
859ce0aa27fSRussell King sfp_bus_put(bus);
860ce0aa27fSRussell King }
861ce0aa27fSRussell King EXPORT_SYMBOL_GPL(sfp_unregister_socket);
862