Received: by 10.223.164.202 with SMTP id h10csp4217089wrb; Mon, 20 Nov 2017 11:48:09 -0800 (PST) X-Google-Smtp-Source: AGs4zMbx5uwGRJKSNw2gQFgHszCZt9igx/Y4Bm5YbQXobzVKskzuY5mw2F0ljYxpxgsWThKNaiuW X-Received: by 10.84.129.1 with SMTP id 1mr14931732plb.40.1511207288903; Mon, 20 Nov 2017 11:48:08 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1511207288; cv=none; d=google.com; s=arc-20160816; b=QAG4ZX9Ja4+/LIudz9YfxW6bUVEiWcaRPanODeb6OvMATZ6SFAq5vI5ufKYzD1tLx5 N10Krcj3z920kcBi4xtdMJcPciNCgMlbxWXu9Fi7+A1eXSNAw6BMQarDBOuN0nlzAgSr Pf/FJR9ZQuMQhr/GAcUXS8Y09zoNR2jHCyrg1C8hJxbZcFyIbWeRXQHi7Eojpp1F4N0w BTUFUvtY/SErj4rUL5F2sGwivVIP7AjM31uy/9kV91eqcAKnCBRzAuJYk4HWKJrakUpp pKRB3APOejU4sPzSP7Tglk2BXauiFH/UA+zks/aUAI3gW2Br/OzYAt6FOAoijOWN5XmV Gwyw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:message-id:references:in-reply-to:date :subject:cc:to:from:arc-authentication-results; bh=sRC5ihDH+XlPTB1KebZU/t+k5TnFRbeTmtXBeQYMTNY=; b=J2NTNSr36h2duDHJOrKq1jzgNLgevi7lZpnrYOgpsulnvKgpzFTmlPzVyaO3Xd585k lh+SghWcoVd4CDSSaQXEKzbVK+GQtgPEd9wZ705e5NSKt9cPlIbtmzqhaRsxw6EGDL47 H/H1pyNsxpkYG54lLtU8SZkGTON3vGuWbtBYOh2VKd9BhO9pqX9aSgiTkooOuL8rLDat 376svwX9U3YxpQ5NVv6jwONPI7KyQdo0AjOtJm0xvWaaFMAbMeaXBMssCV+UxhyEtsTX WutzOWD6FTmkQI4WX1fMyx6F0UjJ33an5HZ4DlLVsywPN3WRFtCwuyo6fEAuNbuyOAOe nLHA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=ibm.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 3si8999327plr.543.2017.11.20.11.47.58; Mon, 20 Nov 2017 11:48:08 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=ibm.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752787AbdKTTrZ (ORCPT + 67 others); Mon, 20 Nov 2017 14:47:25 -0500 Received: from mx0b-001b2d01.pphosted.com ([148.163.158.5]:37724 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1752720AbdKTTrT (ORCPT ); Mon, 20 Nov 2017 14:47:19 -0500 Received: from pps.filterd (m0098413.ppops.net [127.0.0.1]) by mx0b-001b2d01.pphosted.com (8.16.0.21/8.16.0.21) with SMTP id vAKJi6ES131331 for ; Mon, 20 Nov 2017 14:47:18 -0500 Received: from e32.co.us.ibm.com (e32.co.us.ibm.com [32.97.110.150]) by mx0b-001b2d01.pphosted.com with ESMTP id 2ec4nvjg54-1 (version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT) for ; Mon, 20 Nov 2017 14:47:18 -0500 Received: from localhost by e32.co.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Mon, 20 Nov 2017 12:47:17 -0700 Received: from b03cxnp08027.gho.boulder.ibm.com (9.17.130.19) by e32.co.us.ibm.com (192.168.1.132) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Mon, 20 Nov 2017 12:47:14 -0700 Received: from b03ledav006.gho.boulder.ibm.com (b03ledav006.gho.boulder.ibm.com [9.17.130.237]) by b03cxnp08027.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id vAKJlEST50856110; Mon, 20 Nov 2017 12:47:14 -0700 Received: from b03ledav006.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id E0E60C6047; Mon, 20 Nov 2017 12:47:13 -0700 (MST) Received: from oc3016140333.ibm.com (unknown [9.41.174.252]) by b03ledav006.gho.boulder.ibm.com (Postfix) with ESMTP id 6008EC6037; Mon, 20 Nov 2017 12:47:13 -0700 (MST) From: Eddie James To: linux-kernel@vger.kernel.org Cc: gregkh@linuxfoundation.org, devicetree@vger.kernel.org, robh+dt@kernel.org, mark.rutland@arm.com, bradleyb@fuzziesquirrel.com, cbostic@linux.vnet.ibm.com, joel@jms.id.au, eajames@linux.vnet.ibm.com, "Edward A. James" Subject: [PATCH v5 7/8] drivers/fsi: occ: Add miscdevice Date: Mon, 20 Nov 2017 13:46:56 -0600 X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1511207217-14075-1-git-send-email-eajames@linux.vnet.ibm.com> References: <1511207217-14075-1-git-send-email-eajames@linux.vnet.ibm.com> X-TM-AS-GCONF: 00 x-cbid: 17112019-0004-0000-0000-0000133FC787 X-IBM-SpamModules-Scores: X-IBM-SpamModules-Versions: BY=3.00008100; HX=3.00000241; KW=3.00000007; PH=3.00000004; SC=3.00000240; SDB=6.00948744; UDB=6.00479090; IPR=6.00729025; BA=6.00005702; NDR=6.00000001; ZLA=6.00000005; ZF=6.00000009; ZB=6.00000000; ZP=6.00000000; ZH=6.00000000; ZU=6.00000002; MB=3.00018111; XFM=3.00000015; UTC=2017-11-20 19:47:17 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 17112019-0005-0000-0000-000084F39F4B Message-Id: <1511207217-14075-8-git-send-email-eajames@linux.vnet.ibm.com> X-Proofpoint-Virus-Version: vendor=fsecure engine=2.50.10432:,, definitions=2017-11-20_11:,, signatures=0 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 malwarescore=0 suspectscore=1 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 impostorscore=0 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1709140000 definitions=main-1711200264 Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: "Edward A. James" Add a miscdevice for the occ to allow userspace access through standard file operations. Signed-off-by: Edward A. James --- drivers/fsi/fsi-occ.c | 264 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 264 insertions(+) diff --git a/drivers/fsi/fsi-occ.c b/drivers/fsi/fsi-occ.c index 99dbfa3..1aeb67d 100644 --- a/drivers/fsi/fsi-occ.c +++ b/drivers/fsi/fsi-occ.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +41,7 @@ struct occ { struct device *sbefifo; char name[32]; int idx; + struct miscdevice mdev; struct list_head xfrs; spinlock_t list_lock; /* lock access to the xfrs list */ struct mutex occ_lock; /* lock access to the hardware */ @@ -113,6 +115,29 @@ struct occ_client { static DEFINE_IDA(occ_ida); +static int occ_enqueue_xfr(struct occ_xfr *xfr) +{ + int empty; + unsigned long flags; + struct occ_client *client = to_client(xfr); + struct occ *occ = client->occ; + + if (occ->cancel) + return -ENODEV; + + spin_lock_irqsave(&occ->list_lock, flags); + + empty = list_empty(&occ->xfrs); + list_add_tail(&xfr->link, &occ->xfrs); + + spin_unlock_irqrestore(&occ->list_lock, flags); + + if (empty) + queue_work(occ_wq, &occ->work); + + return 0; +} + static void occ_get_client(struct occ_client *client) { kref_get(&client->kref); @@ -131,6 +156,230 @@ static void occ_put_client(struct occ_client *client) kref_put(&client->kref, occ_client_release); } +static int occ_open(struct inode *inode, struct file *file) +{ + struct miscdevice *mdev = file->private_data; + struct occ *occ = to_occ(mdev); + struct occ_client *client = kzalloc(sizeof(*client), GFP_KERNEL); + + if (!client) + return -ENOMEM; + + client->occ = occ; + kref_init(&client->kref); + spin_lock_init(&client->lock); + init_waitqueue_head(&client->wait); + + if (file->f_flags & O_NONBLOCK) + set_bit(CLIENT_NONBLOCKING, &client->flags); + + file->private_data = client; + + return 0; +} + +static inline bool occ_read_ready(struct occ_xfr *xfr, struct occ *occ) +{ + return test_bit(XFR_COMPLETE, &xfr->flags) || + test_bit(XFR_CANCELED, &xfr->flags) || occ->cancel; +} + +static ssize_t occ_read(struct file *file, char __user *buf, size_t len, + loff_t *offset) +{ + int rc; + unsigned long flags; + size_t bytes; + struct occ_xfr *xfr; + struct occ *occ; + struct occ_client *client = file->private_data; + + if (!client) + return -ENODEV; + + if (len > OCC_SRAM_BYTES) + return -EINVAL; + + occ_get_client(client); + xfr = &client->xfr; + occ = client->occ; + + spin_lock_irqsave(&client->lock, flags); + + if (!test_bit(CLIENT_XFR_PENDING, &client->flags)) { + /* we just finished reading all data, return 0 */ + if (client->read_offset) { + rc = 0; + client->read_offset = 0; + } else { + rc = -ENOMSG; + } + + goto done; + } + + if (!test_bit(XFR_COMPLETE, &xfr->flags)) { + if (test_bit(CLIENT_NONBLOCKING, &client->flags)) { + rc = -EAGAIN; + goto done; + } + + spin_unlock_irqrestore(&client->lock, flags); + + rc = wait_event_interruptible(client->wait, + occ_read_ready(xfr, occ)); + + spin_lock_irqsave(&client->lock, flags); + + if (!test_bit(XFR_COMPLETE, &xfr->flags)) { + if (occ->cancel || test_bit(XFR_CANCELED, &xfr->flags)) + rc = -ENODEV; + else + rc = -EINTR; + + goto done; + } + } + + if (xfr->rc) { + rc = xfr->rc; + goto done; + } + + bytes = min(len, xfr->resp_data_length - client->read_offset); + if (copy_to_user(buf, &xfr->buf[client->read_offset], bytes)) { + rc = -EFAULT; + goto done; + } + + client->read_offset += bytes; + + /* xfr done */ + if (client->read_offset == xfr->resp_data_length) + clear_bit(CLIENT_XFR_PENDING, &client->flags); + + rc = bytes; + +done: + spin_unlock_irqrestore(&client->lock, flags); + occ_put_client(client); + return rc; +} + +static ssize_t occ_write(struct file *file, const char __user *buf, + size_t len, loff_t *offset) +{ + int rc; + unsigned long flags; + unsigned int i; + u16 data_length, checksum = 0; + struct occ_xfr *xfr; + struct occ_client *client = file->private_data; + + if (!client) + return -ENODEV; + + if (len > (OCC_CMD_DATA_BYTES + 3) || len < 3) + return -EINVAL; + + occ_get_client(client); + xfr = &client->xfr; + + spin_lock_irqsave(&client->lock, flags); + + if (test_bit(CLIENT_XFR_PENDING, &client->flags)) { + rc = -EBUSY; + goto done; + } + + memset(xfr, 0, sizeof(*xfr)); /* clear out the transfer */ + xfr->buf[0] = 1; /* occ sequence number */ + + /* + * Assume user data follows the occ command format. + * byte 0: command type + * bytes 1-2: data length (msb first) + * bytes 3-n: data + */ + if (copy_from_user(&xfr->buf[1], buf, len)) { + rc = -EFAULT; + goto done; + } + + data_length = (xfr->buf[2] << 8) + xfr->buf[3]; + if (data_length > OCC_CMD_DATA_BYTES) { + rc = -EINVAL; + goto done; + } + + for (i = 0; i < data_length + 4; ++i) + checksum += xfr->buf[i]; + + xfr->buf[data_length + 4] = checksum >> 8; + xfr->buf[data_length + 5] = checksum & 0xFF; + + xfr->cmd_data_length = data_length + 6; + client->read_offset = 0; + + rc = occ_enqueue_xfr(xfr); + if (rc) + goto done; + + set_bit(CLIENT_XFR_PENDING, &client->flags); + rc = len; + +done: + spin_unlock_irqrestore(&client->lock, flags); + occ_put_client(client); + return rc; +} + +static int occ_release(struct inode *inode, struct file *file) +{ + unsigned long flags; + struct occ *occ; + struct occ_xfr *xfr; + struct occ_client *client = file->private_data; + + if (!client) + return -ENODEV; + + xfr = &client->xfr; + occ = client->occ; + + spin_lock_irqsave(&client->lock, flags); + + set_bit(XFR_CANCELED, &xfr->flags); + if (!test_bit(CLIENT_XFR_PENDING, &client->flags)) + goto done; + + spin_lock(&occ->list_lock); + + if (!test_bit(XFR_IN_PROGRESS, &xfr->flags)) { + /* already deleted from list if complete */ + if (!test_bit(XFR_COMPLETE, &xfr->flags)) + list_del(&xfr->link); + } + + spin_unlock(&occ->list_lock); + + wake_up_all(&client->wait); + +done: + spin_unlock_irqrestore(&client->lock, flags); + + occ_put_client(client); + return 0; +} + +static const struct file_operations occ_fops = { + .owner = THIS_MODULE, + .open = occ_open, + .read = occ_read, + .write = occ_write, + .release = occ_release, +}; + static int occ_write_sbefifo(struct sbefifo_client *client, const char *buf, ssize_t len) { @@ -450,6 +699,19 @@ static int occ_probe(struct platform_device *pdev) occ->idx = ida_simple_get(&occ_ida, 1, INT_MAX, GFP_KERNEL); } + snprintf(occ->name, sizeof(occ->name), "occ%d", occ->idx); + occ->mdev.fops = &occ_fops; + occ->mdev.minor = MISC_DYNAMIC_MINOR; + occ->mdev.name = occ->name; + occ->mdev.parent = dev; + + rc = misc_register(&occ->mdev); + if (rc) { + dev_err(dev, "failed to register miscdevice: %d\n", rc); + ida_simple_remove(&occ_ida, occ->idx); + return rc; + } + platform_set_drvdata(pdev, occ); return 0; @@ -471,6 +733,8 @@ static int occ_remove(struct platform_device *pdev) } spin_unlock_irqrestore(&occ->list_lock, flags); + misc_deregister(&occ->mdev); + cancel_work_sync(&occ->work); ida_simple_remove(&occ_ida, occ->idx); -- 1.8.3.1 From 1584621281293680723@xxx Mon Nov 20 21:16:57 +0000 2017 X-GM-THRID: 1584505163360188504 X-Gmail-Labels: Inbox,Category Forums,HistoricalUnread