3737#include <linux/slab.h>
3838#include <linux/smp.h>
3939#include <linux/uuid.h>
40+ #include <linux/xarray.h>
4041
4142#include "common.h"
4243
@@ -99,6 +100,8 @@ struct ffa_drv_info {
99100 struct ffa_pcpu_irq __percpu * irq_pcpu ;
100101 struct workqueue_struct * notif_pcpu_wq ;
101102 struct work_struct irq_work ;
103+ struct xarray partition_info ;
104+ unsigned int partition_count ;
102105};
103106
104107static struct ffa_drv_info * drv_info ;
@@ -694,9 +697,26 @@ static int ffa_notification_get(u32 flags, struct ffa_notify_bitmaps *notify)
694697 return 0 ;
695698}
696699
697- static void __do_sched_recv_cb (u16 partition_id , u16 vcpu , bool is_per_vcpu )
700+ struct ffa_dev_part_info {
701+ ffa_sched_recv_cb callback ;
702+ void * cb_data ;
703+ rwlock_t rw_lock ;
704+ };
705+
706+ static void __do_sched_recv_cb (u16 part_id , u16 vcpu , bool is_per_vcpu )
698707{
699- pr_err ("Callback for partition 0x%x failed.\n" , partition_id );
708+ struct ffa_dev_part_info * partition ;
709+ ffa_sched_recv_cb callback ;
710+ void * cb_data ;
711+
712+ partition = xa_load (& drv_info -> partition_info , part_id );
713+ read_lock (& partition -> rw_lock );
714+ callback = partition -> callback ;
715+ cb_data = partition -> cb_data ;
716+ read_unlock (& partition -> rw_lock );
717+
718+ if (callback )
719+ callback (vcpu , is_per_vcpu , cb_data );
700720}
701721
702722static void ffa_notification_info_get (void )
@@ -845,6 +865,39 @@ static int ffa_memory_lend(struct ffa_mem_ops_args *args)
845865 return ffa_memory_ops (FFA_MEM_LEND , args );
846866}
847867
868+ static int ffa_sched_recv_cb_update (u16 part_id , ffa_sched_recv_cb callback ,
869+ void * cb_data , bool is_registration )
870+ {
871+ struct ffa_dev_part_info * partition ;
872+ bool cb_valid ;
873+
874+ partition = xa_load (& drv_info -> partition_info , part_id );
875+ write_lock (& partition -> rw_lock );
876+
877+ cb_valid = !!partition -> callback ;
878+ if (!(is_registration ^ cb_valid )) {
879+ write_unlock (& partition -> rw_lock );
880+ return - EINVAL ;
881+ }
882+
883+ partition -> callback = callback ;
884+ partition -> cb_data = cb_data ;
885+
886+ write_unlock (& partition -> rw_lock );
887+ return 0 ;
888+ }
889+
890+ static int ffa_sched_recv_cb_register (struct ffa_device * dev ,
891+ ffa_sched_recv_cb cb , void * cb_data )
892+ {
893+ return ffa_sched_recv_cb_update (dev -> vm_id , cb , cb_data , true);
894+ }
895+
896+ static int ffa_sched_recv_cb_unregister (struct ffa_device * dev )
897+ {
898+ return ffa_sched_recv_cb_update (dev -> vm_id , NULL , NULL , false);
899+ }
900+
848901static const struct ffa_info_ops ffa_drv_info_ops = {
849902 .api_version_get = ffa_api_version_get ,
850903 .partition_info_get = ffa_partition_info_get ,
@@ -865,11 +918,17 @@ static const struct ffa_cpu_ops ffa_drv_cpu_ops = {
865918 .run = ffa_run ,
866919};
867920
921+ static const struct ffa_notifier_ops ffa_drv_notifier_ops = {
922+ .sched_recv_cb_register = ffa_sched_recv_cb_register ,
923+ .sched_recv_cb_unregister = ffa_sched_recv_cb_unregister ,
924+ };
925+
868926static const struct ffa_ops ffa_drv_ops = {
869927 .info_ops = & ffa_drv_info_ops ,
870928 .msg_ops = & ffa_drv_msg_ops ,
871929 .mem_ops = & ffa_drv_mem_ops ,
872930 .cpu_ops = & ffa_drv_cpu_ops ,
931+ .notifier_ops = & ffa_drv_notifier_ops ,
873932};
874933
875934void ffa_device_match_uuid (struct ffa_device * ffa_dev , const uuid_t * uuid )
@@ -900,6 +959,7 @@ static void ffa_setup_partitions(void)
900959 int count , idx ;
901960 uuid_t uuid ;
902961 struct ffa_device * ffa_dev ;
962+ struct ffa_dev_part_info * info ;
903963 struct ffa_partition_info * pbuf , * tpbuf ;
904964
905965 count = ffa_partition_probe (& uuid_null , & pbuf );
@@ -908,6 +968,7 @@ static void ffa_setup_partitions(void)
908968 return ;
909969 }
910970
971+ xa_init (& drv_info -> partition_info );
911972 for (idx = 0 , tpbuf = pbuf ; idx < count ; idx ++ , tpbuf ++ ) {
912973 import_uuid (& uuid , (u8 * )tpbuf -> uuid );
913974
@@ -927,10 +988,42 @@ static void ffa_setup_partitions(void)
927988 if (drv_info -> version > FFA_VERSION_1_0 &&
928989 !(tpbuf -> properties & FFA_PARTITION_AARCH64_EXEC ))
929990 ffa_mode_32bit_set (ffa_dev );
991+
992+ info = kzalloc (sizeof (* info ), GFP_KERNEL );
993+ if (!info ) {
994+ ffa_device_unregister (ffa_dev );
995+ continue ;
996+ }
997+ xa_store (& drv_info -> partition_info , tpbuf -> id , info , GFP_KERNEL );
930998 }
999+ drv_info -> partition_count = count ;
1000+
9311001 kfree (pbuf );
9321002}
9331003
1004+ static void ffa_partitions_cleanup (void )
1005+ {
1006+ struct ffa_dev_part_info * * info ;
1007+ int idx , count = drv_info -> partition_count ;
1008+
1009+ if (!count )
1010+ return ;
1011+
1012+ info = kcalloc (count , sizeof (* * info ), GFP_KERNEL );
1013+ if (!info )
1014+ return ;
1015+
1016+ xa_extract (& drv_info -> partition_info , (void * * )info , 0 , VM_ID_MASK ,
1017+ count , XA_PRESENT );
1018+
1019+ for (idx = 0 ; idx < count ; idx ++ )
1020+ kfree (info [idx ]);
1021+ kfree (info );
1022+
1023+ drv_info -> partition_count = 0 ;
1024+ xa_destroy (& drv_info -> partition_info );
1025+ }
1026+
9341027/* FFA FEATURE IDs */
9351028#define FFA_FEAT_NOTIFICATION_PENDING_INT (1)
9361029#define FFA_FEAT_SCHEDULE_RECEIVER_INT (2)
@@ -1164,9 +1257,11 @@ static int __init ffa_init(void)
11641257
11651258 ret = ffa_notifications_setup ();
11661259 if (ret )
1167- goto free_pages ;
1260+ goto partitions_cleanup ;
11681261
11691262 return 0 ;
1263+ partitions_cleanup :
1264+ ffa_partitions_cleanup ();
11701265free_pages :
11711266 if (drv_info -> tx_buffer )
11721267 free_pages_exact (drv_info -> tx_buffer , RXTX_BUFFER_SIZE );
@@ -1182,9 +1277,11 @@ subsys_initcall(ffa_init);
11821277static void __exit ffa_exit (void )
11831278{
11841279 ffa_notifications_cleanup ();
1280+ ffa_partitions_cleanup ();
11851281 ffa_rxtx_unmap (drv_info -> vm_id );
11861282 free_pages_exact (drv_info -> tx_buffer , RXTX_BUFFER_SIZE );
11871283 free_pages_exact (drv_info -> rx_buffer , RXTX_BUFFER_SIZE );
1284+ xa_destroy (& drv_info -> partition_info );
11881285 kfree (drv_info );
11891286 arm_ffa_bus_exit ();
11901287}
0 commit comments