* Re: [PATCH v5 tip 1/7] bpf: make internal bpf API independent of CONFIG_BPF_SYSCALL ifdefs
From: Daniel Borkmann @ 2015-03-02 11:10 UTC (permalink / raw)
To: Masami Hiramatsu, Alexei Starovoitov
Cc: Ingo Molnar, Steven Rostedt, Namhyung Kim,
Arnaldo Carvalho de Melo, Jiri Olsa, David S. Miller,
Peter Zijlstra, linux-api-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <54F44115.40505-FCd8Q96Dh0JBDgjK7y7TUQ@public.gmane.org>
On 03/02/2015 11:53 AM, Masami Hiramatsu wrote:
...
> Hmm, it seems that this still doesn't hide some APIs which is provided
> only when CONFIG_BPF_SYSCALL. For example bpf_register_map_type etc.
> I think all those APIs should be hidden in #ifdef or at least be commented
> so that the user doesn't refer that without the kconfig.
> (I don't think we need to provide dummy functions for those APIs,
> but it's better to clarify which API we can use with which kconfig)
Well, currently all possible map types (hash table, array map) that
would actually call into bpf_register_map_type() are only built when
CONFIG_BPF_SYSCALL is enabled (see kernel/bpf/Makefile). I don't think
new map additions should be added that are not under kernel/bpf/ and/or
enabled outside the CONFIG_BPF_SYSCALL, as it should be considered
part of the eBPF core code.
The difference here (this patch) is simply that we don't want users to
build ifdef spaghetti constructs in user code, so the API that is
actually used by eBPF _users_ is being properly ifdef'ed in the headers.
So, I don't think this is a big problem, but we could move these bits
under the ifdef CONFIG_BPF_SYSCALL w/o providing a dummy in the else part.
I can do that outside of the scope of this set.
^ permalink raw reply
* Re: [PATCH 0/2] add cursor blink interval terminal escape sequence
From: Tomi Valkeinen @ 2015-03-02 11:15 UTC (permalink / raw)
To: Scot Doyle
Cc: Greg Kroah-Hartman, Jiri Slaby, Jean-Christophe Plagniol-Villard,
Michael Kerrisk, Pavel Machek, Geert Uytterhoeven, linux-kernel,
linux-fbdev, linux-api, linux-man
In-Reply-To: <alpine.LNX.2.11.1502271905580.4212@localhost>
[-- Attachment #1: Type: text/plain, Size: 512 bytes --]
On 27/02/15 21:10, Scot Doyle wrote:
> Greg, the first patch of this series is for the tty tree.
>
> Tomi, the second patch of this series is for your tree, but it depends on
> the first patch. Also, will you remove these two previously queued patches?
> "fbcon: store cursor blink interval in fbcon_ops"
> "fbcon: expose cursor blink interval via sysfs"
I have dropped those two patches from fbdev tree.
I don't know much about the console side, so I can't comment anything on
that.
Tomi
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* Re: [PATCH v5 tip 1/7] bpf: make internal bpf API independent of CONFIG_BPF_SYSCALL ifdefs
From: Masami Hiramatsu @ 2015-03-02 11:51 UTC (permalink / raw)
To: Daniel Borkmann
Cc: Alexei Starovoitov, Ingo Molnar, Steven Rostedt, Namhyung Kim,
Arnaldo Carvalho de Melo, Jiri Olsa, David S. Miller,
Peter Zijlstra, linux-api, netdev, linux-kernel
In-Reply-To: <54F4451B.8000703@iogearbox.net>
(2015/03/02 20:10), Daniel Borkmann wrote:
> On 03/02/2015 11:53 AM, Masami Hiramatsu wrote:
> ...
>> Hmm, it seems that this still doesn't hide some APIs which is provided
>> only when CONFIG_BPF_SYSCALL. For example bpf_register_map_type etc.
>> I think all those APIs should be hidden in #ifdef or at least be commented
>> so that the user doesn't refer that without the kconfig.
>> (I don't think we need to provide dummy functions for those APIs,
>> but it's better to clarify which API we can use with which kconfig)
>
> Well, currently all possible map types (hash table, array map) that
> would actually call into bpf_register_map_type() are only built when
> CONFIG_BPF_SYSCALL is enabled (see kernel/bpf/Makefile). I don't think
> new map additions should be added that are not under kernel/bpf/ and/or
> enabled outside the CONFIG_BPF_SYSCALL, as it should be considered
> part of the eBPF core code.
>
> The difference here (this patch) is simply that we don't want users to
> build ifdef spaghetti constructs in user code, so the API that is
> actually used by eBPF _users_ is being properly ifdef'ed in the headers.
>
> So, I don't think this is a big problem, but we could move these bits
> under the ifdef CONFIG_BPF_SYSCALL w/o providing a dummy in the else part.
> I can do that outside of the scope of this set.
Or, maybe we'd better move them into new include/linux/bpf_prog.h which
includes basic include/linux/bpf.h. Then, user can include the bpf_prog.h
instead of bpf.h. Also, we can check CONFIG_BPF_SYSCAL=y at the top of
bpf_prog.h. This makes things clearer :)
Thank you,
--
Masami HIRAMATSU
Software Platform Research Dept. Linux Technology Research Center
Hitachi, Ltd., Yokohama Research Laboratory
E-mail: masami.hiramatsu.pt@hitachi.com
^ permalink raw reply
* Re: [PATCH v5 tip 1/7] bpf: make internal bpf API independent of CONFIG_BPF_SYSCALL ifdefs
From: Daniel Borkmann @ 2015-03-02 12:26 UTC (permalink / raw)
To: Masami Hiramatsu
Cc: Alexei Starovoitov, Ingo Molnar, Steven Rostedt, Namhyung Kim,
Arnaldo Carvalho de Melo, Jiri Olsa, David S. Miller,
Peter Zijlstra, linux-api, netdev, linux-kernel
In-Reply-To: <54F44EC3.4070504@hitachi.com>
On 03/02/2015 12:51 PM, Masami Hiramatsu wrote:
> (2015/03/02 20:10), Daniel Borkmann wrote:
>> On 03/02/2015 11:53 AM, Masami Hiramatsu wrote:
>> ...
>>> Hmm, it seems that this still doesn't hide some APIs which is provided
>>> only when CONFIG_BPF_SYSCALL. For example bpf_register_map_type etc.
>>> I think all those APIs should be hidden in #ifdef or at least be commented
>>> so that the user doesn't refer that without the kconfig.
>>> (I don't think we need to provide dummy functions for those APIs,
>>> but it's better to clarify which API we can use with which kconfig)
>>
>> Well, currently all possible map types (hash table, array map) that
>> would actually call into bpf_register_map_type() are only built when
>> CONFIG_BPF_SYSCALL is enabled (see kernel/bpf/Makefile). I don't think
>> new map additions should be added that are not under kernel/bpf/ and/or
>> enabled outside the CONFIG_BPF_SYSCALL, as it should be considered
>> part of the eBPF core code.
>>
>> The difference here (this patch) is simply that we don't want users to
>> build ifdef spaghetti constructs in user code, so the API that is
>> actually used by eBPF _users_ is being properly ifdef'ed in the headers.
>>
>> So, I don't think this is a big problem, but we could move these bits
>> under the ifdef CONFIG_BPF_SYSCALL w/o providing a dummy in the else part.
>> I can do that outside of the scope of this set.
>
> Or, maybe we'd better move them into new include/linux/bpf_prog.h which
> includes basic include/linux/bpf.h. Then, user can include the bpf_prog.h
> instead of bpf.h. Also, we can check CONFIG_BPF_SYSCAL=y at the top of
> bpf_prog.h. This makes things clearer :)
I'm preferring the 1st variant, though. We have currently two native eBPF
users, that is, socket filters and tc's cls_bpf (queued in net-next) and
looking at the code/API usage, it's really not that hard, where it would
justify to move this to an extra header file, really.
I'm cooking a patch for net-next right now with the first variant (which is
on top of this patch that resides in net-next as-is as well).
Thanks,
Daniel
^ permalink raw reply
* Re: [PATCH RFC 0/3] Drivers: hv: utils: re-implement the kernel/userspace communication layer
From: Vitaly Kuznetsov @ 2015-03-02 13:33 UTC (permalink / raw)
To: Radim Krčmář
Cc: K. Y. Srinivasan, devel-tBiZLqfeLfOHmIFyCCdPziST3g8Odh+X,
Haiyang Zhang, linux-kernel-u79uwXL29TY76Z2rM5mHXA, Dexuan Cui,
Greg Kroah-Hartman, linux-api-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20150227210744.GA11904-KfRq7+sF/6zkZJWtSm8s3NvLeJWuRmrY@public.gmane.org>
Radim Krčmář <rkrcmar-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> writes:
> 2015-02-27 17:14+0100, Vitaly Kuznetsov:
>> This series converts kvp/vss daemons to use misc char devices instead of
>> netlink for userspace/kernel communication and then updates fcopy to be
>> consistent with kvp/vss.
>>
>> Userspace/kernel communication via netlink has a number of issues:
>> - It is hard for userspace to figure out if the kernel part was loaded or not
>> and this fact can change as there is a way to enable/disable the service from
>> host side.
>
> (Hm, this should be just a message to the userspace daemon, but netlink
> probably makes it complicated anyway.)
>
>> Racy daemon startup is also a problem.
>
> (Is it significantly worse than what we need to protect devices?)
>
>> - When the userspace daemon restarts/dies kernel part doesn't receive a
>> notification.
>
> (True, we could use a other-side-closed callback.)
With normal devices we can use e.g. udev/systemd machinery to start/stop
service on device hotplug/hotunplug (and these devices are actually
pluggable/unpluggable from host side) without any special code in
kernel/userspace parts and I'd like to use that.
>
>> - Netlink communication is not stable under heavy load.
>
> (The message order changes?)
>
It is a disaster if it does (the whole transaction will get lost). Same
if any of these messages gets lost.
>> RFC: I'm a bit puzzled on how to split commits 1 and 2 avoiding breakages.
>
> Split the userspace part -- it won't break bisects.
>
Sure if it simplifies the review.
> And then, you could refactor drivers first ... the way we communicate
> with userspace should have little impact on what the rest does (or how).
> At first sight, there are three units, apart from glue,
> 1) communication with host
> 2) communication with userspace
> 3) repacking of data between first two
>
> With an API for userspace communication, the amount of code to replace
> netlink could be lower and resulting patches definitely easier to
> review. (And with extra work, both ABIs could even live side-by-side ;)
Ok, thanks!
--
Vitaly
^ permalink raw reply
* Re: [PATCH RFC 0/3] Drivers: hv: utils: re-implement the kernel/userspace communication layer
From: Vitaly Kuznetsov @ 2015-03-02 13:37 UTC (permalink / raw)
To: KY Srinivasan
Cc: Radim Krčmář, Greg Kroah-Hartman, Haiyang Zhang,
linux-kernel@vger.kernel.org, linux-api@vger.kernel.org,
devel@linuxdriverproject.org
In-Reply-To: <BY2PR0301MB071107C31972876159BB360CA0100@BY2PR0301MB0711.namprd03.prod.outlook.com>
KY Srinivasan <kys@microsoft.com> writes:
>> -----Original Message-----
>> From: Vitaly Kuznetsov [mailto:vkuznets@redhat.com]
>> Sent: Friday, February 27, 2015 8:14 AM
>> To: KY Srinivasan; devel@linuxdriverproject.org
>> Cc: Haiyang Zhang; linux-kernel@vger.kernel.org; Dexuan Cui; Radim Krčmář;
>> Greg Kroah-Hartman; linux-api@vger.kernel.org
>> Subject: [PATCH RFC 0/3] Drivers: hv: utils: re-implement the
>> kernel/userspace communication layer
>>
>> This series converts kvp/vss daemons to use misc char devices instead of
>> netlink for userspace/kernel communication and then updates fcopy to be
>> consistent with kvp/vss.
>>
>> Userspace/kernel communication via netlink has a number of issues:
>> - It is hard for userspace to figure out if the kernel part was loaded or not
>> and this fact can change as there is a way to enable/disable the service from
>> host side. Racy daemon startup is also a problem.
>> - When the userspace daemon restarts/dies kernel part doesn't receive a
>> notification.
>> - Netlink communication is not stable under heavy load.
>> - ...
>>
>> RFC: I'm a bit puzzled on how to split commits 1 and 2 avoiding breakages.
>> Commit 3 can definitely be split, however, it is consistent with commits 1 and
>> 2 at this moment and I'm not sure such split will simplify the review.
>>
>> Vitaly Kuznetsov (3):
>> Drivers: hv: kvp: convert userspace/kernel communication to using char
>> device
>> Drivers: hv: vss: convert userspace/kernel communication to using char
>> device
>> Drivers: hv: fcopy: make it consistent with vss/kvp
>
> Vitaly,
>
> Thank you for working on this. Before I give you detailed comments on your
> patches, I wanted to understand if the cost of maintaining compatibility was
> carefully considered. As a first step we could look at cleanly abstracting the
> transport (between user level and the kernel) out of the kernel driver code
> as well as the new daemon code. What are your thoughts on
> this. Version negotiation is obviously key to maintaining
> compatibility. One of the options we can explore is to continue to
> use netlink for version negotiation and for appropriate daemon versions, we could use
> the char device mechanism for transporting the payload.
Ok, I'll try making it backwards compatible (though I'd opt for
full migratiot to char devices one day and thus having negotiation
possible via the same device as well as via netlink for now).
>
> I like the new state machine you have defined and this is orthogonal to the transport
> options we have. You have sought feedback on how we can split up these changes into
> smaller patches. This is how I would proceed here:
>
> Patch(es) to clean up the current code:
> Patch(es) to clean up the state machine.
> Patch(es) to isolate the kernel/user transport
> Patch(es) to implement the new transport
Thanks, I'll proceed in this way.
>
> Regards,
>
> K. Y
>>
>> drivers/hv/hv_fcopy.c | 395 +++++++++++++++++++++++++---------------
>> ---
>> drivers/hv/hv_kvp.c | 396 +++++++++++++++++++++++++++-------------
>> ----
>> drivers/hv/hv_snapshot.c | 335 +++++++++++++++++++++++++++---------
>> -
>> include/uapi/linux/hyperv.h | 10 ++
>> tools/hv/hv_fcopy_daemon.c | 48 ++++--
>> tools/hv/hv_kvp_daemon.c | 187 ++++-----------------
>> tools/hv/hv_vss_daemon.c | 141 +++-------------
>> 7 files changed, 824 insertions(+), 688 deletions(-)
>>
>> --
>> 1.9.3
--
Vitaly
_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel
^ permalink raw reply
* Re: [PATCH v1 1/5] IB/uverbs: ex_query_device: answer must not depend on request's comp_mask
From: Yann Droneaud @ 2015-03-02 14:08 UTC (permalink / raw)
To: Or Gerlitz, Or Gerlitz
Cc: Roland Dreier, Jason Gunthorpe, Sagi Grimberg, Shachar Raindel,
Eli Cohen, Haggai Eran,
linux-rdma-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-api-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <CAJ3xEMhDtD7MpJ+1Y3z2yMpTrb9C5SaUa94E8xpVLHN4pHe3fw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
Hi Or,
Le samedi 31 janvier 2015 à 22:09 +0200, Or Gerlitz a écrit :
> On Fri, Jan 30, 2015, Yann Droneaud <ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org> wrote:
> > [..] I have not the chance
> > of owning HCA with the support for this feature, nor the patches
> > libibverbs / libmlx5 ... (anyway I would not have the time to test). [...]
>
> Yann, have you ever run Linux over RDMA capable HW (IB, RoCE, iWARP or alike?)
That was a silly question.
So I've took a little time to consider answering it,
perhaps you were gently kidding me.
Anyway, please take the following links as an answer to your question:
"rdma_create_qp() and max_send_wr"
<http://mid.gmane.org/1303404264.2243.19.camel-H/AUWmsJYVeqvyCYKW+Xr6xOck334EZe@public.gmane.org>
"ibv_create_qp() and max_inline_data behavior"
<http://mid.gmane.org/d7685e13978f93890b2939c5ac2d5c7f-zgzEX58YAwA@public.gmane.org>
"[PATCH librdmacm 0/3] no IBV_SEND_INLINE thus memory registration
required on QLogic/Intel HCA"
<http://mid.gmane.org/cover.1376746185.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
"[PATCH 00/22] infiniband: improve userspace input check"
<http://mid.gmane.org/cover.1376847403.git.ydroneaud-RlY5vtjFyJ3QT0dZR+AlfA@public.gmane.org>
I hope this would be enough to join the gang^Wclub. Where're the
by-laws ?
Regards.
--
Yann Droneaud
OPTEYA
^ permalink raw reply
* [PATCH v4 1/4] scsi: ufs: add ioctl interface for query request
From: Gilad Broner @ 2015-03-02 14:56 UTC (permalink / raw)
To: James.Bottomley
Cc: linux-kernel, linux-scsi, linux-arm-msm, santoshsy,
linux-scsi-owner, subhashj, ygardi, draviv, Noa Rubens,
Raviv Shvili, Vinayak Holikatti, James E.J. Bottomley,
open list:ABI/API
In-Reply-To: <1425308203-20695-1-git-send-email-gbroner@codeaurora.org>
From: Dolev Raviv <draviv@codeaurora.org>
This patch exposes the ioctl interface for UFS driver via SCSI device
ioctl interface. As of now UFS driver would provide the ioctl for query
interface to connected UFS device.
Signed-off-by: Dolev Raviv <draviv@codeaurora.org>
Signed-off-by: Noa Rubens <noag@codeaurora.org>
Signed-off-by: Raviv Shvili <rshvili@codeaurora.org>
Signed-off-by: Yaniv Gardi <ygardi@codeaurora.org>
---
drivers/scsi/ufs/ufs.h | 53 +++-------
drivers/scsi/ufs/ufshcd.c | 225 +++++++++++++++++++++++++++++++++++++++++-
include/uapi/scsi/Kbuild | 1 +
include/uapi/scsi/ufs/Kbuild | 3 +
include/uapi/scsi/ufs/ioctl.h | 57 +++++++++++
include/uapi/scsi/ufs/ufs.h | 66 +++++++++++++
6 files changed, 361 insertions(+), 44 deletions(-)
create mode 100644 include/uapi/scsi/ufs/Kbuild
create mode 100644 include/uapi/scsi/ufs/ioctl.h
create mode 100644 include/uapi/scsi/ufs/ufs.h
diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index 42c459a..1f023c4 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -38,6 +38,7 @@
#include <linux/mutex.h>
#include <linux/types.h>
+#include <scsi/ufs/ufs.h>
#define MAX_CDB_SIZE 16
#define GENERAL_UPIU_REQUEST_SIZE 32
@@ -71,6 +72,16 @@ enum {
UFS_UPIU_RPMB_WLUN = 0xC4,
};
+/**
+ * ufs_is_valid_unit_desc_lun - checks if the given LUN has a unit descriptor
+ * @lun: LU number to check
+ * @return: true if the lun has a matching unit descriptor, false otherwise
+ */
+static inline bool ufs_is_valid_unit_desc_lun(u8 lun)
+{
+ return (lun == UFS_UPIU_RPMB_WLUN || (lun < UFS_UPIU_MAX_GENERAL_LUN));
+}
+
/*
* UFS Protocol Information Unit related definitions
*/
@@ -126,35 +137,6 @@ enum {
UPIU_QUERY_FUNC_STANDARD_WRITE_REQUEST = 0x81,
};
-/* Flag idn for Query Requests*/
-enum flag_idn {
- QUERY_FLAG_IDN_FDEVICEINIT = 0x01,
- QUERY_FLAG_IDN_PWR_ON_WPE = 0x03,
- QUERY_FLAG_IDN_BKOPS_EN = 0x04,
-};
-
-/* Attribute idn for Query requests */
-enum attr_idn {
- QUERY_ATTR_IDN_ACTIVE_ICC_LVL = 0x03,
- QUERY_ATTR_IDN_BKOPS_STATUS = 0x05,
- QUERY_ATTR_IDN_EE_CONTROL = 0x0D,
- QUERY_ATTR_IDN_EE_STATUS = 0x0E,
-};
-
-/* Descriptor idn for Query requests */
-enum desc_idn {
- QUERY_DESC_IDN_DEVICE = 0x0,
- QUERY_DESC_IDN_CONFIGURAION = 0x1,
- QUERY_DESC_IDN_UNIT = 0x2,
- QUERY_DESC_IDN_RFU_0 = 0x3,
- QUERY_DESC_IDN_INTERCONNECT = 0x4,
- QUERY_DESC_IDN_STRING = 0x5,
- QUERY_DESC_IDN_RFU_1 = 0x6,
- QUERY_DESC_IDN_GEOMETRY = 0x7,
- QUERY_DESC_IDN_POWER = 0x8,
- QUERY_DESC_IDN_MAX,
-};
-
enum desc_header_offset {
QUERY_DESC_LENGTH_OFFSET = 0x00,
QUERY_DESC_DESC_TYPE_OFFSET = 0x01,
@@ -247,19 +229,6 @@ enum bkops_status {
BKOPS_STATUS_MAX = BKOPS_STATUS_CRITICAL,
};
-/* UTP QUERY Transaction Specific Fields OpCode */
-enum query_opcode {
- UPIU_QUERY_OPCODE_NOP = 0x0,
- UPIU_QUERY_OPCODE_READ_DESC = 0x1,
- UPIU_QUERY_OPCODE_WRITE_DESC = 0x2,
- UPIU_QUERY_OPCODE_READ_ATTR = 0x3,
- UPIU_QUERY_OPCODE_WRITE_ATTR = 0x4,
- UPIU_QUERY_OPCODE_READ_FLAG = 0x5,
- UPIU_QUERY_OPCODE_SET_FLAG = 0x6,
- UPIU_QUERY_OPCODE_CLEAR_FLAG = 0x7,
- UPIU_QUERY_OPCODE_TOGGLE_FLAG = 0x8,
-};
-
/* Query response result code */
enum {
QUERY_RESULT_SUCCESS = 0x00,
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 5d60a86..cb357f8 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -3,7 +3,7 @@
*
* This code is based on drivers/scsi/ufs/ufshcd.c
* Copyright (C) 2011-2013 Samsung India Software Operations
- * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
*
* Authors:
* Santosh Yaraganavi <santosh.sy@samsung.com>
@@ -39,6 +39,7 @@
#include <linux/async.h>
#include <linux/devfreq.h>
+#include <scsi/ufs/ioctl.h>
#include "ufshcd.h"
#include "unipro.h"
@@ -74,6 +75,9 @@
/* Interrupt aggregation default timeout, unit: 40us */
#define INT_AGGR_DEF_TO 0x02
+/* IOCTL opcode for command - ufs set device read only */
+#define UFS_IOCTL_BLKROSET BLKROSET
+
#define ufshcd_toggle_vreg(_dev, _vreg, _on) \
({ \
int _ret; \
@@ -1882,7 +1886,7 @@ static inline int ufshcd_read_unit_desc_param(struct ufs_hba *hba,
* Unit descriptors are only available for general purpose LUs (LUN id
* from 0 to 7) and RPMB Well known LU.
*/
- if (lun != UFS_UPIU_RPMB_WLUN && (lun >= UFS_UPIU_MAX_GENERAL_LUN))
+ if (!ufs_is_valid_unit_desc_lun(lun))
return -EOPNOTSUPP;
return ufshcd_read_desc_param(hba, QUERY_DESC_IDN_UNIT, lun,
@@ -4201,6 +4205,222 @@ static void ufshcd_async_scan(void *data, async_cookie_t cookie)
ufshcd_probe_hba(hba);
}
+/**
+ * ufshcd_query_ioctl - perform user read queries
+ * @hba: per-adapter instance
+ * @lun: used for lun specific queries
+ * @buffer: user space buffer for reading and submitting query data and params
+ * @return: 0 for success negative error code otherwise
+ *
+ * Expected/Submitted buffer structure is struct ufs_ioctl_query_data.
+ * It will read the opcode, idn and buf_length parameters, and, put the
+ * response in the buffer field while updating the used size in buf_length.
+ */
+static int ufshcd_query_ioctl(struct ufs_hba *hba, u8 lun, void __user *buffer)
+{
+ struct ufs_ioctl_query_data *ioctl_data;
+ int err = 0;
+ int length = 0;
+ void *data_ptr;
+ bool flag;
+ u32 att;
+ u8 index;
+ u8 *desc = NULL;
+
+ ioctl_data = kzalloc(sizeof(struct ufs_ioctl_query_data), GFP_KERNEL);
+ if (!ioctl_data) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ /* extract params from user buffer */
+ err = copy_from_user(ioctl_data, buffer,
+ sizeof(struct ufs_ioctl_query_data));
+ if (err) {
+ dev_err(hba->dev,
+ "%s: Failed copying buffer from user, err %d\n",
+ __func__, err);
+ goto out_release_mem;
+ }
+
+ /* verify legal parameters & send query */
+ switch (ioctl_data->opcode) {
+ case UPIU_QUERY_OPCODE_READ_DESC:
+ switch (ioctl_data->idn) {
+ case QUERY_DESC_IDN_DEVICE:
+ case QUERY_DESC_IDN_CONFIGURAION:
+ case QUERY_DESC_IDN_INTERCONNECT:
+ case QUERY_DESC_IDN_GEOMETRY:
+ case QUERY_DESC_IDN_POWER:
+ index = 0;
+ break;
+ case QUERY_DESC_IDN_UNIT:
+ if (!ufs_is_valid_unit_desc_lun(lun)) {
+ dev_err(hba->dev,
+ "%s: No unit descriptor for lun 0x%x\n",
+ __func__, lun);
+ err = -EINVAL;
+ goto out_release_mem;
+ }
+ index = lun;
+ break;
+ default:
+ goto out_einval;
+ }
+ length = min_t(int, QUERY_DESC_MAX_SIZE,
+ ioctl_data->buf_size);
+ desc = kzalloc(length, GFP_KERNEL);
+ if (!desc) {
+ dev_err(hba->dev, "%s: Failed allocating %d bytes\n",
+ __func__, length);
+ err = -ENOMEM;
+ goto out_release_mem;
+ }
+ err = ufshcd_query_descriptor(hba, ioctl_data->opcode,
+ ioctl_data->idn, index, 0, desc, &length);
+ break;
+ case UPIU_QUERY_OPCODE_READ_ATTR:
+ switch (ioctl_data->idn) {
+ case QUERY_ATTR_IDN_BOOT_LU_EN:
+ case QUERY_ATTR_IDN_POWER_MODE:
+ case QUERY_ATTR_IDN_ACTIVE_ICC_LVL:
+ case QUERY_ATTR_IDN_OOO_DATA_EN:
+ case QUERY_ATTR_IDN_BKOPS_STATUS:
+ case QUERY_ATTR_IDN_PURGE_STATUS:
+ case QUERY_ATTR_IDN_MAX_DATA_IN:
+ case QUERY_ATTR_IDN_MAX_DATA_OUT:
+ case QUERY_ATTR_IDN_REF_CLK_FREQ:
+ case QUERY_ATTR_IDN_CONF_DESC_LOCK:
+ case QUERY_ATTR_IDN_MAX_NUM_OF_RTT:
+ case QUERY_ATTR_IDN_EE_CONTROL:
+ case QUERY_ATTR_IDN_EE_STATUS:
+ case QUERY_ATTR_IDN_SECONDS_PASSED:
+ index = 0;
+ break;
+ case QUERY_ATTR_IDN_DYN_CAP_NEEDED:
+ case QUERY_ATTR_IDN_CORR_PRG_BLK_NUM:
+ index = lun;
+ break;
+ default:
+ goto out_einval;
+ }
+ err = ufshcd_query_attr(hba, ioctl_data->opcode,
+ ioctl_data->idn, index, 0, &att);
+ break;
+ case UPIU_QUERY_OPCODE_READ_FLAG:
+ switch (ioctl_data->idn) {
+ case QUERY_FLAG_IDN_FDEVICEINIT:
+ case QUERY_FLAG_IDN_PERMANENT_WPE:
+ case QUERY_FLAG_IDN_PWR_ON_WPE:
+ case QUERY_FLAG_IDN_BKOPS_EN:
+ case QUERY_FLAG_IDN_PURGE_ENABLE:
+ case QUERY_FLAG_IDN_FPHYRESOURCEREMOVAL:
+ case QUERY_FLAG_IDN_BUSY_RTC:
+ break;
+ default:
+ goto out_einval;
+ }
+ err = ufshcd_query_flag(hba, ioctl_data->opcode,
+ ioctl_data->idn, &flag);
+ break;
+ default:
+ goto out_einval;
+ }
+
+ if (err) {
+ dev_err(hba->dev, "%s: Query for idn %d failed\n", __func__,
+ ioctl_data->idn);
+ goto out_release_mem;
+ }
+
+ /*
+ * copy response data
+ * As we might end up reading less data then what is specified in
+ * "ioct_data->buf_size". So we are updating "ioct_data->
+ * buf_size" to what exactly we have read.
+ */
+ switch (ioctl_data->opcode) {
+ case UPIU_QUERY_OPCODE_READ_DESC:
+ ioctl_data->buf_size = min_t(int, ioctl_data->buf_size, length);
+ data_ptr = desc;
+ break;
+ case UPIU_QUERY_OPCODE_READ_ATTR:
+ ioctl_data->buf_size = sizeof(u32);
+ data_ptr = &att;
+ break;
+ case UPIU_QUERY_OPCODE_READ_FLAG:
+ ioctl_data->buf_size = 1;
+ data_ptr = &flag;
+ break;
+ default:
+ BUG_ON(true);
+ }
+
+ /* copy to user */
+ err = copy_to_user(buffer, ioctl_data,
+ sizeof(struct ufs_ioctl_query_data));
+ if (err)
+ dev_err(hba->dev, "%s: Failed copying back to user.\n",
+ __func__);
+ err = copy_to_user(buffer + sizeof(struct ufs_ioctl_query_data),
+ data_ptr, ioctl_data->buf_size);
+ if (err)
+ dev_err(hba->dev, "%s: err %d copying back to user.\n",
+ __func__, err);
+ goto out_release_mem;
+
+out_einval:
+ dev_err(hba->dev,
+ "%s: illegal ufs query ioctl data, opcode 0x%x, idn 0x%x\n",
+ __func__, ioctl_data->opcode, (unsigned int)ioctl_data->idn);
+ err = -EINVAL;
+out_release_mem:
+ kfree(ioctl_data);
+ kfree(desc);
+out:
+ return err;
+}
+
+/**
+ * ufshcd_ioctl - ufs ioctl callback registered in scsi_host
+ * @dev: scsi device required for per LUN queries
+ * @cmd: command opcode
+ * @buffer: user space buffer for transferring data
+ *
+ * Supported commands:
+ * UFS_IOCTL_QUERY
+ */
+static int ufshcd_ioctl(struct scsi_device *dev, int cmd, void __user *buffer)
+{
+ struct ufs_hba *hba = shost_priv(dev->host);
+ int err = 0;
+
+ BUG_ON(!hba);
+ if (!buffer) {
+ dev_err(hba->dev, "%s: User buffer is NULL!\n", __func__);
+ return -EINVAL;
+ }
+
+ switch (cmd) {
+ case UFS_IOCTL_QUERY:
+ pm_runtime_get_sync(hba->dev);
+ err = ufshcd_query_ioctl(hba, ufshcd_scsi_to_upiu_lun(dev->lun),
+ buffer);
+ pm_runtime_put_sync(hba->dev);
+ break;
+ case UFS_IOCTL_BLKROSET:
+ err = -ENOIOCTLCMD;
+ break;
+ default:
+ err = -EINVAL;
+ dev_err(hba->dev, "%s: Illegal ufs-IOCTL cmd %d\n", __func__,
+ cmd);
+ break;
+ }
+
+ return err;
+}
+
static struct scsi_host_template ufshcd_driver_template = {
.module = THIS_MODULE,
.name = UFSHCD,
@@ -4213,6 +4433,7 @@ static struct scsi_host_template ufshcd_driver_template = {
.eh_abort_handler = ufshcd_abort,
.eh_device_reset_handler = ufshcd_eh_device_reset_handler,
.eh_host_reset_handler = ufshcd_eh_host_reset_handler,
+ .ioctl = ufshcd_ioctl,
.this_id = -1,
.sg_tablesize = SG_ALL,
.cmd_per_lun = UFSHCD_CMD_PER_LUN,
diff --git a/include/uapi/scsi/Kbuild b/include/uapi/scsi/Kbuild
index 75746d5..d404525 100644
--- a/include/uapi/scsi/Kbuild
+++ b/include/uapi/scsi/Kbuild
@@ -1,5 +1,6 @@
# UAPI Header export list
header-y += fc/
+header-y += ufs/
header-y += scsi_bsg_fc.h
header-y += scsi_netlink.h
header-y += scsi_netlink_fc.h
diff --git a/include/uapi/scsi/ufs/Kbuild b/include/uapi/scsi/ufs/Kbuild
new file mode 100644
index 0000000..cc3ef20
--- /dev/null
+++ b/include/uapi/scsi/ufs/Kbuild
@@ -0,0 +1,3 @@
+# UAPI Header export list
+header-y += ioctl.h
+header-y += ufs.h
diff --git a/include/uapi/scsi/ufs/ioctl.h b/include/uapi/scsi/ufs/ioctl.h
new file mode 100644
index 0000000..bc4eed7
--- /dev/null
+++ b/include/uapi/scsi/ufs/ioctl.h
@@ -0,0 +1,57 @@
+#ifndef UAPI_UFS_IOCTL_H_
+#define UAPI_UFS_IOCTL_H_
+
+#include <linux/types.h>
+
+/*
+ * IOCTL opcode for ufs queries has the following opcode after
+ * SCSI_IOCTL_GET_PCI
+ */
+#define UFS_IOCTL_QUERY 0x5388
+
+/**
+ * struct ufs_ioctl_query_data - used to transfer data to and from user via ioctl
+ * @opcode: type of data to query (descriptor/attribute/flag)
+ * @idn: id of the data structure
+ * @buf_size: number of allocated bytes/data size on return
+ * @buffer: data location
+ *
+ * Received: buffer and buf_size (available space for transferred data)
+ * Submitted: opcode, idn, length, buf_size
+ */
+struct ufs_ioctl_query_data {
+ /*
+ * User should select one of the opcode defined in "enum query_opcode".
+ * Please check include/uapi/scsi/ufs/ufs.h for the definition of it.
+ * Note that only UPIU_QUERY_OPCODE_READ_DESC,
+ * UPIU_QUERY_OPCODE_READ_ATTR & UPIU_QUERY_OPCODE_READ_FLAG are
+ * supported as of now. All other query_opcode would be considered
+ * invalid.
+ * As of now only read query operations are supported.
+ */
+ __u32 opcode;
+ /*
+ * User should select one of the idn from "enum flag_idn" or "enum
+ * attr_idn" or "enum desc_idn" based on whether opcode above is
+ * attribute, flag or descriptor.
+ * Please check include/uapi/scsi/ufs/ufs.h for the definition of it.
+ */
+ __u8 idn;
+ /*
+ * User should specify the size of the buffer (buffer[0] below) where
+ * it wants to read the query data (attribute/flag/descriptor).
+ * As we might end up reading less data then what is specified in
+ * buf_size. So we are updating buf_size to what exactly we have read.
+ */
+ __u16 buf_size;
+ /*
+ * placeholder for the start of the data buffer where kernel will copy
+ * the query data (attribute/flag/descriptor) read from the UFS device
+ * Note:
+ * For Read Attribute you will have to allocate 4 bytes
+ * For Read Flag you will have to allocate 1 byte
+ */
+ __u8 buffer[0];
+};
+
+#endif /* UAPI_UFS_IOCTL_H_ */
diff --git a/include/uapi/scsi/ufs/ufs.h b/include/uapi/scsi/ufs/ufs.h
new file mode 100644
index 0000000..894ea45
--- /dev/null
+++ b/include/uapi/scsi/ufs/ufs.h
@@ -0,0 +1,66 @@
+#ifndef UAPI_UFS_H_
+#define UAPI_UFS_H_
+
+/* Flag idn for Query Requests*/
+enum flag_idn {
+ QUERY_FLAG_IDN_FDEVICEINIT = 0x01,
+ QUERY_FLAG_IDN_PERMANENT_WPE = 0x02,
+ QUERY_FLAG_IDN_PWR_ON_WPE = 0x03,
+ QUERY_FLAG_IDN_BKOPS_EN = 0x04,
+ QUERY_FLAG_IDN_RESERVED1 = 0x05,
+ QUERY_FLAG_IDN_PURGE_ENABLE = 0x06,
+ QUERY_FLAG_IDN_RESERVED2 = 0x07,
+ QUERY_FLAG_IDN_FPHYRESOURCEREMOVAL = 0x08,
+ QUERY_FLAG_IDN_BUSY_RTC = 0x09,
+};
+
+/* Attribute idn for Query requests */
+enum attr_idn {
+ QUERY_ATTR_IDN_BOOT_LU_EN = 0x00,
+ QUERY_ATTR_IDN_RESERVED = 0x01,
+ QUERY_ATTR_IDN_POWER_MODE = 0x02,
+ QUERY_ATTR_IDN_ACTIVE_ICC_LVL = 0x03,
+ QUERY_ATTR_IDN_OOO_DATA_EN = 0x04,
+ QUERY_ATTR_IDN_BKOPS_STATUS = 0x05,
+ QUERY_ATTR_IDN_PURGE_STATUS = 0x06,
+ QUERY_ATTR_IDN_MAX_DATA_IN = 0x07,
+ QUERY_ATTR_IDN_MAX_DATA_OUT = 0x08,
+ QUERY_ATTR_IDN_DYN_CAP_NEEDED = 0x09,
+ QUERY_ATTR_IDN_REF_CLK_FREQ = 0x0A,
+ QUERY_ATTR_IDN_CONF_DESC_LOCK = 0x0B,
+ QUERY_ATTR_IDN_MAX_NUM_OF_RTT = 0x0C,
+ QUERY_ATTR_IDN_EE_CONTROL = 0x0D,
+ QUERY_ATTR_IDN_EE_STATUS = 0x0E,
+ QUERY_ATTR_IDN_SECONDS_PASSED = 0x0F,
+ QUERY_ATTR_IDN_CNTX_CONF = 0x10,
+ QUERY_ATTR_IDN_CORR_PRG_BLK_NUM = 0x11,
+};
+
+/* Descriptor idn for Query requests */
+enum desc_idn {
+ QUERY_DESC_IDN_DEVICE = 0x0,
+ QUERY_DESC_IDN_CONFIGURAION = 0x1,
+ QUERY_DESC_IDN_UNIT = 0x2,
+ QUERY_DESC_IDN_RFU_0 = 0x3,
+ QUERY_DESC_IDN_INTERCONNECT = 0x4,
+ QUERY_DESC_IDN_STRING = 0x5,
+ QUERY_DESC_IDN_RFU_1 = 0x6,
+ QUERY_DESC_IDN_GEOMETRY = 0x7,
+ QUERY_DESC_IDN_POWER = 0x8,
+ QUERY_DESC_IDN_RFU_2 = 0x9,
+ QUERY_DESC_IDN_MAX,
+};
+
+/* UTP QUERY Transaction Specific Fields OpCode */
+enum query_opcode {
+ UPIU_QUERY_OPCODE_NOP = 0x0,
+ UPIU_QUERY_OPCODE_READ_DESC = 0x1,
+ UPIU_QUERY_OPCODE_WRITE_DESC = 0x2,
+ UPIU_QUERY_OPCODE_READ_ATTR = 0x3,
+ UPIU_QUERY_OPCODE_WRITE_ATTR = 0x4,
+ UPIU_QUERY_OPCODE_READ_FLAG = 0x5,
+ UPIU_QUERY_OPCODE_SET_FLAG = 0x6,
+ UPIU_QUERY_OPCODE_CLEAR_FLAG = 0x7,
+ UPIU_QUERY_OPCODE_TOGGLE_FLAG = 0x8,
+};
+#endif /* UAPI_UFS_H_ */
--
Qualcomm Israel, on behalf of Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply related
* Re: [PATCH 1/9] HSI: cmt_speech: Add cmt-speech driver
From: Sebastian Reichel @ 2015-03-02 15:26 UTC (permalink / raw)
To: Oliver Neukum
Cc: Peter Ujfalusi, Kai Vehmanen, Pavel Machek, Pali Rohar,
Aaro Koskinen, Ivaylo Dimitrov, linux-omap, linux-kernel,
linux-api, Joni Lapilainen
In-Reply-To: <1425291753.2014.5.camel@neukum.org>
[-- Attachment #1: Type: text/plain, Size: 5284 bytes --]
Hi Oliver,
On Mon, Mar 02, 2015 at 11:22:33AM +0100, Oliver Neukum wrote:
> > +static ssize_t cs_char_read(struct file *file, char __user *buf, size_t count,
> > + loff_t *unused)
> > +{
> > + struct cs_char *csdata = file->private_data;
> > + u32 data;
> > + ssize_t retval;
> > +
> > + if (count < sizeof(data))
> > + return -EINVAL;
> > +
> > + for ( ; ; ) {
> > + DEFINE_WAIT(wait);
> > +
> > + spin_lock_bh(&csdata->lock);
> > + if (!list_empty(&csdata->chardev_queue)) {
> > + data = cs_pop_entry(&csdata->chardev_queue);
> > + } else if (!list_empty(&csdata->dataind_queue)) {
> > + data = cs_pop_entry(&csdata->dataind_queue);
> > + --csdata->dataind_pending;
> > +
> > + } else {
> > + data = 0;
> > + }
> > + spin_unlock_bh(&csdata->lock);
> > +
> > + if (data)
> > + break;
> > + if (file->f_flags & O_NONBLOCK) {
> > + retval = -EAGAIN;
> > + goto out;
> > + } else if (signal_pending(current)) {
> > + retval = -ERESTARTSYS;
> > + goto out;
> > + }
> > + prepare_to_wait_exclusive(&csdata->wait, &wait,
> > + TASK_INTERRUPTIBLE);
> > + schedule();
> > + finish_wait(&csdata->wait, &wait);
> > + }
> > +
> > + retval = put_user(data, (u32 __user *)buf);
> > + if (!retval)
> > + retval = sizeof(data);
> > +
> > +out:
> > + return retval;
> > +}
> > +
> > +static ssize_t cs_char_write(struct file *file, const char __user *buf,
> > + size_t count, loff_t *unused)
> > +{
> > + struct cs_char *csdata = file->private_data;
> > + u32 data;
> > + int err;
> > + ssize_t retval;
> > +
> > + if (count < sizeof(data))
> > + return -EINVAL;
> > +
> > + if (get_user(data, (u32 __user *)buf))
> > + retval = -EFAULT;
> > + else
> > + retval = count;
>
> You want to execute the command even if you got -EFAULT?
> That is highly unusual.
I will change this in PATCHv2.
> > +
> > + err = cs_hsi_command(csdata->hi, data);
> > + if (err < 0)
> > + retval = err;
> > +
> > + return retval;
> > +}
> > +
> > +static long cs_char_ioctl(struct file *file, unsigned int cmd,
> > + unsigned long arg)
> > +{
> > + struct cs_char *csdata = file->private_data;
> > + int r = 0;
> > +
> > + switch (cmd) {
> > + case CS_GET_STATE: {
> > + unsigned int state;
> > +
> > + state = cs_hsi_get_state(csdata->hi);
> > + if (copy_to_user((void __user *)arg, &state, sizeof(state)))
> > + r = -EFAULT;
> > + }
> > + break;
> > + case CS_SET_WAKELINE: {
> > + unsigned int state;
> > +
> > + if (copy_from_user(&state, (void __user *)arg, sizeof(state)))
> > + r = -EFAULT;
> > + else
> > + cs_hsi_set_wakeline(csdata->hi, state);
>
> No sanity checking for state?
Will be added in PATCHv2, so that -EINVAL is returned for values > 1.
> > + }
> > + break;
> > + case CS_GET_IF_VERSION: {
> > + unsigned int ifver = CS_IF_VERSION;
> > +
> > + if (copy_to_user((void __user *)arg, &ifver, sizeof(ifver)))
> > + r = -EFAULT;
> > + break;
> > + }
> > + case CS_CONFIG_BUFS: {
> > + struct cs_buffer_config buf_cfg;
> > +
> > + if (copy_from_user(&buf_cfg, (void __user *)arg,
> > + sizeof(buf_cfg)))
> > + r = -EFAULT;
> > + else
> > + r = cs_hsi_buf_config(csdata->hi, &buf_cfg);
>
> Sanity checking?
cs_hsi_buf_config() calls check_buf_params().
> > + break;
> > + }
> > + default:
> > + r = -ENOTTY;
> > + break;
> > + }
> > +
> > + return r;
> > +}
> > +
> > +static int cs_char_mmap(struct file *file, struct vm_area_struct *vma)
> > +{
> > + if (vma->vm_end < vma->vm_start)
> > + return -EINVAL;
> > +
> > + if (((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) != 1)
> > + return -EINVAL;
> > +
> > + vma->vm_flags |= VM_RESERVED;
> > + vma->vm_ops = &cs_char_vm_ops;
> > + vma->vm_private_data = file->private_data;
> > +
> > + return 0;
> > +}
> > +
> > +static int cs_char_open(struct inode *unused, struct file *file)
> > +{
> > + int ret = 0;
> > +
> > + spin_lock_bh(&cs_char_data.lock);
> > + if (cs_char_data.opened) {
> > + ret = -EBUSY;
> > + spin_unlock_bh(&cs_char_data.lock);
> > + goto out;
> > + }
> > + cs_char_data.mmap_base = get_zeroed_page(GFP_ATOMIC);
>
> This could be moved outside the locked sectionand use GFP_KERNEL.
Right, this is fixed by a follow up patch. I kept the patchset split
to keep authorship information. I guess I can squash the first three
patches, though.
> > + if (!cs_char_data.mmap_base) {
> > + dev_err(&cs_char_data.cl->device,
> > + "Shared memory allocation failed.\n");
> > + ret = -ENOMEM;
> > + spin_unlock_bh(&cs_char_data.lock);
> > + goto out;
> > + }
> > + cs_char_data.mmap_size = CS_MMAP_SIZE;
> > + cs_char_data.dataind_pending = 0;
> > + cs_char_data.opened = 1;
> > + file->private_data = &cs_char_data;
> > + spin_unlock_bh(&cs_char_data.lock);
> > +
> > + BUG_ON(cs_char_data.hi);
> > +
> > + ret = cs_hsi_start(&cs_char_data.hi, cs_char_data.cl,
> > + cs_char_data.mmap_base, cs_char_data.mmap_size);
> > + if (ret) {
> > + dev_err(&cs_char_data.cl->device, "Unable to initialize HSI\n");
> > + free_page(cs_char_data.mmap_base);
> > + goto out;
> > + }
> > +
> > +out:
> > + return ret;
> > +}
-- Sebastian
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* Re: [PATCH] capabilities: Ambient capability set V2
From: Christoph Lameter @ 2015-03-02 15:43 UTC (permalink / raw)
To: Serge E. Hallyn
Cc: Serge Hallyn, Andy Lutomirski, Jonathan Corbet, Aaron Jones,
linux-security-module, linux-kernel, akpm, Andrew G. Morgan,
Mimi Zohar, Austin S Hemmelgarn, Markku Savela, Jarkko Sakkinen,
linux-api, Michael Kerrisk
In-Reply-To: <20150301044407.GA14196@mail.hallyn.com>
On Sat, 28 Feb 2015, Serge E. Hallyn wrote:
> Your example program is not filling in pI though?
The setcap sets the inheritance bit. When the binary runs the i bits
should be set.
> Ah, i see why. In get_file_caps() you are still assigning
>
> fP = pA
>
> if the file has no file capabilities. so then you are actually
> doing
>
> pP' = (X & (fP | pA)) | (pI & (fI | pA))
> rather than
> pP' = (X & fP) | (pI & (fI | pA))
I thought that fP, fI and pI = {} since the file has no caps
so this comes out as
pP' = pA
> Other than that, the patch is looking good to me. We should
> consider emitting an audit record when a task fills in its
How do I do that?
> pA, and I do still wonder whether we should be requiring
> CAP_SETFCAP (unsure how best to think of it). But assuming the
> fP = pA was not intended, I think this largely does the right
> thing.
^ permalink raw reply
* Re: [PATCH v2 04/18] clocksource: Add ARM System timer driver
From: Maxime Coquelin @ 2015-03-02 16:53 UTC (permalink / raw)
To: Paul Bolle, Uwe Kleine-König
Cc: Andreas Färber, Geert Uytterhoeven, Rob Herring,
Philipp Zabel, Jonathan Corbet, Pawel Moll, Mark Rutland,
Ian Campbell, Kumar Gala, Russell King, Daniel Lezcano,
Thomas Gleixner, Linus Walleij, Greg Kroah-Hartman, Jiri Slaby,
Arnd Bergmann, Andrew Morton, David S. Miller,
Mauro Carvalho Chehab, Joe Perches, Antti Palosaari, Tejun Heo,
Will Deacon
In-Reply-To: <1424468908.24292.10.camel@x220>
Hi Paul, Uwe,
2015-02-20 22:48 GMT+01:00 Paul Bolle <pebolle@tiscali.nl>:
> On Fri, 2015-02-20 at 20:54 +0100, Uwe Kleine-König wrote:
>> On Fri, Feb 20, 2015 at 07:01:03PM +0100, Maxime Coquelin wrote:
>> > This patch adds clocksource support for ARMv7-M's System timer,
>> > also known as SysTick.
>> >
>> > Signed-off-by: Maxime Coquelin <mcoquelin.stm32@gmail.com>
>> > ---
>> > drivers/clocksource/Kconfig | 7 ++++
>> > drivers/clocksource/Makefile | 1 +
>> > drivers/clocksource/armv7m_systick.c | 78 ++++++++++++++++++++++++++++++++++++
>> > 3 files changed, 86 insertions(+)
>> > create mode 100644 drivers/clocksource/armv7m_systick.c
>> >
>> > diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
>> > index fc01ec2..fb6011e 100644
>> > --- a/drivers/clocksource/Kconfig
>> > +++ b/drivers/clocksource/Kconfig
>> > @@ -124,6 +124,13 @@ config CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
>> > help
>> > Use ARM global timer clock source as sched_clock
>> >
>> > +config ARMV7M_SYSTICK
>> > + bool
>> I assume this symbol is enabled later in the series.
>
> Yes, I noticed it was selected in 14/18 ("ARM: Add STM32 family
> machine").
>
>> Would it make sense
>> to allow enabing the symbol for compile test coverage?
>>
>> > + select CLKSRC_OF if OF
>> What happens if ARMV7M_SYSTICK=y but OF=n? Doesn't the driver fail to
>> compile?
>>
>> > + select CLKSRC_MMIO
>> > + help
>> > + This options enables support for the ARMv7M system timer unit
>> the right spelling is ARMv7-M.
>
> This Kconfig entry has no prompt, so no one is going to see this text
> during make *config. Perhaps this should be made a comment. In that case
> the right spelling should still be used.
Yes, you are right.
Do you agree if I define it like this:
config ARMV7M_SYSTICK
bool "Clocksource driver for ARMv7-M System timer"
depends on OF && (CPU_V7M || COMPILE_TEST)
select CLKSRC_OF
select CLKSRC_MMIO
help
This options enables clocksource support for the ARMv7-M system
timer unit.
Thanks,
Maxime
>
> Thanks,
>
>
> Paul Bolle
>
^ permalink raw reply
* Re: [PATCH v5 tip 1/7] bpf: make internal bpf API independent of CONFIG_BPF_SYSCALL ifdefs
From: Alexei Starovoitov @ 2015-03-02 16:58 UTC (permalink / raw)
To: Daniel Borkmann
Cc: Masami Hiramatsu, Ingo Molnar, Steven Rostedt, Namhyung Kim,
Arnaldo Carvalho de Melo, Jiri Olsa, David S. Miller,
Peter Zijlstra, Linux API, Network Development, LKML
On Mon, Mar 2, 2015 at 4:26 AM, Daniel Borkmann <daniel@iogearbox.net> wrote:
> On 03/02/2015 12:51 PM, Masami Hiramatsu wrote:
>> (2015/03/02 20:10), Daniel Borkmann wrote:
>>>
>>> Well, currently all possible map types (hash table, array map) that
>>> would actually call into bpf_register_map_type() are only built when
>>> CONFIG_BPF_SYSCALL is enabled (see kernel/bpf/Makefile). I don't think
>>> new map additions should be added that are not under kernel/bpf/ and/or
>>> enabled outside the CONFIG_BPF_SYSCALL, as it should be considered
>>> part of the eBPF core code.
agree. New map types will be only under kernel/bpf/
since this is really core infra that every component should be
able to share.
>>> The difference here (this patch) is simply that we don't want users to
>>> build ifdef spaghetti constructs in user code, so the API that is
>>> actually used by eBPF _users_ is being properly ifdef'ed in the headers.
+1
>> Or, maybe we'd better move them into new include/linux/bpf_prog.h which
>> includes basic include/linux/bpf.h. Then, user can include the bpf_prog.h
>> instead of bpf.h. Also, we can check CONFIG_BPF_SYSCAL=y at the top of
>> bpf_prog.h. This makes things clearer :)
>
> I'm preferring the 1st variant, though. We have currently two native eBPF
> users, that is, socket filters and tc's cls_bpf (queued in net-next) and
> looking at the code/API usage, it's really not that hard, where it would
> justify to move this to an extra header file, really.
agree. new header seems overkill to fix something
that is not an issue today.
^ permalink raw reply
* [PATCH v4 1/5] vfio: implement iommu driver capabilities with an enum
From: Baptiste Reynal @ 2015-03-02 16:58 UTC (permalink / raw)
To: iommu, kvmarm
Cc: open list:VFIO DRIVER, open list:ABI/API, open list,
Alex Williamson, tech
In-Reply-To: <1425315507-29661-1-git-send-email-b.reynal@virtualopensystems.com>
From: Antonios Motakis <a.motakis@virtualopensystems.com>
Currently a VFIO driver's IOMMU capabilities are encoded as a series of
numerical defines. Replace this with an enum for future maintainability.
Signed-off-by: Antonios Motakis <a.motakis@virtualopensystems.com>
Signed-off-by: Baptiste Reynal <b.reynal@virtualopensystems.com>
---
include/uapi/linux/vfio.h | 24 +++++++++++-------------
1 file changed, 11 insertions(+), 13 deletions(-)
diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
index 82889c3..5fb3d46 100644
--- a/include/uapi/linux/vfio.h
+++ b/include/uapi/linux/vfio.h
@@ -19,22 +19,20 @@
/* Kernel & User level defines for VFIO IOCTLs. */
-/* Extensions */
-
-#define VFIO_TYPE1_IOMMU 1
-#define VFIO_SPAPR_TCE_IOMMU 2
-#define VFIO_TYPE1v2_IOMMU 3
/*
- * IOMMU enforces DMA cache coherence (ex. PCIe NoSnoop stripping). This
- * capability is subject to change as groups are added or removed.
+ * Capabilities exposed by the VFIO IOMMU driver. Some capabilities are subject
+ * to change as groups are added or removed.
*/
-#define VFIO_DMA_CC_IOMMU 4
-
-/* Check if EEH is supported */
-#define VFIO_EEH 5
+enum vfio_iommu_cap {
+ VFIO_TYPE1_IOMMU = 1,
+ VFIO_SPAPR_TCE_IOMMU = 2,
+ VFIO_TYPE1v2_IOMMU = 3,
+ VFIO_DMA_CC_IOMMU = 4, /* IOMMU enforces DMA cache coherence
+ (ex. PCIe NoSnoop stripping) */
+ VFIO_EEH = 5, /* Check if EEH is supported */
+ VFIO_TYPE1_NESTING_IOMMU = 6, /* Two-stage IOMMU, implies v2 */
+};
-/* Two-stage IOMMU */
-#define VFIO_TYPE1_NESTING_IOMMU 6 /* Implies v2 */
/*
* The IOCTL interface is designed for extensibility by embedding the
--
2.3.1
^ permalink raw reply related
* [PATCH v4 2/5] vfio: introduce the VFIO_DMA_MAP_FLAG_NOEXEC flag
From: Baptiste Reynal @ 2015-03-02 16:58 UTC (permalink / raw)
To: iommu, kvmarm
Cc: open list:VFIO DRIVER, open list:ABI/API, open list,
Alex Williamson, tech
In-Reply-To: <1425315507-29661-1-git-send-email-b.reynal@virtualopensystems.com>
From: Antonios Motakis <a.motakis@virtualopensystems.com>
We introduce the VFIO_DMA_MAP_FLAG_NOEXEC flag to the VFIO dma map call,
and expose its availability via the capability VFIO_DMA_NOEXEC_IOMMU.
This way the user can control whether the XN flag will be set on the
requested mappings. The IOMMU_NOEXEC flag needs to be available for all
the IOMMUs of the container used.
Signed-off-by: Antonios Motakis <a.motakis@virtualopensystems.com>
Signed-off-by: Baptiste Reynal <b.reynal@virtualopensystems.com>
---
include/uapi/linux/vfio.h | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
index 5fb3d46..30801a7 100644
--- a/include/uapi/linux/vfio.h
+++ b/include/uapi/linux/vfio.h
@@ -31,6 +31,7 @@ enum vfio_iommu_cap {
(ex. PCIe NoSnoop stripping) */
VFIO_EEH = 5, /* Check if EEH is supported */
VFIO_TYPE1_NESTING_IOMMU = 6, /* Two-stage IOMMU, implies v2 */
+ VFIO_DMA_NOEXEC_IOMMU = 7,
};
@@ -397,12 +398,17 @@ struct vfio_iommu_type1_info {
*
* Map process virtual addresses to IO virtual addresses using the
* provided struct vfio_dma_map. Caller sets argsz. READ &/ WRITE required.
+ *
+ * To use the VFIO_DMA_MAP_FLAG_NOEXEC flag, the container must support the
+ * VFIO_DMA_NOEXEC_IOMMU capability. If mappings are created using this flag,
+ * any groups subsequently added to the container must support this capability.
*/
struct vfio_iommu_type1_dma_map {
__u32 argsz;
__u32 flags;
#define VFIO_DMA_MAP_FLAG_READ (1 << 0) /* readable from device */
#define VFIO_DMA_MAP_FLAG_WRITE (1 << 1) /* writable from device */
+#define VFIO_DMA_MAP_FLAG_NOEXEC (1 << 2) /* not executable from device */
__u64 vaddr; /* Process virtual address */
__u64 iova; /* IO virtual address */
__u64 size; /* Size of mapping (bytes) */
--
2.3.1
^ permalink raw reply related
* [PATCH v14 02/20] vfio: platform: probe to devices on the platform bus
From: Baptiste Reynal @ 2015-03-02 16:59 UTC (permalink / raw)
To: iommu, kvmarm
Cc: open list:VFIO DRIVER, open list:ABI/API, open list,
Alex Williamson, tech
In-Reply-To: <1425315600-29761-1-git-send-email-b.reynal@virtualopensystems.com>
From: Antonios Motakis <a.motakis@virtualopensystems.com>
Driver to bind to Linux platform devices, and callbacks to discover their
resources to be used by the main VFIO PLATFORM code.
Signed-off-by: Antonios Motakis <a.motakis@virtualopensystems.com>
Signed-off-by: Baptiste Reynal <b.reynal@virtualopensystems.com>
---
drivers/vfio/platform/vfio_platform.c | 103 ++++++++++++++++++++++++++++++++++
include/uapi/linux/vfio.h | 1 +
2 files changed, 104 insertions(+)
create mode 100644 drivers/vfio/platform/vfio_platform.c
diff --git a/drivers/vfio/platform/vfio_platform.c b/drivers/vfio/platform/vfio_platform.c
new file mode 100644
index 0000000..cef645c
--- /dev/null
+++ b/drivers/vfio/platform/vfio_platform.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2013 - Virtual Open Systems
+ * Author: Antonios Motakis <a.motakis@virtualopensystems.com>
+ *
+ * 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
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/vfio.h>
+#include <linux/platform_device.h>
+
+#include "vfio_platform_private.h"
+
+#define DRIVER_VERSION "0.10"
+#define DRIVER_AUTHOR "Antonios Motakis <a.motakis@virtualopensystems.com>"
+#define DRIVER_DESC "VFIO for platform devices - User Level meta-driver"
+
+/* probing devices from the linux platform bus */
+
+static struct resource *get_platform_resource(struct vfio_platform_device *vdev,
+ int num)
+{
+ struct platform_device *dev = (struct platform_device *) vdev->opaque;
+ int i;
+
+ for (i = 0; i < dev->num_resources; i++) {
+ struct resource *r = &dev->resource[i];
+
+ if (resource_type(r) & (IORESOURCE_MEM|IORESOURCE_IO)) {
+ if (!num)
+ return r;
+
+ num--;
+ }
+ }
+ return NULL;
+}
+
+static int get_platform_irq(struct vfio_platform_device *vdev, int i)
+{
+ struct platform_device *pdev = (struct platform_device *) vdev->opaque;
+
+ return platform_get_irq(pdev, i);
+}
+
+static int vfio_platform_probe(struct platform_device *pdev)
+{
+ struct vfio_platform_device *vdev;
+ int ret;
+
+ vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
+ if (!vdev)
+ return -ENOMEM;
+
+ vdev->opaque = (void *) pdev;
+ vdev->name = pdev->name;
+ vdev->flags = VFIO_DEVICE_FLAGS_PLATFORM;
+ vdev->get_resource = get_platform_resource;
+ vdev->get_irq = get_platform_irq;
+
+ ret = vfio_platform_probe_common(vdev, &pdev->dev);
+ if (ret)
+ kfree(vdev);
+
+ return ret;
+}
+
+static int vfio_platform_remove(struct platform_device *pdev)
+{
+ struct vfio_platform_device *vdev;
+
+ vdev = vfio_platform_remove_common(&pdev->dev);
+ if (vdev) {
+ kfree(vdev);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static struct platform_driver vfio_platform_driver = {
+ .probe = vfio_platform_probe,
+ .remove = vfio_platform_remove,
+ .driver = {
+ .name = "vfio-platform",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(vfio_platform_driver);
+
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
index 30801a7..e33b04b 100644
--- a/include/uapi/linux/vfio.h
+++ b/include/uapi/linux/vfio.h
@@ -159,6 +159,7 @@ struct vfio_device_info {
__u32 flags;
#define VFIO_DEVICE_FLAGS_RESET (1 << 0) /* Device supports reset */
#define VFIO_DEVICE_FLAGS_PCI (1 << 1) /* vfio-pci device */
+#define VFIO_DEVICE_FLAGS_PLATFORM (1 << 2) /* vfio-platform device */
__u32 num_regions; /* Max region index + 1 */
__u32 num_irqs; /* Max IRQ index + 1 */
};
--
2.3.1
^ permalink raw reply related
* [PATCH v14 04/20] vfio: amba: VFIO support for AMBA devices
From: Baptiste Reynal @ 2015-03-02 16:59 UTC (permalink / raw)
To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
kvmarm-FPEHb7Xf0XXUo1n7N8X6UoWGPAHP3yOg
Cc: open list:VFIO DRIVER, open list:ABI/API, open list,
Antonios Motakis, tech-lrHrjnjw1UfHK3s98zE1ajGjJy/sRE9J
In-Reply-To: <1425315600-29761-1-git-send-email-b.reynal-lrHrjnjw1UfHK3s98zE1ajGjJy/sRE9J@public.gmane.org>
From: Antonios Motakis <a.motakis-lrHrjnjw1UfHK3s98zE1ajGjJy/sRE9J@public.gmane.org>
Add support for discovering AMBA devices with VFIO and handle them
similarly to Linux platform devices.
Signed-off-by: Antonios Motakis <a.motakis-lrHrjnjw1UfHK3s98zE1ajGjJy/sRE9J@public.gmane.org>
Signed-off-by: Baptiste Reynal <b.reynal-lrHrjnjw1UfHK3s98zE1ajGjJy/sRE9J@public.gmane.org>
---
drivers/vfio/platform/vfio_amba.c | 115 ++++++++++++++++++++++++++++++++++++++
include/uapi/linux/vfio.h | 1 +
2 files changed, 116 insertions(+)
create mode 100644 drivers/vfio/platform/vfio_amba.c
diff --git a/drivers/vfio/platform/vfio_amba.c b/drivers/vfio/platform/vfio_amba.c
new file mode 100644
index 0000000..ff0331f
--- /dev/null
+++ b/drivers/vfio/platform/vfio_amba.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2013 - Virtual Open Systems
+ * Author: Antonios Motakis <a.motakis-lrHrjnjw1UfHK3s98zE1ajGjJy/sRE9J@public.gmane.org>
+ *
+ * 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
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/vfio.h>
+#include <linux/amba/bus.h>
+
+#include "vfio_platform_private.h"
+
+#define DRIVER_VERSION "0.10"
+#define DRIVER_AUTHOR "Antonios Motakis <a.motakis-lrHrjnjw1UfHK3s98zE1ajGjJy/sRE9J@public.gmane.org>"
+#define DRIVER_DESC "VFIO for AMBA devices - User Level meta-driver"
+
+/* probing devices from the AMBA bus */
+
+static struct resource *get_amba_resource(struct vfio_platform_device *vdev,
+ int i)
+{
+ struct amba_device *adev = (struct amba_device *) vdev->opaque;
+
+ if (i == 0)
+ return &adev->res;
+
+ return NULL;
+}
+
+static int get_amba_irq(struct vfio_platform_device *vdev, int i)
+{
+ struct amba_device *adev = (struct amba_device *) vdev->opaque;
+ int ret = 0;
+
+ if (i < AMBA_NR_IRQS)
+ ret = adev->irq[i];
+
+ /* zero is an unset IRQ for AMBA devices */
+ return ret ? ret : -ENXIO;
+}
+
+static int vfio_amba_probe(struct amba_device *adev, const struct amba_id *id)
+{
+ struct vfio_platform_device *vdev;
+ int ret;
+
+ vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
+ if (!vdev)
+ return -ENOMEM;
+
+ vdev->name = kasprintf(GFP_KERNEL, "vfio-amba-%08x", adev->periphid);
+ if (!vdev->name) {
+ kfree(vdev);
+ return -ENOMEM;
+ }
+
+ vdev->opaque = (void *) adev;
+ vdev->flags = VFIO_DEVICE_FLAGS_AMBA;
+ vdev->get_resource = get_amba_resource;
+ vdev->get_irq = get_amba_irq;
+
+ ret = vfio_platform_probe_common(vdev, &adev->dev);
+ if (ret) {
+ kfree(vdev->name);
+ kfree(vdev);
+ }
+
+ return ret;
+}
+
+static int vfio_amba_remove(struct amba_device *adev)
+{
+ struct vfio_platform_device *vdev;
+
+ vdev = vfio_platform_remove_common(&adev->dev);
+ if (vdev) {
+ kfree(vdev->name);
+ kfree(vdev);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static struct amba_id pl330_ids[] = {
+ { 0, 0 },
+};
+
+MODULE_DEVICE_TABLE(amba, pl330_ids);
+
+static struct amba_driver vfio_amba_driver = {
+ .probe = vfio_amba_probe,
+ .remove = vfio_amba_remove,
+ .id_table = pl330_ids,
+ .drv = {
+ .name = "vfio-amba",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_amba_driver(vfio_amba_driver);
+
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
index e33b04b..da07c1a 100644
--- a/include/uapi/linux/vfio.h
+++ b/include/uapi/linux/vfio.h
@@ -160,6 +160,7 @@ struct vfio_device_info {
#define VFIO_DEVICE_FLAGS_RESET (1 << 0) /* Device supports reset */
#define VFIO_DEVICE_FLAGS_PCI (1 << 1) /* vfio-pci device */
#define VFIO_DEVICE_FLAGS_PLATFORM (1 << 2) /* vfio-platform device */
+#define VFIO_DEVICE_FLAGS_AMBA (1 << 3) /* vfio-amba device */
__u32 num_regions; /* Max region index + 1 */
__u32 num_irqs; /* Max IRQ index + 1 */
};
--
2.3.1
^ permalink raw reply related
* Re: [PATCH v2 16/18] ARM: dts: Introduce STM32F429 MCU
From: Andreas Färber @ 2015-03-02 17:42 UTC (permalink / raw)
To: Maxime Coquelin, u.kleine-koenig-bIcnvbaLZ9MEGnE8C9+IrQ,
geert-Td1EMuHUCqxL1ZNQvxDV9g, Rob Herring, Philipp Zabel,
Jonathan Corbet, Pawel Moll, Mark Rutland, Ian Campbell,
Kumar Gala, Russell King, Daniel Lezcano, Thomas Gleixner,
Linus Walleij, Greg Kroah-Hartman, Jiri Slaby, Arnd Bergmann,
Andrew Morton, David S. Miller, Mauro Carvalho Chehab,
Joe Perches, Antti Palosaari, Tejun Heo,
Will Deacon <will.deacon>
In-Reply-To: <1424455277-29983-17-git-send-email-mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 14096 bytes --]
Hi Maxime,
Please don't put the whole world in To, that makes replying to you much
harder. You can put maintainers in CC instead.
Am 20.02.2015 um 19:01 schrieb Maxime Coquelin:
> The STMicrolectornics's STM32F419 MCU has the following main features:
> - Cortex-M4 core running up to @180MHz
> - 2MB internal flash, 256KBytes internal RAM
> - FMC controller to connect SDRAM, NOR and NAND memories
> - SD/MMC/SDIO support
> - Ethernet controller
> - USB OTFG FS & HS controllers
> - I2C, SPI, CAN busses support
> - Several 16 & 32 bits general purpose timers
> - Serial Audio interface
> - LCD controller
>
> Signed-off-by: Maxime Coquelin <mcoquelin.stm32-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> ---
> arch/arm/boot/dts/Makefile | 1 +
> arch/arm/boot/dts/stm32f429-disco.dts | 41 ++++
> arch/arm/boot/dts/stm32f429.dtsi | 396 ++++++++++++++++++++++++++++++++++
> 3 files changed, 438 insertions(+)
> create mode 100644 arch/arm/boot/dts/stm32f429-disco.dts
> create mode 100644 arch/arm/boot/dts/stm32f429.dtsi
>
> diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
> index 91bd5bd..d7da0ef 100644
> --- a/arch/arm/boot/dts/Makefile
> +++ b/arch/arm/boot/dts/Makefile
> @@ -442,6 +442,7 @@ dtb-$(CONFIG_ARCH_STI)+= stih407-b2120.dtb \
> stih416-b2000.dtb \
> stih416-b2020.dtb \
> stih416-b2020e.dtb
> +dtb-$(CONFIG_ARCH_STM32)+= stm32f429-disco.dtb
> dtb-$(CONFIG_MACH_SUN4I) += \
> sun4i-a10-a1000.dtb \
> sun4i-a10-ba10-tvbox.dtb \
> diff --git a/arch/arm/boot/dts/stm32f429-disco.dts b/arch/arm/boot/dts/stm32f429-disco.dts
> new file mode 100644
> index 0000000..0e79cc1
> --- /dev/null
> +++ b/arch/arm/boot/dts/stm32f429-disco.dts
> @@ -0,0 +1,41 @@
Add a suitable license header here? There had been attempts to
dual-license as GPL and MIT/X11.
> +/dts-v1/;
> +#include "stm32f429.dtsi"
> +
> +/ {
> + model = "STMicroelectronics's STM32F429i-DISCO board";
"'s" seems uncommon here and "s's" looks wrong. Just use
"STMicroelectronics STM32F429I-DISCO board"?
> + compatible = "st,stm32f429i-disco", "st,stm32f429";
> +
> + chosen {
> + bootargs = "console=ttyS0,115200 root=/dev/ram rdinit=/linuxrc";
> + linux,stdout-path = &usart1;
I have actually been using USART3, following a guide I found on GitHub.
Which pins do you use for USART1, and is one better than the other?
> + };
> +
> + memory {
> + reg = <0xd0000000 0x800000>;
I have it at 0x90000000!
> + };
> +
> + aliases {
> + ttyS0 = &usart1;
Why ttyS0 here? Shouldn't that be serial0 by convention?
> + };
> +
> + soc {
> + usart1: usart@40011000 {
> + status = "okay";
> + };
This is a new target, so please use the new-style &usart1 {...};
reference rather than replicating the hierarchy.
> +
> + leds {
These LEDs are definitely not on the SoC, they're on the board. Please
move one level up.
> + compatible = "gpio-leds";
In this file you're being parsimonious with newline, yet in the .dtsi
you unnecessarily add newlines before the trailing status property.
> + red {
> + #gpio-cells = <2>;
This looks weird. Drop it?
> + label = "Front Panel LED";
"Front Panel"? Both LEDs are on the front, and several other
architectures avoid spaces in the label for accessing it from /sys.
> + gpios = <&gpiog 14 0>;
GPIO_ACTIVE_HIGH
> + linux,default-trigger = "heartbeat";
Suggest to leave both off by default.
> + };
> + green {
> + #gpio-cells = <2>;
Ditto.
> + gpios = <&gpiog 13 0>;
Ditto.
> + default-state = "off";
> + };
> + };
> + };
> +};
> diff --git a/arch/arm/boot/dts/stm32f429.dtsi b/arch/arm/boot/dts/stm32f429.dtsi
> new file mode 100644
> index 0000000..5b3442a
> --- /dev/null
> +++ b/arch/arm/boot/dts/stm32f429.dtsi
> @@ -0,0 +1,396 @@
> +/*
> + * Device tree for STM32F429
License?
> + */
> +#include "armv7-m.dtsi"
> +#include <dt-bindings/pinctrl/pinctrl-stm32.h>
> +#include <dt-bindings/reset/st,stm32f429.h>
> +
> +/ {
> +
> + aliases {
> + gpio0 = &gpioa;
> + gpio1 = &gpiob;
> + gpio2 = &gpioc;
> + gpio3 = &gpiod;
> + gpio4 = &gpioe;
> + gpio5 = &gpiof;
> + gpio6 = &gpiog;
> + gpio7 = &gpioh;
> + gpio8 = &gpioi;
> + gpio9 = &gpioj;
> + gpio10 = &gpiok;
> + };
> +
> + clocks {
> + clk_sysclk: clk-sysclk {
> + #clock-cells = <0>;
> + compatible = "fixed-clock";
> + clock-frequency = <180000000>;
> + };
> +
> + clk_hclk: clk-hclk {
> + #clock-cells = <0>;
> + compatible = "fixed-clock";
> + clock-frequency = <180000000>;
> + };
> +
> + clk_pclk1: clk-pclk1 {
> + #clock-cells = <0>;
> + compatible = "fixed-clock";
> + clock-frequency = <45000000>;
> + };
> +
> + clk_pclk2: clk-pclk2 {
> + #clock-cells = <0>;
> + compatible = "fixed-clock";
> + clock-frequency = <90000000>;
> + };
> +
> + clk_pmtr1: clk-pmtr1 {
> + #clock-cells = <0>;
> + compatible = "fixed-clock";
> + clock-frequency = <90000000>;
> + };
> +
> + clk_pmtr2: clk-pmtr2 {
> + #clock-cells = <0>;
> + compatible = "fixed-clock";
> + clock-frequency = <180000000>;
> + };
> +
> + clk_systick: clk-systick {
> + compatible = "fixed-factor-clock";
> + clocks = <&clk_hclk>;
> + #clock-cells = <0>;
> + clock-div = <8>;
> + clock-mult = <1>;
> + };
Most of these should be replaceable with my clk driver.
> + };
> +
> + systick: timer@e000e010 {
> + clocks = <&clk_systick>;
> +
> + status = "okay";
> + };
&systick {...};
> +
> + soc {
> + reset: reset@40023810 {
> + #reset-cells = <1>;
> + compatible = "st,stm32-reset";
> + reg = <0x40023810 0x18>;
> + };
Still, this feels wrong, given that it's an RCC IP block...
> +
> + pin-controller {
> + #address-cells = <1>;
> + #size-cells = <1>;
> + compatible = "st,stm32-pinctrl";
> + ranges = <0 0x40020000 0x3000>;
> +
> + gpioa: gpio@40020000 {
> + gpio-controller;
> + #gpio-cells = <2>;
> + reg = <0x0 0x400>;
> + resets = <&reset GPIOA_RESET>;
> + st,bank-name = "GPIOA";
> + };
> +
> + gpiob: gpio@40020400 {
> + gpio-controller;
> + #gpio-cells = <2>;
> + reg = <0x400 0x400>;
> + resets = <&reset GPIOB_RESET>;
> + st,bank-name = "GPIOB";
> + };
> +
> + gpioc: gpio@40020800 {
> + gpio-controller;
> + #gpio-cells = <2>;
> + reg = <0x800 0x400>;
> + resets = <&reset GPIOC_RESET>;
> + st,bank-name = "GPIOC";
> + };
> +
> + gpiod: gpio@40020c00 {
> + gpio-controller;
> + #gpio-cells = <2>;
> + reg = <0xc00 0x400>;
> + resets = <&reset GPIOD_RESET>;
> + st,bank-name = "GPIOD";
> + };
> +
> + gpioe: gpio@40021000 {
> + gpio-controller;
> + #gpio-cells = <2>;
> + reg = <0x1000 0x400>;
> + resets = <&reset GPIOE_RESET>;
> + st,bank-name = "GPIOE";
> + };
> +
> + gpiof: gpio@40021400 {
> + gpio-controller;
> + #gpio-cells = <2>;
> + reg = <0x1400 0x400>;
> + resets = <&reset GPIOF_RESET>;
> + st,bank-name = "GPIOF";
> + };
> +
> + gpiog: gpio@40021800 {
> + gpio-controller;
> + #gpio-cells = <2>;
> + reg = <0x1800 0x400>;
> + resets = <&reset GPIOG_RESET>;
> + st,bank-name = "GPIOG";
> + };
> +
> + gpioh: gpio@40021c00 {
> + gpio-controller;
> + #gpio-cells = <2>;
> + reg = <0x1c00 0x400>;
> + resets = <&reset GPIOH_RESET>;
> + st,bank-name = "GPIOH";
> + };
> +
> + gpioi: gpio@40022000 {
> + gpio-controller;
> + #gpio-cells = <2>;
> + reg = <0x2000 0x400>;
> + resets = <&reset GPIOI_RESET>;
> + st,bank-name = "GPIOI";
> + };
> +
> + gpioj: gpio@40022400 {
> + gpio-controller;
> + #gpio-cells = <2>;
> + reg = <0x2400 0x400>;
> + resets = <&reset GPIOJ_RESET>;
> + st,bank-name = "GPIOJ";
> + };
> +
> + gpiok: gpio@40022800 {
> + gpio-controller;
> + #gpio-cells = <2>;
> + reg = <0x2800 0x400>;
> + resets = <&reset GPIOK_RESET>;
> + st,bank-name = "GPIOK";
> + };
> +
> + usart1 {
> + pinctrl_usart1: usart1-0 {
> + st,pins {
> + tx = <&gpioa 9 ALT7 NO_PULL PUSH_PULL LOW_SPEED>;
> + rx = <&gpioa 10 ALT7 NO_PULL>;
> + };
> + };
> + };
> +
> + usart2 {
> + pinctrl_usart2: usart2-0 {
> + st,pins {
> + tx = <&gpioa 2 ALT7 NO_PULL PUSH_PULL LOW_SPEED>;
> + rx = <&gpioa 3 ALT7 NO_PULL>;
> + };
> + };
> + };
> +
> + usart3 {
> + pinctrl_usart3: usart3-0 {
> + st,pins {
> + tx = <&gpiob 10 ALT7 NO_PULL PUSH_PULL LOW_SPEED>;
> + rx = <&gpiob 11 ALT7 NO_PULL>;
> + };
> + };
> + };
> +
> + usart4 {
> + pinctrl_usart4: usart4-0 {
> + st,pins {
> + tx = <&gpioa 0 ALT8 NO_PULL PUSH_PULL LOW_SPEED>;
> + rx = <&gpioa 1 ALT8 NO_PULL>;
> + };
> + };
> + };
> +
> + usart5 {
> + pinctrl_usart5: usart5-0 {
> + st,pins {
> + tx = <&gpioc 12 ALT8 NO_PULL PUSH_PULL LOW_SPEED>;
> + rx = <&gpiod 2 ALT8 NO_PULL>;
> + };
> + };
> + };
> +
> + usart6 {
> + pinctrl_usart6: usart6-0 {
> + st,pins {
> + tx = <&gpioc 6 ALT8 NO_PULL PUSH_PULL LOW_SPEED>;
> + rx = <&gpioc 7 ALT8 NO_PULL>;
> + };
> + };
> + };
> +
> + usart7 {
> + pinctrl_usart7: usart7-0 {
> + st,pins {
> + tx = <&gpioe 8 ALT8 NO_PULL PUSH_PULL LOW_SPEED>;
> + rx = <&gpioe 7 ALT8 NO_PULL>;
> + };
> + };
> + };
> +
> + usart8 {
> + pinctrl_usart8: usart8-0 {
> + st,pins {
> + tx = <&gpioe 1 ALT8 NO_PULL PUSH_PULL LOW_SPEED>;
> + rx = <&gpioe 0 ALT8 NO_PULL>;
> + };
> + };
> + };
Can't the outer level be avoided here to save space and indentation?
> + };
> +
> + timer2: timer@40000000 {
> + compatible = "st,stm32-timer";
> + reg = <0x40000000 0x400>;
> + interrupts = <28>;
> + resets = <&reset TIM2_RESET>;
> + clocks = <&clk_pmtr1>;
> +
> + status = "disabled";
> + };
> +
> + timer3: timer@40000400 {
> + compatible = "st,stm32-timer";
> + reg = <0x40000400 0x400>;
> + interrupts = <29>;
> + resets = <&reset TIM3_RESET>;
> + clocks = <&clk_pmtr1>;
> +
> + status = "disabled";
> + };
> +
> + timer4: timer@40000800 {
> + compatible = "st,stm32-timer";
> + reg = <0x40000800 0x400>;
> + interrupts = <30>;
> + resets = <&reset TIM4_RESET>;
> + clocks = <&clk_pmtr1>;
> +
> + status = "disabled";
> + };
> +
> + timer5: timer@40000c00 {
> + compatible = "st,stm32-timer";
> + reg = <0x40000c00 0x400>;
> + interrupts = <50>;
> + resets = <&reset TIM5_RESET>;
> + clocks = <&clk_pmtr1>;
> + };
> +
> + timer6: timer@40001000 {
> + compatible = "st,stm32-timer";
> + reg = <0x40001000 0x400>;
> + interrupts = <54>;
> + resets = <&reset TIM6_RESET>;
> + clocks = <&clk_pmtr1>;
> +
> + status = "disabled";
> + };
> +
> + timer7: timer@40001400 {
> + compatible = "st,stm32-timer";
> + reg = <0x40001400 0x400>;
> + interrupts = <55>;
> + resets = <&reset TIM7_RESET>;
> + clocks = <&clk_pmtr1>;
> +
> + status = "disabled";
> + };
> +
> + usart1: usart@40011000 {
> + compatible = "st,stm32-usart";
> + reg = <0x40011000 0x400>;
> + interrupts = <37>;
> + clocks = <&clk_pclk2>;
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_usart1>;
> +
> + status = "disabled";
> + };
> +
> + usart2: usart@40004400 {
> + compatible = "st,stm32-usart";
> + reg = <0x40004400 0x400>;
> + interrupts = <38>;
> + clocks = <&clk_pclk1>;
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_usart1>;
Copy&paste, also below. Is this really .dtsi material?
> +
> + status = "disabled";
> + };
> +
> + usart3: usart@40004800 {
> + compatible = "st,stm32-usart";
> + reg = <0x40004800 0x400>;
> + interrupts = <39>;
> + clocks = <&clk_pclk1>;
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_usart1>;
> +
> + status = "disabled";
> + };
> +
> + usart4: usart@40004c00 {
> + compatible = "st,stm32-usart";
> + reg = <0x40004c00 0x400>;
> + interrupts = <52>;
> + clocks = <&clk_pclk1>;
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_usart1>;
> +
> + status = "disabled";
> + };
> +
> + usart5: usart@40005000 {
> + compatible = "st,stm32-usart";
> + reg = <0x40005000 0x400>;
> + interrupts = <53>;
> + clocks = <&clk_pclk1>;
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_usart1>;
> +
> + status = "disabled";
> + };
> +
> + usart6: usart@40011400 {
> + compatible = "st,stm32-usart";
> + reg = <0x40011400 0x400>;
> + interrupts = <71>;
> + clocks = <&clk_pclk2>;
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_usart1>;
> +
> + status = "disabled";
> + };
> +
> + usart7: usart@40007800 {
Please order all nodes by unit address, not by label.
> + compatible = "st,stm32-usart";
> + reg = <0x40007800 0x400>;
> + interrupts = <82>;
> + clocks = <&clk_pclk1>;
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_usart1>;
> +
> + status = "disabled";
> + };
> +
> + usart8: usart@40007c00 {
> + compatible = "st,stm32-usart";
> + reg = <0x40007c00 0x400>;
> + interrupts = <83>;
> + clocks = <&clk_pclk1>;
> + pinctrl-names = "default";
> + pinctrl-0 = <&pinctrl_usart1>;
> +
> + status = "disabled";
> + };
I remember two of them not being USART but UART? Similarly, two of them
support flow control (or two don't?), for which we would either need a
property or two different compatible strings.
> + };
> +};
Regards,
Andreas
--
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Felix Imendörffer, Jane Smithard, Jennifer Guild, Dilip Upmanyu,
Graham Norton; HRB 21284 (AG Nürnberg)
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* Re: [PATCH 0/9] N900 Modem Speech Support
From: Pali Rohár @ 2015-03-02 19:05 UTC (permalink / raw)
To: Sebastian Reichel
Cc: Peter Ujfalusi, Kai Vehmanen, Pavel Machek, Aaro Koskinen,
Ivaylo Dimitrov, linux-omap, linux-kernel, linux-api
In-Reply-To: <1425271139-24715-1-git-send-email-sre@kernel.org>
[-- Attachment #1: Type: Text/Plain, Size: 2195 bytes --]
On Monday 02 March 2015 05:38:50 Sebastian Reichel wrote:
> Hi,
>
> This patchset contains the missing speech data support for the
> Nokia N900 modem.
>
> Userland access goes via /dev/cmt_speech. The API is
> implemented in libcmtspeechdata, which is used by ofono and
> the freesmartphone.org project. Apart from that the device is
> also used by the phone binaries distributed with Maemo. So
> while this is a new userland ABI for the mainline kernel it
> has been tested in the wild for some years.
>
> Simple Testing of the API can be done by checking out
> libcmtspeechdata [0], building the test tool and executing
> it. The tool will loop back audio data received from the
> caller.
>
> I have prepared a kernel branch, which includes these changes
> at [1].
>
> [0] https://lkml.org/lkml/2015/2/11/526
> [1]
> git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-hsi.g
> it branch/cmt-speech
>
> -- Sebastian
>
> Kai Vehmanen (3):
> HSI: cmt_speech: Add cmt-speech driver
> HSI: cmt_speech: Avoid GFP_ATOMIC in cs_char_open
> HSI: cmt_speech: Return error if HSI port not configured
>
> Sebastian Reichel (6):
> HSI: cmt_speech: Fix build for 4.0 kernel
> HSI: cmt_speech: Cleanup initialisation
> HSI: cmt_speech: Rename driver to cmt-speech
> HSI: cmt_speech: Move cs-protocol.h to
> include/uapi/linux/hsi HSI: cmt_speech: Remove hardcoded
> channel numbers
> HSI: nokia-modem: Add cmt_speech support
>
> drivers/hsi/clients/Kconfig | 11 +-
> drivers/hsi/clients/Makefile | 1 +
> drivers/hsi/clients/cmt_speech.c | 1451
> ++++++++++++++++++++++++++++++++++
> drivers/hsi/clients/nokia-modem.c | 31 +-
> include/uapi/linux/hsi/Kbuild | 2 +-
> include/uapi/linux/hsi/cs-protocol.h | 113 +++
> 6 files changed, 1606 insertions(+), 3 deletions(-)
> create mode 100644 drivers/hsi/clients/cmt_speech.c
> create mode 100644 include/uapi/linux/hsi/cs-protocol.h
Hello, do you have also DT patches? Or no DT changes are needed?
Is this cmt_speech version one from linux-n900 git tree? or it is
new or modified?
--
Pali Rohár
pali.rohar@gmail.com
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply
* Re: [PATCH 0/9] N900 Modem Speech Support
From: Sebastian Reichel @ 2015-03-02 20:51 UTC (permalink / raw)
To: Pali Rohár
Cc: Peter Ujfalusi, Kai Vehmanen, Pavel Machek, Aaro Koskinen,
Ivaylo Dimitrov, linux-omap, linux-kernel, linux-api
In-Reply-To: <201503022005.31729@pali>
[-- Attachment #1: Type: text/plain, Size: 906 bytes --]
Hi,
On Mon, Mar 02, 2015 at 08:05:31PM +0100, Pali Rohár wrote:
> On Monday 02 March 2015 05:38:50 Sebastian Reichel wrote:
> > This patchset contains the missing speech data support for the
> > Nokia N900 modem.
> > [...]
>
> Hello, do you have also DT patches? Or no DT changes are needed?
No DT changes are needed. The DT already contains the n900-modem endpoint
(look for compatible = "nokia,n900-modem"), which is handled by
drivers/hsi/clients/nokia-modem.c.
The nokia-modem driver currently takes care of gpios, irqs, pinctrl
and loads ssi-protocol. After this patchset it also loads
cmt-speech.
> Is this cmt_speech version one from linux-n900 git tree? or it is
> new or modified?
The first 3 patches are from linux-n900 git tree, the other patches
are cleanups and fixups for mainline. Some of those are partly
available in the linux-n900 git tree.
-- Sebastian
[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]
^ permalink raw reply
* Re: [PATCH 1/9] HSI: cmt_speech: Add cmt-speech driver
From: Aaro Koskinen @ 2015-03-02 20:56 UTC (permalink / raw)
To: Sebastian Reichel
Cc: Peter Ujfalusi, Kai Vehmanen, Pavel Machek, Pali Rohar,
Ivaylo Dimitrov, linux-omap, linux-kernel, linux-api,
Kai Vehmanen, Carlos Chinea, Joni Lapilainen
In-Reply-To: <1425271139-24715-2-git-send-email-sre@kernel.org>
Hi,
On Mon, Mar 02, 2015 at 05:38:51AM +0100, Sebastian Reichel wrote:
> From: Kai Vehmanen <kai.vehmanen@nokia.com>
>
> Introduces the cmt-speech driver, which implements
> a character device interface for transferring speech
> data frames over HSI/SSI.
>
> The driver is used to exchange voice/speech data between
> the Nokia N900/N950/N9's modem and its cpu.
>
> Signed-off-by: Kai Vehmanen <kai.vehmanen@nokia.com>
> Signed-off-by: Carlos Chinea <carlos.chinea@nokia.com>
> Signed-off-by: Joni Lapilainen <joni.lapilainen@gmail.com>
> Signed-off-by: Sebastian Reichel <sre@kernel.org>
I think the initial mainline kernel submission for this driver should be
a single patch, so just squash all the cleanups and fixes into this one.
You can document the changes you have made by describing the changes
before your own Signed-off-by line.
A.
^ permalink raw reply
* Re: [GIT PULL] Kselftest updates for 3.20-rc1
From: Dave Jones @ 2015-03-02 21:19 UTC (permalink / raw)
To: Michael Ellerman
Cc: Shuah Khan, Linus Torvalds, linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1423538165.19657.8.camel-Gsx/Oe8HsFggBc27wqDAHg@public.gmane.org>
On Tue, Feb 10, 2015 at 02:16:05PM +1100, Michael Ellerman wrote:
> > On 02/09/2015 05:43 PM, Michael Ellerman wrote:
> > > On Mon, 2015-02-09 at 17:36 -0700, Shuah Khan wrote:
> > >> On 02/09/2015 05:30 PM, Michael Ellerman wrote:
> > >>> On Mon, 2015-02-09 at 11:36 -0700, Shuah Khan wrote:
> > >>>> Hi Linus,
> > >>>>
> > >>>> Please pull the following Kselftest updates for 3.20-rc1
> > >>>>
> > >>>> thanks,
> > >>>> -- Shuah
> > >>>>
> > >>> ...
> > >>>
> > >>> I don't understand why you insist on merging this series with the logic copied
> > >>> 18 times.
> > >>>
> > >>> I'm happy to tweak my series that uses an include file, but I don't see the
> > >>> point of merging this series first when almost every line will be removed when
> > >>> my series goes in.
> > >>
> > >> Please work on the suggestions I made and rework the patches
> > >> and resend. As I mentioned earlier, I want to enable this work
> > >> and them make improvements.
> > >
> > > Yes I would like install to work to. I'd also like it to work for the powerpc
> > > tests you ignored. But I don't want it to involve copying the same logic into
> > > every Makefile in the tree.
> >
> > > My series was sent over a month ago, with plenty of time for you to merge it
> > > instead of this cut-and-paste solution.
> >
> > I asked you to re-work the patches based on my suggestions
> > and resend. I didn't see any patches from you that addressed
> > the comments. I can't merge the patches you sent without
> > addressing the comments.
>
> Your comments were "please rebase on my series", and as I explained that is
> pointless because my series replaces your series.
Michael's series also has a bunch of features this pull doesn't.
I had started implementing some of these features myself before realizing
this stuff was in limbo. (Especially the ability to install to a
different directory: our use case involves packaging up the latest
selftests for use to be run against a long-term stable kernel).
What needs to happen to unblock this, given that nothing has been
merged so far.
Working on selftests is sort of frustrating with all this stuff pending
given the potential conflicts.
Dave
^ permalink raw reply
* Re: [GIT PULL] Kselftest updates for 3.20-rc1
From: Shuah Khan @ 2015-03-02 21:27 UTC (permalink / raw)
To: Dave Jones, Michael Ellerman, Linus Torvalds, linux-kernel,
linux-api
In-Reply-To: <20150302211947.GA2184@codemonkey.org.uk>
On 03/02/2015 02:19 PM, Dave Jones wrote:
> On Tue, Feb 10, 2015 at 02:16:05PM +1100, Michael Ellerman wrote:
>
> > > On 02/09/2015 05:43 PM, Michael Ellerman wrote:
> > > > On Mon, 2015-02-09 at 17:36 -0700, Shuah Khan wrote:
> > > >> On 02/09/2015 05:30 PM, Michael Ellerman wrote:
> > > >>> On Mon, 2015-02-09 at 11:36 -0700, Shuah Khan wrote:
> > > >>>> Hi Linus,
> > > >>>>
> > > >>>> Please pull the following Kselftest updates for 3.20-rc1
> > > >>>>
> > > >>>> thanks,
> > > >>>> -- Shuah
> > > >>>>
> > > >>> ...
> > > >>>
> > > >>> I don't understand why you insist on merging this series with the logic copied
> > > >>> 18 times.
> > > >>>
> > > >>> I'm happy to tweak my series that uses an include file, but I don't see the
> > > >>> point of merging this series first when almost every line will be removed when
> > > >>> my series goes in.
> > > >>
> > > >> Please work on the suggestions I made and rework the patches
> > > >> and resend. As I mentioned earlier, I want to enable this work
> > > >> and them make improvements.
> > > >
> > > > Yes I would like install to work to. I'd also like it to work for the powerpc
> > > > tests you ignored. But I don't want it to involve copying the same logic into
> > > > every Makefile in the tree.
> > >
> > > > My series was sent over a month ago, with plenty of time for you to merge it
> > > > instead of this cut-and-paste solution.
> > >
> > > I asked you to re-work the patches based on my suggestions
> > > and resend. I didn't see any patches from you that addressed
> > > the comments. I can't merge the patches you sent without
> > > addressing the comments.
> >
> > Your comments were "please rebase on my series", and as I explained that is
> > pointless because my series replaces your series.
>
> Michael's series also has a bunch of features this pull doesn't.
> I had started implementing some of these features myself before realizing
> this stuff was in limbo. (Especially the ability to install to a
> different directory: our use case involves packaging up the latest
> selftests for use to be run against a long-term stable kernel).
>
> What needs to happen to unblock this, given that nothing has been
> merged so far.
>
> Working on selftests is sort of frustrating with all this stuff pending
> given the potential conflicts.
>
Dave,
At the moment I am working on an approach that doesn't require
changes to Makefiles. This pull request being in limbo game me
a chance to regroup and come up with a simpler approach. Michael's
work is based on Makefile changes as well.
Please give me couple of days and I will send out patches that add
install, packaging support. I am handling this as tools at the top
level that don't depend on any existing Makefiles targets.
thanks,
-- Shuah
--
Shuah Khan
Sr. Linux Kernel Developer
Open Source Innovation Group
Samsung Research America (Silicon Valley)
shuahkh@osg.samsung.com | (970) 217-8978
^ permalink raw reply
* [PATCH] net: add SO_MAX_DGRAM_QLEN for AF_UNIX SOCK_DGRAM sockets
From: Christian Seiler @ 2015-03-03 0:32 UTC (permalink / raw)
To: netdev
Cc: Christian Seiler, Dan Ballard, Eric Dumazet, David S. Miller,
Hannes Frederic Sowa, linux-api
Allow applications to set their own value for the maximum length of the
receive queue of SOCK_DGRAM AF_UNIX sockets. The default remains the
current value of /proc/sys/net/unix/max_dgram_qlen, which is kept at a
initial value of 10.
Rationale: applications may want to control how many datagrams the
kernel buffers before senders are blocked. A prominent example would be
to create a socket for syslog early at boot but only consume messages
once enough of the system has been set up. The default queue length of
11 messages (= 10 + 1) is too low for this kind of application.
Details:
The value chosen by applications may at most be the limit defined by
the new sysctl max_dgram_qlen_limit. The limit defaults to 2047
(allowing 2048 datagrams to be queued). If the value specified exceeds
the limit, the limit will be used, so applications don't need to try to
guess what the limit is before trying to set it, in analogy to
SO_SNDBUF/SO_RCVBUF.
Also, in analogy to SO_SNDBUF/SO_RCVBUF, a SO_MAX_DGRAM_QLEN_FORCE
option is provided for privileged users to force a higher limit. As
with SO_SNDBUF/SO_RCVBUF, CAP_NET_ADMIN in the init_user_ns is required
for this.
The setsockopt/getsockopt implementations explicitly check to see if
the socket is a UNIX domain socket of type SOCK_DGRAM, otherwise both
will fail. This ensures that listen() for non-datagram sockets is not
broken, since the datagram receive code internally uses the
sk->sk_max_ack_backlog field.
This is inspired by a patch previously submitted to LKML:
<https://lkml.org/lkml/2014/1/22/256>
Cc: Dan Ballard <dan@mindstab.net>
Cc: Eric Dumazet <edumazet@google.com>
Cc: David S. Miller <davem@davemloft.net>
Cc: Hannes Frederic Sowa <hannes@stressinduktion.org>
Cc: linux-api@vger.kernel.org
Signed-off-by: Christian Seiler <christian@iwakd.de>
---
Addendum for the rationale: this has been on the wishlist of the
systemd developers for quite a while. If one wants to configure systemd
to forward log messages to syslog, the only way to do that reliably
now is to increase max_dgram_qlen globally.
I have hopefully addressed the issues brought up in the review of the
patch that inspired this change (arch-stuff, listen(), configurable
limit, unsigned short range check).
I only have access to x86. I've touched all of the corresponding arch
files where I could find other SO_ options, but this has only been
compiled and tested on x86_64.
checkpatch.pl gives me one error, i.e. that there are no spaces before
and after an equal sign in sysctl.h, but there I just followed the rest
of the code. The two warnings it shows me are lines longer than 80
characters; in sysctl_binary.c it follows the rest of the code and in
sock.c I don't think I could make that more readable with less.
OPEN ISSUE: this is somewhat of a generic problem with network
namespaces: upon creation, the parameters are initialized by their
defaults, so each network namespace has the same initial parameters.
This means that for net_ns created within user_ns != init_user_ns,
where sysctls are not exported, the max_dgram_qlen{,_limit} settings
can't be changed at all and will always take the hard-coded default
values, which may or may not be desirable, depending on your
standpoint.
Documentation: this patch updates the documentation in Documentation/,
and I have also prepared a draft update to the man pages, should this
patch be accepted, pushed to github at:
<https://github.com/chris-se/linux-kernel-man-pages/commit/116ebc1e8a14ea0eaffd749c8d19e66c597dabc7>
Note that this is my first submission to the Linux kernel and since
this modfies a lot of arch-specific files, get_maintainer.pl was
decidedly unhelpful (unless I really should write to the maintainers of
every single arch?). If I should have added somebody else to Cc or sent
this somewhere else, please tell me.
Documentation/networking/ip-sysctl.txt | 6 +++++
arch/alpha/include/uapi/asm/socket.h | 3 +++
arch/avr32/include/uapi/asm/socket.h | 3 +++
arch/cris/include/uapi/asm/socket.h | 3 +++
arch/frv/include/uapi/asm/socket.h | 3 +++
arch/ia64/include/uapi/asm/socket.h | 3 +++
arch/m32r/include/uapi/asm/socket.h | 3 +++
arch/mips/include/uapi/asm/socket.h | 3 +++
arch/mn10300/include/uapi/asm/socket.h | 3 +++
arch/parisc/include/uapi/asm/socket.h | 3 +++
arch/powerpc/include/uapi/asm/socket.h | 3 +++
arch/s390/include/uapi/asm/socket.h | 3 +++
arch/sparc/include/uapi/asm/socket.h | 3 +++
arch/xtensa/include/uapi/asm/socket.h | 3 +++
include/net/netns/unix.h | 1 +
include/uapi/asm-generic/socket.h | 3 +++
include/uapi/linux/sysctl.h | 1 +
kernel/sysctl_binary.c | 1 +
net/core/sock.c | 49 ++++++++++++++++++++++++++++++++++
net/unix/af_unix.c | 1 +
net/unix/sysctl_net_unix.c | 41 ++++++++++++++++++++++++++++
21 files changed, 142 insertions(+)
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index 1b8c964..208132b 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -1794,6 +1794,12 @@ max_dgram_qlen - INTEGER
Default: 10
+max_dgram_qlen_limit - INTEGER
+ The maximum length a non-privileged user may set the dgram socket
+ receive queue to.
+
+ Default: 2047
+
UNDOCUMENTED:
diff --git a/arch/alpha/include/uapi/asm/socket.h b/arch/alpha/include/uapi/asm/socket.h
index 9a20821..20c5fa5 100644
--- a/arch/alpha/include/uapi/asm/socket.h
+++ b/arch/alpha/include/uapi/asm/socket.h
@@ -92,4 +92,7 @@
#define SO_ATTACH_BPF 50
#define SO_DETACH_BPF SO_DETACH_FILTER
+#define SO_MAX_DGRAM_QLEN 51
+#define SO_MAX_DGRAM_QLEN_FORCE 52
+
#endif /* _UAPI_ASM_SOCKET_H */
diff --git a/arch/avr32/include/uapi/asm/socket.h b/arch/avr32/include/uapi/asm/socket.h
index 2b65ed6..2a59ca2 100644
--- a/arch/avr32/include/uapi/asm/socket.h
+++ b/arch/avr32/include/uapi/asm/socket.h
@@ -85,4 +85,7 @@
#define SO_ATTACH_BPF 50
#define SO_DETACH_BPF SO_DETACH_FILTER
+#define SO_MAX_DGRAM_QLEN 51
+#define SO_MAX_DGRAM_QLEN_FORCE 52
+
#endif /* _UAPI__ASM_AVR32_SOCKET_H */
diff --git a/arch/cris/include/uapi/asm/socket.h b/arch/cris/include/uapi/asm/socket.h
index e2503d9f..b7a3b5d 100644
--- a/arch/cris/include/uapi/asm/socket.h
+++ b/arch/cris/include/uapi/asm/socket.h
@@ -87,6 +87,9 @@
#define SO_ATTACH_BPF 50
#define SO_DETACH_BPF SO_DETACH_FILTER
+#define SO_MAX_DGRAM_QLEN 51
+#define SO_MAX_DGRAM_QLEN_FORCE 52
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/frv/include/uapi/asm/socket.h b/arch/frv/include/uapi/asm/socket.h
index 4823ad1..f656613 100644
--- a/arch/frv/include/uapi/asm/socket.h
+++ b/arch/frv/include/uapi/asm/socket.h
@@ -85,5 +85,8 @@
#define SO_ATTACH_BPF 50
#define SO_DETACH_BPF SO_DETACH_FILTER
+#define SO_MAX_DGRAM_QLEN 51
+#define SO_MAX_DGRAM_QLEN_FORCE 52
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/ia64/include/uapi/asm/socket.h b/arch/ia64/include/uapi/asm/socket.h
index 59be3d8..dea5bf6 100644
--- a/arch/ia64/include/uapi/asm/socket.h
+++ b/arch/ia64/include/uapi/asm/socket.h
@@ -94,4 +94,7 @@
#define SO_ATTACH_BPF 50
#define SO_DETACH_BPF SO_DETACH_FILTER
+#define SO_MAX_DGRAM_QLEN 51
+#define SO_MAX_DGRAM_QLEN_FORCE 52
+
#endif /* _ASM_IA64_SOCKET_H */
diff --git a/arch/m32r/include/uapi/asm/socket.h b/arch/m32r/include/uapi/asm/socket.h
index 7bc4cb2..876ba82 100644
--- a/arch/m32r/include/uapi/asm/socket.h
+++ b/arch/m32r/include/uapi/asm/socket.h
@@ -85,4 +85,7 @@
#define SO_ATTACH_BPF 50
#define SO_DETACH_BPF SO_DETACH_FILTER
+#define SO_MAX_DGRAM_QLEN 51
+#define SO_MAX_DGRAM_QLEN_FORCE 52
+
#endif /* _ASM_M32R_SOCKET_H */
diff --git a/arch/mips/include/uapi/asm/socket.h b/arch/mips/include/uapi/asm/socket.h
index dec3c85..20d7ece 100644
--- a/arch/mips/include/uapi/asm/socket.h
+++ b/arch/mips/include/uapi/asm/socket.h
@@ -103,4 +103,7 @@
#define SO_ATTACH_BPF 50
#define SO_DETACH_BPF SO_DETACH_FILTER
+#define SO_MAX_DGRAM_QLEN 51
+#define SO_MAX_DGRAM_QLEN_FORCE 52
+
#endif /* _UAPI_ASM_SOCKET_H */
diff --git a/arch/mn10300/include/uapi/asm/socket.h b/arch/mn10300/include/uapi/asm/socket.h
index cab7d6d..60fffd1 100644
--- a/arch/mn10300/include/uapi/asm/socket.h
+++ b/arch/mn10300/include/uapi/asm/socket.h
@@ -85,4 +85,7 @@
#define SO_ATTACH_BPF 50
#define SO_DETACH_BPF SO_DETACH_FILTER
+#define SO_MAX_DGRAM_QLEN 51
+#define SO_MAX_DGRAM_QLEN_FORCE 52
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/parisc/include/uapi/asm/socket.h b/arch/parisc/include/uapi/asm/socket.h
index a5cd40c..b155b48 100644
--- a/arch/parisc/include/uapi/asm/socket.h
+++ b/arch/parisc/include/uapi/asm/socket.h
@@ -84,4 +84,7 @@
#define SO_ATTACH_BPF 0x402B
#define SO_DETACH_BPF SO_DETACH_FILTER
+#define SO_MAX_DGRAM_QLEN 0x402C
+#define SO_MAX_DGRAM_QLEN_FORCE 0x402D
+
#endif /* _UAPI_ASM_SOCKET_H */
diff --git a/arch/powerpc/include/uapi/asm/socket.h b/arch/powerpc/include/uapi/asm/socket.h
index c046666..732ffb7 100644
--- a/arch/powerpc/include/uapi/asm/socket.h
+++ b/arch/powerpc/include/uapi/asm/socket.h
@@ -92,4 +92,7 @@
#define SO_ATTACH_BPF 50
#define SO_DETACH_BPF SO_DETACH_FILTER
+#define SO_MAX_DGRAM_QLEN 51
+#define SO_MAX_DGRAM_QLEN_FORCE 52
+
#endif /* _ASM_POWERPC_SOCKET_H */
diff --git a/arch/s390/include/uapi/asm/socket.h b/arch/s390/include/uapi/asm/socket.h
index 296942d..3dd7e1f 100644
--- a/arch/s390/include/uapi/asm/socket.h
+++ b/arch/s390/include/uapi/asm/socket.h
@@ -91,4 +91,7 @@
#define SO_ATTACH_BPF 50
#define SO_DETACH_BPF SO_DETACH_FILTER
+#define SO_MAX_DGRAM_QLEN 51
+#define SO_MAX_DGRAM_QLEN_FORCE 52
+
#endif /* _ASM_SOCKET_H */
diff --git a/arch/sparc/include/uapi/asm/socket.h b/arch/sparc/include/uapi/asm/socket.h
index e6a16c4..13a6b6d 100644
--- a/arch/sparc/include/uapi/asm/socket.h
+++ b/arch/sparc/include/uapi/asm/socket.h
@@ -81,6 +81,9 @@
#define SO_ATTACH_BPF 0x0034
#define SO_DETACH_BPF SO_DETACH_FILTER
+#define SO_MAX_DGRAM_QLEN 0x0035
+#define SO_MAX_DGRAM_QLEN_FORCE 0x0036
+
/* Security levels - as per NRL IPv6 - don't actually do anything */
#define SO_SECURITY_AUTHENTICATION 0x5001
#define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002
diff --git a/arch/xtensa/include/uapi/asm/socket.h b/arch/xtensa/include/uapi/asm/socket.h
index 4120af0..79f0d2f 100644
--- a/arch/xtensa/include/uapi/asm/socket.h
+++ b/arch/xtensa/include/uapi/asm/socket.h
@@ -96,4 +96,7 @@
#define SO_ATTACH_BPF 50
#define SO_DETACH_BPF SO_DETACH_FILTER
+#define SO_MAX_DGRAM_QLEN 51
+#define SO_MAX_DGRAM_QLEN_FORCE 52
+
#endif /* _XTENSA_SOCKET_H */
diff --git a/include/net/netns/unix.h b/include/net/netns/unix.h
index 284649d..4d0803c 100644
--- a/include/net/netns/unix.h
+++ b/include/net/netns/unix.h
@@ -7,6 +7,7 @@
struct ctl_table_header;
struct netns_unix {
int sysctl_max_dgram_qlen;
+ int sysctl_max_dgram_qlen_limit;
struct ctl_table_header *ctl;
};
diff --git a/include/uapi/asm-generic/socket.h b/include/uapi/asm-generic/socket.h
index 5c15c2a..fba1974 100644
--- a/include/uapi/asm-generic/socket.h
+++ b/include/uapi/asm-generic/socket.h
@@ -87,4 +87,7 @@
#define SO_ATTACH_BPF 50
#define SO_DETACH_BPF SO_DETACH_FILTER
+#define SO_MAX_DGRAM_QLEN 51
+#define SO_MAX_DGRAM_QLEN_FORCE 52
+
#endif /* __ASM_GENERIC_SOCKET_H */
diff --git a/include/uapi/linux/sysctl.h b/include/uapi/linux/sysctl.h
index 0956373..d62d83b 100644
--- a/include/uapi/linux/sysctl.h
+++ b/include/uapi/linux/sysctl.h
@@ -289,6 +289,7 @@ enum
NET_UNIX_DESTROY_DELAY=1,
NET_UNIX_DELETE_DELAY=2,
NET_UNIX_MAX_DGRAM_QLEN=3,
+ NET_UNIX_MAX_DGRAM_QLEN_LIMIT=4,
};
/* /proc/sys/net/netfilter */
diff --git a/kernel/sysctl_binary.c b/kernel/sysctl_binary.c
index 7e7746a..bce8059 100644
--- a/kernel/sysctl_binary.c
+++ b/kernel/sysctl_binary.c
@@ -203,6 +203,7 @@ static const struct bin_table bin_net_unix_table[] = {
/* NET_UNIX_DESTROY_DELAY unused */
/* NET_UNIX_DELETE_DELAY unused */
{ CTL_INT, NET_UNIX_MAX_DGRAM_QLEN, "max_dgram_qlen" },
+ { CTL_INT, NET_UNIX_MAX_DGRAM_QLEN_LIMIT, "max_dgram_qlen_limit" },
{}
};
diff --git a/net/core/sock.c b/net/core/sock.c
index 93c8b20..91af187 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -973,6 +973,42 @@ set_rcvbuf:
sk->sk_max_pacing_rate);
break;
+ case SO_MAX_DGRAM_QLEN:
+#ifdef CONFIG_UNIX
+ /* Only do this for UNIX datagram sockets,
+ * because listen() uses the same field.
+ */
+ if (sock->ops->family == PF_UNIX &&
+ sk->sk_type == SOCK_DGRAM) {
+ /* As with SO_SNDBUF/SO_RCVBUF, don't let
+ * applications play a game of finding out the
+ * largest possible value.
+ */
+ val = min_t(u32, val, sock_net(sk)->unx.sysctl_max_dgram_qlen_limit);
+set_max_dgram_qlen:
+ if (val < 0 || val > USHRT_MAX)
+ ret = -EINVAL;
+ else
+ sk->sk_max_ack_backlog = val;
+ break;
+ }
+#endif
+ ret = -ENOPROTOOPT;
+ break;
+
+ case SO_MAX_DGRAM_QLEN_FORCE:
+#ifdef CONFIG_UNIX
+ if (sock->ops->family == PF_UNIX &&
+ sk->sk_type == SOCK_DGRAM) {
+ if (capable(CAP_NET_ADMIN))
+ goto set_max_dgram_qlen;
+ ret = -EPERM;
+ break;
+ }
+#endif
+ ret = -ENOPROTOOPT;
+ break;
+
default:
ret = -ENOPROTOOPT;
break;
@@ -1233,6 +1269,19 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
v.val = sk->sk_incoming_cpu;
break;
+ case SO_MAX_DGRAM_QLEN:
+#ifdef CONFIG_UNIX
+ /* Only do this for UNIX datagram sockets,
+ * because listen() uses the same field.
+ */
+ if (sock->ops->family == PF_UNIX &&
+ sk->sk_type == SOCK_DGRAM) {
+ v.val = sk->sk_max_ack_backlog;
+ break;
+ }
+#endif
+ return -ENOPROTOOPT;
+
default:
return -ENOPROTOOPT;
}
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 526b6ed..33fec15 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -2406,6 +2406,7 @@ static int __net_init unix_net_init(struct net *net)
int error = -ENOMEM;
net->unx.sysctl_max_dgram_qlen = 10;
+ net->unx.sysctl_max_dgram_qlen_limit = 2047;
if (unix_sysctl_register(net))
goto out;
diff --git a/net/unix/sysctl_net_unix.c b/net/unix/sysctl_net_unix.c
index b3d5150..b4c75a7 100644
--- a/net/unix/sysctl_net_unix.c
+++ b/net/unix/sysctl_net_unix.c
@@ -15,12 +15,23 @@
#include <net/af_unix.h>
+static int proc_unix_do_dgram_qlen(struct ctl_table *ctl, int write,
+ void __user *buffer, size_t *lenp,
+ loff_t *ppos);
+
static struct ctl_table unix_table[] = {
{
.procname = "max_dgram_qlen",
.data = &init_net.unx.sysctl_max_dgram_qlen,
.maxlen = sizeof(int),
.mode = 0644,
+ .proc_handler = proc_unix_do_dgram_qlen
+ },
+ {
+ .procname = "max_dgram_qlen_limit",
+ .data = &init_net.unx.sysctl_max_dgram_qlen_limit,
+ .maxlen = sizeof(int),
+ .mode = 0644,
.proc_handler = proc_dointvec
},
{ }
@@ -39,6 +50,7 @@ int __net_init unix_sysctl_register(struct net *net)
table[0].procname = NULL;
table[0].data = &net->unx.sysctl_max_dgram_qlen;
+ table[1].data = &net->unx.sysctl_max_dgram_qlen_limit;
net->unx.ctl = register_net_sysctl(net, "net/unix", table);
if (net->unx.ctl == NULL)
goto err_reg;
@@ -59,3 +71,32 @@ void unix_sysctl_unregister(struct net *net)
unregister_net_sysctl_table(net->unx.ctl);
kfree(table);
}
+
+int proc_unix_do_dgram_qlen(struct ctl_table *ctl, int write,
+ void __user *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ struct net *net = current->nsproxy->net_ns;
+ struct ctl_table tbl;
+ int ret, new_value;
+
+ memset(&tbl, 0, sizeof(struct ctl_table));
+ tbl.maxlen = sizeof(unsigned int);
+
+ if (write)
+ tbl.data = &new_value;
+ else
+ tbl.data = &net->unx.sysctl_max_dgram_qlen;
+
+ ret = proc_dointvec(&tbl, write, buffer, lenp, ppos);
+ if (write && ret == 0) {
+ if (new_value > net->unx.sysctl_max_dgram_qlen_limit) {
+ pr_warn_once("New value of max_dgram_qlen higher than max_dgram_qlen_limit, also adjusting the latter.");
+ net->unx.sysctl_max_dgram_qlen_limit = new_value;
+ }
+
+ net->unx.sysctl_max_dgram_qlen = new_value;
+ }
+
+ return ret;
+}
--
2.1.4
^ permalink raw reply related
* [PATCHv2 0/2] N900 Modem Speech Support
From: Sebastian Reichel @ 2015-03-03 0:44 UTC (permalink / raw)
To: Sebastian Reichel
Cc: Peter Ujfalusi, Kai Vehmanen, Pavel Machek, Pali Rohar,
Aaro Koskinen, Ivaylo Dimitrov, linux-omap, linux-kernel,
linux-api
Hi,
This patchset contains the missing speech data support for the
Nokia N900 modem.
Userland access goes via /dev/cmt_speech. The API is implemented in
libcmtspeechdata, which is used by ofono and the freesmartphone.org project.
Apart from that the device is also used by the phone binaries distributed
with Maemo. So while this is a new userland ABI for the mainline kernel it
has been tested in the wild for some years.
Simple Testing of the API can be done by checking out libcmtspeechdata [0],
building the test tool and executing it. The tool will loop back audio data
received from the caller.
I have prepared a kernel branch for this patchset, which can be found at [1].
Changes since PATCHv1 [2]:
* Squash cmt-speech patches together
* cs_alloc_cmds(): GFP_ATOMIC -> GFP_KERNEL
* CS_SET_WAKELINE ioctl: Add sanity check
[0] https://lkml.org/lkml/2015/2/11/526
[1] git://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-hsi.git branch/cmt-speech-2
[2] https://lkml.org/lkml/2015/3/1/282
-- Sebastian
Kai Vehmanen (1):
HSI: cmt_speech: Add cmt-speech driver
Sebastian Reichel (1):
HSI: nokia-modem: Add cmt-speech support
drivers/hsi/clients/Kconfig | 11 +-
drivers/hsi/clients/Makefile | 1 +
drivers/hsi/clients/cmt_speech.c | 1457 ++++++++++++++++++++++++++++++++++
drivers/hsi/clients/nokia-modem.c | 31 +-
include/uapi/linux/hsi/Kbuild | 2 +-
include/uapi/linux/hsi/cs-protocol.h | 113 +++
6 files changed, 1612 insertions(+), 3 deletions(-)
create mode 100644 drivers/hsi/clients/cmt_speech.c
create mode 100644 include/uapi/linux/hsi/cs-protocol.h
--
2.1.4
^ permalink raw reply
* [PATCHv2 1/2] HSI: cmt_speech: Add cmt-speech driver
From: Sebastian Reichel @ 2015-03-03 0:44 UTC (permalink / raw)
To: Sebastian Reichel
Cc: Peter Ujfalusi, Kai Vehmanen, Pavel Machek, Pali Rohar,
Aaro Koskinen, Ivaylo Dimitrov, linux-omap, linux-kernel,
linux-api, Kai Vehmanen
In-Reply-To: <1425343454-6551-1-git-send-email-sre@kernel.org>
From: Kai Vehmanen <kai.vehmanen@nokia.com>
Introduces the cmt-speech driver, which implements
a character device interface for transferring speech
data frames over HSI/SSI.
The driver is used to exchange voice/speech data between
the Nokia N900/N950/N9's modem and its cpu.
Signed-off-by: Kai Vehmanen <kai.vehmanen@nokia.com>
Signed-off-by: Carlos Chinea <carlos.chinea@nokia.com>
Signed-off-by: Joni Lapilainen <joni.lapilainen@gmail.com>
Since the original driver has been written for 2.6.28 some
build fixes and general cleanups have been added by me:
* fix build for 4.0 kernel
* replace GFP_ATOMIC with GFP_KERNEL in cs_alloc_cmds()
* add sanity check for CS_SET_WAKELINE ioctl
* cleanup driver initialisation
* rename driver to cmt-speech to be consistent with
ssi-protocol driver
* move cs-protocol.h to include/uapi/linux/hsi, since
it describes a userspace API
* replace hardcoded channels numbers with values provided
via the HSI framework (e.g. coming from DT)
Signed-off-by: Sebastian Reichel <sre@kernel.org>
---
drivers/hsi/clients/Kconfig | 9 +
drivers/hsi/clients/Makefile | 1 +
drivers/hsi/clients/cmt_speech.c | 1457 ++++++++++++++++++++++++++++++++++
include/uapi/linux/hsi/Kbuild | 2 +-
include/uapi/linux/hsi/cs-protocol.h | 113 +++
5 files changed, 1581 insertions(+), 1 deletion(-)
create mode 100644 drivers/hsi/clients/cmt_speech.c
create mode 100644 include/uapi/linux/hsi/cs-protocol.h
diff --git a/drivers/hsi/clients/Kconfig b/drivers/hsi/clients/Kconfig
index bc60dec..26f62f8 100644
--- a/drivers/hsi/clients/Kconfig
+++ b/drivers/hsi/clients/Kconfig
@@ -13,6 +13,15 @@ config NOKIA_MODEM
If unsure, say N.
+config CMT_SPEECH
+ tristate "CMT speech"
+ depends on HSI && PHONET && OMAP_SSI
+ help
+ If you say Y here, you will enable the CMT speech protocol used
+ by Nokia modems.
+
+ If unsure, say N.
+
config SSI_PROTOCOL
tristate "SSI protocol"
depends on HSI && PHONET && OMAP_SSI
diff --git a/drivers/hsi/clients/Makefile b/drivers/hsi/clients/Makefile
index 4d5bc0e..2607232 100644
--- a/drivers/hsi/clients/Makefile
+++ b/drivers/hsi/clients/Makefile
@@ -4,4 +4,5 @@
obj-$(CONFIG_NOKIA_MODEM) += nokia-modem.o
obj-$(CONFIG_SSI_PROTOCOL) += ssi_protocol.o
+obj-$(CONFIG_CMT_SPEECH) += cmt_speech.o
obj-$(CONFIG_HSI_CHAR) += hsi_char.o
diff --git a/drivers/hsi/clients/cmt_speech.c b/drivers/hsi/clients/cmt_speech.c
new file mode 100644
index 0000000..11ac796
--- /dev/null
+++ b/drivers/hsi/clients/cmt_speech.c
@@ -0,0 +1,1457 @@
+/*
+ * cmt_speech.c - HSI CMT speech driver
+ *
+ * Copyright (C) 2008,2009,2010 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Kai Vehmanen <kai.vehmanen@nokia.com>
+ * Original author: Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ *
+ * 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
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/miscdevice.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/sched.h>
+#include <linux/ioctl.h>
+#include <linux/uaccess.h>
+#include <linux/pm_qos.h>
+#include <linux/hsi/hsi.h>
+#include <linux/hsi/ssi_protocol.h>
+#include <linux/hsi/cs-protocol.h>
+
+#define CS_MMAP_SIZE PAGE_SIZE
+
+struct char_queue {
+ struct list_head list;
+ u32 msg;
+};
+
+struct cs_char {
+ unsigned int opened;
+ struct hsi_client *cl;
+ struct cs_hsi_iface *hi;
+ struct list_head chardev_queue;
+ struct list_head dataind_queue;
+ int dataind_pending;
+ /* mmap things */
+ unsigned long mmap_base;
+ unsigned long mmap_size;
+ spinlock_t lock;
+ struct fasync_struct *async_queue;
+ wait_queue_head_t wait;
+ /* hsi channel ids */
+ int channel_id_cmd;
+ int channel_id_data;
+};
+
+#define SSI_CHANNEL_STATE_READING 1
+#define SSI_CHANNEL_STATE_WRITING (1 << 1)
+#define SSI_CHANNEL_STATE_POLL (1 << 2)
+#define SSI_CHANNEL_STATE_ERROR (1 << 3)
+
+#define TARGET_MASK 0xf000000
+#define TARGET_REMOTE (1 << CS_DOMAIN_SHIFT)
+#define TARGET_LOCAL 0
+
+/* Number of pre-allocated commands buffers */
+#define CS_MAX_CMDS 4
+
+/*
+ * During data transfers, transactions must be handled
+ * within 20ms (fixed value in cmtspeech HSI protocol)
+ */
+#define CS_QOS_LATENCY_FOR_DATA_USEC 20000
+
+/* Timeout to wait for pending HSI transfers to complete */
+#define CS_HSI_TRANSFER_TIMEOUT_MS 500
+
+
+#define RX_PTR_BOUNDARY_SHIFT 8
+#define RX_PTR_MAX_SHIFT (RX_PTR_BOUNDARY_SHIFT + \
+ CS_MAX_BUFFERS_SHIFT)
+struct cs_hsi_iface {
+ struct hsi_client *cl;
+ struct hsi_client *master;
+
+ unsigned int iface_state;
+ unsigned int wakeline_state;
+ unsigned int control_state;
+ unsigned int data_state;
+
+ /* state exposed to application */
+ struct cs_mmap_config_block *mmap_cfg;
+
+ unsigned long mmap_base;
+ unsigned long mmap_size;
+
+ unsigned int rx_slot;
+ unsigned int tx_slot;
+
+ /* note: for security reasons, we do not trust the contents of
+ * mmap_cfg, but instead duplicate the variables here */
+ unsigned int buf_size;
+ unsigned int rx_bufs;
+ unsigned int tx_bufs;
+ unsigned int rx_ptr_boundary;
+ unsigned int rx_offsets[CS_MAX_BUFFERS];
+ unsigned int tx_offsets[CS_MAX_BUFFERS];
+ /* size of aligned memory blocks */
+ unsigned int slot_size;
+ unsigned int flags;
+
+ struct list_head cmdqueue;
+
+ struct hsi_msg *data_rx_msg;
+ struct hsi_msg *data_tx_msg;
+ wait_queue_head_t datawait;
+
+ struct pm_qos_request pm_qos_req;
+
+ spinlock_t lock;
+};
+
+static struct cs_char cs_char_data;
+
+static void cs_hsi_read_on_control(struct cs_hsi_iface *hi);
+static void cs_hsi_read_on_data(struct cs_hsi_iface *hi);
+
+static inline void rx_ptr_shift_too_big(void)
+{
+ BUILD_BUG_ON((1LLU << RX_PTR_MAX_SHIFT) > UINT_MAX);
+}
+
+static void cs_notify(u32 message, struct list_head *head)
+{
+ struct char_queue *entry;
+
+ spin_lock(&cs_char_data.lock);
+
+ if (!cs_char_data.opened) {
+ spin_unlock(&cs_char_data.lock);
+ goto out;
+ }
+
+ entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+ if (!entry) {
+ dev_err(&cs_char_data.cl->device,
+ "Can't allocate new entry for the queue.\n");
+ spin_unlock(&cs_char_data.lock);
+ goto out;
+ }
+
+ entry->msg = message;
+ list_add_tail(&entry->list, head);
+
+ spin_unlock(&cs_char_data.lock);
+
+ wake_up_interruptible(&cs_char_data.wait);
+ kill_fasync(&cs_char_data.async_queue, SIGIO, POLL_IN);
+
+out:
+ return;
+}
+
+static u32 cs_pop_entry(struct list_head *head)
+{
+ struct char_queue *entry;
+ u32 data;
+
+ entry = list_entry(head->next, struct char_queue, list);
+ data = entry->msg;
+ list_del(&entry->list);
+ kfree(entry);
+
+ return data;
+}
+
+static void cs_notify_control(u32 message)
+{
+ cs_notify(message, &cs_char_data.chardev_queue);
+}
+
+static void cs_notify_data(u32 message, int maxlength)
+{
+ cs_notify(message, &cs_char_data.dataind_queue);
+
+ spin_lock(&cs_char_data.lock);
+ ++cs_char_data.dataind_pending;
+ while (cs_char_data.dataind_pending > maxlength &&
+ !list_empty(&cs_char_data.dataind_queue)) {
+ dev_dbg(&cs_char_data.cl->device, "data notification "
+ "queue overrun (%u entries)\n", cs_char_data.dataind_pending);
+
+ cs_pop_entry(&cs_char_data.dataind_queue);
+ --cs_char_data.dataind_pending;
+ }
+ spin_unlock(&cs_char_data.lock);
+}
+
+static inline void cs_set_cmd(struct hsi_msg *msg, u32 cmd)
+{
+ u32 *data;
+
+ data = sg_virt(msg->sgt.sgl);
+ *data = cmd;
+}
+
+static inline u32 cs_get_cmd(struct hsi_msg *msg)
+{
+ u32 *data;
+
+ data = sg_virt(msg->sgt.sgl);
+
+ return *data;
+}
+
+static void cs_release_cmd(struct hsi_msg *msg)
+{
+ struct cs_hsi_iface *hi = msg->context;
+
+ list_add_tail(&msg->link, &hi->cmdqueue);
+}
+
+static void cs_cmd_destructor(struct hsi_msg *msg)
+{
+ struct cs_hsi_iface *hi = msg->context;
+
+ spin_lock(&hi->lock);
+
+ dev_dbg(&cs_char_data.cl->device, "control cmd destructor\n");
+
+ if (hi->iface_state != CS_STATE_CLOSED)
+ dev_err(&hi->cl->device, "Cmd flushed while driver active\n");
+
+ if (msg->ttype == HSI_MSG_READ)
+ hi->control_state &=
+ ~(SSI_CHANNEL_STATE_POLL | SSI_CHANNEL_STATE_READING);
+ else if (msg->ttype == HSI_MSG_WRITE &&
+ hi->control_state & SSI_CHANNEL_STATE_WRITING)
+ hi->control_state &= ~SSI_CHANNEL_STATE_WRITING;
+
+ cs_release_cmd(msg);
+
+ spin_unlock(&hi->lock);
+}
+
+static struct hsi_msg *cs_claim_cmd(struct cs_hsi_iface* ssi)
+{
+ struct hsi_msg *msg;
+
+ BUG_ON(list_empty(&ssi->cmdqueue));
+
+ msg = list_first_entry(&ssi->cmdqueue, struct hsi_msg, link);
+ list_del(&msg->link);
+ msg->destructor = cs_cmd_destructor;
+
+ return msg;
+}
+
+static void cs_free_cmds(struct cs_hsi_iface *ssi)
+{
+ struct hsi_msg *msg, *tmp;
+
+ list_for_each_entry_safe(msg, tmp, &ssi->cmdqueue, link) {
+ list_del(&msg->link);
+ msg->destructor = NULL;
+ kfree(sg_virt(msg->sgt.sgl));
+ hsi_free_msg(msg);
+ }
+}
+
+static int cs_alloc_cmds(struct cs_hsi_iface *hi)
+{
+ struct hsi_msg *msg;
+ u32 *buf;
+ unsigned int i;
+
+ INIT_LIST_HEAD(&hi->cmdqueue);
+
+ for (i = 0; i < CS_MAX_CMDS; i++) {
+ msg = hsi_alloc_msg(1, GFP_KERNEL);
+ if (!msg)
+ goto out;
+ buf = kmalloc(sizeof(*buf), GFP_KERNEL);
+ if (!buf) {
+ hsi_free_msg(msg);
+ goto out;
+ }
+ sg_init_one(msg->sgt.sgl, buf, sizeof(*buf));
+ msg->channel = cs_char_data.channel_id_cmd;
+ msg->context = hi;
+ list_add_tail(&msg->link, &hi->cmdqueue);
+ }
+
+ return 0;
+
+out:
+ cs_free_cmds(hi);
+ return -ENOMEM;
+}
+
+static void cs_hsi_data_destructor(struct hsi_msg *msg)
+{
+ struct cs_hsi_iface *hi = msg->context;
+ const char *dir = (msg->ttype == HSI_MSG_READ) ? "TX" : "RX";
+
+ dev_dbg(&cs_char_data.cl->device, "Freeing data %s message\n", dir);
+
+ spin_lock(&hi->lock);
+ if (hi->iface_state != CS_STATE_CLOSED)
+ dev_err(&cs_char_data.cl->device,
+ "Data %s flush while device active\n", dir);
+ if (msg->ttype == HSI_MSG_READ)
+ hi->data_state &=
+ ~(SSI_CHANNEL_STATE_POLL | SSI_CHANNEL_STATE_READING);
+ else
+ hi->data_state &= ~SSI_CHANNEL_STATE_WRITING;
+
+ msg->status = HSI_STATUS_COMPLETED;
+ if (unlikely(waitqueue_active(&hi->datawait)))
+ wake_up_interruptible(&hi->datawait);
+
+ spin_unlock(&hi->lock);
+}
+
+static int cs_hsi_alloc_data(struct cs_hsi_iface *hi)
+{
+ struct hsi_msg *txmsg, *rxmsg;
+ int res = 0;
+
+ rxmsg = hsi_alloc_msg(1, GFP_KERNEL);
+ if (!rxmsg) {
+ res = -ENOMEM;
+ goto out1;
+ }
+ rxmsg->channel = cs_char_data.channel_id_data;
+ rxmsg->destructor = cs_hsi_data_destructor;
+ rxmsg->context = hi;
+
+ txmsg = hsi_alloc_msg(1, GFP_KERNEL);
+ if (!txmsg) {
+ res = -ENOMEM;
+ goto out2;
+ }
+ txmsg->channel = cs_char_data.channel_id_data;
+ txmsg->destructor = cs_hsi_data_destructor;
+ txmsg->context = hi;
+
+ hi->data_rx_msg = rxmsg;
+ hi->data_tx_msg = txmsg;
+
+ return 0;
+
+out2:
+ hsi_free_msg(rxmsg);
+out1:
+ return res;
+}
+
+static void cs_hsi_free_data_msg(struct hsi_msg *msg)
+{
+ WARN_ON(msg->status != HSI_STATUS_COMPLETED &&
+ msg->status != HSI_STATUS_ERROR);
+ hsi_free_msg(msg);
+}
+
+static void cs_hsi_free_data(struct cs_hsi_iface *hi)
+{
+ cs_hsi_free_data_msg(hi->data_rx_msg);
+ cs_hsi_free_data_msg(hi->data_tx_msg);
+}
+
+static inline void __cs_hsi_error_pre(struct cs_hsi_iface *hi,
+ struct hsi_msg *msg, const char *info,
+ unsigned int *state)
+{
+ spin_lock(&hi->lock);
+ dev_err(&hi->cl->device, "HSI %s error, msg %d, state %u\n",
+ info, msg->status, *state);
+}
+
+static inline void __cs_hsi_error_post(struct cs_hsi_iface *hi)
+{
+ spin_unlock(&hi->lock);
+}
+
+static inline void __cs_hsi_error_read_bits(unsigned int *state)
+{
+ *state |= SSI_CHANNEL_STATE_ERROR;
+ *state &= ~(SSI_CHANNEL_STATE_READING | SSI_CHANNEL_STATE_POLL);
+}
+
+static inline void __cs_hsi_error_write_bits(unsigned int *state)
+{
+ *state |= SSI_CHANNEL_STATE_ERROR;
+ *state &= ~SSI_CHANNEL_STATE_WRITING;
+}
+
+static void cs_hsi_control_read_error(struct cs_hsi_iface *hi,
+ struct hsi_msg *msg)
+{
+ __cs_hsi_error_pre(hi, msg, "control read", &hi->control_state);
+ cs_release_cmd(msg);
+ __cs_hsi_error_read_bits(&hi->control_state);
+ __cs_hsi_error_post(hi);
+}
+
+static void cs_hsi_control_write_error(struct cs_hsi_iface *hi,
+ struct hsi_msg *msg)
+{
+ __cs_hsi_error_pre(hi, msg, "control write", &hi->control_state);
+ cs_release_cmd(msg);
+ __cs_hsi_error_write_bits(&hi->control_state);
+ __cs_hsi_error_post(hi);
+
+}
+
+static void cs_hsi_data_read_error(struct cs_hsi_iface *hi, struct hsi_msg *msg)
+{
+ __cs_hsi_error_pre(hi, msg, "data read", &hi->data_state);
+ __cs_hsi_error_read_bits(&hi->data_state);
+ __cs_hsi_error_post(hi);
+}
+
+static void cs_hsi_data_write_error(struct cs_hsi_iface *hi,
+ struct hsi_msg *msg)
+{
+ __cs_hsi_error_pre(hi, msg, "data write", &hi->data_state);
+ __cs_hsi_error_write_bits(&hi->data_state);
+ __cs_hsi_error_post(hi);
+}
+
+static void cs_hsi_read_on_control_complete(struct hsi_msg *msg)
+{
+ u32 cmd = cs_get_cmd(msg);
+ struct cs_hsi_iface *hi = msg->context;
+
+ spin_lock(&hi->lock);
+ hi->control_state &= ~SSI_CHANNEL_STATE_READING;
+ if (msg->status == HSI_STATUS_ERROR) {
+ dev_err(&hi->cl->device, "Control RX error detected\n");
+ cs_hsi_control_read_error(hi, msg);
+ spin_unlock(&hi->lock);
+ goto out;
+ }
+ dev_dbg(&hi->cl->device, "Read on control: %08X\n", cmd);
+ cs_release_cmd(msg);
+ if (hi->flags & CS_FEAT_TSTAMP_RX_CTRL) {
+ struct timespec *tstamp =
+ &hi->mmap_cfg->tstamp_rx_ctrl;
+ do_posix_clock_monotonic_gettime(tstamp);
+ }
+ spin_unlock(&hi->lock);
+
+ cs_notify_control(cmd);
+
+out:
+ cs_hsi_read_on_control(hi);
+}
+
+static void cs_hsi_peek_on_control_complete(struct hsi_msg *msg)
+{
+ struct cs_hsi_iface *hi = msg->context;
+ int ret;
+
+ if (msg->status == HSI_STATUS_ERROR) {
+ dev_err(&hi->cl->device, "Control peek RX error detected\n");
+ cs_hsi_control_read_error(hi, msg);
+ return;
+ }
+
+ WARN_ON(!(hi->control_state & SSI_CHANNEL_STATE_READING));
+
+ dev_dbg(&hi->cl->device, "Peek on control complete, reading\n");
+ msg->sgt.nents = 1;
+ msg->complete = cs_hsi_read_on_control_complete;
+ ret = hsi_async_read(hi->cl, msg);
+ if (ret)
+ cs_hsi_control_read_error(hi, msg);
+}
+
+static void cs_hsi_read_on_control(struct cs_hsi_iface *hi)
+{
+ struct hsi_msg *msg;
+ int ret;
+
+ spin_lock(&hi->lock);
+ if (hi->control_state & SSI_CHANNEL_STATE_READING) {
+ dev_err(&hi->cl->device, "Control read already pending (%d)\n",
+ hi->control_state);
+ spin_unlock(&hi->lock);
+ return;
+ }
+ if (hi->control_state & SSI_CHANNEL_STATE_ERROR) {
+ dev_err(&hi->cl->device, "Control read error (%d)\n",
+ hi->control_state);
+ spin_unlock(&hi->lock);
+ return;
+ }
+ hi->control_state |= SSI_CHANNEL_STATE_READING;
+ dev_dbg(&hi->cl->device, "Issuing RX on control\n");
+ msg = cs_claim_cmd(hi);
+ spin_unlock(&hi->lock);
+
+ msg->sgt.nents = 0;
+ msg->complete = cs_hsi_peek_on_control_complete;
+ ret = hsi_async_read(hi->cl, msg);
+ if (ret)
+ cs_hsi_control_read_error(hi, msg);
+}
+
+static void cs_hsi_write_on_control_complete(struct hsi_msg *msg)
+{
+ struct cs_hsi_iface *hi = msg->context;
+ if (msg->status == HSI_STATUS_COMPLETED) {
+ spin_lock(&hi->lock);
+ hi->control_state &= ~SSI_CHANNEL_STATE_WRITING;
+ cs_release_cmd(msg);
+ spin_unlock(&hi->lock);
+ } else if (msg->status == HSI_STATUS_ERROR) {
+ cs_hsi_control_write_error(hi, msg);
+ } else {
+ dev_err(&hi->cl->device,
+ "unexpected status in control write callback %d\n",
+ msg->status);
+ }
+}
+
+static int cs_hsi_write_on_control(struct cs_hsi_iface *hi, u32 message)
+{
+ struct hsi_msg *msg;
+ int ret;
+
+ spin_lock(&hi->lock);
+ if (hi->control_state & SSI_CHANNEL_STATE_ERROR) {
+ spin_unlock(&hi->lock);
+ return -EIO;
+ }
+ if (hi->control_state & SSI_CHANNEL_STATE_WRITING) {
+ dev_err(&hi->cl->device,
+ "Write still pending on control channel.\n");
+ spin_unlock(&hi->lock);
+ return -EBUSY;
+ }
+ hi->control_state |= SSI_CHANNEL_STATE_WRITING;
+ msg = cs_claim_cmd(hi);
+ spin_unlock(&hi->lock);
+
+ cs_set_cmd(msg, message);
+ msg->sgt.nents = 1;
+ msg->complete = cs_hsi_write_on_control_complete;
+ dev_dbg(&hi->cl->device,
+ "Sending control message %08X\n", message);
+ ret = hsi_async_write(hi->cl, msg);
+ if (ret) {
+ dev_err(&hi->cl->device,
+ "async_write failed with %d\n", ret);
+ cs_hsi_control_write_error(hi, msg);
+ }
+
+ /*
+ * Make sure control read is always pending when issuing
+ * new control writes. This is needed as the controller
+ * may flush our messages if e.g. the peer device reboots
+ * unexpectedly (and we cannot directly resubmit a new read from
+ * the message destructor; see cs_cmd_destructor()).
+ */
+ if (!(hi->control_state & SSI_CHANNEL_STATE_READING)) {
+ dev_err(&hi->cl->device, "Restarting control reads\n");
+ cs_hsi_read_on_control(hi);
+ }
+
+ return 0;
+}
+
+static void cs_hsi_read_on_data_complete(struct hsi_msg *msg)
+{
+ struct cs_hsi_iface *hi = msg->context;
+ u32 payload;
+
+ if (unlikely(msg->status == HSI_STATUS_ERROR)) {
+ cs_hsi_data_read_error(hi, msg);
+ return;
+ }
+
+ spin_lock(&hi->lock);
+ WARN_ON(!(hi->data_state & SSI_CHANNEL_STATE_READING));
+ hi->data_state &= ~SSI_CHANNEL_STATE_READING;
+ payload = CS_RX_DATA_RECEIVED;
+ payload |= hi->rx_slot;
+ hi->rx_slot++;
+ hi->rx_slot %= hi->rx_ptr_boundary;
+ /* expose current rx ptr in mmap area */
+ hi->mmap_cfg->rx_ptr = hi->rx_slot;
+ if (unlikely(waitqueue_active(&hi->datawait)))
+ wake_up_interruptible(&hi->datawait);
+ spin_unlock(&hi->lock);
+
+ cs_notify_data(payload, hi->rx_bufs);
+ cs_hsi_read_on_data(hi);
+}
+
+static void cs_hsi_peek_on_data_complete(struct hsi_msg *msg)
+{
+ struct cs_hsi_iface *hi = msg->context;
+ u32 *address;
+ int ret;
+
+ if (unlikely(msg->status == HSI_STATUS_ERROR)) {
+ cs_hsi_data_read_error(hi, msg);
+ return;
+ }
+ if (unlikely(hi->iface_state != CS_STATE_CONFIGURED)) {
+ dev_err(&hi->cl->device, "Data received in invalid state\n");
+ cs_hsi_data_read_error(hi, msg);
+ return;
+ }
+
+ spin_lock(&hi->lock);
+ WARN_ON(!(hi->data_state & SSI_CHANNEL_STATE_POLL));
+ hi->data_state &= ~SSI_CHANNEL_STATE_POLL;
+ hi->data_state |= SSI_CHANNEL_STATE_READING;
+ spin_unlock(&hi->lock);
+
+ address = (u32 *)(hi->mmap_base +
+ hi->rx_offsets[hi->rx_slot % hi->rx_bufs]);
+ sg_init_one(msg->sgt.sgl, address, hi->buf_size);
+ msg->sgt.nents = 1;
+ msg->complete = cs_hsi_read_on_data_complete;
+ ret = hsi_async_read(hi->cl, msg);
+ if (ret)
+ cs_hsi_data_read_error(hi, msg);
+}
+
+/**
+ * Read/write transaction is ongoing. Returns false if in
+ * SSI_CHANNEL_STATE_POLL state.
+ */
+static inline int cs_state_xfer_active(unsigned int state)
+{
+ return (state & SSI_CHANNEL_STATE_WRITING) ||
+ (state & SSI_CHANNEL_STATE_READING);
+}
+
+/**
+ * No pending read/writes
+ */
+static inline int cs_state_idle(unsigned int state)
+{
+ return !(state & ~SSI_CHANNEL_STATE_ERROR);
+}
+
+static void cs_hsi_read_on_data(struct cs_hsi_iface *hi)
+{
+ struct hsi_msg *rxmsg;
+ int ret;
+
+ spin_lock(&hi->lock);
+ if (hi->data_state &
+ (SSI_CHANNEL_STATE_READING | SSI_CHANNEL_STATE_POLL)) {
+ dev_dbg(&hi->cl->device, "Data read already pending (%u)\n",
+ hi->data_state);
+ spin_unlock(&hi->lock);
+ return;
+ }
+ hi->data_state |= SSI_CHANNEL_STATE_POLL;
+ spin_unlock(&hi->lock);
+
+ rxmsg = hi->data_rx_msg;
+ sg_init_one(rxmsg->sgt.sgl, (void *)hi->mmap_base, 0);
+ rxmsg->sgt.nents = 0;
+ rxmsg->complete = cs_hsi_peek_on_data_complete;
+
+ ret = hsi_async_read(hi->cl, rxmsg);
+ if (ret)
+ cs_hsi_data_read_error(hi, rxmsg);
+}
+
+static void cs_hsi_write_on_data_complete(struct hsi_msg *msg)
+{
+ struct cs_hsi_iface *hi = msg->context;
+
+ if (msg->status == HSI_STATUS_COMPLETED) {
+ spin_lock(&hi->lock);
+ hi->data_state &= ~SSI_CHANNEL_STATE_WRITING;
+ if (unlikely(waitqueue_active(&hi->datawait)))
+ wake_up_interruptible(&hi->datawait);
+ spin_unlock(&hi->lock);
+ } else {
+ cs_hsi_data_write_error(hi, msg);
+ }
+}
+
+static int cs_hsi_write_on_data(struct cs_hsi_iface *hi, unsigned int slot)
+{
+ u32 *address;
+ struct hsi_msg *txmsg;
+ int ret;
+
+ spin_lock(&hi->lock);
+ if (hi->iface_state != CS_STATE_CONFIGURED) {
+ dev_err(&hi->cl->device, "Not configured, aborting\n");
+ ret = -EINVAL;
+ goto error;
+ }
+ if (hi->data_state & SSI_CHANNEL_STATE_ERROR) {
+ dev_err(&hi->cl->device, "HSI error, aborting\n");
+ ret = -EIO;
+ goto error;
+ }
+ if (hi->data_state & SSI_CHANNEL_STATE_WRITING) {
+ dev_err(&hi->cl->device, "Write pending on data channel.\n");
+ ret = -EBUSY;
+ goto error;
+ }
+ hi->data_state |= SSI_CHANNEL_STATE_WRITING;
+ spin_unlock(&hi->lock);
+
+ hi->tx_slot = slot;
+ address = (u32 *)(hi->mmap_base + hi->tx_offsets[hi->tx_slot]);
+ txmsg = hi->data_tx_msg;
+ sg_init_one(txmsg->sgt.sgl, address, hi->buf_size);
+ txmsg->complete = cs_hsi_write_on_data_complete;
+ ret = hsi_async_write(hi->cl, txmsg);
+ if (ret)
+ cs_hsi_data_write_error(hi, txmsg);
+
+ return ret;
+
+error:
+ spin_unlock(&hi->lock);
+ if (ret == -EIO)
+ cs_hsi_data_write_error(hi, hi->data_tx_msg);
+
+ return ret;
+}
+
+static unsigned int cs_hsi_get_state(struct cs_hsi_iface *hi)
+{
+ return hi->iface_state;
+}
+
+static int cs_hsi_command(struct cs_hsi_iface *hi, u32 cmd)
+{
+ int ret = 0;
+
+ local_bh_disable();
+ switch (cmd & TARGET_MASK) {
+ case TARGET_REMOTE:
+ ret = cs_hsi_write_on_control(hi, cmd);
+ break;
+ case TARGET_LOCAL:
+ if ((cmd & CS_CMD_MASK) == CS_TX_DATA_READY)
+ ret = cs_hsi_write_on_data(hi, cmd & CS_PARAM_MASK);
+ else
+ ret = -EINVAL;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ local_bh_enable();
+
+ return ret;
+}
+
+static void cs_hsi_set_wakeline(struct cs_hsi_iface *hi, bool new_state)
+{
+ int change = 0;
+
+ spin_lock_bh(&hi->lock);
+ if (hi->wakeline_state != new_state) {
+ hi->wakeline_state = new_state;
+ change = 1;
+ dev_dbg(&hi->cl->device, "setting wake line to %d (%p)\n",
+ new_state, hi->cl);
+ }
+ spin_unlock_bh(&hi->lock);
+
+ if (change) {
+ if (new_state)
+ ssip_slave_start_tx(hi->master);
+ else
+ ssip_slave_stop_tx(hi->master);
+ }
+
+ dev_dbg(&hi->cl->device, "wake line set to %d (%p)\n",
+ new_state, hi->cl);
+}
+
+static void set_buffer_sizes(struct cs_hsi_iface *hi, int rx_bufs, int tx_bufs)
+{
+ hi->rx_bufs = rx_bufs;
+ hi->tx_bufs = tx_bufs;
+ hi->mmap_cfg->rx_bufs = rx_bufs;
+ hi->mmap_cfg->tx_bufs = tx_bufs;
+
+ if (hi->flags & CS_FEAT_ROLLING_RX_COUNTER) {
+ /*
+ * For more robust overrun detection, let the rx
+ * pointer run in range 0..'boundary-1'. Boundary
+ * is a multiple of rx_bufs, and limited in max size
+ * by RX_PTR_MAX_SHIFT to allow for fast ptr-diff
+ * calculation.
+ */
+ hi->rx_ptr_boundary = (rx_bufs << RX_PTR_BOUNDARY_SHIFT);
+ hi->mmap_cfg->rx_ptr_boundary = hi->rx_ptr_boundary;
+ } else {
+ hi->rx_ptr_boundary = hi->rx_bufs;
+ }
+}
+
+static int check_buf_params(struct cs_hsi_iface *hi,
+ const struct cs_buffer_config *buf_cfg)
+{
+ size_t buf_size_aligned = L1_CACHE_ALIGN(buf_cfg->buf_size) *
+ (buf_cfg->rx_bufs + buf_cfg->tx_bufs);
+ size_t ctrl_size_aligned = L1_CACHE_ALIGN(sizeof(*hi->mmap_cfg));
+ int r = 0;
+
+ if (buf_cfg->rx_bufs > CS_MAX_BUFFERS ||
+ buf_cfg->tx_bufs > CS_MAX_BUFFERS) {
+ r = -EINVAL;
+ } else if ((buf_size_aligned + ctrl_size_aligned) >= hi->mmap_size) {
+ dev_err(&hi->cl->device, "No space for the requested buffer "
+ "configuration\n");
+ r = -ENOBUFS;
+ }
+
+ return r;
+}
+
+/**
+ * Block until pending data transfers have completed.
+ */
+static int cs_hsi_data_sync(struct cs_hsi_iface *hi)
+{
+ int r = 0;
+
+ spin_lock_bh(&hi->lock);
+
+ if (!cs_state_xfer_active(hi->data_state)) {
+ dev_dbg(&hi->cl->device, "hsi_data_sync break, idle\n");
+ goto out;
+ }
+
+ for (;;) {
+ int s;
+ DEFINE_WAIT(wait);
+ if (!cs_state_xfer_active(hi->data_state))
+ goto out;
+ if (signal_pending(current)) {
+ r = -ERESTARTSYS;
+ goto out;
+ }
+ /**
+ * prepare_to_wait must be called with hi->lock held
+ * so that callbacks can check for waitqueue_active()
+ */
+ prepare_to_wait(&hi->datawait, &wait, TASK_INTERRUPTIBLE);
+ spin_unlock_bh(&hi->lock);
+ s = schedule_timeout(
+ msecs_to_jiffies(CS_HSI_TRANSFER_TIMEOUT_MS));
+ spin_lock_bh(&hi->lock);
+ finish_wait(&hi->datawait, &wait);
+ if (!s) {
+ dev_dbg(&hi->cl->device,
+ "hsi_data_sync timeout after %d ms\n",
+ CS_HSI_TRANSFER_TIMEOUT_MS);
+ r = -EIO;
+ goto out;
+ }
+ }
+
+out:
+ spin_unlock_bh(&hi->lock);
+ dev_dbg(&hi->cl->device, "hsi_data_sync done with res %d\n", r);
+
+ return r;
+}
+
+static void cs_hsi_data_enable(struct cs_hsi_iface *hi,
+ struct cs_buffer_config *buf_cfg)
+{
+ unsigned int data_start, i;
+
+ BUG_ON(hi->buf_size == 0);
+
+ set_buffer_sizes(hi, buf_cfg->rx_bufs, buf_cfg->tx_bufs);
+
+ hi->slot_size = L1_CACHE_ALIGN(hi->buf_size);
+ dev_dbg(&hi->cl->device,
+ "setting slot size to %u, buf size %u, align %u\n",
+ hi->slot_size, hi->buf_size, L1_CACHE_BYTES);
+
+ data_start = L1_CACHE_ALIGN(sizeof(*hi->mmap_cfg));
+ dev_dbg(&hi->cl->device,
+ "setting data start at %u, cfg block %u, align %u\n",
+ data_start, sizeof(*hi->mmap_cfg), L1_CACHE_BYTES);
+
+ for (i = 0; i < hi->mmap_cfg->rx_bufs; i++) {
+ hi->rx_offsets[i] = data_start + i * hi->slot_size;
+ hi->mmap_cfg->rx_offsets[i] = hi->rx_offsets[i];
+ dev_dbg(&hi->cl->device, "DL buf #%u at %u\n",
+ i, hi->rx_offsets[i]);
+ }
+ for (i = 0; i < hi->mmap_cfg->tx_bufs; i++) {
+ hi->tx_offsets[i] = data_start +
+ (i + hi->mmap_cfg->rx_bufs) * hi->slot_size;
+ hi->mmap_cfg->tx_offsets[i] = hi->tx_offsets[i];
+ dev_dbg(&hi->cl->device, "UL buf #%u at %u\n",
+ i, hi->rx_offsets[i]);
+ }
+
+ hi->iface_state = CS_STATE_CONFIGURED;
+}
+
+static void cs_hsi_data_disable(struct cs_hsi_iface *hi, int old_state)
+{
+ if (old_state == CS_STATE_CONFIGURED) {
+ dev_dbg(&hi->cl->device,
+ "closing data channel with slot size 0\n");
+ hi->iface_state = CS_STATE_OPENED;
+ }
+}
+
+static int cs_hsi_buf_config(struct cs_hsi_iface *hi,
+ struct cs_buffer_config *buf_cfg)
+{
+ int r = 0;
+ unsigned int old_state = hi->iface_state;
+
+ spin_lock_bh(&hi->lock);
+ /* Prevent new transactions during buffer reconfig */
+ if (old_state == CS_STATE_CONFIGURED)
+ hi->iface_state = CS_STATE_OPENED;
+ spin_unlock_bh(&hi->lock);
+
+ /*
+ * make sure that no non-zero data reads are ongoing before
+ * proceeding to change the buffer layout
+ */
+ r = cs_hsi_data_sync(hi);
+ if (r < 0)
+ return r;
+
+ WARN_ON(cs_state_xfer_active(hi->data_state));
+
+ spin_lock_bh(&hi->lock);
+ r = check_buf_params(hi, buf_cfg);
+ if (r < 0)
+ goto error;
+
+ hi->buf_size = buf_cfg->buf_size;
+ hi->mmap_cfg->buf_size = hi->buf_size;
+ hi->flags = buf_cfg->flags;
+
+ hi->rx_slot = 0;
+ hi->tx_slot = 0;
+ hi->slot_size = 0;
+
+ if (hi->buf_size)
+ cs_hsi_data_enable(hi, buf_cfg);
+ else
+ cs_hsi_data_disable(hi, old_state);
+
+ spin_unlock_bh(&hi->lock);
+
+ if (old_state != hi->iface_state) {
+ if (hi->iface_state == CS_STATE_CONFIGURED) {
+ pm_qos_add_request(&hi->pm_qos_req,
+ PM_QOS_CPU_DMA_LATENCY,
+ CS_QOS_LATENCY_FOR_DATA_USEC);
+ local_bh_disable();
+ cs_hsi_read_on_data(hi);
+ local_bh_enable();
+ } else if (old_state == CS_STATE_CONFIGURED) {
+ pm_qos_remove_request(&hi->pm_qos_req);
+ }
+ }
+ return r;
+
+error:
+ spin_unlock_bh(&hi->lock);
+ return r;
+}
+
+static int cs_hsi_start(struct cs_hsi_iface **hi, struct hsi_client *cl,
+ unsigned long mmap_base, unsigned long mmap_size)
+{
+ int err = 0;
+ struct cs_hsi_iface *hsi_if = kzalloc(sizeof(*hsi_if), GFP_KERNEL);
+
+ dev_dbg(&cl->device, "cs_hsi_start\n");
+
+ if (!hsi_if) {
+ err = -ENOMEM;
+ goto leave0;
+ }
+ spin_lock_init(&hsi_if->lock);
+ hsi_if->cl = cl;
+ hsi_if->iface_state = CS_STATE_CLOSED;
+ hsi_if->mmap_cfg = (struct cs_mmap_config_block *)mmap_base;
+ hsi_if->mmap_base = mmap_base;
+ hsi_if->mmap_size = mmap_size;
+ memset(hsi_if->mmap_cfg, 0, sizeof(*hsi_if->mmap_cfg));
+ init_waitqueue_head(&hsi_if->datawait);
+ err = cs_alloc_cmds(hsi_if);
+ if (err < 0) {
+ dev_err(&cl->device, "Unable to alloc HSI messages\n");
+ goto leave1;
+ }
+ err = cs_hsi_alloc_data(hsi_if);
+ if (err < 0) {
+ dev_err(&cl->device, "Unable to alloc HSI messages for data\n");
+ goto leave2;
+ }
+ err = hsi_claim_port(cl, 1);
+ if (err < 0) {
+ dev_err(&cl->device,
+ "Could not open, HSI port already claimed\n");
+ goto leave3;
+ }
+ hsi_if->master = ssip_slave_get_master(cl);
+ if (IS_ERR(hsi_if->master)) {
+ dev_err(&cl->device, "Could not get HSI master client\n");
+ goto leave4;
+ }
+ if (!ssip_slave_running(hsi_if->master)) {
+ err = -ENODEV;
+ dev_err(&cl->device,
+ "HSI port not initialized\n");
+ goto leave4;
+ }
+
+ hsi_if->iface_state = CS_STATE_OPENED;
+ local_bh_disable();
+ cs_hsi_read_on_control(hsi_if);
+ local_bh_enable();
+
+ dev_dbg(&cl->device, "cs_hsi_start...done\n");
+
+ BUG_ON(!hi);
+ *hi = hsi_if;
+
+ return 0;
+
+leave4:
+ hsi_release_port(cl);
+leave3:
+ cs_hsi_free_data(hsi_if);
+leave2:
+ cs_free_cmds(hsi_if);
+leave1:
+ kfree(hsi_if);
+leave0:
+ dev_dbg(&cl->device, "cs_hsi_start...done/error\n\n");
+
+ return err;
+}
+
+static void cs_hsi_stop(struct cs_hsi_iface *hi)
+{
+ dev_dbg(&hi->cl->device, "cs_hsi_stop\n");
+ cs_hsi_set_wakeline(hi, 0);
+ ssip_slave_put_master(hi->master);
+
+ /* hsi_release_port() needs to be called with CS_STATE_CLOSED */
+ hi->iface_state = CS_STATE_CLOSED;
+ hsi_release_port(hi->cl);
+
+ /*
+ * hsi_release_port() should flush out all the pending
+ * messages, so cs_state_idle() should be true for both
+ * control and data channels.
+ */
+ WARN_ON(!cs_state_idle(hi->control_state));
+ WARN_ON(!cs_state_idle(hi->data_state));
+
+ if (pm_qos_request_active(&hi->pm_qos_req))
+ pm_qos_remove_request(&hi->pm_qos_req);
+
+ spin_lock_bh(&hi->lock);
+ cs_hsi_free_data(hi);
+ cs_free_cmds(hi);
+ spin_unlock_bh(&hi->lock);
+ kfree(hi);
+}
+
+static int cs_char_vma_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+ struct cs_char *csdata = vma->vm_private_data;
+ struct page *page;
+
+ page = virt_to_page(csdata->mmap_base);
+ get_page(page);
+ vmf->page = page;
+
+ return 0;
+}
+
+static struct vm_operations_struct cs_char_vm_ops = {
+ .fault = cs_char_vma_fault,
+};
+
+static int cs_char_fasync(int fd, struct file *file, int on)
+{
+ struct cs_char *csdata = file->private_data;
+
+ if (fasync_helper(fd, file, on, &csdata->async_queue) >= 0)
+ return 0;
+ else
+ return -EIO;
+}
+
+static unsigned int cs_char_poll(struct file *file, poll_table *wait)
+{
+ struct cs_char *csdata = file->private_data;
+ unsigned int ret = 0;
+
+ poll_wait(file, &cs_char_data.wait, wait);
+ spin_lock_bh(&csdata->lock);
+ if (!list_empty(&csdata->chardev_queue))
+ ret = POLLIN | POLLRDNORM;
+ else if (!list_empty(&csdata->dataind_queue))
+ ret = POLLIN | POLLRDNORM;
+ spin_unlock_bh(&csdata->lock);
+
+ return ret;
+}
+
+static ssize_t cs_char_read(struct file *file, char __user *buf, size_t count,
+ loff_t *unused)
+{
+ struct cs_char *csdata = file->private_data;
+ u32 data;
+ ssize_t retval;
+
+ if (count < sizeof(data))
+ return -EINVAL;
+
+ for ( ; ; ) {
+ DEFINE_WAIT(wait);
+
+ spin_lock_bh(&csdata->lock);
+ if (!list_empty(&csdata->chardev_queue)) {
+ data = cs_pop_entry(&csdata->chardev_queue);
+ } else if (!list_empty(&csdata->dataind_queue)) {
+ data = cs_pop_entry(&csdata->dataind_queue);
+ --csdata->dataind_pending;
+
+ } else {
+ data = 0;
+ }
+ spin_unlock_bh(&csdata->lock);
+
+ if (data)
+ break;
+ if (file->f_flags & O_NONBLOCK) {
+ retval = -EAGAIN;
+ goto out;
+ } else if (signal_pending(current)) {
+ retval = -ERESTARTSYS;
+ goto out;
+ }
+ prepare_to_wait_exclusive(&csdata->wait, &wait,
+ TASK_INTERRUPTIBLE);
+ schedule();
+ finish_wait(&csdata->wait, &wait);
+ }
+
+ retval = put_user(data, (u32 __user *)buf);
+ if (!retval)
+ retval = sizeof(data);
+
+out:
+ return retval;
+}
+
+static ssize_t cs_char_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *unused)
+{
+ struct cs_char *csdata = file->private_data;
+ u32 data;
+ int err;
+ ssize_t retval;
+
+ if (count < sizeof(data))
+ return -EINVAL;
+
+ if (get_user(data, (u32 __user *)buf))
+ retval = -EFAULT;
+ else
+ retval = count;
+
+ err = cs_hsi_command(csdata->hi, data);
+ if (err < 0)
+ retval = err;
+
+ return retval;
+}
+
+static long cs_char_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct cs_char *csdata = file->private_data;
+ int r = 0;
+
+ switch (cmd) {
+ case CS_GET_STATE: {
+ unsigned int state;
+
+ state = cs_hsi_get_state(csdata->hi);
+ if (copy_to_user((void __user *)arg, &state, sizeof(state)))
+ r = -EFAULT;
+ }
+ break;
+ case CS_SET_WAKELINE: {
+ unsigned int state;
+
+ if (copy_from_user(&state, (void __user *)arg, sizeof(state))) {
+ r = -EFAULT;
+ break;
+ }
+
+ if (state > 1) {
+ r = -EINVAL;
+ break;
+ }
+
+ cs_hsi_set_wakeline(csdata->hi, !!state);
+ }
+ break;
+ case CS_GET_IF_VERSION: {
+ unsigned int ifver = CS_IF_VERSION;
+
+ if (copy_to_user((void __user *)arg, &ifver, sizeof(ifver)))
+ r = -EFAULT;
+ break;
+ }
+ case CS_CONFIG_BUFS: {
+ struct cs_buffer_config buf_cfg;
+
+ if (copy_from_user(&buf_cfg, (void __user *)arg,
+ sizeof(buf_cfg)))
+ r = -EFAULT;
+ else
+ r = cs_hsi_buf_config(csdata->hi, &buf_cfg);
+ break;
+ }
+ default:
+ r = -ENOTTY;
+ break;
+ }
+
+ return r;
+}
+
+static int cs_char_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ if (vma->vm_end < vma->vm_start)
+ return -EINVAL;
+
+ if (((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) != 1)
+ return -EINVAL;
+
+ vma->vm_flags |= VM_IO | VM_DONTDUMP | VM_DONTEXPAND;
+ vma->vm_ops = &cs_char_vm_ops;
+ vma->vm_private_data = file->private_data;
+
+ return 0;
+}
+
+static int cs_char_open(struct inode *unused, struct file *file)
+{
+ int ret = 0;
+ unsigned long p;
+
+ spin_lock_bh(&cs_char_data.lock);
+ if (cs_char_data.opened) {
+ ret = -EBUSY;
+ spin_unlock_bh(&cs_char_data.lock);
+ goto out1;
+ }
+ cs_char_data.opened = 1;
+ cs_char_data.dataind_pending = 0;
+ spin_unlock_bh(&cs_char_data.lock);
+
+ p = get_zeroed_page(GFP_KERNEL);
+ if (!p) {
+ ret = -ENOMEM;
+ goto out2;
+ }
+
+ ret = cs_hsi_start(&cs_char_data.hi, cs_char_data.cl, p, CS_MMAP_SIZE);
+ if (ret) {
+ dev_err(&cs_char_data.cl->device, "Unable to initialize HSI\n");
+ goto out3;
+ }
+
+ /* these are only used in release so lock not needed */
+ cs_char_data.mmap_base = p;
+ cs_char_data.mmap_size = CS_MMAP_SIZE;
+
+ file->private_data = &cs_char_data;
+
+ return 0;
+
+out3:
+ free_page(p);
+out2:
+ spin_lock_bh(&cs_char_data.lock);
+ cs_char_data.opened = 0;
+ spin_unlock_bh(&cs_char_data.lock);
+out1:
+ return ret;
+}
+
+static void cs_free_char_queue(struct list_head *head)
+{
+ struct char_queue *entry;
+ struct list_head *cursor, *next;
+
+ if (!list_empty(head)) {
+ list_for_each_safe(cursor, next, head) {
+ entry = list_entry(cursor, struct char_queue, list);
+ list_del(&entry->list);
+ kfree(entry);
+ }
+ }
+
+}
+
+static int cs_char_release(struct inode *unused, struct file *file)
+{
+ struct cs_char *csdata = file->private_data;
+
+ cs_hsi_stop(csdata->hi);
+ spin_lock_bh(&csdata->lock);
+ csdata->hi = NULL;
+ free_page(csdata->mmap_base);
+ cs_free_char_queue(&csdata->chardev_queue);
+ cs_free_char_queue(&csdata->dataind_queue);
+ csdata->opened = 0;
+ spin_unlock_bh(&csdata->lock);
+
+ return 0;
+}
+
+static const struct file_operations cs_char_fops = {
+ .owner = THIS_MODULE,
+ .read = cs_char_read,
+ .write = cs_char_write,
+ .poll = cs_char_poll,
+ .unlocked_ioctl = cs_char_ioctl,
+ .mmap = cs_char_mmap,
+ .open = cs_char_open,
+ .release = cs_char_release,
+ .fasync = cs_char_fasync,
+};
+
+static struct miscdevice cs_char_miscdev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "cmt_speech",
+ .fops = &cs_char_fops
+};
+
+static int cs_hsi_client_probe(struct device *dev)
+{
+ int err = 0;
+ struct hsi_client *cl = to_hsi_client(dev);
+
+ dev_dbg(dev, "hsi_client_probe\n");
+ init_waitqueue_head(&cs_char_data.wait);
+ spin_lock_init(&cs_char_data.lock);
+ cs_char_data.opened = 0;
+ cs_char_data.cl = cl;
+ cs_char_data.hi = NULL;
+ INIT_LIST_HEAD(&cs_char_data.chardev_queue);
+ INIT_LIST_HEAD(&cs_char_data.dataind_queue);
+
+ cs_char_data.channel_id_cmd = hsi_get_channel_id_by_name(cl,
+ "speech-control");
+ if (cs_char_data.channel_id_cmd < 0) {
+ err = cs_char_data.channel_id_cmd;
+ dev_err(dev, "Could not get cmd channel (%d)\n", err);
+ return err;
+ }
+
+ cs_char_data.channel_id_data = hsi_get_channel_id_by_name(cl,
+ "speech-data");
+ if (cs_char_data.channel_id_data < 0) {
+ err = cs_char_data.channel_id_data;
+ dev_err(dev, "Could not get data channel (%d)\n", err);
+ return err;
+ }
+
+ err = misc_register(&cs_char_miscdev);
+ if (err)
+ dev_err(dev, "Failed to register: %d\n", err);
+
+ return err;
+}
+
+static int cs_hsi_client_remove(struct device *dev)
+{
+ struct cs_hsi_iface *hi;
+
+ dev_dbg(dev, "hsi_client_remove\n");
+ misc_deregister(&cs_char_miscdev);
+ spin_lock_bh(&cs_char_data.lock);
+ hi = cs_char_data.hi;
+ cs_char_data.hi = NULL;
+ spin_unlock_bh(&cs_char_data.lock);
+ if (hi)
+ cs_hsi_stop(hi);
+
+ return 0;
+}
+
+static struct hsi_client_driver cs_hsi_driver = {
+ .driver = {
+ .name = "cmt-speech",
+ .owner = THIS_MODULE,
+ .probe = cs_hsi_client_probe,
+ .remove = cs_hsi_client_remove,
+ },
+};
+
+static int __init cs_char_init(void)
+{
+ pr_info("CMT speech driver added\n");
+ return hsi_register_client_driver(&cs_hsi_driver);
+}
+module_init(cs_char_init);
+
+static void __exit cs_char_exit(void)
+{
+ hsi_unregister_client_driver(&cs_hsi_driver);
+ pr_info("CMT speech driver removed\n");
+}
+module_exit(cs_char_exit);
+
+MODULE_ALIAS("hsi:cmt-speech");
+MODULE_AUTHOR("Kai Vehmanen <kai.vehmanen@nokia.com>");
+MODULE_AUTHOR("Peter Ujfalusi <peter.ujfalusi@nokia.com>");
+MODULE_DESCRIPTION("CMT speech driver");
+MODULE_LICENSE("GPL");
diff --git a/include/uapi/linux/hsi/Kbuild b/include/uapi/linux/hsi/Kbuild
index 30ab3cd..a16a005 100644
--- a/include/uapi/linux/hsi/Kbuild
+++ b/include/uapi/linux/hsi/Kbuild
@@ -1,2 +1,2 @@
# UAPI Header export list
-header-y += hsi_char.h
+header-y += hsi_char.h cs-protocol.h
diff --git a/include/uapi/linux/hsi/cs-protocol.h b/include/uapi/linux/hsi/cs-protocol.h
new file mode 100644
index 0000000..4957bba
--- /dev/null
+++ b/include/uapi/linux/hsi/cs-protocol.h
@@ -0,0 +1,113 @@
+/*
+ * cmt-speech interface definitions
+ *
+ * Copyright (C) 2008,2009,2010 Nokia Corporation. All rights reserved.
+ *
+ * Contact: Kai Vehmanen <kai.vehmanen@nokia.com>
+ * Original author: Peter Ujfalusi <peter.ujfalusi@nokia.com>
+ *
+ * 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
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef _CS_PROTOCOL_H
+#define _CS_PROTOCOL_H
+
+#include <linux/types.h>
+#include <linux/ioctl.h>
+
+/* chardev parameters */
+#define CS_DEV_FILE_NAME "/dev/cmt_speech"
+
+/* user-space API versioning */
+#define CS_IF_VERSION 2
+
+/* APE kernel <-> user space messages */
+#define CS_CMD_SHIFT 28
+#define CS_DOMAIN_SHIFT 24
+
+#define CS_CMD_MASK 0xff000000
+#define CS_PARAM_MASK 0xffffff
+
+#define CS_CMD(id, dom) \
+ (((id) << CS_CMD_SHIFT) | ((dom) << CS_DOMAIN_SHIFT))
+
+#define CS_ERROR CS_CMD(1, 0)
+#define CS_RX_DATA_RECEIVED CS_CMD(2, 0)
+#define CS_TX_DATA_READY CS_CMD(3, 0)
+#define CS_TX_DATA_SENT CS_CMD(4, 0)
+
+/* params to CS_ERROR indication */
+#define CS_ERR_PEER_RESET 0
+
+/* ioctl interface */
+
+/* parameters to CS_CONFIG_BUFS ioctl */
+#define CS_FEAT_TSTAMP_RX_CTRL (1 << 0)
+#define CS_FEAT_ROLLING_RX_COUNTER (2 << 0)
+
+/* parameters to CS_GET_STATE ioctl */
+#define CS_STATE_CLOSED 0
+#define CS_STATE_OPENED 1 /* resource allocated */
+#define CS_STATE_CONFIGURED 2 /* data path active */
+
+/* maximum number of TX/RX buffers */
+#define CS_MAX_BUFFERS_SHIFT 4
+#define CS_MAX_BUFFERS (1 << CS_MAX_BUFFERS_SHIFT)
+
+/* Parameters for setting up the data buffers */
+struct cs_buffer_config {
+ __u32 rx_bufs; /* number of RX buffer slots */
+ __u32 tx_bufs; /* number of TX buffer slots */
+ __u32 buf_size; /* bytes */
+ __u32 flags; /* see CS_FEAT_* */
+ __u32 reserved[4];
+};
+
+/*
+ * Struct describing the layout and contents of the driver mmap area.
+ * This information is meant as read-only information for the application.
+ */
+struct cs_mmap_config_block {
+ __u32 reserved1;
+ __u32 buf_size; /* 0=disabled, otherwise the transfer size */
+ __u32 rx_bufs; /* # of RX buffers */
+ __u32 tx_bufs; /* # of TX buffers */
+ __u32 reserved2;
+ /* array of offsets within the mmap area for each RX and TX buffer */
+ __u32 rx_offsets[CS_MAX_BUFFERS];
+ __u32 tx_offsets[CS_MAX_BUFFERS];
+ __u32 rx_ptr;
+ __u32 rx_ptr_boundary;
+ __u32 reserved3[2];
+ /*
+ * if enabled with CS_FEAT_TSTAMP_RX_CTRL, monotonic
+ * timestamp taken when the last control command was received
+ */
+ struct timespec tstamp_rx_ctrl;
+};
+
+#define CS_IO_MAGIC 'C'
+
+#define CS_IOW(num, dtype) _IOW(CS_IO_MAGIC, num, dtype)
+#define CS_IOR(num, dtype) _IOR(CS_IO_MAGIC, num, dtype)
+#define CS_IOWR(num, dtype) _IOWR(CS_IO_MAGIC, num, dtype)
+#define CS_IO(num) _IO(CS_IO_MAGIC, num)
+
+#define CS_GET_STATE CS_IOR(21, unsigned int)
+#define CS_SET_WAKELINE CS_IOW(23, unsigned int)
+#define CS_GET_IF_VERSION CS_IOR(30, unsigned int)
+#define CS_CONFIG_BUFS CS_IOW(31, struct cs_buffer_config)
+
+#endif /* _CS_PROTOCOL_H */
--
2.1.4
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox