Commit 9e49fe4d authored by David S. Miller's avatar David S. Miller
Browse files

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 5270041d 2158e856
Loading
Loading
Loading
Loading
+31 −6
Original line number Diff line number Diff line
@@ -185,12 +185,14 @@ struct sfp {
	int (*write)(struct sfp *, bool, u8, void *, size_t);

	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;
	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;
@@ -1720,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;
@@ -1745,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)
@@ -1775,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);

@@ -1802,7 +1807,7 @@ static int sfp_probe(struct platform_device *pdev)
	struct i2c_adapter *i2c;
	struct sfp *sfp;
	bool poll = false;
	int irq, err, i;
	int err, i;

	sfp = sfp_alloc(&pdev->dev);
	if (IS_ERR(sfp))
@@ -1901,20 +1906,23 @@ static int sfp_probe(struct platform_device *pdev)
		if (gpio_flags[i] != GPIOD_IN || !sfp->gpio[i])
			continue;

		irq = gpiod_to_irq(sfp->gpio[i]);
		if (!irq) {
		sfp->gpio_irq[i] = gpiod_to_irq(sfp->gpio[i]);
		if (!sfp->gpio_irq[i]) {
			poll = true;
			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_TRIGGER_RISING |
						IRQF_TRIGGER_FALLING,
						dev_name(sfp->dev), sfp);
		if (err)
		if (err) {
			sfp->gpio_irq[i] = 0;
			poll = true;
		}
	}

	if (poll)
		mod_delayed_work(system_wq, &sfp->poll, poll_jiffies);
@@ -1944,9 +1952,26 @@ static int sfp_remove(struct platform_device *pdev)
	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 = {
	.probe = sfp_probe,
	.remove = sfp_remove,
	.shutdown = sfp_shutdown,
	.driver = {
		.name = "sfp",
		.of_match_table = sfp_of_match,