Merge branch 'SFP-polling-fixes'
Robert Hancock says: ==================== SFP polling fixes This has an updated version of an earlier patch to ensure that SFP operations are stopped during shutdown, and another patch suggested by Russell King to address a potential concurrency issue with SFP state checks. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -185,12 +185,14 @@ struct sfp {
|
|||||||
int (*write)(struct sfp *, bool, u8, void *, size_t);
|
int (*write)(struct sfp *, bool, u8, void *, size_t);
|
||||||
|
|
||||||
struct gpio_desc *gpio[GPIO_MAX];
|
struct gpio_desc *gpio[GPIO_MAX];
|
||||||
|
int gpio_irq[GPIO_MAX];
|
||||||
|
|
||||||
bool attached;
|
bool attached;
|
||||||
|
struct mutex st_mutex; /* Protects state */
|
||||||
unsigned int state;
|
unsigned int state;
|
||||||
struct delayed_work poll;
|
struct delayed_work poll;
|
||||||
struct delayed_work timeout;
|
struct delayed_work timeout;
|
||||||
struct mutex sm_mutex;
|
struct mutex sm_mutex; /* Protects state machine */
|
||||||
unsigned char sm_mod_state;
|
unsigned char sm_mod_state;
|
||||||
unsigned char sm_dev_state;
|
unsigned char sm_dev_state;
|
||||||
unsigned short sm_state;
|
unsigned short sm_state;
|
||||||
@@ -1720,6 +1722,7 @@ static void sfp_check_state(struct sfp *sfp)
|
|||||||
{
|
{
|
||||||
unsigned int state, i, changed;
|
unsigned int state, i, changed;
|
||||||
|
|
||||||
|
mutex_lock(&sfp->st_mutex);
|
||||||
state = sfp_get_state(sfp);
|
state = sfp_get_state(sfp);
|
||||||
changed = state ^ sfp->state;
|
changed = state ^ sfp->state;
|
||||||
changed &= SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT;
|
changed &= SFP_F_PRESENT | SFP_F_LOS | SFP_F_TX_FAULT;
|
||||||
@@ -1745,6 +1748,7 @@ static void sfp_check_state(struct sfp *sfp)
|
|||||||
sfp_sm_event(sfp, state & SFP_F_LOS ?
|
sfp_sm_event(sfp, state & SFP_F_LOS ?
|
||||||
SFP_E_LOS_HIGH : SFP_E_LOS_LOW);
|
SFP_E_LOS_HIGH : SFP_E_LOS_LOW);
|
||||||
rtnl_unlock();
|
rtnl_unlock();
|
||||||
|
mutex_unlock(&sfp->st_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static irqreturn_t sfp_irq(int irq, void *data)
|
static irqreturn_t sfp_irq(int irq, void *data)
|
||||||
@@ -1775,6 +1779,7 @@ static struct sfp *sfp_alloc(struct device *dev)
|
|||||||
sfp->dev = dev;
|
sfp->dev = dev;
|
||||||
|
|
||||||
mutex_init(&sfp->sm_mutex);
|
mutex_init(&sfp->sm_mutex);
|
||||||
|
mutex_init(&sfp->st_mutex);
|
||||||
INIT_DELAYED_WORK(&sfp->poll, sfp_poll);
|
INIT_DELAYED_WORK(&sfp->poll, sfp_poll);
|
||||||
INIT_DELAYED_WORK(&sfp->timeout, sfp_timeout);
|
INIT_DELAYED_WORK(&sfp->timeout, sfp_timeout);
|
||||||
|
|
||||||
@@ -1802,7 +1807,7 @@ static int sfp_probe(struct platform_device *pdev)
|
|||||||
struct i2c_adapter *i2c;
|
struct i2c_adapter *i2c;
|
||||||
struct sfp *sfp;
|
struct sfp *sfp;
|
||||||
bool poll = false;
|
bool poll = false;
|
||||||
int irq, err, i;
|
int err, i;
|
||||||
|
|
||||||
sfp = sfp_alloc(&pdev->dev);
|
sfp = sfp_alloc(&pdev->dev);
|
||||||
if (IS_ERR(sfp))
|
if (IS_ERR(sfp))
|
||||||
@@ -1901,19 +1906,22 @@ static int sfp_probe(struct platform_device *pdev)
|
|||||||
if (gpio_flags[i] != GPIOD_IN || !sfp->gpio[i])
|
if (gpio_flags[i] != GPIOD_IN || !sfp->gpio[i])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
irq = gpiod_to_irq(sfp->gpio[i]);
|
sfp->gpio_irq[i] = gpiod_to_irq(sfp->gpio[i]);
|
||||||
if (!irq) {
|
if (!sfp->gpio_irq[i]) {
|
||||||
poll = true;
|
poll = true;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = devm_request_threaded_irq(sfp->dev, irq, NULL, sfp_irq,
|
err = devm_request_threaded_irq(sfp->dev, sfp->gpio_irq[i],
|
||||||
|
NULL, sfp_irq,
|
||||||
IRQF_ONESHOT |
|
IRQF_ONESHOT |
|
||||||
IRQF_TRIGGER_RISING |
|
IRQF_TRIGGER_RISING |
|
||||||
IRQF_TRIGGER_FALLING,
|
IRQF_TRIGGER_FALLING,
|
||||||
dev_name(sfp->dev), sfp);
|
dev_name(sfp->dev), sfp);
|
||||||
if (err)
|
if (err) {
|
||||||
|
sfp->gpio_irq[i] = 0;
|
||||||
poll = true;
|
poll = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (poll)
|
if (poll)
|
||||||
@@ -1944,9 +1952,26 @@ static int sfp_remove(struct platform_device *pdev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sfp_shutdown(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct sfp *sfp = platform_get_drvdata(pdev);
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < GPIO_MAX; i++) {
|
||||||
|
if (!sfp->gpio_irq[i])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
devm_free_irq(sfp->dev, sfp->gpio_irq[i], sfp);
|
||||||
|
}
|
||||||
|
|
||||||
|
cancel_delayed_work_sync(&sfp->poll);
|
||||||
|
cancel_delayed_work_sync(&sfp->timeout);
|
||||||
|
}
|
||||||
|
|
||||||
static struct platform_driver sfp_driver = {
|
static struct platform_driver sfp_driver = {
|
||||||
.probe = sfp_probe,
|
.probe = sfp_probe,
|
||||||
.remove = sfp_remove,
|
.remove = sfp_remove,
|
||||||
|
.shutdown = sfp_shutdown,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "sfp",
|
.name = "sfp",
|
||||||
.of_match_table = sfp_of_match,
|
.of_match_table = sfp_of_match,
|
||||||
|
|||||||
Reference in New Issue
Block a user