Linux Documentation
 help / color / mirror / Atom feed
* [PATCH v4 08/12] fpga: dfl: make uinit callback optional
From: Wu Hao @ 2019-08-04 10:20 UTC (permalink / raw)
  To: gregkh, mdf, linux-fpga; +Cc: linux-kernel, linux-api, linux-doc, atull, Wu Hao
In-Reply-To: <1564914022-3710-1-git-send-email-hao.wu@intel.com>

This patch makes uinit callback of sub features optional. With
this change, people don't need to prepare any empty uinit callback.

Signed-off-by: Wu Hao <hao.wu@intel.com>
---
 drivers/fpga/dfl.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/fpga/dfl.c b/drivers/fpga/dfl.c
index 87eaef6..c0512af 100644
--- a/drivers/fpga/dfl.c
+++ b/drivers/fpga/dfl.c
@@ -259,7 +259,8 @@ void dfl_fpga_dev_feature_uinit(struct platform_device *pdev)
 
 	dfl_fpga_dev_for_each_feature(pdata, feature)
 		if (feature->ops) {
-			feature->ops->uinit(pdev, feature);
+			if (feature->ops->uinit)
+				feature->ops->uinit(pdev, feature);
 			feature->ops = NULL;
 		}
 }
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH v4 00/12] FPGA DFL updates
From: Wu Hao @ 2019-08-04 10:20 UTC (permalink / raw)
  To: gregkh, mdf, linux-fpga; +Cc: linux-kernel, linux-api, linux-doc, atull, Wu Hao

Hi Greg,

This is v4 patchset which adds more features to FPGA DFL. The avx512
partial reconfiguration support patch is dropped for now as need
to address some opens first.

