@@ -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+
347380static 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+
873911static 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
11401185static const struct ffa_info_ops ffa_drv_info_ops = {
@@ -1145,6 +1190,7 @@ static const struct ffa_info_ops ffa_drv_info_ops = {
11451190static 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
11501196static 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
13581424static 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
13641433static 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)
14281521static 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
14401536static 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
0 commit comments