summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRobert Hancock <hancock@sedsystems.ca>2019-06-07 10:42:36 -0600
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2019-07-26 09:14:05 +0200
commitc7bf2df4504439480afce68e84490d5d976deebc (patch)
tree765d183a5a2bbbbcf58f5d364b10cf45b1ca6c4b /drivers
parentfa4059c5497e42fd9b91da1d32e14792f998e985 (diff)
downloadlinux-stable-c7bf2df4504439480afce68e84490d5d976deebc.tar.gz
linux-stable-c7bf2df4504439480afce68e84490d5d976deebc.tar.bz2
linux-stable-c7bf2df4504439480afce68e84490d5d976deebc.zip
net: sfp: add mutex to prevent concurrent state checks
[ Upstream commit 2158e856f56bb762ef90f3ec244d41a519826f75 ] 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> Signed-off-by: Sasha Levin <sashal@kernel.org>
Diffstat (limited to 'drivers')
-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 8807a806cc47..418522aa2f71 100644
--- a/drivers/net/phy/sfp.c
+++ b/drivers/net/phy/sfp.c
@@ -185,10 +185,11 @@ struct sfp {
struct gpio_desc *gpio[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;
@@ -1718,6 +1719,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;
@@ -1743,6 +1745,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)
@@ -1773,6 +1776,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);