Main changes from v3:
  - drop avx512 partail reconfiguration patch for now.
  - split dfl_fpga_cdev_config_port to 2 functions *_release/assign_port
    (#1).
  - split __dfl_fpga_cdev_config_port_vf into 2 functions with locking
    added (#2).
  - improve description in sysfs doc to avoid misunderstanding (#3).
  - switch to boolean in sysfs entry store function (#3).
  - remove dev_dbg in init/uinit callback function (#7, #9, #11).
  - remove uinit callback which does does nothing (#8, #9)

Main changes from v2:
  - update kernel version/date in sysfs doc (patch #4, #5, #8, #10, #11).
  - add back Documentation patch (patch #12).

Main changes from v1:
  - remove DRV/MODULE_VERSION modifications. (patch #1, #3, #4, #6)
  - remove argsz from new ioctls. (patch #2)
  - replace sysfs_create/remove_* with device_add/remove_* for sysfs entries.
    (patch #5, #8, #11)

Wu Hao (12):
  fpga: dfl: fme: add DFL_FPGA_FME_PORT_RELEASE/ASSIGN ioctl support.
  fpga: dfl: pci: enable SRIOV support.
  fpga: dfl: afu: add AFU state related sysfs interfaces
  fpga: dfl: afu: add userclock sysfs interfaces.
  fpga: dfl: add id_table for dfl private feature driver
  fpga: dfl: afu: export __port_enable/disable function.
  fpga: dfl: afu: add error reporting support.
  fpga: dfl: make uinit callback optional
  fpga: dfl: afu: add STP (SignalTap) support
  fpga: dfl: fme: add capability sysfs interfaces
  fpga: dfl: fme: add global error reporting support
  Documentation: fpga: dfl: add descriptions for virtualization and new
    interfaces.

 Documentation/ABI/testing/sysfs-platform-dfl-fme  |  98 ++++++
 Documentation/ABI/testing/sysfs-platform-dfl-port | 106 ++++++
 Documentation/fpga/dfl.rst                        | 105 ++++++
 drivers/fpga/Makefile                             |   3 +-
 drivers/fpga/dfl-afu-error.c                      | 221 +++++++++++++
 drivers/fpga/dfl-afu-main.c                       | 319 +++++++++++++++++-
 drivers/fpga/dfl-afu.h                            |   7 +
 drivers/fpga/dfl-fme-error.c                      | 381 ++++++++++++++++++++++
 drivers/fpga/dfl-fme-main.c                       | 105 +++++-
 drivers/fpga/dfl-fme-pr.c                         |   7 +-
 drivers/fpga/dfl-fme.h                            |   5 +-
 drivers/fpga/dfl-pci.c                            |  36 ++
 drivers/fpga/dfl.c                                | 216 +++++++++++-
 drivers/fpga/dfl.h                                |  54 ++-
 include/uapi/linux/fpga-dfl.h                     |  18 +
 15 files changed, 1640 insertions(+), 41 deletions(-)
 create mode 100644 drivers/fpga/dfl-afu-error.c
 create mode 100644 drivers/fpga/dfl-fme-error.c

-- 
1.8.3.1


^ permalink raw reply

* Re: [PATCH 9/9] arm64: Retrieve stolen time as paravirtualized guest
From: Marc Zyngier @ 2019-08-04  9:53 UTC (permalink / raw)
  To: Steven Price
  Cc: Catalin Marinas, Paolo Bonzini, Radim Krčmář,
	Russell King, Will Deacon, James Morse, Julien Thierry,
	Suzuki K Pouloze, kvm, kvmarm, linux-arm-kernel, linux-doc,
	linux-kernel
In-Reply-To: <20190802145017.42543-10-steven.price@arm.com>

On Fri,  2 Aug 2019 15:50:17 +0100
Steven Price <steven.price@arm.com> wrote:

> Enable paravirtualization features when running under a hypervisor
> supporting the PV_TIME_ST hypercall.
> 
> For each (v)CPU, we ask the hypervisor for the location of a shared
> page which the hypervisor will use to report stolen time to us. We set
> pv_time_ops to the stolen time function which simply reads the stolen
> value from the shared page for a VCPU. We guarantee single-copy
> atomicity using READ_ONCE which means we can also read the stolen
> time for another VCPU than the currently running one while it is
> potentially being updated by the hypervisor.
> 
> Signed-off-by: Steven Price <steven.price@arm.com>
> ---
>  arch/arm64/kernel/Makefile |   1 +
>  arch/arm64/kernel/kvm.c    | 155 +++++++++++++++++++++++++++++++++++++

nit: Why not using paravirt.c, which clearly states what it does? The
alternative would be to name it kvm-pv.c.

>  include/linux/cpuhotplug.h |   1 +
>  3 files changed, 157 insertions(+)
>  create mode 100644 arch/arm64/kernel/kvm.c
> 
> diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
> index 478491f07b4f..eb36edf9b930 100644
> --- a/arch/arm64/kernel/Makefile
> +++ b/arch/arm64/kernel/Makefile
> @@ -63,6 +63,7 @@ obj-$(CONFIG_CRASH_CORE)		+= crash_core.o
>  obj-$(CONFIG_ARM_SDE_INTERFACE)		+= sdei.o
>  obj-$(CONFIG_ARM64_SSBD)		+= ssbd.o
>  obj-$(CONFIG_ARM64_PTR_AUTH)		+= pointer_auth.o
> +obj-$(CONFIG_PARAVIRT)			+= kvm.o
>  
>  obj-y					+= vdso/ probes/
>  obj-$(CONFIG_COMPAT_VDSO)		+= vdso32/
> diff --git a/arch/arm64/kernel/kvm.c b/arch/arm64/kernel/kvm.c
> new file mode 100644
> index 000000000000..245398c79dae
> --- /dev/null
> +++ b/arch/arm64/kernel/kvm.c
> @@ -0,0 +1,155 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (C) 2019 Arm Ltd.
> +
> +#define pr_fmt(fmt) "kvmarm-pv: " fmt
> +
> +#include <linux/arm-smccc.h>
> +#include <linux/cpuhotplug.h>
> +#include <linux/io.h>
> +#include <linux/printk.h>
> +#include <linux/psci.h>
> +#include <linux/reboot.h>
> +#include <linux/slab.h>
> +
> +#include <asm/paravirt.h>
> +#include <asm/pvclock-abi.h>
> +#include <asm/smp_plat.h>
> +
> +struct kvmarm_stolen_time_region {
> +	struct pvclock_vcpu_stolen_time_info *kaddr;
> +};
> +
> +static DEFINE_PER_CPU(struct kvmarm_stolen_time_region, stolen_time_region);
> +
> +static bool steal_acc = true;
> +static int __init parse_no_stealacc(char *arg)
> +{
> +	steal_acc = false;
> +	return 0;
> +}
> +early_param("no-steal-acc", parse_no_stealacc);
> +
> +/* return stolen time in ns by asking the hypervisor */
> +static u64 kvm_steal_clock(int cpu)
> +{
> +	struct kvmarm_stolen_time_region *reg;
> +
> +	reg = per_cpu_ptr(&stolen_time_region, cpu);
> +	if (!reg->kaddr) {
> +		pr_warn_once("stolen time enabled but not configured for cpu %d\n",
> +			     cpu);
> +		return 0;
> +	}
> +
> +	return le64_to_cpu(READ_ONCE(reg->kaddr->stolen_time));
> +}
> +
> +static int disable_stolen_time_current_cpu(void)
> +{
> +	struct kvmarm_stolen_time_region *reg;
> +
> +	reg = this_cpu_ptr(&stolen_time_region);
> +	if (!reg->kaddr)
> +		return 0;
> +
> +	memunmap(reg->kaddr);
> +	memset(reg, 0, sizeof(*reg));
> +
> +	return 0;
> +}
> +
> +static int stolen_time_dying_cpu(unsigned int cpu)
> +{
> +	return disable_stolen_time_current_cpu();
> +}
> +
> +static int init_stolen_time_cpu(unsigned int cpu)
> +{
> +	struct kvmarm_stolen_time_region *reg;
> +	struct arm_smccc_res res;
> +
> +	reg = this_cpu_ptr(&stolen_time_region);
> +
> +	if (reg->kaddr)
> +		return 0;

Can this actually happen? It'd take two CPU_UP calls from the HP
notifiers to get in that situation...

> +
> +	arm_smccc_1_1_invoke(ARM_SMCCC_HV_PV_TIME_ST, &res);
> +
> +	if ((long)res.a0 < 0)
> +		return -EINVAL;
> +
> +	reg->kaddr = memremap(res.a0,
> +			sizeof(struct pvclock_vcpu_stolen_time_info),
> +			MEMREMAP_WB);
> +
> +	if (reg->kaddr == NULL) {
> +		pr_warn("Failed to map stolen time data structure\n");
> +		return -EINVAL;

-ENOMEM is the expected return code.

> +	}
> +
> +	if (le32_to_cpu(reg->kaddr->revision) != 0 ||
> +			le32_to_cpu(reg->kaddr->attributes) != 0) {
> +		pr_warn("Unexpected revision or attributes in stolen time data\n");
> +		return -ENXIO;
> +	}
> +
> +	return 0;
> +}
> +
> +static int kvm_arm_init_stolen_time(void)
> +{
> +	int ret;
> +
> +	ret = cpuhp_setup_state(CPUHP_AP_ARM_KVMPV_STARTING,
> +				"hypervisor/kvmarm/pv:starting",
> +				init_stolen_time_cpu, stolen_time_dying_cpu);
> +	if (ret < 0)
> +		return ret;
> +	return 0;
> +}
> +
> +static bool has_kvm_steal_clock(void)
> +{
> +	struct arm_smccc_res res;
> +
> +	/* To detect the presence of PV time support we require SMCCC 1.1+ */
> +	if (psci_ops.smccc_version < SMCCC_VERSION_1_1)
> +		return false;
> +
> +	arm_smccc_1_1_invoke(ARM_SMCCC_ARCH_FEATURES_FUNC_ID,
> +			     ARM_SMCCC_HV_PV_FEATURES, &res);
> +
> +	if (res.a0 != SMCCC_RET_SUCCESS)
> +		return false;
> +
> +	arm_smccc_1_1_invoke(ARM_SMCCC_HV_PV_FEATURES,
> +			     ARM_SMCCC_HV_PV_TIME_ST, &res);
> +
> +	if (res.a0 != SMCCC_RET_SUCCESS)
> +		return false;
> +
> +	return true;
> +}
> +
> +static int __init kvm_guest_init(void)
> +{
> +	int ret = 0;
> +
> +	if (!has_kvm_steal_clock())
> +		return 0;
> +
> +	ret = kvm_arm_init_stolen_time();
> +	if (ret)
> +		return ret;
> +
> +	pv_ops.time.steal_clock = kvm_steal_clock;
> +
> +	static_key_slow_inc(&paravirt_steal_enabled);
> +	if (steal_acc)
> +		static_key_slow_inc(&paravirt_steal_rq_enabled);
> +
> +	pr_info("using stolen time PV\n");
> +
> +	return 0;
> +}
> +early_initcall(kvm_guest_init);

Is there any reason why we wouldn't directly call into this rather than
using an initcall?

> diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
> index 068793a619ca..89d75edb5750 100644
> --- a/include/linux/cpuhotplug.h
> +++ b/include/linux/cpuhotplug.h
> @@ -136,6 +136,7 @@ enum cpuhp_state {
>  	/* Must be the last timer callback */
>  	CPUHP_AP_DUMMY_TIMER_STARTING,
>  	CPUHP_AP_ARM_XEN_STARTING,
> +	CPUHP_AP_ARM_KVMPV_STARTING,
>  	CPUHP_AP_ARM_CORESIGHT_STARTING,
>  	CPUHP_AP_ARM64_ISNDEP_STARTING,
>  	CPUHP_AP_SMPCFD_DYING,


Thanks,

	M.
-- 
Without deviation from the norm, progress is not possible.

^ permalink raw reply

* Re: [PATCH] Documentation/admin-guide: Embargoed hardware security issues
From: Jiri Kosina @ 2019-08-04  0:21 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: linux-kernel, Jonathan Corbet, security, linux-doc,
	Thomas Gleixner, Mauro Carvalho Chehab
In-Reply-To: <nycvar.YFH.7.76.1908040214090.5899@cbobk.fhfr.pm>

On Sun, 4 Aug 2019, Jiri Kosina wrote:

> On Thu, 25 Jul 2019, Greg Kroah-Hartman wrote:
> 
> > To address the requirements of embargoed hardware issues, like Meltdown,
> > Spectre, L1TF, etc. it is necessary to define and document a process for
> > handling embargoed hardware security issues.
> 
> I don't know what exactly went wrong, but there is a much more up-to-date 
> version of that document (especially when it comes to vendor contacts), 
> which I sent around on Thu, 2 May 2019 20:23:48 +0200 (CEST) already. 
> Please find it below.
> 
> 
> 
> From: Jiri Kosina <jkosina@suse.cz>

And this should've been

	From: Thomas Gleixner <tglx@linutronix.de>

as Thomas wrote most part of the text of course.

Sorry for the noise,

-- 
Jiri Kosina
SUSE Labs


^ permalink raw reply

* Re: [PATCH] Documentation/admin-guide: Embargoed hardware security issues
From: Jiri Kosina @ 2019-08-04  0:17 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: linux-kernel, Jonathan Corbet, security, linux-doc,
	Thomas Gleixner, Mauro Carvalho Chehab
In-Reply-To: <20190725130113.GA12932@kroah.com>

On Thu, 25 Jul 2019, Greg Kroah-Hartman wrote:

> To address the requirements of embargoed hardware issues, like Meltdown,
> Spectre, L1TF, etc. it is necessary to define and document a process for
> handling embargoed hardware security issues.

I don't know what exactly went wrong, but there is a much more up-to-date 
version of that document (especially when it comes to vendor contacts), 
which I sent around on Thu, 2 May 2019 20:23:48 +0200 (CEST) already. 
Please find it below.



From: Jiri Kosina <jkosina@suse.cz>
Subject: [PATCH] Documentation/admin-guide: Embargoed hardware security issues

To address the requirements of embargoed hardware issues, like Meltdown, 
Spectre, L1TF etc. it is necessary to define and document a process for 
handling embargoed hardware security issues.

Following the discussion at the maintainer summit 2018 in Edinburgh
(https://lwn.net/Articles/769417/) the volunteered people have worked
out a process and a Memorandum of Understanding. The latter addresses
the fact that the Linux kernel community cannot sign NDAs for various
reasons.

The initial contact point for hardware security issues is different from
the regular kernel security contact to provide a known and neutral
interface for hardware vendors and researchers. The initial primary
contact team is proposed to be staffed by Linux Foundation Fellows, who
are not associated to a vendor or a distribution and are well connected
in the industry as a whole.

The process is designed with the experience of the past incidents in mind 
and tries to address the remaining gaps, so future (hopefully rare) 
incidents can be handled more efficiently. It won't remove the fact, that 
most of this has to be done behind closed doors, but it is set up to avoid 
big bureaucratic hurdles for individual developers.

The process is solely for handling hardware security  issues and cannot
be used for regular kernel (software only) security bugs.

To accelerate the adoption of this  process, we introduce the concept of
ambassadors in participating companies. The ambassadors are there to
guide people to comply with the process, but are not automatically
involved in the disclosure of a particular incident.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Josh Poimboeuf <jpoimboe@redhat.com>
Acked-by: Laura Abbott <labbott@redhat.com>
Acked-by: Ben Hutchings <ben@decadent.org.uk>
Reviewed-by: Tyler Hicks <tyhicks@canonical.com>
Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Reviewed-by: Jiri Kosina <jkosina@suse.cz>
---

v6 -> v7: added contacts (and Acks/Reviewed-bys) for distro people
	  fixed spelling of Red Hat
	  fixed spelling of SUSE
v5 -> v6: legal review and minor wording and line-wrapping changes
          Fixed Jiri's email address
V4 -> V5: Fix the last bits (LF and space/tab)
V3 -> V4: Addressed review comments
          Added changelog
          Added Google and Amazon to the ambassador list. Is there
          any company missing?


 .../admin-guide/embargoed-hardware-issues.rst      | 281 +++++++++++++++++++++
 Documentation/admin-guide/index.rst                |   1 +
 2 files changed, 282 insertions(+)
 create mode 100644 Documentation/admin-guide/embargoed-hardware-issues.rst

diff --git a/Documentation/admin-guide/embargoed-hardware-issues.rst b/Documentation/admin-guide/embargoed-hardware-issues.rst
new file mode 100644
index 000000000000..0bc4d01e13dd
--- /dev/null
+++ b/Documentation/admin-guide/embargoed-hardware-issues.rst
@@ -0,0 +1,281 @@
+.. _embargoedhardwareissues:
+
+Embargoed hardware issues
+=========================
+
+Scope
+-----
+
+Hardware issues which result in security problems are a different category
+of security bugs than pure software bugs which  only affect the Linux
+kernel.
+
+Hardware issues like Meltdown, Spectre, L1TF etc. must be treated
+differently because they usually affect all Operating Systems (???OS???) and
+therefore need coordination across different OS vendors, distributions,
+hardware vendors and other parties. For some of the issues, software
+mitigations can depend on microcode or firmware updates, which need further
+coordination.
+
+.. _Contact:
+
+Contact
+-------
+
+The Linux kernel hardware security team is separate from the regular Linux
+kernel security team.
+
+The team is only handling the coordination of embargoed hardware security
+issues. Reports of pure software security bugs in the Linux kernel are not
+handled by this team and the reporter will be guided to contact the regular
+Linux kernel security team (:ref:`Documentation/admin-guide/
+<securitybugs>`) instead.
+
+The team can be contacted by email at <hardware-security@kernel.org>. This
+is a private list of security officers who will help you to coordinate an
+issue according to our documented process.
+
+The list is encrypted and email to the list can be sent by either PGP or
+S/MIME encrypted and must be signed with the reporter's PGP key or S/MIME
+certificate. The list's PGP key and S/MIME certificate are available from
+https://www.kernel.org/....
+
+While hardware security issues are often handled by the affected hardware
+vendor, we welcome contact from researchers or individuals who identified a
+potential hardware flaw.
+
+Hardware security officers
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The current team of hardware security officers:
+
+  - Linus Torvalds (Linux Foundation Fellow)
+  - Greg Kroah-Hartman (Linux Foundation Fellow)
+  - Thomas Gleixner (Linux Foundation Fellow)
+
+Operation of mailing-lists
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The encrypted mailing-lists which are used in our process are hosted on
+Linux Foundation's IT infrastructure. By providing this service Linux
+Foundation's director of IT Infrastructure security technically has the
+ability to access the embargoed information, but is obliged to
+confidentiality by his employment contract. Linux Foundation's director of
+IT Infrastructure security is also responsible for the kernel.org
+infrastructure.
+
+The Linux Foundation's current director of IT Infrastructure security is
+Konstantin Ryabitsev.
+
+
+Non-disclosure agreements
+-------------------------
+
+The Linux kernel hardware security team is not a formal body and therefore
+unable to enter into any non-disclosure agreements.  The kernel community
+is aware of the sensitive nature of such issues and offers a Memorandum of
+Understanding instead.
+
+
+Memorandum of Understanding
+---------------------------
+
+The Linux kernel community has a deep understanding of the requirement to
+keep hardware security issues under embargo for coordination between
+different OS vendors, distributors, hardware vendors and other parties.
+
+The Linux kernel community has successfully handled hardware security
+issues in the past and has the necessary mechanisms in place to allow
+community compliant development under embargo restrictions.
+
+The Linux kernel community has a dedicated hardware security team for
+initial contact, which oversees the process of handling such issues under
+embargo rules.
+
+The hardware security team identifies the developers (domain experts) which
+form the initial response team for a particular issue. The initial response
+team can bring in further developers (domain experts) to address the issue
+in the best technical way.
+
+All involved developers pledge to adhere to the embargo rules and to keep
+the received information confidential. Violation of the pledge will lead to
+immediate exclusion from the current issue and removal from all related
+mailing-lists. In addition, the hardware security team will also exclude
+the offender from future issues. The impact of this consequence is a highly
+effective deterrent in our community. In case a violation happens the
+hardware security team will inform the involved parties immediately. If you
+or anyone becomes aware of a potential violation, please report it
+immediately to the Hardware security officers.
+
+
+Process
+^^^^^^^
+
+Due to the globally distributed nature of Linux kernel development, face to
+face meetings are almost impossible to address hardware security issues.
+Phone conferences are hard to coordinate due to time zones and other
+factors and should be only used when absolutely necessary. Encrypted email
+has been proven to be the most effective and secure communication method
+for these types of issues.
+
+Start of Disclosure
+"""""""""""""""""""
+
+Disclosure starts by contacting the Linux kernel hardware security team by
+email. This initial contact should contain a description of the problem and
+a list of any known affected hardware. If your organization builds or
+distributes the affected hardware, we encourage you to also consider what
+other hardware could be affected.
+
+The hardware security team will provide a per incident specific encrypted
+mailing-list which will be used for initial discussion with the reporter,
+further disclosure and coordination.
+
+The hardware security team will provide the disclosing party a list of
+developers (domain experts) who should be informed initially about the
+issue after confirming with the developers  that they will adhere to this
+Memorandum of Understanding and the documented process. These developers
+form the initial response team and will be responsible for handling the
+issue after initial contact. The hardware security team is supporting the
+response team, but is not necessarily involved in the mitigation
+development process.
+
+While individual developers might be covered by a non-disclosure agreement
+via their employer, they cannot enter individual non-disclosure agreements
+in their role as Linux kernel developers. They will, however, adhere to
+this documented process and the Memorandum of Understanding.
+
+
+Disclosure
+""""""""""
+
+The disclosing party provides detailed information to the initial response
+team via the specific encrypted mailing-list.
+
+From our experience the technical documentation of these issues is usually
+a sufficient starting point and further technical clarification is best
+done via email.
+
+Mitigation development
+""""""""""""""""""""""
+
+The initial response team sets up an encrypted mailing-list or repurposes
+an existing one if appropriate. The disclosing party should provide a list
+of contacts for all other parties who have already been, or should be
+informed about the issue. The response team contacts these parties so they
+can name experts who should be subscribed to the mailing-list.
+
+Using a mailing-list is close to the normal Linux development process and
+has been successfully used in developing mitigations for various hardware
+security issues in the past.
+
+The mailing-list operates in the same way as normal Linux development.
+Patches are posted, discussed and reviewed and if agreed on applied to a
+non-public git repository which is only accessible to the participating
+developers via a secure connection. The repository contains the main
+development branch against the mainline kernel and backport branches for
+stable kernel versions as necessary.
+
+The initial response team will identify further experts from the Linux
+kernel developer community as needed and inform the disclosing party about
+their participation. Bringing in experts can happen at any time of the
+development process and often needs to be handled in a timely manner.
+
+Coordinated release
+"""""""""""""""""""
+
+The involved parties will negotiate the date and time where the embargo
+ends. At that point the prepared mitigations are integrated into the
+relevant kernel trees and published.
+
+While we understand that hardware security issues need coordinated embargo
+time, the embargo time should be constrained to the minimum time which is
+required for all involved parties to develop, test and prepare the
+mitigations. Extending embargo time artificially to meet conference talk
+dates or other non-technical reasons is creating more work and burden for
+the involved developers and response teams as the patches need to be kept
+up to date in order to follow the ongoing upstream kernel development,
+which might create conflicting changes.
+
+CVE assignment
+""""""""""""""
+
+Neither the hardware security team nor the initial response team assign
+CVEs, nor are CVEs required for the development process. If CVEs are
+provided by the disclosing party they can be used for documentation
+purposes.
+
+Process ambassadors
+-------------------
+
+For assistance with this process we have established ambassadors in various
+organizations, who can answer questions about or provide guidance on the
+reporting process and further handling. Ambassadors are not involved in the
+disclosure of a particular issue, unless requested by a response team or by
+an involved disclosed party. The current ambassadors list:
+
+  ============= ========================================================
+  ARM
+  AMD
+  IBM
+  Intel
+  Qualcomm
+
+  Microsoft
+  VMware
+  XEN
+
+  Canonical	Tyler Hicks <tyhicks@canonical.com>
+  Debian	Ben Hutchings <ben@decadent.org.uk>
+  Oracle	Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+  Red Hat	Josh Poimboeuf <jpoimboe@redhat.com>
+  SUSE		Jiri Kosina <jkosina@suse.cz>
+
+  Amazon
+  Google
+  ============== ========================================================
+
+If you want your organization to be added to the ambassadors list, please
+contact the hardware security team. The nominated ambassador has to
+understand and support our process fully and is ideally well connected in
+the Linux kernel community.
+
+Encrypted mailing-lists
+-----------------------
+
+We use encrypted mailing-lists for communication. The operating principle
+of these lists is that email sent to the list is encrypted either with the
+list's PGP key or with the list's S/MIME certificate. The mailing-list
+software decrypts the email and re-encrypts it individually for each
+subscriber with the subscriber's PGP key or S/MIME certificate. Details
+about the mailing-list software and the setup which is used to ensure the
+security of the lists and protection of the data can be found here:
+https://www.kernel.org/....
+
+List keys
+^^^^^^^^^
+
+For initial contact see :ref:`Contact`. For incident specific mailing-lists
+the key and S/MIME certificate are conveyed to the subscribers by email
+sent from the specific list.
+
+Subscription to incident specific lists
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Subscription is handled by the response teams. Disclosed parties who want
+to participate in the communication send a list of potential subscribers to
+the response team so the response team can validate subscription requests.
+
+Each subscriber needs to send a subscription request to the response team
+by email. The email must be signed with the subscriber's PGP key or S/MIME
+certificate. If a PGP key is used, it must be available from a public key
+server and is ideally connected to the Linux kernel's PGP web of trust. See
+also: https://www.kernel.org/signature.html.
+
+The response team verifies that the subscriber request is valid and adds
+the subscriber to the list. After subscription the subscriber will receive
+email from the mailing-list which is signed either with the list's PGP key
+or the list's S/MIME certificate. The subscriber's email client can extract
+the PGP key or the S/MIME certificate from the signature so the subscriber
+can send encrypted email to the list.
+
diff --git a/Documentation/admin-guide/index.rst b/Documentation/admin-guide/index.rst
index 0a491676685e..003585de3816 100644
--- a/Documentation/admin-guide/index.rst
+++ b/Documentation/admin-guide/index.rst
@@ -34,6 +34,7 @@ problems and bugs in particular.
 
    reporting-bugs
    security-bugs
+   embargoed-hardware-issues
    bug-hunting
    bug-bisect
    tainted-kernels

-- 
Jiri Kosina
SUSE Labs


^ permalink raw reply related

* Re: [PATCH 4/9] KVM: arm64: Support stolen time reporting via shared structure
From: Marc Zyngier @ 2019-08-03 18:13 UTC (permalink / raw)
  To: Steven Price
  Cc: kvm, Catalin Marinas, linux-doc, Russell King, linux-kernel,
	linux-arm-kernel, Paolo Bonzini, Will Deacon, kvmarm
In-Reply-To: <20190803185817.11285b2a@why>

On Sat, 3 Aug 2019 18:58:17 +0100
Marc Zyngier <maz@kernel.org> wrote:

> On Fri,  2 Aug 2019 15:50:12 +0100
> Steven Price <steven.price@arm.com> wrote:
> 
> > Implement the service call for configuring a shared structre between a
> > VCPU and the hypervisor in which the hypervisor can write the time
> > stolen from the VCPU's execution time by other tasks on the host.
> > 
> > The hypervisor allocates memory which is placed at an IPA chosen by user
> > space. The hypervisor then uses WRITE_ONCE() to update the shared
> > structre ensuring single copy atomicity of the 64-bit unsigned value
> > that reports stolen time in nanoseconds.
> > 
> > Whenever stolen time is enabled by the guest, the stolen time counter is
> > reset.
> > 
> > The stolen time itself is retrieved from the sched_info structure
> > maintained by the Linux scheduler code. We enable SCHEDSTATS when
> > selecting KVM Kconfig to ensure this value is meaningful.
> > 
> > Signed-off-by: Steven Price <steven.price@arm.com>
> > ---
> >  arch/arm64/include/asm/kvm_host.h | 13 +++++-
> >  arch/arm64/kvm/Kconfig            |  1 +
> >  include/kvm/arm_hypercalls.h      |  1 +
> >  include/linux/kvm_types.h         |  2 +
> >  virt/kvm/arm/arm.c                | 18 ++++++++
> >  virt/kvm/arm/hypercalls.c         | 70 +++++++++++++++++++++++++++++++
> >  6 files changed, 104 insertions(+), 1 deletion(-)
> > 
> > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> > index f656169db8c3..78f270190d43 100644
> > --- a/arch/arm64/include/asm/kvm_host.h
> > +++ b/arch/arm64/include/asm/kvm_host.h
> > @@ -44,6 +44,7 @@
> >  	KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
> >  #define KVM_REQ_IRQ_PENDING	KVM_ARCH_REQ(1)
> >  #define KVM_REQ_VCPU_RESET	KVM_ARCH_REQ(2)
> > +#define KVM_REQ_RECORD_STEAL	KVM_ARCH_REQ(3)
> >  
> >  DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
> >  
> > @@ -83,6 +84,11 @@ struct kvm_arch {
> >  
> >  	/* Mandated version of PSCI */
> >  	u32 psci_version;
> > +
> > +	struct kvm_arch_pvtime {
> > +		void *st;
> > +		gpa_t st_base;
> > +	} pvtime;
> >  };
> >  
> >  #define KVM_NR_MEM_OBJS     40
> > @@ -338,8 +344,13 @@ struct kvm_vcpu_arch {
> >  	/* True when deferrable sysregs are loaded on the physical CPU,
> >  	 * see kvm_vcpu_load_sysregs and kvm_vcpu_put_sysregs. */
> >  	bool sysregs_loaded_on_cpu;
> > -};
> >  
> > +	/* Guest PV state */
> > +	struct {
> > +		u64 steal;
> > +		u64 last_steal;
> > +	} steal;
> > +};
> >  /* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
> >  #define vcpu_sve_pffr(vcpu) ((void *)((char *)((vcpu)->arch.sve_state) + \
> >  				      sve_ffr_offset((vcpu)->arch.sve_max_vl)))
> > diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
> > index a67121d419a2..d8b88e40d223 100644
> > --- a/arch/arm64/kvm/Kconfig
> > +++ b/arch/arm64/kvm/Kconfig
> > @@ -39,6 +39,7 @@ config KVM
> >  	select IRQ_BYPASS_MANAGER
> >  	select HAVE_KVM_IRQ_BYPASS
> >  	select HAVE_KVM_VCPU_RUN_PID_CHANGE
> > +	select SCHEDSTATS
> >  	---help---
> >  	  Support hosting virtualized guest machines.
> >  	  We don't support KVM with 16K page tables yet, due to the multiple
> > diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
> > index 35a5abcc4ca3..9f0710ab4292 100644
> > --- a/include/kvm/arm_hypercalls.h
> > +++ b/include/kvm/arm_hypercalls.h
> > @@ -7,6 +7,7 @@
> >  #include <asm/kvm_emulate.h>
> >  
> >  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
> > +int kvm_update_stolen_time(struct kvm_vcpu *vcpu);
> >  
> >  static inline u32 smccc_get_function(struct kvm_vcpu *vcpu)
> >  {
> > diff --git a/include/linux/kvm_types.h b/include/linux/kvm_types.h
> > index bde5374ae021..1c88e69db3d9 100644
> > --- a/include/linux/kvm_types.h
> > +++ b/include/linux/kvm_types.h
> > @@ -35,6 +35,8 @@ typedef unsigned long  gva_t;
> >  typedef u64            gpa_t;
> >  typedef u64            gfn_t;
> >  
> > +#define GPA_INVALID	(~(gpa_t)0)
> > +
> >  typedef unsigned long  hva_t;
> >  typedef u64            hpa_t;
> >  typedef u64            hfn_t;
> > diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> > index f645c0fbf7ec..ebd963d2580b 100644
> > --- a/virt/kvm/arm/arm.c
> > +++ b/virt/kvm/arm/arm.c
> > @@ -40,6 +40,10 @@
> >  #include <asm/kvm_coproc.h>
> >  #include <asm/sections.h>
> >  
> > +#include <kvm/arm_hypercalls.h>
> > +#include <kvm/arm_pmu.h>
> > +#include <kvm/arm_psci.h>
> > +
> >  #ifdef REQUIRES_VIRT
> >  __asm__(".arch_extension	virt");
> >  #endif
> > @@ -135,6 +139,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
> >  	kvm->arch.max_vcpus = vgic_present ?
> >  				kvm_vgic_get_max_vcpus() : KVM_MAX_VCPUS;
> >  
> > +	kvm->arch.pvtime.st_base = GPA_INVALID;
> >  	return ret;
> >  out_free_stage2_pgd:
> >  	kvm_free_stage2_pgd(kvm);
> > @@ -371,6 +376,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
> >  	kvm_vcpu_load_sysregs(vcpu);
> >  	kvm_arch_vcpu_load_fp(vcpu);
> >  	kvm_vcpu_pmu_restore_guest(vcpu);
> > +	kvm_make_request(KVM_REQ_RECORD_STEAL, vcpu);
> >  
> >  	if (single_task_running())
> >  		vcpu_clear_wfe_traps(vcpu);
> > @@ -617,6 +623,15 @@ static void vcpu_req_sleep(struct kvm_vcpu *vcpu)
> >  	smp_rmb();
> >  }
> >  
> > +static void vcpu_req_record_steal(struct kvm_vcpu *vcpu)
> > +{
> > +	int idx;
> > +
> > +	idx = srcu_read_lock(&vcpu->kvm->srcu);
> > +	kvm_update_stolen_time(vcpu);
> > +	srcu_read_unlock(&vcpu->kvm->srcu, idx);
> > +}
> > +
> >  static int kvm_vcpu_initialized(struct kvm_vcpu *vcpu)
> >  {
> >  	return vcpu->arch.target >= 0;
> > @@ -636,6 +651,9 @@ static void check_vcpu_requests(struct kvm_vcpu *vcpu)
> >  		 * that a VCPU sees new virtual interrupts.
> >  		 */
> >  		kvm_check_request(KVM_REQ_IRQ_PENDING, vcpu);
> > +
> > +		if (kvm_check_request(KVM_REQ_RECORD_STEAL, vcpu))
> > +			vcpu_req_record_steal(vcpu);  
> 
> Something troubles me. Here, you've set the request on load. But you
> can be preempted at any time (preemption gets disabled just after).
> 
> I have the feeling that should you get preempted right here, you'll
> end-up having accumulated the wrong amount of steal time, as the
> request put via load when you'll get scheduled back in will only get
> processed after a full round of entry/exit/entry, which doesn't look
> great.

Ah, no. We're saved by the check for pending requests right before we
jump in the guest, causing an early exit and the whole shebang to be
restarted.

	M.
-- 
Without deviation from the norm, progress is not possible.

^ permalink raw reply

* Re: [PATCH 0/9] arm64: Stolen time support
From: Marc Zyngier @ 2019-08-03 18:05 UTC (permalink / raw)
  To: Steven Price
  Cc: Catalin Marinas, Paolo Bonzini, Radim Krčmář,
	Russell King, Will Deacon, James Morse, Julien Thierry,
	Suzuki K Pouloze, kvm, kvmarm, linux-arm-kernel, linux-doc,
	linux-kernel
In-Reply-To: <20190802145017.42543-1-steven.price@arm.com>

On Fri,  2 Aug 2019 15:50:08 +0100
Steven Price <steven.price@arm.com> wrote:

Hi Steven,

> This series add support for paravirtualized time for arm64 guests and
> KVM hosts following the specification in Arm's document DEN 0057A:
> 
> https://developer.arm.com/docs/den0057/a
> 
> It implements support for stolen time, allowing the guest to
> identify time when it is forcibly not executing.
> 
> It doesn't implement support for Live Physical Time (LPT) as there are
> some concerns about the overheads and approach in the above
> specification, and I expect an updated version of the specification to
> be released soon with just the stolen time parts.

Thanks for posting this.

My current concern with this series is around the fact that we allocate
memory from the kernel on behalf of the guest. It is the first example
of such thing in the ARM port, and I can't really say I'm fond of it.

x86 seems to get away with it by having the memory allocated from
userspace, why I tend to like more. Yes, put_user is more
expensive than a straight store, but this isn't done too often either.

What is the rational for your current approach?

Thanks,

	M.
-- 
Without deviation from the norm, progress is not possible.

^ permalink raw reply

* Re: [PATCH 4/9] KVM: arm64: Support stolen time reporting via shared structure
From: Marc Zyngier @ 2019-08-03 17:58 UTC (permalink / raw)
  To: Steven Price
  Cc: Catalin Marinas, Paolo Bonzini, Radim Krčmář,
	Russell King, Will Deacon, James Morse, Julien Thierry,
	Suzuki K Pouloze, kvm, kvmarm, linux-arm-kernel, linux-doc,
	linux-kernel
In-Reply-To: <20190802145017.42543-5-steven.price@arm.com>

On Fri,  2 Aug 2019 15:50:12 +0100
Steven Price <steven.price@arm.com> wrote:

> Implement the service call for configuring a shared structre between a
> VCPU and the hypervisor in which the hypervisor can write the time
> stolen from the VCPU's execution time by other tasks on the host.
> 
> The hypervisor allocates memory which is placed at an IPA chosen by user
> space. The hypervisor then uses WRITE_ONCE() to update the shared
> structre ensuring single copy atomicity of the 64-bit unsigned value
> that reports stolen time in nanoseconds.
> 
> Whenever stolen time is enabled by the guest, the stolen time counter is
> reset.
> 
> The stolen time itself is retrieved from the sched_info structure
> maintained by the Linux scheduler code. We enable SCHEDSTATS when
> selecting KVM Kconfig to ensure this value is meaningful.
> 
> Signed-off-by: Steven Price <steven.price@arm.com>
> ---
>  arch/arm64/include/asm/kvm_host.h | 13 +++++-
>  arch/arm64/kvm/Kconfig            |  1 +
>  include/kvm/arm_hypercalls.h      |  1 +
>  include/linux/kvm_types.h         |  2 +
>  virt/kvm/arm/arm.c                | 18 ++++++++
>  virt/kvm/arm/hypercalls.c         | 70 +++++++++++++++++++++++++++++++
>  6 files changed, 104 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index f656169db8c3..78f270190d43 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -44,6 +44,7 @@
>  	KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
>  #define KVM_REQ_IRQ_PENDING	KVM_ARCH_REQ(1)
>  #define KVM_REQ_VCPU_RESET	KVM_ARCH_REQ(2)
> +#define KVM_REQ_RECORD_STEAL	KVM_ARCH_REQ(3)
>  
>  DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
>  
> @@ -83,6 +84,11 @@ struct kvm_arch {
>  
>  	/* Mandated version of PSCI */
>  	u32 psci_version;
> +
> +	struct kvm_arch_pvtime {
> +		void *st;
> +		gpa_t st_base;
> +	} pvtime;
>  };
>  
>  #define KVM_NR_MEM_OBJS     40
> @@ -338,8 +344,13 @@ struct kvm_vcpu_arch {
>  	/* True when deferrable sysregs are loaded on the physical CPU,
>  	 * see kvm_vcpu_load_sysregs and kvm_vcpu_put_sysregs. */
>  	bool sysregs_loaded_on_cpu;
> -};
>  
> +	/* Guest PV state */
> +	struct {
> +		u64 steal;
> +		u64 last_steal;
> +	} steal;
> +};
>  /* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
>  #define vcpu_sve_pffr(vcpu) ((void *)((char *)((vcpu)->arch.sve_state) + \
>  				      sve_ffr_offset((vcpu)->arch.sve_max_vl)))
> diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
> index a67121d419a2..d8b88e40d223 100644
> --- a/arch/arm64/kvm/Kconfig
> +++ b/arch/arm64/kvm/Kconfig
> @@ -39,6 +39,7 @@ config KVM
>  	select IRQ_BYPASS_MANAGER
>  	select HAVE_KVM_IRQ_BYPASS
>  	select HAVE_KVM_VCPU_RUN_PID_CHANGE
> +	select SCHEDSTATS
>  	---help---
>  	  Support hosting virtualized guest machines.
>  	  We don't support KVM with 16K page tables yet, due to the multiple
> diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
> index 35a5abcc4ca3..9f0710ab4292 100644
> --- a/include/kvm/arm_hypercalls.h
> +++ b/include/kvm/arm_hypercalls.h
> @@ -7,6 +7,7 @@
>  #include <asm/kvm_emulate.h>
>  
>  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
> +int kvm_update_stolen_time(struct kvm_vcpu *vcpu);
>  
>  static inline u32 smccc_get_function(struct kvm_vcpu *vcpu)
>  {
> diff --git a/include/linux/kvm_types.h b/include/linux/kvm_types.h
> index bde5374ae021..1c88e69db3d9 100644
> --- a/include/linux/kvm_types.h
> +++ b/include/linux/kvm_types.h
> @@ -35,6 +35,8 @@ typedef unsigned long  gva_t;
>  typedef u64            gpa_t;
>  typedef u64            gfn_t;
>  
> +#define GPA_INVALID	(~(gpa_t)0)
> +
>  typedef unsigned long  hva_t;
>  typedef u64            hpa_t;
>  typedef u64            hfn_t;
> diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> index f645c0fbf7ec..ebd963d2580b 100644
> --- a/virt/kvm/arm/arm.c
> +++ b/virt/kvm/arm/arm.c
> @@ -40,6 +40,10 @@
>  #include <asm/kvm_coproc.h>
>  #include <asm/sections.h>
>  
> +#include <kvm/arm_hypercalls.h>
> +#include <kvm/arm_pmu.h>
> +#include <kvm/arm_psci.h>
> +
>  #ifdef REQUIRES_VIRT
>  __asm__(".arch_extension	virt");
>  #endif
> @@ -135,6 +139,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
>  	kvm->arch.max_vcpus = vgic_present ?
>  				kvm_vgic_get_max_vcpus() : KVM_MAX_VCPUS;
>  
> +	kvm->arch.pvtime.st_base = GPA_INVALID;
>  	return ret;
>  out_free_stage2_pgd:
>  	kvm_free_stage2_pgd(kvm);
> @@ -371,6 +376,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
>  	kvm_vcpu_load_sysregs(vcpu);
>  	kvm_arch_vcpu_load_fp(vcpu);
>  	kvm_vcpu_pmu_restore_guest(vcpu);
> +	kvm_make_request(KVM_REQ_RECORD_STEAL, vcpu);
>  
>  	if (single_task_running())
>  		vcpu_clear_wfe_traps(vcpu);
> @@ -617,6 +623,15 @@ static void vcpu_req_sleep(struct kvm_vcpu *vcpu)
>  	smp_rmb();
>  }
>  
> +static void vcpu_req_record_steal(struct kvm_vcpu *vcpu)
> +{
> +	int idx;
> +
> +	idx = srcu_read_lock(&vcpu->kvm->srcu);
> +	kvm_update_stolen_time(vcpu);
> +	srcu_read_unlock(&vcpu->kvm->srcu, idx);
> +}
> +
>  static int kvm_vcpu_initialized(struct kvm_vcpu *vcpu)
>  {
>  	return vcpu->arch.target >= 0;
> @@ -636,6 +651,9 @@ static void check_vcpu_requests(struct kvm_vcpu *vcpu)
>  		 * that a VCPU sees new virtual interrupts.
>  		 */
>  		kvm_check_request(KVM_REQ_IRQ_PENDING, vcpu);
> +
> +		if (kvm_check_request(KVM_REQ_RECORD_STEAL, vcpu))
> +			vcpu_req_record_steal(vcpu);

Something troubles me. Here, you've set the request on load. But you
can be preempted at any time (preemption gets disabled just after).

I have the feeling that should you get preempted right here, you'll
end-up having accumulated the wrong amount of steal time, as the
request put via load when you'll get scheduled back in will only get
processed after a full round of entry/exit/entry, which doesn't look
great.

Am I getting it right?

	M.
-- 
Without deviation from the norm, progress is not possible.

^ permalink raw reply

* Re: [PATCH 6/9] KVM: arm64: Provide a PV_TIME device to user space
From: Marc Zyngier @ 2019-08-03 17:34 UTC (permalink / raw)
  To: Steven Price
  Cc: kvm, Catalin Marinas, linux-doc, Russell King, linux-kernel,
	linux-arm-kernel, Paolo Bonzini, Will Deacon, kvmarm
In-Reply-To: <20190803135113.6cdf500c@why>

On Sat, 3 Aug 2019 13:51:13 +0100
Marc Zyngier <maz@kernel.org> wrote:

[forgot that one]

> On Fri,  2 Aug 2019 15:50:14 +0100
> Steven Price <steven.price@arm.com> wrote:

[...]

> > +static int __init kvm_pvtime_init(void)
> > +{
> > +	kvm_register_device_ops(&pvtime_ops, KVM_DEV_TYPE_ARM_PV_TIME);
> > +
> > +	return 0;
> > +}
> > +
> > +late_initcall(kvm_pvtime_init);

Why is it an initcall? So far, the only initcall we've used is the one
that initializes KVM itself. Can't we just the device_ops just like we
do for the vgic?

	M.
-- 
Without deviation from the norm, progress is not possible.

^ permalink raw reply

* Re: [PATCH 6/9] KVM: arm64: Provide a PV_TIME device to user space
From: Marc Zyngier @ 2019-08-03 12:51 UTC (permalink / raw)
  To: Steven Price
  Cc: Catalin Marinas, Paolo Bonzini, Radim Krčmář,
	Russell King, Will Deacon, James Morse, Julien Thierry,
	Suzuki K Pouloze, kvm, kvmarm, linux-arm-kernel, linux-doc,
	linux-kernel
In-Reply-To: <20190802145017.42543-7-steven.price@arm.com>

On Fri,  2 Aug 2019 15:50:14 +0100
Steven Price <steven.price@arm.com> wrote:

> Allow user space to inform the KVM host where in the physical memory
> map the paravirtualized time structures should be located.
> 
> A device is created which provides the base address of an array of
> Stolen Time (ST) structures, one for each VCPU. There must be (64 *
> total number of VCPUs) bytes of memory available at this location.
> 
> The address is given in terms of the physical address visible to
> the guest and must be 64 byte aligned. The memory should be marked as
> reserved to the guest to stop it allocating it for other purposes.

Why? You seem to be allocating the memory from the kernel, so as far as
the guest is concerned, this isn't generally usable memory.

> 
> Signed-off-by: Steven Price <steven.price@arm.com>
> ---
>  arch/arm64/include/asm/kvm_mmu.h  |   2 +
>  arch/arm64/include/uapi/asm/kvm.h |   6 +
>  arch/arm64/kvm/Makefile           |   1 +
>  include/uapi/linux/kvm.h          |   2 +
>  virt/kvm/arm/mmu.c                |  44 +++++++
>  virt/kvm/arm/pvtime.c             | 190 ++++++++++++++++++++++++++++++
>  6 files changed, 245 insertions(+)
>  create mode 100644 virt/kvm/arm/pvtime.c
> 
> diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
> index befe37d4bc0e..88c8a4b2836f 100644
> --- a/arch/arm64/include/asm/kvm_mmu.h
> +++ b/arch/arm64/include/asm/kvm_mmu.h
> @@ -157,6 +157,8 @@ int kvm_alloc_stage2_pgd(struct kvm *kvm);
>  void kvm_free_stage2_pgd(struct kvm *kvm);
>  int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa,
>  			  phys_addr_t pa, unsigned long size, bool writable);
> +int kvm_phys_addr_memremap(struct kvm *kvm, phys_addr_t guest_ipa,
> +			  phys_addr_t pa, unsigned long size, bool writable);
>  
>  int kvm_handle_guest_abort(struct kvm_vcpu *vcpu, struct kvm_run *run);
>  
> diff --git a/arch/arm64/include/uapi/asm/kvm.h b/arch/arm64/include/uapi/asm/kvm.h
> index 9a507716ae2f..95516a4198ea 100644
> --- a/arch/arm64/include/uapi/asm/kvm.h
> +++ b/arch/arm64/include/uapi/asm/kvm.h
> @@ -367,6 +367,12 @@ struct kvm_vcpu_events {
>  #define KVM_PSCI_RET_INVAL		PSCI_RET_INVALID_PARAMS
>  #define KVM_PSCI_RET_DENIED		PSCI_RET_DENIED
>  
> +/* Device Control API: PV_TIME */
> +#define KVM_DEV_ARM_PV_TIME_PADDR	0
> +#define  KVM_DEV_ARM_PV_TIME_ST		0
> +#define KVM_DEV_ARM_PV_TIME_STATE_SIZE	1
> +#define KVM_DEV_ARM_PV_TIME_STATE	2
> +
>  #endif
>  
>  #endif /* __ARM_KVM_H__ */
> diff --git a/arch/arm64/kvm/Makefile b/arch/arm64/kvm/Makefile
> index 73dce4d47d47..5ffbdc39e780 100644
> --- a/arch/arm64/kvm/Makefile
> +++ b/arch/arm64/kvm/Makefile
> @@ -14,6 +14,7 @@ kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o $(KVM)/e
>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/arm.o $(KVM)/arm/mmu.o $(KVM)/arm/mmio.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/psci.o $(KVM)/arm/perf.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/hypercalls.o
> +kvm-$(CONFIG_KVM_ARM_HOST) += $(KVM)/arm/pvtime.o
>  
>  kvm-$(CONFIG_KVM_ARM_HOST) += inject_fault.o regmap.o va_layout.o
>  kvm-$(CONFIG_KVM_ARM_HOST) += hyp.o hyp-init.o handle_exit.o
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index a7c19540ce21..04bffafa0708 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -1222,6 +1222,8 @@ enum kvm_device_type {
>  #define KVM_DEV_TYPE_ARM_VGIC_ITS	KVM_DEV_TYPE_ARM_VGIC_ITS
>  	KVM_DEV_TYPE_XIVE,
>  #define KVM_DEV_TYPE_XIVE		KVM_DEV_TYPE_XIVE
> +	KVM_DEV_TYPE_ARM_PV_TIME,
> +#define KVM_DEV_TYPE_ARM_PV_TIME	KVM_DEV_TYPE_ARM_PV_TIME
>  	KVM_DEV_TYPE_MAX,
>  };
>  
> diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c
> index 38b4c910b6c3..be28a4aee451 100644
> --- a/virt/kvm/arm/mmu.c
> +++ b/virt/kvm/arm/mmu.c
> @@ -1368,6 +1368,50 @@ int kvm_phys_addr_ioremap(struct kvm *kvm, phys_addr_t guest_ipa,
>  	return ret;
>  }
>  
> +/**
> + * kvm_phys_addr_memremap - map a memory range to guest IPA
> + *
> + * @kvm:	The KVM pointer
> + * @guest_ipa:	The IPA at which to insert the mapping
> + * @pa:		The physical address of the memory
> + * @size:	The size of the mapping
> + */
> +int kvm_phys_addr_memremap(struct kvm *kvm, phys_addr_t guest_ipa,
> +			  phys_addr_t pa, unsigned long size, bool writable)
> +{
> +	phys_addr_t addr, end;
> +	int ret = 0;
> +	unsigned long pfn;
> +	struct kvm_mmu_memory_cache cache = { 0, };
> +
> +	end = (guest_ipa + size + PAGE_SIZE - 1) & PAGE_MASK;
> +	pfn = __phys_to_pfn(pa);
> +
> +	for (addr = guest_ipa; addr < end; addr += PAGE_SIZE) {
> +		pte_t pte = pfn_pte(pfn, PAGE_S2);
> +
> +		if (writable)
> +			pte = kvm_s2pte_mkwrite(pte);
> +
> +		ret = mmu_topup_memory_cache(&cache,
> +					     kvm_mmu_cache_min_pages(kvm),
> +					     KVM_NR_MEM_OBJS);
> +		if (ret)
> +			goto out;
> +		spin_lock(&kvm->mmu_lock);
> +		ret = stage2_set_pte(kvm, &cache, addr, &pte, 0);
> +		spin_unlock(&kvm->mmu_lock);
> +		if (ret)
> +			goto out;
> +
> +		pfn++;
> +	}
> +
> +out:
> +	mmu_free_memory_cache(&cache);
> +	return ret;
> +}

This is an exact copy of kvm_phys_addr_ioremap(), with only the memory
attributes changing. Surely we can have a shared implementation that
takes the memory attribute as a parameter.

> +
>  static bool transparent_hugepage_adjust(kvm_pfn_t *pfnp, phys_addr_t *ipap)
>  {
>  	kvm_pfn_t pfn = *pfnp;
> diff --git a/virt/kvm/arm/pvtime.c b/virt/kvm/arm/pvtime.c
> new file mode 100644
> index 000000000000..9051bc07eae1
> --- /dev/null
> +++ b/virt/kvm/arm/pvtime.c
> @@ -0,0 +1,190 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Copyright (C) 2019 Arm Ltd.
> +
> +#include <linux/kvm_host.h>
> +#include <asm/kvm_mmu.h>
> +
> +/* We currently only support PV time on ARM64 */
> +#ifdef CONFIG_ARM64

And we're only compiling it on arm64, so why the #ifdef?

> +
> +#include <asm/pvclock-abi.h>
> +
> +static int max_stolen_size(void)
> +{
> +	int size = KVM_MAX_VCPUS * sizeof(struct pvclock_vcpu_stolen_time_info);

So we're always allocating enough memory for 512 CPUs? That's an
additional 32kB of contiguous memory...

> +
> +	return ALIGN(size, PAGE_SIZE);
> +}
> +
> +static int kvm_arm_pvtime_create(struct kvm_device *dev, u32 type)
> +{
> +	struct kvm_arch_pvtime *pvtime = &dev->kvm->arch.pvtime;
> +
> +	pvtime->st = alloc_pages_exact(max_stolen_size(),
> +				       GFP_KERNEL | __GFP_ZERO);
> +	if (!pvtime->st)
> +		return -ENOMEM;

Is there any chance we could use a vmalloc allocation instead? This
would lift the requirement on having physically contiguous memory.

> +
> +	return 0;
> +}
> +
> +static void kvm_arm_pvtime_destroy(struct kvm_device *dev)
> +{
> +	struct kvm_arch_pvtime *pvtime = &dev->kvm->arch.pvtime;
> +
> +	pvtime->st_base = GPA_INVALID;
> +	free_pages_exact(pvtime->st, max_stolen_size());
> +	kfree(dev);
> +}
> +
> +static int pvtime_map_pages(struct kvm *kvm, gpa_t guest_paddr,
> +			    void *kaddr, int size)
> +{
> +	return kvm_phys_addr_memremap(kvm, guest_paddr,
> +			virt_to_phys(kaddr),
> +			size, false);
> +}
> +
> +static int pvtime_save_state(struct kvm *kvm, u64 type, void __user *user)
> +{
> +	void *source;
> +	size_t size;
> +
> +	switch (type) {
> +	case KVM_DEV_ARM_PV_TIME_ST:
> +		source = kvm->arch.pvtime.st;
> +		size = sizeof(struct pvclock_vcpu_stolen_time_info) *
> +			atomic_read(&kvm->online_vcpus);
> +		break;
> +	default:
> +		return -ENXIO;
> +	}
> +
> +	if (copy_to_user(user, source, size))
> +		return -EFAULT;
> +	return 0;
> +}
> +
> +static int pvtime_restore_state(struct kvm *kvm, u64 type, void __user *user)
> +{
> +	void *dest;
> +	size_t size;
> +
> +	switch (type) {
> +	case KVM_DEV_ARM_PV_TIME_ST:
> +		dest = kvm->arch.pvtime.st;
> +		size = sizeof(struct pvclock_vcpu_stolen_time_info) *
> +			atomic_read(&kvm->online_vcpus);
> +		break;
> +	default:
> +		return -ENXIO;
> +	}
> +
> +	if (copy_from_user(dest, user, size))
> +		return -EFAULT;
> +
> +	return 0;
> +}
> +
> +static int kvm_arm_pvtime_set_attr(struct kvm_device *dev,
> +				   struct kvm_device_attr *attr)
> +{
> +	struct kvm_arch_pvtime *pvtime = &dev->kvm->arch.pvtime;
> +	u64 __user *user = (u64 __user *)attr->addr;
> +	u64 paddr;
> +	int ret;
> +
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_PV_TIME_PADDR:
> +		if (get_user(paddr, user))
> +			return -EFAULT;
> +		if (paddr & 63)
> +			return -EINVAL;

You should check whether the device fits into the IPA space for this
guest, and whether it overlaps with anything else.

> +		switch (attr->attr) {
> +		case KVM_DEV_ARM_PV_TIME_ST:
> +			if (pvtime->st_base != GPA_INVALID)
> +				return -EEXIST;
> +			ret = pvtime_map_pages(dev->kvm, paddr, pvtime->st,
> +					max_stolen_size());

Consider moving the size directly into pvtime_map_pages(), and dropping
the pvtime->st parameter. All you need is kvm and paddr.

> +			if (ret)
> +				return ret;
> +			pvtime->st_base = paddr;
> +			return 0;
> +		}
> +		break;
> +	case KVM_DEV_ARM_PV_TIME_STATE_SIZE:
> +		return -EPERM;
> +	case KVM_DEV_ARM_PV_TIME_STATE:
> +		return pvtime_restore_state(dev->kvm, attr->attr, user);
> +	}
> +	return -ENXIO;
> +}
> +
> +static int kvm_arm_pvtime_get_attr(struct kvm_device *dev,
> +				   struct kvm_device_attr *attr)
> +{
> +	u64 __user *user = (u64 __user *)attr->addr;
> +	u32 size;
> +
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_PV_TIME_PADDR:
> +		switch (attr->attr) {
> +		case KVM_DEV_ARM_PV_TIME_ST:
> +			if (put_user(dev->kvm->arch.pvtime.st_base, user))
> +				return -EFAULT;
> +			return 0;
> +		}
> +		break;
> +	case KVM_DEV_ARM_PV_TIME_STATE_SIZE:
> +		switch (attr->attr) {
> +		case KVM_DEV_ARM_PV_TIME_ST:
> +			size = sizeof(struct pvclock_vcpu_stolen_time_info);
> +			size *= atomic_read(&dev->kvm->online_vcpus);
> +			break;
> +		default:
> +			return -ENXIO;
> +		}
> +		if (put_user(size, user))
> +			return -EFAULT;
> +		return 0;
> +	case KVM_DEV_ARM_PV_TIME_STATE:
> +		return pvtime_save_state(dev->kvm, attr->attr, user);
> +	}
> +	return -ENXIO;
> +}
> +
> +static int kvm_arm_pvtime_has_attr(struct kvm_device *dev,
> +				   struct kvm_device_attr *attr)
> +{
> +	switch (attr->group) {
> +	case KVM_DEV_ARM_PV_TIME_PADDR:
> +	case KVM_DEV_ARM_PV_TIME_STATE_SIZE:
> +	case KVM_DEV_ARM_PV_TIME_STATE:
> +		switch (attr->attr) {
> +		case KVM_DEV_ARM_PV_TIME_ST:
> +			return 0;
> +		}
> +		break;
> +	}
> +	return -ENXIO;
> +}
> +
> +static const struct kvm_device_ops pvtime_ops = {
> +	"Arm PV time",
> +	.create = kvm_arm_pvtime_create,
> +	.destroy = kvm_arm_pvtime_destroy,
> +	.set_attr = kvm_arm_pvtime_set_attr,
> +	.get_attr = kvm_arm_pvtime_get_attr,
> +	.has_attr = kvm_arm_pvtime_has_attr
> +};
> +
> +static int __init kvm_pvtime_init(void)
> +{
> +	kvm_register_device_ops(&pvtime_ops, KVM_DEV_TYPE_ARM_PV_TIME);
> +
> +	return 0;
> +}
> +
> +late_initcall(kvm_pvtime_init);
> +
> +#endif

Thanks,

	M.
-- 
Without deviation from the norm, progress is not possible.

^ permalink raw reply

* Re: [PATCH 4/9] KVM: arm64: Support stolen time reporting via shared structure
From: Marc Zyngier @ 2019-08-03 11:55 UTC (permalink / raw)
  To: Steven Price
  Cc: Catalin Marinas, Paolo Bonzini, Radim Krčmář,
	Russell King, Will Deacon, James Morse, Julien Thierry,
	Suzuki K Pouloze, kvm, kvmarm, linux-arm-kernel, linux-doc,
	linux-kernel
In-Reply-To: <20190802145017.42543-5-steven.price@arm.com>

On Fri,  2 Aug 2019 15:50:12 +0100
Steven Price <steven.price@arm.com> wrote:

> Implement the service call for configuring a shared structre between a

structure

> VCPU and the hypervisor in which the hypervisor can write the time
> stolen from the VCPU's execution time by other tasks on the host.
> 
> The hypervisor allocates memory which is placed at an IPA chosen by user
> space. The hypervisor then uses WRITE_ONCE() to update the shared
> structre ensuring single copy atomicity of the 64-bit unsigned value

structure

> that reports stolen time in nanoseconds.
> 
> Whenever stolen time is enabled by the guest, the stolen time counter is
> reset.
> 
> The stolen time itself is retrieved from the sched_info structure
> maintained by the Linux scheduler code. We enable SCHEDSTATS when
> selecting KVM Kconfig to ensure this value is meaningful.
> 
> Signed-off-by: Steven Price <steven.price@arm.com>
> ---
>  arch/arm64/include/asm/kvm_host.h | 13 +++++-
>  arch/arm64/kvm/Kconfig            |  1 +
>  include/kvm/arm_hypercalls.h      |  1 +
>  include/linux/kvm_types.h         |  2 +
>  virt/kvm/arm/arm.c                | 18 ++++++++
>  virt/kvm/arm/hypercalls.c         | 70 +++++++++++++++++++++++++++++++
>  6 files changed, 104 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index f656169db8c3..78f270190d43 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -44,6 +44,7 @@
>  	KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP)
>  #define KVM_REQ_IRQ_PENDING	KVM_ARCH_REQ(1)
>  #define KVM_REQ_VCPU_RESET	KVM_ARCH_REQ(2)
> +#define KVM_REQ_RECORD_STEAL	KVM_ARCH_REQ(3)
>  
>  DECLARE_STATIC_KEY_FALSE(userspace_irqchip_in_use);
>  
> @@ -83,6 +84,11 @@ struct kvm_arch {
>  
>  	/* Mandated version of PSCI */
>  	u32 psci_version;
> +
> +	struct kvm_arch_pvtime {
> +		void *st;

Is it really a void *? I'm sure you can use a proper type here...

> +		gpa_t st_base;
> +	} pvtime;
>  };
>  
>  #define KVM_NR_MEM_OBJS     40
> @@ -338,8 +344,13 @@ struct kvm_vcpu_arch {
>  	/* True when deferrable sysregs are loaded on the physical CPU,
>  	 * see kvm_vcpu_load_sysregs and kvm_vcpu_put_sysregs. */
>  	bool sysregs_loaded_on_cpu;
> -};
>  
> +	/* Guest PV state */
> +	struct {
> +		u64 steal;
> +		u64 last_steal;
> +	} steal;
> +};
>  /* Pointer to the vcpu's SVE FFR for sve_{save,load}_state() */
>  #define vcpu_sve_pffr(vcpu) ((void *)((char *)((vcpu)->arch.sve_state) + \
>  				      sve_ffr_offset((vcpu)->arch.sve_max_vl)))
> diff --git a/arch/arm64/kvm/Kconfig b/arch/arm64/kvm/Kconfig
> index a67121d419a2..d8b88e40d223 100644
> --- a/arch/arm64/kvm/Kconfig
> +++ b/arch/arm64/kvm/Kconfig
> @@ -39,6 +39,7 @@ config KVM
>  	select IRQ_BYPASS_MANAGER
>  	select HAVE_KVM_IRQ_BYPASS
>  	select HAVE_KVM_VCPU_RUN_PID_CHANGE
> +	select SCHEDSTATS
>  	---help---
>  	  Support hosting virtualized guest machines.
>  	  We don't support KVM with 16K page tables yet, due to the multiple
> diff --git a/include/kvm/arm_hypercalls.h b/include/kvm/arm_hypercalls.h
> index 35a5abcc4ca3..9f0710ab4292 100644
> --- a/include/kvm/arm_hypercalls.h
> +++ b/include/kvm/arm_hypercalls.h
> @@ -7,6 +7,7 @@
>  #include <asm/kvm_emulate.h>
>  
>  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu);
> +int kvm_update_stolen_time(struct kvm_vcpu *vcpu);
>  
>  static inline u32 smccc_get_function(struct kvm_vcpu *vcpu)
>  {
> diff --git a/include/linux/kvm_types.h b/include/linux/kvm_types.h
> index bde5374ae021..1c88e69db3d9 100644
> --- a/include/linux/kvm_types.h
> +++ b/include/linux/kvm_types.h
> @@ -35,6 +35,8 @@ typedef unsigned long  gva_t;
>  typedef u64            gpa_t;
>  typedef u64            gfn_t;
>  
> +#define GPA_INVALID	(~(gpa_t)0)
> +
>  typedef unsigned long  hva_t;
>  typedef u64            hpa_t;
>  typedef u64            hfn_t;
> diff --git a/virt/kvm/arm/arm.c b/virt/kvm/arm/arm.c
> index f645c0fbf7ec..ebd963d2580b 100644
> --- a/virt/kvm/arm/arm.c
> +++ b/virt/kvm/arm/arm.c
> @@ -40,6 +40,10 @@
>  #include <asm/kvm_coproc.h>
>  #include <asm/sections.h>
>  
> +#include <kvm/arm_hypercalls.h>
> +#include <kvm/arm_pmu.h>
> +#include <kvm/arm_psci.h>
> +
>  #ifdef REQUIRES_VIRT
>  __asm__(".arch_extension	virt");
>  #endif
> @@ -135,6 +139,7 @@ int kvm_arch_init_vm(struct kvm *kvm, unsigned long type)
>  	kvm->arch.max_vcpus = vgic_present ?
>  				kvm_vgic_get_max_vcpus() : KVM_MAX_VCPUS;
>  
> +	kvm->arch.pvtime.st_base = GPA_INVALID;
>  	return ret;
>  out_free_stage2_pgd:
>  	kvm_free_stage2_pgd(kvm);
> @@ -371,6 +376,7 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
>  	kvm_vcpu_load_sysregs(vcpu);
>  	kvm_arch_vcpu_load_fp(vcpu);
>  	kvm_vcpu_pmu_restore_guest(vcpu);
> +	kvm_make_request(KVM_REQ_RECORD_STEAL, vcpu);
>  
>  	if (single_task_running())
>  		vcpu_clear_wfe_traps(vcpu);
> @@ -617,6 +623,15 @@ static void vcpu_req_sleep(struct kvm_vcpu *vcpu)
>  	smp_rmb();
>  }
>  
> +static void vcpu_req_record_steal(struct kvm_vcpu *vcpu)
> +{
> +	int idx;
> +
> +	idx = srcu_read_lock(&vcpu->kvm->srcu);
> +	kvm_update_stolen_time(vcpu);
> +	srcu_read_unlock(&vcpu->kvm->srcu, idx);
> +}
> +
>  static int kvm_vcpu_initialized(struct kvm_vcpu *vcpu)
>  {
>  	return vcpu->arch.target >= 0;
> @@ -636,6 +651,9 @@ static void check_vcpu_requests(struct kvm_vcpu *vcpu)
>  		 * that a VCPU sees new virtual interrupts.
>  		 */
>  		kvm_check_request(KVM_REQ_IRQ_PENDING, vcpu);
> +
> +		if (kvm_check_request(KVM_REQ_RECORD_STEAL, vcpu))
> +			vcpu_req_record_steal(vcpu);
>  	}
>  }
>  
> diff --git a/virt/kvm/arm/hypercalls.c b/virt/kvm/arm/hypercalls.c
> index 2906b2df99df..196c71c8dd87 100644
> --- a/virt/kvm/arm/hypercalls.c
> +++ b/virt/kvm/arm/hypercalls.c
> @@ -10,6 +10,70 @@
>  #include <kvm/arm_hypercalls.h>
>  #include <kvm/arm_psci.h>
>  
> +
> +static struct pvclock_vcpu_stolen_time_info *pvtime_get_st(
> +		struct kvm_vcpu *vcpu)

nit: on a single line.

> +{
> +	struct pvclock_vcpu_stolen_time_info *st = vcpu->kvm->arch.pvtime.st;
> +
> +	if (!st)
> +		return NULL;
> +
> +	return &st[kvm_vcpu_get_idx(vcpu)];
> +}
> +
> +int kvm_update_stolen_time(struct kvm_vcpu *vcpu)
> +{
> +	u64 steal;
> +	struct pvclock_vcpu_stolen_time_info *kaddr;
> +
> +	if (vcpu->kvm->arch.pvtime.st_base == GPA_INVALID)
> +		return -ENOTSUPP;

So for a guest that doesn't have stolen time support (which is 100% of
them for the foreseeable future), we still set a request, take the srcu
lock and end-up here for nothing. I'd rather we test this st_base
early, as it should never change once the guest has started.

> +
> +	kaddr = pvtime_get_st(vcpu);
> +
> +	if (!kaddr)
> +		return -ENOTSUPP;

How can this happen?

> +
> +	kaddr->revision = 0;
> +	kaddr->attributes = 0;

Why does this need to be written each time we update the stolen time? I
have the feeling this would be better moved to the hypercall
initializing the data structure.

> +
> +	/* Let's do the local bookkeeping */
> +	steal = vcpu->arch.steal.steal;
> +	steal += current->sched_info.run_delay - vcpu->arch.steal.last_steal;
> +	vcpu->arch.steal.last_steal = current->sched_info.run_delay;
> +	vcpu->arch.steal.steal = steal;
> +
> +	/* Now write out the value to the shared page */
> +	WRITE_ONCE(kaddr->stolen_time, cpu_to_le64(steal));

Is there any requirement for this to be visible to another CPU than the
one this is being written from?

> +
> +	return 0;
> +}
> +
> +static int kvm_hypercall_stolen_time(struct kvm_vcpu *vcpu)
> +{
> +	u64 ret;
> +	int err;
> +
> +	/*
> +	 * Start counting stolen time from the time the guest requests
> +	 * the feature enabled.
> +	 */
> +	vcpu->arch.steal.steal = 0;
> +	vcpu->arch.steal.last_steal = current->sched_info.run_delay;
> +
> +	err = kvm_update_stolen_time(vcpu);
> +
> +	if (err)
> +		ret = SMCCC_RET_NOT_SUPPORTED;
> +	else
> +		ret = vcpu->kvm->arch.pvtime.st_base +
> +			(sizeof(struct pvclock_vcpu_stolen_time_info) *
> +			 kvm_vcpu_get_idx(vcpu));
> +
> +	smccc_set_retval(vcpu, ret, 0, 0, 0);
> +	return 1;
> +}
>  int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>  {
>  	u32 func_id = smccc_get_function(vcpu);
> @@ -57,8 +121,14 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>  	case ARM_SMCCC_HV_PV_FEATURES:
>  		feature = smccc_get_arg1(vcpu);
>  		switch (feature) {
> +		case ARM_SMCCC_HV_PV_FEATURES:
> +		case ARM_SMCCC_HV_PV_TIME_ST:
> +			val = SMCCC_RET_SUCCESS;
> +			break;
>  		}
>  		break;
> +	case ARM_SMCCC_HV_PV_TIME_ST:
> +		return kvm_hypercall_stolen_time(vcpu);
>  	default:
>  		return kvm_psci_call(vcpu);
>  	}


Thanks,

	M.
-- 
Without deviation from the norm, progress is not possible.

^ permalink raw reply

* Re: [PATCH 1/9] KVM: arm64: Document PV-time interface
From: Marc Zyngier @ 2019-08-03 11:13 UTC (permalink / raw)
  To: Steven Price
  Cc: Catalin Marinas, Paolo Bonzini, Radim Krčmář,
	Russell King, Will Deacon, James Morse, Julien Thierry,
	Suzuki K Pouloze, kvm, kvmarm, linux-arm-kernel, linux-doc,
	linux-kernel, peter.maydell
In-Reply-To: <20190802145017.42543-2-steven.price@arm.com>

On Fri,  2 Aug 2019 15:50:09 +0100
Steven Price <steven.price@arm.com> wrote:

[+Peter for the userspace aspect of things]

Hi Steve,

> Introduce a paravirtualization interface for KVM/arm64 based on the
> "Arm Paravirtualized Time for Arm-Base Systems" specification DEN 0057A.
> 
> This only adds the details about "Stolen Time" as the details of "Live
> Physical Time" have not been fully agreed.
> 
> User space can specify a reserved area of memory for the guest and
> inform KVM to populate the memory with information on time that the host
> kernel has stolen from the guest.
> 
> A hypercall interface is provided for the guest to interrogate the
> hypervisor's support for this interface and the location of the shared
> memory structures.
> 
> Signed-off-by: Steven Price <steven.price@arm.com>
> ---
>  Documentation/virtual/kvm/arm/pvtime.txt | 107 +++++++++++++++++++++++
>  1 file changed, 107 insertions(+)
>  create mode 100644 Documentation/virtual/kvm/arm/pvtime.txt
> 
> diff --git a/Documentation/virtual/kvm/arm/pvtime.txt b/Documentation/virtual/kvm/arm/pvtime.txt
> new file mode 100644
> index 000000000000..e6ae9799e1d5
> --- /dev/null
> +++ b/Documentation/virtual/kvm/arm/pvtime.txt
> @@ -0,0 +1,107 @@
> +Paravirtualized time support for arm64
> +======================================
> +
> +Arm specification DEN0057/A defined a standard for paravirtualised time
> +support for Aarch64 guests:

nit: AArch64

> +
> +https://developer.arm.com/docs/den0057/a

Between this file and the above document, which one is authoritative?

> +
> +KVM/Arm64 implements the stolen time part of this specification by providing

nit: KVM/arm64

> +some hypervisor service calls to support a paravirtualized guest obtaining a
> +view of the amount of time stolen from its execution.
> +
> +Two new SMCCC compatible hypercalls are defined:
> +
> +PV_FEATURES 0xC5000020
> +PV_TIME_ST  0xC5000022
> +
> +These are only available in the SMC64/HVC64 calling convention as
> +paravirtualized time is not available to 32 bit Arm guests.
> +
> +PV_FEATURES
> +    Function ID:  (uint32)  : 0xC5000020
> +    PV_func_id:   (uint32)  : Either PV_TIME_LPT or PV_TIME_ST
> +    Return value: (int32)   : NOT_SUPPORTED (-1) or SUCCESS (0) if the relevant
> +                              PV-time feature is supported by the hypervisor.

How is PV_FEATURES discovered? Is the intention to make it a generic
ARM-wide PV discovery mechanism, not specific to PV time?

> +
> +PV_TIME_ST
> +    Function ID:  (uint32)  : 0xC5000022
> +    Return value: (int64)   : IPA of the stolen time data structure for this
> +                              (V)CPU. On failure:
> +                              NOT_SUPPORTED (-1)
> +

Is the size implicit? What are the memory attributes? This either needs
documenting here, or point to the right bit to the spec.

> +Stolen Time
> +-----------
> +
> +The structure pointed to by the PV_TIME_ST hypercall is as follows:
> +
> +  Field       | Byte Length | Byte Offset | Description
> +  ----------- | ----------- | ----------- | --------------------------
> +  Revision    |      4      |      0      | Must be 0 for version 0.1
> +  Attributes  |      4      |      4      | Must be 0
> +  Stolen time |      8      |      8      | Stolen time in unsigned
> +              |             |             | nanoseconds indicating how
> +              |             |             | much time this VCPU thread
> +              |             |             | was involuntarily not
> +              |             |             | running on a physical CPU.
> +
> +The structure will be updated by the hypervisor periodically as time is stolen

Is it really periodic? If so, when is the update frequency?

> +from the VCPU. It will be present within a reserved region of the normal
> +memory given to the guest. The guest should not attempt to write into this
> +memory. There is a structure by VCPU of the guest.

What if the vcpu writes to it? Does it get a fault? If there is a
structure per vcpu, what is the layout in memory? How does a vcpu find
its own data structure? Is that the address returned by PV_TIME_ST?

> +
> +User space interface
> +====================
> +
> +User space can request that KVM provide the paravirtualized time interface to
> +a guest by creating a KVM_DEV_TYPE_ARM_PV_TIME device, for example:
> +
> +    struct kvm_create_device pvtime_device = {
> +            .type = KVM_DEV_TYPE_ARM_PV_TIME,
> +            .attr = 0,
> +            .flags = 0,
> +    };
> +
> +    pvtime_fd = ioctl(vm_fd, KVM_CREATE_DEVICE, &pvtime_device);
> +
> +The guest IPA of the structures must be given to KVM. This is the base address

nit: s/guest //

> +of an array of stolen time structures (one for each VCPU). For example:
> +
> +    struct kvm_device_attr st_base = {
> +            .group = KVM_DEV_ARM_PV_TIME_PADDR,
> +            .attr = KVM_DEV_ARM_PV_TIME_ST,
> +            .addr = (u64)(unsigned long)&st_paddr
> +    };
> +
> +    ioctl(pvtime_fd, KVM_SET_DEVICE_ATTR, &st_base);

So the allocation itself is performed by the kernel? What are the
ordering requirements between creating vcpus and the device? What are
the alignment requirements for the base address?

> +
> +For migration (or save/restore) of a guest it is necessary to save the contents
> +of the shared page(s) and later restore them. KVM_DEV_ARM_PV_TIME_STATE_SIZE
> +provides the size of this data and KVM_DEV_ARM_PV_TIME_STATE allows the state
> +to be read/written.

Is the size variable depending on the number of vcpus?

> +
> +It is also necessary for the physical address to be set identically when
> +restoring.
> +
> +    void *save_state(int fd, u64 attr, u32 *size) {
> +        struct kvm_device_attr get_size = {
> +                .group = KVM_DEV_ARM_PV_TIME_STATE_SIZE,
> +                .attr = attr,
> +                .addr = (u64)(unsigned long)size
> +        };
> +
> +        ioctl(fd, KVM_GET_DEVICE_ATTR, get_size);
> +
> +        void *buffer = malloc(*size);
> +
> +        struct kvm_device_attr get_state = {
> +                .group = KVM_DEV_ARM_PV_TIME_STATE,
> +                .attr = attr,
> +                .addr = (u64)(unsigned long)size
> +        };
> +
> +        ioctl(fd, KVM_GET_DEVICE_ATTR, buffer);
> +    }
> +
> +    void *st_state = save_state(pvtime_fd, KVM_DEV_ARM_PV_TIME_ST, &st_size);
> +

Thanks,

	M.
-- 
Without deviation from the norm, progress is not possible.

^ permalink raw reply

* Re: [PATCH 3/9] KVM: arm64: Implement PV_FEATURES call
From: Marc Zyngier @ 2019-08-03 11:21 UTC (permalink / raw)
  To: Steven Price
  Cc: Catalin Marinas, Paolo Bonzini, Radim Krčmář,
	Russell King, Will Deacon, James Morse, Julien Thierry,
	Suzuki K Pouloze, kvm, kvmarm, linux-arm-kernel, linux-doc,
	linux-kernel
In-Reply-To: <20190802145017.42543-4-steven.price@arm.com>

On Fri,  2 Aug 2019 15:50:11 +0100
Steven Price <steven.price@arm.com> wrote:

> This provides a mechanism for querying which paravirtualized features
> are available in this hypervisor.
> 
> Also add the header file which defines the ABI for the paravirtualized
> clock features we're about to add.
> 
> Signed-off-by: Steven Price <steven.price@arm.com>
> ---
>  arch/arm64/include/asm/pvclock-abi.h | 20 ++++++++++++++++++++
>  include/linux/arm-smccc.h            | 14 ++++++++++++++
>  virt/kvm/arm/hypercalls.c            |  9 +++++++++
>  3 files changed, 43 insertions(+)
>  create mode 100644 arch/arm64/include/asm/pvclock-abi.h
> 
> diff --git a/arch/arm64/include/asm/pvclock-abi.h b/arch/arm64/include/asm/pvclock-abi.h
> new file mode 100644
> index 000000000000..1f7cdc102691
> --- /dev/null
> +++ b/arch/arm64/include/asm/pvclock-abi.h
> @@ -0,0 +1,20 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/* Copyright (C) 2019 Arm Ltd. */
> +
> +#ifndef __ASM_PVCLOCK_ABI_H
> +#define __ASM_PVCLOCK_ABI_H
> +
> +/* The below structures and constants are defined in ARM DEN0057A */
> +
> +struct pvclock_vcpu_stolen_time_info {
> +	__le32 revision;
> +	__le32 attributes;
> +	__le64 stolen_time;
> +	/* Structure must be 64 byte aligned, pad to that size */
> +	u8 padding[48];
> +} __packed;
> +
> +#define PV_VM_TIME_NOT_SUPPORTED	-1

Isn't the intent for this to be the same value as
SMCCC_RET_NOT_SUPPORTED?

> +#define PV_VM_TIME_INVALID_PARAMETERS	-2

It overlaps with SMCCC_RET_NOT_REQUIRED. Is that a problem? Should we
consider a spec change for this?

> +
> +#endif
> diff --git a/include/linux/arm-smccc.h b/include/linux/arm-smccc.h
> index 080012a6f025..e7f129f26ebd 100644
> --- a/include/linux/arm-smccc.h
> +++ b/include/linux/arm-smccc.h
> @@ -45,6 +45,7 @@
>  #define ARM_SMCCC_OWNER_SIP		2
>  #define ARM_SMCCC_OWNER_OEM		3
>  #define ARM_SMCCC_OWNER_STANDARD	4
> +#define ARM_SMCCC_OWNER_STANDARD_HYP	5
>  #define ARM_SMCCC_OWNER_TRUSTED_APP	48
>  #define ARM_SMCCC_OWNER_TRUSTED_APP_END	49
>  #define ARM_SMCCC_OWNER_TRUSTED_OS	50
> @@ -302,5 +303,18 @@ asmlinkage void __arm_smccc_hvc(unsigned long a0, unsigned long a1,
>  #define SMCCC_RET_NOT_SUPPORTED			-1
>  #define SMCCC_RET_NOT_REQUIRED			-2
>  
> +/* Paravirtualised time calls (defined by ARM DEN0057A) */
> +#define ARM_SMCCC_HV_PV_FEATURES				\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
> +			   ARM_SMCCC_SMC_64,			\
> +			   ARM_SMCCC_OWNER_STANDARD_HYP,	\
> +			   0x20)
> +
> +#define ARM_SMCCC_HV_PV_TIME_ST					\
> +	ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL,			\
> +			   ARM_SMCCC_SMC_64,			\
> +			   ARM_SMCCC_OWNER_STANDARD_HYP,	\
> +			   0x22)
> +
>  #endif /*__ASSEMBLY__*/
>  #endif /*__LINUX_ARM_SMCCC_H*/
> diff --git a/virt/kvm/arm/hypercalls.c b/virt/kvm/arm/hypercalls.c
> index f875241bd030..2906b2df99df 100644
> --- a/virt/kvm/arm/hypercalls.c
> +++ b/virt/kvm/arm/hypercalls.c
> @@ -5,6 +5,7 @@
>  #include <linux/kvm_host.h>
>  
>  #include <asm/kvm_emulate.h>
> +#include <asm/pvclock-abi.h>
>  
>  #include <kvm/arm_hypercalls.h>
>  #include <kvm/arm_psci.h>
> @@ -48,6 +49,14 @@ int kvm_hvc_call_handler(struct kvm_vcpu *vcpu)
>  				break;
>  			}
>  			break;
> +		case ARM_SMCCC_HV_PV_FEATURES:
> +			val = SMCCC_RET_SUCCESS;
> +			break;
> +		}
> +		break;
> +	case ARM_SMCCC_HV_PV_FEATURES:
> +		feature = smccc_get_arg1(vcpu);
> +		switch (feature) {
>  		}
>  		break;
>  	default:


