Blame view

drivers/net/phy/sfp-bus.c 16.1 KB
ce0aa27ff   Russell King   sfp: add sfp-bus ...
1
2
3
4
5
6
7
8
9
  #include <linux/export.h>
  #include <linux/kref.h>
  #include <linux/list.h>
  #include <linux/mutex.h>
  #include <linux/phylink.h>
  #include <linux/rtnetlink.h>
  #include <linux/slab.h>
  
  #include "sfp.h"
0a6fcd3fc   Russell King   sfp: add document...
10
11
12
  /**
   * struct sfp_bus - internal representation of a sfp bus
   */
ce0aa27ff   Russell King   sfp: add sfp-bus ...
13
  struct sfp_bus {
0a6fcd3fc   Russell King   sfp: add document...
14
  	/* private: */
ce0aa27ff   Russell King   sfp: add sfp-bus ...
15
16
  	struct kref kref;
  	struct list_head node;
c19bb0007   Russell King   sfp: convert to f...
17
  	struct fwnode_handle *fwnode;
ce0aa27ff   Russell King   sfp: add sfp-bus ...
18
19
20
21
22
23
24
25
26
27
28
29
30
  
  	const struct sfp_socket_ops *socket_ops;
  	struct device *sfp_dev;
  	struct sfp *sfp;
  
  	const struct sfp_upstream_ops *upstream_ops;
  	void *upstream;
  	struct net_device *netdev;
  	struct phy_device *phydev;
  
  	bool registered;
  	bool started;
  };
0a6fcd3fc   Russell King   sfp: add document...
31
32
33
34
35
36
37
38
39
40
41
42
43
44
  /**
   * sfp_parse_port() - Parse the EEPROM base ID, setting the port type
   * @bus: a pointer to the &struct sfp_bus structure for the sfp module
   * @id: a pointer to the module's &struct sfp_eeprom_id
   * @support: optional pointer to an array of unsigned long for the
   *   ethtool support mask
   *
   * Parse the EEPROM identification given in @id, and return one of
   * %PORT_TP, %PORT_FIBRE or %PORT_OTHER. If @support is non-%NULL,
   * also set the ethtool %ETHTOOL_LINK_MODE_xxx_BIT corresponding with
   * the connector type.
   *
   * If the port type is not known, returns %PORT_OTHER.
   */
ce0aa27ff   Russell King   sfp: add sfp-bus ...
45
46
47
48
49
50
51
52
53
54
55
56
57
  int sfp_parse_port(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
  		   unsigned long *support)
  {
  	int port;
  
  	/* port is the physical connector, set this from the connector field. */
  	switch (id->base.connector) {
  	case SFP_CONNECTOR_SC:
  	case SFP_CONNECTOR_FIBERJACK:
  	case SFP_CONNECTOR_LC:
  	case SFP_CONNECTOR_MT_RJ:
  	case SFP_CONNECTOR_MU:
  	case SFP_CONNECTOR_OPTICAL_PIGTAIL:
ce0aa27ff   Russell King   sfp: add sfp-bus ...
58
59
60
61
  		port = PORT_FIBRE;
  		break;
  
  	case SFP_CONNECTOR_RJ45:
ce0aa27ff   Russell King   sfp: add sfp-bus ...
62
63
  		port = PORT_TP;
  		break;
f10fcbcf9   Russell King   sfp: improve supp...
64
65
66
  	case SFP_CONNECTOR_COPPER_PIGTAIL:
  		port = PORT_DA;
  		break;
ce0aa27ff   Russell King   sfp: add sfp-bus ...
67
68
  	case SFP_CONNECTOR_UNSPEC:
  		if (id->base.e1000_base_t) {
ce0aa27ff   Russell King   sfp: add sfp-bus ...
69
70
71
72
73
74
75
76
  			port = PORT_TP;
  			break;
  		}
  		/* fallthrough */
  	case SFP_CONNECTOR_SG: /* guess */
  	case SFP_CONNECTOR_MPO_1X12:
  	case SFP_CONNECTOR_MPO_2X16:
  	case SFP_CONNECTOR_HSSDC_II:
ce0aa27ff   Russell King   sfp: add sfp-bus ...
77
78
79
80
81
82
83
84
85
86
87
  	case SFP_CONNECTOR_NOSEPARATE:
  	case SFP_CONNECTOR_MXC_2X16:
  		port = PORT_OTHER;
  		break;
  	default:
  		dev_warn(bus->sfp_dev, "SFP: unknown connector id 0x%02x
  ",
  			 id->base.connector);
  		port = PORT_OTHER;
  		break;
  	}
f10fcbcf9   Russell King   sfp: improve supp...
88
89
90
91
92
93
94
95
96
97
98
  	if (support) {
  		switch (port) {
  		case PORT_FIBRE:
  			phylink_set(support, FIBRE);
  			break;
  
  		case PORT_TP:
  			phylink_set(support, TP);
  			break;
  		}
  	}
ce0aa27ff   Russell King   sfp: add sfp-bus ...
99
100
101
  	return port;
  }
  EXPORT_SYMBOL_GPL(sfp_parse_port);
0a6fcd3fc   Russell King   sfp: add document...
102
  /**
0a6fcd3fc   Russell King   sfp: add document...
103
104
105
106
107
108
109
110
   * sfp_parse_support() - Parse the eeprom id for supported link modes
   * @bus: a pointer to the &struct sfp_bus structure for the sfp module
   * @id: a pointer to the module's &struct sfp_eeprom_id
   * @support: pointer to an array of unsigned long for the ethtool support mask
   *
   * Parse the EEPROM identification information and derive the supported
   * ethtool link modes for the module.
   */
ce0aa27ff   Russell King   sfp: add sfp-bus ...
111
112
113
  void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id,
  		       unsigned long *support)
  {
9962acf7f   Russell King   sfp: add support ...
114
  	unsigned int br_min, br_nom, br_max;
03145864b   Russell King   sfp: support 1G B...
115
  	__ETHTOOL_DECLARE_LINK_MODE_MASK(modes) = { 0, };
ce0aa27ff   Russell King   sfp: add sfp-bus ...
116

9962acf7f   Russell King   sfp: add support ...
117
118
119
120
121
  	/* Decode the bitrate information to MBd */
  	br_min = br_nom = br_max = 0;
  	if (id->base.br_nominal) {
  		if (id->base.br_nominal != 255) {
  			br_nom = id->base.br_nominal * 100;
52c5cd1bf   Antoine Tenart   net: phy: sfp: fi...
122
  			br_min = br_nom - id->base.br_nominal * id->ext.br_min;
9962acf7f   Russell King   sfp: add support ...
123
124
125
126
127
128
  			br_max = br_nom + id->base.br_nominal * id->ext.br_max;
  		} else if (id->ext.br_max) {
  			br_nom = 250 * id->ext.br_max;
  			br_max = br_nom + br_nom * id->ext.br_min / 100;
  			br_min = br_nom - br_nom * id->ext.br_min / 100;
  		}
2b999ba89   Antoine Tenart   net: phy: sfp: ha...
129
130
131
132
133
134
135
  
  		/* When using passive cables, in case neither BR,min nor BR,max
  		 * are specified, set br_min to 0 as the nominal value is then
  		 * used as the maximum.
  		 */
  		if (br_min == br_max && id->base.sfp_ct_passive)
  			br_min = 0;
9962acf7f   Russell King   sfp: add support ...
136
  	}
ce0aa27ff   Russell King   sfp: add sfp-bus ...
137
138
  	/* Set ethtool support from the compliance fields. */
  	if (id->base.e10g_base_sr)
03145864b   Russell King   sfp: support 1G B...
139
  		phylink_set(modes, 10000baseSR_Full);
ce0aa27ff   Russell King   sfp: add sfp-bus ...
140
  	if (id->base.e10g_base_lr)
03145864b   Russell King   sfp: support 1G B...
141
  		phylink_set(modes, 10000baseLR_Full);
ce0aa27ff   Russell King   sfp: add sfp-bus ...
142
  	if (id->base.e10g_base_lrm)
03145864b   Russell King   sfp: support 1G B...
143
  		phylink_set(modes, 10000baseLRM_Full);
ce0aa27ff   Russell King   sfp: add sfp-bus ...
144
  	if (id->base.e10g_base_er)
03145864b   Russell King   sfp: support 1G B...
145
  		phylink_set(modes, 10000baseER_Full);
ce0aa27ff   Russell King   sfp: add sfp-bus ...
146
147
148
  	if (id->base.e1000_base_sx ||
  	    id->base.e1000_base_lx ||
  	    id->base.e1000_base_cx)
03145864b   Russell King   sfp: support 1G B...
149
  		phylink_set(modes, 1000baseX_Full);
ce0aa27ff   Russell King   sfp: add sfp-bus ...
150
  	if (id->base.e1000_base_t) {
03145864b   Russell King   sfp: support 1G B...
151
152
  		phylink_set(modes, 1000baseT_Half);
  		phylink_set(modes, 1000baseT_Full);
ce0aa27ff   Russell King   sfp: add sfp-bus ...
153
  	}
9962acf7f   Russell King   sfp: add support ...
154
155
156
  	/* 1000Base-PX or 1000Base-BX10 */
  	if ((id->base.e_base_px || id->base.e_base_bx10) &&
  	    br_min <= 1300 && br_max >= 1200)
4aa6d46d1   Baruch Siach   net: phy: sfp: co...
157
  		phylink_set(modes, 1000baseX_Full);
9962acf7f   Russell King   sfp: add support ...
158

f10fcbcf9   Russell King   sfp: improve supp...
159
160
161
162
163
164
  	/* For active or passive cables, select the link modes
  	 * based on the bit rates and the cable compliance bytes.
  	 */
  	if ((id->base.sfp_ct_passive || id->base.sfp_ct_active) && br_nom) {
  		/* This may look odd, but some manufacturers use 12000MBd */
  		if (br_min <= 12000 && br_max >= 10300)
03145864b   Russell King   sfp: support 1G B...
165
  			phylink_set(modes, 10000baseCR_Full);
f10fcbcf9   Russell King   sfp: improve supp...
166
  		if (br_min <= 3200 && br_max >= 3100)
03145864b   Russell King   sfp: support 1G B...
167
  			phylink_set(modes, 2500baseX_Full);
f10fcbcf9   Russell King   sfp: improve supp...
168
  		if (br_min <= 1300 && br_max >= 1200)
03145864b   Russell King   sfp: support 1G B...
169
  			phylink_set(modes, 1000baseX_Full);
f10fcbcf9   Russell King   sfp: improve supp...
170
171
172
  	}
  	if (id->base.sfp_ct_passive) {
  		if (id->base.passive.sff8431_app_e)
03145864b   Russell King   sfp: support 1G B...
173
  			phylink_set(modes, 10000baseCR_Full);
f10fcbcf9   Russell King   sfp: improve supp...
174
175
176
177
  	}
  	if (id->base.sfp_ct_active) {
  		if (id->base.active.sff8431_app_e ||
  		    id->base.active.sff8431_lim) {
03145864b   Russell King   sfp: support 1G B...
178
  			phylink_set(modes, 10000baseCR_Full);
f10fcbcf9   Russell King   sfp: improve supp...
179
180
  		}
  	}
ce0aa27ff   Russell King   sfp: add sfp-bus ...
181
182
183
184
  	switch (id->base.extended_cc) {
  	case 0x00: /* Unspecified */
  		break;
  	case 0x02: /* 100Gbase-SR4 or 25Gbase-SR */
03145864b   Russell King   sfp: support 1G B...
185
186
  		phylink_set(modes, 100000baseSR4_Full);
  		phylink_set(modes, 25000baseSR_Full);
ce0aa27ff   Russell King   sfp: add sfp-bus ...
187
188
189
  		break;
  	case 0x03: /* 100Gbase-LR4 or 25Gbase-LR */
  	case 0x04: /* 100Gbase-ER4 or 25Gbase-ER */
03145864b   Russell King   sfp: support 1G B...
190
  		phylink_set(modes, 100000baseLR4_ER4_Full);
ce0aa27ff   Russell King   sfp: add sfp-bus ...
191
192
193
194
  		break;
  	case 0x0b: /* 100Gbase-CR4 or 25Gbase-CR CA-L */
  	case 0x0c: /* 25Gbase-CR CA-S */
  	case 0x0d: /* 25Gbase-CR CA-N */
03145864b   Russell King   sfp: support 1G B...
195
196
  		phylink_set(modes, 100000baseCR4_Full);
  		phylink_set(modes, 25000baseCR_Full);
ce0aa27ff   Russell King   sfp: add sfp-bus ...
197
198
199
200
201
202
203
204
205
206
207
208
209
210
  		break;
  	default:
  		dev_warn(bus->sfp_dev,
  			 "Unknown/unsupported extended compliance code: 0x%02x
  ",
  			 id->base.extended_cc);
  		break;
  	}
  
  	/* For fibre channel SFP, derive possible BaseX modes */
  	if (id->base.fc_speed_100 ||
  	    id->base.fc_speed_200 ||
  	    id->base.fc_speed_400) {
  		if (id->base.br_nominal >= 31)
03145864b   Russell King   sfp: support 1G B...
211
  			phylink_set(modes, 2500baseX_Full);
ce0aa27ff   Russell King   sfp: add sfp-bus ...
212
  		if (id->base.br_nominal >= 12)
03145864b   Russell King   sfp: support 1G B...
213
  			phylink_set(modes, 1000baseX_Full);
ce0aa27ff   Russell King   sfp: add sfp-bus ...
214
  	}
03145864b   Russell King   sfp: support 1G B...
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
  
  	/* If we haven't discovered any modes that this module supports, try
  	 * the encoding and bitrate to determine supported modes. Some BiDi
  	 * modules (eg, 1310nm/1550nm) are not 1000BASE-BX compliant due to
  	 * the differing wavelengths, so do not set any transceiver bits.
  	 */
  	if (bitmap_empty(modes, __ETHTOOL_LINK_MODE_MASK_NBITS)) {
  		/* If the encoding and bit rate allows 1000baseX */
  		if (id->base.encoding == SFP_ENCODING_8B10B && br_nom &&
  		    br_min <= 1300 && br_max >= 1200)
  			phylink_set(modes, 1000baseX_Full);
  	}
  
  	bitmap_or(support, support, modes, __ETHTOOL_LINK_MODE_MASK_NBITS);
  
  	phylink_set(support, Autoneg);
  	phylink_set(support, Pause);
  	phylink_set(support, Asym_Pause);
ce0aa27ff   Russell King   sfp: add sfp-bus ...
233
234
  }
  EXPORT_SYMBOL_GPL(sfp_parse_support);
a9c79364d   Russell King   phylink,sfp: nego...
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
  /**
   * sfp_select_interface() - Select appropriate phy_interface_t mode
   * @bus: a pointer to the &struct sfp_bus structure for the sfp module
   * @id: a pointer to the module's &struct sfp_eeprom_id
   * @link_modes: ethtool link modes mask
   *
   * Derive the phy_interface_t mode for the information found in the
   * module's identifying EEPROM and the link modes mask. There is no
   * standard or defined way to derive this information, so we decide
   * based upon the link mode mask.
   */
  phy_interface_t sfp_select_interface(struct sfp_bus *bus,
  				     const struct sfp_eeprom_id *id,
  				     unsigned long *link_modes)
  {
  	if (phylink_test(link_modes, 10000baseCR_Full) ||
  	    phylink_test(link_modes, 10000baseSR_Full) ||
  	    phylink_test(link_modes, 10000baseLR_Full) ||
  	    phylink_test(link_modes, 10000baseLRM_Full) ||
  	    phylink_test(link_modes, 10000baseER_Full))
  		return PHY_INTERFACE_MODE_10GKR;
  
  	if (phylink_test(link_modes, 2500baseX_Full))
  		return PHY_INTERFACE_MODE_2500BASEX;
  
  	if (id->base.e1000_base_t ||
  	    id->base.e100_base_lx ||
  	    id->base.e100_base_fx)
  		return PHY_INTERFACE_MODE_SGMII;
  
  	if (phylink_test(link_modes, 1000baseX_Full))
  		return PHY_INTERFACE_MODE_1000BASEX;
  
  	dev_warn(bus->sfp_dev, "Unable to ascertain link mode
  ");
  
  	return PHY_INTERFACE_MODE_NA;
  }
  EXPORT_SYMBOL_GPL(sfp_select_interface);
ce0aa27ff   Russell King   sfp: add sfp-bus ...
274
275
276
277
278
279
280
  static LIST_HEAD(sfp_buses);
  static DEFINE_MUTEX(sfp_mutex);
  
  static const struct sfp_upstream_ops *sfp_get_upstream_ops(struct sfp_bus *bus)
  {
  	return bus->registered ? bus->upstream_ops : NULL;
  }
c19bb0007   Russell King   sfp: convert to f...
281
  static struct sfp_bus *sfp_bus_get(struct fwnode_handle *fwnode)
ce0aa27ff   Russell King   sfp: add sfp-bus ...
282
283
284
285
286
287
288
289
  {
  	struct sfp_bus *sfp, *new, *found = NULL;
  
  	new = kzalloc(sizeof(*new), GFP_KERNEL);
  
  	mutex_lock(&sfp_mutex);
  
  	list_for_each_entry(sfp, &sfp_buses, node) {
c19bb0007   Russell King   sfp: convert to f...
290
  		if (sfp->fwnode == fwnode) {
ce0aa27ff   Russell King   sfp: add sfp-bus ...
291
292
293
294
295
296
297
298
  			kref_get(&sfp->kref);
  			found = sfp;
  			break;
  		}
  	}
  
  	if (!found && new) {
  		kref_init(&new->kref);
c19bb0007   Russell King   sfp: convert to f...
299
  		new->fwnode = fwnode;
ce0aa27ff   Russell King   sfp: add sfp-bus ...
300
301
302
303
304
305
306
307
308
309
310
  		list_add(&new->node, &sfp_buses);
  		found = new;
  		new = NULL;
  	}
  
  	mutex_unlock(&sfp_mutex);
  
  	kfree(new);
  
  	return found;
  }
b6e67d6d4   Russell King   sfp: fix sparse w...
311
  static void sfp_bus_release(struct kref *kref)
ce0aa27ff   Russell King   sfp: add sfp-bus ...
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
  {
  	struct sfp_bus *bus = container_of(kref, struct sfp_bus, kref);
  
  	list_del(&bus->node);
  	mutex_unlock(&sfp_mutex);
  	kfree(bus);
  }
  
  static void sfp_bus_put(struct sfp_bus *bus)
  {
  	kref_put_mutex(&bus->kref, sfp_bus_release, &sfp_mutex);
  }
  
  static int sfp_register_bus(struct sfp_bus *bus)
  {
  	const struct sfp_upstream_ops *ops = bus->upstream_ops;
  	int ret;
  
  	if (ops) {
  		if (ops->link_down)
  			ops->link_down(bus->upstream);
  		if (ops->connect_phy && bus->phydev) {
  			ret = ops->connect_phy(bus->upstream, bus->phydev);
  			if (ret)
  				return ret;
  		}
  	}
9e5cc54ea   Russell King   net: sfp: do not ...
339
  	bus->socket_ops->attach(bus->sfp);
ce0aa27ff   Russell King   sfp: add sfp-bus ...
340
341
  	if (bus->started)
  		bus->socket_ops->start(bus->sfp);
126d6848e   Russell King   sfp: fix oops wit...
342
  	bus->netdev->sfp_bus = bus;
ce0aa27ff   Russell King   sfp: add sfp-bus ...
343
344
345
346
347
348
349
  	bus->registered = true;
  	return 0;
  }
  
  static void sfp_unregister_bus(struct sfp_bus *bus)
  {
  	const struct sfp_upstream_ops *ops = bus->upstream_ops;
126d6848e   Russell King   sfp: fix oops wit...
350
  	bus->netdev->sfp_bus = NULL;
ce0aa27ff   Russell King   sfp: add sfp-bus ...
351
352
353
  	if (bus->registered) {
  		if (bus->started)
  			bus->socket_ops->stop(bus->sfp);
9e5cc54ea   Russell King   net: sfp: do not ...
354
  		bus->socket_ops->detach(bus->sfp);
ce0aa27ff   Russell King   sfp: add sfp-bus ...
355
356
357
358
359
  		if (bus->phydev && ops && ops->disconnect_phy)
  			ops->disconnect_phy(bus->upstream);
  	}
  	bus->registered = false;
  }
0a6fcd3fc   Russell King   sfp: add document...
360
361
362
363
364
365
366
367
368
369
  /**
   * sfp_get_module_info() - Get the ethtool_modinfo for a SFP module
   * @bus: a pointer to the &struct sfp_bus structure for the sfp module
   * @modinfo: a &struct ethtool_modinfo
   *
   * Fill in the type and eeprom_len parameters in @modinfo for a module on
   * the sfp bus specified by @bus.
   *
   * Returns 0 on success or a negative errno number.
   */
ce0aa27ff   Russell King   sfp: add sfp-bus ...
370
371
  int sfp_get_module_info(struct sfp_bus *bus, struct ethtool_modinfo *modinfo)
  {
ce0aa27ff   Russell King   sfp: add sfp-bus ...
372
373
374
  	return bus->socket_ops->module_info(bus->sfp, modinfo);
  }
  EXPORT_SYMBOL_GPL(sfp_get_module_info);
0a6fcd3fc   Russell King   sfp: add document...
375
376
377
378
379
380
381
382
383
384
385
  /**
   * sfp_get_module_eeprom() - Read the SFP module EEPROM
   * @bus: a pointer to the &struct sfp_bus structure for the sfp module
   * @ee: a &struct ethtool_eeprom
   * @data: buffer to contain the EEPROM data (must be at least @ee->len bytes)
   *
   * Read the EEPROM as specified by the supplied @ee. See the documentation
   * for &struct ethtool_eeprom for the region to be read.
   *
   * Returns 0 on success or a negative errno number.
   */
ce0aa27ff   Russell King   sfp: add sfp-bus ...
386
  int sfp_get_module_eeprom(struct sfp_bus *bus, struct ethtool_eeprom *ee,
516b29edc   Florian Fainelli   net: phy: Cosmeti...
387
  			  u8 *data)
ce0aa27ff   Russell King   sfp: add sfp-bus ...
388
  {
ce0aa27ff   Russell King   sfp: add sfp-bus ...
389
390
391
  	return bus->socket_ops->module_eeprom(bus->sfp, ee, data);
  }
  EXPORT_SYMBOL_GPL(sfp_get_module_eeprom);
0a6fcd3fc   Russell King   sfp: add document...
392
393
394
395
396
397
398
399
400
  /**
   * sfp_upstream_start() - Inform the SFP that the network device is up
   * @bus: a pointer to the &struct sfp_bus structure for the sfp module
   *
   * Inform the SFP socket that the network device is now up, so that the
   * module can be enabled by allowing TX_DISABLE to be deasserted. This
   * should be called from the network device driver's &struct net_device_ops
   * ndo_open() method.
   */
ce0aa27ff   Russell King   sfp: add sfp-bus ...
401
402
403
404
405
406
407
  void sfp_upstream_start(struct sfp_bus *bus)
  {
  	if (bus->registered)
  		bus->socket_ops->start(bus->sfp);
  	bus->started = true;
  }
  EXPORT_SYMBOL_GPL(sfp_upstream_start);
0a6fcd3fc   Russell King   sfp: add document...
408
409
410
411
412
413
414
415
416
  /**
   * sfp_upstream_stop() - Inform the SFP that the network device is down
   * @bus: a pointer to the &struct sfp_bus structure for the sfp module
   *
   * Inform the SFP socket that the network device is now up, so that the
   * module can be disabled by asserting TX_DISABLE, disabling the laser
   * in optical modules. This should be called from the network device
   * driver's &struct net_device_ops ndo_stop() method.
   */
ce0aa27ff   Russell King   sfp: add sfp-bus ...
417
418
419
420
421
422
423
  void sfp_upstream_stop(struct sfp_bus *bus)
  {
  	if (bus->registered)
  		bus->socket_ops->stop(bus->sfp);
  	bus->started = false;
  }
  EXPORT_SYMBOL_GPL(sfp_upstream_stop);
f20a4c46b   Russell King   sfp: ensure we cl...
424
425
426
427
428
429
  static void sfp_upstream_clear(struct sfp_bus *bus)
  {
  	bus->upstream_ops = NULL;
  	bus->upstream = NULL;
  	bus->netdev = NULL;
  }
0a6fcd3fc   Russell King   sfp: add document...
430
431
  /**
   * sfp_register_upstream() - Register the neighbouring device
4bb7df7d6   Florian Fainelli   net: phy: sfp: Fi...
432
   * @fwnode: firmware node for the SFP bus
0a6fcd3fc   Russell King   sfp: add document...
433
434
435
436
437
438
439
440
441
442
   * @ndev: network device associated with the interface
   * @upstream: the upstream private data
   * @ops: the upstream's &struct sfp_upstream_ops
   *
   * Register the upstream device (eg, PHY) with the SFP bus. MAC drivers
   * should use phylink, which will call this function for them. Returns
   * a pointer to the allocated &struct sfp_bus.
   *
   * On error, returns %NULL.
   */
c19bb0007   Russell King   sfp: convert to f...
443
  struct sfp_bus *sfp_register_upstream(struct fwnode_handle *fwnode,
516b29edc   Florian Fainelli   net: phy: Cosmeti...
444
445
  				      struct net_device *ndev, void *upstream,
  				      const struct sfp_upstream_ops *ops)
ce0aa27ff   Russell King   sfp: add sfp-bus ...
446
  {
c19bb0007   Russell King   sfp: convert to f...
447
  	struct sfp_bus *bus = sfp_bus_get(fwnode);
ce0aa27ff   Russell King   sfp: add sfp-bus ...
448
449
450
451
452
453
454
  	int ret = 0;
  
  	if (bus) {
  		rtnl_lock();
  		bus->upstream_ops = ops;
  		bus->upstream = upstream;
  		bus->netdev = ndev;
f20a4c46b   Russell King   sfp: ensure we cl...
455
  		if (bus->sfp) {
ce0aa27ff   Russell King   sfp: add sfp-bus ...
456
  			ret = sfp_register_bus(bus);
f20a4c46b   Russell King   sfp: ensure we cl...
457
458
459
  			if (ret)
  				sfp_upstream_clear(bus);
  		}
ce0aa27ff   Russell King   sfp: add sfp-bus ...
460
461
462
463
464
465
466
467
468
469
470
  		rtnl_unlock();
  	}
  
  	if (ret) {
  		sfp_bus_put(bus);
  		bus = NULL;
  	}
  
  	return bus;
  }
  EXPORT_SYMBOL_GPL(sfp_register_upstream);
0a6fcd3fc   Russell King   sfp: add document...
471
472
473
474
475
476
477
  /**
   * sfp_unregister_upstream() - Unregister sfp bus
   * @bus: a pointer to the &struct sfp_bus structure for the sfp module
   *
   * Unregister a previously registered upstream connection for the SFP
   * module. @bus is returned from sfp_register_upstream().
   */
ce0aa27ff   Russell King   sfp: add sfp-bus ...
478
479
480
  void sfp_unregister_upstream(struct sfp_bus *bus)
  {
  	rtnl_lock();
0b2122e49   Russell King   sfp: fix sfp-bus ...
481
482
  	if (bus->sfp)
  		sfp_unregister_bus(bus);
f20a4c46b   Russell King   sfp: ensure we cl...
483
  	sfp_upstream_clear(bus);
ce0aa27ff   Russell King   sfp: add sfp-bus ...
484
485
486
487
488
  	rtnl_unlock();
  
  	sfp_bus_put(bus);
  }
  EXPORT_SYMBOL_GPL(sfp_unregister_upstream);
ce0aa27ff   Russell King   sfp: add sfp-bus ...
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
  /* Socket driver entry points */
  int sfp_add_phy(struct sfp_bus *bus, struct phy_device *phydev)
  {
  	const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus);
  	int ret = 0;
  
  	if (ops && ops->connect_phy)
  		ret = ops->connect_phy(bus->upstream, phydev);
  
  	if (ret == 0)
  		bus->phydev = phydev;
  
  	return ret;
  }
  EXPORT_SYMBOL_GPL(sfp_add_phy);
  
  void sfp_remove_phy(struct sfp_bus *bus)
  {
  	const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus);
  
  	if (ops && ops->disconnect_phy)
  		ops->disconnect_phy(bus->upstream);
  	bus->phydev = NULL;
  }
  EXPORT_SYMBOL_GPL(sfp_remove_phy);
