Skip to content

Commit 0b6f609

Browse files
committed
firmware: arm_ffa: Allow multiple UUIDs per partition to register SRI callback
JIRA: https://issues.redhat.com/browse/RHEL-102691 commit be61da9 Author: Sudeep Holla <sudeep.holla@arm.com> Date: Mon, 17 Feb 2025 15:38:59 +0000 A partition can implement multiple UUIDs and currently we successfully register each UUID service as a FF-A device. However when adding the same partition info to the XArray which tracks the SRI callbacks more than once, it fails. In order to allow multiple UUIDs per partition to register SRI callbacks the partition information stored in the XArray needs to be extended to a listed list. A function to remove the list of partition information in the XArray is not added as there are no users at the time. All the partitions are added at probe/initialisation and removed at cleanup stage. Tested-by: Viresh Kumar <viresh.kumar@linaro.org> Message-Id: <20250217-ffa_updates-v3-18-bd1d9de615e7@arm.com> Signed-off-by: Sudeep Holla <sudeep.holla@arm.com> Signed-off-by: Marcin Juszkiewicz <mjuszkiewicz@redhat.com>
1 parent b98722f commit 0b6f609

File tree

1 file changed

+117
-42
lines changed

1 file changed

+117
-42
lines changed

drivers/firmware/arm_ffa/driver.c

Lines changed: 117 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -925,27 +925,32 @@ struct ffa_dev_part_info {
925925
ffa_sched_recv_cb callback;
926926
void *cb_data;
927927
rwlock_t rw_lock;
928+
struct ffa_device *dev;
929+
struct list_head node;
928930
};
929931

930932
static void __do_sched_recv_cb(u16 part_id, u16 vcpu, bool is_per_vcpu)
931933
{
932-
struct ffa_dev_part_info *partition;
934+
struct ffa_dev_part_info *partition = NULL, *tmp;
933935
ffa_sched_recv_cb callback;
936+
struct list_head *phead;
934937
void *cb_data;
935938

936-
partition = xa_load(&drv_info->partition_info, part_id);
937-
if (!partition) {
939+
phead = xa_load(&drv_info->partition_info, part_id);
940+
if (!phead) {
938941
pr_err("%s: Invalid partition ID 0x%x\n", __func__, part_id);
939942
return;
940943
}
941944

942-
read_lock(&partition->rw_lock);
943-
callback = partition->callback;
944-
cb_data = partition->cb_data;
945-
read_unlock(&partition->rw_lock);
945+
list_for_each_entry_safe(partition, tmp, phead, node) {
946+
read_lock(&partition->rw_lock);
947+
callback = partition->callback;
948+
cb_data = partition->cb_data;
949+
read_unlock(&partition->rw_lock);
946950

947-
if (callback)
948-
callback(vcpu, is_per_vcpu, cb_data);
951+
if (callback)
952+
callback(vcpu, is_per_vcpu, cb_data);
953+
}
949954
}
950955

951956
static void ffa_notification_info_get(void)
@@ -1123,18 +1128,29 @@ struct notifier_cb_info {
11231128
void *cb_data;
11241129
};
11251130

1126-
static int ffa_sched_recv_cb_update(u16 part_id, ffa_sched_recv_cb callback,
1127-
void *cb_data, bool is_registration)
1131+
static int
1132+
ffa_sched_recv_cb_update(struct ffa_device *dev, ffa_sched_recv_cb callback,
1133+
void *cb_data, bool is_registration)
11281134
{
1129-
struct ffa_dev_part_info *partition;
1135+
struct ffa_dev_part_info *partition = NULL, *tmp;
1136+
struct list_head *phead;
11301137
bool cb_valid;
11311138

11321139
if (ffa_notifications_disabled())
11331140
return -EOPNOTSUPP;
11341141

1135-
partition = xa_load(&drv_info->partition_info, part_id);
1142+
phead = xa_load(&drv_info->partition_info, dev->vm_id);
1143+
if (!phead) {
1144+
pr_err("%s: Invalid partition ID 0x%x\n", __func__, dev->vm_id);
1145+
return -EINVAL;
1146+
}
1147+
1148+
list_for_each_entry_safe(partition, tmp, phead, node)
1149+
if (partition->dev == dev)
1150+
break;
1151+
11361152
if (!partition) {
1137-
pr_err("%s: Invalid partition ID 0x%x\n", __func__, part_id);
1153+
pr_err("%s: No such partition ID 0x%x\n", __func__, dev->vm_id);
11381154
return -EINVAL;
11391155
}
11401156

@@ -1156,12 +1172,12 @@ static int ffa_sched_recv_cb_update(u16 part_id, ffa_sched_recv_cb callback,
11561172
static int ffa_sched_recv_cb_register(struct ffa_device *dev,
11571173
ffa_sched_recv_cb cb, void *cb_data)
11581174
{
1159-
return ffa_sched_recv_cb_update(dev->vm_id, cb, cb_data, true);
1175+
return ffa_sched_recv_cb_update(dev, cb, cb_data, true);
11601176
}
11611177

11621178
static int ffa_sched_recv_cb_unregister(struct ffa_device *dev)
11631179
{
1164-
return ffa_sched_recv_cb_update(dev->vm_id, NULL, NULL, false);
1180+
return ffa_sched_recv_cb_update(dev, NULL, NULL, false);
11651181
}
11661182

11671183
static int ffa_notification_bind(u16 dst_id, u64 bitmap, u32 flags)
@@ -1548,37 +1564,101 @@ static struct notifier_block ffa_bus_nb = {
15481564
.notifier_call = ffa_bus_notifier,
15491565
};
15501566

1551-
static int ffa_xa_add_partition_info(int vm_id)
1567+
static int ffa_xa_add_partition_info(struct ffa_device *dev)
15521568
{
15531569
struct ffa_dev_part_info *info;
1554-
int ret;
1570+
struct list_head *head, *phead;
1571+
int ret = -ENOMEM;
1572+
1573+
phead = xa_load(&drv_info->partition_info, dev->vm_id);
1574+
if (phead) {
1575+
head = phead;
1576+
list_for_each_entry(info, head, node) {
1577+
if (info->dev == dev) {
1578+
pr_err("%s: duplicate dev %p part ID 0x%x\n",
1579+
__func__, dev, dev->vm_id);
1580+
return -EEXIST;
1581+
}
1582+
}
1583+
}
15551584

15561585
info = kzalloc(sizeof(*info), GFP_KERNEL);
15571586
if (!info)
1558-
return -ENOMEM;
1587+
return ret;
15591588

15601589
rwlock_init(&info->rw_lock);
1561-
ret = xa_insert(&drv_info->partition_info, vm_id, info, GFP_KERNEL);
1562-
if (ret) {
1563-
pr_err("%s: failed to save partition ID 0x%x - ret:%d. Abort.\n",
1564-
__func__, vm_id, ret);
1565-
kfree(info);
1590+
info->dev = dev;
1591+
1592+
if (!phead) {
1593+
phead = kzalloc(sizeof(*phead), GFP_KERNEL);
1594+
if (!phead)
1595+
goto free_out;
1596+
1597+
INIT_LIST_HEAD(phead);
1598+
1599+
ret = xa_insert(&drv_info->partition_info, dev->vm_id, phead,
1600+
GFP_KERNEL);
1601+
if (ret) {
1602+
pr_err("%s: failed to save part ID 0x%x Ret:%d\n",
1603+
__func__, dev->vm_id, ret);
1604+
goto free_out;
1605+
}
1606+
}
1607+
list_add(&info->node, phead);
1608+
return 0;
1609+
1610+
free_out:
1611+
kfree(phead);
1612+
kfree(info);
1613+
return ret;
1614+
}
1615+
1616+
static int ffa_setup_host_partition(int vm_id)
1617+
{
1618+
struct ffa_partition_info buf = { 0 };
1619+
struct ffa_device *ffa_dev;
1620+
int ret;
1621+
1622+
buf.id = vm_id;
1623+
ffa_dev = ffa_device_register(&buf, &ffa_drv_ops);
1624+
if (!ffa_dev) {
1625+
pr_err("%s: failed to register host partition ID 0x%x\n",
1626+
__func__, vm_id);
1627+
return -EINVAL;
15661628
}
15671629

1630+
ret = ffa_xa_add_partition_info(ffa_dev);
1631+
if (ret)
1632+
return ret;
1633+
1634+
if (ffa_notifications_disabled())
1635+
return 0;
1636+
1637+
ret = ffa_sched_recv_cb_update(ffa_dev, ffa_self_notif_handle,
1638+
drv_info, true);
1639+
if (ret)
1640+
pr_info("Failed to register driver sched callback %d\n", ret);
1641+
15681642
return ret;
15691643
}
15701644

15711645
static void ffa_partitions_cleanup(void)
15721646
{
1573-
struct ffa_dev_part_info *info;
1647+
struct list_head *phead;
15741648
unsigned long idx;
15751649

15761650
/* Clean up/free all registered devices */
15771651
ffa_devices_unregister();
15781652

1579-
xa_for_each(&drv_info->partition_info, idx, info) {
1653+
xa_for_each(&drv_info->partition_info, idx, phead) {
1654+
struct ffa_dev_part_info *info, *tmp;
1655+
15801656
xa_erase(&drv_info->partition_info, idx);
1581-
kfree(info);
1657+
list_for_each_entry_safe(info, tmp, phead, node) {
1658+
list_del(&info->node);
1659+
kfree(info);
1660+
}
1661+
kfree(phead);
15821662
}
15831663

15841664
xa_destroy(&drv_info->partition_info);
@@ -1621,20 +1701,24 @@ static int ffa_setup_partitions(void)
16211701
!(tpbuf->properties & FFA_PARTITION_AARCH64_EXEC))
16221702
ffa_mode_32bit_set(ffa_dev);
16231703

1624-
if (ffa_xa_add_partition_info(ffa_dev->vm_id)) {
1704+
if (ffa_xa_add_partition_info(ffa_dev)) {
16251705
ffa_device_unregister(ffa_dev);
16261706
continue;
16271707
}
16281708
}
16291709

16301710
kfree(pbuf);
16311711

1632-
/* Check if the host is already added as part of partition info */
1712+
/*
1713+
* Check if the host is already added as part of partition info
1714+
* No multiple UUID possible for the host, so just checking if
1715+
* there is an entry will suffice
1716+
*/
16331717
if (xa_load(&drv_info->partition_info, drv_info->vm_id))
16341718
return 0;
16351719

16361720
/* Allocate for the host */
1637-
ret = ffa_xa_add_partition_info(drv_info->vm_id);
1721+
ret = ffa_setup_host_partition(drv_info->vm_id);
16381722
if (ret)
16391723
ffa_partitions_cleanup();
16401724

@@ -1943,19 +2027,10 @@ static int __init ffa_init(void)
19432027
ffa_notifications_setup();
19442028

19452029
ret = ffa_setup_partitions();
1946-
if (ret) {
1947-
pr_err("failed to setup partitions\n");
1948-
goto cleanup_notifs;
1949-
}
1950-
1951-
ret = ffa_sched_recv_cb_update(drv_info->vm_id, ffa_self_notif_handle,
1952-
drv_info, true);
1953-
if (ret)
1954-
pr_info("Failed to register driver sched callback %d\n", ret);
1955-
1956-
return 0;
2030+
if (!ret)
2031+
return ret;
19572032

1958-
cleanup_notifs:
2033+
pr_err("failed to setup partitions\n");
19592034
ffa_notifications_cleanup();
19602035
free_pages:
19612036
if (drv_info->tx_buffer)

0 commit comments

Comments
 (0)