Thanks,

	M.
-- 
Without deviation from the norm, progress is not possible.

^ permalink raw reply

* Re: [EXT] Re: [PATCH 1/6] dt-bindings: arm: fsl: Add the S32V234-EVB board
From: Stefan-gabriel Mirea @ 2019-08-03  8:00 UTC (permalink / raw)
  To: Rob Herring
  Cc: corbet@lwn.net, mark.rutland@arm.com, gregkh@linuxfoundation.org,
	catalin.marinas@arm.com, will@kernel.org, shawnguo@kernel.org,
	Leo Li, jslaby@suse.com, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
	linux-serial@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, Eddy Petrisor
In-Reply-To: <CAL_JsqL++GZBxczxePni9ysNq06kObB4EzJEi1e4M=PurPZFgQ@mail.gmail.com>

Hello Rob,

On 8/3/2019 1:38 AM, Rob Herring wrote:
> On Fri, Aug 2, 2019 at 1:47 PM Stefan-gabriel Mirea
> <stefan-gabriel.mirea@nxp.com> wrote:
>> +      - description: S32V234 Customer Evaluation Board
>
> Most of the entries in this file are for all the boards for an SoC.
>
>> +        items:
>> +          - enum:
>> +              - fsl,s32v234-evb
>
> If that's not going to be the case here, you can use 'const' here.