ce0aa27ff   Russell King   sfp: add sfp-bus ...
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
  void sfp_link_up(struct sfp_bus *bus)
  {
  	const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus);
  
  	if (ops && ops->link_up)
  		ops->link_up(bus->upstream);
  }
  EXPORT_SYMBOL_GPL(sfp_link_up);
  
  void sfp_link_down(struct sfp_bus *bus)
  {
  	const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus);
  
  	if (ops && ops->link_down)
  		ops->link_down(bus->upstream);
  }
  EXPORT_SYMBOL_GPL(sfp_link_down);
  
  int sfp_module_insert(struct sfp_bus *bus, const struct sfp_eeprom_id *id)
  {
  	const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus);
  	int ret = 0;
  
  	if (ops && ops->module_insert)
  		ret = ops->module_insert(bus->upstream, id);
  
  	return ret;
  }
  EXPORT_SYMBOL_GPL(sfp_module_insert);
  
  void sfp_module_remove(struct sfp_bus *bus)
  {
  	const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus);
  
  	if (ops && ops->module_remove)
  		ops->module_remove(bus->upstream);
  }
  EXPORT_SYMBOL_GPL(sfp_module_remove);
f20a4c46b   Russell King   sfp: ensure we cl...
552
553
554
555
556
557
  static void sfp_socket_clear(struct sfp_bus *bus)
  {
  	bus->sfp_dev = NULL;
  	bus->sfp = NULL;
  	bus->socket_ops = NULL;
  }
