27
27
#include <linux/bitfield.h>
28
28
#include <linux/cpuhotplug.h>
29
29
#include <linux/device.h>
30
+ #include <linux/hashtable.h>
30
31
#include <linux/interrupt.h>
31
32
#include <linux/io.h>
32
33
#include <linux/kernel.h>
33
34
#include <linux/module.h>
34
35
#include <linux/mm.h>
36
+ #include <linux/mutex.h>
35
37
#include <linux/of_irq.h>
36
38
#include <linux/scatterlist.h>
37
39
#include <linux/slab.h>
57
59
*/
58
60
#define RXTX_BUFFER_SIZE SZ_4K
59
61
62
+ #define FFA_MAX_NOTIFICATIONS 64
63
+
60
64
static ffa_fn * invoke_ffa_fn ;
61
65
62
66
static const int ffa_linux_errmap [] = {
@@ -102,6 +106,8 @@ struct ffa_drv_info {
102
106
struct work_struct irq_work ;
103
107
struct xarray partition_info ;
104
108
unsigned int partition_count ;
109
+ DECLARE_HASHTABLE (notifier_hash , ilog2 (FFA_MAX_NOTIFICATIONS ));
110
+ struct mutex notify_lock ; /* lock to protect notifier hashtable */
105
111
};
106
112
107
113
static struct ffa_drv_info * drv_info ;
@@ -626,6 +632,8 @@ static int ffa_notification_bitmap_destroy(void)
626
632
#define MAX_IDS_64 20
627
633
#define MAX_IDS_32 10
628
634
635
+ #define PER_VCPU_NOTIFICATION_FLAG BIT(0)
636
+
629
637
static int ffa_notification_bind_common (u16 dst_id , u64 bitmap ,
630
638
u32 flags , bool is_bind )
631
639
{
@@ -865,6 +873,21 @@ static int ffa_memory_lend(struct ffa_mem_ops_args *args)
865
873
return ffa_memory_ops (FFA_MEM_LEND , args );
866
874
}
867
875
876
+ #define FFA_SECURE_PARTITION_ID_FLAG BIT(15)
877
+
878
+ enum notify_type {
879
+ NON_SECURE_VM ,
880
+ SECURE_PARTITION ,
881
+ FRAMEWORK ,
882
+ };
883
+
884
+ struct notifier_cb_info {
885
+ struct hlist_node hnode ;
886
+ ffa_notifier_cb cb ;
887
+ void * cb_data ;
888
+ enum notify_type type ;
889
+ };
890
+
868
891
static int ffa_sched_recv_cb_update (u16 part_id , ffa_sched_recv_cb callback ,
869
892
void * cb_data , bool is_registration )
870
893
{
@@ -898,6 +921,123 @@ static int ffa_sched_recv_cb_unregister(struct ffa_device *dev)
898
921
return ffa_sched_recv_cb_update (dev -> vm_id , NULL , NULL , false);
899
922
}
900
923
924
+ static int ffa_notification_bind (u16 dst_id , u64 bitmap , u32 flags )
925
+ {
926
+ return ffa_notification_bind_common (dst_id , bitmap , flags , true);
927
+ }
928
+
929
+ static int ffa_notification_unbind (u16 dst_id , u64 bitmap )
930
+ {
931
+ return ffa_notification_bind_common (dst_id , bitmap , 0 , false);
932
+ }
933
+
934
+ /* Should be called while the notify_lock is taken */
935
+ static struct notifier_cb_info *
936
+ notifier_hash_node_get (u16 notify_id , enum notify_type type )
937
+ {
938
+ struct notifier_cb_info * node ;
939
+
940
+ hash_for_each_possible (drv_info -> notifier_hash , node , hnode , notify_id )
941
+ if (type == node -> type )
942
+ return node ;
943
+
944
+ return NULL ;
945
+ }
946
+
947
+ static int
948
+ update_notifier_cb (int notify_id , enum notify_type type , ffa_notifier_cb cb ,
949
+ void * cb_data , bool is_registration )
950
+ {
951
+ struct notifier_cb_info * cb_info = NULL ;
952
+ bool cb_found ;
953
+
954
+ cb_info = notifier_hash_node_get (notify_id , type );
955
+ cb_found = !!cb_info ;
956
+
957
+ if (!(is_registration ^ cb_found ))
958
+ return - EINVAL ;
959
+
960
+ if (is_registration ) {
961
+ cb_info = kzalloc (sizeof (* cb_info ), GFP_KERNEL );
962
+ if (!cb_info )
963
+ return - ENOMEM ;
964
+
965
+ cb_info -> type = type ;
966
+ cb_info -> cb = cb ;
967
+ cb_info -> cb_data = cb_data ;
968
+
969
+ hash_add (drv_info -> notifier_hash , & cb_info -> hnode , notify_id );
970
+ } else {
971
+ hash_del (& cb_info -> hnode );
972
+ }
973
+
974
+ return 0 ;
975
+ }
976
+
977
+ static enum notify_type ffa_notify_type_get (u16 vm_id )
978
+ {
979
+ if (vm_id & FFA_SECURE_PARTITION_ID_FLAG )
980
+ return SECURE_PARTITION ;
981
+ else
982
+ return NON_SECURE_VM ;
983
+ }
984
+
985
+ static int ffa_notify_relinquish (struct ffa_device * dev , int notify_id )
986
+ {
987
+ int rc ;
988
+ enum notify_type type = ffa_notify_type_get (dev -> vm_id );
989
+
990
+ if (notify_id >= FFA_MAX_NOTIFICATIONS )
991
+ return - EINVAL ;
992
+
993
+ mutex_lock (& drv_info -> notify_lock );
994
+
995
+ rc = update_notifier_cb (notify_id , type , NULL , NULL , false);
996
+ if (rc ) {
997
+ pr_err ("Could not unregister notification callback\n" );
998
+ mutex_unlock (& drv_info -> notify_lock );
999
+ return rc ;
1000
+ }
1001
+
1002
+ rc = ffa_notification_unbind (dev -> vm_id , BIT (notify_id ));
1003
+
1004
+ mutex_unlock (& drv_info -> notify_lock );
1005
+
1006
+ return rc ;
1007
+ }
1008
+
1009
+ static int ffa_notify_request (struct ffa_device * dev , bool is_per_vcpu ,
1010
+ ffa_notifier_cb cb , void * cb_data , int notify_id )
1011
+ {
1012
+ int rc ;
1013
+ u32 flags = 0 ;
1014
+ enum notify_type type = ffa_notify_type_get (dev -> vm_id );
1015
+
1016
+ if (notify_id >= FFA_MAX_NOTIFICATIONS )
1017
+ return - EINVAL ;
1018
+
1019
+ mutex_lock (& drv_info -> notify_lock );
1020
+
1021
+ if (is_per_vcpu )
1022
+ flags = PER_VCPU_NOTIFICATION_FLAG ;
1023
+
1024
+ rc = ffa_notification_bind (dev -> vm_id , BIT (notify_id ), flags );
1025
+ if (rc ) {
1026
+ mutex_unlock (& drv_info -> notify_lock );
1027
+ return rc ;
1028
+ }
1029
+
1030
+ rc = update_notifier_cb (notify_id , type , cb , cb_data , true);
1031
+ if (rc ) {
1032
+ pr_err ("Failed to register callback for %d - %d\n" ,
1033
+ notify_id , rc );
1034
+ ffa_notification_unbind (dev -> vm_id , BIT (notify_id ));
1035
+ }
1036
+ mutex_unlock (& drv_info -> notify_lock );
1037
+
1038
+ return rc ;
1039
+ }
1040
+
901
1041
static const struct ffa_info_ops ffa_drv_info_ops = {
902
1042
.api_version_get = ffa_api_version_get ,
903
1043
.partition_info_get = ffa_partition_info_get ,
@@ -921,6 +1061,8 @@ static const struct ffa_cpu_ops ffa_drv_cpu_ops = {
921
1061
static const struct ffa_notifier_ops ffa_drv_notifier_ops = {
922
1062
.sched_recv_cb_register = ffa_sched_recv_cb_register ,
923
1063
.sched_recv_cb_unregister = ffa_sched_recv_cb_unregister ,
1064
+ .notify_request = ffa_notify_request ,
1065
+ .notify_relinquish = ffa_notify_relinquish ,
924
1066
};
925
1067
926
1068
static const struct ffa_ops ffa_drv_ops = {
@@ -1194,6 +1336,9 @@ static int ffa_notifications_setup(void)
1194
1336
if (ret )
1195
1337
goto cleanup ;
1196
1338
1339
+ hash_init (drv_info -> notifier_hash );
1340
+ mutex_init (& drv_info -> notify_lock );
1341
+
1197
1342
return 0 ;
1198
1343
cleanup :
1199
1344
ffa_notifications_cleanup ();
0 commit comments