// SPDX-License-Identifier: GPL-2.0-only #include <linux/export.h> #include <linux/kref.h> #include <linux/list.h> #include <linux/mutex.h> #include <linux/phylink.h> #include <linux/property.h> #include <linux/rtnetlink.h> #include <linux/slab.h> #include "sfp.h" /** * struct sfp_bus - internal representation of a sfp bus */ struct sfp_bus { … }; /** * 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. */ int sfp_parse_port(struct sfp_bus *bus, const struct sfp_eeprom_id *id, unsigned long *support) { … } EXPORT_SYMBOL_GPL(…); /** * sfp_may_have_phy() - indicate whether the module may have a PHY * @bus: a pointer to the &struct sfp_bus structure for the sfp module * @id: a pointer to the module's &struct sfp_eeprom_id * * Parse the EEPROM identification given in @id, and return whether * this module may have a PHY. */ bool sfp_may_have_phy(struct sfp_bus *bus, const struct sfp_eeprom_id *id) { … } EXPORT_SYMBOL_GPL(…); /** * 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 * @interfaces: pointer to an array of unsigned long for phy interface modes * mask * * Parse the EEPROM identification information and derive the supported * ethtool link modes for the module. */ void sfp_parse_support(struct sfp_bus *bus, const struct sfp_eeprom_id *id, unsigned long *support, unsigned long *interfaces) { … } EXPORT_SYMBOL_GPL(…); /** * sfp_select_interface() - Select appropriate phy_interface_t mode * @bus: a pointer to the &struct sfp_bus structure for the sfp module * @link_modes: ethtool link modes mask * * Derive the phy_interface_t mode for the SFP module from the link * modes mask. */ phy_interface_t sfp_select_interface(struct sfp_bus *bus, const unsigned long *link_modes) { … } EXPORT_SYMBOL_GPL(…); static LIST_HEAD(sfp_buses); static DEFINE_MUTEX(sfp_mutex); static const struct sfp_upstream_ops *sfp_get_upstream_ops(struct sfp_bus *bus) { … } static struct sfp_bus *sfp_bus_get(const struct fwnode_handle *fwnode) { … } static void sfp_bus_release(struct kref *kref) { … } /** * sfp_bus_put() - put a reference on the &struct sfp_bus * @bus: the &struct sfp_bus found via sfp_bus_find_fwnode() * * Put a reference on the &struct sfp_bus and free the underlying structure * if this was the last reference. */ void sfp_bus_put(struct sfp_bus *bus) { … } EXPORT_SYMBOL_GPL(…); static int sfp_register_bus(struct sfp_bus *bus) { … } static void sfp_unregister_bus(struct sfp_bus *bus) { … } /** * 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. */ int sfp_get_module_info(struct sfp_bus *bus, struct ethtool_modinfo *modinfo) { … } EXPORT_SYMBOL_GPL(…); /** * 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. */ int sfp_get_module_eeprom(struct sfp_bus *bus, struct ethtool_eeprom *ee, u8 *data) { … } EXPORT_SYMBOL_GPL(…); /** * sfp_get_module_eeprom_by_page() - Read a page from the SFP module EEPROM * @bus: a pointer to the &struct sfp_bus structure for the sfp module * @page: a &struct ethtool_module_eeprom * @extack: extack for reporting problems * * Read an EEPROM page as specified by the supplied @page. See the * documentation for &struct ethtool_module_eeprom for the page to be read. * * Returns 0 on success or a negative errno number. More error * information might be provided via extack */ int sfp_get_module_eeprom_by_page(struct sfp_bus *bus, const struct ethtool_module_eeprom *page, struct netlink_ext_ack *extack) { … } EXPORT_SYMBOL_GPL(…); /** * 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. */ void sfp_upstream_start(struct sfp_bus *bus) { … } EXPORT_SYMBOL_GPL(…); /** * 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. */ void sfp_upstream_stop(struct sfp_bus *bus) { … } EXPORT_SYMBOL_GPL(…); static void sfp_upstream_clear(struct sfp_bus *bus) { … } /** * sfp_upstream_set_signal_rate() - set data signalling rate * @bus: a pointer to the &struct sfp_bus structure for the sfp module * @rate_kbd: signalling rate in units of 1000 baud * * Configure the rate select settings on the SFP module for the signalling * rate (not the same as the data rate). * * Locks that may be held: * Phylink's state_mutex * rtnl lock * SFP's sm_mutex */ void sfp_upstream_set_signal_rate(struct sfp_bus *bus, unsigned int rate_kbd) { … } EXPORT_SYMBOL_GPL(…); /** * sfp_bus_find_fwnode() - parse and locate the SFP bus from fwnode * @fwnode: firmware node for the parent device (MAC or PHY) * * Parse the parent device's firmware node for a SFP bus, and locate * the sfp_bus structure, incrementing its reference count. This must * be put via sfp_bus_put() when done. * * Returns: * - on success, a pointer to the sfp_bus structure, * - %NULL if no SFP is specified, * - on failure, an error pointer value: * * - corresponding to the errors detailed for * fwnode_property_get_reference_args(). * - %-ENOMEM if we failed to allocate the bus. * - an error from the upstream's connect_phy() method. */ struct sfp_bus *sfp_bus_find_fwnode(const struct fwnode_handle *fwnode) { … } EXPORT_SYMBOL_GPL(…); /** * sfp_bus_add_upstream() - parse and register the neighbouring device * @bus: the &struct sfp_bus found via sfp_bus_find_fwnode() * @upstream: the upstream private data * @ops: the upstream's &struct sfp_upstream_ops * * Add upstream driver for the SFP bus, and if the bus is complete, register * the SFP bus using sfp_register_upstream(). This takes a reference on the * bus, so it is safe to put the bus after this call. * * Returns: * - on success, a pointer to the sfp_bus structure, * - %NULL if no SFP is specified, * - on failure, an error pointer value: * * - corresponding to the errors detailed for * fwnode_property_get_reference_args(). * - %-ENOMEM if we failed to allocate the bus. * - an error from the upstream's connect_phy() method. */ int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream, const struct sfp_upstream_ops *ops) { … } EXPORT_SYMBOL_GPL(…); /** * sfp_bus_del_upstream() - Delete a sfp bus * @bus: a pointer to the &struct sfp_bus structure for the sfp module * * Delete a previously registered upstream connection for the SFP * module. @bus should have been added by sfp_bus_add_upstream(). */ void sfp_bus_del_upstream(struct sfp_bus *bus) { … } EXPORT_SYMBOL_GPL(…); /** * sfp_get_name() - Get the SFP device name * @bus: a pointer to the &struct sfp_bus structure for the sfp module * * Gets the SFP device's name, if @bus has a registered socket. Callers must * hold RTNL, and the returned name is only valid until RTNL is released. * * Returns: * - The name of the SFP device registered with sfp_register_socket() * - %NULL if no device was registered on @bus */ const char *sfp_get_name(struct sfp_bus *bus) { … } EXPORT_SYMBOL_GPL(…); /* Socket driver entry points */ int sfp_add_phy(struct sfp_bus *bus, struct phy_device *phydev) { … } EXPORT_SYMBOL_GPL(…); void sfp_remove_phy(struct sfp_bus *bus) { … } EXPORT_SYMBOL_GPL(…); void sfp_link_up(struct sfp_bus *bus) { … } EXPORT_SYMBOL_GPL(…); void sfp_link_down(struct sfp_bus *bus) { … } EXPORT_SYMBOL_GPL(…); int sfp_module_insert(struct sfp_bus *bus, const struct sfp_eeprom_id *id, const struct sfp_quirk *quirk) { … } EXPORT_SYMBOL_GPL(…); void sfp_module_remove(struct sfp_bus *bus) { … } EXPORT_SYMBOL_GPL(…); int sfp_module_start(struct sfp_bus *bus) { … } EXPORT_SYMBOL_GPL(…); void sfp_module_stop(struct sfp_bus *bus) { … } EXPORT_SYMBOL_GPL(…); static void sfp_socket_clear(struct sfp_bus *bus) { … } struct sfp_bus *sfp_register_socket(struct device *dev, struct sfp *sfp, const struct sfp_socket_ops *ops) { … } EXPORT_SYMBOL_GPL(…); void sfp_unregister_socket(struct sfp_bus *bus) { … } EXPORT_SYMBOL_GPL(…);