[PATCH linux dev-4.10 1/3] drivers/fsi/sbefifo: refactor to upstream list state

Eddie James eajames at linux.vnet.ibm.com
Fri Sep 22 08:55:21 AEST 2017



On 09/21/2017 05:43 PM, Eddie James wrote:
> From: "Edward A. James" <eajames at us.ibm.com>
>
> Includes various fixes:
>   - check for complete while waiting for data in read()
>   - fix probe if probe fails
>   - general cleanup
>   - slightly safer (earlier) get_client()
>   - reorder some of the remove() operations for safety

To clarify, this hasn't actually been sent upstream yet. But no changes 
planned to send this upstream.

Thanks,
Eddie

>
> Signed-off-by: Edward A. James <eajames at us.ibm.com>
> ---
>   drivers/fsi/fsi-sbefifo.c   | 329 ++++++++++++++++++++++++--------------------
>   include/linux/fsi-sbefifo.h |   6 +-
>   2 files changed, 180 insertions(+), 155 deletions(-)
>
> diff --git a/drivers/fsi/fsi-sbefifo.c b/drivers/fsi/fsi-sbefifo.c
> index 1c37ff7..5d25ade 100644
> --- a/drivers/fsi/fsi-sbefifo.c
> +++ b/drivers/fsi/fsi-sbefifo.c
> @@ -11,20 +11,27 @@
>    * GNU General Public License for more details.
>    */
>
> -#include <linux/delay.h>
> +#include <linux/device.h>
>   #include <linux/errno.h>
> -#include <linux/idr.h>
> +#include <linux/fs.h>
>   #include <linux/fsi.h>
> +#include <linux/fsi-sbefifo.h>
> +#include <linux/idr.h>
> +#include <linux/kernel.h>
> +#include <linux/kref.h>
>   #include <linux/list.h>
>   #include <linux/miscdevice.h>
>   #include <linux/module.h>
>   #include <linux/of.h>
> +#include <linux/of_device.h>
>   #include <linux/of_platform.h>
>   #include <linux/poll.h>
>   #include <linux/sched.h>
>   #include <linux/slab.h>
> +#include <linux/spinlock.h>
>   #include <linux/timer.h>
>   #include <linux/uaccess.h>
> +#include <linux/wait.h>
>
>   /*
>    * The SBEFIFO is a pipe-like FSI device for communicating with
> @@ -44,14 +51,15 @@
>   #define   SBEFIFO_EOT_MAGIC		0xffffffff
>   #define SBEFIFO_EOT_ACK		0x14
>
> +#define SBEFIFO_RESCHEDULE	msecs_to_jiffies(500)
> +
>   struct sbefifo {
>   	struct timer_list poll_timer;
> -	struct fsi_device *fsi_dev;
> -	struct miscdevice mdev;
> +	struct fsi_device *fsi_dev;	/* parent fsi device */
> +	struct miscdevice mdev;		/* /dev/ entry */
>   	wait_queue_head_t wait;
> -	struct list_head link;
>   	struct list_head xfrs;
> -	struct kref kref;
> +	struct kref kref;		/* reference counter */
>   	spinlock_t lock;
>   	char name[32];
>   	int idx;
> @@ -87,14 +95,12 @@ struct sbefifo_client {
>   	unsigned long f_flags;
>   };
>
> -static struct list_head sbefifo_fifos;
> -
>   static DEFINE_IDA(sbefifo_ida);
>
>   static int sbefifo_inw(struct sbefifo *sbefifo, int reg, u32 *word)
>   {
>   	int rc;
> -	u32 raw_word;
> +	__be32 raw_word;
>
>   	rc = fsi_device_read(sbefifo->fsi_dev, reg, &raw_word,
>   			     sizeof(raw_word));
> @@ -102,17 +108,19 @@ static int sbefifo_inw(struct sbefifo *sbefifo, int reg, u32 *word)
>   		return rc;
>
>   	*word = be32_to_cpu(raw_word);
> +
>   	return 0;
>   }
>
>   static int sbefifo_outw(struct sbefifo *sbefifo, int reg, u32 word)
>   {
> -	u32 raw_word = cpu_to_be32(word);
> +	__be32 raw_word = cpu_to_be32(word);
>
>   	return fsi_device_write(sbefifo->fsi_dev, reg, &raw_word,
>   				sizeof(raw_word));
>   }
>
> +/* Don't flip endianness of data to/from FIFO, just pass through. */
>   static int sbefifo_readw(struct sbefifo *sbefifo, u32 *word)
>   {
>   	return fsi_device_read(sbefifo->fsi_dev, SBEFIFO_DWN, word,
> @@ -136,7 +144,7 @@ static int sbefifo_ack_eot(struct sbefifo *sbefifo)
>   		return ret;
>
>   	return sbefifo_outw(sbefifo, SBEFIFO_DWN | SBEFIFO_EOT_ACK,
> -			SBEFIFO_EOT_MAGIC);
> +			    SBEFIFO_EOT_MAGIC);
>   }
>
>   static size_t sbefifo_dev_nwreadable(u32 sts)
> @@ -210,6 +218,7 @@ static bool sbefifo_buf_readnb(struct sbefifo_buf *buf, size_t n)
>   		rpos = buf->buf;
>
>   	WRITE_ONCE(buf->rpos, rpos);
> +
>   	return rpos == wpos;
>   }
>
> @@ -229,14 +238,14 @@ static bool sbefifo_buf_wrotenb(struct sbefifo_buf *buf, size_t n)
>   		set_bit(SBEFIFO_BUF_FULL, &buf->flags);
>
>   	WRITE_ONCE(buf->wpos, wpos);
> +
>   	return rpos == wpos;
>   }
>
>   static void sbefifo_free(struct kref *kref)
>   {
> -	struct sbefifo *sbefifo;
> +	struct sbefifo *sbefifo = container_of(kref, struct sbefifo, kref);
>
> -	sbefifo = container_of(kref, struct sbefifo, kref);
>   	kfree(sbefifo);
>   }
>
> @@ -255,9 +264,12 @@ static struct sbefifo_xfr *sbefifo_enq_xfr(struct sbefifo_client *client)
>   	struct sbefifo *sbefifo = client->dev;
>   	struct sbefifo_xfr *xfr;
>
> +	if (READ_ONCE(sbefifo->rc))
> +		return ERR_PTR(sbefifo->rc);
> +
>   	xfr = kzalloc(sizeof(*xfr), GFP_KERNEL);
>   	if (!xfr)
> -		return NULL;
> +		return ERR_PTR(-ENOMEM);
>
>   	xfr->rbuf = &client->rbuf;
>   	xfr->wbuf = &client->wbuf;
> @@ -267,21 +279,12 @@ static struct sbefifo_xfr *sbefifo_enq_xfr(struct sbefifo_client *client)
>   	return xfr;
>   }
>
> -static struct sbefifo_xfr *sbefifo_client_next_xfr(
> -		struct sbefifo_client *client)
> -{
> -	if (list_empty(&client->xfrs))
> -		return NULL;
> -
> -	return container_of(client->xfrs.next, struct sbefifo_xfr,
> -			client);
> -}
> -
>   static bool sbefifo_xfr_rsp_pending(struct sbefifo_client *client)
>   {
> -	struct sbefifo_xfr *xfr;
> +	struct sbefifo_xfr *xfr = list_first_entry_or_null(&client->xfrs,
> +							   struct sbefifo_xfr,
> +							   client);
>
> -	xfr = sbefifo_client_next_xfr(client);
>   	if (xfr && test_bit(SBEFIFO_XFR_RESP_PENDING, &xfr->flags))
>   		return true;
>
> @@ -309,10 +312,11 @@ static struct sbefifo_client *sbefifo_new_client(struct sbefifo *sbefifo)
>
>   static void sbefifo_client_release(struct kref *kref)
>   {
> -	struct sbefifo_client *client;
>   	struct sbefifo_xfr *xfr;
> +	struct sbefifo_client *client = container_of(kref,
> +						     struct sbefifo_client,
> +						     kref);
>
> -	client = container_of(kref, struct sbefifo_client, kref);
>   	list_for_each_entry(xfr, &client->xfrs, client) {
>   		/*
>   		 * The client left with pending or running xfrs.
> @@ -349,6 +353,7 @@ static struct sbefifo_xfr *sbefifo_next_xfr(struct sbefifo *sbefifo)
>   			kfree(xfr);
>   			continue;
>   		}
> +
>   		return xfr;
>   	}
>
> @@ -370,7 +375,7 @@ static void sbefifo_poll_timer(unsigned long data)
>
>   	spin_lock(&sbefifo->lock);
>   	xfr = list_first_entry_or_null(&sbefifo->xfrs, struct sbefifo_xfr,
> -			xfrs);
> +				       xfrs);
>   	if (!xfr)
>   		goto out_unlock;
>
> @@ -388,8 +393,7 @@ static void sbefifo_poll_timer(unsigned long data)
>
>   	 /* Drain the write buffer. */
>   	while ((bufn = sbefifo_buf_nbreadable(wbuf))) {
> -		ret = sbefifo_inw(sbefifo, SBEFIFO_UP | SBEFIFO_STS,
> -				&sts);
> +		ret = sbefifo_inw(sbefifo, SBEFIFO_UP | SBEFIFO_STS, &sts);
>   		if (ret)
>   			goto out;
>
> @@ -397,7 +401,7 @@ static void sbefifo_poll_timer(unsigned long data)
>   		if (devn == 0) {
>   			/* No open slot for write.  Reschedule. */
>   			sbefifo->poll_timer.expires = jiffies +
> -				msecs_to_jiffies(500);
> +				SBEFIFO_RESCHEDULE;
>   			add_timer(&sbefifo->poll_timer);
>   			goto out_unlock;
>   		}
> @@ -414,9 +418,8 @@ static void sbefifo_poll_timer(unsigned long data)
>
>   	 /* Send EOT if the writer is finished. */
>   	if (test_and_clear_bit(SBEFIFO_XFR_WRITE_DONE, &xfr->flags)) {
> -		ret = sbefifo_outw(sbefifo,
> -				SBEFIFO_UP | SBEFIFO_EOT_RAISE,
> -				SBEFIFO_EOT_MAGIC);
> +		ret = sbefifo_outw(sbefifo, SBEFIFO_UP | SBEFIFO_EOT_RAISE,
> +				   SBEFIFO_EOT_MAGIC);
>   		if (ret)
>   			goto out;
>
> @@ -438,7 +441,7 @@ static void sbefifo_poll_timer(unsigned long data)
>   		if (devn == 0) {
>   			/* No data yet.  Reschedule. */
>   			sbefifo->poll_timer.expires = jiffies +
> -				msecs_to_jiffies(500);
> +				SBEFIFO_RESCHEDULE;
>   			add_timer(&sbefifo->poll_timer);
>   			goto out_unlock;
>   		}
> @@ -466,7 +469,7 @@ static void sbefifo_poll_timer(unsigned long data)
>   			set_bit(SBEFIFO_XFR_COMPLETE, &xfr->flags);
>   			list_del(&xfr->xfrs);
>   			if (unlikely(test_bit(SBEFIFO_XFR_CANCEL,
> -							&xfr->flags)))
> +					      &xfr->flags)))
>   				kfree(xfr);
>   			break;
>   		}
> @@ -476,7 +479,7 @@ static void sbefifo_poll_timer(unsigned long data)
>   	if (unlikely(ret)) {
>   		sbefifo->rc = ret;
>   		dev_err(&sbefifo->fsi_dev->dev,
> -				"Fatal bus access failure: %d\n", ret);
> +			"Fatal bus access failure: %d\n", ret);
>   		list_for_each_entry(xfr, &sbefifo->xfrs, xfrs)
>   			kfree(xfr);
>   		INIT_LIST_HEAD(&sbefifo->xfrs);
> @@ -497,7 +500,7 @@ static void sbefifo_poll_timer(unsigned long data)
>   static int sbefifo_open(struct inode *inode, struct file *file)
>   {
>   	struct sbefifo *sbefifo = container_of(file->private_data,
> -			struct sbefifo, mdev);
> +					       struct sbefifo, mdev);
>   	struct sbefifo_client *client;
>   	int ret;
>
> @@ -535,6 +538,19 @@ static unsigned int sbefifo_poll(struct file *file, poll_table *wait)
>   	return mask;
>   }
>
> +static bool sbefifo_read_ready(struct sbefifo *sbefifo,
> +			       struct sbefifo_client *client, size_t *n)
> +{
> +	struct sbefifo_xfr *xfr = list_first_entry_or_null(&client->xfrs,
> +							   struct sbefifo_xfr,
> +							   client);
> +
> +	*n = sbefifo_buf_nbreadable(&client->rbuf);
> +
> +	return READ_ONCE(sbefifo->rc) || *n ||
> +		(xfr && test_bit(SBEFIFO_XFR_COMPLETE, &xfr->flags));
> +}
> +
>   static ssize_t sbefifo_read_common(struct sbefifo_client *client,
>   				   char __user *ubuf, char *kbuf, size_t len)
>   {
> @@ -551,30 +567,38 @@ static ssize_t sbefifo_read_common(struct sbefifo_client *client,
>
>   	sbefifo_get_client(client);
>   	if (wait_event_interruptible(sbefifo->wait,
> -				(ret = READ_ONCE(sbefifo->rc)) ||
> -				(n = sbefifo_buf_nbreadable(
> -						&client->rbuf)))) {
> -		sbefifo_put_client(client);
> -		return -ERESTARTSYS;
> +				     sbefifo_read_ready(sbefifo, client,
> +							&n))) {
> +		ret = -ERESTARTSYS;
> +		goto out;
>   	}
> +
> +	ret = READ_ONCE(sbefifo->rc);
>   	if (ret) {
>   		INIT_LIST_HEAD(&client->xfrs);
> -		sbefifo_put_client(client);
> -		return ret;
> +		goto out;
>   	}
>
>   	n = min_t(size_t, n, len);
>
>   	if (ubuf) {
>   		if (copy_to_user(ubuf, READ_ONCE(client->rbuf.rpos), n)) {
> -			sbefifo_put_client(client);
> -			return -EFAULT;
> +			ret = -EFAULT;
> +			goto out;
>   		}
> -	} else
> +	} else {
>   		memcpy(kbuf, READ_ONCE(client->rbuf.rpos), n);
> +	}
>
>   	if (sbefifo_buf_readnb(&client->rbuf, n)) {
> -		xfr = sbefifo_client_next_xfr(client);
> +		xfr = list_first_entry_or_null(&client->xfrs,
> +					       struct sbefifo_xfr, client);
> +		if (!xfr) {
> +			/* should be impossible to not have an xfr here */
> +			wake_up(&sbefifo->wait);
> +			goto out;
> +		}
> +
>   		if (!test_bit(SBEFIFO_XFR_COMPLETE, &xfr->flags)) {
>   			/*
>   			 * Fill the read buffer back up.
> @@ -589,22 +613,31 @@ static ssize_t sbefifo_read_common(struct sbefifo_client *client,
>   		}
>   	}
>
> -	sbefifo_put_client(client);
> +	ret = n;
>
> -	return n;
> +out:
> +	sbefifo_put_client(client);
> +	return ret;
>   }
>
> -static ssize_t sbefifo_read(struct file *file, char __user *buf,
> -		size_t len, loff_t *offset)
> +static ssize_t sbefifo_read(struct file *file, char __user *buf, size_t len,
> +			    loff_t *offset)
>   {
>   	struct sbefifo_client *client = file->private_data;
>
> -	WARN_ON(*offset);
> +	return sbefifo_read_common(client, buf, NULL, len);
> +}
>
> -	if (!access_ok(VERIFY_WRITE, buf, len))
> -		return -EFAULT;
> +static bool sbefifo_write_ready(struct sbefifo *sbefifo,
> +				struct sbefifo_xfr *xfr,
> +				struct sbefifo_client *client, size_t *n)
> +{
> +	struct sbefifo_xfr *next = list_first_entry_or_null(&client->xfrs,
> +							    struct sbefifo_xfr,
> +							    client);
>
> -	return sbefifo_read_common(client, buf, NULL, len);
> +	*n = sbefifo_buf_nbwriteable(&client->wbuf);
> +	return READ_ONCE(sbefifo->rc) || (next == xfr && *n);
>   }
>
>   static ssize_t sbefifo_write_common(struct sbefifo_client *client,
> @@ -612,6 +645,7 @@ static ssize_t sbefifo_write_common(struct sbefifo_client *client,
>   				    size_t len)
>   {
>   	struct sbefifo *sbefifo = client->dev;
> +	struct sbefifo_buf *wbuf = &client->wbuf;
>   	struct sbefifo_xfr *xfr;
>   	ssize_t ret = 0;
>   	size_t n;
> @@ -622,24 +656,26 @@ static ssize_t sbefifo_write_common(struct sbefifo_client *client,
>   	if (!len)
>   		return 0;
>
> -	n = sbefifo_buf_nbwriteable(&client->wbuf);
> +	sbefifo_get_client(client);
> +	n = sbefifo_buf_nbwriteable(wbuf);
>
>   	spin_lock_irq(&sbefifo->lock);
> -	xfr = sbefifo_next_xfr(sbefifo);
>
> +	xfr = sbefifo_next_xfr(sbefifo);	/* next xfr to be executed */
>   	if ((client->f_flags & O_NONBLOCK) && xfr && n < len) {
>   		spin_unlock_irq(&sbefifo->lock);
> -		return -EAGAIN;
> +		ret = -EAGAIN;
> +		goto out;
>   	}
>
> -	xfr = sbefifo_enq_xfr(client);
> -	if (!xfr) {
> +	xfr = sbefifo_enq_xfr(client);		/* this xfr queued up */
> +	if (IS_ERR(xfr)) {
>   		spin_unlock_irq(&sbefifo->lock);
> -		return -ENOMEM;
> +		ret = PTR_ERR(xfr);
> +		goto out;
>   	}
> -	spin_unlock_irq(&sbefifo->lock);
>
> -	sbefifo_get_client(client);
> +	spin_unlock_irq(&sbefifo->lock);
>
>   	/*
>   	 * Partial writes are not really allowed in that EOT is sent exactly
> @@ -647,49 +683,47 @@ static ssize_t sbefifo_write_common(struct sbefifo_client *client,
>   	 */
>   	while (len) {
>   		if (wait_event_interruptible(sbefifo->wait,
> -				READ_ONCE(sbefifo->rc) ||
> -					(sbefifo_client_next_xfr(client) == xfr &&
> -					 (n = sbefifo_buf_nbwriteable(
> -							&client->wbuf))))) {
> +					     sbefifo_write_ready(sbefifo, xfr,
> +								 client,
> +								 &n))) {
>   			set_bit(SBEFIFO_XFR_CANCEL, &xfr->flags);
>   			sbefifo_get(sbefifo);
>   			if (mod_timer(&sbefifo->poll_timer, jiffies))
>   				sbefifo_put(sbefifo);
> -
> -			sbefifo_put_client(client);
> -			return -ERESTARTSYS;
> +			ret = -ERESTARTSYS;
> +			goto out;
>   		}
> -		if (sbefifo->rc) {
> +
> +		ret = READ_ONCE(sbefifo->rc);
> +		if (ret) {
>   			INIT_LIST_HEAD(&client->xfrs);
> -			sbefifo_put_client(client);
> -			return sbefifo->rc;
> +			goto out;
>   		}
>
>   		n = min_t(size_t, n, len);
>
>   		if (ubuf) {
> -			if (copy_from_user(READ_ONCE(client->wbuf.wpos), ubuf,
> -			    n)) {
> +			if (copy_from_user(READ_ONCE(wbuf->wpos), ubuf, n)) {
>   				set_bit(SBEFIFO_XFR_CANCEL, &xfr->flags);
>   				sbefifo_get(sbefifo);
>   				if (mod_timer(&sbefifo->poll_timer, jiffies))
>   					sbefifo_put(sbefifo);
> -				sbefifo_put_client(client);
> -				return -EFAULT;
> +				ret = -EFAULT;
> +				goto out;
>   			}
>
>   			ubuf += n;
>   		} else {
> -			memcpy(READ_ONCE(client->wbuf.wpos), kbuf, n);
> +			memcpy(READ_ONCE(wbuf->wpos), kbuf, n);
>   			kbuf += n;
>   		}
>
> -		sbefifo_buf_wrotenb(&client->wbuf, n);
> +		sbefifo_buf_wrotenb(wbuf, n);
>   		len -= n;
>   		ret += n;
>
> -		/* set flag before starting the worker, as it may run through
> -		 * and check the flag before we exit this loop!
> +		/* Set this before starting timer to avoid race condition on
> +		 * this flag with the timer function writer.
>   		 */
>   		if (!len)
>   			set_bit(SBEFIFO_XFR_WRITE_DONE, &xfr->flags);
> @@ -702,21 +736,16 @@ static ssize_t sbefifo_write_common(struct sbefifo_client *client,
>   			sbefifo_put(sbefifo);
>   	}
>
> +out:
>   	sbefifo_put_client(client);
> -
>   	return ret;
>   }
>
>   static ssize_t sbefifo_write(struct file *file, const char __user *buf,
> -		size_t len, loff_t *offset)
> +			     size_t len, loff_t *offset)
>   {
>   	struct sbefifo_client *client = file->private_data;
>
> -	WARN_ON(*offset);
> -
> -	if (!access_ok(VERIFY_READ, buf, len))
> -		return -EFAULT;
> -
>   	return sbefifo_write_common(client, buf, NULL, len);
>   }
>
> @@ -742,18 +771,15 @@ static int sbefifo_release(struct inode *inode, struct file *file)
>   struct sbefifo_client *sbefifo_drv_open(struct device *dev,
>   					unsigned long flags)
>   {
> -	struct sbefifo_client *client = NULL;
> -	struct sbefifo *sbefifo;
> -	struct fsi_device *fsi_dev = to_fsi_dev(dev);
> +	struct sbefifo_client *client;
> +	struct sbefifo *sbefifo = dev_get_drvdata(dev);
>
> -	list_for_each_entry(sbefifo, &sbefifo_fifos, link) {
> -		if (sbefifo->fsi_dev != fsi_dev)
> -			continue;
> +	if (!sbefifo)
> +		return NULL;
>
> -		client = sbefifo_new_client(sbefifo);
> -		if (client)
> -			client->f_flags = flags;
> -	}
> +	client = sbefifo_new_client(sbefifo);
> +	if (client)
> +		client->f_flags = flags;
>
>   	return client;
>   }
> @@ -802,95 +828,92 @@ static int sbefifo_probe(struct device *dev)
>   	u32 sts;
>   	int ret, child_idx = 0;
>
> -	dev_dbg(dev, "Found sbefifo device\n");
>   	sbefifo = kzalloc(sizeof(*sbefifo), GFP_KERNEL);
>   	if (!sbefifo)
>   		return -ENOMEM;
>
>   	sbefifo->fsi_dev = fsi_dev;
>
> -	ret = sbefifo_inw(sbefifo,
> -			SBEFIFO_UP | SBEFIFO_STS, &sts);
> +	ret = sbefifo_inw(sbefifo, SBEFIFO_UP | SBEFIFO_STS, &sts);
>   	if (ret)
>   		return ret;
> +
>   	if (!(sts & SBEFIFO_EMPTY)) {
> -		dev_err(&sbefifo->fsi_dev->dev,
> -				"Found data in upstream fifo\n");
> +		dev_err(dev, "Found data in upstream fifo\n");
>   		return -EIO;
>   	}
>
>   	ret = sbefifo_inw(sbefifo, SBEFIFO_DWN | SBEFIFO_STS, &sts);
>   	if (ret)
>   		return ret;
> +
>   	if (!(sts & SBEFIFO_EMPTY)) {
> -		dev_err(&sbefifo->fsi_dev->dev,
> -				"Found data in downstream fifo\n");
> +		dev_err(dev, "found data in downstream fifo\n");
>   		return -EIO;
>   	}
>
> -	sbefifo->mdev.minor = MISC_DYNAMIC_MINOR;
> -	sbefifo->mdev.fops = &sbefifo_fops;
> -	sbefifo->mdev.name = sbefifo->name;
> -	sbefifo->mdev.parent = dev;
>   	spin_lock_init(&sbefifo->lock);
>   	kref_init(&sbefifo->kref);
> +	init_waitqueue_head(&sbefifo->wait);
> +	INIT_LIST_HEAD(&sbefifo->xfrs);
>
>   	sbefifo->idx = ida_simple_get(&sbefifo_ida, 1, INT_MAX, GFP_KERNEL);
>   	snprintf(sbefifo->name, sizeof(sbefifo->name), "sbefifo%d",
> -			sbefifo->idx);
> -	init_waitqueue_head(&sbefifo->wait);
> -	INIT_LIST_HEAD(&sbefifo->xfrs);
> +		 sbefifo->idx);
>
>   	/* This bit of silicon doesn't offer any interrupts... */
>   	setup_timer(&sbefifo->poll_timer, sbefifo_poll_timer,
> -			(unsigned long)sbefifo);
> -
> -	if (dev->of_node) {
> -		/* create platform devs for dts child nodes (occ, etc) */
> -		for_each_child_of_node(dev->of_node, np) {
> -			snprintf(child_name, sizeof(child_name), "%s-dev%d",
> -				 sbefifo->name, child_idx++);
> -			child = of_platform_device_create(np, child_name, dev);
> -			if (!child)
> -				dev_warn(&sbefifo->fsi_dev->dev,
> -					 "failed to create child node dev\n");
> -		}
> +		    (unsigned long)sbefifo);
> +
> +	sbefifo->mdev.minor = MISC_DYNAMIC_MINOR;
> +	sbefifo->mdev.fops = &sbefifo_fops;
> +	sbefifo->mdev.name = sbefifo->name;
> +	sbefifo->mdev.parent = dev;
> +	ret = misc_register(&sbefifo->mdev);
> +	if (ret) {
> +		dev_err(dev, "failed to register miscdevice: %d\n", ret);
> +		ida_simple_remove(&sbefifo_ida, sbefifo->idx);
> +		sbefifo_put(sbefifo);
> +		return ret;
> +	}
> +
> +	/* create platform devs for dts child nodes (occ, etc) */
> +	for_each_available_child_of_node(dev->of_node, np) {
> +		snprintf(child_name, sizeof(child_name), "%s-dev%d",
> +			 sbefifo->name, child_idx++);
> +		child = of_platform_device_create(np, child_name, dev);
> +		if (!child)
> +			dev_warn(dev, "failed to create child %s dev\n",
> +				 child_name);
>   	}
>
> -	list_add(&sbefifo->link, &sbefifo_fifos);
> -	
> -	return misc_register(&sbefifo->mdev);
> +	dev_set_drvdata(dev, sbefifo);
> +
> +	return 0;
>   }
>
>   static int sbefifo_remove(struct device *dev)
>   {
> -	struct fsi_device *fsi_dev = to_fsi_dev(dev);
> -	struct sbefifo *sbefifo, *sbefifo_tmp;
> +	struct sbefifo *sbefifo = dev_get_drvdata(dev);
>   	struct sbefifo_xfr *xfr;
>
> -	list_for_each_entry_safe(sbefifo, sbefifo_tmp, &sbefifo_fifos, link) {
> -		if (sbefifo->fsi_dev != fsi_dev)
> -			continue;
> -
> -		device_for_each_child(dev, NULL, sbefifo_unregister_child);
> +	WRITE_ONCE(sbefifo->rc, -ENODEV);
> +	wake_up(&sbefifo->wait);
>
> -		misc_deregister(&sbefifo->mdev);
> -		list_del(&sbefifo->link);
> -		ida_simple_remove(&sbefifo_ida, sbefifo->idx);
> +	misc_deregister(&sbefifo->mdev);
> +	device_for_each_child(dev, NULL, sbefifo_unregister_child);
>
> -		if (del_timer_sync(&sbefifo->poll_timer))
> -			sbefifo_put(sbefifo);
> +	ida_simple_remove(&sbefifo_ida, sbefifo->idx);
>
> -		spin_lock(&sbefifo->lock);
> -		list_for_each_entry(xfr, &sbefifo->xfrs, xfrs)
> -			kfree(xfr);
> -		spin_unlock(&sbefifo->lock);
> +	if (del_timer_sync(&sbefifo->poll_timer))
> +		sbefifo_put(sbefifo);
>
> -		WRITE_ONCE(sbefifo->rc, -ENODEV);
> +	spin_lock(&sbefifo->lock);
> +	list_for_each_entry(xfr, &sbefifo->xfrs, xfrs)
> +		kfree(xfr);
> +	spin_unlock(&sbefifo->lock);
>
> -		wake_up(&sbefifo->wait);
> -		sbefifo_put(sbefifo);
> -	}
> +	sbefifo_put(sbefifo);
>
>   	return 0;
>   }
> @@ -915,17 +938,19 @@ static int sbefifo_remove(struct device *dev)
>
>   static int sbefifo_init(void)
>   {
> -	INIT_LIST_HEAD(&sbefifo_fifos);
>   	return fsi_driver_register(&sbefifo_drv);
>   }
>
>   static void sbefifo_exit(void)
>   {
>   	fsi_driver_unregister(&sbefifo_drv);
> +
> +	ida_destroy(&sbefifo_ida);
>   }
>
>   module_init(sbefifo_init);
>   module_exit(sbefifo_exit);
>   MODULE_LICENSE("GPL");
>   MODULE_AUTHOR("Brad Bishop <bradleyb at fuzziesquirrel.com>");
> -MODULE_DESCRIPTION("Linux device interface to the POWER self boot engine");
> +MODULE_AUTHOR("Eddie James <eajames at linux.vnet.ibm.com>");
> +MODULE_DESCRIPTION("Linux device interface to the POWER Self Boot Engine");
> diff --git a/include/linux/fsi-sbefifo.h b/include/linux/fsi-sbefifo.h
> index 1b46c63..8e55891 100644
> --- a/include/linux/fsi-sbefifo.h
> +++ b/include/linux/fsi-sbefifo.h
> @@ -13,8 +13,8 @@
>    * GNU General Public License for more details.
>    */
>
> -#ifndef __FSI_SBEFIFO_H__
> -#define __FSI_SBEFIFO_H__
> +#ifndef LINUX_FSI_SBEFIFO_H
> +#define LINUX_FSI_SBEFIFO_H
>
>   struct device;
>   struct sbefifo_client;
> @@ -27,4 +27,4 @@ extern int sbefifo_drv_write(struct sbefifo_client *client, const char *buf,
>   			     size_t len);
>   extern void sbefifo_drv_release(struct sbefifo_client *client);
>
> -#endif /* __FSI_SBEFIFO_H__ */
> +#endif /* LINUX_FSI_SBEFIFO_H */



More information about the openbmc mailing list