* [PATCHv4 2/7] arm64: dts: stratix10: add stratix10 service driver binding to base dtsi
From: richard.gong at linux.intel.com @ 2018-05-04 14:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1525443697-31009-1-git-send-email-richard.gong@linux.intel.com>
From: Richard Gong <richard.gong@intel.com>
Add Intel Stratix10 service layer to the device tree
Signed-off-by: Richard Gong <richard.gong@intel.com>
Signed-off-by: Alan Tull <atull@kernel.org>
---
v2: Change to put service layer driver node under the firmware node
Change compatible to "intel, stratix10-svc"
v3: No change
v4: s/service driver/stratix10 service driver/ in subject line
---
arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi b/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi
index 0b28f1f..985b9e5 100644
--- a/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi
+++ b/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi
@@ -24,6 +24,19 @@
#address-cells = <2>;
#size-cells = <2>;
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ service_reserved: svcbuffer at 0 {
+ compatible = "shared-dma-pool";
+ reg = <0x0 0x0 0x0 0x1000000>;
+ alignment = <0x1000>;
+ no-map;
+ };
+ };
+
cpus {
#address-cells = <1>;
#size-cells = <0>;
@@ -454,5 +467,13 @@
resets = <&rst WATCHDOG3_RESET>;
status = "disabled";
};
+
+ firmware {
+ svc {
+ compatible = "intel,stratix10-svc";
+ method = "smc";
+ memory-region = <&service_reserved>;
+ };
+ };
};
};
--
2.7.4
^ permalink raw reply related
* [PATCHv4 3/7] driver, misc: add Intel Stratix10 service layer driver
From: richard.gong at linux.intel.com @ 2018-05-04 14:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1525443697-31009-1-git-send-email-richard.gong@linux.intel.com>
From: Richard Gong <richard.gong@intel.com>
Some features of the Intel Stratix10 SoC require a level of privilege
higher than the kernel is granted. Such secure features include
FPGA programming. In terms of the ARMv8 architecture, the kernel runs
at Exception Level 1 (EL1), access to the features requires
Exception Level 3 (EL3).
The Intel Stratix10 SoC service layer provides an in kernel API for
drivers to request access to the secure features. The requests are queued
and processed one by one. ARM?s SMCCC is used to pass the execution
of the requests on to a secure monitor (EL3).
The header file stratix10-sve-client.h defines the interface between
service providers (FPGA manager is one of them) and service layer.
The header file stratix10-smc.h defines the secure monitor call (SMC)
message protocols used for service layer driver in normal world
(EL1) to communicate with secure monitor SW in secure monitor exception
level 3 (EL3).
Signed-off-by: Richard Gong <richard.gong@intel.com>
Signed-off-by: Alan Tull <atull@kernel.org>
---
v2: Remove intel-service subdirectory and intel-service.h, move
intel-smc.h and intel-service.c to driver/misc subdirectory
Correct SPDX markers
Change service layer driver be 'default n'
Remove global variables
Add timeout for do..while() loop
Add kernel-doc for the functions and structs, correct multiline comments
Replace kfifo_in/kfifo_out with kfifo_in_spinlocked/kfifo_out_spinlocked
rename struct intel_svc_data (at client header) to intel_svc_client_msg
rename struct intel_svc_private_mem to intel_svc_data
Other corrections/changes from Intel internal code reviews
v3: Change all exported functions with "intel_svc_" as the prefix
Increase timeout values for claiming back submitted buffer(s)
Rename struct intel_command_reconfig_payload to
struct intel_svc_command_reconfig_payload
Add pr_err() to provide the error return value
Other corrections/changes
v4: s/intel/stratix10/ on some variables, structs, functions, and file names
intel-service.c -> stratix10-svc.c
intel-smc.h -> stratix10-smc.h
intel-service-client.h -> stratix10-svc-client.h
Remove non-kernel-doc formatting
---
drivers/misc/Kconfig | 12 +
drivers/misc/Makefile | 1 +
drivers/misc/stratix10-smc.h | 203 ++++++++
drivers/misc/stratix10-svc.c | 945 +++++++++++++++++++++++++++++++++++
include/linux/stratix10-svc-client.h | 190 +++++++
5 files changed, 1351 insertions(+)
create mode 100644 drivers/misc/stratix10-smc.h
create mode 100644 drivers/misc/stratix10-svc.c
create mode 100644 include/linux/stratix10-svc-client.h
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 5d71300..5d5b648 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -138,6 +138,18 @@ config INTEL_MID_PTI
an Intel Atom (non-netbook) mobile device containing a MIPI
P1149.7 standard implementation.
+config STRATIX10_SERVICE
+ tristate "Stratix10 Service Layer"
+ depends on HAVE_ARM_SMCCC
+ default n
+ help
+ Stratix10 service layer runs at privileged exception level, interfaces with
+ the service providers (FPGA manager is one of them) and manages secure
+ monitor call to communicate with secure monitor software at secure monitor
+ exception level.
+
+ Say Y here if you want Stratix10 service layer support.
+
config SGI_IOC4
tristate "SGI IOC4 Base IO support"
depends on PCI
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 20be70c..99fed8b 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_AD525X_DPOT) += ad525x_dpot.o
obj-$(CONFIG_AD525X_DPOT_I2C) += ad525x_dpot-i2c.o
obj-$(CONFIG_AD525X_DPOT_SPI) += ad525x_dpot-spi.o
obj-$(CONFIG_INTEL_MID_PTI) += pti.o
+obj-$(CONFIG_STRATIX10_SERVICE) += stratix10-svc.o
obj-$(CONFIG_ATMEL_SSC) += atmel-ssc.o
obj-$(CONFIG_ATMEL_TCLIB) += atmel_tclib.o
obj-$(CONFIG_DUMMY_IRQ) += dummy-irq.o
diff --git a/drivers/misc/stratix10-smc.h b/drivers/misc/stratix10-smc.h
new file mode 100644
index 0000000..6cda41f
--- /dev/null
+++ b/drivers/misc/stratix10-smc.h
@@ -0,0 +1,203 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2017-2018, Intel Corporation
+ */
+
+#ifndef __STRATIX10_SMC_H
+#define __STRATIX10_SMC_H
+
+#include <linux/arm-smccc.h>
+#include <linux/bitops.h>
+
+/**
+ * This file defines the Secure Monitor Call (SMC) message protocol used for
+ * service layer driver in normal world (EL1) to communicate with secure
+ * monitor software in Secure Monitor Exception Level 3 (EL3).
+ *
+ * This file is shared with secure firmware (FW) which is out of kernel tree.
+ *
+ * An ARM SMC instruction takes a function identifier and up to 6 64-bit
+ * register values as arguments, and can return up to 4 64-bit register
+ * value. The operation of the secure monitor is determined by the parameter
+ * values passed in through registers.
+
+ * EL1 and EL3 communicates pointer as physical address rather than the
+ * virtual address.
+ *
+ * Functions specified by ARM SMC Calling convention:
+ *
+ * FAST call executes atomic operations, returns when the requested operation
+ * has completed.
+ * STD call starts a operation which can be preempted by a non-secure
+ * interrupt. The call can return before the requested operation has
+ * completed.
+ *
+ * a0..a7 is used as register names in the descriptions below, on arm32
+ * that translates to r0..r7 and on arm64 to w0..w7.
+ */
+
+#define INTEL_SIP_SMC_STD_CALL_VAL(func_num) \
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_STD_CALL, ARM_SMCCC_SMC_64, \
+ ARM_SMCCC_OWNER_SIP, (func_num))
+
+#define INTEL_SIP_SMC_FAST_CALL_VAL(func_num) \
+ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, ARM_SMCCC_SMC_64, \
+ ARM_SMCCC_OWNER_SIP, (func_num))
+
+/**
+ * Return values in INTEL_SIP_SMC_* call
+ *
+ * INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION:
+ * Secure monitor software doesn't recognize the request.
+ *
+ * INTEL_SIP_SMC_STATUS_OK:
+ * FPGA configuration completed successfully,
+ * In case of FPGA configuration write operation, it means secure monitor
+ * software can accept the next chunk of FPGA configuration data.
+ *
+ * INTEL_SIP_SMC_FPGA_CONFIG_STATUS_BUSY:
+ * In case of FPGA configuration write operation, it means secure monitor
+ * software is still processing previous data & can't accept the next chunk
+ * of data. Service driver needs to issue
+ * INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE call to query the
+ * completed block(s).
+ *
+ * INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR:
+ * There is error during the FPGA configuration process.
+ */
+#define INTEL_SIP_SMC_RETURN_UNKNOWN_FUNCTION 0xFFFFFFFF
+#define INTEL_SIP_SMC_STATUS_OK 0x0
+#define INTEL_SIP_SMC_FPGA_CONFIG_STATUS_BUSY 0x1
+#define INTEL_SIP_SMC_FPGA_CONFIG_STATUS_REJECTED 0x2
+#define INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR 0x4
+
+/**
+ * Request INTEL_SIP_SMC_FPGA_CONFIG_START
+ *
+ * Sync call used by service driver at EL1 to request the FPGA in EL3 to
+ * be prepare to receive a new configuration.
+ *
+ * Call register usage:
+ * a0: INTEL_SIP_SMC_FPGA_CONFIG_START.
+ * a1: flag for full or partial configuration
+ * 0 full reconfiguration.
+ * 1 partial reconfiguration.
+ * a2-7: not used.
+ *
+ * Return status:
+ * a0: INTEL_SIP_SMC_STATUS_OK, or INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR.
+ * a1-3: not used.
+ */
+#define INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_START 1
+#define INTEL_SIP_SMC_FPGA_CONFIG_START \
+ INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_START)
+
+/**
+ * Request INTEL_SIP_SMC_FPGA_CONFIG_WRITE
+ *
+ * Async call used by service driver at EL1 to provide FPGA configuration data
+ * to secure world.
+ *
+ * Call register usage:
+ * a0: INTEL_SIP_SMC_FPGA_CONFIG_WRITE.
+ * a1: 64bit physical address of the configuration data memory block
+ * a2: Size of configuration data block.
+ * a3-7: not used.
+ *
+ * Return status:
+ * a0: INTEL_SIP_SMC_STATUS_OK, INTEL_SIP_SMC_FPGA_CONFIG_STATUS_BUSY or
+ * INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR.
+ * a1: 64bit physical address of 1st completed memory block if any completed
+ * block, otherwise zero value.
+ * a2: 64bit physical address of 2nd completed memory block if any completed
+ * block, otherwise zero value.
+ * a3: 64bit physical address of 3rd completed memory block if any completed
+ * block, otherwise zero value.
+ */
+#define INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_WRITE 2
+#define INTEL_SIP_SMC_FPGA_CONFIG_WRITE \
+ INTEL_SIP_SMC_STD_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_WRITE)
+
+/**
+ * Request INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE
+ *
+ * Sync call used by service driver at EL1 to track the completed write
+ * transactions. This request is called after INTEL_SIP_SMC_FPGA_CONFIG_WRITE
+ * call returns INTEL_SIP_SMC_FPGA_CONFIG_STATUS_BUSY.
+ *
+ * Call register usage:
+ * a0: INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE.
+ * a1-7: not used.
+ *
+ * Return status:
+ * a0: INTEL_SIP_SMC_STATUS_OK, INTEL_SIP_SMC_FPGA_CONFIG_STATUS_BUSY or
+ * INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR.
+ * a1: 64bit physical address of 1st completed memory block.
+ * a2: 64bit physical address of 2nd completed memory block if
+ * any completed block, otherwise zero value.
+ * a3: 64bit physical address of 3rd completed memory block if
+ * any completed block, otherwise zero value.
+ */
+#define INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_COMPLETED_WRITE 3
+#define INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE \
+INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_COMPLETED_WRITE)
+
+/**
+ * Request INTEL_SIP_SMC_FPGA_CONFIG_ISDONE
+ *
+ * Sync call used by service driver at EL1 to inform secure world that all
+ * data are sent, to check whether or not the secure world had completed
+ * the FPGA configuration process.
+ *
+ * Call register usage:
+ * a0: INTEL_SIP_SMC_FPGA_CONFIG_ISDONE.
+ * a1-7: not used.
+ *
+ * Return status:
+ * a0: INTEL_SIP_SMC_STATUS_OK, INTEL_SIP_SMC_FPGA_CONFIG_STATUS_BUSY or
+ * INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR.
+ * a1-3: not used.
+ */
+#define INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_ISDONE 4
+#define INTEL_SIP_SMC_FPGA_CONFIG_ISDONE \
+ INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_ISDONE)
+
+/**
+ * Request INTEL_SIP_SMC_FPGA_CONFIG_GET_MEM
+ *
+ * Sync call used by service driver at EL1 to query the physical address of
+ * memory block reserved by secure monitor software.
+ *
+ * Call register usage:
+ * a0:INTEL_SIP_SMC_FPGA_CONFIG_GET_MEM.
+ * a1-7: not used.
+ *
+ * Return status:
+ * a0: INTEL_SIP_SMC_STATUS_OK or INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR.
+ * a1: start of physical address of reserved memory block.
+ * a2: size of reserved memory block.
+ * a3: not used.
+ */
+#define INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_GET_MEM 5
+#define INTEL_SIP_SMC_FPGA_CONFIG_GET_MEM \
+ INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_GET_MEM)
+
+/**
+ * Request INTEL_SIP_SMC_FPGA_CONFIG_LOOPBACK
+ *
+ * For SMC loop-back mode only, used for internal integration, debugging
+ * or troubleshooting.
+ *
+ * Call register usage:
+ * a0: INTEL_SIP_SMC_FPGA_CONFIG_LOOPBACK.
+ * a1-7: not used.
+ *
+ * Return status:
+ * a0: INTEL_SIP_SMC_STATUS_OK or INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR.
+ * a1-3: not used.
+ */
+#define INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_LOOPBACK 6
+#define INTEL_SIP_SMC_FPGA_CONFIG_LOOPBACK \
+ INTEL_SIP_SMC_FAST_CALL_VAL(INTEL_SIP_SMC_FUNCID_FPGA_CONFIG_LOOPBACK)
+
+#endif
diff --git a/drivers/misc/stratix10-svc.c b/drivers/misc/stratix10-svc.c
new file mode 100644
index 0000000..1daceac
--- /dev/null
+++ b/drivers/misc/stratix10-svc.c
@@ -0,0 +1,945 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2017-2018, Intel Corporation
+ */
+
+#include <linux/arm-smccc.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/genalloc.h>
+#include <linux/stratix10-svc-client.h>
+#include <linux/io.h>
+#include <linux/kfifo.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include "stratix10-smc.h"
+
+/**
+ * SVC_NUM_DATA_IN_FIFO - number of struct stratix10_svc_data in the FIFO
+ *
+ * SVC_NUM_CHANNEL - number of channel supported by service layer driver
+ *
+ * FPGA_CONFIG_DATA_CLAIM_TIMEOUT_MS - claim back the submitted buffer(s)
+ * from the secure world for FPGA manager to reuse, or to free the buffer(s)
+ * when all bit-stream data had be send.
+ *
+ * FPGA_CONFIG_STATUS_TIMEOUT_SEC - poll the FPGA configuration status,
+ * service layer will return error to FPGA manager when timeout occurs,
+ * timeout is set to 30 seconds (30 * 1000) at Intel Stratix10 SoC.
+ */
+#define SVC_NUM_DATA_IN_FIFO 32
+#define SVC_NUM_CHANNEL 2
+#define FPGA_CONFIG_DATA_CLAIM_TIMEOUT_MS 200
+#define FPGA_CONFIG_STATUS_TIMEOUT_SEC 30
+
+typedef void (svc_invoke_fn)(unsigned long, unsigned long, unsigned long,
+ unsigned long, unsigned long, unsigned long,
+ unsigned long, unsigned long,
+ struct arm_smccc_res *);
+
+struct stratix10_svc_chan;
+
+/**
+ * struct stratix10_svc_sh_memory - service shared memory structure
+ * @sync_complete: state for a completion
+ * @addr: physical address of shared memory block
+ * @size: size of shared memory block
+ * @invoke_fn: function to issue secure monitor or hypervisor call
+ *
+ * This struct is used to save physical address and size of shared memory
+ * block. The shared memory blocked is allocated by secure monitor software
+ * at secure world.
+ *
+ * Service layer driver uses the physical address and size to create a memory
+ * pool, then allocates data buffer from that memory pool for service client.
+ */
+struct stratix10_svc_sh_memory {
+ struct completion sync_complete;
+ unsigned long addr;
+ unsigned long size;
+ svc_invoke_fn *invoke_fn;
+};
+
+/**
+ * struct stratix10_svc_data_mem - service memory structure
+ * @vaddr: virtual address
+ * @paddr: physical address
+ * @size: size of memory
+ * @node: link list head node
+ *
+ * This struct is used in a list that keeps track of buffers which have
+ * been allocated or freed from the memory pool. Service layer driver also
+ * uses this struct to transfer physical address to virtual address.
+ */
+struct stratix10_svc_data_mem {
+ void *vaddr;
+ phys_addr_t paddr;
+ size_t size;
+ struct list_head node;
+};
+
+/**
+ * struct stratix10_svc_data - service data structure
+ * @chan: service channel
+ * @paddr: playload physical address
+ * @size: playload size
+ * @command: service command requested by client
+ *
+ * This struct is used in service FIFO for inter-process communication.
+ */
+struct stratix10_svc_data {
+ struct stratix10_svc_chan *chan;
+ phys_addr_t paddr;
+ size_t size;
+ u32 command;
+};
+
+/**
+ * struct stratix10_svc_controller - service controller
+ * @dev: device
+ * @chans: array of service channels
+ * $num_chans: number of channels in 'chans' array
+ * @node: list management
+ * @genpool: memory pool pointing to the memory region
+ * @task: pointer to the thread task which handles SMC or HVC call
+ * @svc_fifo: a queue for storing service message data
+ * @complete_status: state for completion
+ * @svc_fifo_lock: protect access to service message data queue
+ * @invoke_fn: function to issue secure monitor call or hypervisor call
+ *
+ * This struct is used to create communication channels for service clients, to
+ * handle secure monitor or hypervisor call.
+ */
+struct stratix10_svc_controller {
+ struct device *dev;
+ struct stratix10_svc_chan *chans;
+ int num_chans;
+ struct list_head node;
+ struct gen_pool *genpool;
+ struct task_struct *task;
+ struct kfifo svc_fifo;
+ struct completion complete_status;
+ spinlock_t svc_fifo_lock;
+ svc_invoke_fn *invoke_fn;
+};
+
+/**
+ * struct stratix10_svc_chan - service communication channel
+ * @ctrl: pointer to service controller which is the provider of this channel
+ * @scl: pointer to service client which owns the channel
+ * @name: service client name associated with the channel
+ * @lock: protect access to the channel
+ *
+ * This struct is used by service client to communicate with service layer, each
+ * service client has its own channel created by service controller.
+ */
+struct stratix10_svc_chan {
+ struct stratix10_svc_controller *ctrl;
+ struct stratix10_svc_client *scl;
+ char *name;
+ spinlock_t lock;
+};
+
+static LIST_HEAD(svc_ctrl);
+static LIST_HEAD(svc_data_mem);
+
+/**
+ * stratix10_svc_request_channel_byname() - request a service channel
+ * @client: pointer to service client
+ * @name: service client name
+ *
+ * This function is used by service client to request a service channel.
+ *
+ * Return: a pointer to channel assigned to the client on success,
+ * or ERR_PTR() on error.
+ */
+struct stratix10_svc_chan *stratix10_svc_request_channel_byname(
+ struct stratix10_svc_client *client, const char *name)
+{
+ struct device *dev = client->dev;
+ struct stratix10_svc_controller *controller;
+ struct stratix10_svc_chan *chan;
+ unsigned long flag;
+ int i;
+
+ chan = ERR_PTR(-EPROBE_DEFER);
+ if (list_empty(&svc_ctrl))
+ return ERR_PTR(-ENODEV);
+
+ controller = list_first_entry(&svc_ctrl,
+ struct stratix10_svc_controller, node);
+ for (i = 0; i < SVC_NUM_CHANNEL; i++) {
+ if (!strcmp(controller->chans[i].name, name)) {
+ chan = &controller->chans[i];
+ break;
+ }
+ }
+
+ if (chan->scl || !try_module_get(controller->dev->driver->owner)) {
+ dev_dbg(dev, "%s: svc not free\n", __func__);
+ return ERR_PTR(-EBUSY);
+ }
+
+ spin_lock_irqsave(&chan->lock, flag);
+ chan->scl = client;
+ spin_unlock_irqrestore(&chan->lock, flag);
+
+ return chan;
+}
+EXPORT_SYMBOL_GPL(stratix10_svc_request_channel_byname);
+
+/**
+ * stratix10_svc_free_channel() - free service channel
+ * @chan: service channel to be freed
+ *
+ * This function is used by service client to free a service channel.
+ */
+void stratix10_svc_free_channel(struct stratix10_svc_chan *chan)
+{
+ unsigned long flag;
+
+ spin_lock_irqsave(&chan->lock, flag);
+ chan->scl = NULL;
+ module_put(chan->ctrl->dev->driver->owner);
+ spin_unlock_irqrestore(&chan->lock, flag);
+}
+EXPORT_SYMBOL_GPL(stratix10_svc_free_channel);
+
+/**
+ * stratix10_svc_send() - send a message data to the remote
+ * @chan: service channel assigned to the client
+ * @msg: message data to be sent, in the format of
+ * "struct stratix10_svc_client_msg"
+ *
+ * This function is used by service client to add a message to the service
+ * layer driver's queue for being sent to the secure world.
+ *
+ * Return: 0 for success, -ENOMEM or -ENOBUFS on error.
+ */
+int stratix10_svc_send(struct stratix10_svc_chan *chan, void *msg)
+{
+ struct stratix10_svc_client_msg
+ *p_msg = (struct stratix10_svc_client_msg *)msg;
+ struct stratix10_svc_data_mem *p_mem;
+ struct stratix10_svc_data *p_data;
+ int ret = 0;
+
+ p_data = kmalloc(sizeof(*p_data), GFP_KERNEL);
+ if (!p_data)
+ return -ENOMEM;
+
+ pr_debug("%s: sent P-va=%p, P-com=%x, P-size=%u\n", __func__,
+ p_msg->payload, p_msg->command,
+ (unsigned int)p_msg->payload_length);
+
+ p_data->paddr = 0;
+ list_for_each_entry(p_mem, &svc_data_mem, node) {
+ if (p_mem->vaddr == p_msg->payload) {
+ p_data->paddr = p_mem->paddr;
+ break;
+ }
+ }
+
+ p_data->command = p_msg->command;
+ p_data->size = p_msg->payload_length;
+ p_data->chan = chan;
+ pr_debug("%s: put to FIFO pa=0x%016x, cmd=%x, size=%u\n", __func__,
+ (unsigned int)p_data->paddr, p_data->command,
+ (unsigned int)p_data->size);
+ ret = kfifo_in_spinlocked(&chan->ctrl->svc_fifo, p_data,
+ sizeof(*p_data),
+ &chan->ctrl->svc_fifo_lock);
+
+ kfree(p_data);
+
+ if (!ret)
+ return -ENOBUFS;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(stratix10_svc_send);
+
+/**
+ * stratix10_svc_allocate_memory() - allocate memory
+ * @chan: service channel assigned to the client
+ * @size: memory size requested by a specific service client
+ *
+ * Service layer allocates the requested number of bytes buffer from the
+ * memory pool, service client uses this function to get allocated buffers.
+ *
+ * Return: address of allocated memory on success, or ERR_PTR() on error.
+ */
+void *stratix10_svc_allocate_memory(struct stratix10_svc_chan *chan,
+ size_t size)
+{
+ struct stratix10_svc_data_mem *pmem;
+ unsigned long va;
+ phys_addr_t pa;
+ struct gen_pool *genpool = chan->ctrl->genpool;
+ size_t s = roundup(size, 1 << genpool->min_alloc_order);
+
+ pmem = devm_kzalloc(chan->ctrl->dev, sizeof(*pmem), GFP_KERNEL);
+ if (!pmem)
+ return ERR_PTR(-ENOMEM);
+
+ va = gen_pool_alloc(genpool, s);
+ if (!va)
+ return ERR_PTR(-ENOMEM);
+
+ memset((void *)va, 0, s);
+ pa = gen_pool_virt_to_phys(genpool, va);
+
+ pmem->vaddr = (void *)va;
+ pmem->paddr = pa;
+ pmem->size = s;
+ list_add_tail(&pmem->node, &svc_data_mem);
+ pr_debug("%s: va=%p, pa=0x%016x\n", __func__,
+ pmem->vaddr, (unsigned int)pmem->paddr);
+
+ return (void *)va;
+}
+EXPORT_SYMBOL_GPL(stratix10_svc_allocate_memory);
+
+/**
+ * stratix10_svc_free_memory() - free allocated memory
+ * @chan: service channel assigned to the client
+ * @kaddr: memory to be freed
+ *
+ * This function is used by service client to free allocated buffers.
+ */
+void stratix10_svc_free_memory(struct stratix10_svc_chan *chan, void *kaddr)
+{
+ struct stratix10_svc_data_mem *pmem;
+ size_t size = 0;
+
+ list_for_each_entry(pmem, &svc_data_mem, node)
+ if (pmem->vaddr == kaddr) {
+ size = pmem->size;
+ break;
+ }
+
+ gen_pool_free(chan->ctrl->genpool, (unsigned long)kaddr, size);
+ pmem->vaddr = NULL;
+ list_del(&pmem->node);
+}
+EXPORT_SYMBOL_GPL(stratix10_svc_free_memory);
+
+/**
+ * svc_pa_to_va() - translate physical address to virtual address
+ * @addr: to be translated physical address
+ *
+ * Return: valid virtual address or NULL if the provided physical
+ * address doesn't exist.
+ */
+static void *svc_pa_to_va(unsigned long addr)
+{
+ struct stratix10_svc_data_mem *pmem;
+
+ pr_debug("claim back P-addr=0x%016x\n", (unsigned int)addr);
+ list_for_each_entry(pmem, &svc_data_mem, node) {
+ if (pmem->paddr == addr)
+ return pmem->vaddr;
+ }
+
+ /* physical address is not found */
+ return NULL;
+}
+
+/**
+ * svc_thread_cmd_data_claim() - claim back buffer from the secure world
+ * @addr: pointer to service layer controller
+ * @p_data: pointer to service data structure
+ * @cb_data: pointer to callback data structure to service client
+ *
+ * Claim back the submitted buffers from the secure world and pass buffer
+ * back to service client (FPGA manager, etc) for reuse.
+ */
+static void svc_thread_cmd_data_claim(struct stratix10_svc_controller *ctrl,
+ struct stratix10_svc_data *p_data,
+ struct stratix10_svc_cb_data *cb_data)
+{
+ struct arm_smccc_res res;
+ unsigned long timeout;
+
+ reinit_completion(&ctrl->complete_status);
+ timeout = msecs_to_jiffies(FPGA_CONFIG_DATA_CLAIM_TIMEOUT_MS);
+
+ pr_debug("%s: claim back the submitted buffer\n", __func__);
+ do {
+ ctrl->invoke_fn(INTEL_SIP_SMC_FPGA_CONFIG_COMPLETED_WRITE,
+ 0, 0, 0, 0, 0, 0, 0, &res);
+
+ if (res.a0 == INTEL_SIP_SMC_STATUS_OK) {
+ if (!res.a1) {
+ complete(&ctrl->complete_status);
+ break;
+ }
+ cb_data->status = BIT(SVC_STATUS_RECONFIG_BUFFER_DONE);
+ cb_data->kaddr1 = svc_pa_to_va(res.a1);
+ cb_data->kaddr2 = (res.a2) ?
+ svc_pa_to_va(res.a2) : NULL;
+ cb_data->kaddr3 = (res.a3) ?
+ svc_pa_to_va(res.a3) : NULL;
+ p_data->chan->scl->receive_cb(p_data->chan->scl,
+ cb_data);
+ } else {
+ pr_debug("%s: secure world busy, polling again\n",
+ __func__);
+ }
+ } while (res.a0 == INTEL_SIP_SMC_STATUS_OK ||
+ res.a0 == INTEL_SIP_SMC_FPGA_CONFIG_STATUS_BUSY ||
+ wait_for_completion_timeout(&ctrl->complete_status, timeout));
+}
+
+/**
+ * svc_thread_cmd_config_status() - check configuration status
+ * @ctrl: pointer to service layer controller
+ * @p_data: pointer to service data structure
+ * @cb_data: pointer to callback data structure to service client
+ *
+ * Check whether the secure firmware at secure world has finished the FPGA
+ * configuration, and then inform FPGA manager the configuration status.
+ */
+static void svc_thread_cmd_config_status(struct stratix10_svc_controller *ctrl,
+ struct stratix10_svc_data *p_data,
+ struct stratix10_svc_cb_data *cb_data)
+{
+ struct arm_smccc_res res;
+ int count_in_sec;
+
+ cb_data->kaddr1 = NULL;
+ cb_data->kaddr2 = NULL;
+ cb_data->kaddr3 = NULL;
+ cb_data->status = BIT(SVC_STATUS_RECONFIG_ERROR);
+
+ pr_debug("%s: polling config status\n", __func__);
+
+ count_in_sec = FPGA_CONFIG_STATUS_TIMEOUT_SEC;
+ while (count_in_sec) {
+ ctrl->invoke_fn(INTEL_SIP_SMC_FPGA_CONFIG_ISDONE,
+ 0, 0, 0, 0, 0, 0, 0, &res);
+ if ((res.a0 == INTEL_SIP_SMC_STATUS_OK) ||
+ (res.a0 == INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR))
+ break;
+
+ /*
+ * configuration is still in progress, wait one second then
+ * poll again
+ */
+ msleep(1000);
+ count_in_sec--;
+ };
+
+ if (res.a0 == INTEL_SIP_SMC_STATUS_OK && count_in_sec)
+ cb_data->status = BIT(SVC_STATUS_RECONFIG_COMPLETED);
+
+ p_data->chan->scl->receive_cb(p_data->chan->scl, cb_data);
+}
+
+/**
+ * svc_thread_recv_status_ok() - handle the successful status
+ * @p_data: pointer to service data structure
+ * @cb_data: pointer to callback data structure to service client
+ * @res: result from SMC or HVC call
+ *
+ * Send back the correspond status to the service client (FPGA manager etc).
+ */
+static void svc_thread_recv_status_ok(struct stratix10_svc_data *p_data,
+ struct stratix10_svc_cb_data *cb_data,
+ struct arm_smccc_res res)
+{
+ cb_data->kaddr1 = NULL;
+ cb_data->kaddr2 = NULL;
+ cb_data->kaddr3 = NULL;
+
+ switch (p_data->command) {
+ case COMMAND_RECONFIG:
+ cb_data->status = BIT(SVC_STATUS_RECONFIG_REQUEST_OK);
+ break;
+ case COMMAND_RECONFIG_DATA_SUBMIT:
+ cb_data->status = BIT(SVC_STATUS_RECONFIG_BUFFER_SUBMITTED);
+ break;
+ case COMMAND_NOOP:
+ cb_data->status = BIT(SVC_STATUS_RECONFIG_BUFFER_SUBMITTED);
+ cb_data->kaddr1 = svc_pa_to_va(res.a1);
+ break;
+ case COMMAND_RECONFIG_STATUS:
+ cb_data->status = BIT(SVC_STATUS_RECONFIG_COMPLETED);
+ break;
+ default:
+ break;
+ }
+
+ pr_debug("%s: call receive_cb\n", __func__);
+ p_data->chan->scl->receive_cb(p_data->chan->scl, cb_data);
+}
+
+/**
+ * svc_normal_to_secure_thread() - the function to run in the kthread
+ * @data: data pointer for kthread function
+ *
+ * Service layer driver creates stratix10_svc_smc_hvc_call kthread on CPU
+ * node 0, its function stratix10_svc_secure_call_thread is used to handle
+ * SMC or HVC calls between kernel driver and secure monitor software.
+ *
+ * Return: 0 for success or -ENOMEM on error.
+ */
+static int svc_normal_to_secure_thread(void *data)
+{
+ struct stratix10_svc_controller
+ *ctrl = (struct stratix10_svc_controller *)data;
+ struct stratix10_svc_data *pdata;
+ struct stratix10_svc_cb_data *cbdata;
+ struct arm_smccc_res res;
+ unsigned long a0, a1, a2;
+ int ret_fifo = 0;
+
+ pdata = kmalloc(sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ cbdata = kmalloc(sizeof(*cbdata), GFP_KERNEL);
+ if (!cbdata)
+ return -ENOMEM;
+
+ /* default set, to remove build warning */
+ a0 = INTEL_SIP_SMC_FPGA_CONFIG_LOOPBACK;
+ a1 = 0;
+ a2 = 0;
+
+ while (!kthread_should_stop()) {
+ ret_fifo = kfifo_out_spinlocked(&ctrl->svc_fifo,
+ pdata, sizeof(*pdata),
+ &ctrl->svc_fifo_lock);
+
+ if (!ret_fifo)
+ continue;
+
+ pr_debug("get from FIFO pa=0x%016x, command=%u, size=%u\n",
+ (unsigned int)pdata->paddr, pdata->command,
+ (unsigned int)pdata->size);
+
+ switch (pdata->command) {
+ case COMMAND_RECONFIG_DATA_CLAIM:
+ svc_thread_cmd_data_claim(ctrl, pdata, cbdata);
+ continue;
+ case COMMAND_RECONFIG:
+ a0 = INTEL_SIP_SMC_FPGA_CONFIG_START;
+ a1 = 0;
+ a2 = 0;
+ break;
+ case COMMAND_RECONFIG_DATA_SUBMIT:
+ a0 = INTEL_SIP_SMC_FPGA_CONFIG_WRITE;
+ a1 = (unsigned long)pdata->paddr;
+ a2 = (unsigned long)pdata->size;
+ break;
+ case COMMAND_RECONFIG_STATUS:
+ a0 = INTEL_SIP_SMC_FPGA_CONFIG_ISDONE;
+ a1 = 0;
+ a2 = 0;
+ break;
+ default:
+ /* it shouldn't happen */
+ break;
+ }
+ pr_debug("%s: before SMC call -- a0=0x%016x a1=0x%016x",
+ __func__, (unsigned int)a0, (unsigned int)a1);
+ pr_debug(" a2=0x%016x\n", (unsigned int)a2);
+
+ ctrl->invoke_fn(a0, a1, a2, 0, 0, 0, 0, 0, &res);
+
+ pr_debug("%s: after SMC call -- res.a0=0x%016x",
+ __func__, (unsigned int)res.a0);
+ pr_debug(" res.a1=0x%016x, res.a2=0x%016x",
+ (unsigned int)res.a1, (unsigned int)res.a2);
+ pr_debug(" res.a3=0x%016x\n", (unsigned int)res.a3);
+
+ switch (res.a0) {
+ case INTEL_SIP_SMC_STATUS_OK:
+ svc_thread_recv_status_ok(pdata, cbdata, res);
+ break;
+ case INTEL_SIP_SMC_FPGA_CONFIG_STATUS_BUSY:
+ switch (pdata->command) {
+ case COMMAND_RECONFIG_DATA_SUBMIT:
+ svc_thread_cmd_data_claim(ctrl,
+ pdata, cbdata);
+ break;
+ case COMMAND_RECONFIG_STATUS:
+ svc_thread_cmd_config_status(ctrl,
+ pdata, cbdata);
+ break;
+ default:
+ break;
+ }
+ break;
+ case INTEL_SIP_SMC_FPGA_CONFIG_STATUS_REJECTED:
+ pr_debug("%s: STATUS_REJECTED\n", __func__);
+ break;
+ case INTEL_SIP_SMC_FPGA_CONFIG_STATUS_ERROR:
+ pr_err("%s: STATUS_ERROR\n", __func__);
+ cbdata->status = BIT(SVC_STATUS_RECONFIG_ERROR);
+ cbdata->kaddr1 = NULL;
+ cbdata->kaddr2 = NULL;
+ cbdata->kaddr3 = NULL;
+ pdata->chan->scl->receive_cb(pdata->chan->scl, cbdata);
+ break;
+ default:
+ break;
+ }
+ };
+
+ kfree(cbdata);
+ kfree(pdata);
+
+ return 0;
+}
+
+/**
+ * svc_normal_to_secure_shm_thread() - the function to run in the kthread
+ * @data: data pointer for kthread function
+ *
+ * Service layer driver creates stratix10_svc_smc_hvc_shm kthread on CPU
+ * node 0, its function stratix10_svc_secure_shm_thread is used to query the
+ * physical address of memory block reserved by secure monitor software at
+ * secure world.
+ *
+ * svc_normal_to_secure_shm_thread() calls do_exit() directly since it is a
+ * standlone thread for which no one will call kthread_stop() or return when
+ * 'kthread_should_stop()' is true.
+ */
+static int svc_normal_to_secure_shm_thread(void *data)
+{
+ struct stratix10_svc_sh_memory
+ *sh_mem = (struct stratix10_svc_sh_memory *)data;
+ struct arm_smccc_res res;
+
+ /* SMC or HVC call to get shared memory info from secure world */
+ sh_mem->invoke_fn(INTEL_SIP_SMC_FPGA_CONFIG_GET_MEM,
+ 0, 0, 0, 0, 0, 0, 0, &res);
+ if (res.a0 == INTEL_SIP_SMC_STATUS_OK) {
+ sh_mem->addr = res.a1;
+ sh_mem->size = res.a2;
+ } else {
+ pr_err("%s: after SMC call -- res.a0=0x%016x", __func__,
+ (unsigned int)res.a0);
+ sh_mem->addr = 0;
+ sh_mem->size = 0;
+ }
+
+ complete(&sh_mem->sync_complete);
+ do_exit(0);
+}
+
+/**
+ * svc_get_sh_memory() - get memory block reserved by secure monitor SW
+ * @pdev: pointer to service layer device
+ * @sh_memory pointer to service shared memory structure
+ *
+ * Return: zero for successfully getting the physical address of memory block
+ * reserved by secure monitor software, or negative value on error.
+ */
+static int svc_get_sh_memory(struct platform_device *pdev,
+ struct stratix10_svc_sh_memory *sh_memory)
+{
+ struct device *dev = &pdev->dev;
+ struct task_struct *sh_memory_task;
+
+ init_completion(&sh_memory->sync_complete);
+
+ /* smc or hvc call happens on cpu 0 bound kthread */
+ sh_memory_task = kthread_create_on_cpu(svc_normal_to_secure_shm_thread,
+ (void *)sh_memory,
+ 0, "svc_smc_hvc_shm_thread");
+ if (IS_ERR(sh_memory_task)) {
+ dev_err(dev, "fail to create stratix10_svc_smc_shm_thread\n");
+ return -EINVAL;
+ }
+
+ wake_up_process(sh_memory_task);
+
+ if (!wait_for_completion_timeout(&sh_memory->sync_complete, 10 * HZ)) {
+ dev_err(dev,
+ "timeout to get sh-memory paras from secure world\n");
+ return -ETIMEDOUT;
+ }
+
+ if (!sh_memory->addr || !sh_memory->size) {
+ dev_err(dev,
+ "fails to get shared memory info from secure world\n");
+ return -ENOMEM;
+ }
+
+ dev_dbg(dev, "SM software provides paddr: 0x%016x, size: 0x%08x\n",
+ (unsigned int)sh_memory->addr,
+ (unsigned int)sh_memory->size);
+
+ return 0;
+}
+
+/**
+ * svc_create_memory_pool() - create a memory pool from reserved memory block
+ * @pdev: pointer to service layer device
+ * @sh_memory: pointer to service shared memory structure
+ *
+ * Return: pool allocated from reserved memory block or ERR_PTR() on error.
+ */
+static struct gen_pool *
+svc_create_memory_pool(struct platform_device *pdev,
+ struct stratix10_svc_sh_memory *sh_memory)
+{
+ struct device *dev = &pdev->dev;
+ struct gen_pool *genpool;
+ unsigned long vaddr;
+ phys_addr_t paddr;
+ size_t size;
+ phys_addr_t begin;
+ phys_addr_t end;
+ void *va;
+ size_t page_mask = PAGE_SIZE - 1;
+ int min_alloc_order = 3;
+ int ret;
+
+ begin = roundup(sh_memory->addr, PAGE_SIZE);
+ end = rounddown(sh_memory->addr + sh_memory->size, PAGE_SIZE);
+ paddr = begin;
+ size = end - begin;
+ va = memremap(paddr, size, MEMREMAP_WC);
+ if (!va) {
+ dev_err(dev, "fail to remap shared memory\n");
+ return ERR_PTR(-EINVAL);
+ }
+ vaddr = (unsigned long)va;
+ dev_dbg(dev,
+ "reserved memory vaddr: %p, paddr: 0x%16x size: 0x%8x\n",
+ va, (unsigned int)paddr, (unsigned int)size);
+ if ((vaddr & page_mask) || (paddr & page_mask) ||
+ (size & page_mask)) {
+ dev_err(dev, "page is not aligned\n");
+ return ERR_PTR(-EINVAL);
+ }
+ genpool = gen_pool_create(min_alloc_order, -1);
+ if (!genpool) {
+ dev_err(dev, "fail to create genpool\n");
+ return ERR_PTR(-ENOMEM);
+ }
+ gen_pool_set_algo(genpool, gen_pool_best_fit, NULL);
+ ret = gen_pool_add_virt(genpool, vaddr, paddr, size, -1);
+ if (ret) {
+ dev_err(dev, "fail to add memory chunk to the pool\n");
+ gen_pool_destroy(genpool);
+ return ERR_PTR(ret);
+ }
+
+ return genpool;
+}
+
+/**
+ * svc_smccc_smc() - secure monitor call between normal and secure world
+ * @a0-a7: arguments passed in registers 0 to 7
+ * @res: result values from register 0 to 3
+ */
+static void svc_smccc_smc(unsigned long a0, unsigned long a1,
+ unsigned long a2, unsigned long a3,
+ unsigned long a4, unsigned long a5,
+ unsigned long a6, unsigned long a7,
+ struct arm_smccc_res *res)
+{
+ arm_smccc_smc(a0, a1, a2, a3, a4, a5, a6, a7, res);
+}
+
+/**
+ * svc_smccc_hvc() - hypervisor call between normal and secure world
+ * @a0-a7: arguments passed in registers 0 to 7
+ * @res: result values from register 0 to 3
+ */
+static void svc_smccc_hvc(unsigned long a0, unsigned long a1,
+ unsigned long a2, unsigned long a3,
+ unsigned long a4, unsigned long a5,
+ unsigned long a6, unsigned long a7,
+ struct arm_smccc_res *res)
+{
+ arm_smccc_hvc(a0, a1, a2, a3, a4, a5, a6, a7, res);
+}
+
+/**
+ * get_invoke_func() - invoke SMC or HVC call
+ * @dev: pointer to device
+ *
+ * Return: function pointer to svc_smccc_smc or svc_smccc_hvc.
+ */
+static svc_invoke_fn *get_invoke_func(struct device *dev)
+{
+ const char *method;
+
+ if (of_property_read_string(dev->of_node, "method", &method)) {
+ dev_warn(dev, "missing \"method\" property\n");
+ return ERR_PTR(-ENXIO);
+ }
+
+ if (!strcmp(method, "smc"))
+ return svc_smccc_smc;
+ if (!strcmp(method, "hvc"))
+ return svc_smccc_hvc;
+
+ dev_warn(dev, "invalid \"method\" property: %s\n", method);
+
+ return ERR_PTR(-EINVAL);
+}
+
+static const struct of_device_id stratix10_svc_drv_match[] = {
+ {.compatible = "intel,stratix10-svc"},
+ {},
+};
+
+static int stratix10_svc_drv_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct stratix10_svc_controller *controller;
+ struct stratix10_svc_chan *chans;
+ struct gen_pool *genpool;
+ struct stratix10_svc_sh_memory *sh_memory;
+ struct task_struct *task;
+ svc_invoke_fn *invoke_fn;
+ size_t fifo_size;
+ int ret;
+
+ /* get SMC or HVC function */
+ invoke_fn = get_invoke_func(dev);
+ if (IS_ERR(invoke_fn))
+ return -EINVAL;
+
+ sh_memory = devm_kzalloc(dev, sizeof(*sh_memory), GFP_KERNEL);
+ if (!sh_memory)
+ return -ENOMEM;
+
+ sh_memory->invoke_fn = invoke_fn;
+ ret = svc_get_sh_memory(pdev, sh_memory);
+ if (ret)
+ return ret;
+
+ genpool = svc_create_memory_pool(pdev, sh_memory);
+ if (!genpool)
+ return -ENOMEM;
+
+ /* allocate service controller and supporting channel */
+ controller = devm_kzalloc(dev, sizeof(*controller), GFP_KERNEL);
+ if (!controller)
+ return -ENOMEM;
+
+ chans = devm_kmalloc_array(dev, SVC_NUM_CHANNEL,
+ sizeof(*chans), GFP_KERNEL | __GFP_ZERO);
+ if (!chans)
+ return -ENOMEM;
+
+ /* smc or hvc call happens on cpu 0 bound kthread */
+ task = kthread_create_on_cpu(svc_normal_to_secure_thread,
+ (void *)controller, 0,
+ "svc_smc_hvc_thread");
+ if (IS_ERR(task)) {
+ dev_err(dev, "fails to create svc_smc_hvc_thread\n");
+ return -EINVAL;
+ }
+
+ controller->dev = dev;
+ controller->num_chans = SVC_NUM_CHANNEL;
+ controller->chans = chans;
+ controller->genpool = genpool;
+ controller->task = task;
+ controller->invoke_fn = invoke_fn;
+ init_completion(&controller->complete_status);
+
+ fifo_size = sizeof(struct stratix10_svc_data) * SVC_NUM_DATA_IN_FIFO;
+ ret = kfifo_alloc(&controller->svc_fifo, fifo_size, GFP_KERNEL);
+ if (ret) {
+ dev_err(dev, "fails to allocate FIFO\n");
+ return ret;
+ }
+ spin_lock_init(&controller->svc_fifo_lock);
+
+ chans[0].scl = NULL;
+ chans[0].ctrl = controller;
+ chans[0].name = SVC_CLIENT_FPGA;
+ spin_lock_init(&chans[0].lock);
+
+ chans[1].scl = NULL;
+ chans[1].ctrl = controller;
+ chans[1].name = SVC_CLIENT_DUMMY;
+ spin_lock_init(&chans[1].lock);
+
+ wake_up_process(controller->task);
+
+ list_add_tail(&controller->node, &svc_ctrl);
+ platform_set_drvdata(pdev, controller);
+
+ pr_info("Intel Service Layer Driver Initialized\n");
+
+ return ret;
+}
+
+static int stratix10_svc_drv_remove(struct platform_device *pdev)
+{
+ struct stratix10_svc_controller *ctrl = platform_get_drvdata(pdev);
+
+ kfifo_free(&ctrl->svc_fifo);
+ kthread_stop(ctrl->task);
+ if (ctrl->genpool)
+ gen_pool_destroy(ctrl->genpool);
+ list_del(&ctrl->node);
+
+ return 0;
+}
+
+static struct platform_driver stratix10_svc_driver = {
+ .probe = stratix10_svc_drv_probe,
+ .remove = stratix10_svc_drv_remove,
+ .driver = {
+ .name = "stratix10-svc",
+ .of_match_table = stratix10_svc_drv_match,
+ },
+};
+
+static int __init stratix10_svc_init(void)
+{
+ struct device_node *fw_np;
+ struct device_node *np;
+ int ret;
+
+ fw_np = of_find_node_by_name(NULL, "firmware");
+ if (!fw_np)
+ return -ENODEV;
+
+ np = of_find_matching_node(fw_np, stratix10_svc_drv_match);
+ if (!np) {
+ of_node_put(fw_np);
+ return -ENODEV;
+ }
+
+ of_node_put(np);
+ ret = of_platform_populate(fw_np, stratix10_svc_drv_match, NULL, NULL);
+ of_node_put(fw_np);
+ if (ret)
+ return ret;
+
+ return platform_driver_register(&stratix10_svc_driver);
+}
+
+static void __exit stratix10_svc_exit(void)
+{
+ return platform_driver_unregister(&stratix10_svc_driver);
+}
+
+subsys_initcall(stratix10_svc_init);
+module_exit(stratix10_svc_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Intel Stratix10 Service Layer Driver");
+MODULE_AUTHOR("Richard Gong <richard.gong@intel.com>");
+MODULE_ALIAS("platform:stratix10-svc");
diff --git a/include/linux/stratix10-svc-client.h b/include/linux/stratix10-svc-client.h
new file mode 100644
index 0000000..5c8c054
--- /dev/null
+++ b/include/linux/stratix10-svc-client.h
@@ -0,0 +1,190 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2017-2018, Intel Corporation
+ */
+
+#ifndef __STRATIX10_SVC_CLIENT_H
+#define __STRATIX10_SVC_CLIENT_H
+
+/**
+ * Service layer driver supports client names
+ *
+ * fpga: for FPGA configuration
+ * dummy: for integration/debug/trouble-shooting
+ */
+#define SVC_CLIENT_FPGA "fpga"
+#define SVC_CLIENT_DUMMY "dummy"
+
+/**
+ * Status of the sent command, in bit number
+ *
+ * SVC_COMMAND_STATUS_RECONFIG_REQUEST_OK:
+ * Secure firmware accepts the request of FPGA reconfiguration.
+ *
+ * SVC_STATUS_RECONFIG_BUFFER_SUBMITTED:
+ * Service client successfully submits FPGA configuration
+ * data buffer to secure firmware.
+ *
+ * SVC_COMMAND_STATUS_RECONFIG_BUFFER_DONE:
+ * Secure firmware completes data process, ready to accept the
+ * next WRITE transaction.
+ *
+ * SVC_COMMAND_STATUS_RECONFIG_COMPLETED:
+ * Secure firmware completes FPGA configuration successfully, FPGA should
+ * be in user mode.
+ *
+ * SVC_COMMAND_STATUS_RECONFIG_BUSY:
+ * FPGA configuration is still in process.
+ *
+ * SVC_COMMAND_STATUS_RECONFIG_ERROR:
+ * Error encountered during FPGA configuration.
+ */
+#define SVC_STATUS_RECONFIG_REQUEST_OK 0
+#define SVC_STATUS_RECONFIG_BUFFER_SUBMITTED 1
+#define SVC_STATUS_RECONFIG_BUFFER_DONE 2
+#define SVC_STATUS_RECONFIG_COMPLETED 3
+#define SVC_STATUS_RECONFIG_BUSY 4
+#define SVC_STATUS_RECONFIG_ERROR 5
+
+/**
+ * Flag bit for COMMAND_RECONFIG
+ *
+ * COMMAND_RECONFIG_FLAG_PARTIAL:
+ * Set to FPGA configuration type (full or partial), the default
+ * is full reconfig.
+ */
+#define COMMAND_RECONFIG_FLAG_PARTIAL 0
+
+/* Timeout settings for FPGA manager driver */
+#define SVC_RECONFIG_REQUEST_TIMEOUT_MS 100
+#define SVC_RECONFIG_BUFFER_TIMEOUT_MS 240
+
+struct stratix10_svc_chan;
+
+/**
+ * enum stratix10_svc_command_code - supporting service commands
+ *
+ * @COMMAND_NOOP: do 'dummy' request for integration/debug/trouble-shootings
+ *
+ * @COMMAND_RECONFIG: ask for FPGA configuration preparation, return status
+ * is SVC_STATUS_RECONFIG_REQUEST_OK
+ *
+ * @COMMAND_RECONFIG_DATA_SUBMIT: submit buffer(s) of bit-stream data for the
+ * FPGA configuration, return status is SVC_STATUS_RECONFIG_BUFFER_SUBMITTED,
+ * or SVC_STATUS_RECONFIG_ERROR
+ *
+ * @COMMAND_RECONFIG_DATA_CLAIM: check the status of the configuration, return
+ * status is SVC_STATUS_RECONFIG_COMPLETED, or SVC_STATUS_RECONFIG_BUSY, or
+ * SVC_STATUS_RECONFIG_ERROR
+
+ * @COMMAND_RECONFIG_STATUS: check the status of the configuration, return
+ * status is SVC_STATUS_RECONFIG_COMPLETED, or SVC_STATUS_RECONFIG_BUSY, or
+ * SVC_STATUS_RECONFIG_ERROR
+ */
+enum stratix10_svc_command_code {
+ COMMAND_NOOP = 0,
+ COMMAND_RECONFIG,
+ COMMAND_RECONFIG_DATA_SUBMIT,
+ COMMAND_RECONFIG_DATA_CLAIM,
+ COMMAND_RECONFIG_STATUS
+};
+
+/**
+ * struct stratix10_svc_client_msg - message sent by client to service
+ * @command: service command
+ * @payload: starting address of data need be processed
+ * @payload_length: data size in bytes
+ */
+struct stratix10_svc_client_msg {
+ void *payload;
+ size_t payload_length;
+ enum stratix10_svc_command_code command;
+};
+
+/**
+ * struct stratix10_svc_command_reconfig_payload - reconfig payload
+ * @flags: flag bit for the type of FPGA configuration
+ */
+struct stratix10_svc_command_reconfig_payload {
+ u32 flags;
+};
+
+/**
+ * struct stratix10_svc_cb_data - callback data structure from service layer
+ * @status: the status of sent command
+ * @kaddr1-3: used when status is SVC_COMMAND_STATUS_RECONFIG_BUFFER_DONE
+ *
+ * kaddr1 - address of 1st completed data block.
+ * kaddr2 - address of 2nd completed data block.
+ * kaddr3 - address of 3rd completed data block.
+ */
+struct stratix10_svc_cb_data {
+ u32 status;
+ void *kaddr1;
+ void *kaddr2;
+ void *kaddr3;
+};
+
+/**
+ * struct stratix10_svc_client - service client structure
+ * @dev: the client device
+ * @receive_callback: callback to provide service client the received data
+ * @priv: client private data
+ */
+struct stratix10_svc_client {
+ struct device *dev;
+ void (*receive_cb)(struct stratix10_svc_client *client,
+ struct stratix10_svc_cb_data *cb_data);
+ void *priv;
+};
+
+/**
+ * stratix10_svc_request_channel_byname() - request service channel
+ * @client: identity of the client requesting the channel
+ * @name: supporting client name defined above
+ *
+ * Return: a pointer to channel assigned to the client on success,
+ * or ERR_PTR() on error.
+ */
+struct stratix10_svc_chan
+*stratix10_svc_request_channel_byname(struct stratix10_svc_client *client,
+ const char *name);
+
+/**
+ * stratix10_svc_free_channel() - free service channel.
+ * @chan: service channel to be freed
+ */
+void stratix10_svc_free_channel(struct stratix10_svc_chan *chan);
+
+/**
+ * stratix10_svc_allocate_memory() - allocate the momory
+ * @chan: service channel assigned to the client
+ * @size: number of bytes client requests
+ *
+ * Service layer allocates the requested number of bytes from the memory
+ * pool for the client.
+ *
+ * Return: the starting address of allocated memory on success, or
+ * ERR_PTR() on error.
+ */
+void *stratix10_svc_allocate_memory(struct stratix10_svc_chan *chan,
+ size_t size);
+
+/**
+ * stratix10_svc_free_memory() - free allocated memory
+ * @chan: service channel assigned to the client
+ * @kaddr: starting address of memory to be free back to pool
+ */
+void stratix10_svc_free_memory(struct stratix10_svc_chan *chan, void *kaddr);
+
+/**
+ * stratix10_svc_send() - send a message to the remote
+ * @chan: service channel assigned to the client
+ * @msg: message data to be sent, in the format of
+ * struct stratix10_svc_client_msg
+ *
+ * Return: 0 for success, -ENOMEM or -ENOBUFS on error.
+ */
+int stratix10_svc_send(struct stratix10_svc_chan *chan, void *msg);
+#endif
+
--
2.7.4
^ permalink raw reply related
* [PATCHv4 4/7] dt-bindings: fpga: add Stratix10 SoC FPGA manager binding
From: richard.gong at linux.intel.com @ 2018-05-04 14:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1525443697-31009-1-git-send-email-richard.gong@linux.intel.com>
From: Alan Tull <atull@kernel.org>
Add a Device Tree binding for the Intel Stratix10 SoC FPGA manager.
Signed-off-by: Alan Tull <atull@kernel.org>
Signed-off-by: Richard Gong <richard.gong@intel.com>
---
v2: this patch is added in patch set version 2
v3: change to put fpga_mgr node under firmware/svc node
v4: s/fpga-mgr at 0/fpga-mgr/ to remove unit_address
Add Richard's signed-off-by
---
.../bindings/fpga/intel-stratix10-soc-fpga-mgr.txt | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
create mode 100644 Documentation/devicetree/bindings/fpga/intel-stratix10-soc-fpga-mgr.txt
diff --git a/Documentation/devicetree/bindings/fpga/intel-stratix10-soc-fpga-mgr.txt b/Documentation/devicetree/bindings/fpga/intel-stratix10-soc-fpga-mgr.txt
new file mode 100644
index 0000000..6e03f79
--- /dev/null
+++ b/Documentation/devicetree/bindings/fpga/intel-stratix10-soc-fpga-mgr.txt
@@ -0,0 +1,17 @@
+Intel Stratix10 SoC FPGA Manager
+
+Required properties:
+The fpga_mgr node has the following mandatory property, must be located under
+firmware/svc node.
+
+- compatible : should contain "intel,stratix10-soc-fpga-mgr"
+
+Example:
+
+ firmware {
+ svc {
+ fpga_mgr: fpga-mgr {
+ compatible = "intel,stratix10-soc-fpga-mgr";
+ };
+ };
+ };
--
2.7.4
^ permalink raw reply related
* [PATCHv4 5/7] arm64: dts: stratix10: add fpga manager and region
From: richard.gong at linux.intel.com @ 2018-05-04 14:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1525443697-31009-1-git-send-email-richard.gong@linux.intel.com>
From: Alan Tull <atull@kernel.org>
Add the Stratix10 FPGA manager and a FPGA region to the
device tree.
Signed-off-by: Alan Tull <atull@kernel.org>
Signed-off-by: Richard Gong <richard.gong@intel.com>
---
v2: this patch is added in patch set version 2
v3: change to put fpga_mgr node under firmware/svc node
v4: s/fpga-mgr at 0/fpga-mgr/ to remove unit_address
Add Richard's signed-off-by
---
arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi b/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi
index 985b9e5..9e32607 100644
--- a/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi
+++ b/arch/arm64/boot/dts/altera/socfpga_stratix10.dtsi
@@ -106,6 +106,14 @@
interrupt-parent = <&intc>;
ranges = <0 0 0 0xffffffff>;
+ base_fpga_region {
+ #address-cells = <0x1>;
+ #size-cells = <0x1>;
+
+ compatible = "fpga-region";
+ fpga-mgr = <&fpga_mgr>;
+ };
+
clkmgr: clock-controller at ffd10000 {
compatible = "intel,stratix10-clkmgr";
reg = <0xffd10000 0x1000>;
@@ -473,6 +481,10 @@
compatible = "intel,stratix10-svc";
method = "smc";
memory-region = <&service_reserved>;
+
+ fpga_mgr: fpga-mgr {
+ compatible = "intel,stratix10-soc-fpga-mgr";
+ };
};
};
};
--
2.7.4
^ permalink raw reply related
* [PATCHv4 6/7] fpga: add intel stratix10 soc fpga manager driver
From: richard.gong at linux.intel.com @ 2018-05-04 14:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1525443697-31009-1-git-send-email-richard.gong@linux.intel.com>
From: Alan Tull <atull@kernel.org>
Add driver for reconfiguring Intel Stratix10 SoC FPGA devices.
This driver communicates through the Intel Service Driver which
does communication with privileged hardware (that does the
FPGA programming) through a secure mailbox.
Signed-off-by: Alan Tull <atull@kernel.org>
Signed-off-by: Richard Gong <richard.gong@intel.com>
---
v2: this patch is added in patch set version 2
v3: change to align to the update of service client APIs, and the
update of fpga_mgr device node
v4: changes to align with stratix10-svc-client API updates
Add Richard's signed-off-by
---
drivers/fpga/Kconfig | 6 +
drivers/fpga/Makefile | 1 +
drivers/fpga/stratix10-soc.c | 534 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 541 insertions(+)
create mode 100644 drivers/fpga/stratix10-soc.c
diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
index f47ef84..1624a73 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -57,6 +57,12 @@ config FPGA_MGR_ZYNQ_FPGA
help
FPGA manager driver support for Xilinx Zynq FPGAs.
+config FPGA_MGR_STRATIX10_SOC
+ tristate "Intel Stratix10 SoC FPGA Manager"
+ depends on (ARCH_STRATIX10 && STRATIX10_SERVICE)
+ help
+ FPGA manager driver support for the Intel Stratix10 SoC.
+
config FPGA_MGR_XILINX_SPI
tristate "Xilinx Configuration over Slave Serial (SPI)"
depends on SPI
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
index 3cb276a..6eef670 100644
--- a/drivers/fpga/Makefile
+++ b/drivers/fpga/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_FPGA_MGR_ALTERA_PS_SPI) += altera-ps-spi.o
obj-$(CONFIG_FPGA_MGR_ICE40_SPI) += ice40-spi.o
obj-$(CONFIG_FPGA_MGR_SOCFPGA) += socfpga.o
obj-$(CONFIG_FPGA_MGR_SOCFPGA_A10) += socfpga-a10.o
+obj-$(CONFIG_FPGA_MGR_STRATIX10_SOC) += stratix10-soc.o
obj-$(CONFIG_FPGA_MGR_TS73XX) += ts73xx-fpga.o
obj-$(CONFIG_FPGA_MGR_XILINX_SPI) += xilinx-spi.o
obj-$(CONFIG_FPGA_MGR_ZYNQ_FPGA) += zynq-fpga.o
diff --git a/drivers/fpga/stratix10-soc.c b/drivers/fpga/stratix10-soc.c
new file mode 100644
index 0000000..3bdffae
--- /dev/null
+++ b/drivers/fpga/stratix10-soc.c
@@ -0,0 +1,534 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * FPGA Manager Driver for Intel Stratix10 SoC
+ *
+ * Copyright (C) 2018 Intel Corporation
+ */
+#include <linux/completion.h>
+#include <linux/fpga/fpga-mgr.h>
+#include <linux/stratix10-svc-client.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+/*
+ * FPGA programming requires a higher level of privilege (EL3), per the SoC
+ * design.
+ */
+#define NUM_SVC_BUFS 4
+#define SVC_BUF_SIZE SZ_512K
+
+/* Indicates buffer is in use if set */
+#define SVC_BUF_LOCK 0
+
+/**
+ * struct s10_svc_buf
+ * @buf: virtual address of buf provided by service layer
+ * @lock: locked if buffer is in use
+ */
+struct s10_svc_buf {
+ char *buf;
+ unsigned long lock;
+};
+
+struct s10_priv {
+ struct stratix10_svc_chan *chan;
+ struct stratix10_svc_client client;
+ struct completion status_return_completion;
+ struct s10_svc_buf svc_bufs[NUM_SVC_BUFS];
+ unsigned long status;
+};
+
+static int s10_svc_send_msg(struct s10_priv *priv,
+ enum stratix10_svc_command_code command,
+ void *payload, u32 payload_length)
+{
+ struct stratix10_svc_chan *chan = priv->chan;
+ struct stratix10_svc_client_msg msg;
+ int ret;
+
+ pr_debug("%s cmd=%d payload=%p legnth=%d\n",
+ __func__, command, payload, payload_length);
+
+ msg.command = command;
+ msg.payload = payload;
+ msg.payload_length = payload_length;
+
+ ret = stratix10_svc_send(chan, &msg);
+ pr_debug("stratix10_svc_send returned status %d\n", ret);
+
+ return ret;
+}
+
+/**
+ * s10_free_buffers
+ * Free buffers allocated from the service layer's pool that are not in use.
+ * @mgr: fpga manager struct
+ * Free all buffers that are not in use.
+ * Return true when all buffers are freed.
+ */
+static bool s10_free_buffers(struct fpga_manager *mgr)
+{
+ struct s10_priv *priv = mgr->priv;
+ uint num_free = 0;
+ uint i;
+
+ for (i = 0; i < NUM_SVC_BUFS; i++) {
+ if (!priv->svc_bufs[i].buf) {
+ num_free++;
+ continue;
+ }
+
+ if (!test_and_set_bit_lock(SVC_BUF_LOCK,
+ &priv->svc_bufs[i].lock)) {
+ stratix10_svc_free_memory(priv->chan,
+ priv->svc_bufs[i].buf);
+ priv->svc_bufs[i].buf = NULL;
+ num_free++;
+ }
+ }
+
+ return num_free == NUM_SVC_BUFS;
+}
+
+/**
+ * s10_free_buffer_count
+ * Count how many buffers are not in use.
+ * @mgr: fpga manager struct
+ * Return # of buffers that are not in use.
+ */
+static uint s10_free_buffer_count(struct fpga_manager *mgr)
+{
+ struct s10_priv *priv = mgr->priv;
+ uint num_free = 0;
+ uint i;
+
+ for (i = 0; i < NUM_SVC_BUFS; i++)
+ if (!priv->svc_bufs[i].buf)
+ num_free++;
+
+ return num_free;
+}
+
+/**
+ * s10_unlock_bufs
+ * Given the returned buffer address, match that address to our buffer struct
+ * and unlock that buffer. This marks it as available to be refilled and sent
+ * (or freed).
+ * @priv: private data
+ * @kaddr: kernel address of buffer that was returned from service layer
+ */
+static void s10_unlock_bufs(struct s10_priv *priv, void *kaddr)
+{
+ uint i;
+
+ if (!kaddr)
+ return;
+
+ for (i = 0; i < NUM_SVC_BUFS; i++)
+ if (priv->svc_bufs[i].buf == kaddr) {
+ clear_bit_unlock(SVC_BUF_LOCK,
+ &priv->svc_bufs[i].lock);
+ return;
+ }
+
+ WARN(1, "Unknown buffer returned from service layer %p\n", kaddr);
+}
+
+/**
+ * s10_receive_callback
+ * Callback for service layer to use to provide client (this driver) messages
+ * received through the mailbox.
+ * @client: service layer client struct
+ * @data: message
+ */
+static void s10_receive_callback(struct stratix10_svc_client *client,
+ struct stratix10_svc_cb_data *data)
+{
+ struct s10_priv *priv = client->priv;
+ u32 status;
+ int i;
+
+ WARN_ONCE(!data, "%s: stratix10_svc_rc_data = NULL", __func__);
+
+ status = data->status;
+
+ /*
+ * Here we set status bits as we receive them. Elsewhere, we always use
+ * test_and_clear_bit() to check status in priv->status
+ */
+ for (i = 0; i <= SVC_STATUS_RECONFIG_ERROR; i++)
+ if (status & (1 << i))
+ set_bit(i, &priv->status);
+
+ if (status & BIT(SVC_STATUS_RECONFIG_BUFFER_DONE)) {
+ s10_unlock_bufs(priv, data->kaddr1);
+ s10_unlock_bufs(priv, data->kaddr2);
+ s10_unlock_bufs(priv, data->kaddr3);
+ }
+
+ complete(&priv->status_return_completion);
+}
+
+/**
+ * s10_ops_write_init
+ * Prepare for FPGA reconfiguration by requesting partial reconfig and
+ * allocating buffers from the service layer.
+ * @mgr: fpga manager
+ * @info: fpga image info
+ * @buf: fpga image buffer
+ * @count: size of buf in bytes
+ */
+static int s10_ops_write_init(struct fpga_manager *mgr,
+ struct fpga_image_info *info,
+ const char *buf, size_t count)
+{
+ struct s10_priv *priv = mgr->priv;
+ struct device *dev = priv->client.dev;
+ unsigned long timeout;
+ struct stratix10_svc_command_reconfig_payload payload;
+ char *kbuf;
+ uint i;
+ int ret;
+
+ if (info->flags & FPGA_MGR_PARTIAL_RECONFIG) {
+ dev_info(dev, "Requesting partial reconfiguration.\n");
+ payload.flags |= BIT(COMMAND_RECONFIG_FLAG_PARTIAL);
+ } else {
+ dev_info(dev, "Requesting full reconfiguration.\n");
+ }
+
+ reinit_completion(&priv->status_return_completion);
+ ret = s10_svc_send_msg(priv, COMMAND_RECONFIG,
+ &payload, sizeof(payload));
+ if (ret)
+ return ret;
+
+ timeout = msecs_to_jiffies(SVC_RECONFIG_REQUEST_TIMEOUT_MS);
+ ret = wait_for_completion_interruptible_timeout(
+ &priv->status_return_completion, timeout);
+ if (!ret) {
+ dev_err(dev, "timeout waiting for RECONFIG_REQUEST\n");
+ return -ETIMEDOUT;
+ }
+ if (ret < 0) {
+ dev_err(dev, "error (%d) waiting for RECONFIG_REQUEST\n", ret);
+ return ret;
+ }
+
+ if (!test_and_clear_bit(SVC_STATUS_RECONFIG_REQUEST_OK,
+ &priv->status))
+ return -ETIMEDOUT;
+
+ /* Allocate buffers from the service layer's pool. */
+ for (i = 0; i < NUM_SVC_BUFS; i++) {
+ kbuf = stratix10_svc_allocate_memory(priv->chan, SVC_BUF_SIZE);
+ if (!kbuf) {
+ s10_free_buffers(mgr);
+ return -ENOMEM;
+ }
+
+ priv->svc_bufs[i].buf = kbuf;
+ priv->svc_bufs[i].lock = 0;
+ }
+
+ return 0;
+}
+
+/**
+ * s10_send_buf
+ * Send a buffer to the service layer queue
+ * @mgr: fpga manager struct
+ * @buf_num: index of buffer in svc_bufs array
+ * @buf: fpga image buffer
+ * @count: size of buf in bytes
+ * Returns # of bytes transferred or -errno, never 0
+ */
+static int s10_send_buf(struct fpga_manager *mgr, uint buf_num,
+ const char *buf, size_t count)
+
+{
+ struct s10_priv *priv = mgr->priv;
+ struct device *dev = priv->client.dev;
+ void *svc_buf;
+ size_t xfer_sz;
+ int ret;
+
+ xfer_sz = count < SVC_BUF_SIZE ? count : SVC_BUF_SIZE;
+
+ svc_buf = priv->svc_bufs[buf_num].buf;
+ memcpy(svc_buf, buf, xfer_sz);
+ ret = s10_svc_send_msg(priv, COMMAND_RECONFIG_DATA_SUBMIT,
+ svc_buf, xfer_sz);
+ if (ret) {
+ dev_err(dev,
+ "Error while sending data to service layer (%d)", ret);
+ return ret;
+ }
+
+ return xfer_sz;
+}
+
+/**
+ * s10_ops_write
+ * Send a FPGA image to privileged layers to write to the FPGA. When done
+ * sending, free all service layer buffers we allocated in write_init.
+ * @mgr: fpga manager
+ * @buf: fpga image buffer
+ * @count: size of buf in bytes
+ * Returns 0 for success or negative errno.
+ */
+static int s10_ops_write(struct fpga_manager *mgr, const char *buf,
+ size_t count)
+{
+ struct s10_priv *priv = mgr->priv;
+ struct device *dev = priv->client.dev;
+ unsigned long timeout;
+ size_t sent = 0;
+ int ret = 0;
+ uint i;
+
+ timeout = msecs_to_jiffies(SVC_RECONFIG_BUFFER_TIMEOUT_MS);
+
+ /* Buffer loop: either send buffers or free them. */
+ while (1) {
+ reinit_completion(&priv->status_return_completion);
+
+ if (count > 0) {
+ for (i = 0; i < NUM_SVC_BUFS; i++)
+ if (!test_and_set_bit_lock(
+ SVC_BUF_LOCK, &priv->svc_bufs[i].lock))
+ break;
+
+ if (i == NUM_SVC_BUFS)
+ /* wait for a free buffer */
+ continue;
+
+ sent = s10_send_buf(mgr, i, buf, count);
+ /*
+ * If service queue was full, we won't get a callback.
+ * Wait and try again
+ */
+ if (sent < 0)
+ continue;
+
+ count -= sent;
+ buf += sent;
+ } else {
+ s10_free_buffers(mgr);
+ if (s10_free_buffer_count(mgr) == NUM_SVC_BUFS)
+ return 0;
+
+ ret = s10_svc_send_msg(
+ priv, COMMAND_RECONFIG_DATA_CLAIM,
+ NULL, 0);
+ if (ret)
+ break;
+ }
+
+ /*
+ * If callback hasn't already happened, wait for buffers to be
+ * returned from service layer
+ */
+ if (priv->status)
+ ret = 0;
+ else
+ ret = wait_for_completion_interruptible_timeout(
+ &priv->status_return_completion, timeout);
+
+ if (test_and_clear_bit(
+ SVC_STATUS_RECONFIG_BUFFER_DONE, &priv->status))
+ continue;
+
+ if (test_and_clear_bit(SVC_STATUS_RECONFIG_BUFFER_SUBMITTED,
+ &priv->status))
+ continue;
+
+ if (test_and_clear_bit(SVC_STATUS_RECONFIG_ERROR,
+ &priv->status)) {
+ dev_err(dev, "ERROR - giving up - SVC_STATUS_RECONFIG_ERROR\n");
+ ret = -EFAULT;
+ break;
+ }
+
+ if (!ret) {
+ dev_err(dev, "timeout waiting for svc layer buffers\n");
+ ret = -ETIMEDOUT;
+ break;
+ }
+ if (ret < 0) {
+ dev_err(dev,
+ "error (%d) waiting for svc layer buffers\n",
+ ret);
+ break;
+ }
+ }
+
+ s10_free_buffers(mgr);
+ if (s10_free_buffer_count(mgr) != NUM_SVC_BUFS)
+ dev_err(dev, "%s not all buffers were freed\n", __func__);
+
+ return ret;
+}
+
+/**
+ * s10_ops_write_complete
+ * Wait for FPGA configuration to be done
+ * @mgr: fpga manager
+ * @info: fpga image info
+ * Returns 0 for success negative errno.
+ */
+static int s10_ops_write_complete(struct fpga_manager *mgr,
+ struct fpga_image_info *info)
+{
+ struct s10_priv *priv = mgr->priv;
+ struct device *dev = priv->client.dev;
+ unsigned long timeout;
+ int ret;
+
+ timeout = usecs_to_jiffies(info->config_complete_timeout_us);
+
+ do {
+ reinit_completion(&priv->status_return_completion);
+
+ ret = s10_svc_send_msg(priv, COMMAND_RECONFIG_STATUS, NULL, 0);
+ if (ret)
+ return ret;
+
+ ret = wait_for_completion_interruptible_timeout(
+ &priv->status_return_completion, timeout);
+ if (!ret) {
+ dev_err(dev,
+ "timeout waiting for RECONFIG_COMPLETED\n");
+ return -ETIMEDOUT;
+ }
+ if (ret < 0) {
+ dev_err(dev,
+ "error (%d) waiting for RECONFIG_COMPLETED\n",
+ ret);
+ return ret;
+ }
+ /* Not error or timeout, so ret is # of jiffies until timeout */
+ timeout = ret;
+
+ if (test_and_clear_bit(SVC_STATUS_RECONFIG_COMPLETED,
+ &priv->status))
+ break;
+
+ if (test_and_clear_bit(SVC_STATUS_RECONFIG_ERROR,
+ &priv->status)) {
+ dev_err(dev, "ERROR - giving up - SVC_STATUS_RECONFIG_ERROR\n");
+ return -EFAULT;
+ }
+ } while (1);
+
+ return 0;
+}
+
+static enum fpga_mgr_states s10_ops_state(struct fpga_manager *mgr)
+{
+ return FPGA_MGR_STATE_UNKNOWN;
+}
+
+static const struct fpga_manager_ops s10_ops = {
+ .state = s10_ops_state,
+ .write_init = s10_ops_write_init,
+ .write = s10_ops_write,
+ .write_complete = s10_ops_write_complete,
+};
+
+static int s10_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct s10_priv *priv;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->client.dev = dev;
+ priv->client.receive_cb = s10_receive_callback;
+ priv->client.priv = priv;
+
+ priv->chan = stratix10_svc_request_channel_byname(&priv->client,
+ SVC_CLIENT_FPGA);
+ if (IS_ERR(priv->chan)) {
+ dev_err(dev, "couldn't get service channel (%s)\n",
+ SVC_CLIENT_FPGA);
+ return PTR_ERR(priv->chan);
+ }
+
+ init_completion(&priv->status_return_completion);
+
+ ret = fpga_mgr_register(dev, "Stratix10 SOC FPGA Manager",
+ &s10_ops, priv);
+
+ if (ret)
+ stratix10_svc_free_channel(priv->chan);
+
+ return ret;
+}
+
+static int s10_remove(struct platform_device *pdev)
+{
+ struct fpga_manager *mgr = platform_get_drvdata(pdev);
+ struct s10_priv *priv = mgr->priv;
+
+ fpga_mgr_unregister(&pdev->dev);
+ stratix10_svc_free_channel(priv->chan);
+
+ return 0;
+}
+
+static const struct of_device_id s10_of_match[] = {
+ { .compatible = "intel,stratix10-soc-fpga-mgr", },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, s10_of_match);
+
+static struct platform_driver s10_driver = {
+ .probe = s10_probe,
+ .remove = s10_remove,
+ .driver = {
+ .name = "Stratix10 SoC FPGA manager",
+ .of_match_table = of_match_ptr(s10_of_match),
+ },
+};
+
+static int __init s10_init(void)
+{
+ struct device_node *fw_np;
+ struct device_node *np;
+ int ret;
+
+ fw_np = of_find_node_by_name(NULL, "svc");
+ if (!fw_np)
+ return -ENODEV;
+
+ np = of_find_matching_node(fw_np, s10_of_match);
+ if (!np) {
+ of_node_put(fw_np);
+ return -ENODEV;
+ }
+
+ of_node_put(np);
+ ret = of_platform_populate(fw_np, s10_of_match, NULL, NULL);
+ of_node_put(fw_np);
+ if (ret)
+ return ret;
+
+ return platform_driver_register(&s10_driver);
+}
+
+static void __exit s10_exit(void)
+{
+ return platform_driver_unregister(&s10_driver);
+}
+
+module_init(s10_init);
+module_exit(s10_exit);
+
+MODULE_AUTHOR("Alan Tull <atull@kernel.org>");
+MODULE_DESCRIPTION("Intel Stratix 10 SOC FPGA Manager");
+MODULE_LICENSE("GPL v2");
--
2.7.4
^ permalink raw reply related
* [PATCHv4 7/7] defconfig: enable fpga and service layer
From: richard.gong at linux.intel.com @ 2018-05-04 14:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1525443697-31009-1-git-send-email-richard.gong@linux.intel.com>
From: Richard Gong <richard.gong@intel.com>
Enable fpga framework, Stratix 10 SoC FPGA manager and Stratix10
Service Layer
Signed-off-by: Richard Gong <richard.gong@intel.com>
Signed-off-by: Alan Tull <atull@kernel.org>
---
v2: this patch is added in patch set version 2
v3: no change
v4: s/CONFIG_INTEL_SERVICE/CONFIG_STRATIX10_SERVICE/
Add CONFIG_OF_FPGA_REGION=y
s/Intel/Stratix10/ in subject line
---
arch/arm64/configs/defconfig | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index ecf6137..5f7a9b7 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -180,6 +180,7 @@ CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_NBD=m
CONFIG_VIRTIO_BLK=y
CONFIG_BLK_DEV_NVME=m
+CONFIG_STRATIX10_SERVICE=y
CONFIG_SRAM=y
CONFIG_EEPROM_AT25=m
# CONFIG_SCSI_PROC_FS is not set
@@ -595,6 +596,11 @@ CONFIG_PHY_TEGRA_XUSB=y
CONFIG_QCOM_L2_PMU=y
CONFIG_QCOM_L3_PMU=y
CONFIG_MESON_EFUSE=m
+CONFIG_FPGA=y
+CONFIG_FPGA_MGR_STRATIX10_SOC=y
+CONFIG_FPGA_REGION=y
+CONFIG_FPGA_BRIDGE=y
+CONFIG_OF_FPGA_REGION=y
CONFIG_QCOM_QFPROM=y
CONFIG_UNIPHIER_EFUSE=y
CONFIG_TEE=y
--
2.7.4
^ permalink raw reply related
* [PATCH] clk: davinci: pll-dm355: fix SYSCLKn parent names
From: David Lechner @ 2018-05-04 14:24 UTC (permalink / raw)
To: linux-arm-kernel
This fixes the parent clock names of the SYSCLKn clocks for the DM355
SoC in the TI DaVinici PLL clock driver.
It appears that this name just didn't get updated to the correct name
like the other SoCs during the driver's development.
Reported-by: Sekhar Nori <nsekhar@ti.com>
Signed-off-by: David Lechner <david@lechnology.com>
---
Sekhar, can you please test to make sure this works?
drivers/clk/davinci/pll-dm355.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/drivers/clk/davinci/pll-dm355.c b/drivers/clk/davinci/pll-dm355.c
index a0cff4212ac3..13dc6b8ea97a 100644
--- a/drivers/clk/davinci/pll-dm355.c
+++ b/drivers/clk/davinci/pll-dm355.c
@@ -22,10 +22,10 @@ static const struct davinci_pll_clk_info dm355_pll1_info = {
PLL_POSTDIV_ALWAYS_ENABLED | PLL_POSTDIV_FIXED_DIV,
};
-SYSCLK(1, pll1_sysclk1, pll1, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED);
-SYSCLK(2, pll1_sysclk2, pll1, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED);
-SYSCLK(3, pll1_sysclk3, pll1, 5, SYSCLK_ALWAYS_ENABLED);
-SYSCLK(4, pll1_sysclk4, pll1, 5, SYSCLK_ALWAYS_ENABLED);
+SYSCLK(1, pll1_sysclk1, pll1_pllen, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED);
+SYSCLK(2, pll1_sysclk2, pll1_pllen, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED);
+SYSCLK(3, pll1_sysclk3, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED);
+SYSCLK(4, pll1_sysclk4, pll1_pllen, 5, SYSCLK_ALWAYS_ENABLED);
int dm355_pll1_init(struct device *dev, void __iomem *base, struct regmap *cfgchip)
{
@@ -62,8 +62,8 @@ static const struct davinci_pll_clk_info dm355_pll2_info = {
PLL_POSTDIV_ALWAYS_ENABLED | PLL_POSTDIV_FIXED_DIV,
};
-SYSCLK(1, pll2_sysclk1, pll2, 5, SYSCLK_FIXED_DIV);
-SYSCLK(2, pll2_sysclk2, pll2, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED);
+SYSCLK(1, pll2_sysclk1, pll2_pllen, 5, SYSCLK_FIXED_DIV);
+SYSCLK(2, pll2_sysclk2, pll2_pllen, 5, SYSCLK_FIXED_DIV | SYSCLK_ALWAYS_ENABLED);
int dm355_pll2_init(struct device *dev, void __iomem *base, struct regmap *cfgchip)
{
--
2.17.0
^ permalink raw reply related
* [PATCH v9 07/27] ARM: davinci: dm355: add new clock init using common clock framework
From: David Lechner @ 2018-05-04 14:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <093052da-08b8-fe68-d319-254ae1da4d0d@ti.com>
On 05/04/2018 05:01 AM, Sekhar Nori wrote:
> On Thursday 03 May 2018 09:14 PM, David Lechner wrote:
>> On 05/03/2018 10:34 AM, Sekhar Nori wrote:
>>> On Friday 27 April 2018 05:47 AM, David Lechner wrote:
>>>> This adds the new board-specific clock init in mach-davinci/dm355.c
>>>> using the new common clock framework drivers.
>>>>
>>>> The #ifdefs are needed to prevent compile errors until the entire
>>>> ARCH_DAVINCI is converted.
>>>>
>>>> Also clean up the #includes since we are adding some here.
>>>>
>>>> Signed-off-by: David Lechner <david@lechnology.com>
>>>
>>> I am having trouble booting DM355 EVM with the series applied.
>>> Still to debug what is going wrong.
>>
>> Can you dump the PLL registers using /sys/kernel/debug/clk/... ?
>
> I was able to get to ramdisk shell if I set clk_ignore_unused. Here is
> the dump:
>
...
> I didn't have time today to analyze these myself. Hope it helps.
>
I just sent out a patch to fix this: "clk: davinci: pll-dm355: fix
SYSCLKn parent names".
^ permalink raw reply
* Potential deadlock in vgic
From: Andre Przywara @ 2018-05-04 14:51 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180504130854.GA14663@hc>
Hi,
On 04/05/18 14:08, Jan Glauber wrote:
> On Fri, May 04, 2018 at 02:47:42PM +0200, Christoffer Dall wrote:
>> Hi Jan,
>>
>> On Fri, May 04, 2018 at 01:03:44PM +0200, Jan Glauber wrote:
>>> Hi all,
>>>
>>> enabling lockdep I see the following reported in the host when I start a kvm guest:
>>>
>>> [12399.954245] CPU0 CPU1
>>> [12399.958762] ---- ----
>>> [12399.963279] lock(&(&dist->lpi_list_lock)->rlock);
>>> [12399.968146] local_irq_disable();
>>> [12399.974052] lock(&(&vgic_cpu->ap_list_lock)->rlock);
>>> [12399.981696] lock(&(&dist->lpi_list_lock)->rlock);
>>> [12399.989081] <Interrupt>
>>> [12399.991688] lock(&(&vgic_cpu->ap_list_lock)->rlock);
>>> [12399.996989]
>>> *** DEADLOCK ***
>>>
>>> [12400.002897] 2 locks held by qemu-system-aar/5597:
>>> [12400.007587] #0: 0000000042beb9dc (&vcpu->mutex){+.+.}, at: kvm_vcpu_ioctl+0x7c/0xa68
>>> [12400.015411] #1: 00000000c45d644a (&(&vgic_cpu->ap_list_lock)->rlock){-.-.}, at: kvm_vgic_sync_hwstate+0x8c/0x328
>>>
>>>
>>> There is nothing unusual in my config or qemu parameters, I can upload these
>>> if needed. I see this on ThunderX and ThunderX2 and also with older kernels
>>> (4.13+ distribution kernel).
>>>
>>> I tried making the lpi_list_lock irq safe but that just leads to different
>>> warnings. The locking here seems to be quite sophisticated and I'm not familiar
>>> with it.
>>
>> That's unfortunate. The problem here is that we end up violating our
>> locking order, which stipulates that ap_list_lock must be taken before
>> the lpi_list_lock.
>>
>> Give that we can take the ap_list_lock from interrupt context (timers
>> firing), the only solution I can easily think of is to change
>> lpi_list_lock takers to disable interrupts as well.
>>
>> Which warnings did you encounter with that approach?
>
> Hi Christoffer,
>
> making lpi_list_lock irq safe I get:
>
> [ 394.239174] ========================================================
> [ 394.245515] WARNING: possible irq lock inversion dependency detected
> [ 394.251857] 4.17.0-rc3-jang+ #72 Not tainted
> [ 394.256114] --------------------------------------------------------
> [ 394.262454] qemu-system-aar/5596 just changed the state of lock:
> [ 394.268448] 00000000da3f09ef (&(&irq->irq_lock)->rlock#3){+...}, at: update_affinity+0x3c/0xa8
> [ 394.277066] but this lock was taken by another, HARDIRQ-safe lock in the past:
> [ 394.284274] (&(&vgic_cpu->ap_list_lock)->rlock){-.-.}
> [ 394.284278]
>
> and interrupts could create inverse lock ordering between them.
>
> [ 394.300777]
> other info that might help us debug this:
> [ 394.307292] Possible interrupt unsafe locking scenario:
>
> [ 394.314066] CPU0 CPU1
> [ 394.318584] ---- ----
> [ 394.323101] lock(&(&irq->irq_lock)->rlock#3);
> [ 394.327622] local_irq_disable();
> [ 394.333528] lock(&(&vgic_cpu->ap_list_lock)->rlock);
> [ 394.341172] lock(&(&irq->irq_lock)->rlock#3);
> [ 394.348210] <Interrupt>
> [ 394.350817] lock(&(&vgic_cpu->ap_list_lock)->rlock);
> [ 394.356118]
That's weird, as that shouldn't happen anymore. IIRC we switched *both*
ap_list_lock and irq_lock over to be IRQ safe, so the first lock on CPU0
would disable IRQs, making the interrupt afterwards impossible.
Did we actually forget some irq_lock's to convert over and lockdep is
picking those up?
So if this is the case, we should be fine by making the missing ones
irqsave as well, then adding _irqsave to the lpi_list_lock, which has
just a few users and guards only short critical sections contained
within a function.
Cheers,
Andre.
> *** DEADLOCK ***
>
> [ 394.362025] 4 locks held by qemu-system-aar/5596:
> [ 394.366716] #0: 00000000719c7423 (&vcpu->mutex){+.+.}, at: kvm_vcpu_ioctl+0x7c/0xa68
> [ 394.374545] #1: 0000000060090841 (&kvm->srcu){....}, at: kvm_handle_guest_abort+0x11c/0xb70
> [ 394.382984] #2: 0000000064647766 (&its->cmd_lock){+.+.}, at: vgic_mmio_write_its_cwriter+0x44/0xa8
> [ 394.392022] #3: 0000000075f90a8a (&its->its_lock){+.+.}, at: vgic_its_process_commands.part.11+0xac/0x780
> _______________________________________________
> kvmarm mailing list
> kvmarm at lists.cs.columbia.edu
> https://lists.cs.columbia.edu/mailman/listinfo/kvmarm
>
^ permalink raw reply
* [PATCH net-next v2 00/15] ARM: sun8i: r40: Add Ethernet support
From: Maxime Ripard @ 2018-05-04 15:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180503.144042.266645949281979304.davem@davemloft.net>
On Thu, May 03, 2018 at 02:40:42PM -0400, David Miller wrote:
> From: Maxime Ripard <maxime.ripard@bootlin.com>
> Date: Thu, 3 May 2018 15:12:57 +0200
>
> > Hi Dave,
> >
> > On Wed, May 02, 2018 at 11:06:17AM -0400, David Miller wrote:
> >> From: Chen-Yu Tsai <wens@csie.org>
> >> Date: Wed, 2 May 2018 00:33:45 +0800
> >>
> >> > I should've mentioned that patches 3 ~ 10, and only these, should go
> >> > through net-next. sunxi will handle the remaining clk, device tree, and
> >> > soc driver patches.
> >>
> >> Ok, I just noticed this.
> >>
> >> Why don't you just post those patches separately as a series on their
> >> own then, in order to avoid confusion?
> >>
> >> Then you can adjust the patch series header posting to explain the
> >> non-net-next changes, where they got merged, and what they provide
> >> in order to faciliate the net-next changes.
> >
> > I now that we usually have some feedback from non-net maintainers that
> > they actually prefer seeing the full picture (and I also tend to
> > prefer that as well) and having all the patches relevant to enable a
> > particular feature, even if it means getting multiple maintainers
> > involved.
> >
> > Just to make sure we understood you fully, do you want Chen-Yu to
> > resend his serie following your comments, or was that just a general
> > remark for next time?
>
> Yeah, good questions.
>
> I think it can be argued either way. For review having the complete
> context is important.
>
> But from a maintainer's standpoint, when there is any ambiguity
> whatsoever about what patches go into this tree or that, it is really
> frowned upon and is quite error prone.
>
> Also, that header posting is _SO_ important. It explains the series.
> But for these 'partial apply' situations the header posting refers
> to patches not in the series.
>
> This looks terrible in the logs, when, as I do, the header posting
> text is added to a marge commit for the series. People will read it
> and say "where are all of these other changes mentioned in the text?
> was this series misapplied?"
>
> That's why, maybe after the review is successful, I want the actual
> patch series standalone with appropriately updated header posting
> text.
Ok, thanks for the explanation, that makes sense :)
Maxime
--
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180504/fe9e3279/attachment.sig>
^ permalink raw reply
* [PATCH 3/7] pinctrl: sunxi: add support for H6 R_PIO pin controller
From: Maxime Ripard @ 2018-05-04 15:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180503183847.11046-4-icenowy@aosc.io>
On Fri, May 04, 2018 at 02:38:43AM +0800, Icenowy Zheng wrote:
> Allwinner H6 SoC has a R_PIO pin controller like other Allwinner SoCs,
> which controls the PL and PM pin banks.
>
> Add support for it.
>
> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
Acked-by: Maxime Ripard <maxime.ripard@bootlin.com>
Thanks!
Maxime
--
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180504/714eefbf/attachment.sig>
^ permalink raw reply
* [PATCH 1/7] clk: sunxi-ng: add support for H6 PRCM CCU
From: Maxime Ripard @ 2018-05-04 15:06 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180503183847.11046-2-icenowy@aosc.io>
On Fri, May 04, 2018 at 02:38:41AM +0800, Icenowy Zheng wrote:
> The H6 has clock/reset controls in PRCM part, like old SoCs such as H3
> and A64. However, the PRCM CCU is rearranged; the register arragement
> is now similar to the main CCU of H6, and the PRCM now has two APB
> buses to control -- one is clocked from AHB clock derivde from AR100
> clock, the other is clocked from the same mux with AR100 clock.
> Therefore a new driver is written for it.
>
> As there's no official document about the PRCM in H6, all the information
> are indirectly collected from BSP and parts of the document, and the
> information source is noted as comments in the driver's source code. If
> reliable information is provided furtherly, the driver needs to be
> rechecked.
>
> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
Applied, thanks!
Maxime
--
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180504/36132935/attachment.sig>
^ permalink raw reply
* [PATCH 2/7] arm64: allwinner: h6: add PRCM CCU device node
From: Maxime Ripard @ 2018-05-04 15:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180503183847.11046-3-icenowy@aosc.io>
On Fri, May 04, 2018 at 02:38:42AM +0800, Icenowy Zheng wrote:
> Allwinner H6 has also a PRCM CCU.
>
> Add its device node into the device tree.
>
> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
Applied, thanks!
Maxime
--
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180504/d0705481/attachment.sig>
^ permalink raw reply
* [PATCH 4/7] arm64: allwinner: h6: add node for R_PIO pin controller
From: Maxime Ripard @ 2018-05-04 15:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180503183847.11046-5-icenowy@aosc.io>
On Fri, May 04, 2018 at 02:38:44AM +0800, Icenowy Zheng wrote:
> Allwinner H6 SoC has a R_PIO pin controller which controls PL and PM
> GPIO banks.
>
> Add support for it.
>
> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
> ---
> arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi | 13 +++++++++++++
> 1 file changed, 13 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
> index db9da343ba46..a18b78fb4850 100644
> --- a/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
> +++ b/arch/arm64/boot/dts/allwinner/sun50i-h6.dtsi
> @@ -183,5 +183,18 @@
> #clock-cells = <1>;
> #reset-cells = <1>;
> };
> +
> + r_pio: pinctrl at 7022000 {
> + compatible = "allwinner,sun50i-h6-r-pinctrl";
> + reg = <0x07022000 0x400>;
> + interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>,
> + <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>;
> + clocks = <&r_ccu CLK_R_APB1>, <&osc24M>, <&osc32k>;
As usual, try not to use the indices you introduce in the previous
patches of your serie. This introduces a dependency between the clk
and arm-soc tree that is not easy to deal with.
changed for the raw index, and applied, thanks!
maxime
--
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180504/d03e455a/attachment.sig>
^ permalink raw reply
* [PATCH 5/7] arm64: allwinner: h6: add R_INTC interrupt controller
From: Maxime Ripard @ 2018-05-04 15:10 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180503183847.11046-6-icenowy@aosc.io>
On Fri, May 04, 2018 at 02:38:45AM +0800, Icenowy Zheng wrote:
> Allwinner H6 SoC has also a R_INTC interrupt controller like Allwinner
> A64 SoC, but has its base address changed due to the memory map change
> in H6.
>
> Add it into the device tree.
>
> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
Applied, thanks!
Maxime
--
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180504/9fc17ff6/attachment.sig>
^ permalink raw reply
* [PATCH 6/7] arm64: allwinner: h6: add R_I2C controller
From: Maxime Ripard @ 2018-05-04 15:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180503183847.11046-7-icenowy@aosc.io>
On Fri, May 04, 2018 at 02:38:46AM +0800, Icenowy Zheng wrote:
> Allwinner H6 SoC has a R_I2C controller wired to the PL0/PL1 pins, which
> are used in the reference design to connect AXP805 PMIC.
>
> Add support for it.
>
> Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
Dropped the headers (that should have been in your previous patch to
maintain the bisectability) and changed for indices, and applied.
Maxime
--
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180504/388bbe10/attachment-0001.sig>
^ permalink raw reply
* Potential deadlock in vgic
From: Andre Przywara @ 2018-05-04 15:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180504130854.GA14663@hc>
Hi Jan,
can you please test this patch with your setup, to see if it still
screams? That converts two forgotten irq_lock's over to be irqsafe,
plus lets lpi_list_lock join them (which you already did, IIUC).
That should appease lockdep, hopefully.
Cheers,
Andre.
---
virt/kvm/arm/vgic/vgic-debug.c | 5 +++--
virt/kvm/arm/vgic/vgic-its.c | 15 +++++++++------
virt/kvm/arm/vgic/vgic.c | 12 +++++++-----
3 files changed, 19 insertions(+), 13 deletions(-)
diff --git a/virt/kvm/arm/vgic/vgic-debug.c b/virt/kvm/arm/vgic/vgic-debug.c
index 10b38178cff2..4ffc0b5e6105 100644
--- a/virt/kvm/arm/vgic/vgic-debug.c
+++ b/virt/kvm/arm/vgic/vgic-debug.c
@@ -211,6 +211,7 @@ static int vgic_debug_show(struct seq_file *s, void *v)
struct vgic_state_iter *iter = (struct vgic_state_iter *)v;
struct vgic_irq *irq;
struct kvm_vcpu *vcpu = NULL;
+ unsigned long flags;
if (iter->dist_id == 0) {
print_dist_state(s, &kvm->arch.vgic);
@@ -227,9 +228,9 @@ static int vgic_debug_show(struct seq_file *s, void *v)
irq = &kvm->arch.vgic.spis[iter->intid - VGIC_NR_PRIVATE_IRQS];
}
- spin_lock(&irq->irq_lock);
+ spin_lock_irqsave(&irq->irq_lock, flags);
print_irq_state(s, irq, vcpu);
- spin_unlock(&irq->irq_lock);
+ spin_unlock_irqrestore(&irq->irq_lock, flags);
return 0;
}
diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index a8f07243aa9f..51a80b600632 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -52,6 +52,7 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid,
{
struct vgic_dist *dist = &kvm->arch.vgic;
struct vgic_irq *irq = vgic_get_irq(kvm, NULL, intid), *oldirq;
+ unsigned long flags;
int ret;
/* In this case there is no put, since we keep the reference. */
@@ -71,7 +72,7 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid,
irq->intid = intid;
irq->target_vcpu = vcpu;
- spin_lock(&dist->lpi_list_lock);
+ spin_lock_irqsave(&dist->lpi_list_lock, flags);
/*
* There could be a race with another vgic_add_lpi(), so we need to
@@ -99,7 +100,7 @@ static struct vgic_irq *vgic_add_lpi(struct kvm *kvm, u32 intid,
dist->lpi_list_count++;
out_unlock:
- spin_unlock(&dist->lpi_list_lock);
+ spin_unlock_irqrestore(&dist->lpi_list_lock, flags);
/*
* We "cache" the configuration table entries in our struct vgic_irq's.
@@ -315,6 +316,7 @@ static int vgic_copy_lpi_list(struct kvm_vcpu *vcpu, u32 **intid_ptr)
{
struct vgic_dist *dist = &vcpu->kvm->arch.vgic;
struct vgic_irq *irq;
+ unsigned long flags;
u32 *intids;
int irq_count, i = 0;
@@ -330,7 +332,7 @@ static int vgic_copy_lpi_list(struct kvm_vcpu *vcpu, u32 **intid_ptr)
if (!intids)
return -ENOMEM;
- spin_lock(&dist->lpi_list_lock);
+ spin_lock_irqsave(&dist->lpi_list_lock, flags);
list_for_each_entry(irq, &dist->lpi_list_head, lpi_list) {
if (i == irq_count)
break;
@@ -339,7 +341,7 @@ static int vgic_copy_lpi_list(struct kvm_vcpu *vcpu, u32 **intid_ptr)
continue;
intids[i++] = irq->intid;
}
- spin_unlock(&dist->lpi_list_lock);
+ spin_unlock_irqrestore(&dist->lpi_list_lock, flags);
*intid_ptr = intids;
return i;
@@ -348,10 +350,11 @@ static int vgic_copy_lpi_list(struct kvm_vcpu *vcpu, u32 **intid_ptr)
static int update_affinity(struct vgic_irq *irq, struct kvm_vcpu *vcpu)
{
int ret = 0;
+ unsigned long flags;
- spin_lock(&irq->irq_lock);
+ spin_lock_irqsave(&irq->irq_lock, flags);
irq->target_vcpu = vcpu;
- spin_unlock(&irq->irq_lock);
+ spin_unlock_irqrestore(&irq->irq_lock, flags);
if (irq->hw) {
struct its_vlpi_map map;
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 5f52a2bca36f..6efcddfb5167 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -75,8 +75,9 @@ static struct vgic_irq *vgic_get_lpi(struct kvm *kvm, u32 intid)
{
struct vgic_dist *dist = &kvm->arch.vgic;
struct vgic_irq *irq = NULL;
+ unsigned long flags;
- spin_lock(&dist->lpi_list_lock);
+ spin_lock_irqsave(&dist->lpi_list_lock, flags);
list_for_each_entry(irq, &dist->lpi_list_head, lpi_list) {
if (irq->intid != intid)
@@ -92,7 +93,7 @@ static struct vgic_irq *vgic_get_lpi(struct kvm *kvm, u32 intid)
irq = NULL;
out_unlock:
- spin_unlock(&dist->lpi_list_lock);
+ spin_unlock_irqrestore(&dist->lpi_list_lock, flags);
return irq;
}
@@ -137,19 +138,20 @@ static void vgic_irq_release(struct kref *ref)
void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)
{
struct vgic_dist *dist = &kvm->arch.vgic;
+ unsigned long flags;
if (irq->intid < VGIC_MIN_LPI)
return;
- spin_lock(&dist->lpi_list_lock);
+ spin_lock_irqsave(&dist->lpi_list_lock, flags);
if (!kref_put(&irq->refcount, vgic_irq_release)) {
- spin_unlock(&dist->lpi_list_lock);
+ spin_unlock_irqrestore(&dist->lpi_list_lock, flags);
return;
};
list_del(&irq->lpi_list);
dist->lpi_list_count--;
- spin_unlock(&dist->lpi_list_lock);
+ spin_unlock_irqrestore(&dist->lpi_list_lock, flags);
kfree(irq);
}
--
2.14.1
^ permalink raw reply related
* [PATCH] arm64: vgic-v2: Fix proxying of cpuif access
From: James Morse @ 2018-05-04 15:19 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180427145102.5645-1-marc.zyngier@arm.com>
Hi Marc,
On 27/04/18 15:51, Marc Zyngier wrote:
> Proxying the cpuif accesses at EL2 makes use of vcpu_data_guest_to_host
> and co, which check the endianness, which call into vcpu_read_sys_reg...
> which isn't mapped at EL2 (it was inlined before, and got moved OoL
> with the VHE optimizations).
>
> The result is of course a nice panic. Let's add some specialized
> cruft to keep the broken platforms that require this hack alive.
> I'd rather kill BE support, but hey, just in case...
I have this a spin on Juno with a big-endian host and 64K pages:
Trying to boot a BE guest hangs.
Trying to boot a LE guest hangs.
> @@ -64,14 +88,11 @@ int __hyp_text __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu)
> addr += fault_ipa - vgic->vgic_cpu_base;
>
> if (kvm_vcpu_dabt_iswrite(vcpu)) {
> - u32 data = vcpu_data_guest_to_host(vcpu,
> - vcpu_get_reg(vcpu, rd),
> - sizeof(u32));
> + u32 data = __guest_to_host_u32(vcpu, vcpu_get_reg(vcpu, rd));
> writel_relaxed(data, addr);
> } else {
> - u32 data = readl_relaxed(addr);
> - vcpu_set_reg(vcpu, rd, vcpu_data_host_to_guest(vcpu, data,
> - sizeof(u32)));
> + u32 data = __host_to_guest_u32(vcpu, readl_relaxed(addr));
> + vcpu_set_reg(vcpu, rd, data);
> }
This happens because readl()/writel() are doing their own swabbing on
big-endian, even if the guest had already done this.
As I've trampled all over this patch, I'll post a v2...
Thanks,
James
^ permalink raw reply
* [PATCH v2] arm64: vgic-v2: Fix proxying of cpuif access
From: James Morse @ 2018-05-04 15:19 UTC (permalink / raw)
To: linux-arm-kernel
Proxying the cpuif accesses at EL2 makes use of vcpu_data_guest_to_host
and co, which check the endianness, which call into vcpu_read_sys_reg...
which isn't mapped at EL2 (it was inlined before, and got moved OoL
with the VHE optimizations).
The result is of course a nice panic. Let's add some specialized
cruft to keep the broken platforms that require this hack alive.
But, this code used vcpu_data_guest_to_host(), which expected us to
write the value to host memory, instead we have trapped the guest's
read or write to an mmio-device, and are about to replay it using the
host's readl()/writel() which also perform swabbing based on the host
endianness. This goes wrong when both host and guest are big-endian,
as readl()/writel() will undo the guest's swabbing, causing the
big-endian value to be written to device-memory.
What needs doing?
A big-endian guest will have pre-swabbed data before storing, undo this.
If its necessary for the host, writel() will re-swab it.
For a read a big-endian guest expects to swab the data after the load.
The hosts's readl() will correct for host endianness, giving us the
device-memory's value in the register. For a big-endian guest, swab it
as if we'd only done the load.
For a little-endian guest, nothing needs doing as readl()/writel() leave
the correct device-memory value in registers.
Tested on Juno with that rarest of things: a big-endian 64K host.
Based on a patch from Marc Zyngier.
Reported-by: Suzuki K Poulose <suzuki.poulose@arm.com>
Fixes: bf8feb39642b ("arm64: KVM: vgic-v2: Add GICV access from HYP")
CC: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: James Morse <james.morse@arm.com>
---
This patch doesn't apply before 8a43a2b34b7d
("KVM: arm/arm64: Move arm64-only vgic-v2-sr.c file to arm64"), but the
backport is straightforward.
arch/arm64/kvm/hyp/vgic-v2-cpuif-proxy.c | 24 +++++++++++++++++++-----
1 file changed, 19 insertions(+), 5 deletions(-)
diff --git a/arch/arm64/kvm/hyp/vgic-v2-cpuif-proxy.c b/arch/arm64/kvm/hyp/vgic-v2-cpuif-proxy.c
index 86801b6055d6..39be799d0417 100644
--- a/arch/arm64/kvm/hyp/vgic-v2-cpuif-proxy.c
+++ b/arch/arm64/kvm/hyp/vgic-v2-cpuif-proxy.c
@@ -18,11 +18,20 @@
#include <linux/compiler.h>
#include <linux/irqchip/arm-gic.h>
#include <linux/kvm_host.h>
+#include <linux/swab.h>
#include <asm/kvm_emulate.h>
#include <asm/kvm_hyp.h>
#include <asm/kvm_mmu.h>
+static bool __hyp_text __is_be(struct kvm_vcpu *vcpu)
+{
+ if (vcpu_mode_is_32bit(vcpu))
+ return !!(read_sysreg_el2(spsr) & COMPAT_PSR_E_BIT);
+
+ return !!(read_sysreg(SCTLR_EL1) & SCTLR_ELx_EE);
+}
+
/*
* __vgic_v2_perform_cpuif_access -- perform a GICV access on behalf of the
* guest.
@@ -64,14 +73,19 @@ int __hyp_text __vgic_v2_perform_cpuif_access(struct kvm_vcpu *vcpu)
addr += fault_ipa - vgic->vgic_cpu_base;
if (kvm_vcpu_dabt_iswrite(vcpu)) {
- u32 data = vcpu_data_guest_to_host(vcpu,
- vcpu_get_reg(vcpu, rd),
- sizeof(u32));
+ u32 data = vcpu_get_reg(vcpu, rd);
+ if (__is_be(vcpu)) {
+ /* guest pre-swabbed data, undo this for writel() */
+ data = swab32(data);
+ }
writel_relaxed(data, addr);
} else {
u32 data = readl_relaxed(addr);
- vcpu_set_reg(vcpu, rd, vcpu_data_host_to_guest(vcpu, data,
- sizeof(u32)));
+ if (__is_be(vcpu)) {
+ /* guest expects swabbed data */
+ data = swab32(data);
+ }
+ vcpu_set_reg(vcpu, rd, data);
}
return 1;
--
2.16.2
^ permalink raw reply related
* [PATCH] arm: Convert arm boot_lock to raw
From: Tony Lindgren @ 2018-05-04 15:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180504105600.20613-1-bigeasy@linutronix.de>
* Sebastian Andrzej Siewior <bigeasy@linutronix.de> [180504 10:58]:
> From: Frank Rowand <frank.rowand@am.sony.com>
>
> The arm boot_lock is used by the secondary processor startup code. The locking
> task is the idle thread, which has idle->sched_class == &idle_sched_class.
> idle_sched_class->enqueue_task == NULL, so if the idle task blocks on the
> lock, the attempt to wake it when the lock becomes available will fail:
>
> try_to_wake_up()
> ...
> activate_task()
> enqueue_task()
> p->sched_class->enqueue_task(rq, p, flags)
>
> Fix by converting boot_lock to a raw spin lock.
Still works for me:
Tested-by: Tony Lindgren <tony@atomide.com>
^ permalink raw reply
* [PATCH 3/4] ARM: dts: imx27: use lable to override osc26m clock setting
From: Fabio Estevam @ 2018-05-04 15:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1525395446-1953-4-git-send-email-shawnguo@kernel.org>
Hi Shawn,
On Thu, May 3, 2018 at 9:57 PM, Shawn Guo <shawnguo@kernel.org> wrote:
> Instead of copying the whole node hierarchy, let's define a label for
> clock osc26m in soc dtsi and use it for overriding clock-frequency.
>
> Signed-off-by: Shawn Guo <shawnguo@kernel.org>
In the Subject: s/lable/label
Other than that the series looks good.
^ permalink raw reply
* [GIT PULL] ARM: tegra: Device tree fixes for v4.17
From: Thierry Reding @ 2018-05-04 15:38 UTC (permalink / raw)
To: linux-arm-kernel
Hi ARM SoC maintainers,
The following changes since commit 60cc43fc888428bb2f18f08997432d426a243338:
Linux 4.17-rc1 (2018-04-15 18:24:20 -0700)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git tags/tegra-for-4.17-fixes
for you to fetch changes up to 9bf4e370048d2bbae5262d0c6280e0142804a272:
ARM: dts: tegra20: Revert "Fix ULPI regression on Tegra20" (2018-05-04 17:32:29 +0200)
Thanks,
Thierry
----------------------------------------------------------------
ARM: tegra: Device tree fixes for v4.17
This contains a single revert for a patch that was merged in v4.17-rc1
and that turns out to cause a regression on some boards. Further, the
original issue that the patch was supposed to fix seems to have
disappeared.
----------------------------------------------------------------
Dmitry Osipenko (1):
ARM: dts: tegra20: Revert "Fix ULPI regression on Tegra20"
arch/arm/boot/dts/tegra20.dtsi | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
^ permalink raw reply
* [PATCH v2] arm64: vgic-v2: Fix proxying of cpuif access
From: Marc Zyngier @ 2018-05-04 15:43 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180504151924.13696-1-james.morse@arm.com>
On 04/05/18 16:19, James Morse wrote:
> Proxying the cpuif accesses at EL2 makes use of vcpu_data_guest_to_host
> and co, which check the endianness, which call into vcpu_read_sys_reg...
> which isn't mapped at EL2 (it was inlined before, and got moved OoL
> with the VHE optimizations).
>
> The result is of course a nice panic. Let's add some specialized
> cruft to keep the broken platforms that require this hack alive.
>
> But, this code used vcpu_data_guest_to_host(), which expected us to
> write the value to host memory, instead we have trapped the guest's
> read or write to an mmio-device, and are about to replay it using the
> host's readl()/writel() which also perform swabbing based on the host
> endianness. This goes wrong when both host and guest are big-endian,
> as readl()/writel() will undo the guest's swabbing, causing the
> big-endian value to be written to device-memory.
>
> What needs doing?
> A big-endian guest will have pre-swabbed data before storing, undo this.
> If its necessary for the host, writel() will re-swab it.
>
> For a read a big-endian guest expects to swab the data after the load.
> The hosts's readl() will correct for host endianness, giving us the
> device-memory's value in the register. For a big-endian guest, swab it
> as if we'd only done the load.
>
> For a little-endian guest, nothing needs doing as readl()/writel() leave
> the correct device-memory value in registers.
>
> Tested on Juno with that rarest of things: a big-endian 64K host.
<song>
The Thing That Should Not Be
</song>
> Based on a patch from Marc Zyngier.
>
> Reported-by: Suzuki K Poulose <suzuki.poulose@arm.com>
> Fixes: bf8feb39642b ("arm64: KVM: vgic-v2: Add GICV access from HYP")
> CC: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: James Morse <james.morse@arm.com>
Awesome, thanks a lot for picking this up and fixing it the right way!
I'll queue it right away.
Thanks,
M.
--
Jazz is not dead. It just smells funny...
^ permalink raw reply
* [PATCH v2 09/10] ARM: dts: sun7i-a20: Add Video Engine and reserved memory nodes
From: Maxime Ripard @ 2018-05-04 15:44 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <dd6b502c66aad1fe34eb0b16a1e44a4ebfd172f1.camel@bootlin.com>
On Fri, May 04, 2018 at 03:57:48PM +0200, Paul Kocialkowski wrote:
> On Fri, 2018-05-04 at 15:40 +0200, Maxime Ripard wrote:
> > On Fri, May 04, 2018 at 02:04:38PM +0200, Paul Kocialkowski wrote:
> > > On Fri, 2018-05-04 at 11:15 +0200, Maxime Ripard wrote:
> > > > On Fri, May 04, 2018 at 10:47:44AM +0200, Paul Kocialkowski wrote:
> > > > > > > > > + reg = <0x01c0e000 0x1000>;
> > > > > > > > > + memory-region = <&ve_memory>;
> > > > > > > >
> > > > > > > > Since you made the CMA region the default one, you don't
> > > > > > > > need
> > > > > > > > to
> > > > > > > > tie
> > > > > > > > it to that device in particular (and you can drop it being
> > > > > > > > mandatory
> > > > > > > > from your binding as well).
> > > > > > >
> > > > > > > What if another driver (or the system) claims memory from
> > > > > > > that
> > > > > > > zone
> > > > > > > and
> > > > > > > that the reserved memory ends up not being available for the
> > > > > > > VPU
> > > > > > > anymore?
> > > > > > >
> > > > > > > Acccording to the reserved-memory documentation, the
> > > > > > > reusable
> > > > > > > property
> > > > > > > (that we need for dmabuf) puts a limitation that the device
> > > > > > > driver
> > > > > > > owning the region must be able to reclaim it back.
> > > > > > >
> > > > > > > How does that work out if the CMA region is not tied to a
> > > > > > > driver
> > > > > > > in
> > > > > > > particular?
> > > > > >
> > > > > > I'm not sure to get what you're saying. You have the property
> > > > > > linux,cma-default in your reserved region, so the behaviour
> > > > > > you
> > > > > > described is what you explicitly asked for.
> > > > >
> > > > > My point is that I don't see how the driver can claim back (part
> > > > > of)
> > > > > the
> > > > > reserved area if the area is not explicitly attached to it.
> > > > >
> > > > > Or is that mechanism made in a way that all drivers wishing to
> > > > > use
> > > > > the
> > > > > reserved memory area can claim it back from the system, but
> > > > > there is
> > > > > no
> > > > > priority (other than first-come first-served) for which drivers
> > > > > claims
> > > > > it back in case two want to use the same reserved region (in a
> > > > > scenario
> > > > > where there isn't enough memory to allow both drivers)?
> > > >
> > > > This is indeed what happens. Reusable is to let the system use the
> > > > reserved memory for things like caches that can easily be dropped
> > > > when
> > > > a driver wants to use the memory in that reserved area. Once that
> > > > memory has been allocated, there's no claiming back, unless that
> > > > memory segment was freed of course.
> > >
> > > Thanks for the clarification. So in our case, perhaps the best fit
> > > would
> > > be to make that area the default CMA pool so that we can be ensured
> > > that
> > > the whole 96 MiB is available for the VPU and that no other consumer
> > > of
> > > CMA will use it?
> >
> > The best fit for what use case ? We already discussed this, and I
> > don't see any point in having two separate CMA regions. If you have a
> > reasonably sized region that will accomodate for both the VPU and
> > display engine, why would we want to split them?
>
> The use case I have in mind is boilerplate use of the VPU with the
> display engine, say with DMAbuf.
>
> It wasn't exactly clear in my memory whether we had decided that the CMA
> pool we use for the VPU should also be used for other CMA consumers (I
> realize that this is what we've been doing all along by having
> linux,cma-default; though).
>
> The fact that the memory region will accomodate for both the display
> engine and the VPU is not straightforward IMO and I think this has to be
> an explicit choice that we take. I was under the impression that we
> chose the 96 MiB because that's what the Allwinner reference code does.
> Does the reference code also use this pool for display?
Yes
> I liked the idea of having 96 MiB fully reserved to the VPU because it
> allows us to provide a limit on the use case, such as "this guarantees N
> buffers for resolution foo in format bar". If the display engine also
> uses it, then the limit also depends on how many GEM buffers are
> allocated (unless I'm missing something).
This also guarantees that you take away a fifth of the RAM on some
boards. If we had yet another CMA pool of 64MB as is the multi_v7
defconfig, that's a third of your RAM that's gone, possibly for no
particular reason.
If we make the math, let's say that we are running a system with 4
planes used in 1080p, with 4 Bpp, in double buffering (which is
already an unlikely setup). Let's add on top of that that we're
decoding a 1080p video with 8 buffers pre-allocated with 2Bpp (in
YUV422). Which really seems extreme now :)
And we're at 80MB. My guess is that your memory bus is going to be
dead before you need to use all that memory.
Maxime
--
Maxime Ripard, Bootlin (formerly Free Electrons)
Embedded Linux and Kernel engineering
https://bootlin.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180504/dafc7cb2/attachment.sig>
^ permalink raw reply
* [PATCH] PCI: Check whether bridges allow access to extended config space
From: Gilles Buloz @ 2018-05-04 15:45 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180503223127.GB15790@bhelgaas-glaptop.roam.corp.google.com>
Le 04/05/2018 00:31, Bjorn Helgaas a ?crit :
> [+cc LKML]
>
> On Thu, May 03, 2018 at 12:40:27PM +0000, Gilles Buloz wrote:
>> Subject: [PATCH] For exception at PCI probe due to bridge reporting UR
>>
>> Even if a device supports extended config access, no such access must be
>> done to this device If there's a bridge not supporting that in the path
>> to this device. Doing such access with UR reporting enabled on the root
>> bridge leads to an exception.
>>
>> This is the case on a LS1043A CPU (NXP QorIQ Layerscape) platform with
>> the following bus topology :
>> LS1043 PCIe root
>> -> PEX8112 PCIe-to-PCI bridge (not supporting ext cfg on PCI side)
>> -> PMC slot connector (for legacy PMC modules)
>> With a PMC module topology as follows :
>> PMC connector
>> -> PCI-to-PCIe bridge
>> -> PCIe switch (4 ports)
>> -> 4 PCIe devices (one on each port)
>> In this case all devices behind the PEX8112 are supporting extended config
>> access but this is prohibited by the PEX8112. Without this patch, an
>> exception (synchronous abort) occurs in pci_cfg_space_size_ext().
>>
>> This patch checks the parent bridge of each allocated child bus to know if
>> extended config access is supported on the child bus, and sets a flag in
>> child->bus_flags if not supported. This flag is inherited by all children
>> buses of this child bus and then is checked to avoid this unsupported
>> accesses to every device on these buses.
> Hi Gilles,
>
> Thanks for the patch! I reworked it a little bit to simplify the code
> in pci_alloc_child_bus(). Can you test it and make sure I didn't
> break anything?
>
Hi Bjorn,
Your rework works as expected. Tested on LS1043A platform with kernel 4.17-rc1, and with some backport on kernel 4.1.35
Suggestion : maybe change the pci_info() string to have :
pci_bus 0000:xx: extended config space not accessible
instead of
pci_bus 0000:xx: extended config space not accessible on secondary bus
as xx is already the number of the secondary bus
Info : with kernel 4.17-rc1, it turns out I need pcie_aspm=off to have the PMC devices behind the
PCI-to-PCIe bridge of the PMC safely detected/configured. But this is not caused by the patch.
Without pcie_aspm=off I saw this at one boot :
"pci 0000:02:0e.0: ASPM: Could not configure common clock" for this bridge, but devices
correctly detected/configured
but at most boots I get :
no ASPM message but "pci 0000:04:02.0: bridge configuration invalid ([bus ff-ff]), reconfiguring "
instead, and some devices are missing. Also lspci show "rev ff" for some devices.
I don't see this problem on 4.1.35 with the same backported patch.
Gilles
> commit cbaaa85b558a8f974e301fa0364d568efaf491ce
> Author: Gilles Buloz <Gilles.Buloz@kontron.com>
> Date: Thu May 3 15:21:44 2018 -0500
>
> PCI: Check whether bridges allow access to extended config space
>
> Even if a device supports extended config space, i.e., it is a PCI-X Mode 2
> or a PCI Express device, the extended space may not be accessible if
> there's a conventional PCI bus in the path to it.
>
> We currently figure that out in pci_cfg_space_size() by reading the first
> dword of extended config space. On most platforms that returns ~0 data if
> the space is inaccessible, but it may set error bits in PCI status
> registers, and on some platforms it causes exceptions that we currently
> don't recover from.
>
> For example, a PCIe-to-conventional PCI bridge treats config transactions
> with a non-zero Extended Register Address as an Unsupported Request on PCIe
> and a received Master-Abort on the destination bus (see PCI Express to
> PCI/PCI-X Bridge spec, r1.0, sec 4.1.3).
>
> A sample case is a LS1043A CPU (NXP QorIQ Layerscape) platform with the
> following bus topology:
>
> LS1043 PCIe Root Port
> -> PEX8112 PCIe-to-PCI bridge (doesn't support ext cfg on PCI side)
> -> PMC slot connector (for legacy PMC modules)
>
> With a PMC module topology as follows:
>
> PMC connector
> -> PCI-to-PCIe bridge
> -> PCIe switch (4 ports)
> -> 4 PCIe devices (one on each port)
>
> The PCIe devices on the PMC module support extended config space, but we
> can't reach it because the PEX8112 can't generate accesses to the extended
> space on its secondary bus. Attempts to access it cause Unsupported
> Request errors, which result in synchronous aborts on this platform.
>
> To avoid these errors, check whether bridges are capable of generating
> extended config space addresses on their secondary interfaces. If they
> can't, we restrict devices below the bridge to only the 256-byte
> PCI-compatible config space.
>
> Signed-off-by: Gilles Buloz <gilles.buloz@kontron.com>
> [bhelgaas: changelog, rework patch so bus_flags testing is all in
> pci_bridge_child_ext_cfg_accessible()]
> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
>
> diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
> index ac91b6fd0bcd..7b1b7b2e01e4 100644
> --- a/drivers/pci/probe.c
> +++ b/drivers/pci/probe.c
> @@ -882,6 +882,45 @@ static int pci_register_host_bridge(struct pci_host_bridge *bridge)
> return err;
> }
>
> +static bool pci_bridge_child_ext_cfg_accessible(struct pci_dev *bridge)
> +{
> + int pos;
> + u32 status;
> +
> + /*
> + * If extended config space isn't accessible on a bridge's primary
> + * bus, we certainly can't access it on the secondary bus.
> + */
> + if (bridge->bus->bus_flags & PCI_BUS_FLAGS_NO_EXTCFG)
> + return false;
> +
> + /*
> + * PCIe Root Ports and switch ports are PCIe on both sides, so if
> + * extended config space is accessible on the primary, it's also
> + * accessible on the secondary.
> + */
> + if (pci_is_pcie(bridge) &&
> + (pci_pcie_type(bridge) == PCI_EXP_TYPE_ROOT_PORT ||
> + pci_pcie_type(bridge) == PCI_EXP_TYPE_UPSTREAM ||
> + pci_pcie_type(bridge) == PCI_EXP_TYPE_DOWNSTREAM))
> + return true;
> +
> + /*
> + * For the other bridge types:
> + * - PCI-to-PCI bridges
> + * - PCIe-to-PCI/PCI-X forward bridges
> + * - PCI/PCI-X-to-PCIe reverse bridges
> + * extended config space on the secondary side is only accessible
> + * if the bridge supports PCI-X Mode 2.
> + */
> + pos = pci_find_capability(bridge, PCI_CAP_ID_PCIX);
> + if (!pos)
> + return false;
> +
> + pci_read_config_dword(bridge, pos + PCI_X_STATUS, &status);
> + return status & (PCI_X_STATUS_266MHZ | PCI_X_STATUS_533MHZ);
> +}
> +
> static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent,
> struct pci_dev *bridge, int busnr)
> {
> @@ -923,6 +962,16 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent,
> pci_set_bus_of_node(child);
> pci_set_bus_speed(child);
>
> + /*
> + * Check whether extended config space is accessible on the child
> + * bus. Note that we currently assume it is always accessible on
> + * the root bus.
> + */
> + if (!pci_bridge_child_ext_cfg_accessible(bridge)) {
> + child->bus_flags |= PCI_BUS_FLAGS_NO_EXTCFG;
> + pci_info(child, "extended config space not accessible on secondary bus\n");
> + }
> +
> /* Set up default resource pointers and names */
> for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) {
> child->resource[i] = &bridge->resource[PCI_BRIDGE_RESOURCES+i];
> @@ -1393,6 +1442,9 @@ int pci_cfg_space_size(struct pci_dev *dev)
> u32 status;
> u16 class;
>
> + if (dev->bus->bus_flags & PCI_BUS_FLAGS_NO_EXTCFG)
> + return PCI_CFG_SPACE_SIZE;
> +
> class = dev->class >> 8;
> if (class == PCI_CLASS_BRIDGE_HOST)
> return pci_cfg_space_size_ext(dev);
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index 230615620a4a..f7aa6d9f8999 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -217,6 +217,7 @@ enum pci_bus_flags {
> PCI_BUS_FLAGS_NO_MSI = (__force pci_bus_flags_t) 1,
> PCI_BUS_FLAGS_NO_MMRBC = (__force pci_bus_flags_t) 2,
> PCI_BUS_FLAGS_NO_AERSID = (__force pci_bus_flags_t) 4,
> + PCI_BUS_FLAGS_NO_EXTCFG = (__force pci_bus_flags_t) 8,
> };
>
> /* Values from Link Status register, PCIe r3.1, sec 7.8.8 */
>
> .
>
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox