Commit d3cd3b55 authored by Arnd Bergmann's avatar Arnd Bergmann

Merge tag 'ffa-updates-6.7' of...

Merge tag 'ffa-updates-6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux into soc/drivers

Arm FF-A updates for v6.7

The main addition is the initial support for the notifications and
memory transaction descriptor changes added in FF-A v1.1 specification.

The notification mechanism enables a requester/sender endpoint to notify
a service provider/receiver endpoint about an event with non-blocking
semantics. A notification is akin to the doorbell between two endpoints
in a communication protocol that is based upon the doorbell/mailbox
mechanism.

The framework is responsible for the delivery of the notification from
the ender to the receiver without blocking the sender. The receiver
endpoint relies on the OS scheduler for allocation of CPU cycles to
handle a notification.

OS is referred as the receiver’s scheduler in the context of notifications.
The framework is responsible for informing the receiver’s scheduler that
the receiver must be run since it has a pending notification.

The series also includes support for the new format of memory transaction
descriptors introduced in v1.1 specification.

Apart from the main additions, it includes minor fixes to re-enable FF-A
drivers usage of 32bit mode of messaging and kernel warning due to the
missing assignment of IDR allocation ID to the FFA device. It also adds
emitting 'modalias' to the base attribute of FF-A devices.

* tag 'ffa-updates-6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux:
  firmware: arm_ffa: Upgrade the driver version to v1.1
  firmware: arm_ffa: Update memory descriptor to support v1.1 format
  firmware: arm_ffa: Switch to using ffa_mem_desc_offset() accessor
  KVM: arm64: FFA: Remove access of endpoint memory access descriptor array
  firmware: arm_ffa: Simplify the computation of transmit and fragment length
  firmware: arm_ffa: Add notification handling mechanism
  firmware: arm_ffa: Add interface to send a notification to a given partition
  firmware: arm_ffa: Add interfaces to request notification callbacks
  firmware: arm_ffa: Add schedule receiver callback mechanism
  firmware: arm_ffa: Initial support for scheduler receiver interrupt
  firmware: arm_ffa: Implement the NOTIFICATION_INFO_GET interface
  firmware: arm_ffa: Implement the FFA_NOTIFICATION_GET interface
  firmware: arm_ffa: Implement the FFA_NOTIFICATION_SET interface
  firmware: arm_ffa: Implement the FFA_RUN interface
  firmware: arm_ffa: Implement the notification bind and unbind interface
  firmware: arm_ffa: Implement notification bitmap create and destroy interfaces
  firmware: arm_ffa: Update the FF-A command list with v1.1 additions
  firmware: arm_ffa: Emit modalias for FF-A devices
  firmware: arm_ffa: Allow the FF-A drivers to use 32bit mode of messaging
  firmware: arm_ffa: Assign the missing IDR allocation ID to the FFA device

Link: https://lore.kernel.org/r/20231010124354.1620064-1-sudeep.holla@arm.comSigned-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parents d1debb7b bcefd1bf
......@@ -423,6 +423,7 @@ static __always_inline void do_ffa_mem_xfer(const u64 func_id,
DECLARE_REG(u32, fraglen, ctxt, 2);
DECLARE_REG(u64, addr_mbz, ctxt, 3);
DECLARE_REG(u32, npages_mbz, ctxt, 4);
struct ffa_mem_region_attributes *ep_mem_access;
struct ffa_composite_mem_region *reg;
struct ffa_mem_region *buf;
u32 offset, nr_ranges;
......@@ -452,7 +453,9 @@ static __always_inline void do_ffa_mem_xfer(const u64 func_id,
buf = hyp_buffers.tx;
memcpy(buf, host_buffers.tx, fraglen);
offset = buf->ep_mem_access[0].composite_off;
ep_mem_access = (void *)buf +
ffa_mem_desc_offset(buf, 0, FFA_VERSION_1_0);
offset = ep_mem_access->composite_off;
if (!offset || buf->ep_count != 1 || buf->sender_id != HOST_FFA_ID) {
ret = FFA_RET_INVALID_PARAMETERS;
goto out_unlock;
......@@ -504,6 +507,7 @@ static void do_ffa_mem_reclaim(struct arm_smccc_res *res,
DECLARE_REG(u32, handle_lo, ctxt, 1);
DECLARE_REG(u32, handle_hi, ctxt, 2);
DECLARE_REG(u32, flags, ctxt, 3);
struct ffa_mem_region_attributes *ep_mem_access;
struct ffa_composite_mem_region *reg;
u32 offset, len, fraglen, fragoff;
struct ffa_mem_region *buf;
......@@ -528,7 +532,9 @@ static void do_ffa_mem_reclaim(struct arm_smccc_res *res,
len = res->a1;
fraglen = res->a2;
offset = buf->ep_mem_access[0].composite_off;
ep_mem_access = (void *)buf +
ffa_mem_desc_offset(buf, 0, FFA_VERSION_1_0);
offset = ep_mem_access->composite_off;
/*
* We can trust the SPMD to get this right, but let's at least
* check that we end up with something that doesn't look _completely_
......
......@@ -15,6 +15,8 @@
#include "common.h"
#define SCMI_UEVENT_MODALIAS_FMT "arm_ffa:%04x:%pUb"
static DEFINE_IDA(ffa_bus_id);
static int ffa_device_match(struct device *dev, struct device_driver *drv)
......@@ -63,10 +65,20 @@ static int ffa_device_uevent(const struct device *dev, struct kobj_uevent_env *e
{
const struct ffa_device *ffa_dev = to_ffa_dev(dev);
return add_uevent_var(env, "MODALIAS=arm_ffa:%04x:%pUb",
return add_uevent_var(env, "MODALIAS=" SCMI_UEVENT_MODALIAS_FMT,
ffa_dev->vm_id, &ffa_dev->uuid);
}
static ssize_t modalias_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct ffa_device *ffa_dev = to_ffa_dev(dev);
return sysfs_emit(buf, SCMI_UEVENT_MODALIAS_FMT, ffa_dev->vm_id,
&ffa_dev->uuid);
}
static DEVICE_ATTR_RO(modalias);
static ssize_t partition_id_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
......@@ -88,6 +100,7 @@ static DEVICE_ATTR_RO(uuid);
static struct attribute *ffa_device_attributes_attrs[] = {
&dev_attr_partition_id.attr,
&dev_attr_uuid.attr,
&dev_attr_modalias.attr,
NULL,
};
ATTRIBUTE_GROUPS(ffa_device_attributes);
......@@ -193,6 +206,7 @@ struct ffa_device *ffa_device_register(const uuid_t *uuid, int vm_id,
dev->release = ffa_release_device;
dev_set_name(&ffa_dev->dev, "arm-ffa-%d", id);
ffa_dev->id = id;
ffa_dev->vm_id = vm_id;
ffa_dev->ops = ops;
uuid_copy(&ffa_dev->uuid, uuid);
......
This diff is collapsed.
......@@ -6,6 +6,7 @@
#ifndef _LINUX_ARM_FFA_H
#define _LINUX_ARM_FFA_H
#include <linux/bitfield.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/types.h>
......@@ -20,6 +21,7 @@
#define FFA_ERROR FFA_SMC_32(0x60)
#define FFA_SUCCESS FFA_SMC_32(0x61)
#define FFA_FN64_SUCCESS FFA_SMC_64(0x61)
#define FFA_INTERRUPT FFA_SMC_32(0x62)
#define FFA_VERSION FFA_SMC_32(0x63)
#define FFA_FEATURES FFA_SMC_32(0x64)
......@@ -54,6 +56,23 @@
#define FFA_MEM_FRAG_RX FFA_SMC_32(0x7A)
#define FFA_MEM_FRAG_TX FFA_SMC_32(0x7B)
#define FFA_NORMAL_WORLD_RESUME FFA_SMC_32(0x7C)
#define FFA_NOTIFICATION_BITMAP_CREATE FFA_SMC_32(0x7D)
#define FFA_NOTIFICATION_BITMAP_DESTROY FFA_SMC_32(0x7E)
#define FFA_NOTIFICATION_BIND FFA_SMC_32(0x7F)
#define FFA_NOTIFICATION_UNBIND FFA_SMC_32(0x80)
#define FFA_NOTIFICATION_SET FFA_SMC_32(0x81)
#define FFA_NOTIFICATION_GET FFA_SMC_32(0x82)
#define FFA_NOTIFICATION_INFO_GET FFA_SMC_32(0x83)
#define FFA_FN64_NOTIFICATION_INFO_GET FFA_SMC_64(0x83)
#define FFA_RX_ACQUIRE FFA_SMC_32(0x84)
#define FFA_SPM_ID_GET FFA_SMC_32(0x85)
#define FFA_MSG_SEND2 FFA_SMC_32(0x86)
#define FFA_SECONDARY_EP_REGISTER FFA_SMC_32(0x87)
#define FFA_FN64_SECONDARY_EP_REGISTER FFA_SMC_64(0x87)
#define FFA_MEM_PERM_GET FFA_SMC_32(0x88)
#define FFA_FN64_MEM_PERM_GET FFA_SMC_64(0x88)
#define FFA_MEM_PERM_SET FFA_SMC_32(0x89)
#define FFA_FN64_MEM_PERM_SET FFA_SMC_64(0x89)
/*
* For some calls it is necessary to use SMC64 to pass or return 64-bit values.
......@@ -76,6 +95,7 @@
#define FFA_RET_DENIED (-6)
#define FFA_RET_RETRY (-7)
#define FFA_RET_ABORTED (-8)
#define FFA_RET_NO_DATA (-9)
/* FFA version encoding */
#define FFA_MAJOR_VERSION_MASK GENMASK(30, 16)
......@@ -86,6 +106,7 @@
(FIELD_PREP(FFA_MAJOR_VERSION_MASK, (major)) | \
FIELD_PREP(FFA_MINOR_VERSION_MASK, (minor)))
#define FFA_VERSION_1_0 FFA_PACK_VERSION_INFO(1, 0)
#define FFA_VERSION_1_1 FFA_PACK_VERSION_INFO(1, 1)
/**
* FF-A specification mentions explicitly about '4K pages'. This should
......@@ -278,8 +299,8 @@ struct ffa_mem_region {
#define FFA_MEM_NON_SHAREABLE (0)
#define FFA_MEM_OUTER_SHAREABLE (2)
#define FFA_MEM_INNER_SHAREABLE (3)
u8 attributes;
u8 reserved_0;
/* Memory region attributes, upper byte MBZ pre v1.1 */
u16 attributes;
/*
* Clear memory region contents after unmapping it from the sender and
* before mapping it for any receiver.
......@@ -317,27 +338,41 @@ struct ffa_mem_region {
* memory region.
*/
u64 tag;
u32 reserved_1;
/* Size of each endpoint memory access descriptor, MBZ pre v1.1 */
u32 ep_mem_size;
/*
* The number of `ffa_mem_region_attributes` entries included in this
* transaction.
*/
u32 ep_count;
/*
* An array of endpoint memory access descriptors.
* Each one specifies a memory region offset, an endpoint and the
* attributes with which this memory region should be mapped in that
* endpoint's page table.
* 16-byte aligned offset from the base address of this descriptor
* to the first element of the endpoint memory access descriptor array
* Valid only from v1.1
*/
struct ffa_mem_region_attributes ep_mem_access[];
u32 ep_mem_offset;
/* MBZ, valid only from v1.1 */
u32 reserved[3];
};
#define COMPOSITE_OFFSET(x) \
(offsetof(struct ffa_mem_region, ep_mem_access[x]))
#define CONSTITUENTS_OFFSET(x) \
(offsetof(struct ffa_composite_mem_region, constituents[x]))
#define COMPOSITE_CONSTITUENTS_OFFSET(x, y) \
(COMPOSITE_OFFSET(x) + CONSTITUENTS_OFFSET(y))
static inline u32
ffa_mem_desc_offset(struct ffa_mem_region *buf, int count, u32 ffa_version)
{
u32 offset = count * sizeof(struct ffa_mem_region_attributes);
/*
* Earlier to v1.1, the endpoint memory descriptor array started at
* offset 32(i.e. offset of ep_mem_offset in the current structure)
*/
if (ffa_version <= FFA_VERSION_1_0)
offset += offsetof(struct ffa_mem_region, ep_mem_offset);
else
offset += sizeof(struct ffa_mem_region);
return offset;
}
struct ffa_mem_ops_args {
bool use_txbuf;
......@@ -367,10 +402,30 @@ struct ffa_mem_ops {
int (*memory_lend)(struct ffa_mem_ops_args *args);
};
struct ffa_cpu_ops {
int (*run)(struct ffa_device *dev, u16 vcpu);
};
typedef void (*ffa_sched_recv_cb)(u16 vcpu, bool is_per_vcpu, void *cb_data);
typedef void (*ffa_notifier_cb)(int notify_id, void *cb_data);
struct ffa_notifier_ops {
int (*sched_recv_cb_register)(struct ffa_device *dev,
ffa_sched_recv_cb cb, void *cb_data);
int (*sched_recv_cb_unregister)(struct ffa_device *dev);
int (*notify_request)(struct ffa_device *dev, bool per_vcpu,
ffa_notifier_cb cb, void *cb_data, int notify_id);
int (*notify_relinquish)(struct ffa_device *dev, int notify_id);
int (*notify_send)(struct ffa_device *dev, int notify_id, bool per_vcpu,
u16 vcpu);
};
struct ffa_ops {
const struct ffa_info_ops *info_ops;
const struct ffa_msg_ops *msg_ops;
const struct ffa_mem_ops *mem_ops;
const struct ffa_cpu_ops *cpu_ops;
const struct ffa_notifier_ops *notifier_ops;
};
#endif /* _LINUX_ARM_FFA_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment