treewide: Add SPDX license identifier for missed files
[linux-block.git] / drivers / net / phy / sfp-bus.c
CommitLineData
457c8996 1// SPDX-License-Identifier: GPL-2.0-only
ce0aa27f
RK
2#include <linux/export.h>
3#include <linux/kref.h>
4#include <linux/list.h>
5#include <linux/mutex.h>
6#include <linux/phylink.h>
7#include <linux/rtnetlink.h>
8#include <linux/slab.h>
9
10#include "sfp.h"
11
0a6fcd3f
RK
12/**
13 * struct sfp_bus - internal representation of a sfp bus
14 */
ce0aa27f 15struct sfp_bus {
0a6fcd3f 16 /* private: */
ce0aa27f
RK
17 struct kref kref;
18 struct list_head node;
c19bb000 19 struct fwnode_handle *fwnode;
ce0aa27f
RK
20
21 const struct sfp_socket_ops *socket_ops;
22 struct device *sfp_dev;
23 struct sfp *sfp;
24
25 const struct sfp_upstream_ops *upstream_ops;
26 void *upstream;
27 struct net_device *netdev;
28 struct phy_device *phydev;
29
30 bool registered;
31 bool started;
32};
33
0a6fcd3f
RK
34/**
35 * sfp_parse_port() - Parse the EEPROM base ID, setting the port type
36 * @bus: a pointer to the &struct sfp_bus structure for the sfp module
37 * @id: a pointer to the module's &struct sfp_eeprom_id
38 * @support: optional pointer to an array of unsigned long for the
39 * ethtool support mask
40 *
41 * Parse the EEPROM identification given in @id, and return one of
42 * %PORT_TP, %PORT_FIBRE or %PORT_OTHER. If @support is non-%NULL,
43 * also set the ethtool %ETHTOOL_LINK_MODE_xxx_BIT corresponding with
44 * the connector type.
45 *
46 * If the port type is not known, returns %PORT_OTHER.
47 */
ce0aa27f
RK
48int sfp_parse_port(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
49 unsigned long *support)
50{
51 int port;
52
53 /* port is the physical connector, set this from the connector field. */
54 switch (id->base.connector) {
55 case SFP_CONNECTOR_SC:
56 case SFP_CONNECTOR_FIBERJACK:
57 case SFP_CONNECTOR_LC:
58 case SFP_CONNECTOR_MT_RJ:
59 case SFP_CONNECTOR_MU:
60 case SFP_CONNECTOR_OPTICAL_PIGTAIL:
ce0aa27f
RK
61 port = PORT_FIBRE;
62 break;
63
64 case SFP_CONNECTOR_RJ45:
ce0aa27f
RK
65 port = PORT_TP;
66 break;
67
f10fcbcf
RK
68 case SFP_CONNECTOR_COPPER_PIGTAIL:
69 port = PORT_DA;
70 break;
71
ce0aa27f
RK
72 case SFP_CONNECTOR_UNSPEC:
73 if (id->base.e1000_base_t) {
ce0aa27f
RK
74 port = PORT_TP;
75 break;
76 }
77 /* fallthrough */
78 case SFP_CONNECTOR_SG: /* guess */
79 case SFP_CONNECTOR_MPO_1X12:
80 case SFP_CONNECTOR_MPO_2X16:
81 case SFP_CONNECTOR_HSSDC_II:
ce0aa27f
RK
82 case SFP_CONNECTOR_NOSEPARATE:
83 case SFP_CONNECTOR_MXC_2X16:
84 port = PORT_OTHER;
85 break;
86 default:
87 dev_warn(bus->sfp_dev, "SFP: unknown connector id 0x%02x\n",
88 id->base.connector);
89 port = PORT_OTHER;
90 break;
91 }
92
f10fcbcf
RK
93 if (support) {
94 switch (port) {
95 case PORT_FIBRE:
96 phylink_set(support, FIBRE);
97 break;
98
99 case PORT_TP:
100 phylink_set(support, TP);
101 break;
102 }
103 }
104
ce0aa27f
RK
105 return port;
106}
107EXPORT_SYMBOL_GPL(sfp_parse_port);
108
0a6fcd3f
RK
109/**
110 * sfp_parse_support() - Parse the eeprom id for supported link modes
111 * @bus: a pointer to the &struct sfp_bus structure for the sfp module
112 * @id: a pointer to the module's &struct sfp_eeprom_id
113 * @support: pointer to an array of unsigned long for the ethtool support mask
114 *
115 * Parse the EEPROM identification information and derive the supported
116 * ethtool link modes for the module.
117 */
ce0aa27f
RK
118void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
119 unsigned long *support)
120{
9962acf7 121 unsigned int br_min, br_nom, br_max;
03145864 122 __ETHTOOL_DECLARE_LINK_MODE_MASK(modes) = { 0, };
ce0aa27f 123
9962acf7
RK
124 /* Decode the bitrate information to MBd */
125 br_min = br_nom = br_max = 0;
126 if (id->base.br_nominal) {
127 if (id->base.br_nominal != 255) {
128 br_nom = id->base.br_nominal * 100;
52c5cd1b 129 br_min = br_nom - id->base.br_nominal * id->ext.br_min;
9962acf7
RK
130 br_max = br_nom + id->base.br_nominal * id->ext.br_max;
131 } else if (id->ext.br_max) {
132 br_nom = 250 * id->ext.br_max;
133 br_max = br_nom + br_nom * id->ext.br_min / 100;
134 br_min = br_nom - br_nom * id->ext.br_min / 100;
135 }
2b999ba8
AT
136
137 /* When using passive cables, in case neither BR,min nor BR,max
138 * are specified, set br_min to 0 as the nominal value is then
139 * used as the maximum.
140 */
141 if (br_min == br_max && id->base.sfp_ct_passive)
142 br_min = 0;
9962acf7
RK
143 }
144
ce0aa27f
RK
145 /* Set ethtool support from the compliance fields. */
146 if (id->base.e10g_base_sr)
03145864 147 phylink_set(modes, 10000baseSR_Full);
ce0aa27f 148 if (id->base.e10g_base_lr)
03145864 149 phylink_set(modes, 10000baseLR_Full);
ce0aa27f 150 if (id->base.e10g_base_lrm)
03145864 151 phylink_set(modes, 10000baseLRM_Full);
ce0aa27f 152 if (id->base.e10g_base_er)
03145864 153 phylink_set(modes, 10000baseER_Full);
ce0aa27f
RK
154 if (id->base.e1000_base_sx ||
155 id->base.e1000_base_lx ||
156 id->base.e1000_base_cx)
03145864 157 phylink_set(modes, 1000baseX_Full);
ce0aa27f 158 if (id->base.e1000_base_t) {
03145864
RK
159 phylink_set(modes, 1000baseT_Half);
160 phylink_set(modes, 1000baseT_Full);
ce0aa27f
RK
161 }
162
9962acf7
RK
163 /* 1000Base-PX or 1000Base-BX10 */
164 if ((id->base.e_base_px || id->base.e_base_bx10) &&
165 br_min <= 1300 && br_max >= 1200)
d7f7e001 166 phylink_set(modes, 1000baseX_Full);
9962acf7 167
f10fcbcf
RK
168 /* For active or passive cables, select the link modes
169 * based on the bit rates and the cable compliance bytes.
170 */
171 if ((id->base.sfp_ct_passive || id->base.sfp_ct_active) && br_nom) {
172 /* This may look odd, but some manufacturers use 12000MBd */
173 if (br_min <= 12000 && br_max >= 10300)
03145864 174 phylink_set(modes, 10000baseCR_Full);
f10fcbcf 175 if (br_min <= 3200 && br_max >= 3100)
03145864 176 phylink_set(modes, 2500baseX_Full);
f10fcbcf 177 if (br_min <= 1300 && br_max >= 1200)
03145864 178 phylink_set(modes, 1000baseX_Full);
f10fcbcf
RK
179 }
180 if (id->base.sfp_ct_passive) {
181 if (id->base.passive.sff8431_app_e)
03145864 182 phylink_set(modes, 10000baseCR_Full);
f10fcbcf
RK
183 }
184 if (id->base.sfp_ct_active) {
185 if (id->base.active.sff8431_app_e ||
186 id->base.active.sff8431_lim) {
03145864 187 phylink_set(modes, 10000baseCR_Full);
f10fcbcf
RK
188 }
189 }
190
ce0aa27f
RK
191 switch (id->base.extended_cc) {
192 case 0x00: /* Unspecified */
193 break;
194 case 0x02: /* 100Gbase-SR4 or 25Gbase-SR */
03145864
RK
195 phylink_set(modes, 100000baseSR4_Full);
196 phylink_set(modes, 25000baseSR_Full);
ce0aa27f
RK
197 break;
198 case 0x03: /* 100Gbase-LR4 or 25Gbase-LR */
199 case 0x04: /* 100Gbase-ER4 or 25Gbase-ER */
03145864 200 phylink_set(modes, 100000baseLR4_ER4_Full);
ce0aa27f
RK
201 break;
202 case 0x0b: /* 100Gbase-CR4 or 25Gbase-CR CA-L */
203 case 0x0c: /* 25Gbase-CR CA-S */
204 case 0x0d: /* 25Gbase-CR CA-N */
03145864
RK
205 phylink_set(modes, 100000baseCR4_Full);
206 phylink_set(modes, 25000baseCR_Full);
ce0aa27f
RK
207 break;
208 default:
209 dev_warn(bus->sfp_dev,
210 "Unknown/unsupported extended compliance code: 0x%02x\n",
211 id->base.extended_cc);
212 break;
213 }
214
215 /* For fibre channel SFP, derive possible BaseX modes */
216 if (id->base.fc_speed_100 ||
217 id->base.fc_speed_200 ||
218 id->base.fc_speed_400) {
219 if (id->base.br_nominal >= 31)
03145864 220 phylink_set(modes, 2500baseX_Full);
ce0aa27f 221 if (id->base.br_nominal >= 12)
03145864 222 phylink_set(modes, 1000baseX_Full);
ce0aa27f 223 }
03145864
RK
224
225 /* If we haven't discovered any modes that this module supports, try
226 * the encoding and bitrate to determine supported modes. Some BiDi
227 * modules (eg, 1310nm/1550nm) are not 1000BASE-BX compliant due to
228 * the differing wavelengths, so do not set any transceiver bits.
229 */
230 if (bitmap_empty(modes, __ETHTOOL_LINK_MODE_MASK_NBITS)) {
231 /* If the encoding and bit rate allows 1000baseX */
232 if (id->base.encoding == SFP_ENCODING_8B10B && br_nom &&
233 br_min <= 1300 && br_max >= 1200)
234 phylink_set(modes, 1000baseX_Full);
235 }
236
237 bitmap_or(support, support, modes, __ETHTOOL_LINK_MODE_MASK_NBITS);
238
239 phylink_set(support, Autoneg);
240 phylink_set(support, Pause);
241 phylink_set(support, Asym_Pause);
ce0aa27f
RK
242}
243EXPORT_SYMBOL_GPL(sfp_parse_support);
244
a9c79364
RK
245/**
246 * sfp_select_interface() - Select appropriate phy_interface_t mode
247 * @bus: a pointer to the &struct sfp_bus structure for the sfp module
248 * @id: a pointer to the module's &struct sfp_eeprom_id
249 * @link_modes: ethtool link modes mask
250 *
251 * Derive the phy_interface_t mode for the information found in the
252 * module's identifying EEPROM and the link modes mask. There is no
253 * standard or defined way to derive this information, so we decide
254 * based upon the link mode mask.
255 */
256phy_interface_t sfp_select_interface(struct sfp_bus *bus,
257 const struct sfp_eeprom_id *id,
258 unsigned long *link_modes)
259{
260 if (phylink_test(link_modes, 10000baseCR_Full) ||
261 phylink_test(link_modes, 10000baseSR_Full) ||
262 phylink_test(link_modes, 10000baseLR_Full) ||
263 phylink_test(link_modes, 10000baseLRM_Full) ||
264 phylink_test(link_modes, 10000baseER_Full))
265 return PHY_INTERFACE_MODE_10GKR;
266
267 if (phylink_test(link_modes, 2500baseX_Full))
268 return PHY_INTERFACE_MODE_2500BASEX;
269
270 if (id->base.e1000_base_t ||
271 id->base.e100_base_lx ||
272 id->base.e100_base_fx)
273 return PHY_INTERFACE_MODE_SGMII;
274
275 if (phylink_test(link_modes, 1000baseX_Full))
276 return PHY_INTERFACE_MODE_1000BASEX;
277
278 dev_warn(bus->sfp_dev, "Unable to ascertain link mode\n");
279
280 return PHY_INTERFACE_MODE_NA;
281}
282EXPORT_SYMBOL_GPL(sfp_select_interface);
283
ce0aa27f
RK
284static LIST_HEAD(sfp_buses);
285static DEFINE_MUTEX(sfp_mutex);
286
287static const struct sfp_upstream_ops *sfp_get_upstream_ops(struct sfp_bus *bus)
288{
289 return bus->registered ? bus->upstream_ops : NULL;
290}
291
c19bb000 292static struct sfp_bus *sfp_bus_get(struct fwnode_handle *fwnode)
ce0aa27f
RK
293{
294 struct sfp_bus *sfp, *new, *found = NULL;
295
296 new = kzalloc(sizeof(*new), GFP_KERNEL);
297
298 mutex_lock(&sfp_mutex);
299
300 list_for_each_entry(sfp, &sfp_buses, node) {
c19bb000 301 if (sfp->fwnode == fwnode) {
ce0aa27f
RK
302 kref_get(&sfp->kref);
303 found = sfp;
304 break;
305 }
306 }
307
308 if (!found && new) {
309 kref_init(&new->kref);
c19bb000 310 new->fwnode = fwnode;
ce0aa27f
RK
311 list_add(&new->node, &sfp_buses);
312 found = new;
313 new = NULL;
314 }
315
316 mutex_unlock(&sfp_mutex);
317
318 kfree(new);
319
320 return found;
321}
322
b6e67d6d 323static void sfp_bus_release(struct kref *kref)
ce0aa27f
RK
324{
325 struct sfp_bus *bus = container_of(kref, struct sfp_bus, kref);
326
327 list_del(&bus->node);
328 mutex_unlock(&sfp_mutex);
329 kfree(bus);
330}
331
332static void sfp_bus_put(struct sfp_bus *bus)
333{
334 kref_put_mutex(&bus->kref, sfp_bus_release, &sfp_mutex);
335}
336
337static int sfp_register_bus(struct sfp_bus *bus)
338{
339 const struct sfp_upstream_ops *ops = bus->upstream_ops;
340 int ret;
341
342 if (ops) {
343 if (ops->link_down)
344 ops->link_down(bus->upstream);
345 if (ops->connect_phy && bus->phydev) {
346 ret = ops->connect_phy(bus->upstream, bus->phydev);
347 if (ret)
348 return ret;
349 }
350 }
b5bfc21a 351 bus->socket_ops->attach(bus->sfp);
ce0aa27f
RK
352 if (bus->started)
353 bus->socket_ops->start(bus->sfp);
126d6848 354 bus->netdev->sfp_bus = bus;
ce0aa27f
RK
355 bus->registered = true;
356 return 0;
357}
358
359static void sfp_unregister_bus(struct sfp_bus *bus)
360{
361 const struct sfp_upstream_ops *ops = bus->upstream_ops;
362
126d6848 363 bus->netdev->sfp_bus = NULL;
ce0aa27f
RK
364 if (bus->registered) {
365 if (bus->started)
366 bus->socket_ops->stop(bus->sfp);
b5bfc21a 367 bus->socket_ops->detach(bus->sfp);
ce0aa27f
RK
368 if (bus->phydev && ops && ops->disconnect_phy)
369 ops->disconnect_phy(bus->upstream);
370 }
371 bus->registered = false;
372}
373
0a6fcd3f
RK
374/**
375 * sfp_get_module_info() - Get the ethtool_modinfo for a SFP module
376 * @bus: a pointer to the &struct sfp_bus structure for the sfp module
377 * @modinfo: a &struct ethtool_modinfo
378 *
379 * Fill in the type and eeprom_len parameters in @modinfo for a module on
380 * the sfp bus specified by @bus.
381 *
382 * Returns 0 on success or a negative errno number.
383 */
ce0aa27f
RK
384int sfp_get_module_info(struct sfp_bus *bus, struct ethtool_modinfo *modinfo)
385{
ce0aa27f
RK
386 return bus->socket_ops->module_info(bus->sfp, modinfo);
387}
388EXPORT_SYMBOL_GPL(sfp_get_module_info);
389
0a6fcd3f
RK
390/**
391 * sfp_get_module_eeprom() - Read the SFP module EEPROM
392 * @bus: a pointer to the &struct sfp_bus structure for the sfp module
393 * @ee: a &struct ethtool_eeprom
394 * @data: buffer to contain the EEPROM data (must be at least @ee->len bytes)
395 *
396 * Read the EEPROM as specified by the supplied @ee. See the documentation
397 * for &struct ethtool_eeprom for the region to be read.
398 *
399 * Returns 0 on success or a negative errno number.
400 */
ce0aa27f 401int sfp_get_module_eeprom(struct sfp_bus *bus, struct ethtool_eeprom *ee,
516b29ed 402 u8 *data)
ce0aa27f 403{
ce0aa27f
RK
404 return bus->socket_ops->module_eeprom(bus->sfp, ee, data);
405}
406EXPORT_SYMBOL_GPL(sfp_get_module_eeprom);
407
0a6fcd3f
RK
408/**
409 * sfp_upstream_start() - Inform the SFP that the network device is up
410 * @bus: a pointer to the &struct sfp_bus structure for the sfp module
411 *
412 * Inform the SFP socket that the network device is now up, so that the
413 * module can be enabled by allowing TX_DISABLE to be deasserted. This
414 * should be called from the network device driver's &struct net_device_ops
415 * ndo_open() method.
416 */
ce0aa27f
RK
417void sfp_upstream_start(struct sfp_bus *bus)
418{
419 if (bus->registered)
420 bus->socket_ops->start(bus->sfp);
421 bus->started = true;
422}
423EXPORT_SYMBOL_GPL(sfp_upstream_start);
424
0a6fcd3f
RK
425/**
426 * sfp_upstream_stop() - Inform the SFP that the network device is down
427 * @bus: a pointer to the &struct sfp_bus structure for the sfp module
428 *
429 * Inform the SFP socket that the network device is now up, so that the
430 * module can be disabled by asserting TX_DISABLE, disabling the laser
431 * in optical modules. This should be called from the network device
432 * driver's &struct net_device_ops ndo_stop() method.
433 */
ce0aa27f
RK
434void sfp_upstream_stop(struct sfp_bus *bus)
435{
436 if (bus->registered)
437 bus->socket_ops->stop(bus->sfp);
438 bus->started = false;
439}
440EXPORT_SYMBOL_GPL(sfp_upstream_stop);
441
f20a4c46
RK
442static void sfp_upstream_clear(struct sfp_bus *bus)
443{
444 bus->upstream_ops = NULL;
445 bus->upstream = NULL;
446 bus->netdev = NULL;
447}
448
0a6fcd3f
RK
449/**
450 * sfp_register_upstream() - Register the neighbouring device
4bb7df7d 451 * @fwnode: firmware node for the SFP bus
0a6fcd3f
RK
452 * @ndev: network device associated with the interface
453 * @upstream: the upstream private data
454 * @ops: the upstream's &struct sfp_upstream_ops
455 *
456 * Register the upstream device (eg, PHY) with the SFP bus. MAC drivers
457 * should use phylink, which will call this function for them. Returns
458 * a pointer to the allocated &struct sfp_bus.
459 *
460 * On error, returns %NULL.
461 */
c19bb000 462struct sfp_bus *sfp_register_upstream(struct fwnode_handle *fwnode,
516b29ed
FF
463 struct net_device *ndev, void *upstream,
464 const struct sfp_upstream_ops *ops)
ce0aa27f 465{
c19bb000 466 struct sfp_bus *bus = sfp_bus_get(fwnode);
ce0aa27f
RK
467 int ret = 0;
468
469 if (bus) {
470 rtnl_lock();
471 bus->upstream_ops = ops;
472 bus->upstream = upstream;
473 bus->netdev = ndev;
474
f20a4c46 475 if (bus->sfp) {
ce0aa27f 476 ret = sfp_register_bus(bus);
f20a4c46
RK
477 if (ret)
478 sfp_upstream_clear(bus);
479 }
ce0aa27f
RK
480 rtnl_unlock();
481 }
482
483 if (ret) {
484 sfp_bus_put(bus);
485 bus = NULL;
486 }
487
488 return bus;
489}
490EXPORT_SYMBOL_GPL(sfp_register_upstream);
491
0a6fcd3f
RK
492/**
493 * sfp_unregister_upstream() - Unregister sfp bus
494 * @bus: a pointer to the &struct sfp_bus structure for the sfp module
495 *
496 * Unregister a previously registered upstream connection for the SFP
497 * module. @bus is returned from sfp_register_upstream().
498 */
ce0aa27f
RK
499void sfp_unregister_upstream(struct sfp_bus *bus)
500{
501 rtnl_lock();
0b2122e4
RK
502 if (bus->sfp)
503 sfp_unregister_bus(bus);
f20a4c46 504 sfp_upstream_clear(bus);
ce0aa27f
RK
505 rtnl_unlock();
506
507 sfp_bus_put(bus);
508}
509EXPORT_SYMBOL_GPL(sfp_unregister_upstream);
510
ce0aa27f
RK
511/* Socket driver entry points */
512int sfp_add_phy(struct sfp_bus *bus, struct phy_device *phydev)
513{
514 const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus);
515 int ret = 0;
516
517 if (ops && ops->connect_phy)
518 ret = ops->connect_phy(bus->upstream, phydev);
519
520 if (ret == 0)
521 bus->phydev = phydev;
522
523 return ret;
524}
525EXPORT_SYMBOL_GPL(sfp_add_phy);
526
527void sfp_remove_phy(struct sfp_bus *bus)
528{
529 const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus);
530
531 if (ops && ops->disconnect_phy)
532 ops->disconnect_phy(bus->upstream);
533 bus->phydev = NULL;
534}
535EXPORT_SYMBOL_GPL(sfp_remove_phy);
536
ce0aa27f
RK
537void sfp_link_up(struct sfp_bus *bus)
538{
539 const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus);
540
541 if (ops && ops->link_up)
542 ops->link_up(bus->upstream);
543}
544EXPORT_SYMBOL_GPL(sfp_link_up);
545
546void sfp_link_down(struct sfp_bus *bus)
547{
548 const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus);
549
550 if (ops && ops->link_down)
551 ops->link_down(bus->upstream);
552}
553EXPORT_SYMBOL_GPL(sfp_link_down);
554
555int sfp_module_insert(struct sfp_bus *bus, const struct sfp_eeprom_id *id)
556{
557 const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus);
558 int ret = 0;
559
560 if (ops && ops->module_insert)
561 ret = ops->module_insert(bus->upstream, id);
562
563 return ret;
564}
565EXPORT_SYMBOL_GPL(sfp_module_insert);
566
567void sfp_module_remove(struct sfp_bus *bus)
568{
569 const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus);
570
571 if (ops && ops->module_remove)
572 ops->module_remove(bus->upstream);
573}
574EXPORT_SYMBOL_GPL(sfp_module_remove);
575
f20a4c46
RK
576static void sfp_socket_clear(struct sfp_bus *bus)
577{
578 bus->sfp_dev = NULL;
579 bus->sfp = NULL;
580 bus->socket_ops = NULL;
581}
582
ce0aa27f
RK
583struct sfp_bus *sfp_register_socket(struct device *dev, struct sfp *sfp,
584 const struct sfp_socket_ops *ops)
585{
c19bb000 586 struct sfp_bus *bus = sfp_bus_get(dev->fwnode);
ce0aa27f
RK
587 int ret = 0;
588
589 if (bus) {
590 rtnl_lock();
591 bus->sfp_dev = dev;
592 bus->sfp = sfp;
593 bus->socket_ops = ops;
594
f20a4c46 595 if (bus->netdev) {
ce0aa27f 596 ret = sfp_register_bus(bus);
f20a4c46
RK
597 if (ret)
598 sfp_socket_clear(bus);
599 }
ce0aa27f
RK
600 rtnl_unlock();
601 }
602
603 if (ret) {
604 sfp_bus_put(bus);
605 bus = NULL;
606 }
607
608 return bus;
609}
610EXPORT_SYMBOL_GPL(sfp_register_socket);
611
612void sfp_unregister_socket(struct sfp_bus *bus)
613{
614 rtnl_lock();
0b2122e4
RK
615 if (bus->netdev)
616 sfp_unregister_bus(bus);
f20a4c46 617 sfp_socket_clear(bus);
ce0aa27f
RK
618 rtnl_unlock();
619
620 sfp_bus_put(bus);
621}
622EXPORT_SYMBOL_GPL(sfp_unregister_socket);