{"id":817201,"url":"http://patchwork.ozlabs.org/api/patches/817201/?format=json","web_url":"http://patchwork.ozlabs.org/project/openbmc/patch/1506033838-2078-2-git-send-email-eajames@linux.vnet.ibm.com/","project":{"id":56,"url":"http://patchwork.ozlabs.org/api/projects/56/?format=json","name":"OpenBMC development","link_name":"openbmc","list_id":"openbmc.lists.ozlabs.org","list_email":"openbmc@lists.ozlabs.org","web_url":"http://github.com/openbmc/","scm_url":"","webscm_url":"","list_archive_url":"","list_archive_url_format":"","commit_url_format":""},"msgid":"<1506033838-2078-2-git-send-email-eajames@linux.vnet.ibm.com>","list_archive_url":null,"date":"2017-09-21T22:43:56","name":"[linux,dev-4.10,1/3] drivers/fsi/sbefifo: refactor to upstream list state","commit_ref":null,"pull_url":null,"state":"superseded","archived":true,"hash":"07f2aecd49eaa8e795286b349a17eaafe52dca9b","submitter":{"id":70876,"url":"http://patchwork.ozlabs.org/api/people/70876/?format=json","name":"Eddie James","email":"eajames@linux.vnet.ibm.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/openbmc/patch/1506033838-2078-2-git-send-email-eajames@linux.vnet.ibm.com/mbox/","series":[{"id":4493,"url":"http://patchwork.ozlabs.org/api/series/4493/?format=json","web_url":"http://patchwork.ozlabs.org/project/openbmc/list/?series=4493","date":"2017-09-21T22:43:57","name":"drivers/fsi: Fixup client remove functions","version":1,"mbox":"http://patchwork.ozlabs.org/series/4493/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/817201/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/817201/checks/","tags":{},"related":[],"headers":{"Return-Path":"<openbmc-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org>","X-Original-To":["incoming@patchwork.ozlabs.org","openbmc@lists.ozlabs.org"],"Delivered-To":["patchwork-incoming@bilbo.ozlabs.org","openbmc@lists.ozlabs.org"],"Received":["from lists.ozlabs.org (lists.ozlabs.org [103.22.144.68])\n\t(using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby ozlabs.org (Postfix) with ESMTPS id 3xysF250Fgz9t38\n\tfor <incoming@patchwork.ozlabs.org>;\n\tFri, 22 Sep 2017 08:47:18 +1000 (AEST)","from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3])\n\tby lists.ozlabs.org (Postfix) with ESMTP id 3xysF23j98zDrFJ\n\tfor <incoming@patchwork.ozlabs.org>;\n\tFri, 22 Sep 2017 08:47:18 +1000 (AEST)","from mx0a-001b2d01.pphosted.com (mx0a-001b2d01.pphosted.com\n\t[148.163.156.1])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256\n\tbits)) (No client certificate requested)\n\tby lists.ozlabs.org (Postfix) with ESMTPS id 3xys9h3ln8zDqT0\n\tfor <openbmc@lists.ozlabs.org>; Fri, 22 Sep 2017 08:44:24 +1000 (AEST)","from pps.filterd (m0098396.ppops.net [127.0.0.1])\n\tby mx0a-001b2d01.pphosted.com (8.16.0.21/8.16.0.21) with SMTP id\n\tv8LMiKdN064324\n\tfor <openbmc@lists.ozlabs.org>; Thu, 21 Sep 2017 18:44:22 -0400","from e19.ny.us.ibm.com (e19.ny.us.ibm.com [129.33.205.209])\n\tby mx0a-001b2d01.pphosted.com with ESMTP id 2d4jnk4e2e-1\n\t(version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT)\n\tfor <openbmc@lists.ozlabs.org>; Thu, 21 Sep 2017 18:44:21 -0400","from localhost\n\tby e19.ny.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use\n\tOnly! Violators will be prosecuted\n\tfor <openbmc@lists.ozlabs.org> from <eajames@linux.vnet.ibm.com>;\n\tThu, 21 Sep 2017 18:44:05 -0400","from b01cxnp22034.gho.pok.ibm.com (9.57.198.24)\n\tby e19.ny.us.ibm.com (146.89.104.206) with IBM ESMTP SMTP Gateway:\n\tAuthorized Use Only! Violators will be prosecuted; \n\tThu, 21 Sep 2017 18:44:02 -0400","from b01ledav001.gho.pok.ibm.com (b01ledav001.gho.pok.ibm.com\n\t[9.57.199.106])\n\tby b01cxnp22034.gho.pok.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP\n\tid v8LMi2Is51970088; Thu, 21 Sep 2017 22:44:02 GMT","from b01ledav001.gho.pok.ibm.com (unknown [127.0.0.1])\n\tby IMSVA (Postfix) with ESMTP id AE6C12803E;\n\tThu, 21 Sep 2017 18:43:55 -0400 (EDT)","from oc3016140333.ibm.com (unknown [9.41.174.252])\n\tby b01ledav001.gho.pok.ibm.com (Postfix) with ESMTP id 250692803F;\n\tThu, 21 Sep 2017 18:43:55 -0400 (EDT)"],"Authentication-Results":"ozlabs.org;\n\tspf=none (mailfrom) smtp.mailfrom=linux.vnet.ibm.com\n\t(client-ip=148.163.156.1; helo=mx0a-001b2d01.pphosted.com;\n\tenvelope-from=eajames@linux.vnet.ibm.com; receiver=<UNKNOWN>)","From":"Eddie James <eajames@linux.vnet.ibm.com>","To":"openbmc@lists.ozlabs.org","Subject":"[PATCH linux dev-4.10 1/3] drivers/fsi/sbefifo: refactor to upstream\n\tlist state","Date":"Thu, 21 Sep 2017 17:43:56 -0500","X-Mailer":"git-send-email 1.8.3.1","In-Reply-To":"<1506033838-2078-1-git-send-email-eajames@linux.vnet.ibm.com>","References":"<1506033838-2078-1-git-send-email-eajames@linux.vnet.ibm.com>","X-TM-AS-GCONF":"00","x-cbid":"17092122-0056-0000-0000-000003CD0551","X-IBM-SpamModules-Scores":"","X-IBM-SpamModules-Versions":"BY=3.00007775; HX=3.00000241; KW=3.00000007;\n\tPH=3.00000004; SC=3.00000231; SDB=6.00920429; UDB=6.00462502;\n\tIPR=6.00700651; \n\tBA=6.00005601; NDR=6.00000001; ZLA=6.00000005; ZF=6.00000009;\n\tZB=6.00000000; \n\tZP=6.00000000; ZH=6.00000000; ZU=6.00000002; MB=3.00017240;\n\tXFM=3.00000015; UTC=2017-09-21 22:44:03","X-IBM-AV-DETECTION":"SAVI=unused REMOTE=unused XFE=unused","x-cbparentid":"17092122-0057-0000-0000-000008040AB9","Message-Id":"<1506033838-2078-2-git-send-email-eajames@linux.vnet.ibm.com>","X-Proofpoint-Virus-Version":"vendor=fsecure engine=2.50.10432:, ,\n\tdefinitions=2017-09-21_06:, , signatures=0","X-Proofpoint-Spam-Details":"rule=outbound_notspam policy=outbound score=0\n\tspamscore=0 suspectscore=4\n\tmalwarescore=0 phishscore=0 adultscore=0 bulkscore=0 classifier=spam\n\tadjust=0 reason=mlx scancount=1 engine=8.0.1-1707230000\n\tdefinitions=main-1709210305","X-BeenThere":"openbmc@lists.ozlabs.org","X-Mailman-Version":"2.1.24","Precedence":"list","List-Id":"Development list for OpenBMC <openbmc.lists.ozlabs.org>","List-Unsubscribe":"<https://lists.ozlabs.org/options/openbmc>,\n\t<mailto:openbmc-request@lists.ozlabs.org?subject=unsubscribe>","List-Archive":"<http://lists.ozlabs.org/pipermail/openbmc/>","List-Post":"<mailto:openbmc@lists.ozlabs.org>","List-Help":"<mailto:openbmc-request@lists.ozlabs.org?subject=help>","List-Subscribe":"<https://lists.ozlabs.org/listinfo/openbmc>,\n\t<mailto:openbmc-request@lists.ozlabs.org?subject=subscribe>","Cc":"andrew@aj.id.au, \"Edward A. James\" <eajames@us.ibm.com>","Errors-To":"openbmc-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org","Sender":"\"openbmc\"\n\t<openbmc-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org>"},"content":"From: \"Edward A. James\" <eajames@us.ibm.com>\n\nIncludes various fixes:\n - check for complete while waiting for data in read()\n - fix probe if probe fails\n - general cleanup\n - slightly safer (earlier) get_client()\n - reorder some of the remove() operations for safety\n\nSigned-off-by: Edward A. James <eajames@us.ibm.com>\n---\n drivers/fsi/fsi-sbefifo.c   | 329 ++++++++++++++++++++++++--------------------\n include/linux/fsi-sbefifo.h |   6 +-\n 2 files changed, 180 insertions(+), 155 deletions(-)","diff":"diff --git a/drivers/fsi/fsi-sbefifo.c b/drivers/fsi/fsi-sbefifo.c\nindex 1c37ff7..5d25ade 100644\n--- a/drivers/fsi/fsi-sbefifo.c\n+++ b/drivers/fsi/fsi-sbefifo.c\n@@ -11,20 +11,27 @@\n  * GNU General Public License for more details.\n  */\n \n-#include <linux/delay.h>\n+#include <linux/device.h>\n #include <linux/errno.h>\n-#include <linux/idr.h>\n+#include <linux/fs.h>\n #include <linux/fsi.h>\n+#include <linux/fsi-sbefifo.h>\n+#include <linux/idr.h>\n+#include <linux/kernel.h>\n+#include <linux/kref.h>\n #include <linux/list.h>\n #include <linux/miscdevice.h>\n #include <linux/module.h>\n #include <linux/of.h>\n+#include <linux/of_device.h>\n #include <linux/of_platform.h>\n #include <linux/poll.h>\n #include <linux/sched.h>\n #include <linux/slab.h>\n+#include <linux/spinlock.h>\n #include <linux/timer.h>\n #include <linux/uaccess.h>\n+#include <linux/wait.h>\n \n /*\n  * The SBEFIFO is a pipe-like FSI device for communicating with\n@@ -44,14 +51,15 @@\n #define   SBEFIFO_EOT_MAGIC\t\t0xffffffff\n #define SBEFIFO_EOT_ACK\t\t0x14\n \n+#define SBEFIFO_RESCHEDULE\tmsecs_to_jiffies(500)\n+\n struct sbefifo {\n \tstruct timer_list poll_timer;\n-\tstruct fsi_device *fsi_dev;\n-\tstruct miscdevice mdev;\n+\tstruct fsi_device *fsi_dev;\t/* parent fsi device */\n+\tstruct miscdevice mdev;\t\t/* /dev/ entry */\n \twait_queue_head_t wait;\n-\tstruct list_head link;\n \tstruct list_head xfrs;\n-\tstruct kref kref;\n+\tstruct kref kref;\t\t/* reference counter */\n \tspinlock_t lock;\n \tchar name[32];\n \tint idx;\n@@ -87,14 +95,12 @@ struct sbefifo_client {\n \tunsigned long f_flags;\n };\n \n-static struct list_head sbefifo_fifos;\n-\n static DEFINE_IDA(sbefifo_ida);\n \n static int sbefifo_inw(struct sbefifo *sbefifo, int reg, u32 *word)\n {\n \tint rc;\n-\tu32 raw_word;\n+\t__be32 raw_word;\n \n \trc = fsi_device_read(sbefifo->fsi_dev, reg, &raw_word,\n \t\t\t     sizeof(raw_word));\n@@ -102,17 +108,19 @@ static int sbefifo_inw(struct sbefifo *sbefifo, int reg, u32 *word)\n \t\treturn rc;\n \n \t*word = be32_to_cpu(raw_word);\n+\n \treturn 0;\n }\n \n static int sbefifo_outw(struct sbefifo *sbefifo, int reg, u32 word)\n {\n-\tu32 raw_word = cpu_to_be32(word);\n+\t__be32 raw_word = cpu_to_be32(word);\n \n \treturn fsi_device_write(sbefifo->fsi_dev, reg, &raw_word,\n \t\t\t\tsizeof(raw_word));\n }\n \n+/* Don't flip endianness of data to/from FIFO, just pass through. */\n static int sbefifo_readw(struct sbefifo *sbefifo, u32 *word)\n {\n \treturn fsi_device_read(sbefifo->fsi_dev, SBEFIFO_DWN, word,\n@@ -136,7 +144,7 @@ static int sbefifo_ack_eot(struct sbefifo *sbefifo)\n \t\treturn ret;\n \n \treturn sbefifo_outw(sbefifo, SBEFIFO_DWN | SBEFIFO_EOT_ACK,\n-\t\t\tSBEFIFO_EOT_MAGIC);\n+\t\t\t    SBEFIFO_EOT_MAGIC);\n }\n \n static size_t sbefifo_dev_nwreadable(u32 sts)\n@@ -210,6 +218,7 @@ static bool sbefifo_buf_readnb(struct sbefifo_buf *buf, size_t n)\n \t\trpos = buf->buf;\n \n \tWRITE_ONCE(buf->rpos, rpos);\n+\n \treturn rpos == wpos;\n }\n \n@@ -229,14 +238,14 @@ static bool sbefifo_buf_wrotenb(struct sbefifo_buf *buf, size_t n)\n \t\tset_bit(SBEFIFO_BUF_FULL, &buf->flags);\n \n \tWRITE_ONCE(buf->wpos, wpos);\n+\n \treturn rpos == wpos;\n }\n \n static void sbefifo_free(struct kref *kref)\n {\n-\tstruct sbefifo *sbefifo;\n+\tstruct sbefifo *sbefifo = container_of(kref, struct sbefifo, kref);\n \n-\tsbefifo = container_of(kref, struct sbefifo, kref);\n \tkfree(sbefifo);\n }\n \n@@ -255,9 +264,12 @@ static struct sbefifo_xfr *sbefifo_enq_xfr(struct sbefifo_client *client)\n \tstruct sbefifo *sbefifo = client->dev;\n \tstruct sbefifo_xfr *xfr;\n \n+\tif (READ_ONCE(sbefifo->rc))\n+\t\treturn ERR_PTR(sbefifo->rc);\n+\n \txfr = kzalloc(sizeof(*xfr), GFP_KERNEL);\n \tif (!xfr)\n-\t\treturn NULL;\n+\t\treturn ERR_PTR(-ENOMEM);\n \n \txfr->rbuf = &client->rbuf;\n \txfr->wbuf = &client->wbuf;\n@@ -267,21 +279,12 @@ static struct sbefifo_xfr *sbefifo_enq_xfr(struct sbefifo_client *client)\n \treturn xfr;\n }\n \n-static struct sbefifo_xfr *sbefifo_client_next_xfr(\n-\t\tstruct sbefifo_client *client)\n-{\n-\tif (list_empty(&client->xfrs))\n-\t\treturn NULL;\n-\n-\treturn container_of(client->xfrs.next, struct sbefifo_xfr,\n-\t\t\tclient);\n-}\n-\n static bool sbefifo_xfr_rsp_pending(struct sbefifo_client *client)\n {\n-\tstruct sbefifo_xfr *xfr;\n+\tstruct sbefifo_xfr *xfr = list_first_entry_or_null(&client->xfrs,\n+\t\t\t\t\t\t\t   struct sbefifo_xfr,\n+\t\t\t\t\t\t\t   client);\n \n-\txfr = sbefifo_client_next_xfr(client);\n \tif (xfr && test_bit(SBEFIFO_XFR_RESP_PENDING, &xfr->flags))\n \t\treturn true;\n \n@@ -309,10 +312,11 @@ static struct sbefifo_client *sbefifo_new_client(struct sbefifo *sbefifo)\n \n static void sbefifo_client_release(struct kref *kref)\n {\n-\tstruct sbefifo_client *client;\n \tstruct sbefifo_xfr *xfr;\n+\tstruct sbefifo_client *client = container_of(kref,\n+\t\t\t\t\t\t     struct sbefifo_client,\n+\t\t\t\t\t\t     kref);\n \n-\tclient = container_of(kref, struct sbefifo_client, kref);\n \tlist_for_each_entry(xfr, &client->xfrs, client) {\n \t\t/*\n \t\t * The client left with pending or running xfrs.\n@@ -349,6 +353,7 @@ static struct sbefifo_xfr *sbefifo_next_xfr(struct sbefifo *sbefifo)\n \t\t\tkfree(xfr);\n \t\t\tcontinue;\n \t\t}\n+\n \t\treturn xfr;\n \t}\n \n@@ -370,7 +375,7 @@ static void sbefifo_poll_timer(unsigned long data)\n \n \tspin_lock(&sbefifo->lock);\n \txfr = list_first_entry_or_null(&sbefifo->xfrs, struct sbefifo_xfr,\n-\t\t\txfrs);\n+\t\t\t\t       xfrs);\n \tif (!xfr)\n \t\tgoto out_unlock;\n \n@@ -388,8 +393,7 @@ static void sbefifo_poll_timer(unsigned long data)\n \n \t /* Drain the write buffer. */\n \twhile ((bufn = sbefifo_buf_nbreadable(wbuf))) {\n-\t\tret = sbefifo_inw(sbefifo, SBEFIFO_UP | SBEFIFO_STS,\n-\t\t\t\t&sts);\n+\t\tret = sbefifo_inw(sbefifo, SBEFIFO_UP | SBEFIFO_STS, &sts);\n \t\tif (ret)\n \t\t\tgoto out;\n \n@@ -397,7 +401,7 @@ static void sbefifo_poll_timer(unsigned long data)\n \t\tif (devn == 0) {\n \t\t\t/* No open slot for write.  Reschedule. */\n \t\t\tsbefifo->poll_timer.expires = jiffies +\n-\t\t\t\tmsecs_to_jiffies(500);\n+\t\t\t\tSBEFIFO_RESCHEDULE;\n \t\t\tadd_timer(&sbefifo->poll_timer);\n \t\t\tgoto out_unlock;\n \t\t}\n@@ -414,9 +418,8 @@ static void sbefifo_poll_timer(unsigned long data)\n \n \t /* Send EOT if the writer is finished. */\n \tif (test_and_clear_bit(SBEFIFO_XFR_WRITE_DONE, &xfr->flags)) {\n-\t\tret = sbefifo_outw(sbefifo,\n-\t\t\t\tSBEFIFO_UP | SBEFIFO_EOT_RAISE,\n-\t\t\t\tSBEFIFO_EOT_MAGIC);\n+\t\tret = sbefifo_outw(sbefifo, SBEFIFO_UP | SBEFIFO_EOT_RAISE,\n+\t\t\t\t   SBEFIFO_EOT_MAGIC);\n \t\tif (ret)\n \t\t\tgoto out;\n \n@@ -438,7 +441,7 @@ static void sbefifo_poll_timer(unsigned long data)\n \t\tif (devn == 0) {\n \t\t\t/* No data yet.  Reschedule. */\n \t\t\tsbefifo->poll_timer.expires = jiffies +\n-\t\t\t\tmsecs_to_jiffies(500);\n+\t\t\t\tSBEFIFO_RESCHEDULE;\n \t\t\tadd_timer(&sbefifo->poll_timer);\n \t\t\tgoto out_unlock;\n \t\t}\n@@ -466,7 +469,7 @@ static void sbefifo_poll_timer(unsigned long data)\n \t\t\tset_bit(SBEFIFO_XFR_COMPLETE, &xfr->flags);\n \t\t\tlist_del(&xfr->xfrs);\n \t\t\tif (unlikely(test_bit(SBEFIFO_XFR_CANCEL,\n-\t\t\t\t\t\t\t&xfr->flags)))\n+\t\t\t\t\t      &xfr->flags)))\n \t\t\t\tkfree(xfr);\n \t\t\tbreak;\n \t\t}\n@@ -476,7 +479,7 @@ static void sbefifo_poll_timer(unsigned long data)\n \tif (unlikely(ret)) {\n \t\tsbefifo->rc = ret;\n \t\tdev_err(&sbefifo->fsi_dev->dev,\n-\t\t\t\t\"Fatal bus access failure: %d\\n\", ret);\n+\t\t\t\"Fatal bus access failure: %d\\n\", ret);\n \t\tlist_for_each_entry(xfr, &sbefifo->xfrs, xfrs)\n \t\t\tkfree(xfr);\n \t\tINIT_LIST_HEAD(&sbefifo->xfrs);\n@@ -497,7 +500,7 @@ static void sbefifo_poll_timer(unsigned long data)\n static int sbefifo_open(struct inode *inode, struct file *file)\n {\n \tstruct sbefifo *sbefifo = container_of(file->private_data,\n-\t\t\tstruct sbefifo, mdev);\n+\t\t\t\t\t       struct sbefifo, mdev);\n \tstruct sbefifo_client *client;\n \tint ret;\n \n@@ -535,6 +538,19 @@ static unsigned int sbefifo_poll(struct file *file, poll_table *wait)\n \treturn mask;\n }\n \n+static bool sbefifo_read_ready(struct sbefifo *sbefifo,\n+\t\t\t       struct sbefifo_client *client, size_t *n)\n+{\n+\tstruct sbefifo_xfr *xfr = list_first_entry_or_null(&client->xfrs,\n+\t\t\t\t\t\t\t   struct sbefifo_xfr,\n+\t\t\t\t\t\t\t   client);\n+\n+\t*n = sbefifo_buf_nbreadable(&client->rbuf);\n+\n+\treturn READ_ONCE(sbefifo->rc) || *n ||\n+\t\t(xfr && test_bit(SBEFIFO_XFR_COMPLETE, &xfr->flags));\n+}\n+\n static ssize_t sbefifo_read_common(struct sbefifo_client *client,\n \t\t\t\t   char __user *ubuf, char *kbuf, size_t len)\n {\n@@ -551,30 +567,38 @@ static ssize_t sbefifo_read_common(struct sbefifo_client *client,\n \n \tsbefifo_get_client(client);\n \tif (wait_event_interruptible(sbefifo->wait,\n-\t\t\t\t(ret = READ_ONCE(sbefifo->rc)) ||\n-\t\t\t\t(n = sbefifo_buf_nbreadable(\n-\t\t\t\t\t\t&client->rbuf)))) {\n-\t\tsbefifo_put_client(client);\n-\t\treturn -ERESTARTSYS;\n+\t\t\t\t     sbefifo_read_ready(sbefifo, client,\n+\t\t\t\t\t\t\t&n))) {\n+\t\tret = -ERESTARTSYS;\n+\t\tgoto out;\n \t}\n+\n+\tret = READ_ONCE(sbefifo->rc);\n \tif (ret) {\n \t\tINIT_LIST_HEAD(&client->xfrs);\n-\t\tsbefifo_put_client(client);\n-\t\treturn ret;\n+\t\tgoto out;\n \t}\n \n \tn = min_t(size_t, n, len);\n \n \tif (ubuf) {\n \t\tif (copy_to_user(ubuf, READ_ONCE(client->rbuf.rpos), n)) {\n-\t\t\tsbefifo_put_client(client);\n-\t\t\treturn -EFAULT;\n+\t\t\tret = -EFAULT;\n+\t\t\tgoto out;\n \t\t}\n-\t} else\n+\t} else {\n \t\tmemcpy(kbuf, READ_ONCE(client->rbuf.rpos), n);\n+\t}\n \n \tif (sbefifo_buf_readnb(&client->rbuf, n)) {\n-\t\txfr = sbefifo_client_next_xfr(client);\n+\t\txfr = list_first_entry_or_null(&client->xfrs,\n+\t\t\t\t\t       struct sbefifo_xfr, client);\n+\t\tif (!xfr) {\n+\t\t\t/* should be impossible to not have an xfr here */\n+\t\t\twake_up(&sbefifo->wait);\n+\t\t\tgoto out;\n+\t\t}\n+\n \t\tif (!test_bit(SBEFIFO_XFR_COMPLETE, &xfr->flags)) {\n \t\t\t/*\n \t\t\t * Fill the read buffer back up.\n@@ -589,22 +613,31 @@ static ssize_t sbefifo_read_common(struct sbefifo_client *client,\n \t\t}\n \t}\n \n-\tsbefifo_put_client(client);\n+\tret = n;\n \n-\treturn n;\n+out:\n+\tsbefifo_put_client(client);\n+\treturn ret;\n }\n \n-static ssize_t sbefifo_read(struct file *file, char __user *buf,\n-\t\tsize_t len, loff_t *offset)\n+static ssize_t sbefifo_read(struct file *file, char __user *buf, size_t len,\n+\t\t\t    loff_t *offset)\n {\n \tstruct sbefifo_client *client = file->private_data;\n \n-\tWARN_ON(*offset);\n+\treturn sbefifo_read_common(client, buf, NULL, len);\n+}\n \n-\tif (!access_ok(VERIFY_WRITE, buf, len))\n-\t\treturn -EFAULT;\n+static bool sbefifo_write_ready(struct sbefifo *sbefifo,\n+\t\t\t\tstruct sbefifo_xfr *xfr,\n+\t\t\t\tstruct sbefifo_client *client, size_t *n)\n+{\n+\tstruct sbefifo_xfr *next = list_first_entry_or_null(&client->xfrs,\n+\t\t\t\t\t\t\t    struct sbefifo_xfr,\n+\t\t\t\t\t\t\t    client);\n \n-\treturn sbefifo_read_common(client, buf, NULL, len);\n+\t*n = sbefifo_buf_nbwriteable(&client->wbuf);\n+\treturn READ_ONCE(sbefifo->rc) || (next == xfr && *n);\n }\n \n static ssize_t sbefifo_write_common(struct sbefifo_client *client,\n@@ -612,6 +645,7 @@ static ssize_t sbefifo_write_common(struct sbefifo_client *client,\n \t\t\t\t    size_t len)\n {\n \tstruct sbefifo *sbefifo = client->dev;\n+\tstruct sbefifo_buf *wbuf = &client->wbuf;\n \tstruct sbefifo_xfr *xfr;\n \tssize_t ret = 0;\n \tsize_t n;\n@@ -622,24 +656,26 @@ static ssize_t sbefifo_write_common(struct sbefifo_client *client,\n \tif (!len)\n \t\treturn 0;\n \n-\tn = sbefifo_buf_nbwriteable(&client->wbuf);\n+\tsbefifo_get_client(client);\n+\tn = sbefifo_buf_nbwriteable(wbuf);\n \n \tspin_lock_irq(&sbefifo->lock);\n-\txfr = sbefifo_next_xfr(sbefifo);\n \n+\txfr = sbefifo_next_xfr(sbefifo);\t/* next xfr to be executed */\n \tif ((client->f_flags & O_NONBLOCK) && xfr && n < len) {\n \t\tspin_unlock_irq(&sbefifo->lock);\n-\t\treturn -EAGAIN;\n+\t\tret = -EAGAIN;\n+\t\tgoto out;\n \t}\n \n-\txfr = sbefifo_enq_xfr(client);\n-\tif (!xfr) {\n+\txfr = sbefifo_enq_xfr(client);\t\t/* this xfr queued up */\n+\tif (IS_ERR(xfr)) {\n \t\tspin_unlock_irq(&sbefifo->lock);\n-\t\treturn -ENOMEM;\n+\t\tret = PTR_ERR(xfr);\n+\t\tgoto out;\n \t}\n-\tspin_unlock_irq(&sbefifo->lock);\n \n-\tsbefifo_get_client(client);\n+\tspin_unlock_irq(&sbefifo->lock);\n \n \t/*\n \t * Partial writes are not really allowed in that EOT is sent exactly\n@@ -647,49 +683,47 @@ static ssize_t sbefifo_write_common(struct sbefifo_client *client,\n \t */\n \twhile (len) {\n \t\tif (wait_event_interruptible(sbefifo->wait,\n-\t\t\t\tREAD_ONCE(sbefifo->rc) ||\n-\t\t\t\t\t(sbefifo_client_next_xfr(client) == xfr &&\n-\t\t\t\t\t (n = sbefifo_buf_nbwriteable(\n-\t\t\t\t\t\t\t&client->wbuf))))) {\n+\t\t\t\t\t     sbefifo_write_ready(sbefifo, xfr,\n+\t\t\t\t\t\t\t\t client,\n+\t\t\t\t\t\t\t\t &n))) {\n \t\t\tset_bit(SBEFIFO_XFR_CANCEL, &xfr->flags);\n \t\t\tsbefifo_get(sbefifo);\n \t\t\tif (mod_timer(&sbefifo->poll_timer, jiffies))\n \t\t\t\tsbefifo_put(sbefifo);\n-\n-\t\t\tsbefifo_put_client(client);\n-\t\t\treturn -ERESTARTSYS;\n+\t\t\tret = -ERESTARTSYS;\n+\t\t\tgoto out;\n \t\t}\n-\t\tif (sbefifo->rc) {\n+\n+\t\tret = READ_ONCE(sbefifo->rc);\n+\t\tif (ret) {\n \t\t\tINIT_LIST_HEAD(&client->xfrs);\n-\t\t\tsbefifo_put_client(client);\n-\t\t\treturn sbefifo->rc;\n+\t\t\tgoto out;\n \t\t}\n \n \t\tn = min_t(size_t, n, len);\n \n \t\tif (ubuf) {\n-\t\t\tif (copy_from_user(READ_ONCE(client->wbuf.wpos), ubuf,\n-\t\t\t    n)) {\n+\t\t\tif (copy_from_user(READ_ONCE(wbuf->wpos), ubuf, n)) {\n \t\t\t\tset_bit(SBEFIFO_XFR_CANCEL, &xfr->flags);\n \t\t\t\tsbefifo_get(sbefifo);\n \t\t\t\tif (mod_timer(&sbefifo->poll_timer, jiffies))\n \t\t\t\t\tsbefifo_put(sbefifo);\n-\t\t\t\tsbefifo_put_client(client);\n-\t\t\t\treturn -EFAULT;\n+\t\t\t\tret = -EFAULT;\n+\t\t\t\tgoto out;\n \t\t\t}\n \n \t\t\tubuf += n;\n \t\t} else {\n-\t\t\tmemcpy(READ_ONCE(client->wbuf.wpos), kbuf, n);\n+\t\t\tmemcpy(READ_ONCE(wbuf->wpos), kbuf, n);\n \t\t\tkbuf += n;\n \t\t}\n \n-\t\tsbefifo_buf_wrotenb(&client->wbuf, n);\n+\t\tsbefifo_buf_wrotenb(wbuf, n);\n \t\tlen -= n;\n \t\tret += n;\n \n-\t\t/* set flag before starting the worker, as it may run through\n-\t\t * and check the flag before we exit this loop!\n+\t\t/* Set this before starting timer to avoid race condition on\n+\t\t * this flag with the timer function writer.\n \t\t */\n \t\tif (!len)\n \t\t\tset_bit(SBEFIFO_XFR_WRITE_DONE, &xfr->flags);\n@@ -702,21 +736,16 @@ static ssize_t sbefifo_write_common(struct sbefifo_client *client,\n \t\t\tsbefifo_put(sbefifo);\n \t}\n \n+out:\n \tsbefifo_put_client(client);\n-\n \treturn ret;\n }\n \n static ssize_t sbefifo_write(struct file *file, const char __user *buf,\n-\t\tsize_t len, loff_t *offset)\n+\t\t\t     size_t len, loff_t *offset)\n {\n \tstruct sbefifo_client *client = file->private_data;\n \n-\tWARN_ON(*offset);\n-\n-\tif (!access_ok(VERIFY_READ, buf, len))\n-\t\treturn -EFAULT;\n-\n \treturn sbefifo_write_common(client, buf, NULL, len);\n }\n \n@@ -742,18 +771,15 @@ static int sbefifo_release(struct inode *inode, struct file *file)\n struct sbefifo_client *sbefifo_drv_open(struct device *dev,\n \t\t\t\t\tunsigned long flags)\n {\n-\tstruct sbefifo_client *client = NULL;\n-\tstruct sbefifo *sbefifo;\n-\tstruct fsi_device *fsi_dev = to_fsi_dev(dev);\n+\tstruct sbefifo_client *client;\n+\tstruct sbefifo *sbefifo = dev_get_drvdata(dev);\n \n-\tlist_for_each_entry(sbefifo, &sbefifo_fifos, link) {\n-\t\tif (sbefifo->fsi_dev != fsi_dev)\n-\t\t\tcontinue;\n+\tif (!sbefifo)\n+\t\treturn NULL;\n \n-\t\tclient = sbefifo_new_client(sbefifo);\n-\t\tif (client)\n-\t\t\tclient->f_flags = flags;\n-\t}\n+\tclient = sbefifo_new_client(sbefifo);\n+\tif (client)\n+\t\tclient->f_flags = flags;\n \n \treturn client;\n }\n@@ -802,95 +828,92 @@ static int sbefifo_probe(struct device *dev)\n \tu32 sts;\n \tint ret, child_idx = 0;\n \n-\tdev_dbg(dev, \"Found sbefifo device\\n\");\n \tsbefifo = kzalloc(sizeof(*sbefifo), GFP_KERNEL);\n \tif (!sbefifo)\n \t\treturn -ENOMEM;\n \n \tsbefifo->fsi_dev = fsi_dev;\n \n-\tret = sbefifo_inw(sbefifo,\n-\t\t\tSBEFIFO_UP | SBEFIFO_STS, &sts);\n+\tret = sbefifo_inw(sbefifo, SBEFIFO_UP | SBEFIFO_STS, &sts);\n \tif (ret)\n \t\treturn ret;\n+\n \tif (!(sts & SBEFIFO_EMPTY)) {\n-\t\tdev_err(&sbefifo->fsi_dev->dev,\n-\t\t\t\t\"Found data in upstream fifo\\n\");\n+\t\tdev_err(dev, \"Found data in upstream fifo\\n\");\n \t\treturn -EIO;\n \t}\n \n \tret = sbefifo_inw(sbefifo, SBEFIFO_DWN | SBEFIFO_STS, &sts);\n \tif (ret)\n \t\treturn ret;\n+\n \tif (!(sts & SBEFIFO_EMPTY)) {\n-\t\tdev_err(&sbefifo->fsi_dev->dev,\n-\t\t\t\t\"Found data in downstream fifo\\n\");\n+\t\tdev_err(dev, \"found data in downstream fifo\\n\");\n \t\treturn -EIO;\n \t}\n \n-\tsbefifo->mdev.minor = MISC_DYNAMIC_MINOR;\n-\tsbefifo->mdev.fops = &sbefifo_fops;\n-\tsbefifo->mdev.name = sbefifo->name;\n-\tsbefifo->mdev.parent = dev;\n \tspin_lock_init(&sbefifo->lock);\n \tkref_init(&sbefifo->kref);\n+\tinit_waitqueue_head(&sbefifo->wait);\n+\tINIT_LIST_HEAD(&sbefifo->xfrs);\n \n \tsbefifo->idx = ida_simple_get(&sbefifo_ida, 1, INT_MAX, GFP_KERNEL);\n \tsnprintf(sbefifo->name, sizeof(sbefifo->name), \"sbefifo%d\",\n-\t\t\tsbefifo->idx);\n-\tinit_waitqueue_head(&sbefifo->wait);\n-\tINIT_LIST_HEAD(&sbefifo->xfrs);\n+\t\t sbefifo->idx);\n \n \t/* This bit of silicon doesn't offer any interrupts... */\n \tsetup_timer(&sbefifo->poll_timer, sbefifo_poll_timer,\n-\t\t\t(unsigned long)sbefifo);\n-\n-\tif (dev->of_node) {\n-\t\t/* create platform devs for dts child nodes (occ, etc) */\n-\t\tfor_each_child_of_node(dev->of_node, np) {\n-\t\t\tsnprintf(child_name, sizeof(child_name), \"%s-dev%d\",\n-\t\t\t\t sbefifo->name, child_idx++);\n-\t\t\tchild = of_platform_device_create(np, child_name, dev);\n-\t\t\tif (!child)\n-\t\t\t\tdev_warn(&sbefifo->fsi_dev->dev,\n-\t\t\t\t\t \"failed to create child node dev\\n\");\n-\t\t}\n+\t\t    (unsigned long)sbefifo);\n+\n+\tsbefifo->mdev.minor = MISC_DYNAMIC_MINOR;\n+\tsbefifo->mdev.fops = &sbefifo_fops;\n+\tsbefifo->mdev.name = sbefifo->name;\n+\tsbefifo->mdev.parent = dev;\n+\tret = misc_register(&sbefifo->mdev);\n+\tif (ret) {\n+\t\tdev_err(dev, \"failed to register miscdevice: %d\\n\", ret);\n+\t\tida_simple_remove(&sbefifo_ida, sbefifo->idx);\n+\t\tsbefifo_put(sbefifo);\n+\t\treturn ret;\n+\t}\n+\n+\t/* create platform devs for dts child nodes (occ, etc) */\n+\tfor_each_available_child_of_node(dev->of_node, np) {\n+\t\tsnprintf(child_name, sizeof(child_name), \"%s-dev%d\",\n+\t\t\t sbefifo->name, child_idx++);\n+\t\tchild = of_platform_device_create(np, child_name, dev);\n+\t\tif (!child)\n+\t\t\tdev_warn(dev, \"failed to create child %s dev\\n\",\n+\t\t\t\t child_name);\n \t}\n \n-\tlist_add(&sbefifo->link, &sbefifo_fifos);\n-\t\n-\treturn misc_register(&sbefifo->mdev);\n+\tdev_set_drvdata(dev, sbefifo);\n+\n+\treturn 0;\n }\n \n static int sbefifo_remove(struct device *dev)\n {\n-\tstruct fsi_device *fsi_dev = to_fsi_dev(dev);\n-\tstruct sbefifo *sbefifo, *sbefifo_tmp;\n+\tstruct sbefifo *sbefifo = dev_get_drvdata(dev);\n \tstruct sbefifo_xfr *xfr;\n \n-\tlist_for_each_entry_safe(sbefifo, sbefifo_tmp, &sbefifo_fifos, link) {\n-\t\tif (sbefifo->fsi_dev != fsi_dev)\n-\t\t\tcontinue;\n-\n-\t\tdevice_for_each_child(dev, NULL, sbefifo_unregister_child);\n+\tWRITE_ONCE(sbefifo->rc, -ENODEV);\n+\twake_up(&sbefifo->wait);\n \n-\t\tmisc_deregister(&sbefifo->mdev);\n-\t\tlist_del(&sbefifo->link);\n-\t\tida_simple_remove(&sbefifo_ida, sbefifo->idx);\n+\tmisc_deregister(&sbefifo->mdev);\n+\tdevice_for_each_child(dev, NULL, sbefifo_unregister_child);\n \n-\t\tif (del_timer_sync(&sbefifo->poll_timer))\n-\t\t\tsbefifo_put(sbefifo);\n+\tida_simple_remove(&sbefifo_ida, sbefifo->idx);\n \n-\t\tspin_lock(&sbefifo->lock);\n-\t\tlist_for_each_entry(xfr, &sbefifo->xfrs, xfrs)\n-\t\t\tkfree(xfr);\n-\t\tspin_unlock(&sbefifo->lock);\n+\tif (del_timer_sync(&sbefifo->poll_timer))\n+\t\tsbefifo_put(sbefifo);\n \n-\t\tWRITE_ONCE(sbefifo->rc, -ENODEV);\n+\tspin_lock(&sbefifo->lock);\n+\tlist_for_each_entry(xfr, &sbefifo->xfrs, xfrs)\n+\t\tkfree(xfr);\n+\tspin_unlock(&sbefifo->lock);\n \n-\t\twake_up(&sbefifo->wait);\n-\t\tsbefifo_put(sbefifo);\n-\t}\n+\tsbefifo_put(sbefifo);\n \n \treturn 0;\n }\n@@ -915,17 +938,19 @@ static int sbefifo_remove(struct device *dev)\n \n static int sbefifo_init(void)\n {\n-\tINIT_LIST_HEAD(&sbefifo_fifos);\n \treturn fsi_driver_register(&sbefifo_drv);\n }\n \n static void sbefifo_exit(void)\n {\n \tfsi_driver_unregister(&sbefifo_drv);\n+\n+\tida_destroy(&sbefifo_ida);\n }\n \n module_init(sbefifo_init);\n module_exit(sbefifo_exit);\n MODULE_LICENSE(\"GPL\");\n MODULE_AUTHOR(\"Brad Bishop <bradleyb@fuzziesquirrel.com>\");\n-MODULE_DESCRIPTION(\"Linux device interface to the POWER self boot engine\");\n+MODULE_AUTHOR(\"Eddie James <eajames@linux.vnet.ibm.com>\");\n+MODULE_DESCRIPTION(\"Linux device interface to the POWER Self Boot Engine\");\ndiff --git a/include/linux/fsi-sbefifo.h b/include/linux/fsi-sbefifo.h\nindex 1b46c63..8e55891 100644\n--- a/include/linux/fsi-sbefifo.h\n+++ b/include/linux/fsi-sbefifo.h\n@@ -13,8 +13,8 @@\n  * GNU General Public License for more details.\n  */\n \n-#ifndef __FSI_SBEFIFO_H__\n-#define __FSI_SBEFIFO_H__\n+#ifndef LINUX_FSI_SBEFIFO_H\n+#define LINUX_FSI_SBEFIFO_H\n \n struct device;\n struct sbefifo_client;\n@@ -27,4 +27,4 @@ extern int sbefifo_drv_write(struct sbefifo_client *client, const char *buf,\n \t\t\t     size_t len);\n extern void sbefifo_drv_release(struct sbefifo_client *client);\n \n-#endif /* __FSI_SBEFIFO_H__ */\n+#endif /* LINUX_FSI_SBEFIFO_H */\n","prefixes":["linux","dev-4.10","1/3"]}