We also intend to submit patches for the SBC-S32V234[1] board in the
future and I believe that its 'compatible' should share this entry.
Would it therefore be preferable to update the description at this
moment and add a comment, like:

      - description: S32V234 based Boards
        items:
          - enum:
              - fsl,s32v234-evb           # S32V234-EVB2 Customer Evaluation Board
          - const: fsl,s32v234

or just replace the single-value 'enum' with a 'const' for now?

Regards,
Stefan

[1] https://www.nxp.com/design/development-boards/automotive-development-platforms/s32v-mpus-platforms/s32v-vision-and-sensor-fusion-evaluation-board:SBC-S32V234

^ permalink raw reply

* Re: [PATCH 1/6] dt-bindings: arm: fsl: Add the S32V234-EVB board
From: Rob Herring @ 2019-08-02 22:38 UTC (permalink / raw)
  To: Stefan-gabriel Mirea
  Cc: corbet@lwn.net, mark.rutland@arm.com, gregkh@linuxfoundation.org,
	catalin.marinas@arm.com, will@kernel.org, shawnguo@kernel.org,
	Leo Li, jslaby@suse.com, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
	linux-serial@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, Eddy Petrisor
In-Reply-To: <20190802194702.30249-2-stefan-gabriel.mirea@nxp.com>

