SFP_E_INSERT = 0,
SFP_E_REMOVE,
+ SFP_E_DEV_ATTACH,
+ SFP_E_DEV_DETACH,
SFP_E_DEV_DOWN,
SFP_E_DEV_UP,
SFP_E_TX_FAULT,
SFP_MOD_PRESENT,
SFP_MOD_ERROR,
- SFP_DEV_DOWN = 0,
+ SFP_DEV_DETACHED = 0,
+ SFP_DEV_DOWN,
SFP_DEV_UP,
SFP_S_DOWN = 0,
}
static const char * const dev_state_strings[] = {
+ [SFP_DEV_DETACHED] = "detached",
[SFP_DEV_DOWN] = "down",
[SFP_DEV_UP] = "up",
};
static const char * const event_strings[] = {
[SFP_E_INSERT] = "insert",
[SFP_E_REMOVE] = "remove",
+ [SFP_E_DEV_ATTACH] = "dev_attach",
+ [SFP_E_DEV_DETACH] = "dev_detach",
[SFP_E_DEV_DOWN] = "dev_down",
[SFP_E_DEV_UP] = "dev_up",
[SFP_E_TX_FAULT] = "tx_fault",
struct gpio_desc *gpio[GPIO_MAX];
int gpio_irq[GPIO_MAX];
- bool attached;
struct mutex st_mutex; /* Protects state */
unsigned int state;
struct delayed_work poll;
dev_info(sfp->dev, "module removed\n");
}
-/* This state machine tracks the netdev up/down state */
+/* This state machine tracks the upstream's state */
static void sfp_sm_device(struct sfp *sfp, unsigned int event)
{
switch (sfp->sm_dev_state) {
default:
- if (event == SFP_E_DEV_UP)
+ if (event == SFP_E_DEV_ATTACH)
+ sfp->sm_dev_state = SFP_DEV_DOWN;
+ break;
+
+ case SFP_DEV_DOWN:
+ if (event == SFP_E_DEV_DETACH)
+ sfp->sm_dev_state = SFP_DEV_DETACHED;
+ else if (event == SFP_E_DEV_UP)
sfp->sm_dev_state = SFP_DEV_UP;
break;
case SFP_DEV_UP:
- if (event == SFP_E_DEV_DOWN)
+ if (event == SFP_E_DEV_DETACH)
+ sfp->sm_dev_state = SFP_DEV_DETACHED;
+ else if (event == SFP_E_DEV_DOWN)
sfp->sm_dev_state = SFP_DEV_DOWN;
break;
}
*/
static void sfp_sm_module(struct sfp *sfp, unsigned int event)
{
- /* Handle remove event globally, it resets this state machine */
- if (event == SFP_E_REMOVE) {
+ /* Handle remove event globally, it resets this state machine.
+ * Also deal with upstream detachment.
+ */
+ if (event == SFP_E_REMOVE || sfp->sm_dev_state < SFP_DEV_DOWN) {
if (sfp->sm_mod_state > SFP_MOD_PROBE)
sfp_sm_mod_remove(sfp);
- sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
+ if (sfp->sm_mod_state != SFP_MOD_EMPTY)
+ sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
return;
}
switch (sfp->sm_mod_state) {
default:
- if (event == SFP_E_INSERT && sfp->attached)
+ if (event == SFP_E_INSERT)
sfp_sm_mod_next(sfp, SFP_MOD_PROBE, T_SERIAL);
break;
sm_state_to_str(sfp->sm_state),
event_to_str(event));
- sfp_sm_module(sfp, event);
sfp_sm_device(sfp, event);
+ sfp_sm_module(sfp, event);
sfp_sm_main(sfp, event);
dev_dbg(sfp->dev, "SM: exit %s:%s:%s\n",
static void sfp_attach(struct sfp *sfp)
{
- sfp->attached = true;
+ sfp_sm_event(sfp, SFP_E_DEV_ATTACH);
if (sfp->state & SFP_F_PRESENT)
sfp_sm_event(sfp, SFP_E_INSERT);
}
static void sfp_detach(struct sfp *sfp)
{
- sfp->attached = false;
- sfp_sm_event(sfp, SFP_E_REMOVE);
+ sfp_sm_event(sfp, SFP_E_DEV_DETACH);
}
static void sfp_start(struct sfp *sfp)