ce0aa27ff   Russell King   sfp: add sfp-bus ...
558
559
560
  struct sfp_bus *sfp_register_socket(struct device *dev, struct sfp *sfp,
  				    const struct sfp_socket_ops *ops)
  {
c19bb0007   Russell King   sfp: convert to f...
561
  	struct sfp_bus *bus = sfp_bus_get(dev->fwnode);
ce0aa27ff   Russell King   sfp: add sfp-bus ...
562
563
564
565
566
567
568
  	int ret = 0;
  
  	if (bus) {
  		rtnl_lock();
  		bus->sfp_dev = dev;
  		bus->sfp = sfp;
  		bus->socket_ops = ops;
f20a4c46b   Russell King   sfp: ensure we cl...
569
  		if (bus->netdev) {
ce0aa27ff   Russell King   sfp: add sfp-bus ...
570
  			ret = sfp_register_bus(bus);
f20a4c46b   Russell King   sfp: ensure we cl...
571
572
573
  			if (ret)
  				sfp_socket_clear(bus);
  		}
ce0aa27ff   Russell King   sfp: add sfp-bus ...
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
  		rtnl_unlock();
  	}
  
  	if (ret) {
  		sfp_bus_put(bus);
  		bus = NULL;
  	}
  
  	return bus;
  }
  EXPORT_SYMBOL_GPL(sfp_register_socket);
  
  void sfp_unregister_socket(struct sfp_bus *bus)
  {
  	rtnl_lock();
0b2122e49   Russell King   sfp: fix sfp-bus ...
589
590
  	if (bus->netdev)
  		sfp_unregister_bus(bus);
f20a4c46b   Russell King   sfp: ensure we cl...
591
  	sfp_socket_clear(bus);
ce0aa27ff   Russell King   sfp: add sfp-bus ...
592
593
594
595
596
  	rtnl_unlock();
  
  	sfp_bus_put(bus);
  }
  EXPORT_SYMBOL_GPL(sfp_unregister_socket);