summary refs log tree commit diff
path: root/drivers/net/phy
diff options
context:
space:
mode:
authorRobert Hancock <hancock@sedsystems.ca>2019-06-07 10:42:36 -0600
committerDavid S. Miller <davem@davemloft.net>2019-06-09 19:25:59 -0700
commit2158e856f56bb762ef90f3ec244d41a519826f75 (patch)
tree50eb78dea2a7df27e52f863b4c2a288ac4e54e9f /drivers/net/phy
parent257c25598584f9f7aaccbcd7b9a6faf23aec3156 (diff)
downloadlinux-2158e856f56bb762ef90f3ec244d41a519826f75.tar.gz
net: sfp: add mutex to prevent concurrent state checks
sfp_check_state can potentially be called by both a threaded IRQ handler
and delayed work. If it is concurrently called, it could result in
incorrect state management. Add a st_mutex to protect the state - this
lock gets taken outside of code that checks and handle state changes, and
the existing sm_mutex nests inside of it.

Suggested-by: Russell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: Robert Hancock <hancock@sedsystems.ca>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/phy')
-rw-r--r--drivers/net/phy/sfp.c6
1 files changed, 5 insertions, 1 deletions
diff --git a/drivers/net/phy/sfp.c b/drivers/net/phy/sfp.c
index 44d787d36342..97960d73b4ab 100644
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -188,10 +188,11 @@ struct sfp {
 	int gpio_irq[GPIO_MAX];
 
 	bool attached;
+	struct mutex st_mutex;			/* Protects state */
 	unsigned int state;
 	struct delayed_work poll;
 	struct delayed_work timeout;
-	struct mutex sm_mutex;
+	struct mutex sm_mutex;			/* Protects state machine */
 	unsigned char sm_mod_state;
 	unsigned char sm_dev_state;
 	unsigned short sm_state;
@@ -1721,6 +1722,7 @@ static void sfp_check_state(struct sfp *sfp)
 {
 	unsigned int state, i, changed;
 
+	mutex_lock(&sfp->st_mutex);
 	state = sfp_get_state(sfp);
 	changed = state ^ sfp->state;
 	changed &= SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT;
@@ -1746,6 +1748,7 @@ static void sfp_check_state(struct sfp *sfp)
 		sfp_sm_event(sfp, state & SFP_F_LOS ?
 				SFP_E_LOS_HIGH : SFP_E_LOS_LOW);
 	rtnl_unlock();
+	mutex_unlock(&sfp->st_mutex);
 }
 
 static irqreturn_t sfp_irq(int irq, void *data)
@@ -1776,6 +1779,7 @@ static struct sfp *sfp_alloc(struct device *dev)
 	sfp->dev = dev;
 
 	mutex_init(&sfp->sm_mutex);
+	mutex_init(&sfp->st_mutex);
 	INIT_DELAYED_WORK(&sfp->poll, sfp_poll);
 	INIT_DELAYED_WORK(&sfp->timeout, sfp_timeout);