Received: by 10.223.164.202 with SMTP id h10csp4218106wrb; Mon, 20 Nov 2017 11:49:18 -0800 (PST) X-Google-Smtp-Source: AGs4zMY1zDaXJ35MB6T5NaOha3fNRBp87DfPgBcCOxLFIpTlLVi+RPMNWzMULWma5BiRRl4fpQyV X-Received: by 10.84.164.165 with SMTP id w34mr14900884pla.308.1511207358227; Mon, 20 Nov 2017 11:49:18 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1511207358; cv=none; d=google.com; s=arc-20160816; b=0iXh0AjxvSEzQjiUN3UTumhDXGgmCpaCDvxCjSnfr35M9HZfBIge/YVWJ7/fqLOjmn lcHM+LioCKEkr91yBFPaFB4Zn1mSj1Gl08on/E1z+V6hoXohu2k2GU/po5/MvMGdAEcq xJ5e6zKxu0KSw0H7ZTsOxFSxdqun/WwxfthFcea8C70muZWIcsLnu+bzDJVpOBkBIkf6 nZ4ot/OTAE8r7L3RH5ZAr9wibAq/ARog3svMM2nIrbH+y1eT2Baqd6Lm64ve/kQ0gz9u vvlEHFZ7ax4OyADM5oIJRLBh0liXLS91RJ6V9fbfHioCoIbiWVFWx2zcNcz4DR+DT1CE U4HA== 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=u6p9ukfm4sVq3KPcRr9mu35eifPh1lA1JlHKtYXeNPY=; b=QUwx9tz2vkRU6rj+EdK9IWcRUOW0uEvOUyKbu0u9SAuoqZ0DlfwYynQXsz8u6EHL5x ikaN0/blBKHwApClVOIfnzjJsffyjx2blZwBW5HCJ59PRfmKrbxMwNivAFWfHJnsYuKE yYKcWpmDKAlTObtU1GmXbPfhhVDMd8+FFBSNYSLeWd/BfsSHkdAKAXsnI0BBO/J9PmtI Vn3yPYT9Wkk/0SiGnA0uLQf0sV2SnTkQcIxMD4zDIQB4iG83zrEFGywCAbG2LlNSYb5g Kb1snVm95Er02hQTgvkNBQm/LrJQI+Z6W5bmKkv0OK/0M8yn/BBdsdx+TPOycdpjV50c HPRw== 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 q2si8975103plh.626.2017.11.20.11.49.08; Mon, 20 Nov 2017 11:49:18 -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 S1752549AbdKTTsD (ORCPT + 67 others); Mon, 20 Nov 2017 14:48:03 -0500 Received: from mx0a-001b2d01.pphosted.com ([148.163.156.1]:60610 "EHLO mx0a-001b2d01.pphosted.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752412AbdKTTrU (ORCPT ); Mon, 20 Nov 2017 14:47:20 -0500 Received: from pps.filterd (m0098404.ppops.net [127.0.0.1]) by mx0a-001b2d01.pphosted.com (8.16.0.21/8.16.0.21) with SMTP id vAKJks80131277 for ; Mon, 20 Nov 2017 14:47:20 -0500 Received: from e37.co.us.ibm.com (e37.co.us.ibm.com [32.97.110.158]) by mx0a-001b2d01.pphosted.com with ESMTP id 2ec1ugcd27-1 (version=TLSv1.2 cipher=AES256-SHA bits=256 verify=NOT) for ; Mon, 20 Nov 2017 14:47:20 -0500 Received: from localhost by e37.co.us.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Mon, 20 Nov 2017 12:47:19 -0700 Received: from b03cxnp08028.gho.boulder.ibm.com (9.17.130.20) by e37.co.us.ibm.com (192.168.1.137) with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted; Mon, 20 Nov 2017 12:47:16 -0700 Received: from b03ledav006.gho.boulder.ibm.com (b03ledav006.gho.boulder.ibm.com [9.17.130.237]) by b03cxnp08028.gho.boulder.ibm.com (8.14.9/8.14.9/NCO v10.0) with ESMTP id vAKJlGeG3604982; Mon, 20 Nov 2017 12:47:16 -0700 Received: from b03ledav006.gho.boulder.ibm.com (unknown [127.0.0.1]) by IMSVA (Postfix) with ESMTP id 49B00C6043; Mon, 20 Nov 2017 12:47:16 -0700 (MST) Received: from oc3016140333.ibm.com (unknown [9.41.174.252]) by b03ledav006.gho.boulder.ibm.com (Postfix) with ESMTP id BE7AFC604A; Mon, 20 Nov 2017 12:47:15 -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 8/8] drivers/fsi: occ: Add in-kernel API Date: Mon, 20 Nov 2017 13:46:57 -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-0024-0000-0000-00001785D732 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:18 X-IBM-AV-DETECTION: SAVI=unused REMOTE=unused XFE=unused x-cbparentid: 17112019-0025-0000-0000-00004D958FE6 Message-Id: <1511207217-14075-9-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 an in-kernel read/write API with exported functions. This is necessary for other drivers which want to directly interact with the OCC. Also add a child platform device node for the associated hwmon device. Signed-off-by: Edward A. James --- drivers/fsi/fsi-occ.c | 138 ++++++++++++++++++++++++++++++++++++++++-------- include/linux/fsi-occ.h | 41 ++++++++++++++ 2 files changed, 157 insertions(+), 22 deletions(-) create mode 100644 include/linux/fsi-occ.h diff --git a/drivers/fsi/fsi-occ.c b/drivers/fsi/fsi-occ.c index 1aeb67d..1713550 100644 --- a/drivers/fsi/fsi-occ.c +++ b/drivers/fsi/fsi-occ.c @@ -19,7 +19,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -32,8 +34,6 @@ #define OCC_CMD_DATA_BYTES 4090 #define OCC_RESP_DATA_BYTES 4089 -#define OCC_RESP_CMD_IN_PRG 0xFF - #define OCC_TIMEOUT_MS 1000 #define OCC_CMD_IN_PRG_WAIT_MS 50 @@ -156,23 +156,34 @@ 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) +static struct occ_client *occ_open_common(struct occ *occ, unsigned long flags) { - 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; + return NULL; client->occ = occ; kref_init(&client->kref); spin_lock_init(&client->lock); init_waitqueue_head(&client->wait); - if (file->f_flags & O_NONBLOCK) + if (flags & O_NONBLOCK) set_bit(CLIENT_NONBLOCKING, &client->flags); + return client; +} + +static int occ_open(struct inode *inode, struct file *file) +{ + struct occ_client *client; + struct miscdevice *mdev = file->private_data; + struct occ *occ = to_occ(mdev); + + client = occ_open_common(occ, file->f_flags); + if (!client) + return -ENOMEM; + file->private_data = client; return 0; @@ -184,15 +195,14 @@ static inline bool occ_read_ready(struct occ_xfr *xfr, struct occ *occ) 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) +static ssize_t occ_read_common(struct occ_client *client, char __user *ubuf, + char *kbuf, size_t len) { 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; @@ -247,9 +257,14 @@ static ssize_t occ_read(struct file *file, char __user *buf, size_t len, } 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; + if (ubuf) { + if (copy_to_user(ubuf, &xfr->buf[client->read_offset], + bytes)) { + rc = -EFAULT; + goto done; + } + } else { + memcpy(kbuf, &xfr->buf[client->read_offset], bytes); } client->read_offset += bytes; @@ -266,15 +281,23 @@ static ssize_t occ_read(struct file *file, char __user *buf, size_t len, return rc; } -static ssize_t occ_write(struct file *file, const char __user *buf, - size_t len, loff_t *offset) +static ssize_t occ_read(struct file *file, char __user *buf, size_t len, + loff_t *offset) +{ + struct occ_client *client = file->private_data; + + return occ_read_common(client, buf, NULL, len); +} + +static ssize_t occ_write_common(struct occ_client *client, + const char __user *ubuf, const char *kbuf, + size_t len) { 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; @@ -301,9 +324,13 @@ static ssize_t occ_write(struct file *file, const char __user *buf, * bytes 1-2: data length (msb first) * bytes 3-n: data */ - if (copy_from_user(&xfr->buf[1], buf, len)) { - rc = -EFAULT; - goto done; + if (ubuf) { + if (copy_from_user(&xfr->buf[1], ubuf, len)) { + rc = -EFAULT; + goto done; + } + } else { + memcpy(&xfr->buf[1], kbuf, len); } data_length = (xfr->buf[2] << 8) + xfr->buf[3]; @@ -334,12 +361,19 @@ static ssize_t occ_write(struct file *file, const char __user *buf, return rc; } -static int occ_release(struct inode *inode, struct file *file) +static ssize_t occ_write(struct file *file, const char __user *buf, + size_t len, loff_t *offset) +{ + struct occ_client *client = file->private_data; + + return occ_write_common(client, buf, NULL, len); +} + +static int occ_release_common(struct occ_client *client) { unsigned long flags; struct occ *occ; struct occ_xfr *xfr; - struct occ_client *client = file->private_data; if (!client) return -ENODEV; @@ -372,6 +406,13 @@ static int occ_release(struct inode *inode, struct file *file) return 0; } +static int occ_release(struct inode *inode, struct file *file) +{ + struct occ_client *client = file->private_data; + + return occ_release_common(client); +} + static const struct file_operations occ_fops = { .owner = THIS_MODULE, .open = occ_open, @@ -665,12 +706,55 @@ static void occ_worker(struct work_struct *work) goto again; } +struct occ_client *occ_drv_open(struct device *dev, unsigned long flags) +{ + struct occ *occ = dev_get_drvdata(dev); + + if (!occ) + return NULL; + + return occ_open_common(occ, flags); +} +EXPORT_SYMBOL_GPL(occ_drv_open); + +int occ_drv_read(struct occ_client *client, char *buf, size_t len) +{ + return occ_read_common(client, NULL, buf, len); +} +EXPORT_SYMBOL_GPL(occ_drv_read); + +int occ_drv_write(struct occ_client *client, const char *buf, size_t len) +{ + return occ_write_common(client, NULL, buf, len); +} +EXPORT_SYMBOL_GPL(occ_drv_write); + +void occ_drv_release(struct occ_client *client) +{ + occ_release_common(client); +} +EXPORT_SYMBOL_GPL(occ_drv_release); + +static int occ_unregister_child(struct device *dev, void *data) +{ + struct platform_device *child = to_platform_device(dev); + + of_device_unregister(child); + if (dev->of_node) + of_node_clear_flag(dev->of_node, OF_POPULATED); + + return 0; +} + static int occ_probe(struct platform_device *pdev) { - int rc; + int rc, child_idx = 0; u32 reg; struct occ *occ; + struct device_node *np; + struct platform_device *child; struct device *dev = &pdev->dev; + char child_name[32]; occ = devm_kzalloc(dev, sizeof(*occ), GFP_KERNEL); if (!occ) @@ -712,6 +796,15 @@ static int occ_probe(struct platform_device *pdev) return rc; } + /* create platform devs for dts child nodes (hwmon, etc) */ + for_each_available_child_of_node(dev->of_node, np) { + snprintf(child_name, sizeof(child_name), "occ%d-dev%d", + occ->idx, child_idx++); + child = of_platform_device_create(np, child_name, dev); + if (!child) + dev_warn(dev, "failed to create child node dev\n"); + } + platform_set_drvdata(pdev, occ); return 0; @@ -734,6 +827,7 @@ static int occ_remove(struct platform_device *pdev) spin_unlock_irqrestore(&occ->list_lock, flags); misc_deregister(&occ->mdev); + device_for_each_child(&pdev->dev, NULL, occ_unregister_child); cancel_work_sync(&occ->work); diff --git a/include/linux/fsi-occ.h b/include/linux/fsi-occ.h new file mode 100644 index 0000000..0a4a54a --- /dev/null +++ b/include/linux/fsi-occ.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) IBM Corporation 2017 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERGCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef LINUX_FSI_OCC_H +#define LINUX_FSI_OCC_H + +struct device; +struct occ_client; + +#define OCC_RESP_CMD_IN_PRG 0xFF +#define OCC_RESP_SUCCESS 0 +#define OCC_RESP_CMD_INVAL 0x11 +#define OCC_RESP_CMD_LEN_INVAL 0x12 +#define OCC_RESP_DATA_INVAL 0x13 +#define OCC_RESP_CHKSUM_ERR 0x14 +#define OCC_RESP_INT_ERR 0x15 +#define OCC_RESP_BAD_STATE 0x16 +#define OCC_RESP_CRIT_EXCEPT 0xE0 +#define OCC_RESP_CRIT_INIT 0xE1 +#define OCC_RESP_CRIT_WATCHDOG 0xE2 +#define OCC_RESP_CRIT_OCB 0xE3 +#define OCC_RESP_CRIT_HW 0xE4 + +extern struct occ_client *occ_drv_open(struct device *dev, + unsigned long flags); +extern int occ_drv_read(struct occ_client *client, char *buf, size_t len); +extern int occ_drv_write(struct occ_client *client, const char *buf, + size_t len); +extern void occ_drv_release(struct occ_client *client); + +#endif /* LINUX_FSI_OCC_H */ -- 1.8.3.1 From 1583495565022227104@xxx Wed Nov 08 11:04:10 +0000 2017 X-GM-THRID: 1583329603309959733 X-Gmail-Labels: Inbox,Category Forums,HistoricalUnread