mirror of
https://github.com/torvalds/linux.git
synced 2026-05-27 08:33:17 +02:00
Arm FF-A updates for v6.15
This update primarily focuses on FF-A framework notification support
along with other improvements, including UUID handling enhancements
and various fixes.
1. FF-A framework notification upport
- Adds support for multiple UUIDs per partition to register individual
SRI callbacks.
- Handles Rx buffer full framework notifications and provides a general
interface for future extensions.
2. Improved multiple UUID/services per-partition handling
- Adds support for UUID passing in FFA_MSG_SEND2, improving multiple
UUID/service support in the driver.
- Introduces a helper function to check whether a partition can
receive REQUEST2 messages.
3. Partition handling generic improvements
- Implements device unregistration for better partition cleanup.
- Improves handling of the host partition presence in partition info.
4. FF-A version updates
- Upgrades the driver version to FF-A v1.2.
- Rejects major versions higher than the driver version as incompatible.
5. Big-Endian support fixes
- Fixes big-endian issues in:
__ffa_partition_info_regs_get()
__ffa_partition_info_get()
- Big-endian support is still incomplete, and only these changes can
be verified without additional application/testing updates at the
moment. We can discover all the partitions correctly with big-endian
kernel now.
6. Miscellaneous fixes
- Fixes function prototype misalignments in: sync_send_receive{,2}
- Adds explicit type casting for return values from: FFA_VERSION
and NOTIFICATION_INFO_GET
- Corrects vCPU list parsing in ffa_notification_info_get().
7. UUID management in the driver and DMA mask updates
- Replaces UUID buffer with the standard UUID format in ffa_partition_info
structure.
- Fixes a typo in some FF-A bus macros.
- Sets dma_mask for FF-A devices.
In short, this update enhances notification handling, UUID support, and
overall robustness of the FF-A driver while addressing multiple fixes
and cleanups.
-----BEGIN PGP SIGNATURE-----
iQIzBAABCAAdFiEEunHlEgbzHrJD3ZPhAEG6vDF+4pgFAmfG2gkACgkQAEG6vDF+
4pgCsA//UN0T8cX8BxgAYjEjGYxrwzvJJsjFN4gxIeiXa0aLUWRObSNbr8qkDWd/
MnWYgDdmy5DdzBFc5yGnpTlgS7hQFPCywfnxU2sErJmFthG9FsrcZ4C3xss+aLP9
QTqn8QpOMIAMegg+35FkzLaIcPjkJbAJNMvvBmC0BJUhU4eJFrtSXTnc4ijJDk0y
jNxW/il0gSv6d/GJOiHDop+0W+XrxuCvbAtOzshiIZ6eZEew5rY1EJdHPsEAuh7h
5tP1mIQZbXD8iwgKQmVqh+gSAUCRvK1l9WfsOTw6gK7+IL3kpuSOP0UjR/mB6F0Y
TivwuFQtDlbpLD/TbiJqkTzJVF+aWouq5onv/hFUVSapcWlXlb8QO2mHXhCblgTV
rTAi61WVlU95RB7ZmKG0pBig1LRsCw/tc9u2+zv8jOmVc9zDDYG7YHguOtx8d8uY
z9yNXooNzes9F1EZyxQDhe/f/q7QKs9XUnG6WBmd6FXF0F3qDAfi+yySOY1fUUdh
cO7Vy4bNNywg+/U+ePqMm11DnjLIjIny9z9s3ruyyQ4LuCTGq/oJc0nLaniH3ukb
iynZVUXbXu1PXm5bGW+CpoA/ivlLo+FuFPIFgwXFVlgACvnNDfJXKG5a/5SxHbpD
b4VCRkMz2wmamwYD6veZBq4AOHkrnWlnF6eZs08z1PBIzd2kfLo=
=qX1J
-----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
iQIzBAABCgAdFiEEiK/NIGsWEZVxh/FrYKtH/8kJUicFAmfJyysACgkQYKtH/8kJ
UifldBAAmSmOhxSHMSW9D5vtJW33XPsHf3zjcDjHHVNoF4AHZDWpvN2xTbBRhe1c
iPf4R1A+Otfa0BfxTFyG5gMIMfyRGjSmkveDVlnnrn+dLafc2AyiHZsOAaz6PvSN
zG3FFbMSPKBqNVy2CEbDDb/HfOtodzIpiqcHDO/kBSlrMz7hNn81TsOQ+BqvMjNE
d7yddFvdEZZYGphHD6Q/cOcrFfuWNhfYkn130sORg8eolIhp+SsXXBKlOxgjBtRX
TbRW6FUCE+aEZtyrzOpsopI9zqXsgPy7h6BgnlDc3INB+1N1re7zQlvh4Jsqn4wh
DmhAhrPLf8NzkUuIIRUDPBoNRwIP+1MvGAvKWq8FyMh2hvZ+ARW87FxiABEiwCbc
/N1waQrapdLB695cKAEDCaBrgN+opxWOx7P6X3tCRAirIRpEtNaLJ/Awd4lfDoyK
qacIjsw+KQy9TGi1k/TPslVZ5E2wiVqmlEJjyC3KchVK7AIDDFQ480C7IC9gnJPZ
TVlyUGWN0iHK8Aer0AvO0lV4z5E0fL6ovJhPX/8/3uLaPNFKXs5+m5+0i0RJPYw9
0phlX7CyXSlm9IMmPQv2BgPI/+dKifRA0mtoDvtfQe6gbpihnXYcm0+90jVaa/bE
DxaLozWLoQqWc22nQCDFJ6XUK5WC11bRr5KYFg07FqSYFEE/JA0=
=Phyc
-----END PGP SIGNATURE-----
Merge tag 'ffa-updates-6.15' of https://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux into soc/drivers
Arm FF-A updates for v6.15
This update primarily focuses on FF-A framework notification support
along with other improvements, including UUID handling enhancements
and various fixes.
1. FF-A framework notification upport
- Adds support for multiple UUIDs per partition to register individual
SRI callbacks.
- Handles Rx buffer full framework notifications and provides a general
interface for future extensions.
2. Improved multiple UUID/services per-partition handling
- Adds support for UUID passing in FFA_MSG_SEND2, improving multiple
UUID/service support in the driver.
- Introduces a helper function to check whether a partition can
receive REQUEST2 messages.
3. Partition handling generic improvements
- Implements device unregistration for better partition cleanup.
- Improves handling of the host partition presence in partition info.
4. FF-A version updates
- Upgrades the driver version to FF-A v1.2.
- Rejects major versions higher than the driver version as incompatible.
5. Big-Endian support fixes
- Fixes big-endian issues in:
__ffa_partition_info_regs_get()
__ffa_partition_info_get()
- Big-endian support is still incomplete, and only these changes can
be verified without additional application/testing updates at the
moment. We can discover all the partitions correctly with big-endian
kernel now.
6. Miscellaneous fixes
- Fixes function prototype misalignments in: sync_send_receive{,2}
- Adds explicit type casting for return values from: FFA_VERSION
and NOTIFICATION_INFO_GET
- Corrects vCPU list parsing in ffa_notification_info_get().
7. UUID management in the driver and DMA mask updates
- Replaces UUID buffer with the standard UUID format in ffa_partition_info
structure.
- Fixes a typo in some FF-A bus macros.
- Sets dma_mask for FF-A devices.
In short, this update enhances notification handling, UUID support, and
overall robustness of the FF-A driver while addressing multiple fixes
and cleanups.
* tag 'ffa-updates-6.15' of https://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux: (23 commits)
firmware: arm_ffa: Set dma_mask for ffa devices
firmware: arm_ffa: Skip the first/partition ID when parsing vCPU list
firmware: arm_ffa: Explicitly cast return value from NOTIFICATION_INFO_GET
firmware: arm_ffa: Explicitly cast return value from FFA_VERSION before comparison
firmware: arm_ffa: Handle ffa_notification_get correctly at virtual FF-A instance
firmware: arm_ffa: Allow multiple UUIDs per partition to register SRI callback
firmware: arm_ffa: Add support for handling framework notifications
firmware: arm_ffa: Add support for {un,}registration of framework notifications
firmware: arm_ffa: Stash ffa_device instead of notify_type in notifier_cb_info
firmware: arm_ffa: Refactoring to prepare for framework notification support
firmware: arm_ffa: Remove unnecessary declaration of ffa_partitions_cleanup()
firmware: arm_ffa: Reject higher major version as incompatible
firmware: arm_ffa: Upgrade FF-A version to v1.2 in the driver
firmware: arm_ffa: Add support for passing UUID in FFA_MSG_SEND2
firmware: arm_ffa: Helper to check if a partition can receive REQUEST2 messages
firmware: arm_ffa: Unregister the FF-A devices when cleaning up the partitions
firmware: arm_ffa: Handle the presence of host partition in the partition info
firmware: arm_ffa: Refactor addition of partition information into XArray
firmware: arm_ffa: Fix big-endian support in __ffa_partition_info_regs_get()
firmware: arm_ffa: Fix big-endian support in __ffa_partition_info_get()
...
Link: https://lore.kernel.org/r/20250304105928.432997-1-sudeep.holla@arm.com
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
commit
4f1afeaa30
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
#include "common.h"
|
||||
|
||||
#define SCMI_UEVENT_MODALIAS_FMT "arm_ffa:%04x:%pUb"
|
||||
#define FFA_UEVENT_MODALIAS_FMT "arm_ffa:%04x:%pUb"
|
||||
|
||||
static DEFINE_IDA(ffa_bus_id);
|
||||
|
||||
|
|
@ -68,7 +68,7 @@ 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=" SCMI_UEVENT_MODALIAS_FMT,
|
||||
return add_uevent_var(env, "MODALIAS=" FFA_UEVENT_MODALIAS_FMT,
|
||||
ffa_dev->vm_id, &ffa_dev->uuid);
|
||||
}
|
||||
|
||||
|
|
@ -77,7 +77,7 @@ static ssize_t modalias_show(struct device *dev,
|
|||
{
|
||||
struct ffa_device *ffa_dev = to_ffa_dev(dev);
|
||||
|
||||
return sysfs_emit(buf, SCMI_UEVENT_MODALIAS_FMT, ffa_dev->vm_id,
|
||||
return sysfs_emit(buf, FFA_UEVENT_MODALIAS_FMT, ffa_dev->vm_id,
|
||||
&ffa_dev->uuid);
|
||||
}
|
||||
static DEVICE_ATTR_RO(modalias);
|
||||
|
|
@ -160,11 +160,12 @@ static int __ffa_devices_unregister(struct device *dev, void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void ffa_devices_unregister(void)
|
||||
void ffa_devices_unregister(void)
|
||||
{
|
||||
bus_for_each_dev(&ffa_bus_type, NULL, NULL,
|
||||
__ffa_devices_unregister);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ffa_devices_unregister);
|
||||
|
||||
bool ffa_device_is_valid(struct ffa_device *ffa_dev)
|
||||
{
|
||||
|
|
@ -192,7 +193,6 @@ ffa_device_register(const struct ffa_partition_info *part_info,
|
|||
const struct ffa_ops *ops)
|
||||
{
|
||||
int id, ret;
|
||||
uuid_t uuid;
|
||||
struct device *dev;
|
||||
struct ffa_device *ffa_dev;
|
||||
|
||||
|
|
@ -212,14 +212,14 @@ ffa_device_register(const struct ffa_partition_info *part_info,
|
|||
dev = &ffa_dev->dev;
|
||||
dev->bus = &ffa_bus_type;
|
||||
dev->release = ffa_release_device;
|
||||
dev->dma_mask = &dev->coherent_dma_mask;
|
||||
dev_set_name(&ffa_dev->dev, "arm-ffa-%d", id);
|
||||
|
||||
ffa_dev->id = id;
|
||||
ffa_dev->vm_id = part_info->id;
|
||||
ffa_dev->properties = part_info->properties;
|
||||
ffa_dev->ops = ops;
|
||||
import_uuid(&uuid, (u8 *)part_info->uuid);
|
||||
uuid_copy(&ffa_dev->uuid, &uuid);
|
||||
uuid_copy(&ffa_dev->uuid, &part_info->uuid);
|
||||
|
||||
ret = device_register(&ffa_dev->dev);
|
||||
if (ret) {
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@
|
|||
|
||||
#include "common.h"
|
||||
|
||||
#define FFA_DRIVER_VERSION FFA_VERSION_1_1
|
||||
#define FFA_DRIVER_VERSION FFA_VERSION_1_2
|
||||
#define FFA_MIN_VERSION FFA_VERSION_1_0
|
||||
|
||||
#define SENDER_ID_MASK GENMASK(31, 16)
|
||||
|
|
@ -114,7 +114,6 @@ struct ffa_drv_info {
|
|||
};
|
||||
|
||||
static struct ffa_drv_info *drv_info;
|
||||
static void ffa_partitions_cleanup(void);
|
||||
|
||||
/*
|
||||
* The driver must be able to support all the versions from the earliest
|
||||
|
|
@ -145,11 +144,19 @@ static int ffa_version_check(u32 *version)
|
|||
.a0 = FFA_VERSION, .a1 = FFA_DRIVER_VERSION,
|
||||
}, &ver);
|
||||
|
||||
if (ver.a0 == FFA_RET_NOT_SUPPORTED) {
|
||||
if ((s32)ver.a0 == FFA_RET_NOT_SUPPORTED) {
|
||||
pr_info("FFA_VERSION returned not supported\n");
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (FFA_MAJOR_VERSION(ver.a0) > FFA_MAJOR_VERSION(FFA_DRIVER_VERSION)) {
|
||||
pr_err("Incompatible v%d.%d! Latest supported v%d.%d\n",
|
||||
FFA_MAJOR_VERSION(ver.a0), FFA_MINOR_VERSION(ver.a0),
|
||||
FFA_MAJOR_VERSION(FFA_DRIVER_VERSION),
|
||||
FFA_MINOR_VERSION(FFA_DRIVER_VERSION));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ver.a0 < FFA_MIN_VERSION) {
|
||||
pr_err("Incompatible v%d.%d! Earliest supported v%d.%d\n",
|
||||
FFA_MAJOR_VERSION(ver.a0), FFA_MINOR_VERSION(ver.a0),
|
||||
|
|
@ -276,9 +283,21 @@ __ffa_partition_info_get(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
|
|||
}
|
||||
|
||||
if (buffer && count <= num_partitions)
|
||||
for (idx = 0; idx < count; idx++)
|
||||
memcpy(buffer + idx, drv_info->rx_buffer + idx * sz,
|
||||
buf_sz);
|
||||
for (idx = 0; idx < count; idx++) {
|
||||
struct ffa_partition_info_le {
|
||||
__le16 id;
|
||||
__le16 exec_ctxt;
|
||||
__le32 properties;
|
||||
uuid_t uuid;
|
||||
} *rx_buf = drv_info->rx_buffer + idx * sz;
|
||||
struct ffa_partition_info *buf = buffer + idx;
|
||||
|
||||
buf->id = le16_to_cpu(rx_buf->id);
|
||||
buf->exec_ctxt = le16_to_cpu(rx_buf->exec_ctxt);
|
||||
buf->properties = le32_to_cpu(rx_buf->properties);
|
||||
if (buf_sz > 8)
|
||||
import_uuid(&buf->uuid, (u8 *)&rx_buf->uuid);
|
||||
}
|
||||
|
||||
ffa_rx_release();
|
||||
|
||||
|
|
@ -295,14 +314,24 @@ __ffa_partition_info_get(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
|
|||
#define CURRENT_INDEX(x) ((u16)(FIELD_GET(CURRENT_INDEX_MASK, (x))))
|
||||
#define UUID_INFO_TAG(x) ((u16)(FIELD_GET(UUID_INFO_TAG_MASK, (x))))
|
||||
#define PARTITION_INFO_SZ(x) ((u16)(FIELD_GET(PARTITION_INFO_SZ_MASK, (x))))
|
||||
#define PART_INFO_ID_MASK GENMASK(15, 0)
|
||||
#define PART_INFO_EXEC_CXT_MASK GENMASK(31, 16)
|
||||
#define PART_INFO_PROPS_MASK GENMASK(63, 32)
|
||||
#define PART_INFO_ID(x) ((u16)(FIELD_GET(PART_INFO_ID_MASK, (x))))
|
||||
#define PART_INFO_EXEC_CXT(x) ((u16)(FIELD_GET(PART_INFO_EXEC_CXT_MASK, (x))))
|
||||
#define PART_INFO_PROPERTIES(x) ((u32)(FIELD_GET(PART_INFO_PROPS_MASK, (x))))
|
||||
static int
|
||||
__ffa_partition_info_get_regs(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
|
||||
struct ffa_partition_info *buffer, int num_parts)
|
||||
{
|
||||
u16 buf_sz, start_idx, cur_idx, count = 0, prev_idx = 0, tag = 0;
|
||||
struct ffa_partition_info *buf = buffer;
|
||||
ffa_value_t partition_info;
|
||||
|
||||
do {
|
||||
__le64 *regs;
|
||||
int idx;
|
||||
|
||||
start_idx = prev_idx ? prev_idx + 1 : 0;
|
||||
|
||||
invoke_ffa_fn((ffa_value_t){
|
||||
|
|
@ -326,8 +355,25 @@ __ffa_partition_info_get_regs(u32 uuid0, u32 uuid1, u32 uuid2, u32 uuid3,
|
|||
if (buf_sz > sizeof(*buffer))
|
||||
buf_sz = sizeof(*buffer);
|
||||
|
||||
memcpy(buffer + prev_idx * buf_sz, &partition_info.a3,
|
||||
(cur_idx - start_idx + 1) * buf_sz);
|
||||
regs = (void *)&partition_info.a3;
|
||||
for (idx = 0; idx < cur_idx - start_idx + 1; idx++, buf++) {
|
||||
union {
|
||||
uuid_t uuid;
|
||||
u64 regs[2];
|
||||
} uuid_regs = {
|
||||
.regs = {
|
||||
le64_to_cpu(*(regs + 1)),
|
||||
le64_to_cpu(*(regs + 2)),
|
||||
}
|
||||
};
|
||||
u64 val = *(u64 *)regs;
|
||||
|
||||
buf->id = PART_INFO_ID(val);
|
||||
buf->exec_ctxt = PART_INFO_EXEC_CXT(val);
|
||||
buf->properties = PART_INFO_PROPERTIES(val);
|
||||
uuid_copy(&buf->uuid, &uuid_regs.uuid);
|
||||
regs += 3;
|
||||
}
|
||||
prev_idx = cur_idx;
|
||||
|
||||
} while (cur_idx < (count - 1));
|
||||
|
|
@ -445,9 +491,9 @@ static int ffa_msg_send_direct_req(u16 src_id, u16 dst_id, bool mode_32bit,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int ffa_msg_send2(u16 src_id, u16 dst_id, void *buf, size_t sz)
|
||||
static int ffa_msg_send2(struct ffa_device *dev, u16 src_id, void *buf, size_t sz)
|
||||
{
|
||||
u32 src_dst_ids = PACK_TARGET_INFO(src_id, dst_id);
|
||||
u32 src_dst_ids = PACK_TARGET_INFO(src_id, dev->vm_id);
|
||||
struct ffa_indirect_msg_hdr *msg;
|
||||
ffa_value_t ret;
|
||||
int retval = 0;
|
||||
|
|
@ -463,6 +509,7 @@ static int ffa_msg_send2(u16 src_id, u16 dst_id, void *buf, size_t sz)
|
|||
msg->offset = sizeof(*msg);
|
||||
msg->send_recv_id = src_dst_ids;
|
||||
msg->size = sz;
|
||||
uuid_copy(&msg->uuid, &dev->uuid);
|
||||
memcpy((u8 *)msg + msg->offset, buf, sz);
|
||||
|
||||
/* flags = 0, sender VMID = 0 works for both physical/virtual NS */
|
||||
|
|
@ -760,6 +807,13 @@ static int ffa_notification_bitmap_destroy(void)
|
|||
return 0;
|
||||
}
|
||||
|
||||
enum notify_type {
|
||||
SECURE_PARTITION,
|
||||
NON_SECURE_VM,
|
||||
SPM_FRAMEWORK,
|
||||
NS_HYP_FRAMEWORK,
|
||||
};
|
||||
|
||||
#define NOTIFICATION_LOW_MASK GENMASK(31, 0)
|
||||
#define NOTIFICATION_HIGH_MASK GENMASK(63, 32)
|
||||
#define NOTIFICATION_BITMAP_HIGH(x) \
|
||||
|
|
@ -783,10 +837,22 @@ static int ffa_notification_bitmap_destroy(void)
|
|||
#define MAX_IDS_32 10
|
||||
|
||||
#define PER_VCPU_NOTIFICATION_FLAG BIT(0)
|
||||
#define SECURE_PARTITION_BITMAP BIT(0)
|
||||
#define NON_SECURE_VM_BITMAP BIT(1)
|
||||
#define SPM_FRAMEWORK_BITMAP BIT(2)
|
||||
#define NS_HYP_FRAMEWORK_BITMAP BIT(3)
|
||||
#define SECURE_PARTITION_BITMAP_ENABLE BIT(SECURE_PARTITION)
|
||||
#define NON_SECURE_VM_BITMAP_ENABLE BIT(NON_SECURE_VM)
|
||||
#define SPM_FRAMEWORK_BITMAP_ENABLE BIT(SPM_FRAMEWORK)
|
||||
#define NS_HYP_FRAMEWORK_BITMAP_ENABLE BIT(NS_HYP_FRAMEWORK)
|
||||
#define FFA_BITMAP_SECURE_ENABLE_MASK \
|
||||
(SECURE_PARTITION_BITMAP_ENABLE | SPM_FRAMEWORK_BITMAP_ENABLE)
|
||||
#define FFA_BITMAP_NS_ENABLE_MASK \
|
||||
(NON_SECURE_VM_BITMAP_ENABLE | NS_HYP_FRAMEWORK_BITMAP_ENABLE)
|
||||
#define FFA_BITMAP_ALL_ENABLE_MASK \
|
||||
(FFA_BITMAP_SECURE_ENABLE_MASK | FFA_BITMAP_NS_ENABLE_MASK)
|
||||
|
||||
#define FFA_SECURE_PARTITION_ID_FLAG BIT(15)
|
||||
|
||||
#define SPM_FRAMEWORK_BITMAP(x) NOTIFICATION_BITMAP_LOW(x)
|
||||
#define NS_HYP_FRAMEWORK_BITMAP(x) NOTIFICATION_BITMAP_HIGH(x)
|
||||
#define FRAMEWORK_NOTIFY_RX_BUFFER_FULL BIT(0)
|
||||
|
||||
static int ffa_notification_bind_common(u16 dst_id, u64 bitmap,
|
||||
u32 flags, bool is_bind)
|
||||
|
|
@ -852,9 +918,15 @@ static int ffa_notification_get(u32 flags, struct ffa_notify_bitmaps *notify)
|
|||
else if (ret.a0 != FFA_SUCCESS)
|
||||
return -EINVAL; /* Something else went wrong. */
|
||||
|
||||
notify->sp_map = PACK_NOTIFICATION_BITMAP(ret.a2, ret.a3);
|
||||
notify->vm_map = PACK_NOTIFICATION_BITMAP(ret.a4, ret.a5);
|
||||
notify->arch_map = PACK_NOTIFICATION_BITMAP(ret.a6, ret.a7);
|
||||
if (flags & SECURE_PARTITION_BITMAP_ENABLE)
|
||||
notify->sp_map = PACK_NOTIFICATION_BITMAP(ret.a2, ret.a3);
|
||||
if (flags & NON_SECURE_VM_BITMAP_ENABLE)
|
||||
notify->vm_map = PACK_NOTIFICATION_BITMAP(ret.a4, ret.a5);
|
||||
if (flags & SPM_FRAMEWORK_BITMAP_ENABLE)
|
||||
notify->arch_map = SPM_FRAMEWORK_BITMAP(ret.a6);
|
||||
if (flags & NS_HYP_FRAMEWORK_BITMAP_ENABLE)
|
||||
notify->arch_map = PACK_NOTIFICATION_BITMAP(notify->arch_map,
|
||||
ret.a7);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -863,27 +935,32 @@ struct ffa_dev_part_info {
|
|||
ffa_sched_recv_cb callback;
|
||||
void *cb_data;
|
||||
rwlock_t rw_lock;
|
||||
struct ffa_device *dev;
|
||||
struct list_head node;
|
||||
};
|
||||
|
||||
static void __do_sched_recv_cb(u16 part_id, u16 vcpu, bool is_per_vcpu)
|
||||
{
|
||||
struct ffa_dev_part_info *partition;
|
||||
struct ffa_dev_part_info *partition = NULL, *tmp;
|
||||
ffa_sched_recv_cb callback;
|
||||
struct list_head *phead;
|
||||
void *cb_data;
|
||||
|
||||
partition = xa_load(&drv_info->partition_info, part_id);
|
||||
if (!partition) {
|
||||
phead = xa_load(&drv_info->partition_info, part_id);
|
||||
if (!phead) {
|
||||
pr_err("%s: Invalid partition ID 0x%x\n", __func__, part_id);
|
||||
return;
|
||||
}
|
||||
|
||||
read_lock(&partition->rw_lock);
|
||||
callback = partition->callback;
|
||||
cb_data = partition->cb_data;
|
||||
read_unlock(&partition->rw_lock);
|
||||
list_for_each_entry_safe(partition, tmp, phead, node) {
|
||||
read_lock(&partition->rw_lock);
|
||||
callback = partition->callback;
|
||||
cb_data = partition->cb_data;
|
||||
read_unlock(&partition->rw_lock);
|
||||
|
||||
if (callback)
|
||||
callback(vcpu, is_per_vcpu, cb_data);
|
||||
if (callback)
|
||||
callback(vcpu, is_per_vcpu, cb_data);
|
||||
}
|
||||
}
|
||||
|
||||
static void ffa_notification_info_get(void)
|
||||
|
|
@ -899,7 +976,7 @@ static void ffa_notification_info_get(void)
|
|||
}, &ret);
|
||||
|
||||
if (ret.a0 != FFA_FN_NATIVE(SUCCESS) && ret.a0 != FFA_SUCCESS) {
|
||||
if (ret.a2 != FFA_RET_NO_DATA)
|
||||
if ((s32)ret.a2 != FFA_RET_NO_DATA)
|
||||
pr_err("Notification Info fetch failed: 0x%lx (0x%lx)",
|
||||
ret.a0, ret.a2);
|
||||
return;
|
||||
|
|
@ -935,7 +1012,7 @@ static void ffa_notification_info_get(void)
|
|||
}
|
||||
|
||||
/* Per vCPU Notification */
|
||||
for (idx = 0; idx < ids_count[list]; idx++) {
|
||||
for (idx = 1; idx < ids_count[list]; idx++) {
|
||||
if (ids_processed >= max_ids - 1)
|
||||
break;
|
||||
|
||||
|
|
@ -1015,17 +1092,17 @@ static int ffa_sync_send_receive(struct ffa_device *dev,
|
|||
|
||||
static int ffa_indirect_msg_send(struct ffa_device *dev, void *buf, size_t sz)
|
||||
{
|
||||
return ffa_msg_send2(drv_info->vm_id, dev->vm_id, buf, sz);
|
||||
return ffa_msg_send2(dev, drv_info->vm_id, buf, sz);
|
||||
}
|
||||
|
||||
static int ffa_sync_send_receive2(struct ffa_device *dev, const uuid_t *uuid,
|
||||
static int ffa_sync_send_receive2(struct ffa_device *dev,
|
||||
struct ffa_send_direct_data2 *data)
|
||||
{
|
||||
if (!drv_info->msg_direct_req2_supp)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return ffa_msg_send_direct_req2(drv_info->vm_id, dev->vm_id,
|
||||
uuid, data);
|
||||
&dev->uuid, data);
|
||||
}
|
||||
|
||||
static int ffa_memory_share(struct ffa_mem_ops_args *args)
|
||||
|
|
@ -1051,35 +1128,39 @@ static int ffa_memory_lend(struct ffa_mem_ops_args *args)
|
|||
return ffa_memory_ops(FFA_MEM_LEND, args);
|
||||
}
|
||||
|
||||
#define FFA_SECURE_PARTITION_ID_FLAG BIT(15)
|
||||
|
||||
#define ffa_notifications_disabled() (!drv_info->notif_enabled)
|
||||
|
||||
enum notify_type {
|
||||
NON_SECURE_VM,
|
||||
SECURE_PARTITION,
|
||||
FRAMEWORK,
|
||||
};
|
||||
|
||||
struct notifier_cb_info {
|
||||
struct hlist_node hnode;
|
||||
struct ffa_device *dev;
|
||||
ffa_fwk_notifier_cb fwk_cb;
|
||||
ffa_notifier_cb cb;
|
||||
void *cb_data;
|
||||
enum notify_type type;
|
||||
};
|
||||
|
||||
static int ffa_sched_recv_cb_update(u16 part_id, ffa_sched_recv_cb callback,
|
||||
void *cb_data, bool is_registration)
|
||||
static int
|
||||
ffa_sched_recv_cb_update(struct ffa_device *dev, ffa_sched_recv_cb callback,
|
||||
void *cb_data, bool is_registration)
|
||||
{
|
||||
struct ffa_dev_part_info *partition;
|
||||
struct ffa_dev_part_info *partition = NULL, *tmp;
|
||||
struct list_head *phead;
|
||||
bool cb_valid;
|
||||
|
||||
if (ffa_notifications_disabled())
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
partition = xa_load(&drv_info->partition_info, part_id);
|
||||
phead = xa_load(&drv_info->partition_info, dev->vm_id);
|
||||
if (!phead) {
|
||||
pr_err("%s: Invalid partition ID 0x%x\n", __func__, dev->vm_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
list_for_each_entry_safe(partition, tmp, phead, node)
|
||||
if (partition->dev == dev)
|
||||
break;
|
||||
|
||||
if (!partition) {
|
||||
pr_err("%s: Invalid partition ID 0x%x\n", __func__, part_id);
|
||||
pr_err("%s: No such partition ID 0x%x\n", __func__, dev->vm_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -1101,12 +1182,12 @@ static int ffa_sched_recv_cb_update(u16 part_id, ffa_sched_recv_cb callback,
|
|||
static int ffa_sched_recv_cb_register(struct ffa_device *dev,
|
||||
ffa_sched_recv_cb cb, void *cb_data)
|
||||
{
|
||||
return ffa_sched_recv_cb_update(dev->vm_id, cb, cb_data, true);
|
||||
return ffa_sched_recv_cb_update(dev, cb, cb_data, true);
|
||||
}
|
||||
|
||||
static int ffa_sched_recv_cb_unregister(struct ffa_device *dev)
|
||||
{
|
||||
return ffa_sched_recv_cb_update(dev->vm_id, NULL, NULL, false);
|
||||
return ffa_sched_recv_cb_update(dev, NULL, NULL, false);
|
||||
}
|
||||
|
||||
static int ffa_notification_bind(u16 dst_id, u64 bitmap, u32 flags)
|
||||
|
|
@ -1119,27 +1200,69 @@ static int ffa_notification_unbind(u16 dst_id, u64 bitmap)
|
|||
return ffa_notification_bind_common(dst_id, bitmap, 0, false);
|
||||
}
|
||||
|
||||
/* Should be called while the notify_lock is taken */
|
||||
static enum notify_type ffa_notify_type_get(u16 vm_id)
|
||||
{
|
||||
if (vm_id & FFA_SECURE_PARTITION_ID_FLAG)
|
||||
return SECURE_PARTITION;
|
||||
else
|
||||
return NON_SECURE_VM;
|
||||
}
|
||||
|
||||
/* notifier_hnode_get* should be called with notify_lock held */
|
||||
static struct notifier_cb_info *
|
||||
notifier_hash_node_get(u16 notify_id, enum notify_type type)
|
||||
notifier_hnode_get_by_vmid(u16 notify_id, int vmid)
|
||||
{
|
||||
struct notifier_cb_info *node;
|
||||
|
||||
hash_for_each_possible(drv_info->notifier_hash, node, hnode, notify_id)
|
||||
if (type == node->type)
|
||||
if (node->fwk_cb && vmid == node->dev->vm_id)
|
||||
return node;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct notifier_cb_info *
|
||||
notifier_hnode_get_by_vmid_uuid(u16 notify_id, int vmid, const uuid_t *uuid)
|
||||
{
|
||||
struct notifier_cb_info *node;
|
||||
|
||||
if (uuid_is_null(uuid))
|
||||
return notifier_hnode_get_by_vmid(notify_id, vmid);
|
||||
|
||||
hash_for_each_possible(drv_info->notifier_hash, node, hnode, notify_id)
|
||||
if (node->fwk_cb && vmid == node->dev->vm_id &&
|
||||
uuid_equal(&node->dev->uuid, uuid))
|
||||
return node;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct notifier_cb_info *
|
||||
notifier_hnode_get_by_type(u16 notify_id, enum notify_type type)
|
||||
{
|
||||
struct notifier_cb_info *node;
|
||||
|
||||
hash_for_each_possible(drv_info->notifier_hash, node, hnode, notify_id)
|
||||
if (node->cb && type == ffa_notify_type_get(node->dev->vm_id))
|
||||
return node;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
update_notifier_cb(int notify_id, enum notify_type type, ffa_notifier_cb cb,
|
||||
void *cb_data, bool is_registration)
|
||||
update_notifier_cb(struct ffa_device *dev, int notify_id, void *cb,
|
||||
void *cb_data, bool is_registration, bool is_framework)
|
||||
{
|
||||
struct notifier_cb_info *cb_info = NULL;
|
||||
enum notify_type type = ffa_notify_type_get(dev->vm_id);
|
||||
bool cb_found;
|
||||
|
||||
cb_info = notifier_hash_node_get(notify_id, type);
|
||||
if (is_framework)
|
||||
cb_info = notifier_hnode_get_by_vmid_uuid(notify_id, dev->vm_id,
|
||||
&dev->uuid);
|
||||
else
|
||||
cb_info = notifier_hnode_get_by_type(notify_id, type);
|
||||
|
||||
cb_found = !!cb_info;
|
||||
|
||||
if (!(is_registration ^ cb_found))
|
||||
|
|
@ -1150,9 +1273,12 @@ update_notifier_cb(int notify_id, enum notify_type type, ffa_notifier_cb cb,
|
|||
if (!cb_info)
|
||||
return -ENOMEM;
|
||||
|
||||
cb_info->type = type;
|
||||
cb_info->cb = cb;
|
||||
cb_info->dev = dev;
|
||||
cb_info->cb_data = cb_data;
|
||||
if (is_framework)
|
||||
cb_info->fwk_cb = cb;
|
||||
else
|
||||
cb_info->cb = cb;
|
||||
|
||||
hash_add(drv_info->notifier_hash, &cb_info->hnode, notify_id);
|
||||
} else {
|
||||
|
|
@ -1162,18 +1288,10 @@ update_notifier_cb(int notify_id, enum notify_type type, ffa_notifier_cb cb,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static enum notify_type ffa_notify_type_get(u16 vm_id)
|
||||
{
|
||||
if (vm_id & FFA_SECURE_PARTITION_ID_FLAG)
|
||||
return SECURE_PARTITION;
|
||||
else
|
||||
return NON_SECURE_VM;
|
||||
}
|
||||
|
||||
static int ffa_notify_relinquish(struct ffa_device *dev, int notify_id)
|
||||
static int __ffa_notify_relinquish(struct ffa_device *dev, int notify_id,
|
||||
bool is_framework)
|
||||
{
|
||||
int rc;
|
||||
enum notify_type type = ffa_notify_type_get(dev->vm_id);
|
||||
|
||||
if (ffa_notifications_disabled())
|
||||
return -EOPNOTSUPP;
|
||||
|
|
@ -1183,53 +1301,83 @@ static int ffa_notify_relinquish(struct ffa_device *dev, int notify_id)
|
|||
|
||||
mutex_lock(&drv_info->notify_lock);
|
||||
|
||||
rc = update_notifier_cb(notify_id, type, NULL, NULL, false);
|
||||
rc = update_notifier_cb(dev, notify_id, NULL, NULL, false,
|
||||
is_framework);
|
||||
if (rc) {
|
||||
pr_err("Could not unregister notification callback\n");
|
||||
mutex_unlock(&drv_info->notify_lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = ffa_notification_unbind(dev->vm_id, BIT(notify_id));
|
||||
if (!is_framework)
|
||||
rc = ffa_notification_unbind(dev->vm_id, BIT(notify_id));
|
||||
|
||||
mutex_unlock(&drv_info->notify_lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ffa_notify_relinquish(struct ffa_device *dev, int notify_id)
|
||||
{
|
||||
return __ffa_notify_relinquish(dev, notify_id, false);
|
||||
}
|
||||
|
||||
static int ffa_fwk_notify_relinquish(struct ffa_device *dev, int notify_id)
|
||||
{
|
||||
return __ffa_notify_relinquish(dev, notify_id, true);
|
||||
}
|
||||
|
||||
static int __ffa_notify_request(struct ffa_device *dev, bool is_per_vcpu,
|
||||
void *cb, void *cb_data,
|
||||
int notify_id, bool is_framework)
|
||||
{
|
||||
int rc;
|
||||
u32 flags = 0;
|
||||
|
||||
if (ffa_notifications_disabled())
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (notify_id >= FFA_MAX_NOTIFICATIONS)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&drv_info->notify_lock);
|
||||
|
||||
if (!is_framework) {
|
||||
if (is_per_vcpu)
|
||||
flags = PER_VCPU_NOTIFICATION_FLAG;
|
||||
|
||||
rc = ffa_notification_bind(dev->vm_id, BIT(notify_id), flags);
|
||||
if (rc) {
|
||||
mutex_unlock(&drv_info->notify_lock);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
rc = update_notifier_cb(dev, notify_id, cb, cb_data, true,
|
||||
is_framework);
|
||||
if (rc) {
|
||||
pr_err("Failed to register callback for %d - %d\n",
|
||||
notify_id, rc);
|
||||
if (!is_framework)
|
||||
ffa_notification_unbind(dev->vm_id, BIT(notify_id));
|
||||
}
|
||||
mutex_unlock(&drv_info->notify_lock);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int ffa_notify_request(struct ffa_device *dev, bool is_per_vcpu,
|
||||
ffa_notifier_cb cb, void *cb_data, int notify_id)
|
||||
{
|
||||
int rc;
|
||||
u32 flags = 0;
|
||||
enum notify_type type = ffa_notify_type_get(dev->vm_id);
|
||||
return __ffa_notify_request(dev, is_per_vcpu, cb, cb_data, notify_id,
|
||||
false);
|
||||
}
|
||||
|
||||
if (ffa_notifications_disabled())
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (notify_id >= FFA_MAX_NOTIFICATIONS)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&drv_info->notify_lock);
|
||||
|
||||
if (is_per_vcpu)
|
||||
flags = PER_VCPU_NOTIFICATION_FLAG;
|
||||
|
||||
rc = ffa_notification_bind(dev->vm_id, BIT(notify_id), flags);
|
||||
if (rc) {
|
||||
mutex_unlock(&drv_info->notify_lock);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = update_notifier_cb(notify_id, type, cb, cb_data, true);
|
||||
if (rc) {
|
||||
pr_err("Failed to register callback for %d - %d\n",
|
||||
notify_id, rc);
|
||||
ffa_notification_unbind(dev->vm_id, BIT(notify_id));
|
||||
}
|
||||
mutex_unlock(&drv_info->notify_lock);
|
||||
|
||||
return rc;
|
||||
static int
|
||||
ffa_fwk_notify_request(struct ffa_device *dev, ffa_fwk_notifier_cb cb,
|
||||
void *cb_data, int notify_id)
|
||||
{
|
||||
return __ffa_notify_request(dev, false, cb, cb_data, notify_id, true);
|
||||
}
|
||||
|
||||
static int ffa_notify_send(struct ffa_device *dev, int notify_id,
|
||||
|
|
@ -1258,7 +1406,7 @@ static void handle_notif_callbacks(u64 bitmap, enum notify_type type)
|
|||
continue;
|
||||
|
||||
mutex_lock(&drv_info->notify_lock);
|
||||
cb_info = notifier_hash_node_get(notify_id, type);
|
||||
cb_info = notifier_hnode_get_by_type(notify_id, type);
|
||||
mutex_unlock(&drv_info->notify_lock);
|
||||
|
||||
if (cb_info && cb_info->cb)
|
||||
|
|
@ -1266,21 +1414,68 @@ static void handle_notif_callbacks(u64 bitmap, enum notify_type type)
|
|||
}
|
||||
}
|
||||
|
||||
static void notif_get_and_handle(void *unused)
|
||||
static void handle_fwk_notif_callbacks(u32 bitmap)
|
||||
{
|
||||
void *buf;
|
||||
uuid_t uuid;
|
||||
int notify_id = 0, target;
|
||||
struct ffa_indirect_msg_hdr *msg;
|
||||
struct notifier_cb_info *cb_info = NULL;
|
||||
|
||||
/* Only one framework notification defined and supported for now */
|
||||
if (!(bitmap & FRAMEWORK_NOTIFY_RX_BUFFER_FULL))
|
||||
return;
|
||||
|
||||
mutex_lock(&drv_info->rx_lock);
|
||||
|
||||
msg = drv_info->rx_buffer;
|
||||
buf = kmemdup((void *)msg + msg->offset, msg->size, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
mutex_unlock(&drv_info->rx_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
target = SENDER_ID(msg->send_recv_id);
|
||||
if (msg->offset >= sizeof(*msg))
|
||||
uuid_copy(&uuid, &msg->uuid);
|
||||
else
|
||||
uuid_copy(&uuid, &uuid_null);
|
||||
|
||||
mutex_unlock(&drv_info->rx_lock);
|
||||
|
||||
ffa_rx_release();
|
||||
|
||||
mutex_lock(&drv_info->notify_lock);
|
||||
cb_info = notifier_hnode_get_by_vmid_uuid(notify_id, target, &uuid);
|
||||
mutex_unlock(&drv_info->notify_lock);
|
||||
|
||||
if (cb_info && cb_info->fwk_cb)
|
||||
cb_info->fwk_cb(notify_id, cb_info->cb_data, buf);
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
static void notif_get_and_handle(void *cb_data)
|
||||
{
|
||||
int rc;
|
||||
struct ffa_notify_bitmaps bitmaps;
|
||||
u32 flags;
|
||||
struct ffa_drv_info *info = cb_data;
|
||||
struct ffa_notify_bitmaps bitmaps = { 0 };
|
||||
|
||||
rc = ffa_notification_get(SECURE_PARTITION_BITMAP |
|
||||
SPM_FRAMEWORK_BITMAP, &bitmaps);
|
||||
if (info->vm_id == 0) /* Non secure physical instance */
|
||||
flags = FFA_BITMAP_SECURE_ENABLE_MASK;
|
||||
else
|
||||
flags = FFA_BITMAP_ALL_ENABLE_MASK;
|
||||
|
||||
rc = ffa_notification_get(flags, &bitmaps);
|
||||
if (rc) {
|
||||
pr_err("Failed to retrieve notifications with %d!\n", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
handle_fwk_notif_callbacks(SPM_FRAMEWORK_BITMAP(bitmaps.arch_map));
|
||||
handle_fwk_notif_callbacks(NS_HYP_FRAMEWORK_BITMAP(bitmaps.arch_map));
|
||||
handle_notif_callbacks(bitmaps.vm_map, NON_SECURE_VM);
|
||||
handle_notif_callbacks(bitmaps.sp_map, SECURE_PARTITION);
|
||||
handle_notif_callbacks(bitmaps.arch_map, FRAMEWORK);
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -1329,6 +1524,8 @@ static const struct ffa_notifier_ops ffa_drv_notifier_ops = {
|
|||
.sched_recv_cb_unregister = ffa_sched_recv_cb_unregister,
|
||||
.notify_request = ffa_notify_request,
|
||||
.notify_relinquish = ffa_notify_relinquish,
|
||||
.fwk_notify_request = ffa_fwk_notify_request,
|
||||
.fwk_notify_relinquish = ffa_fwk_notify_relinquish,
|
||||
.notify_send = ffa_notify_send,
|
||||
};
|
||||
|
||||
|
|
@ -1384,11 +1581,110 @@ static struct notifier_block ffa_bus_nb = {
|
|||
.notifier_call = ffa_bus_notifier,
|
||||
};
|
||||
|
||||
static int ffa_xa_add_partition_info(struct ffa_device *dev)
|
||||
{
|
||||
struct ffa_dev_part_info *info;
|
||||
struct list_head *head, *phead;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
phead = xa_load(&drv_info->partition_info, dev->vm_id);
|
||||
if (phead) {
|
||||
head = phead;
|
||||
list_for_each_entry(info, head, node) {
|
||||
if (info->dev == dev) {
|
||||
pr_err("%s: duplicate dev %p part ID 0x%x\n",
|
||||
__func__, dev, dev->vm_id);
|
||||
return -EEXIST;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info = kzalloc(sizeof(*info), GFP_KERNEL);
|
||||
if (!info)
|
||||
return ret;
|
||||
|
||||
rwlock_init(&info->rw_lock);
|
||||
info->dev = dev;
|
||||
|
||||
if (!phead) {
|
||||
phead = kzalloc(sizeof(*phead), GFP_KERNEL);
|
||||
if (!phead)
|
||||
goto free_out;
|
||||
|
||||
INIT_LIST_HEAD(phead);
|
||||
|
||||
ret = xa_insert(&drv_info->partition_info, dev->vm_id, phead,
|
||||
GFP_KERNEL);
|
||||
if (ret) {
|
||||
pr_err("%s: failed to save part ID 0x%x Ret:%d\n",
|
||||
__func__, dev->vm_id, ret);
|
||||
goto free_out;
|
||||
}
|
||||
}
|
||||
list_add(&info->node, phead);
|
||||
return 0;
|
||||
|
||||
free_out:
|
||||
kfree(phead);
|
||||
kfree(info);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ffa_setup_host_partition(int vm_id)
|
||||
{
|
||||
struct ffa_partition_info buf = { 0 };
|
||||
struct ffa_device *ffa_dev;
|
||||
int ret;
|
||||
|
||||
buf.id = vm_id;
|
||||
ffa_dev = ffa_device_register(&buf, &ffa_drv_ops);
|
||||
if (!ffa_dev) {
|
||||
pr_err("%s: failed to register host partition ID 0x%x\n",
|
||||
__func__, vm_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = ffa_xa_add_partition_info(ffa_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (ffa_notifications_disabled())
|
||||
return 0;
|
||||
|
||||
ret = ffa_sched_recv_cb_update(ffa_dev, ffa_self_notif_handle,
|
||||
drv_info, true);
|
||||
if (ret)
|
||||
pr_info("Failed to register driver sched callback %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ffa_partitions_cleanup(void)
|
||||
{
|
||||
struct list_head *phead;
|
||||
unsigned long idx;
|
||||
|
||||
/* Clean up/free all registered devices */
|
||||
ffa_devices_unregister();
|
||||
|
||||
xa_for_each(&drv_info->partition_info, idx, phead) {
|
||||
struct ffa_dev_part_info *info, *tmp;
|
||||
|
||||
xa_erase(&drv_info->partition_info, idx);
|
||||
list_for_each_entry_safe(info, tmp, phead, node) {
|
||||
list_del(&info->node);
|
||||
kfree(info);
|
||||
}
|
||||
kfree(phead);
|
||||
}
|
||||
|
||||
xa_destroy(&drv_info->partition_info);
|
||||
}
|
||||
|
||||
static int ffa_setup_partitions(void)
|
||||
{
|
||||
int count, idx, ret;
|
||||
struct ffa_device *ffa_dev;
|
||||
struct ffa_dev_part_info *info;
|
||||
struct ffa_partition_info *pbuf, *tpbuf;
|
||||
|
||||
if (drv_info->version == FFA_VERSION_1_0) {
|
||||
|
|
@ -1422,59 +1718,30 @@ static int ffa_setup_partitions(void)
|
|||
!(tpbuf->properties & FFA_PARTITION_AARCH64_EXEC))
|
||||
ffa_mode_32bit_set(ffa_dev);
|
||||
|
||||
info = kzalloc(sizeof(*info), GFP_KERNEL);
|
||||
if (!info) {
|
||||
if (ffa_xa_add_partition_info(ffa_dev)) {
|
||||
ffa_device_unregister(ffa_dev);
|
||||
continue;
|
||||
}
|
||||
rwlock_init(&info->rw_lock);
|
||||
ret = xa_insert(&drv_info->partition_info, tpbuf->id,
|
||||
info, GFP_KERNEL);
|
||||
if (ret) {
|
||||
pr_err("%s: failed to save partition ID 0x%x - ret:%d\n",
|
||||
__func__, tpbuf->id, ret);
|
||||
ffa_device_unregister(ffa_dev);
|
||||
kfree(info);
|
||||
}
|
||||
}
|
||||
|
||||
kfree(pbuf);
|
||||
|
||||
/* Allocate for the host */
|
||||
info = kzalloc(sizeof(*info), GFP_KERNEL);
|
||||
if (!info) {
|
||||
/* Already registered devices are freed on bus_exit */
|
||||
ffa_partitions_cleanup();
|
||||
return -ENOMEM;
|
||||
}
|
||||
/*
|
||||
* Check if the host is already added as part of partition info
|
||||
* No multiple UUID possible for the host, so just checking if
|
||||
* there is an entry will suffice
|
||||
*/
|
||||
if (xa_load(&drv_info->partition_info, drv_info->vm_id))
|
||||
return 0;
|
||||
|
||||
rwlock_init(&info->rw_lock);
|
||||
ret = xa_insert(&drv_info->partition_info, drv_info->vm_id,
|
||||
info, GFP_KERNEL);
|
||||
if (ret) {
|
||||
pr_err("%s: failed to save Host partition ID 0x%x - ret:%d. Abort.\n",
|
||||
__func__, drv_info->vm_id, ret);
|
||||
kfree(info);
|
||||
/* Already registered devices are freed on bus_exit */
|
||||
/* Allocate for the host */
|
||||
ret = ffa_setup_host_partition(drv_info->vm_id);
|
||||
if (ret)
|
||||
ffa_partitions_cleanup();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ffa_partitions_cleanup(void)
|
||||
{
|
||||
struct ffa_dev_part_info *info;
|
||||
unsigned long idx;
|
||||
|
||||
xa_for_each(&drv_info->partition_info, idx, info) {
|
||||
xa_erase(&drv_info->partition_info, idx);
|
||||
kfree(info);
|
||||
}
|
||||
|
||||
xa_destroy(&drv_info->partition_info);
|
||||
}
|
||||
|
||||
/* FFA FEATURE IDs */
|
||||
#define FFA_FEAT_NOTIFICATION_PENDING_INT (1)
|
||||
#define FFA_FEAT_SCHEDULE_RECEIVER_INT (2)
|
||||
|
|
@ -1777,19 +2044,10 @@ static int __init ffa_init(void)
|
|||
ffa_notifications_setup();
|
||||
|
||||
ret = ffa_setup_partitions();
|
||||
if (ret) {
|
||||
pr_err("failed to setup partitions\n");
|
||||
goto cleanup_notifs;
|
||||
}
|
||||
if (!ret)
|
||||
return ret;
|
||||
|
||||
ret = ffa_sched_recv_cb_update(drv_info->vm_id, ffa_self_notif_handle,
|
||||
drv_info, true);
|
||||
if (ret)
|
||||
pr_info("Failed to register driver sched callback %d\n", ret);
|
||||
|
||||
return 0;
|
||||
|
||||
cleanup_notifs:
|
||||
pr_err("failed to setup partitions\n");
|
||||
ffa_notifications_cleanup();
|
||||
free_pages:
|
||||
if (drv_info->tx_buffer)
|
||||
|
|
|
|||
|
|
@ -112,6 +112,7 @@
|
|||
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)
|
||||
#define FFA_VERSION_1_2 FFA_PACK_VERSION_INFO(1, 2)
|
||||
|
||||
/**
|
||||
* FF-A specification mentions explicitly about '4K pages'. This should
|
||||
|
|
@ -176,6 +177,7 @@ void ffa_device_unregister(struct ffa_device *ffa_dev);
|
|||
int ffa_driver_register(struct ffa_driver *driver, struct module *owner,
|
||||
const char *mod_name);
|
||||
void ffa_driver_unregister(struct ffa_driver *driver);
|
||||
void ffa_devices_unregister(void);
|
||||
bool ffa_device_is_valid(struct ffa_device *ffa_dev);
|
||||
|
||||
#else
|
||||
|
|
@ -188,6 +190,8 @@ ffa_device_register(const struct ffa_partition_info *part_info,
|
|||
|
||||
static inline void ffa_device_unregister(struct ffa_device *dev) {}
|
||||
|
||||
static inline void ffa_devices_unregister(void) {}
|
||||
|
||||
static inline int
|
||||
ffa_driver_register(struct ffa_driver *driver, struct module *owner,
|
||||
const char *mod_name)
|
||||
|
|
@ -237,8 +241,12 @@ struct ffa_partition_info {
|
|||
#define FFA_PARTITION_NOTIFICATION_RECV BIT(3)
|
||||
/* partition runs in the AArch64 execution state. */
|
||||
#define FFA_PARTITION_AARCH64_EXEC BIT(8)
|
||||
/* partition supports receipt of direct request2 */
|
||||
#define FFA_PARTITION_DIRECT_REQ2_RECV BIT(9)
|
||||
/* partition can send direct request2. */
|
||||
#define FFA_PARTITION_DIRECT_REQ2_SEND BIT(10)
|
||||
u32 properties;
|
||||
u32 uuid[4];
|
||||
uuid_t uuid;
|
||||
};
|
||||
|
||||
static inline
|
||||
|
|
@ -256,6 +264,10 @@ bool ffa_partition_check_property(struct ffa_device *dev, u32 property)
|
|||
#define ffa_partition_supports_direct_recv(dev) \
|
||||
ffa_partition_check_property(dev, FFA_PARTITION_DIRECT_RECV)
|
||||
|
||||
#define ffa_partition_supports_direct_req2_recv(dev) \
|
||||
(ffa_partition_check_property(dev, FFA_PARTITION_DIRECT_REQ2_RECV) && \
|
||||
!dev->mode_32bit)
|
||||
|
||||
/* For use with FFA_MSG_SEND_DIRECT_{REQ,RESP} which pass data via registers */
|
||||
struct ffa_send_direct_data {
|
||||
unsigned long data0; /* w3/x3 */
|
||||
|
|
@ -271,6 +283,7 @@ struct ffa_indirect_msg_hdr {
|
|||
u32 offset;
|
||||
u32 send_recv_id;
|
||||
u32 size;
|
||||
uuid_t uuid;
|
||||
};
|
||||
|
||||
/* For use with FFA_MSG_SEND_DIRECT_{REQ,RESP}2 which pass data via registers */
|
||||
|
|
@ -439,7 +452,7 @@ struct ffa_msg_ops {
|
|||
int (*sync_send_receive)(struct ffa_device *dev,
|
||||
struct ffa_send_direct_data *data);
|
||||
int (*indirect_send)(struct ffa_device *dev, void *buf, size_t sz);
|
||||
int (*sync_send_receive2)(struct ffa_device *dev, const uuid_t *uuid,
|
||||
int (*sync_send_receive2)(struct ffa_device *dev,
|
||||
struct ffa_send_direct_data2 *data);
|
||||
};
|
||||
|
||||
|
|
@ -455,6 +468,7 @@ struct ffa_cpu_ops {
|
|||
|
||||
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);
|
||||
typedef void (*ffa_fwk_notifier_cb)(int notify_id, void *cb_data, void *buf);
|
||||
|
||||
struct ffa_notifier_ops {
|
||||
int (*sched_recv_cb_register)(struct ffa_device *dev,
|
||||
|
|
@ -463,6 +477,10 @@ struct ffa_notifier_ops {
|
|||
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 (*fwk_notify_request)(struct ffa_device *dev,
|
||||
ffa_fwk_notifier_cb cb, void *cb_data,
|
||||
int notify_id);
|
||||
int (*fwk_notify_relinquish)(struct ffa_device *dev, int notify_id);
|
||||
int (*notify_send)(struct ffa_device *dev, int notify_id, bool per_vcpu,
|
||||
u16 vcpu);
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user