Skip to content

Commit 93f9f5a

Browse files
committed
Merge tag 'ffa-updates-6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux into soc/drivers
Arm FF-A updates for v6.10 1. Support for handling notification pending interrupt(NPI) The FF-A uses the notification pending interrupt to inform the receiver that it has a pending notification. This is a virtual interrupt and is used by the following type of receivers: - A guest/VM running under a hypervisor(normal world usecase) - An S-EL1 SP running under a S-EL2 SPMC(secure world only usecase) Also, when the FF-A driver is running inside a guest VM under an hypervisor, the driver/guest VM doesn't have the permission/capability to request the creation of notification bitmaps. For a VM, the hypervisor reserves memory for its VM and hypervisor framework notification bitmaps and the SPMC reserves memory for its SP and SPMC framework notification bitmaps before the hypervisor initializes it. These changes include skipping of creation of notification bitmaps, some refactoring around schedule receiver interrupt(SRI) handling and addition of support for NPI. 2. Support for FF-A indirect messaging The FFA_MSG_SEND2 can be used to transmit a partition message from the Tx buffer of the sender(the driver in this case) endpoint to the Rx buffer of the receiver endpoint and inform the scheduler that the receiver endpoint must be run. Apart from these two main features, there is an optimisation to avoid queuing of a work when already running on the worker queue. * tag 'ffa-updates-6.10' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux: firmware: arm_ffa: Avoid queuing work when running on the worker queue firmware: arm_ffa: Fix memory corruption in ffa_msg_send2() firmware: arm_ffa: Add support for FFA_MSG_SEND2 firmware: arm_ffa: Stash the partition properties for query purposes firmware: arm_ffa: Fix kernel warning about incorrect SRI/NPI firmware: arm_ffa: Add support for handling notification pending interrupt(NPI) firmware: arm_ffa: Refactor SRI handling in prepartion to add NPI support firmware: arm_ffa: Skip creation of the notification bitmaps Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Arnd Bergmann <[email protected]>
2 parents 21cbc10 + 3a3e2b8 commit 93f9f5a

File tree

2 files changed

+169
-45
lines changed

2 files changed

+169
-45
lines changed

drivers/firmware/arm_ffa/driver.c

Lines changed: 142 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -101,11 +101,12 @@ struct ffa_drv_info {
101101
bool bitmap_created;
102102
bool notif_enabled;
103103
unsigned int sched_recv_irq;
104+
unsigned int notif_pend_irq;
104105
unsigned int cpuhp_state;
105106
struct ffa_pcpu_irq __percpu *irq_pcpu;
106107
struct workqueue_struct *notif_pcpu_wq;
107108
struct work_struct notif_pcpu_work;
108-
struct work_struct irq_work;
109+
struct work_struct sched_recv_irq_work;
109110
struct xarray partition_info;
110111
DECLARE_HASHTABLE(notifier_hash, ilog2(FFA_MAX_NOTIFICATIONS));
111112
struct mutex notify_lock; /* lock to protect notifier hashtable */
@@ -344,6 +345,38 @@ static int ffa_msg_send_direct_req(u16 src_id, u16 dst_id, bool mode_32bit,
344345
return -EINVAL;
345346
}
346347

348+
static int ffa_msg_send2(u16 src_id, u16 dst_id, void *buf, size_t sz)
349+
{
350+
u32 src_dst_ids = PACK_TARGET_INFO(src_id, dst_id);
351+
struct ffa_indirect_msg_hdr *msg;
352+
ffa_value_t ret;
353+
int retval = 0;
354+
355+
if (sz > (RXTX_BUFFER_SIZE - sizeof(*msg)))
356+
return -ERANGE;
357+
358+
mutex_lock(&drv_info->tx_lock);
359+
360+
msg = drv_info->tx_buffer;
361+
msg->flags = 0;
362+
msg->res0 = 0;
363+
msg->offset = sizeof(*msg);
364+
msg->send_recv_id = src_dst_ids;
365+
msg->size = sz;
366+
memcpy((u8 *)msg + msg->offset, buf, sz);
367+
368+
/* flags = 0, sender VMID = 0 works for both physical/virtual NS */
369+
invoke_ffa_fn((ffa_value_t){
370+
.a0 = FFA_MSG_SEND2, .a1 = 0, .a2 = 0
371+
}, &ret);
372+
373+
if (ret.a0 == FFA_ERROR)
374+
retval = ffa_to_linux_errno((int)ret.a2);
375+
376+
mutex_unlock(&drv_info->tx_lock);
377+
return retval;
378+
}
379+
347380
static int ffa_mem_first_frag(u32 func_id, phys_addr_t buf, u32 buf_sz,
348381
u32 frag_len, u32 len, u64 *handle)
349382
{
@@ -870,6 +903,11 @@ static int ffa_sync_send_receive(struct ffa_device *dev,
870903
dev->mode_32bit, data);
871904
}
872905

906+
static int ffa_indirect_msg_send(struct ffa_device *dev, void *buf, size_t sz)
907+
{
908+
return ffa_msg_send2(drv_info->vm_id, dev->vm_id, buf, sz);
909+
}
910+
873911
static int ffa_memory_share(struct ffa_mem_ops_args *args)
874912
{
875913
if (drv_info->mem_ops_native)
@@ -1108,7 +1146,7 @@ static void handle_notif_callbacks(u64 bitmap, enum notify_type type)
11081146
}
11091147
}
11101148

1111-
static void notif_pcpu_irq_work_fn(struct work_struct *work)
1149+
static void notif_get_and_handle(void *unused)
11121150
{
11131151
int rc;
11141152
struct ffa_notify_bitmaps bitmaps;
@@ -1131,10 +1169,17 @@ ffa_self_notif_handle(u16 vcpu, bool is_per_vcpu, void *cb_data)
11311169
struct ffa_drv_info *info = cb_data;
11321170

11331171
if (!is_per_vcpu)
1134-
notif_pcpu_irq_work_fn(&info->notif_pcpu_work);
1172+
notif_get_and_handle(info);
11351173
else
1136-
queue_work_on(vcpu, info->notif_pcpu_wq,
1137-
&info->notif_pcpu_work);
1174+
smp_call_function_single(vcpu, notif_get_and_handle, info, 0);
1175+
}
1176+
1177+
static void notif_pcpu_irq_work_fn(struct work_struct *work)
1178+
{
1179+
struct ffa_drv_info *info = container_of(work, struct ffa_drv_info,
1180+
notif_pcpu_work);
1181+
1182+
ffa_self_notif_handle(smp_processor_id(), true, info);
11381183
}
11391184

11401185
static const struct ffa_info_ops ffa_drv_info_ops = {
@@ -1145,6 +1190,7 @@ static const struct ffa_info_ops ffa_drv_info_ops = {
11451190
static const struct ffa_msg_ops ffa_drv_msg_ops = {
11461191
.mode_32bit_set = ffa_mode_32bit_set,
11471192
.sync_send_receive = ffa_sync_send_receive,
1193+
.indirect_send = ffa_indirect_msg_send,
11481194
};
11491195

11501196
static const struct ffa_mem_ops ffa_drv_mem_ops = {
@@ -1227,6 +1273,8 @@ static int ffa_setup_partitions(void)
12271273
continue;
12281274
}
12291275

1276+
ffa_dev->properties = tpbuf->properties;
1277+
12301278
if (drv_info->version > FFA_VERSION_1_0 &&
12311279
!(tpbuf->properties & FFA_PARTITION_AARCH64_EXEC))
12321280
ffa_mode_32bit_set(ffa_dev);
@@ -1291,12 +1339,23 @@ static void ffa_partitions_cleanup(void)
12911339
#define FFA_FEAT_SCHEDULE_RECEIVER_INT (2)
12921340
#define FFA_FEAT_MANAGED_EXIT_INT (3)
12931341

1294-
static irqreturn_t irq_handler(int irq, void *irq_data)
1342+
static irqreturn_t ffa_sched_recv_irq_handler(int irq, void *irq_data)
1343+
{
1344+
struct ffa_pcpu_irq *pcpu = irq_data;
1345+
struct ffa_drv_info *info = pcpu->info;
1346+
1347+
queue_work(info->notif_pcpu_wq, &info->sched_recv_irq_work);
1348+
1349+
return IRQ_HANDLED;
1350+
}
1351+
1352+
static irqreturn_t notif_pend_irq_handler(int irq, void *irq_data)
12951353
{
12961354
struct ffa_pcpu_irq *pcpu = irq_data;
12971355
struct ffa_drv_info *info = pcpu->info;
12981356

1299-
queue_work(info->notif_pcpu_wq, &info->irq_work);
1357+
queue_work_on(smp_processor_id(), info->notif_pcpu_wq,
1358+
&info->notif_pcpu_work);
13001359

13011360
return IRQ_HANDLED;
13021361
}
@@ -1306,15 +1365,23 @@ static void ffa_sched_recv_irq_work_fn(struct work_struct *work)
13061365
ffa_notification_info_get();
13071366
}
13081367

1309-
static int ffa_sched_recv_irq_map(void)
1368+
static int ffa_irq_map(u32 id)
13101369
{
1311-
int ret, irq, sr_intid;
1370+
char *err_str;
1371+
int ret, irq, intid;
13121372

1313-
/* The returned sr_intid is assumed to be SGI donated to NS world */
1314-
ret = ffa_features(FFA_FEAT_SCHEDULE_RECEIVER_INT, 0, &sr_intid, NULL);
1373+
if (id == FFA_FEAT_NOTIFICATION_PENDING_INT)
1374+
err_str = "Notification Pending Interrupt";
1375+
else if (id == FFA_FEAT_SCHEDULE_RECEIVER_INT)
1376+
err_str = "Schedule Receiver Interrupt";
1377+
else
1378+
err_str = "Unknown ID";
1379+
1380+
/* The returned intid is assumed to be SGI donated to NS world */
1381+
ret = ffa_features(id, 0, &intid, NULL);
13151382
if (ret < 0) {
13161383
if (ret != -EOPNOTSUPP)
1317-
pr_err("Failed to retrieve scheduler Rx interrupt\n");
1384+
pr_err("Failed to retrieve FF-A %s %u\n", err_str, id);
13181385
return ret;
13191386
}
13201387

@@ -1329,12 +1396,12 @@ static int ffa_sched_recv_irq_map(void)
13291396

13301397
oirq.np = gic;
13311398
oirq.args_count = 1;
1332-
oirq.args[0] = sr_intid;
1399+
oirq.args[0] = intid;
13331400
irq = irq_create_of_mapping(&oirq);
13341401
of_node_put(gic);
13351402
#ifdef CONFIG_ACPI
13361403
} else {
1337-
irq = acpi_register_gsi(NULL, sr_intid, ACPI_EDGE_SENSITIVE,
1404+
irq = acpi_register_gsi(NULL, intid, ACPI_EDGE_SENSITIVE,
13381405
ACPI_ACTIVE_HIGH);
13391406
#endif
13401407
}
@@ -1347,23 +1414,28 @@ static int ffa_sched_recv_irq_map(void)
13471414
return irq;
13481415
}
13491416

1350-
static void ffa_sched_recv_irq_unmap(void)
1417+
static void ffa_irq_unmap(unsigned int irq)
13511418
{
1352-
if (drv_info->sched_recv_irq) {
1353-
irq_dispose_mapping(drv_info->sched_recv_irq);
1354-
drv_info->sched_recv_irq = 0;
1355-
}
1419+
if (!irq)
1420+
return;
1421+
irq_dispose_mapping(irq);
13561422
}
13571423

13581424
static int ffa_cpuhp_pcpu_irq_enable(unsigned int cpu)
13591425
{
1360-
enable_percpu_irq(drv_info->sched_recv_irq, IRQ_TYPE_NONE);
1426+
if (drv_info->sched_recv_irq)
1427+
enable_percpu_irq(drv_info->sched_recv_irq, IRQ_TYPE_NONE);
1428+
if (drv_info->notif_pend_irq)
1429+
enable_percpu_irq(drv_info->notif_pend_irq, IRQ_TYPE_NONE);
13611430
return 0;
13621431
}
13631432

13641433
static int ffa_cpuhp_pcpu_irq_disable(unsigned int cpu)
13651434
{
1366-
disable_percpu_irq(drv_info->sched_recv_irq);
1435+
if (drv_info->sched_recv_irq)
1436+
disable_percpu_irq(drv_info->sched_recv_irq);
1437+
if (drv_info->notif_pend_irq)
1438+
disable_percpu_irq(drv_info->notif_pend_irq);
13671439
return 0;
13681440
}
13691441

@@ -1382,13 +1454,16 @@ static void ffa_uninit_pcpu_irq(void)
13821454
if (drv_info->sched_recv_irq)
13831455
free_percpu_irq(drv_info->sched_recv_irq, drv_info->irq_pcpu);
13841456

1457+
if (drv_info->notif_pend_irq)
1458+
free_percpu_irq(drv_info->notif_pend_irq, drv_info->irq_pcpu);
1459+
13851460
if (drv_info->irq_pcpu) {
13861461
free_percpu(drv_info->irq_pcpu);
13871462
drv_info->irq_pcpu = NULL;
13881463
}
13891464
}
13901465

1391-
static int ffa_init_pcpu_irq(unsigned int irq)
1466+
static int ffa_init_pcpu_irq(void)
13921467
{
13931468
struct ffa_pcpu_irq __percpu *irq_pcpu;
13941469
int ret, cpu;
@@ -1402,13 +1477,31 @@ static int ffa_init_pcpu_irq(unsigned int irq)
14021477

14031478
drv_info->irq_pcpu = irq_pcpu;
14041479

1405-
ret = request_percpu_irq(irq, irq_handler, "ARM-FFA", irq_pcpu);
1406-
if (ret) {
1407-
pr_err("Error registering notification IRQ %d: %d\n", irq, ret);
1408-
return ret;
1480+
if (drv_info->sched_recv_irq) {
1481+
ret = request_percpu_irq(drv_info->sched_recv_irq,
1482+
ffa_sched_recv_irq_handler,
1483+
"ARM-FFA-SRI", irq_pcpu);
1484+
if (ret) {
1485+
pr_err("Error registering percpu SRI nIRQ %d : %d\n",
1486+
drv_info->sched_recv_irq, ret);
1487+
drv_info->sched_recv_irq = 0;
1488+
return ret;
1489+
}
14091490
}
14101491

1411-
INIT_WORK(&drv_info->irq_work, ffa_sched_recv_irq_work_fn);
1492+
if (drv_info->notif_pend_irq) {
1493+
ret = request_percpu_irq(drv_info->notif_pend_irq,
1494+
notif_pend_irq_handler,
1495+
"ARM-FFA-NPI", irq_pcpu);
1496+
if (ret) {
1497+
pr_err("Error registering percpu NPI nIRQ %d : %d\n",
1498+
drv_info->notif_pend_irq, ret);
1499+
drv_info->notif_pend_irq = 0;
1500+
return ret;
1501+
}
1502+
}
1503+
1504+
INIT_WORK(&drv_info->sched_recv_irq_work, ffa_sched_recv_irq_work_fn);
14121505
INIT_WORK(&drv_info->notif_pcpu_work, notif_pcpu_irq_work_fn);
14131506
drv_info->notif_pcpu_wq = create_workqueue("ffa_pcpu_irq_notification");
14141507
if (!drv_info->notif_pcpu_wq)
@@ -1428,7 +1521,10 @@ static int ffa_init_pcpu_irq(unsigned int irq)
14281521
static void ffa_notifications_cleanup(void)
14291522
{
14301523
ffa_uninit_pcpu_irq();
1431-
ffa_sched_recv_irq_unmap();
1524+
ffa_irq_unmap(drv_info->sched_recv_irq);
1525+
drv_info->sched_recv_irq = 0;
1526+
ffa_irq_unmap(drv_info->notif_pend_irq);
1527+
drv_info->notif_pend_irq = 0;
14321528

14331529
if (drv_info->bitmap_created) {
14341530
ffa_notification_bitmap_destroy();
@@ -1439,30 +1535,31 @@ static void ffa_notifications_cleanup(void)
14391535

14401536
static void ffa_notifications_setup(void)
14411537
{
1442-
int ret, irq;
1538+
int ret;
14431539

14441540
ret = ffa_features(FFA_NOTIFICATION_BITMAP_CREATE, 0, NULL, NULL);
1445-
if (ret) {
1446-
pr_info("Notifications not supported, continuing with it ..\n");
1447-
return;
1448-
}
1541+
if (!ret) {
1542+
ret = ffa_notification_bitmap_create();
1543+
if (ret) {
1544+
pr_err("Notification bitmap create error %d\n", ret);
1545+
return;
1546+
}
14491547

1450-
ret = ffa_notification_bitmap_create();
1451-
if (ret) {
1452-
pr_info("Notification bitmap create error %d\n", ret);
1453-
return;
1548+
drv_info->bitmap_created = true;
14541549
}
1455-
drv_info->bitmap_created = true;
14561550

1457-
irq = ffa_sched_recv_irq_map();
1458-
if (irq <= 0) {
1459-
ret = irq;
1460-
goto cleanup;
1461-
}
1551+
ret = ffa_irq_map(FFA_FEAT_SCHEDULE_RECEIVER_INT);
1552+
if (ret > 0)
1553+
drv_info->sched_recv_irq = ret;
1554+
1555+
ret = ffa_irq_map(FFA_FEAT_NOTIFICATION_PENDING_INT);
1556+
if (ret > 0)
1557+
drv_info->notif_pend_irq = ret;
14621558

1463-
drv_info->sched_recv_irq = irq;
1559+
if (!drv_info->sched_recv_irq && !drv_info->notif_pend_irq)
1560+
goto cleanup;
14641561

1465-
ret = ffa_init_pcpu_irq(irq);
1562+
ret = ffa_init_pcpu_irq();
14661563
if (ret)
14671564
goto cleanup;
14681565

include/linux/arm_ffa.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@
126126
/* FFA Bus/Device/Driver related */
127127
struct ffa_device {
128128
u32 id;
129+
u32 properties;
129130
int vm_id;
130131
bool mode_32bit;
131132
uuid_t uuid;
@@ -221,12 +222,29 @@ struct ffa_partition_info {
221222
#define FFA_PARTITION_DIRECT_SEND BIT(1)
222223
/* partition can send and receive indirect messages. */
223224
#define FFA_PARTITION_INDIRECT_MSG BIT(2)
225+
/* partition can receive notifications */
226+
#define FFA_PARTITION_NOTIFICATION_RECV BIT(3)
224227
/* partition runs in the AArch64 execution state. */
225228
#define FFA_PARTITION_AARCH64_EXEC BIT(8)
226229
u32 properties;
227230
u32 uuid[4];
228231
};
229232

233+
static inline
234+
bool ffa_partition_check_property(struct ffa_device *dev, u32 property)
235+
{
236+
return dev->properties & property;
237+
}
238+
239+
#define ffa_partition_supports_notify_recv(dev) \
240+
ffa_partition_check_property(dev, FFA_PARTITION_NOTIFICATION_RECV)
241+
242+
#define ffa_partition_supports_indirect_msg(dev) \
243+
ffa_partition_check_property(dev, FFA_PARTITION_INDIRECT_MSG)
244+
245+
#define ffa_partition_supports_direct_recv(dev) \
246+
ffa_partition_check_property(dev, FFA_PARTITION_DIRECT_RECV)
247+
230248
/* For use with FFA_MSG_SEND_DIRECT_{REQ,RESP} which pass data via registers */
231249
struct ffa_send_direct_data {
232250
unsigned long data0; /* w3/x3 */
@@ -236,6 +254,14 @@ struct ffa_send_direct_data {
236254
unsigned long data4; /* w7/x7 */
237255
};
238256

257+
struct ffa_indirect_msg_hdr {
258+
u32 flags;
259+
u32 res0;
260+
u32 offset;
261+
u32 send_recv_id;
262+
u32 size;
263+
};
264+
239265
struct ffa_mem_region_addr_range {
240266
/* The base IPA of the constituent memory region, aligned to 4 kiB */
241267
u64 address;
@@ -396,6 +422,7 @@ struct ffa_msg_ops {
396422
void (*mode_32bit_set)(struct ffa_device *dev);
397423
int (*sync_send_receive)(struct ffa_device *dev,
398424
struct ffa_send_direct_data *data);
425+
int (*indirect_send)(struct ffa_device *dev, void *buf, size_t sz);
399426
};
400427

401428
struct ffa_mem_ops {

0 commit comments

Comments
 (0)