On Fri, Aug 2, 2019 at 1:47 PM Stefan-gabriel Mirea
<stefan-gabriel.mirea@nxp.com> wrote:
>
> From: Eddy Petrișor <eddy.petrisor@nxp.com>
>
> Add entry for the NXP S32V234 Customer Evaluation Board to the board/SoC
> bindings.
>
> Signed-off-by: Eddy Petrișor <eddy.petrisor@nxp.com>
> Signed-off-by: Stefan-Gabriel Mirea <stefan-gabriel.mirea@nxp.com>
> ---
>  Documentation/devicetree/bindings/arm/fsl.yaml | 6 ++++++
>  1 file changed, 6 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml
> index 7294ac36f4c0..104d60a11177 100644
> --- a/Documentation/devicetree/bindings/arm/fsl.yaml
> +++ b/Documentation/devicetree/bindings/arm/fsl.yaml
> @@ -309,4 +309,10 @@ properties:
>                - fsl,ls2088a-rdb
>            - const: fsl,ls2088a
>
> +      - description: S32V234 Customer Evaluation Board

Most of the entries in this file are for all the boards for an SoC.

> +        items:
> +          - enum:
> +              - fsl,s32v234-evb

If that's not going to be the case here, you can use 'const' here.

> +          - const: fsl,s32v234
> +
>  ...
> --
> 2.22.0
>

^ permalink raw reply

* [PATCH 6/6] arm64: defconfig: Enable configs for S32V234
From: Stefan-gabriel Mirea @ 2019-08-02 19:47 UTC (permalink / raw)
  To: corbet@lwn.net, robh+dt@kernel.org, mark.rutland@arm.com,
	gregkh@linuxfoundation.org, catalin.marinas@arm.com,
	will@kernel.org, shawnguo@kernel.org, Leo Li
  Cc: jslaby@suse.com, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
	linux-serial@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, Cosmin Stefan Stoica
In-Reply-To: <20190802194702.30249-1-stefan-gabriel.mirea@nxp.com>

From: Mihaela Martinas <Mihaela.Martinas@freescale.com>

Enable support for the S32V234 SoC, including the previously added UART
driver.

Signed-off-by: Mihaela Martinas <Mihaela.Martinas@freescale.com>
Signed-off-by: Adrian.Nitu <adrian.nitu@freescale.com>
Signed-off-by: Stoica Cosmin-Stefan <cosmin.stoica@nxp.com>
Signed-off-by: Stefan-Gabriel Mirea <stefan-gabriel.mirea@nxp.com>
---
 arch/arm64/configs/defconfig | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 0e58ef02880c..bb5aa95a8455 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -48,6 +48,7 @@ CONFIG_ARCH_MXC=y
 CONFIG_ARCH_QCOM=y
 CONFIG_ARCH_RENESAS=y
 CONFIG_ARCH_ROCKCHIP=y
+CONFIG_ARCH_S32=y
 CONFIG_ARCH_SEATTLE=y
 CONFIG_ARCH_STRATIX10=y
 CONFIG_ARCH_SYNQUACER=y
@@ -347,6 +348,8 @@ CONFIG_SERIAL_XILINX_PS_UART=y
 CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y
 CONFIG_SERIAL_FSL_LPUART=y
 CONFIG_SERIAL_FSL_LPUART_CONSOLE=y
+CONFIG_SERIAL_FSL_LINFLEXUART=y
+CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE=y
 CONFIG_SERIAL_MVEBU_UART=y
 CONFIG_SERIAL_DEV_BUS=y
 CONFIG_VIRTIO_CONSOLE=y
-- 
2.22.0


^ permalink raw reply related

* [PATCH 5/6] tty: serial: Add linflexuart driver for S32V234
From: Stefan-gabriel Mirea @ 2019-08-02 19:47 UTC (permalink / raw)
  To: corbet@lwn.net, robh+dt@kernel.org, mark.rutland@arm.com,
	gregkh@linuxfoundation.org, catalin.marinas@arm.com,
	will@kernel.org, shawnguo@kernel.org, Leo Li
  Cc: jslaby@suse.com, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
	linux-serial@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, Cosmin Stefan Stoica,
	Larisa Ileana Grigore
In-Reply-To: <20190802194702.30249-1-stefan-gabriel.mirea@nxp.com>

Introduce support for LINFlex driver, based on:
- the version of Freescale LPUART driver after commit b3e3bf2ef2c7 ("Merge
  4.0-rc7 into tty-next");
- commit abf1e0a98083 ("tty: serial: fsl_lpuart: lock port on console
  write").
In this basic version, the driver can be tested using initramfs and relies
on the clocks and pin muxing set up by U-Boot.

Remarks concerning the earlycon support:

- LinFlexD does not allow character transmissions in the INIT mode (see
  section 47.4.2.1 in the reference manual[1]). Therefore, a mutual
  exclusion between the first linflex_setup_watermark/linflex_set_termios
  executions and linflex_earlycon_putchar was employed and the characters
  normally sent to earlycon during initialization are kept in a buffer and
  sent afterwards.

- Empirically, character transmission is also forbidden within the last 1-2
  ms before entering the INIT mode, so we use an explicit timeout
  (PREINIT_DELAY) between linflex_earlycon_putchar and the first call to
  linflex_setup_watermark.

- U-Boot currently uses the UART FIFO mode, while this driver makes the
  transition to the buffer mode. Therefore, the earlycon putchar function
  matches the U-Boot behavior before initializations and the Linux behavior
  after.

[1] https://www.nxp.com/webapp/Download?colCode=S32V234RM

Signed-off-by: Stoica Cosmin-Stefan <cosmin.stoica@nxp.com>
Signed-off-by: Adrian.Nitu <adrian.nitu@freescale.com>
Signed-off-by: Larisa Grigore <Larisa.Grigore@nxp.com>
Signed-off-by: Ana Nedelcu <B56683@freescale.com>
Signed-off-by: Mihaela Martinas <Mihaela.Martinas@freescale.com>
Signed-off-by: Matthew Nunez <matthew.nunez@nxp.com>
[stefan-gabriel.mirea@nxp.com: Reduced for upstreaming and implemented
                               earlycon support]
Signed-off-by: Stefan-Gabriel Mirea <stefan-gabriel.mirea@nxp.com>
---
 .../admin-guide/kernel-parameters.txt         |   6 +
 drivers/tty/serial/Kconfig                    |  15 +
 drivers/tty/serial/Makefile                   |   1 +
 drivers/tty/serial/fsl_linflexuart.c          | 956 ++++++++++++++++++
 include/uapi/linux/serial_core.h              |   3 +
 5 files changed, 981 insertions(+)
 create mode 100644 drivers/tty/serial/fsl_linflexuart.c

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 46b826fcb5ad..4d545732aadc 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -1090,6 +1090,12 @@
 			the framebuffer, pass the 'ram' option so that it is
 			mapped with the correct attributes.
 
+		linflex,<addr>
+			Use early console provided by Freescale LinFlex UART
+			serial driver for NXP S32V234 SoCs. A valid base
+			address must be provided, and the serial port must
+			already be setup and configured.
+
 	earlyprintk=	[X86,SH,ARM,M68k,S390]
 			earlyprintk=vga
 			earlyprintk=sclp
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index fd385c8c53a5..b4fa2f7c96bd 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -1452,6 +1452,21 @@ config SERIAL_FSL_LPUART_CONSOLE
 	  If you have enabled the lpuart serial port on the Freescale SoCs,
 	  you can make it the console by answering Y to this option.
 
+config SERIAL_FSL_LINFLEXUART
+	tristate "Freescale linflexuart serial port support"
+	select SERIAL_CORE
+	help
+	  Support for the on-chip linflexuart on some Freescale SOCs.
+
+config SERIAL_FSL_LINFLEXUART_CONSOLE
+	bool "Console on Freescale linflexuart serial port"
+	depends on SERIAL_FSL_LINFLEXUART=y
+	select SERIAL_CORE_CONSOLE
+	select SERIAL_EARLYCON
+	help
+	  If you have enabled the linflexuart serial port on the Freescale
+	  SoCs, you can make it the console by answering Y to this option.
+
 config SERIAL_CONEXANT_DIGICOLOR
 	tristate "Conexant Digicolor CX92xxx USART serial port support"
 	depends on OF
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 7cd7cabfa6c4..7a3d52a453b7 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -82,6 +82,7 @@ obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o
 obj-$(CONFIG_SERIAL_ARC)	+= arc_uart.o
 obj-$(CONFIG_SERIAL_RP2)	+= rp2.o
 obj-$(CONFIG_SERIAL_FSL_LPUART)	+= fsl_lpuart.o
+obj-$(CONFIG_SERIAL_FSL_LINFLEXUART)	+= fsl_linflexuart.o
 obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR)	+= digicolor-usart.o
 obj-$(CONFIG_SERIAL_MEN_Z135)	+= men_z135_uart.o
 obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
diff --git a/drivers/tty/serial/fsl_linflexuart.c b/drivers/tty/serial/fsl_linflexuart.c
new file mode 100644
index 000000000000..7c4e6872b360
--- /dev/null
+++ b/drivers/tty/serial/fsl_linflexuart.c
@@ -0,0 +1,956 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Freescale linflexuart serial port driver
+ *
+ * Copyright 2012-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
+ */
+
+#if defined(CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE) && \
+	defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/console.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/serial_core.h>
+#include <linux/slab.h>
+#include <linux/tty_flip.h>
+#include <linux/delay.h>
+
+/* All registers are 32-bit width */
+
+#define LINCR1	0x0000	/* LIN control register				*/
+#define LINIER	0x0004	/* LIN interrupt enable register		*/
+#define LINSR	0x0008	/* LIN status register				*/
+#define LINESR	0x000C	/* LIN error status register			*/
+#define UARTCR	0x0010	/* UART mode control register			*/
+#define UARTSR	0x0014	/* UART mode status register			*/
+#define LINTCSR	0x0018	/* LIN timeout control status register		*/
+#define LINOCR	0x001C	/* LIN output compare register			*/
+#define LINTOCR	0x0020	/* LIN timeout control register			*/
+#define LINFBRR	0x0024	/* LIN fractional baud rate register		*/
+#define LINIBRR	0x0028	/* LIN integer baud rate register		*/
+#define LINCFR	0x002C	/* LIN checksum field register			*/
+#define LINCR2	0x0030	/* LIN control register 2			*/
+#define BIDR	0x0034	/* Buffer identifier register			*/
+#define BDRL	0x0038	/* Buffer data register least significant	*/
+#define BDRM	0x003C	/* Buffer data register most significant	*/
+#define IFER	0x0040	/* Identifier filter enable register		*/
+#define IFMI	0x0044	/* Identifier filter match index		*/
+#define IFMR	0x0048	/* Identifier filter mode register		*/
+#define GCR	0x004C	/* Global control register			*/
+#define UARTPTO	0x0050	/* UART preset timeout register			*/
+#define UARTCTO	0x0054	/* UART current timeout register		*/
+
+/*
+ * Register field definitions
+ */
+
+#define LINFLEXD_LINCR1_INIT		BIT(0)
+#define LINFLEXD_LINCR1_MME		BIT(4)
+#define LINFLEXD_LINCR1_BF		BIT(7)
+
+#define LINFLEXD_LINSR_LINS_INITMODE	BIT(12)
+#define LINFLEXD_LINSR_LINS_MASK	(0xF << 12)
+
+#define LINFLEXD_LINIER_SZIE		BIT(15)
+#define LINFLEXD_LINIER_OCIE		BIT(14)
+#define LINFLEXD_LINIER_BEIE		BIT(13)
+#define LINFLEXD_LINIER_CEIE		BIT(12)
+#define LINFLEXD_LINIER_HEIE		BIT(11)
+#define LINFLEXD_LINIER_FEIE		BIT(8)
+#define LINFLEXD_LINIER_BOIE		BIT(7)
+#define LINFLEXD_LINIER_LSIE		BIT(6)
+#define LINFLEXD_LINIER_WUIE		BIT(5)
+#define LINFLEXD_LINIER_DBFIE		BIT(4)
+#define LINFLEXD_LINIER_DBEIETOIE	BIT(3)
+#define LINFLEXD_LINIER_DRIE		BIT(2)
+#define LINFLEXD_LINIER_DTIE		BIT(1)
+#define LINFLEXD_LINIER_HRIE		BIT(0)
+
+#define LINFLEXD_UARTCR_OSR_MASK	(0xF << 24)
+#define LINFLEXD_UARTCR_OSR(uartcr)	(((uartcr) \
+					& LINFLEXD_UARTCR_OSR_MASK) >> 24)
+
+#define LINFLEXD_UARTCR_ROSE		BIT(23)
+
+#define LINFLEXD_UARTCR_RFBM		BIT(9)
+#define LINFLEXD_UARTCR_TFBM		BIT(8)
+#define LINFLEXD_UARTCR_WL1		BIT(7)
+#define LINFLEXD_UARTCR_PC1		BIT(6)
+
+#define LINFLEXD_UARTCR_RXEN		BIT(5)
+#define LINFLEXD_UARTCR_TXEN		BIT(4)
+#define LINFLEXD_UARTCR_PC0		BIT(3)
+
+#define LINFLEXD_UARTCR_PCE		BIT(2)
+#define LINFLEXD_UARTCR_WL0		BIT(1)
+#define LINFLEXD_UARTCR_UART		BIT(0)
+
+#define LINFLEXD_UARTSR_SZF		BIT(15)
+#define LINFLEXD_UARTSR_OCF		BIT(14)
+#define LINFLEXD_UARTSR_PE3		BIT(13)
+#define LINFLEXD_UARTSR_PE2		BIT(12)
+#define LINFLEXD_UARTSR_PE1		BIT(11)
+#define LINFLEXD_UARTSR_PE0		BIT(10)
+#define LINFLEXD_UARTSR_RMB		BIT(9)
+#define LINFLEXD_UARTSR_FEF		BIT(8)
+#define LINFLEXD_UARTSR_BOF		BIT(7)
+#define LINFLEXD_UARTSR_RPS		BIT(6)
+#define LINFLEXD_UARTSR_WUF		BIT(5)
+#define LINFLEXD_UARTSR_4		BIT(4)
+
+#define LINFLEXD_UARTSR_TO		BIT(3)
+
+#define LINFLEXD_UARTSR_DRFRFE		BIT(2)
+#define LINFLEXD_UARTSR_DTFTFF		BIT(1)
+#define LINFLEXD_UARTSR_NF		BIT(0)
+#define LINFLEXD_UARTSR_PE		(LINFLEXD_UARTSR_PE0 |\
+					 LINFLEXD_UARTSR_PE1 |\
+					 LINFLEXD_UARTSR_PE2 |\
+					 LINFLEXD_UARTSR_PE3)
+
+#define LINFLEX_LDIV_MULTIPLIER		(16)
+
+#define DRIVER_NAME	"fsl-linflexuart"
+#define DEV_NAME	"ttyLF"
+#define UART_NR		4
+
+#define EARLYCON_BUFFER_INITIAL_CAP	8
+
+#define PREINIT_DELAY			2000 /* us */
+
+static const struct of_device_id linflex_dt_ids[] = {
+	{
+		.compatible = "fsl,s32-linflexuart",
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, linflex_dt_ids);
+
+#ifdef CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE
+static struct uart_port *earlycon_port;
+static bool linflex_earlycon_same_instance;
+static spinlock_t init_lock;
+static bool during_init;
+
+static struct {
+	char *content;
+	unsigned int len, cap;
+} earlycon_buf;
+#endif
+
+static void linflex_stop_tx(struct uart_port *port)
+{
+	unsigned long ier;
+
+	ier = readl(port->membase + LINIER);
+	ier &= ~(LINFLEXD_LINIER_DTIE);
+	writel(ier, port->membase + LINIER);
+}
+
+static void linflex_stop_rx(struct uart_port *port)
+{
+	unsigned long ier;
+
+	ier = readl(port->membase + LINIER);
+	writel(ier & ~LINFLEXD_LINIER_DRIE, port->membase + LINIER);
+}
+
+static inline void linflex_transmit_buffer(struct uart_port *sport)
+{
+	struct circ_buf *xmit = &sport->state->xmit;
+	unsigned char c;
+	unsigned long status;
+
+	while (!uart_circ_empty(xmit)) {
+		c = xmit->buf[xmit->tail];
+		writeb(c, sport->membase + BDRL);
+
+		/* Waiting for data transmission completed. */
+		while (((status = readl(sport->membase + UARTSR)) &
+					LINFLEXD_UARTSR_DTFTFF) !=
+					LINFLEXD_UARTSR_DTFTFF)
+			;
+
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		sport->icount.tx++;
+
+		writel(status | LINFLEXD_UARTSR_DTFTFF,
+		       sport->membase + UARTSR);
+	}
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(sport);
+
+	if (uart_circ_empty(xmit))
+		linflex_stop_tx(sport);
+}
+
+static void linflex_start_tx(struct uart_port *port)
+{
+	unsigned long ier;
+
+	linflex_transmit_buffer(port);
+	ier = readl(port->membase + LINIER);
+	writel(ier | LINFLEXD_LINIER_DTIE, port->membase + LINIER);
+}
+
+static irqreturn_t linflex_txint(int irq, void *dev_id)
+{
+	struct uart_port *sport = dev_id;
+	struct circ_buf *xmit = &sport->state->xmit;
+	unsigned long flags;
+	unsigned long status;
+
+	spin_lock_irqsave(&sport->lock, flags);
+
+	if (sport->x_char) {
+		writeb(sport->x_char, sport->membase + BDRL);
+
+		/* waiting for data transmission completed */
+		while (((status = readl(sport->membase + UARTSR)) &
+			LINFLEXD_UARTSR_DTFTFF) != LINFLEXD_UARTSR_DTFTFF)
+			;
+
+		writel(status | LINFLEXD_UARTSR_DTFTFF,
+		       sport->membase + UARTSR);
+
+		goto out;
+	}
+
+	if (uart_circ_empty(xmit) || uart_tx_stopped(sport)) {
+		linflex_stop_tx(sport);
+		goto out;
+	}
+
+	linflex_transmit_buffer(sport);
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(sport);
+
+out:
+	spin_unlock_irqrestore(&sport->lock, flags);
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t linflex_rxint(int irq, void *dev_id)
+{
+	struct uart_port *sport = dev_id;
+	unsigned int flg;
+	struct tty_port *port = &sport->state->port;
+	unsigned long flags, status;
+	unsigned char rx;
+
+	spin_lock_irqsave(&sport->lock, flags);
+
+	status = readl(sport->membase + UARTSR);
+	while (status & LINFLEXD_UARTSR_RMB) {
+		rx = readb(sport->membase + BDRM);
+		flg = TTY_NORMAL;
+		sport->icount.rx++;
+
+		if (status & (LINFLEXD_UARTSR_BOF | LINFLEXD_UARTSR_SZF |
+			      LINFLEXD_UARTSR_FEF | LINFLEXD_UARTSR_PE)) {
+			if (status & LINFLEXD_UARTSR_SZF)
+				status |= LINFLEXD_UARTSR_SZF;
+			if (status & LINFLEXD_UARTSR_BOF)
+				status |= LINFLEXD_UARTSR_BOF;
+			if (status & LINFLEXD_UARTSR_FEF)
+				status |= LINFLEXD_UARTSR_FEF;
+			if (status & LINFLEXD_UARTSR_PE)
+				status |=  LINFLEXD_UARTSR_PE;
+		}
+
+		writel(status | LINFLEXD_UARTSR_RMB | LINFLEXD_UARTSR_DRFRFE,
+		       sport->membase + UARTSR);
+		status = readl(sport->membase + UARTSR);
+
+		if (uart_handle_sysrq_char(sport, (unsigned char)rx))
+			continue;
+
+#ifdef SUPPORT_SYSRQ
+			sport->sysrq = 0;
+#endif
+		tty_insert_flip_char(port, rx, flg);
+	}
+
+	spin_unlock_irqrestore(&sport->lock, flags);
+
+	tty_flip_buffer_push(port);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t linflex_int(int irq, void *dev_id)
+{
+	struct uart_port *sport = dev_id;
+	unsigned long status;
+
+	status = readl(sport->membase + UARTSR);
+
+	if (status & LINFLEXD_UARTSR_DRFRFE)
+		linflex_rxint(irq, dev_id);
+	if (status & LINFLEXD_UARTSR_DTFTFF)
+		linflex_txint(irq, dev_id);
+
+	return IRQ_HANDLED;
+}
+
+/* return TIOCSER_TEMT when transmitter is not busy */
+static unsigned int linflex_tx_empty(struct uart_port *port)
+{
+	unsigned long status;
+
+	status = readl(port->membase + UARTSR) & LINFLEXD_UARTSR_DTFTFF;
+
+	return status ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int linflex_get_mctrl(struct uart_port *port)
+{
+	return 0;
+}
+
+static void linflex_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+static void linflex_break_ctl(struct uart_port *port, int break_state)
+{
+}
+
+static void linflex_setup_watermark(struct uart_port *sport)
+{
+	unsigned long cr, ier, cr1;
+
+	/* Disable transmission/reception */
+	ier = readl(sport->membase + LINIER);
+	ier &= ~(LINFLEXD_LINIER_DRIE | LINFLEXD_LINIER_DTIE);
+	writel(ier, sport->membase + LINIER);
+
+	cr = readl(sport->membase + UARTCR);
+	cr &= ~(LINFLEXD_UARTCR_RXEN | LINFLEXD_UARTCR_TXEN);
+	writel(cr, sport->membase + UARTCR);
+
+	/* Enter initialization mode by setting INIT bit */
+
+	/* set the Linflex in master mode and activate by-pass filter */
+	cr1 = LINFLEXD_LINCR1_BF | LINFLEXD_LINCR1_MME
+	      | LINFLEXD_LINCR1_INIT;
+	writel(cr1, sport->membase + LINCR1);
+
+	/* wait for init mode entry */
+	while ((readl(sport->membase + LINSR)
+		& LINFLEXD_LINSR_LINS_MASK)
+		!= LINFLEXD_LINSR_LINS_INITMODE)
+		;
+
+	/*
+	 *	UART = 0x1;		- Linflex working in UART mode
+	 *	TXEN = 0x1;		- Enable transmission of data now
+	 *	RXEn = 0x1;		- Receiver enabled
+	 *	WL0 = 0x1;		- 8 bit data
+	 *	PCE = 0x0;		- No parity
+	 */
+
+	/* set UART bit to allow writing other bits */
+	writel(LINFLEXD_UARTCR_UART, sport->membase + UARTCR);
+
+	cr = (LINFLEXD_UARTCR_RXEN | LINFLEXD_UARTCR_TXEN |
+	      LINFLEXD_UARTCR_WL0 | LINFLEXD_UARTCR_UART);
+
+	writel(cr, sport->membase + UARTCR);
+
+	cr1 &= ~(LINFLEXD_LINCR1_INIT);
+
+	writel(cr1, sport->membase + LINCR1);
+
+	ier = readl(sport->membase + LINIER);
+	ier |= LINFLEXD_LINIER_DRIE;
+	ier |= LINFLEXD_LINIER_DTIE;
+
+	writel(ier, sport->membase + LINIER);
+}
+
+static int linflex_startup(struct uart_port *port)
+{
+	int ret = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	linflex_setup_watermark(port);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	ret = devm_request_irq(port->dev, port->irq, linflex_int, 0,
+			       DRIVER_NAME, port);
+
+	return ret;
+}
+
+static void linflex_shutdown(struct uart_port *port)
+{
+	unsigned long ier;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	/* disable interrupts */
+	ier = readl(port->membase + LINIER);
+	ier &= ~(LINFLEXD_LINIER_DRIE | LINFLEXD_LINIER_DTIE);
+	writel(ier, port->membase + LINIER);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+
+	devm_free_irq(port->dev, port->irq, port);
+}
+
+static void
+linflex_set_termios(struct uart_port *port, struct ktermios *termios,
+		    struct ktermios *old)
+{
+	unsigned long flags;
+	unsigned long cr, old_cr, cr1;
+	unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8;
+
+	cr = readl(port->membase + UARTCR);
+	old_cr = cr;
+
+	/* Enter initialization mode by setting INIT bit */
+	cr1 = readl(port->membase + LINCR1);
+	cr1 |= LINFLEXD_LINCR1_INIT;
+	writel(cr1, port->membase + LINCR1);
+
+	/* wait for init mode entry */
+	while ((readl(port->membase + LINSR)
+		& LINFLEXD_LINSR_LINS_MASK)
+		!= LINFLEXD_LINSR_LINS_INITMODE)
+		;
+
+	/*
+	 * only support CS8 and CS7, and for CS7 must enable PE.
+	 * supported mode:
+	 *	- (7,e/o,1)
+	 *	- (8,n,1)
+	 *	- (8,e/o,1)
+	 */
+	/* enter the UART into configuration mode */
+
+	while ((termios->c_cflag & CSIZE) != CS8 &&
+	       (termios->c_cflag & CSIZE) != CS7) {
+		termios->c_cflag &= ~CSIZE;
+		termios->c_cflag |= old_csize;
+		old_csize = CS8;
+	}
+
+	if ((termios->c_cflag & CSIZE) == CS7) {
+		/* Word length: WL1WL0:00 */
+		cr = old_cr & ~LINFLEXD_UARTCR_WL1 & ~LINFLEXD_UARTCR_WL0;
+	}
+
+	if ((termios->c_cflag & CSIZE) == CS8) {
+		/* Word length: WL1WL0:01 */
+		cr = (old_cr | LINFLEXD_UARTCR_WL0) & ~LINFLEXD_UARTCR_WL1;
+	}
+
+	if (termios->c_cflag & CMSPAR) {
+		if ((termios->c_cflag & CSIZE) != CS8) {
+			termios->c_cflag &= ~CSIZE;
+			termios->c_cflag |= CS8;
+		}
+		/* has a space/sticky bit */
+		cr |= LINFLEXD_UARTCR_WL0;
+	}
+
+	if (termios->c_cflag & CSTOPB)
+		termios->c_cflag &= ~CSTOPB;
+
+	/* parity must be enabled when CS7 to match 8-bits format */
+	if ((termios->c_cflag & CSIZE) == CS7)
+		termios->c_cflag |= PARENB;
+
+	if ((termios->c_cflag & PARENB)) {
+		cr |= LINFLEXD_UARTCR_PCE;
+		if (termios->c_cflag & PARODD)
+			cr = (cr | LINFLEXD_UARTCR_PC0) &
+			     (~LINFLEXD_UARTCR_PC1);
+		else
+			cr = cr & (~LINFLEXD_UARTCR_PC1 &
+				   ~LINFLEXD_UARTCR_PC0);
+	} else {
+		cr &= ~LINFLEXD_UARTCR_PCE;
+	}
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	port->read_status_mask = 0;
+
+	if (termios->c_iflag & INPCK)
+		port->read_status_mask |=	(LINFLEXD_UARTSR_FEF |
+						 LINFLEXD_UARTSR_PE0 |
+						 LINFLEXD_UARTSR_PE1 |
+						 LINFLEXD_UARTSR_PE2 |
+						 LINFLEXD_UARTSR_PE3);
+	if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
+		port->read_status_mask |= LINFLEXD_UARTSR_FEF;
+
+	/* characters to ignore */
+	port->ignore_status_mask = 0;
+	if (termios->c_iflag & IGNPAR)
+		port->ignore_status_mask |= LINFLEXD_UARTSR_PE;
+	if (termios->c_iflag & IGNBRK) {
+		port->ignore_status_mask |= LINFLEXD_UARTSR_PE;
+		/*
+		 * if we're ignoring parity and break indicators,
+		 * ignore overruns too (for real raw support).
+		 */
+		if (termios->c_iflag & IGNPAR)
+			port->ignore_status_mask |= LINFLEXD_UARTSR_BOF;
+	}
+
+	writel(cr, port->membase + UARTCR);
+
+	cr1 &= ~(LINFLEXD_LINCR1_INIT);
+
+	writel(cr1, port->membase + LINCR1);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *linflex_type(struct uart_port *port)
+{
+	return "FSL_LINFLEX";
+}
+
+static void linflex_release_port(struct uart_port *port)
+{
+	/* nothing to do */
+}
+
+static int linflex_request_port(struct uart_port *port)
+{
+	return 0;
+}
+
+/* configure/auto-configure the port */
+static void linflex_config_port(struct uart_port *port, int flags)
+{
+	if (flags & UART_CONFIG_TYPE)
+		port->type = PORT_LINFLEXUART;
+}
+
+static int linflex_verify_port(struct uart_port *port,
+			       struct serial_struct *ser)
+{
+	if ((ser->type != PORT_UNKNOWN && ser->type != PORT_LINFLEXUART) ||
+	    (port->irq != ser->irq) ||
+	    (ser->io_type != UPIO_MEM) ||
+	    (port->iobase != ser->port) ||
+	    (ser->hub6 != 0))
+		return -EINVAL;
+
+	return 0;
+}
+
+static const struct uart_ops linflex_pops = {
+	.tx_empty	= linflex_tx_empty,
+	.set_mctrl	= linflex_set_mctrl,
+	.get_mctrl	= linflex_get_mctrl,
+	.stop_tx	= linflex_stop_tx,
+	.start_tx	= linflex_start_tx,
+	.stop_rx	= linflex_stop_rx,
+	.break_ctl	= linflex_break_ctl,
+	.startup	= linflex_startup,
+	.shutdown	= linflex_shutdown,
+	.set_termios	= linflex_set_termios,
+	.type		= linflex_type,
+	.request_port	= linflex_request_port,
+	.release_port	= linflex_release_port,
+	.config_port	= linflex_config_port,
+	.verify_port	= linflex_verify_port,
+};
+
+static struct uart_port *linflex_ports[UART_NR];
+
+#ifdef CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE
+static void linflex_console_putchar(struct uart_port *port, int ch)
+{
+	unsigned long cr;
+
+	cr = readl(port->membase + UARTCR);
+
+	writeb(ch, port->membase + BDRL);
+
+	if (!(cr & LINFLEXD_UARTCR_TFBM))
+		while ((readl(port->membase + UARTSR) &
+					LINFLEXD_UARTSR_DTFTFF)
+				!= LINFLEXD_UARTSR_DTFTFF)
+			;
+	else
+		while (readl(port->membase + UARTSR) &
+					LINFLEXD_UARTSR_DTFTFF)
+			;
+
+	if (!(cr & LINFLEXD_UARTCR_TFBM)) {
+		writel((readl(port->membase + UARTSR) |
+					LINFLEXD_UARTSR_DTFTFF),
+					port->membase + UARTSR);
+	}
+}
+
+static void linflex_earlycon_putchar(struct uart_port *port, int ch)
+{
+	unsigned long flags;
+	char *ret;
+
+	if (!linflex_earlycon_same_instance) {
+		linflex_console_putchar(port, ch);
+		return;
+	}
+
+	spin_lock_irqsave(&init_lock, flags);
+	if (!during_init)
+		goto outside_init;
+
+	if (earlycon_buf.len >= 1 << CONFIG_LOG_BUF_SHIFT)
+		goto init_release;
+
+	if (!earlycon_buf.cap) {
+		earlycon_buf.content = kmalloc(EARLYCON_BUFFER_INITIAL_CAP,
+					       GFP_ATOMIC);
+		earlycon_buf.cap = earlycon_buf.content ?
+				   EARLYCON_BUFFER_INITIAL_CAP : 0;
+	} else if (earlycon_buf.len == earlycon_buf.cap) {
+		ret = krealloc(earlycon_buf.content, earlycon_buf.cap << 1,
+			       GFP_ATOMIC);
+		if (ret) {
+			earlycon_buf.content = ret;
+			earlycon_buf.cap <<= 1;
+		}
+	}
+
+	if (earlycon_buf.len < earlycon_buf.cap)
+		earlycon_buf.content[earlycon_buf.len++] = ch;
+
+	goto init_release;
+
+outside_init:
+	linflex_console_putchar(port, ch);
+init_release:
+	spin_unlock_irqrestore(&init_lock, flags);
+}
+
+static void linflex_string_write(struct uart_port *sport, const char *s,
+				 unsigned int count)
+{
+	unsigned long cr, ier = 0;
+
+	ier = readl(sport->membase + LINIER);
+	linflex_stop_tx(sport);
+
+	cr = readl(sport->membase + UARTCR);
+	cr |= (LINFLEXD_UARTCR_TXEN);
+	writel(cr, sport->membase + UARTCR);
+
+	uart_console_write(sport, s, count, linflex_console_putchar);
+
+	writel(ier, sport->membase + LINIER);
+}
+
+static void
+linflex_console_write(struct console *co, const char *s, unsigned int count)
+{
+	struct uart_port *sport = linflex_ports[co->index];
+	unsigned long flags;
+	int locked = 1;
+
+	if (sport->sysrq)
+		locked = 0;
+	else if (oops_in_progress)
+		locked = spin_trylock_irqsave(&sport->lock, flags);
+	else
+		spin_lock_irqsave(&sport->lock, flags);
+
+	linflex_string_write(sport, s, count);
+
+	if (locked)
+		spin_unlock_irqrestore(&sport->lock, flags);
+}
+
+/*
+ * if the port was already initialised (eg, by a boot loader),
+ * try to determine the current setup.
+ */
+static void __init
+linflex_console_get_options(struct uart_port *sport, int *parity, int *bits)
+{
+	unsigned long cr;
+
+	cr = readl(sport->membase + UARTCR);
+	cr &= LINFLEXD_UARTCR_RXEN | LINFLEXD_UARTCR_TXEN;
+
+	if (!cr)
+		return;
+
+	/* ok, the port was enabled */
+
+	*parity = 'n';
+	if (cr & LINFLEXD_UARTCR_PCE) {
+		if (cr & LINFLEXD_UARTCR_PC0)
+			*parity = 'o';
+		else
+			*parity = 'e';
+	}
+
+	if ((cr & LINFLEXD_UARTCR_WL0) && ((cr & LINFLEXD_UARTCR_WL1) == 0)) {
+		if (cr & LINFLEXD_UARTCR_PCE)
+			*bits = 9;
+		else
+			*bits = 8;
+	}
+}
+
+static int __init linflex_console_setup(struct console *co, char *options)
+{
+	struct uart_port *sport;
+	int baud = 115200;
+	int bits = 8;
+	int parity = 'n';
+	int flow = 'n';
+	int ret;
+	int i;
+	unsigned long flags;
+	/*
+	 * check whether an invalid uart number has been specified, and
+	 * if so, search for the first available port that does have
+	 * console support.
+	 */
+	if (co->index == -1 || co->index >= ARRAY_SIZE(linflex_ports))
+		co->index = 0;
+
+	sport = linflex_ports[co->index];
+	if (!sport)
+		return -ENODEV;
+
+	if (options)
+		uart_parse_options(options, &baud, &parity, &bits, &flow);
+	else
+		linflex_console_get_options(sport, &parity, &bits);
+
+	if (earlycon_port && sport->mapbase == earlycon_port->mapbase) {
+		linflex_earlycon_same_instance = true;
+
+		spin_lock_irqsave(&init_lock, flags);
+		during_init = true;
+		spin_unlock_irqrestore(&init_lock, flags);
+
+		/* Workaround for character loss or output of many invalid
+		 * characters, when INIT mode is entered shortly after a
+		 * character has just been printed.
+		 */
+		udelay(PREINIT_DELAY);
+	}
+
+	linflex_setup_watermark(sport);
+
+	ret = uart_set_options(sport, co, baud, parity, bits, flow);
+
+	if (!linflex_earlycon_same_instance)
+		goto done;
+
+	spin_lock_irqsave(&init_lock, flags);
+
+	/* Emptying buffer */
+	if (earlycon_buf.len) {
+		for (i = 0; i < earlycon_buf.len; i++)
+			linflex_console_putchar(earlycon_port,
+				earlycon_buf.content[i]);
+
+		kfree(earlycon_buf.content);
+		earlycon_buf.len = 0;
+	}
+
+	during_init = false;
+	spin_unlock_irqrestore(&init_lock, flags);
+
+done:
+	return ret;
+}
+
+static struct uart_driver linflex_reg;
+static struct console linflex_console = {
+	.name		= DEV_NAME,
+	.write		= linflex_console_write,
+	.device		= uart_console_device,
+	.setup		= linflex_console_setup,
+	.flags		= CON_PRINTBUFFER,
+	.index		= -1,
+	.data		= &linflex_reg,
+};
+
+static void linflex_earlycon_write(struct console *con, const char *s,
+				   unsigned int n)
+{
+	struct earlycon_device *dev = con->data;
+
+	uart_console_write(&dev->port, s, n, linflex_earlycon_putchar);
+}
+
+static int __init linflex_early_console_setup(struct earlycon_device *device,
+					      const char *options)
+{
+	if (!device->port.membase)
+		return -ENODEV;
+
+	device->con->write = linflex_earlycon_write;
+	earlycon_port = &device->port;
+
+	return 0;
+}
+
+OF_EARLYCON_DECLARE(linflex, "fsl,s32v234-linflexuart",
+		    linflex_early_console_setup);
+
+#define LINFLEX_CONSOLE	(&linflex_console)
+#else
+#define LINFLEX_CONSOLE	NULL
+#endif
+
+static struct uart_driver linflex_reg = {
+	.owner		= THIS_MODULE,
+	.driver_name	= DRIVER_NAME,
+	.dev_name	= DEV_NAME,
+	.nr		= ARRAY_SIZE(linflex_ports),
+	.cons		= LINFLEX_CONSOLE,
+};
+
+static int linflex_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct uart_port *sport;
+	struct resource *res;
+	int ret;
+
+	sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL);
+	if (!sport)
+		return -ENOMEM;
+
+	ret = of_alias_get_id(np, "serial");
+	if (ret < 0) {
+		dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret);
+		return ret;
+	}
+	if (ret >= UART_NR) {
+		dev_err(&pdev->dev, "driver limited to %d serial ports\n",
+			UART_NR);
+		return -ENOMEM;
+	}
+
+	sport->line = ret;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+
+	sport->mapbase = res->start;
+	sport->membase = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(sport->membase))
+		return PTR_ERR(sport->membase);
+
+	sport->dev = &pdev->dev;
+	sport->type = PORT_LINFLEXUART;
+	sport->iotype = UPIO_MEM;
+	sport->irq = platform_get_irq(pdev, 0);
+	sport->ops = &linflex_pops;
+	sport->flags = UPF_BOOT_AUTOCONF;
+
+	linflex_ports[sport->line] = sport;
+
+	platform_set_drvdata(pdev, sport);
+
+	ret = uart_add_one_port(&linflex_reg, sport);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int linflex_remove(struct platform_device *pdev)
+{
+	struct uart_port *sport = platform_get_drvdata(pdev);
+
+	uart_remove_one_port(&linflex_reg, sport);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int linflex_suspend(struct device *dev)
+{
+	struct uart_port *sport = dev_get_drvdata(dev);
+
+	uart_suspend_port(&linflex_reg, sport);
+
+	return 0;
+}
+
+static int linflex_resume(struct device *dev)
+{
+	struct uart_port *sport = dev_get_drvdata(dev);
+
+	uart_resume_port(&linflex_reg, sport);
+
+	return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(linflex_pm_ops, linflex_suspend, linflex_resume);
+
+static struct platform_driver linflex_driver = {
+	.probe		= linflex_probe,
+	.remove		= linflex_remove,
+	.driver		= {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+		.of_match_table	= linflex_dt_ids,
+		.pm	= &linflex_pm_ops,
+	},
+};
+
+static int __init linflex_serial_init(void)
+{
+	int ret;
+
+	ret = uart_register_driver(&linflex_reg);
+	if (ret)
+		return ret;
+
+	ret = platform_driver_register(&linflex_driver);
+	if (ret)
+		uart_unregister_driver(&linflex_reg);
+
+#ifdef CONFIG_SERIAL_FSL_LINFLEXUART_CONSOLE
+	spin_lock_init(&init_lock);
+#endif
+
+	return ret;
+}
+
+static void __exit linflex_serial_exit(void)
+{
+	platform_driver_unregister(&linflex_driver);
+	uart_unregister_driver(&linflex_reg);
+}
+
+module_init(linflex_serial_init);
+module_exit(linflex_serial_exit);
+
+MODULE_DESCRIPTION("Freescale linflex serial port driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h
index 5642c05e0da0..25a3dead4473 100644
--- a/include/uapi/linux/serial_core.h
+++ b/include/uapi/linux/serial_core.h
@@ -293,4 +293,7 @@
 /* SiFive UART */
 #define PORT_SIFIVE_V0	120
 
+/* Freescale Linflex UART */
+#define PORT_LINFLEXUART	121
+
 #endif /* _UAPILINUX_SERIAL_CORE_H */
-- 
2.22.0


^ permalink raw reply related

* [PATCH 3/6] arm64: dts: fsl: Add device tree for S32V234-EVB
From: Stefan-gabriel Mirea @ 2019-08-02 19:47 UTC (permalink / raw)
  To: corbet@lwn.net, robh+dt@kernel.org, mark.rutland@arm.com,
	gregkh@linuxfoundation.org, catalin.marinas@arm.com,
	will@kernel.org, shawnguo@kernel.org, Leo Li
  Cc: jslaby@suse.com, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
	linux-serial@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, Cosmin Stefan Stoica,
	Dan Nica, Larisa Ileana Grigore
In-Reply-To: <20190802194702.30249-1-stefan-gabriel.mirea@nxp.com>

From: Stoica Cosmin-Stefan <cosmin.stoica@nxp.com>

Add initial version of device tree for S32V234-EVB, including nodes for the
4 Cortex-A53 cores, AIPS bus with UART modules, ARM architected timer and
Generic Interrupt Controller (GIC).

Keep SoC level separate from board level to let future boards with this SoC
share common properties, while the dts files will keep board-dependent
properties.

Signed-off-by: Stoica Cosmin-Stefan <cosmin.stoica@nxp.com>
Signed-off-by: Mihaela Martinas <Mihaela.Martinas@freescale.com>
Signed-off-by: Dan Nica <dan.nica@nxp.com>
Signed-off-by: Larisa Grigore <Larisa.Grigore@nxp.com>
Signed-off-by: Phu Luu An <phu.luuan@nxp.com>
Signed-off-by: Stefan-Gabriel Mirea <stefan-gabriel.mirea@nxp.com>
---
 arch/arm64/boot/dts/freescale/Makefile        |   2 +
 .../boot/dts/freescale/fsl-s32v234-evb.dts    |  20 +++
 .../arm64/boot/dts/freescale/fsl-s32v234.dtsi | 130 ++++++++++++++++++
 3 files changed, 152 insertions(+)
 create mode 100644 arch/arm64/boot/dts/freescale/fsl-s32v234-evb.dts
 create mode 100644 arch/arm64/boot/dts/freescale/fsl-s32v234.dtsi

diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
index c043aca66572..3af29b58a833 100644
--- a/arch/arm64/boot/dts/freescale/Makefile
+++ b/arch/arm64/boot/dts/freescale/Makefile
@@ -26,3 +26,5 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mq-librem5-devkit.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mq-zii-ultra-rmb3.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8mq-zii-ultra-zest.dtb
 dtb-$(CONFIG_ARCH_MXC) += imx8qxp-mek.dtb
+
+dtb-$(CONFIG_ARCH_S32) += fsl-s32v234-evb.dtb
diff --git a/arch/arm64/boot/dts/freescale/fsl-s32v234-evb.dts b/arch/arm64/boot/dts/freescale/fsl-s32v234-evb.dts
new file mode 100644
index 000000000000..9b3983402998
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/fsl-s32v234-evb.dts
@@ -0,0 +1,20 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2016-2017 NXP
+ */
+
+/dts-v1/;
+#include "fsl-s32v234.dtsi"
+
+/ {
+	compatible = "fsl,s32v234-evb", "fsl,s32v234";
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart1 {
+	status = "okay";
+};
diff --git a/arch/arm64/boot/dts/freescale/fsl-s32v234.dtsi b/arch/arm64/boot/dts/freescale/fsl-s32v234.dtsi
new file mode 100644
index 000000000000..6d686d3ba997
--- /dev/null
+++ b/arch/arm64/boot/dts/freescale/fsl-s32v234.dtsi
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2016-2018 NXP
+ */
+
+/memreserve/ 0x80000000 0x00010000;
+
+/ {
+	model = "Freescale S32V234";
+	compatible = "fsl,s32v234";
+	interrupt-parent = <&gic>;
+	#address-cells = <2>;
+	#size-cells = <2>;
+
+	aliases {
+		serial0 = &uart0;
+		serial1 = &uart1;
+	};
+
+	cpus {
+		#address-cells = <2>;
+		#size-cells = <0>;
+
+		cpu0: cpu@0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x0 0x0>;
+			enable-method = "spin-table";
+			cpu-release-addr = <0x0 0x80000000>;
+			next-level-cache = <&cluster0_l2_cache>;
+		};
+		cpu1: cpu@1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x0 0x1>;
+			enable-method = "spin-table";
+			cpu-release-addr = <0x0 0x80000000>;
+			next-level-cache = <&cluster0_l2_cache>;
+		};
+		cpu2: cpu@100 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x0 0x100>;
+			enable-method = "spin-table";
+			cpu-release-addr = <0x0 0x80000000>;
+			next-level-cache = <&cluster1_l2_cache>;
+		};
+		cpu3: cpu@101 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a53";
+			reg = <0x0 0x101>;
+			enable-method = "spin-table";
+			cpu-release-addr = <0x0 0x80000000>;
+			next-level-cache = <&cluster1_l2_cache>;
+		};
+
+		cluster0_l2_cache: l2-cache0 {
+			compatible = "cache";
+		};
+
+		cluster1_l2_cache: l2-cache1 {
+			compatible = "cache";
+		};
+	};
+
+	soc {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		compatible = "simple-bus";
+		interrupt-parent = <&gic>;
+		ranges;
+
+		aips0: aips-bus@40000000 {
+			compatible = "simple-bus";
+			#address-cells = <2>;
+			#size-cells = <2>;
+			interrupt-parent = <&gic>;
+			reg = <0x0 0x40000000 0x0 0x7D000>;
+			ranges;
+
+			uart0: serial@40053000 {
+				compatible = "fsl,s32-linflexuart";
+				reg = <0x0 0x40053000 0x0 0x1000>;
+				interrupts = <0 59 1>;
+				status = "disabled";
+			};
+		};
+
+		aips1: aips-bus@40080000 {
+			compatible = "simple-bus";
+			#address-cells = <2>;
+			#size-cells = <2>;
+			interrupt-parent = <&gic>;
+			reg = <0x0 0x40080000 0x0 0x70000>;
+			ranges;
+
+			uart1: serial@400bc000 {
+				compatible = "fsl,s32-linflexuart";
+				reg = <0x0 0x400bc000 0x0 0x1000>;
+				interrupts = <0 60 1>;
+				status = "disabled";
+			};
+		};
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupts = <1 13 0xf08>,
+			     <1 14 0xf08>,
+			     <1 11 0xf08>,
+			     <1 10 0xf08>;
+		/* clock-frequency might be modified by u-boot, depending on the
+		 * chip version.
+		 */
+		clock-frequency = <10000000>;
+	};
+
+	gic: interrupt-controller@7d001000 {
+		compatible = "arm,cortex-a15-gic", "arm,cortex-a9-gic";
+		#interrupt-cells = <3>;
+		#address-cells = <0>;
+		interrupt-controller;
+		reg = <0 0x7d001000 0 0x1000>,
+		      <0 0x7d002000 0 0x2000>,
+		      <0 0x7d004000 0 0x2000>,
+		      <0 0x7d006000 0 0x2000>;
+		interrupts = <1 9 0xf04>;
+	};
+};
-- 
2.22.0


^ permalink raw reply related

* [PATCH 4/6] dt-bindings: serial: Document Freescale LINFlex UART
From: Stefan-gabriel Mirea @ 2019-08-02 19:47 UTC (permalink / raw)
  To: corbet@lwn.net, robh+dt@kernel.org, mark.rutland@arm.com,
	gregkh@linuxfoundation.org, catalin.marinas@arm.com,
	will@kernel.org, shawnguo@kernel.org, Leo Li
  Cc: jslaby@suse.com, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
	linux-serial@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, Cosmin Stefan Stoica,
	Larisa Ileana Grigore
In-Reply-To: <20190802194702.30249-1-stefan-gabriel.mirea@nxp.com>

From: Stoica Cosmin-Stefan <cosmin.stoica@nxp.com>

Add documentation for the serial communication interface module (LINFlex),
found in two instances on S32V234.

Signed-off-by: Stoica Cosmin-Stefan <cosmin.stoica@nxp.com>
Signed-off-by: Larisa Grigore <Larisa.Grigore@nxp.com>
Signed-off-by: Stefan-Gabriel Mirea <stefan-gabriel.mirea@nxp.com>
---
 .../bindings/serial/fsl,s32-linflexuart.txt   | 24 +++++++++++++++++++
 1 file changed, 24 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.txt

diff --git a/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.txt b/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.txt
new file mode 100644
index 000000000000..957ffeaca9f1
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.txt
@@ -0,0 +1,24 @@
+* Freescale Linflex UART
+
+The LINFlexD controller implements several LIN protocol versions, as well as
+support for full-duplex UART communication through 8-bit and 9-bit frames. The
+Linflex UART driver enables operation only in UART mode.
+
+See chapter 47 ("LINFlexD") in the reference manual[1].
+
+Required properties:
+- compatible :
+  - "fsl,s32-linflexuart" for linflex configured in uart mode which
+  is compatible with the one integrated on S32V234 SoC
+- reg : Address and length of the register set for the device
+- interrupts : Should contain uart interrupt
+
+Example:
+uart0:serial@40053000 {
+	compatible = "fsl,s32-linflexuart";
+	reg = <0x0 0x40053000 0x0 0x1000>;
+	interrupts = <0 59 4>;
+	status = "disabled";
+};
+
+[1] https://www.nxp.com/webapp/Download?colCode=S32V234RM
-- 
2.22.0


^ permalink raw reply related

* [PATCH 2/6] arm64: Introduce config for S32
From: Stefan-gabriel Mirea @ 2019-08-02 19:47 UTC (permalink / raw)
  To: corbet@lwn.net, robh+dt@kernel.org, mark.rutland@arm.com,
	gregkh@linuxfoundation.org, catalin.marinas@arm.com,
	will@kernel.org, shawnguo@kernel.org, Leo Li
  Cc: jslaby@suse.com, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
	linux-serial@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, Cosmin Stefan Stoica
In-Reply-To: <20190802194702.30249-1-stefan-gabriel.mirea@nxp.com>

From: Mihaela Martinas <Mihaela.Martinas@freescale.com>

Add configuration option for the Freescale S32 platform family in
Kconfig.platforms. For starters, the only SoC supported will be Treerunner
(S32V234), with a single execution target: the S32V234-EVB (rev 29288)
board.

Signed-off-by: Mihaela Martinas <Mihaela.Martinas@freescale.com>
Signed-off-by: Stoica Cosmin-Stefan <cosmin.stoica@nxp.com>
Signed-off-by: Stefan-Gabriel Mirea <stefan-gabriel.mirea@nxp.com>
---
 arch/arm64/Kconfig.platforms | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index 4778c775de1b..a9a6152d37eb 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -210,6 +210,11 @@ config ARCH_ROCKCHIP
 	  This enables support for the ARMv8 based Rockchip chipsets,
 	  like the RK3368.
 
+config ARCH_S32
+	bool "Freescale S32 SoC Family"
+	help
+	  This enables support for the Freescale S32 family of processors.
+
 config ARCH_SEATTLE
 	bool "AMD Seattle SoC Family"
 	help
-- 
2.22.0


^ permalink raw reply related

* [PATCH 1/6] dt-bindings: arm: fsl: Add the S32V234-EVB board
From: Stefan-gabriel Mirea @ 2019-08-02 19:47 UTC (permalink / raw)
  To: corbet@lwn.net, robh+dt@kernel.org, mark.rutland@arm.com,
	gregkh@linuxfoundation.org, catalin.marinas@arm.com,
	will@kernel.org, shawnguo@kernel.org, Leo Li
  Cc: jslaby@suse.com, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
	linux-serial@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, Eddy Petrisor
In-Reply-To: <20190802194702.30249-1-stefan-gabriel.mirea@nxp.com>

From: Eddy Petrișor <eddy.petrisor@nxp.com>

Add entry for the NXP S32V234 Customer Evaluation Board to the board/SoC
bindings.

Signed-off-by: Eddy Petrișor <eddy.petrisor@nxp.com>
Signed-off-by: Stefan-Gabriel Mirea <stefan-gabriel.mirea@nxp.com>
---
 Documentation/devicetree/bindings/arm/fsl.yaml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/fsl.yaml b/Documentation/devicetree/bindings/arm/fsl.yaml
index 7294ac36f4c0..104d60a11177 100644
--- a/Documentation/devicetree/bindings/arm/fsl.yaml
+++ b/Documentation/devicetree/bindings/arm/fsl.yaml
@@ -309,4 +309,10 @@ properties:
               - fsl,ls2088a-rdb
           - const: fsl,ls2088a
 
+      - description: S32V234 Customer Evaluation Board
+        items:
+          - enum:
+              - fsl,s32v234-evb
+          - const: fsl,s32v234
+
 ...
-- 
2.22.0


^ permalink raw reply related

* [PATCH 0/6] Add initial support for S32V234-EVB
From: Stefan-gabriel Mirea @ 2019-08-02 19:47 UTC (permalink / raw)
  To: corbet@lwn.net, robh+dt@kernel.org, mark.rutland@arm.com,
	gregkh@linuxfoundation.org, catalin.marinas@arm.com,
	will@kernel.org, shawnguo@kernel.org, Leo Li
  Cc: jslaby@suse.com, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
	linux-serial@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org

Hello,

NXP's S32V234[1] ("Treerunner") vision microprocessors are targeted for
high-performance, computationally intensive vision and sensor fusion
applications that require automotive safety levels. They include leading
edge Camera Vision modules like APEX-2, ISP and GPU. The S32V234-EVB and
S32V234-SBC boards are available for customer evaluation.

The following patch series introduces minimal enablement support for the
NXP S32V234-EVB2[2] board, which leverages most of the SoC capabilities.
The series includes a driver for operating the on-chip LINFlexD controller
in UART mode.

In the future, we aim to submit multiple drivers upstream, which can be
found in the kernel of our Auto Linux BSP[3] ("ALB"), starting with basic
pinmuxing, clock and uSDHC drivers.

For validation, you can use the U-Boot bootloader in the ALB[4], which we
build and test with our patched version of the Linaro GCC 6.3.1 2017.05
toolchain for ARM 64-bit, with sources available on [5].

[1] https://www.nxp.com/products/processors-and-microcontrollers/arm-based-processors-and-mcus/s32-automotive-platform/vision-processor-for-front-and-surround-view-camera-machine-learning-and-sensor-fusion:S32V234
[2] https://www.nxp.com/support/developer-resources/evaluation-and-development-boards/ultra-reliable-dev-platforms/s32v-mpus-platforms/s32v-vision-and-sensor-fusion-evaluation-system:S32V234EVB
[3] https://source.codeaurora.org/external/autobsps32/linux/
[4] https://source.codeaurora.org/external/autobsps32/u-boot/
[5] https://source.codeaurora.org/external/s32ds/compiler/gcc/

Eddy Petrișor (1):
  dt-bindings: arm: fsl: Add the S32V234-EVB board

Mihaela Martinas (2):
  arm64: Introduce config for S32
  arm64: defconfig: Enable configs for S32V234

Stefan-Gabriel Mirea (1):
  tty: serial: Add linflexuart driver for S32V234

Stoica Cosmin-Stefan (2):
  arm64: dts: fsl: Add device tree for S32V234-EVB
  dt-bindings: serial: Document Freescale LINFlex UART

 .../admin-guide/kernel-parameters.txt         |   6 +
 .../devicetree/bindings/arm/fsl.yaml          |   6 +
 .../bindings/serial/fsl,s32-linflexuart.txt   |  24 +
 arch/arm64/Kconfig.platforms                  |   5 +
 arch/arm64/boot/dts/freescale/Makefile        |   2 +
 .../boot/dts/freescale/fsl-s32v234-evb.dts    |  20 +
 .../arm64/boot/dts/freescale/fsl-s32v234.dtsi | 130 +++
 arch/arm64/configs/defconfig                  |   3 +
 drivers/tty/serial/Kconfig                    |  15 +
 drivers/tty/serial/Makefile                   |   1 +
 drivers/tty/serial/fsl_linflexuart.c          | 956 ++++++++++++++++++
 include/uapi/linux/serial_core.h              |   3 +
 12 files changed, 1171 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/serial/fsl,s32-linflexuart.txt
 create mode 100644 arch/arm64/boot/dts/freescale/fsl-s32v234-evb.dts
 create mode 100644 arch/arm64/boot/dts/freescale/fsl-s32v234.dtsi
 create mode 100644 drivers/tty/serial/fsl_linflexuart.c

-- 
2.22.0


^ permalink raw reply

* Re: [PATCH] Documentation/checkpatch: Prefer str_has_prefix over strncmp
From: Chuhong Yuan @ 2019-08-02 15:21 UTC (permalink / raw)
  To: Jonathan Corbet; +Cc: Andy Whitcroft, Joe Perches, linux-doc, LKML
In-Reply-To: <20190802073858.19a86f82@lwn.net>

Jonathan Corbet <corbet@lwn.net> 于2019年8月2日周五 下午9:38写道:
>
> On Fri,  2 Aug 2019 14:25:37 +0800
> Chuhong Yuan <hslester96@gmail.com> wrote:
>
> > Add strncmp() to Documentation/process/deprecated.rst since
> > using strncmp() to check whether a string starts with a
> > prefix is error-prone.
> > The safe replacement is str_has_prefix().
>
> Is that the *only* use of strncmp()?

This is not the only use of strncmp().
Maybe add a case description like strncpy() is more precise?
For example, "strncmp() on string prefix".

>
> > Also add check to the newly introduced deprecated_string_apis
> > in checkpatch.pl.
> >
> > This patch depends on patch:
> > "Documentation/checkpatch: Prefer stracpy/strscpy over
> > strcpy/strlcpy/strncpy."
> >
> > Signed-off-by: Chuhong Yuan <hslester96@gmail.com>
> > ---
> >  Documentation/process/deprecated.rst | 8 ++++++++
> >  scripts/checkpatch.pl                | 1 +
> >  2 files changed, 9 insertions(+)
> >
> > diff --git a/Documentation/process/deprecated.rst b/Documentation/process/deprecated.rst
> > index 56280e108d5a..22d3f0dbcf61 100644
> > --- a/Documentation/process/deprecated.rst
> > +++ b/Documentation/process/deprecated.rst
> > @@ -109,6 +109,14 @@ the given limit of bytes to copy. This is inefficient and can lead to
> >  linear read overflows if a source string is not NUL-terminated. The
> >  safe replacement is stracpy() or strscpy().
> >
> > +strncmp()
> > +---------
> > +:c:func:`strncmp` is often used to test if a string starts with a prefix
>
> Please don't use :c:func: anymore; just say strncmp() and the right things
> will happen.
>

I will revise this in the next version.

Regards,
Chuhong

> Thanks,
>
> jon

^ permalink raw reply

* [PATCH 0/9] arm64: Stolen time support
From: Steven Price @ 2019-08-02 14:50 UTC (permalink / raw)
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Paolo Bonzini,
	Radim Krčmář, Russell King, Will Deacon,
	James Morse, Julien Thierry, Suzuki K Pouloze, kvm, kvmarm,
	linux-arm-kernel, linux-doc, linux-kernel

This series add support for paravirtualized time for arm64 guests and
KVM hosts following the specification in Arm's document DEN 0057A:

https://developer.arm.com/docs/den0057/a

It implements support for stolen time, allowing the guest to
identify time when it is forcibly not executing.

It doesn't implement support for Live Physical Time (LPT) as there are
some concerns about the overheads and approach in the above
specification, and I expect an updated version of the specification to
be released soon with just the stolen time parts.

I previously posted a series including LPT (as well as stolen time):
https://lore.kernel.org/kvmarm/20181212150226.38051-1-steven.price@arm.com/

Patches 2, 5, 7 and 8 are cleanup patches and could be taken separately.

Christoffer Dall (1):
  KVM: arm/arm64: Factor out hypercall handling from PSCI code

Steven Price (8):
  KVM: arm64: Document PV-time interface
  KVM: arm64: Implement PV_FEATURES call
  KVM: arm64: Support stolen time reporting via shared structure
  KVM: Allow kvm_device_ops to be const
  KVM: arm64: Provide a PV_TIME device to user space
  arm/arm64: Provide a wrapper for SMCCC 1.1 calls
  arm/arm64: Make use of the SMCCC 1.1 wrapper
  arm64: Retrieve stolen time as paravirtualized guest

 Documentation/virtual/kvm/arm/pvtime.txt | 107 +++++++++++++
 arch/arm/kvm/Makefile                    |   2 +-
 arch/arm/kvm/handle_exit.c               |   2 +-
 arch/arm/mm/proc-v7-bugs.c               |  13 +-
 arch/arm64/include/asm/kvm_host.h        |  13 +-
 arch/arm64/include/asm/kvm_mmu.h         |   2 +
 arch/arm64/include/asm/pvclock-abi.h     |  20 +++
 arch/arm64/include/uapi/asm/kvm.h        |   6 +
 arch/arm64/kernel/Makefile               |   1 +
 arch/arm64/kernel/cpu_errata.c           |  80 ++++------
 arch/arm64/kernel/kvm.c                  | 155 ++++++++++++++++++
 arch/arm64/kvm/Kconfig                   |   1 +
 arch/arm64/kvm/Makefile                  |   2 +
 arch/arm64/kvm/handle_exit.c             |   4 +-
 include/kvm/arm_hypercalls.h             |  44 ++++++
 include/kvm/arm_psci.h                   |   2 +-
 include/linux/arm-smccc.h                |  58 +++++++
 include/linux/cpuhotplug.h               |   1 +
 include/linux/kvm_host.h                 |   4 +-
 include/linux/kvm_types.h                |   2 +
 include/uapi/linux/kvm.h                 |   2 +
 virt/kvm/arm/arm.c                       |  18 +++
 virt/kvm/arm/hypercalls.c                | 138 ++++++++++++++++
 virt/kvm/arm/mmu.c                       |  44 ++++++
 virt/kvm/arm/psci.c                      |  84 +---------
 virt/kvm/arm/pvtime.c                    | 190 +++++++++++++++++++++++
 virt/kvm/kvm_main.c                      |   6 +-
 27 files changed, 848 insertions(+), 153 deletions(-)
 create mode 100644 Documentation/virtual/kvm/arm/pvtime.txt
 create mode 100644 arch/arm64/include/asm/pvclock-abi.h
 create mode 100644 arch/arm64/kernel/kvm.c
 create mode 100644 include/kvm/arm_hypercalls.h
 create mode 100644 virt/kvm/arm/hypercalls.c
 create mode 100644 virt/kvm/arm/pvtime.c

-- 
2.20.1


^ permalink raw reply

* [PATCH 1/9] KVM: arm64: Document PV-time interface
From: Steven Price @ 2019-08-02 14:50 UTC (permalink / raw)
  Cc: Steven Price, Catalin Marinas, Marc Zyngier, Paolo Bonzini,
	Radim Krčmář, Russell King, Will Deacon,
	James Morse, Julien Thierry, Suzuki K Pouloze, kvm, kvmarm,
	linux-arm-kernel, linux-doc, linux-kernel
In-Reply-To: <20190802145017.42543-1-steven.price@arm.com>

Introduce a paravirtualization interface for KVM/arm64 based on the
"Arm Paravirtualized Time for Arm-Base Systems" specification DEN 0057A.

This only adds the details about "Stolen Time" as the details of "Live
Physical Time" have not been fully agreed.

User space can specify a reserved area of memory for the guest and
inform KVM to populate the memory with information on time that the host
kernel has stolen from the guest.

A hypercall interface is provided for the guest to interrogate the
hypervisor's support for this interface and the location of the shared
memory structures.

Signed-off-by: Steven Price <steven.price@arm.com>
---
 Documentation/virtual/kvm/arm/pvtime.txt | 107 +++++++++++++++++++++++
 1 file changed, 107 insertions(+)
 create mode 100644 Documentation/virtual/kvm/arm/pvtime.txt

diff --git a/Documentation/virtual/kvm/arm/pvtime.txt b/Documentation/virtual/kvm/arm/pvtime.txt
new file mode 100644
index 000000000000..e6ae9799e1d5
--- /dev/null
+++ b/Documentation/virtual/kvm/arm/pvtime.txt
@@ -0,0 +1,107 @@
+Paravirtualized time support for arm64
+======================================
+
+Arm specification DEN0057/A defined a standard for paravirtualised time
+support for Aarch64 guests:
+
+https://developer.arm.com/docs/den0057/a
+
+KVM/Arm64 implements the stolen time part of this specification by providing
+some hypervisor service calls to support a paravirtualized guest obtaining a
+view of the amount of time stolen from its execution.
+
+Two new SMCCC compatible hypercalls are defined:
+
+PV_FEATURES 0xC5000020
+PV_TIME_ST  0xC5000022
+
+These are only available in the SMC64/HVC64 calling convention as
+paravirtualized time is not available to 32 bit Arm guests.
+
+PV_FEATURES
+    Function ID:  (uint32)  : 0xC5000020
+    PV_func_id:   (uint32)  : Either PV_TIME_LPT or PV_TIME_ST
+    Return value: (int32)   : NOT_SUPPORTED (-1) or SUCCESS (0) if the relevant
+                              PV-time feature is supported by the hypervisor.
+
+PV_TIME_ST
+    Function ID:  (uint32)  : 0xC5000022
+    Return value: (int64)   : IPA of the stolen time data structure for this
+                              (V)CPU. On failure:
+                              NOT_SUPPORTED (-1)
+
+Stolen Time
+-----------
+
+The structure pointed to by the PV_TIME_ST hypercall is as follows:
+
+  Field       | Byte Length | Byte Offset | Description
+  ----------- | ----------- | ----------- | --------------------------
+  Revision    |      4      |      0      | Must be 0 for version 0.1
+  Attributes  |      4      |      4      | Must be 0
+  Stolen time |      8      |      8      | Stolen time in unsigned
+              |             |             | nanoseconds indicating how
+              |             |             | much time this VCPU thread
+              |             |             | was involuntarily not
+              |             |             | running on a physical CPU.
+
+The structure will be updated by the hypervisor periodically as time is stolen
+from the VCPU. It will be present within a reserved region of the normal
+memory given to the guest. The guest should not attempt to write into this
+memory. There is a structure by VCPU of the guest.
+
+User space interface
+====================
+
+User space can request that KVM provide the paravirtualized time interface to
+a guest by creating a KVM_DEV_TYPE_ARM_PV_TIME device, for example:
+
+    struct kvm_create_device pvtime_device = {
+            .type = KVM_DEV_TYPE_ARM_PV_TIME,
+            .attr = 0,
+            .flags = 0,
+    };
+
+    pvtime_fd = ioctl(vm_fd, KVM_CREATE_DEVICE, &pvtime_device);
+
+The guest IPA of the structures must be given to KVM. This is the base address
+of an array of stolen time structures (one for each VCPU). For example:
+
+    struct kvm_device_attr st_base = {
+            .group = KVM_DEV_ARM_PV_TIME_PADDR,
+            .attr = KVM_DEV_ARM_PV_TIME_ST,
+            .addr = (u64)(unsigned long)&st_paddr
+    };
+
+    ioctl(pvtime_fd, KVM_SET_DEVICE_ATTR, &st_base);
+
+For migration (or save/restore) of a guest it is necessary to save the contents
+of the shared page(s) and later restore them. KVM_DEV_ARM_PV_TIME_STATE_SIZE
+provides the size of this data and KVM_DEV_ARM_PV_TIME_STATE allows the state
+to be read/written.
+
+It is also necessary for the physical address to be set identically when
+restoring.
+
+    void *save_state(int fd, u64 attr, u32 *size) {
+        struct kvm_device_attr get_size = {
+                .group = KVM_DEV_ARM_PV_TIME_STATE_SIZE,
+                .attr = attr,
+                .addr = (u64)(unsigned long)size
+        };
+
+        ioctl(fd, KVM_GET_DEVICE_ATTR, get_size);
+
+        void *buffer = malloc(*size);
+
+        struct kvm_device_attr get_state = {
+                .group = KVM_DEV_ARM_PV_TIME_STATE,
+                .attr = attr,
+                .addr = (u64)(unsigned long)size
+        };
+
+        ioctl(fd, KVM_GET_DEVICE_ATTR, buffer);
+    }
+
+    void *st_state = save_state(pvtime_fd, KVM_DEV_ARM_PV_TIME_ST, &st_size);
+
-- 
2.20.1


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox