linux/drivers/net/phy/sfp.c

// SPDX-License-Identifier: GPL-2.0
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/hwmon.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/jiffies.h>
#include <linux/mdio/mdio-i2c.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/phy.h>
#include <linux/platform_device.h>
#include <linux/rtnetlink.h>
#include <linux/slab.h>
#include <linux/workqueue.h>

#include "sfp.h"
#include "swphy.h"

enum {};

static const char  * const mod_state_strings[] =;

static const char *mod_state_to_str(unsigned short mod_state)
{}

static const char * const dev_state_strings[] =;

static const char *dev_state_to_str(unsigned short dev_state)
{}

static const char * const event_strings[] =;

static const char *event_to_str(unsigned short event)
{}

static const char * const sm_state_strings[] =;

static const char *sm_state_to_str(unsigned short sm_state)
{}

static const char *gpio_names[] =;

static const enum gpiod_flags gpio_flags[] =;

/* t_start_up (SFF-8431) or t_init (SFF-8472) is the time required for a
 * non-cooled module to initialise its laser safety circuitry. We wait
 * an initial T_WAIT period before we check the tx fault to give any PHY
 * on board (for a copper SFP) time to initialise.
 */
#define T_WAIT
#define T_START_UP
#define T_START_UP_BAD_GPON

/* t_reset is the time required to assert the TX_DISABLE signal to reset
 * an indicated TX_FAULT.
 */
#define T_RESET_US
#define T_FAULT_RECOVER

/* N_FAULT_INIT is the number of recovery attempts at module initialisation
 * time. If the TX_FAULT signal is not deasserted after this number of
 * attempts at clearing it, we decide that the module is faulty.
 * N_FAULT is the same but after the module has initialised.
 */
#define N_FAULT_INIT
#define N_FAULT

/* T_PHY_RETRY is the time interval between attempts to probe the PHY.
 * R_PHY_RETRY is the number of attempts.
 */
#define T_PHY_RETRY
#define R_PHY_RETRY

/* SFP module presence detection is poor: the three MOD DEF signals are
 * the same length on the PCB, which means it's possible for MOD DEF 0 to
 * connect before the I2C bus on MOD DEF 1/2.
 *
 * The SFF-8472 specifies t_serial ("Time from power on until module is
 * ready for data transmission over the two wire serial bus.") as 300ms.
 */
#define T_SERIAL
#define T_HPOWER_LEVEL
#define T_PROBE_RETRY_INIT
#define R_PROBE_RETRY_INIT
#define T_PROBE_RETRY_SLOW
#define R_PROBE_RETRY_SLOW

/* SFP modules appear to always have their PHY configured for bus address
 * 0x56 (which with mdio-i2c, translates to a PHY address of 22).
 * RollBall SFPs access phy via SFP Enhanced Digital Diagnostic Interface
 * via address 0x51 (mdio-i2c will use RollBall protocol on this address).
 */
#define SFP_PHY_ADDR
#define SFP_PHY_ADDR_ROLLBALL

/* SFP_EEPROM_BLOCK_SIZE is the size of data chunk to read the EEPROM
 * at a time. Some SFP modules and also some Linux I2C drivers do not like
 * reads longer than 16 bytes.
 */
#define SFP_EEPROM_BLOCK_SIZE

struct sff_data {};

struct sfp {};

static bool sff_module_supported(const struct sfp_eeprom_id *id)
{}

static const struct sff_data sff_data =;

static bool sfp_module_supported(const struct sfp_eeprom_id *id)
{}

static const struct sff_data sfp_data =;

static const struct of_device_id sfp_of_match[] =;
MODULE_DEVICE_TABLE(of, sfp_of_match);

static void sfp_fixup_long_startup(struct sfp *sfp)
{}

static void sfp_fixup_ignore_los(struct sfp *sfp)
{}

static void sfp_fixup_ignore_tx_fault(struct sfp *sfp)
{}

static void sfp_fixup_nokia(struct sfp *sfp)
{}

// For 10GBASE-T short-reach modules
static void sfp_fixup_10gbaset_30m(struct sfp *sfp)
{}

static void sfp_fixup_rollball(struct sfp *sfp)
{}

static void sfp_fixup_fs_2_5gt(struct sfp *sfp)
{}

static void sfp_fixup_fs_10gt(struct sfp *sfp)
{}

static void sfp_fixup_halny_gsfp(struct sfp *sfp)
{}

static void sfp_fixup_rollball_cc(struct sfp *sfp)
{}

static void sfp_quirk_2500basex(const struct sfp_eeprom_id *id,
				unsigned long *modes,
				unsigned long *interfaces)
{}

static void sfp_quirk_disable_autoneg(const struct sfp_eeprom_id *id,
				      unsigned long *modes,
				      unsigned long *interfaces)
{}

static void sfp_quirk_oem_2_5g(const struct sfp_eeprom_id *id,
			       unsigned long *modes,
			       unsigned long *interfaces)
{}

static void sfp_quirk_ubnt_uf_instant(const struct sfp_eeprom_id *id,
				      unsigned long *modes,
				      unsigned long *interfaces)
{}

#define SFP_QUIRK(_v, _p, _m, _f)
#define SFP_QUIRK_M(_v, _p, _m)
#define SFP_QUIRK_F(_v, _p, _f)

static const struct sfp_quirk sfp_quirks[] =;

static size_t sfp_strlen(const char *str, size_t maxlen)
{}

static bool sfp_match(const char *qs, const char *str, size_t len)
{}

static const struct sfp_quirk *sfp_lookup_quirk(const struct sfp_eeprom_id *id)
{}

static unsigned long poll_jiffies;

static unsigned int sfp_gpio_get_state(struct sfp *sfp)
{}

static unsigned int sff_gpio_get_state(struct sfp *sfp)
{}

static void sfp_gpio_set_state(struct sfp *sfp, unsigned int state)
{}

static int sfp_i2c_read(struct sfp *sfp, bool a2, u8 dev_addr, void *buf,
			size_t len)
{}

static int sfp_i2c_write(struct sfp *sfp, bool a2, u8 dev_addr, void *buf,
	size_t len)
{}

static int sfp_i2c_configure(struct sfp *sfp, struct i2c_adapter *i2c)
{}

static int sfp_i2c_mdiobus_create(struct sfp *sfp)
{}

static void sfp_i2c_mdiobus_destroy(struct sfp *sfp)
{}

/* Interface */
static int sfp_read(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len)
{}

static int sfp_write(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len)
{}

static int sfp_modify_u8(struct sfp *sfp, bool a2, u8 addr, u8 mask, u8 val)
{}

static unsigned int sfp_soft_get_state(struct sfp *sfp)
{}

static void sfp_soft_set_state(struct sfp *sfp, unsigned int state,
			       unsigned int soft)
{}

static void sfp_soft_start_poll(struct sfp *sfp)
{}

static void sfp_soft_stop_poll(struct sfp *sfp)
{}

/* sfp_get_state() - must be called with st_mutex held, or in the
 * initialisation path.
 */
static unsigned int sfp_get_state(struct sfp *sfp)
{}

/* sfp_set_state() - must be called with st_mutex held, or in the
 * initialisation path.
 */
static void sfp_set_state(struct sfp *sfp, unsigned int state)
{}

static void sfp_mod_state(struct sfp *sfp, unsigned int mask, unsigned int set)
{}

static unsigned int sfp_check(void *buf, size_t len)
{}

/* hwmon */
#if IS_ENABLED(CONFIG_HWMON)
static umode_t sfp_hwmon_is_visible(const void *data,
				    enum hwmon_sensor_types type,
				    u32 attr, int channel)
{}

static int sfp_hwmon_read_sensor(struct sfp *sfp, int reg, long *value)
{}

static void sfp_hwmon_to_rx_power(long *value)
{}

static void sfp_hwmon_calibrate(struct sfp *sfp, unsigned int slope, int offset,
				long *value)
{}

static void sfp_hwmon_calibrate_temp(struct sfp *sfp, long *value)
{}

static void sfp_hwmon_calibrate_vcc(struct sfp *sfp, long *value)
{}

static void sfp_hwmon_calibrate_bias(struct sfp *sfp, long *value)
{}

static void sfp_hwmon_calibrate_tx_power(struct sfp *sfp, long *value)
{}

static int sfp_hwmon_read_temp(struct sfp *sfp, int reg, long *value)
{}

static int sfp_hwmon_read_vcc(struct sfp *sfp, int reg, long *value)
{}

static int sfp_hwmon_read_bias(struct sfp *sfp, int reg, long *value)
{}

static int sfp_hwmon_read_tx_power(struct sfp *sfp, int reg, long *value)
{}

static int sfp_hwmon_read_rx_power(struct sfp *sfp, int reg, long *value)
{}

static int sfp_hwmon_temp(struct sfp *sfp, u32 attr, long *value)
{}

static int sfp_hwmon_vcc(struct sfp *sfp, u32 attr, long *value)
{}

static int sfp_hwmon_bias(struct sfp *sfp, u32 attr, long *value)
{}

static int sfp_hwmon_tx_power(struct sfp *sfp, u32 attr, long *value)
{}

static int sfp_hwmon_rx_power(struct sfp *sfp, u32 attr, long *value)
{}

static int sfp_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
			  u32 attr, int channel, long *value)
{}

static const char *const sfp_hwmon_power_labels[] =;

static int sfp_hwmon_read_string(struct device *dev,
				 enum hwmon_sensor_types type,
				 u32 attr, int channel, const char **str)
{}

static const struct hwmon_ops sfp_hwmon_ops =;

static const struct hwmon_channel_info * const sfp_hwmon_info[] =;

static const struct hwmon_chip_info sfp_hwmon_chip_info =;

static void sfp_hwmon_probe(struct work_struct *work)
{}

static int sfp_hwmon_insert(struct sfp *sfp)
{}

static void sfp_hwmon_remove(struct sfp *sfp)
{}

static int sfp_hwmon_init(struct sfp *sfp)
{}

static void sfp_hwmon_exit(struct sfp *sfp)
{}
#else
static int sfp_hwmon_insert(struct sfp *sfp)
{
	return 0;
}

static void sfp_hwmon_remove(struct sfp *sfp)
{
}

static int sfp_hwmon_init(struct sfp *sfp)
{
	return 0;
}

static void sfp_hwmon_exit(struct sfp *sfp)
{
}
#endif

/* Helpers */
static void sfp_module_tx_disable(struct sfp *sfp)
{}

static void sfp_module_tx_enable(struct sfp *sfp)
{}

#if IS_ENABLED(CONFIG_DEBUG_FS)
static int sfp_debug_state_show(struct seq_file *s, void *data)
{}
DEFINE_SHOW_ATTRIBUTE();

static void sfp_debugfs_init(struct sfp *sfp)
{}

static void sfp_debugfs_exit(struct sfp *sfp)
{}
#else
static void sfp_debugfs_init(struct sfp *sfp)
{
}

static void sfp_debugfs_exit(struct sfp *sfp)
{
}
#endif

static void sfp_module_tx_fault_reset(struct sfp *sfp)
{}

/* SFP state machine */
static void sfp_sm_set_timer(struct sfp *sfp, unsigned int timeout)
{}

static void sfp_sm_next(struct sfp *sfp, unsigned int state,
			unsigned int timeout)
{}

static void sfp_sm_mod_next(struct sfp *sfp, unsigned int state,
			    unsigned int timeout)
{}

static void sfp_sm_phy_detach(struct sfp *sfp)
{}

static int sfp_sm_probe_phy(struct sfp *sfp, int addr, bool is_c45)
{}

static void sfp_sm_link_up(struct sfp *sfp)
{}

static void sfp_sm_link_down(struct sfp *sfp)
{}

static void sfp_sm_link_check_los(struct sfp *sfp)
{}

static bool sfp_los_event_active(struct sfp *sfp, unsigned int event)
{}

static bool sfp_los_event_inactive(struct sfp *sfp, unsigned int event)
{}

static void sfp_sm_fault(struct sfp *sfp, unsigned int next_state, bool warn)
{}

static int sfp_sm_add_mdio_bus(struct sfp *sfp)
{}

/* Probe a SFP for a PHY device if the module supports copper - the PHY
 * normally sits at I2C bus address 0x56, and may either be a clause 22
 * or clause 45 PHY.
 *
 * Clause 22 copper SFP modules normally operate in Cisco SGMII mode with
 * negotiation enabled, but some may be in 1000base-X - which is for the
 * PHY driver to determine.
 *
 * Clause 45 copper SFP+ modules (10G) appear to switch their interface
 * mode according to the negotiated line speed.
 */
static int sfp_sm_probe_for_phy(struct sfp *sfp)
{}

static int sfp_module_parse_power(struct sfp *sfp)
{}

static int sfp_sm_mod_hpower(struct sfp *sfp, bool enable)
{}

static void sfp_module_parse_rate_select(struct sfp *sfp)
{}

/* GPON modules based on Realtek RTL8672 and RTL9601C chips (e.g. V-SOL
 * V2801F, CarlitoxxPro CPGOS03-0490, Ubiquiti U-Fiber Instant, ...) do
 * not support multibyte reads from the EEPROM. Each multi-byte read
 * operation returns just one byte of EEPROM followed by zeros. There is
 * no way to identify which modules are using Realtek RTL8672 and RTL9601C
 * chips. Moreover every OEM of V-SOL V2801F module puts its own vendor
 * name and vendor id into EEPROM, so there is even no way to detect if
 * module is V-SOL V2801F. Therefore check for those zeros in the read
 * data and then based on check switch to reading EEPROM to one byte
 * at a time.
 */
static bool sfp_id_needs_byte_io(struct sfp *sfp, void *buf, size_t len)
{}

static int sfp_cotsworks_fixup_check(struct sfp *sfp, struct sfp_eeprom_id *id)
{}

static int sfp_module_parse_sff8472(struct sfp *sfp)
{}

static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
{}

static void sfp_sm_mod_remove(struct sfp *sfp)
{}

/* This state machine tracks the upstream's state */
static void sfp_sm_device(struct sfp *sfp, unsigned int event)
{}

/* This state machine tracks the insert/remove state of the module, probes
 * the on-board EEPROM, and sets up the power level.
 */
static void sfp_sm_module(struct sfp *sfp, unsigned int event)
{}

static void sfp_sm_main(struct sfp *sfp, unsigned int event)
{}

static void __sfp_sm_event(struct sfp *sfp, unsigned int event)
{}

static void sfp_sm_event(struct sfp *sfp, unsigned int event)
{}

static void sfp_attach(struct sfp *sfp)
{}

static void sfp_detach(struct sfp *sfp)
{}

static void sfp_start(struct sfp *sfp)
{}

static void sfp_stop(struct sfp *sfp)
{}

static void sfp_set_signal_rate(struct sfp *sfp, unsigned int rate_kbd)
{}

static int sfp_module_info(struct sfp *sfp, struct ethtool_modinfo *modinfo)
{}

static int sfp_module_eeprom(struct sfp *sfp, struct ethtool_eeprom *ee,
			     u8 *data)
{}

static int sfp_module_eeprom_by_page(struct sfp *sfp,
				     const struct ethtool_module_eeprom *page,
				     struct netlink_ext_ack *extack)
{
	if (!(sfp->state & SFP_F_PRESENT))
		return -ENODEV;

	if (page->bank) {
		NL_SET_ERR_MSG(extack, "Banks not supported");
		return -EOPNOTSUPP;
	}

	if (page->page) {
		NL_SET_ERR_MSG(extack, "Only page 0 supported");
		return -EOPNOTSUPP;
	}

	if (page->i2c_address != 0x50 &&
	    page->i2c_address != 0x51) {
		NL_SET_ERR_MSG(extack, "Only address 0x50 and 0x51 supported");
		return -EOPNOTSUPP;
	}

	return sfp_read(sfp, page->i2c_address == 0x51, page->offset,
			page->data, page->length);
};

static const struct sfp_socket_ops sfp_module_ops =;

static void sfp_timeout(struct work_struct *work)
{}

static void sfp_check_state(struct sfp *sfp)
{}

static irqreturn_t sfp_irq(int irq, void *data)
{}

static void sfp_poll(struct work_struct *work)
{}

static struct sfp *sfp_alloc(struct device *dev)
{}

static void sfp_cleanup(void *data)
{}

static int sfp_i2c_get(struct sfp *sfp)
{}

static int sfp_probe(struct platform_device *pdev)
{}

static void sfp_remove(struct platform_device *pdev)
{}

static void sfp_shutdown(struct platform_device *pdev)
{}

static struct platform_driver sfp_driver =;

static int sfp_init(void)
{}
module_init();

static void sfp_exit(void)
{}
module_exit(sfp_exit);

MODULE_ALIAS();
MODULE_AUTHOR();
MODULE_LICENSE();
MODULE_DESCRIPTION();