|
|
|
|
@@ -24,14 +24,18 @@ enum {
|
|
|
|
|
GPIO_LOS,
|
|
|
|
|
GPIO_TX_FAULT,
|
|
|
|
|
GPIO_TX_DISABLE,
|
|
|
|
|
GPIO_RATE_SELECT,
|
|
|
|
|
GPIO_RS0,
|
|
|
|
|
GPIO_RS1,
|
|
|
|
|
GPIO_MAX,
|
|
|
|
|
|
|
|
|
|
SFP_F_PRESENT = BIT(GPIO_MODDEF0),
|
|
|
|
|
SFP_F_LOS = BIT(GPIO_LOS),
|
|
|
|
|
SFP_F_TX_FAULT = BIT(GPIO_TX_FAULT),
|
|
|
|
|
SFP_F_TX_DISABLE = BIT(GPIO_TX_DISABLE),
|
|
|
|
|
SFP_F_RATE_SELECT = BIT(GPIO_RATE_SELECT),
|
|
|
|
|
SFP_F_RS0 = BIT(GPIO_RS0),
|
|
|
|
|
SFP_F_RS1 = BIT(GPIO_RS1),
|
|
|
|
|
|
|
|
|
|
SFP_F_OUTPUTS = SFP_F_TX_DISABLE | SFP_F_RS0 | SFP_F_RS1,
|
|
|
|
|
|
|
|
|
|
SFP_E_INSERT = 0,
|
|
|
|
|
SFP_E_REMOVE,
|
|
|
|
|
@@ -148,6 +152,7 @@ static const char *gpio_names[] = {
|
|
|
|
|
"tx-fault",
|
|
|
|
|
"tx-disable",
|
|
|
|
|
"rate-select0",
|
|
|
|
|
"rate-select1",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const enum gpiod_flags gpio_flags[] = {
|
|
|
|
|
@@ -156,6 +161,7 @@ static const enum gpiod_flags gpio_flags[] = {
|
|
|
|
|
GPIOD_IN,
|
|
|
|
|
GPIOD_ASIS,
|
|
|
|
|
GPIOD_ASIS,
|
|
|
|
|
GPIOD_ASIS,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* t_start_up (SFF-8431) or t_init (SFF-8472) is the time required for a
|
|
|
|
|
@@ -242,10 +248,18 @@ struct sfp {
|
|
|
|
|
|
|
|
|
|
bool need_poll;
|
|
|
|
|
|
|
|
|
|
/* Access rules:
|
|
|
|
|
* state_hw_drive: st_mutex held
|
|
|
|
|
* state_hw_mask: st_mutex held
|
|
|
|
|
* state_soft_mask: st_mutex held
|
|
|
|
|
* state: st_mutex held unless reading input bits
|
|
|
|
|
*/
|
|
|
|
|
struct mutex st_mutex; /* Protects state */
|
|
|
|
|
unsigned int state_hw_drive;
|
|
|
|
|
unsigned int state_hw_mask;
|
|
|
|
|
unsigned int state_soft_mask;
|
|
|
|
|
unsigned int state;
|
|
|
|
|
|
|
|
|
|
struct delayed_work poll;
|
|
|
|
|
struct delayed_work timeout;
|
|
|
|
|
struct mutex sm_mutex; /* Protects state machine */
|
|
|
|
|
@@ -262,6 +276,10 @@ struct sfp {
|
|
|
|
|
unsigned int module_t_start_up;
|
|
|
|
|
unsigned int module_t_wait;
|
|
|
|
|
|
|
|
|
|
unsigned int rate_kbd;
|
|
|
|
|
unsigned int rs_threshold_kbd;
|
|
|
|
|
unsigned int rs_state_mask;
|
|
|
|
|
|
|
|
|
|
bool have_a2;
|
|
|
|
|
bool tx_fault_ignore;
|
|
|
|
|
|
|
|
|
|
@@ -312,7 +330,7 @@ static bool sfp_module_supported(const struct sfp_eeprom_id *id)
|
|
|
|
|
|
|
|
|
|
static const struct sff_data sfp_data = {
|
|
|
|
|
.gpios = SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT |
|
|
|
|
|
SFP_F_TX_DISABLE | SFP_F_RATE_SELECT,
|
|
|
|
|
SFP_F_TX_DISABLE | SFP_F_RS0 | SFP_F_RS1,
|
|
|
|
|
.module_supported = sfp_module_supported,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
@@ -500,20 +518,37 @@ static unsigned int sff_gpio_get_state(struct sfp *sfp)
|
|
|
|
|
|
|
|
|
|
static void sfp_gpio_set_state(struct sfp *sfp, unsigned int state)
|
|
|
|
|
{
|
|
|
|
|
if (state & SFP_F_PRESENT) {
|
|
|
|
|
/* If the module is present, drive the signals */
|
|
|
|
|
if (sfp->gpio[GPIO_TX_DISABLE])
|
|
|
|
|
unsigned int drive;
|
|
|
|
|
|
|
|
|
|
if (state & SFP_F_PRESENT)
|
|
|
|
|
/* If the module is present, drive the requested signals */
|
|
|
|
|
drive = sfp->state_hw_drive;
|
|
|
|
|
else
|
|
|
|
|
/* Otherwise, let them float to the pull-ups */
|
|
|
|
|
drive = 0;
|
|
|
|
|
|
|
|
|
|
if (sfp->gpio[GPIO_TX_DISABLE]) {
|
|
|
|
|
if (drive & SFP_F_TX_DISABLE)
|
|
|
|
|
gpiod_direction_output(sfp->gpio[GPIO_TX_DISABLE],
|
|
|
|
|
state & SFP_F_TX_DISABLE);
|
|
|
|
|
if (state & SFP_F_RATE_SELECT)
|
|
|
|
|
gpiod_direction_output(sfp->gpio[GPIO_RATE_SELECT],
|
|
|
|
|
state & SFP_F_RATE_SELECT);
|
|
|
|
|
} else {
|
|
|
|
|
/* Otherwise, let them float to the pull-ups */
|
|
|
|
|
if (sfp->gpio[GPIO_TX_DISABLE])
|
|
|
|
|
else
|
|
|
|
|
gpiod_direction_input(sfp->gpio[GPIO_TX_DISABLE]);
|
|
|
|
|
if (state & SFP_F_RATE_SELECT)
|
|
|
|
|
gpiod_direction_input(sfp->gpio[GPIO_RATE_SELECT]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sfp->gpio[GPIO_RS0]) {
|
|
|
|
|
if (drive & SFP_F_RS0)
|
|
|
|
|
gpiod_direction_output(sfp->gpio[GPIO_RS0],
|
|
|
|
|
state & SFP_F_RS0);
|
|
|
|
|
else
|
|
|
|
|
gpiod_direction_input(sfp->gpio[GPIO_RS0]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (sfp->gpio[GPIO_RS1]) {
|
|
|
|
|
if (drive & SFP_F_RS1)
|
|
|
|
|
gpiod_direction_output(sfp->gpio[GPIO_RS1],
|
|
|
|
|
state & SFP_F_RS1);
|
|
|
|
|
else
|
|
|
|
|
gpiod_direction_input(sfp->gpio[GPIO_RS1]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -675,16 +710,33 @@ static unsigned int sfp_soft_get_state(struct sfp *sfp)
|
|
|
|
|
return state & sfp->state_soft_mask;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void sfp_soft_set_state(struct sfp *sfp, unsigned int state)
|
|
|
|
|
static void sfp_soft_set_state(struct sfp *sfp, unsigned int state,
|
|
|
|
|
unsigned int soft)
|
|
|
|
|
{
|
|
|
|
|
u8 mask = SFP_STATUS_TX_DISABLE_FORCE;
|
|
|
|
|
u8 mask = 0;
|
|
|
|
|
u8 val = 0;
|
|
|
|
|
|
|
|
|
|
if (soft & SFP_F_TX_DISABLE)
|
|
|
|
|
mask |= SFP_STATUS_TX_DISABLE_FORCE;
|
|
|
|
|
if (state & SFP_F_TX_DISABLE)
|
|
|
|
|
val |= SFP_STATUS_TX_DISABLE_FORCE;
|
|
|
|
|
|
|
|
|
|
if (soft & SFP_F_RS0)
|
|
|
|
|
mask |= SFP_STATUS_RS0_SELECT;
|
|
|
|
|
if (state & SFP_F_RS0)
|
|
|
|
|
val |= SFP_STATUS_RS0_SELECT;
|
|
|
|
|
|
|
|
|
|
sfp_modify_u8(sfp, true, SFP_STATUS, mask, val);
|
|
|
|
|
if (mask)
|
|
|
|
|
sfp_modify_u8(sfp, true, SFP_STATUS, mask, val);
|
|
|
|
|
|
|
|
|
|
val = mask = 0;
|
|
|
|
|
if (soft & SFP_F_RS1)
|
|
|
|
|
mask |= SFP_EXT_STATUS_RS1_SELECT;
|
|
|
|
|
if (state & SFP_F_RS1)
|
|
|
|
|
val |= SFP_EXT_STATUS_RS1_SELECT;
|
|
|
|
|
|
|
|
|
|
if (mask)
|
|
|
|
|
sfp_modify_u8(sfp, true, SFP_EXT_STATUS, mask, val);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void sfp_soft_start_poll(struct sfp *sfp)
|
|
|
|
|
@@ -692,27 +744,35 @@ static void sfp_soft_start_poll(struct sfp *sfp)
|
|
|
|
|
const struct sfp_eeprom_id *id = &sfp->id;
|
|
|
|
|
unsigned int mask = 0;
|
|
|
|
|
|
|
|
|
|
sfp->state_soft_mask = 0;
|
|
|
|
|
if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_DISABLE)
|
|
|
|
|
mask |= SFP_F_TX_DISABLE;
|
|
|
|
|
if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_FAULT)
|
|
|
|
|
mask |= SFP_F_TX_FAULT;
|
|
|
|
|
if (id->ext.enhopts & SFP_ENHOPTS_SOFT_RX_LOS)
|
|
|
|
|
mask |= SFP_F_LOS;
|
|
|
|
|
if (id->ext.enhopts & SFP_ENHOPTS_SOFT_RATE_SELECT)
|
|
|
|
|
mask |= sfp->rs_state_mask;
|
|
|
|
|
|
|
|
|
|
mutex_lock(&sfp->st_mutex);
|
|
|
|
|
// Poll the soft state for hardware pins we want to ignore
|
|
|
|
|
sfp->state_soft_mask = ~sfp->state_hw_mask & mask;
|
|
|
|
|
|
|
|
|
|
if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) &&
|
|
|
|
|
!sfp->need_poll)
|
|
|
|
|
mod_delayed_work(system_wq, &sfp->poll, poll_jiffies);
|
|
|
|
|
mutex_unlock(&sfp->st_mutex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void sfp_soft_stop_poll(struct sfp *sfp)
|
|
|
|
|
{
|
|
|
|
|
mutex_lock(&sfp->st_mutex);
|
|
|
|
|
sfp->state_soft_mask = 0;
|
|
|
|
|
mutex_unlock(&sfp->st_mutex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* sfp_get_state() - must be called with st_mutex held, or in the
|
|
|
|
|
* initialisation path.
|
|
|
|
|
*/
|
|
|
|
|
static unsigned int sfp_get_state(struct sfp *sfp)
|
|
|
|
|
{
|
|
|
|
|
unsigned int soft = sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT);
|
|
|
|
|
@@ -725,13 +785,26 @@ static unsigned int sfp_get_state(struct sfp *sfp)
|
|
|
|
|
return state;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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)
|
|
|
|
|
{
|
|
|
|
|
unsigned int soft;
|
|
|
|
|
|
|
|
|
|
sfp->set_state(sfp, state);
|
|
|
|
|
|
|
|
|
|
if (state & SFP_F_PRESENT &&
|
|
|
|
|
sfp->state_soft_mask & SFP_F_TX_DISABLE)
|
|
|
|
|
sfp_soft_set_state(sfp, state);
|
|
|
|
|
soft = sfp->state_soft_mask & SFP_F_OUTPUTS;
|
|
|
|
|
if (state & SFP_F_PRESENT && soft)
|
|
|
|
|
sfp_soft_set_state(sfp, state, soft);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void sfp_mod_state(struct sfp *sfp, unsigned int mask, unsigned int set)
|
|
|
|
|
{
|
|
|
|
|
mutex_lock(&sfp->st_mutex);
|
|
|
|
|
sfp->state = (sfp->state & ~mask) | set;
|
|
|
|
|
sfp_set_state(sfp, sfp->state);
|
|
|
|
|
mutex_unlock(&sfp->st_mutex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static unsigned int sfp_check(void *buf, size_t len)
|
|
|
|
|
@@ -1537,16 +1610,14 @@ static void sfp_module_tx_disable(struct sfp *sfp)
|
|
|
|
|
{
|
|
|
|
|
dev_dbg(sfp->dev, "tx disable %u -> %u\n",
|
|
|
|
|
sfp->state & SFP_F_TX_DISABLE ? 1 : 0, 1);
|
|
|
|
|
sfp->state |= SFP_F_TX_DISABLE;
|
|
|
|
|
sfp_set_state(sfp, sfp->state);
|
|
|
|
|
sfp_mod_state(sfp, SFP_F_TX_DISABLE, SFP_F_TX_DISABLE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void sfp_module_tx_enable(struct sfp *sfp)
|
|
|
|
|
{
|
|
|
|
|
dev_dbg(sfp->dev, "tx disable %u -> %u\n",
|
|
|
|
|
sfp->state & SFP_F_TX_DISABLE ? 1 : 0, 0);
|
|
|
|
|
sfp->state &= ~SFP_F_TX_DISABLE;
|
|
|
|
|
sfp_set_state(sfp, sfp->state);
|
|
|
|
|
sfp_mod_state(sfp, SFP_F_TX_DISABLE, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#if IS_ENABLED(CONFIG_DEBUG_FS)
|
|
|
|
|
@@ -1567,10 +1638,15 @@ static int sfp_debug_state_show(struct seq_file *s, void *data)
|
|
|
|
|
sfp->sm_fault_retries);
|
|
|
|
|
seq_printf(s, "PHY probe remaining retries: %d\n",
|
|
|
|
|
sfp->sm_phy_retries);
|
|
|
|
|
seq_printf(s, "Signalling rate: %u kBd\n", sfp->rate_kbd);
|
|
|
|
|
seq_printf(s, "Rate select threshold: %u kBd\n",
|
|
|
|
|
sfp->rs_threshold_kbd);
|
|
|
|
|
seq_printf(s, "moddef0: %d\n", !!(sfp->state & SFP_F_PRESENT));
|
|
|
|
|
seq_printf(s, "rx_los: %d\n", !!(sfp->state & SFP_F_LOS));
|
|
|
|
|
seq_printf(s, "tx_fault: %d\n", !!(sfp->state & SFP_F_TX_FAULT));
|
|
|
|
|
seq_printf(s, "tx_disable: %d\n", !!(sfp->state & SFP_F_TX_DISABLE));
|
|
|
|
|
seq_printf(s, "rs0: %d\n", !!(sfp->state & SFP_F_RS0));
|
|
|
|
|
seq_printf(s, "rs1: %d\n", !!(sfp->state & SFP_F_RS1));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
DEFINE_SHOW_ATTRIBUTE(sfp_debug_state);
|
|
|
|
|
@@ -1599,16 +1675,18 @@ static void sfp_debugfs_exit(struct sfp *sfp)
|
|
|
|
|
|
|
|
|
|
static void sfp_module_tx_fault_reset(struct sfp *sfp)
|
|
|
|
|
{
|
|
|
|
|
unsigned int state = sfp->state;
|
|
|
|
|
unsigned int state;
|
|
|
|
|
|
|
|
|
|
if (state & SFP_F_TX_DISABLE)
|
|
|
|
|
return;
|
|
|
|
|
mutex_lock(&sfp->st_mutex);
|
|
|
|
|
state = sfp->state;
|
|
|
|
|
if (!(state & SFP_F_TX_DISABLE)) {
|
|
|
|
|
sfp_set_state(sfp, state | SFP_F_TX_DISABLE);
|
|
|
|
|
|
|
|
|
|
sfp_set_state(sfp, state | SFP_F_TX_DISABLE);
|
|
|
|
|
udelay(T_RESET_US);
|
|
|
|
|
|
|
|
|
|
udelay(T_RESET_US);
|
|
|
|
|
|
|
|
|
|
sfp_set_state(sfp, state);
|
|
|
|
|
sfp_set_state(sfp, state);
|
|
|
|
|
}
|
|
|
|
|
mutex_unlock(&sfp->st_mutex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* SFP state machine */
|
|
|
|
|
@@ -1874,6 +1952,95 @@ static int sfp_sm_mod_hpower(struct sfp *sfp, bool enable)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void sfp_module_parse_rate_select(struct sfp *sfp)
|
|
|
|
|
{
|
|
|
|
|
u8 rate_id;
|
|
|
|
|
|
|
|
|
|
sfp->rs_threshold_kbd = 0;
|
|
|
|
|
sfp->rs_state_mask = 0;
|
|
|
|
|
|
|
|
|
|
if (!(sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_RATE_SELECT)))
|
|
|
|
|
/* No support for RateSelect */
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* Default to INF-8074 RateSelect operation. The signalling threshold
|
|
|
|
|
* rate is not well specified, so always select "Full Bandwidth", but
|
|
|
|
|
* SFF-8079 reveals that it is understood that RS0 will be low for
|
|
|
|
|
* 1.0625Gb/s and high for 2.125Gb/s. Choose a value half-way between.
|
|
|
|
|
* This method exists prior to SFF-8472.
|
|
|
|
|
*/
|
|
|
|
|
sfp->rs_state_mask = SFP_F_RS0;
|
|
|
|
|
sfp->rs_threshold_kbd = 1594;
|
|
|
|
|
|
|
|
|
|
/* Parse the rate identifier, which is complicated due to history:
|
|
|
|
|
* SFF-8472 rev 9.5 marks this field as reserved.
|
|
|
|
|
* SFF-8079 references SFF-8472 rev 9.5 and defines bit 0. SFF-8472
|
|
|
|
|
* compliance is not required.
|
|
|
|
|
* SFF-8472 rev 10.2 defines this field using values 0..4
|
|
|
|
|
* SFF-8472 rev 11.0 redefines this field with bit 0 for SFF-8079
|
|
|
|
|
* and even values.
|
|
|
|
|
*/
|
|
|
|
|
rate_id = sfp->id.base.rate_id;
|
|
|
|
|
if (rate_id == 0)
|
|
|
|
|
/* Unspecified */
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* SFF-8472 rev 10.0..10.4 did not account for SFF-8079 using bit 0,
|
|
|
|
|
* and allocated value 3 to SFF-8431 independent tx/rx rate select.
|
|
|
|
|
* Convert this to a SFF-8472 rev 11.0 rate identifier.
|
|
|
|
|
*/
|
|
|
|
|
if (sfp->id.ext.sff8472_compliance >= SFP_SFF8472_COMPLIANCE_REV10_2 &&
|
|
|
|
|
sfp->id.ext.sff8472_compliance < SFP_SFF8472_COMPLIANCE_REV11_0 &&
|
|
|
|
|
rate_id == 3)
|
|
|
|
|
rate_id = SFF_RID_8431;
|
|
|
|
|
|
|
|
|
|
if (rate_id & SFF_RID_8079) {
|
|
|
|
|
/* SFF-8079 RateSelect / Application Select in conjunction with
|
|
|
|
|
* SFF-8472 rev 9.5. SFF-8079 defines rate_id as a bitfield
|
|
|
|
|
* with only bit 0 used, which takes precedence over SFF-8472.
|
|
|
|
|
*/
|
|
|
|
|
if (!(sfp->id.ext.enhopts & SFP_ENHOPTS_APP_SELECT_SFF8079)) {
|
|
|
|
|
/* SFF-8079 Part 1 - rate selection between Fibre
|
|
|
|
|
* Channel 1.0625/2.125/4.25 Gbd modes. Note that RS0
|
|
|
|
|
* is high for 2125, so we have to subtract 1 to
|
|
|
|
|
* include it.
|
|
|
|
|
*/
|
|
|
|
|
sfp->rs_threshold_kbd = 2125 - 1;
|
|
|
|
|
sfp->rs_state_mask = SFP_F_RS0;
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* SFF-8472 rev 9.5 does not define the rate identifier */
|
|
|
|
|
if (sfp->id.ext.sff8472_compliance <= SFP_SFF8472_COMPLIANCE_REV9_5)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* SFF-8472 rev 11.0 defines rate_id as a numerical value which will
|
|
|
|
|
* always have bit 0 clear due to SFF-8079's bitfield usage of rate_id.
|
|
|
|
|
*/
|
|
|
|
|
switch (rate_id) {
|
|
|
|
|
case SFF_RID_8431_RX_ONLY:
|
|
|
|
|
sfp->rs_threshold_kbd = 4250;
|
|
|
|
|
sfp->rs_state_mask = SFP_F_RS0;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SFF_RID_8431_TX_ONLY:
|
|
|
|
|
sfp->rs_threshold_kbd = 4250;
|
|
|
|
|
sfp->rs_state_mask = SFP_F_RS1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SFF_RID_8431:
|
|
|
|
|
sfp->rs_threshold_kbd = 4250;
|
|
|
|
|
sfp->rs_state_mask = SFP_F_RS0 | SFP_F_RS1;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case SFF_RID_10G8G:
|
|
|
|
|
sfp->rs_threshold_kbd = 9000;
|
|
|
|
|
sfp->rs_state_mask = SFP_F_RS0 | SFP_F_RS1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
|
@@ -1953,6 +2120,7 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
|
|
|
|
|
/* SFP module inserted - read I2C data */
|
|
|
|
|
struct sfp_eeprom_id id;
|
|
|
|
|
bool cotsworks_sfbg;
|
|
|
|
|
unsigned int mask;
|
|
|
|
|
bool cotsworks;
|
|
|
|
|
u8 check;
|
|
|
|
|
int ret;
|
|
|
|
|
@@ -2092,14 +2260,19 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
/* Initialise state bits to use from hardware */
|
|
|
|
|
sfp->state_hw_mask = SFP_F_PRESENT;
|
|
|
|
|
sfp_module_parse_rate_select(sfp);
|
|
|
|
|
|
|
|
|
|
mask = SFP_F_PRESENT;
|
|
|
|
|
if (sfp->gpio[GPIO_TX_DISABLE])
|
|
|
|
|
sfp->state_hw_mask |= SFP_F_TX_DISABLE;
|
|
|
|
|
mask |= SFP_F_TX_DISABLE;
|
|
|
|
|
if (sfp->gpio[GPIO_TX_FAULT])
|
|
|
|
|
sfp->state_hw_mask |= SFP_F_TX_FAULT;
|
|
|
|
|
mask |= SFP_F_TX_FAULT;
|
|
|
|
|
if (sfp->gpio[GPIO_LOS])
|
|
|
|
|
sfp->state_hw_mask |= SFP_F_LOS;
|
|
|
|
|
mask |= SFP_F_LOS;
|
|
|
|
|
if (sfp->gpio[GPIO_RS0])
|
|
|
|
|
mask |= SFP_F_RS0;
|
|
|
|
|
if (sfp->gpio[GPIO_RS1])
|
|
|
|
|
mask |= SFP_F_RS1;
|
|
|
|
|
|
|
|
|
|
sfp->module_t_start_up = T_START_UP;
|
|
|
|
|
sfp->module_t_wait = T_WAIT;
|
|
|
|
|
@@ -2117,8 +2290,17 @@ static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
|
|
|
|
|
sfp->mdio_protocol = MDIO_I2C_NONE;
|
|
|
|
|
|
|
|
|
|
sfp->quirk = sfp_lookup_quirk(&id);
|
|
|
|
|
|
|
|
|
|
mutex_lock(&sfp->st_mutex);
|
|
|
|
|
/* Initialise state bits to use from hardware */
|
|
|
|
|
sfp->state_hw_mask = mask;
|
|
|
|
|
|
|
|
|
|
/* We want to drive the rate select pins that the module is using */
|
|
|
|
|
sfp->state_hw_drive |= sfp->rs_state_mask;
|
|
|
|
|
|
|
|
|
|
if (sfp->quirk && sfp->quirk->fixup)
|
|
|
|
|
sfp->quirk->fixup(sfp);
|
|
|
|
|
mutex_unlock(&sfp->st_mutex);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
@@ -2132,6 +2314,7 @@ static void sfp_sm_mod_remove(struct sfp *sfp)
|
|
|
|
|
|
|
|
|
|
memset(&sfp->id, 0, sizeof(sfp->id));
|
|
|
|
|
sfp->module_power_mW = 0;
|
|
|
|
|
sfp->state_hw_drive = SFP_F_TX_DISABLE;
|
|
|
|
|
sfp->have_a2 = false;
|
|
|
|
|
|
|
|
|
|
dev_info(sfp->dev, "module removed\n");
|
|
|
|
|
@@ -2452,10 +2635,8 @@ 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)
|
|
|
|
|
{
|
|
|
|
|
mutex_lock(&sfp->sm_mutex);
|
|
|
|
|
|
|
|
|
|
dev_dbg(sfp->dev, "SM: enter %s:%s:%s event %s\n",
|
|
|
|
|
mod_state_to_str(sfp->sm_mod_state),
|
|
|
|
|
dev_state_to_str(sfp->sm_dev_state),
|
|
|
|
|
@@ -2470,7 +2651,12 @@ static void sfp_sm_event(struct sfp *sfp, unsigned int event)
|
|
|
|
|
mod_state_to_str(sfp->sm_mod_state),
|
|
|
|
|
dev_state_to_str(sfp->sm_dev_state),
|
|
|
|
|
sm_state_to_str(sfp->sm_state));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void sfp_sm_event(struct sfp *sfp, unsigned int event)
|
|
|
|
|
{
|
|
|
|
|
mutex_lock(&sfp->sm_mutex);
|
|
|
|
|
__sfp_sm_event(sfp, event);
|
|
|
|
|
mutex_unlock(&sfp->sm_mutex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -2494,6 +2680,20 @@ static void sfp_stop(struct sfp *sfp)
|
|
|
|
|
sfp_sm_event(sfp, SFP_E_DEV_DOWN);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void sfp_set_signal_rate(struct sfp *sfp, unsigned int rate_kbd)
|
|
|
|
|
{
|
|
|
|
|
unsigned int set;
|
|
|
|
|
|
|
|
|
|
sfp->rate_kbd = rate_kbd;
|
|
|
|
|
|
|
|
|
|
if (rate_kbd > sfp->rs_threshold_kbd)
|
|
|
|
|
set = sfp->rs_state_mask;
|
|
|
|
|
else
|
|
|
|
|
set = 0;
|
|
|
|
|
|
|
|
|
|
sfp_mod_state(sfp, SFP_F_RS0 | SFP_F_RS1, set);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int sfp_module_info(struct sfp *sfp, struct ethtool_modinfo *modinfo)
|
|
|
|
|
{
|
|
|
|
|
/* locking... and check module is present */
|
|
|
|
|
@@ -2578,6 +2778,7 @@ static const struct sfp_socket_ops sfp_module_ops = {
|
|
|
|
|
.detach = sfp_detach,
|
|
|
|
|
.start = sfp_start,
|
|
|
|
|
.stop = sfp_stop,
|
|
|
|
|
.set_signal_rate = sfp_set_signal_rate,
|
|
|
|
|
.module_info = sfp_module_info,
|
|
|
|
|
.module_eeprom = sfp_module_eeprom,
|
|
|
|
|
.module_eeprom_by_page = sfp_module_eeprom_by_page,
|
|
|
|
|
@@ -2596,6 +2797,7 @@ static void sfp_check_state(struct sfp *sfp)
|
|
|
|
|
{
|
|
|
|
|
unsigned int state, i, changed;
|
|
|
|
|
|
|
|
|
|
rtnl_lock();
|
|
|
|
|
mutex_lock(&sfp->st_mutex);
|
|
|
|
|
state = sfp_get_state(sfp);
|
|
|
|
|
changed = state ^ sfp->state;
|
|
|
|
|
@@ -2609,23 +2811,24 @@ static void sfp_check_state(struct sfp *sfp)
|
|
|
|
|
dev_dbg(sfp->dev, "%s %u -> %u\n", gpio_names[i],
|
|
|
|
|
!!(sfp->state & BIT(i)), !!(state & BIT(i)));
|
|
|
|
|
|
|
|
|
|
state |= sfp->state & (SFP_F_TX_DISABLE | SFP_F_RATE_SELECT);
|
|
|
|
|
state |= sfp->state & SFP_F_OUTPUTS;
|
|
|
|
|
sfp->state = state;
|
|
|
|
|
mutex_unlock(&sfp->st_mutex);
|
|
|
|
|
|
|
|
|
|
rtnl_lock();
|
|
|
|
|
mutex_lock(&sfp->sm_mutex);
|
|
|
|
|
if (changed & SFP_F_PRESENT)
|
|
|
|
|
sfp_sm_event(sfp, state & SFP_F_PRESENT ?
|
|
|
|
|
SFP_E_INSERT : SFP_E_REMOVE);
|
|
|
|
|
__sfp_sm_event(sfp, state & SFP_F_PRESENT ?
|
|
|
|
|
SFP_E_INSERT : SFP_E_REMOVE);
|
|
|
|
|
|
|
|
|
|
if (changed & SFP_F_TX_FAULT)
|
|
|
|
|
sfp_sm_event(sfp, state & SFP_F_TX_FAULT ?
|
|
|
|
|
SFP_E_TX_FAULT : SFP_E_TX_CLEAR);
|
|
|
|
|
__sfp_sm_event(sfp, state & SFP_F_TX_FAULT ?
|
|
|
|
|
SFP_E_TX_FAULT : SFP_E_TX_CLEAR);
|
|
|
|
|
|
|
|
|
|
if (changed & SFP_F_LOS)
|
|
|
|
|
sfp_sm_event(sfp, state & SFP_F_LOS ?
|
|
|
|
|
SFP_E_LOS_HIGH : SFP_E_LOS_LOW);
|
|
|
|
|
__sfp_sm_event(sfp, state & SFP_F_LOS ?
|
|
|
|
|
SFP_E_LOS_HIGH : SFP_E_LOS_LOW);
|
|
|
|
|
mutex_unlock(&sfp->sm_mutex);
|
|
|
|
|
rtnl_unlock();
|
|
|
|
|
mutex_unlock(&sfp->st_mutex);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static irqreturn_t sfp_irq(int irq, void *data)
|
|
|
|
|
@@ -2643,6 +2846,8 @@ static void sfp_poll(struct work_struct *work)
|
|
|
|
|
|
|
|
|
|
sfp_check_state(sfp);
|
|
|
|
|
|
|
|
|
|
// st_mutex doesn't need to be held here for state_soft_mask,
|
|
|
|
|
// it's unimportant if we race while reading this.
|
|
|
|
|
if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) ||
|
|
|
|
|
sfp->need_poll)
|
|
|
|
|
mod_delayed_work(system_wq, &sfp->poll, poll_jiffies);
|
|
|
|
|
@@ -2748,6 +2953,7 @@ static int sfp_probe(struct platform_device *pdev)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sfp->state_hw_mask = SFP_F_PRESENT;
|
|
|
|
|
sfp->state_hw_drive = SFP_F_TX_DISABLE;
|
|
|
|
|
|
|
|
|
|
sfp->get_state = sfp_gpio_get_state;
|
|
|
|
|
sfp->set_state = sfp_gpio_set_state;
|
|
|
|
|
@@ -2773,9 +2979,9 @@ static int sfp_probe(struct platform_device *pdev)
|
|
|
|
|
*/
|
|
|
|
|
sfp->state = sfp_get_state(sfp) | SFP_F_TX_DISABLE;
|
|
|
|
|
|
|
|
|
|
if (sfp->gpio[GPIO_RATE_SELECT] &&
|
|
|
|
|
gpiod_get_value_cansleep(sfp->gpio[GPIO_RATE_SELECT]))
|
|
|
|
|
sfp->state |= SFP_F_RATE_SELECT;
|
|
|
|
|
if (sfp->gpio[GPIO_RS0] &&
|
|
|
|
|
gpiod_get_value_cansleep(sfp->gpio[GPIO_RS0]))
|
|
|
|
|
sfp->state |= SFP_F_RS0;
|
|
|
|
|
sfp_set_state(sfp, sfp->state);
|
|
|
|
|
sfp_module_tx_disable(sfp);
|
|
|
|
|
if (sfp->state & SFP_F_PRESENT) {
|
|
|
|
|
|