2727#include <linux/bitfield.h>
2828#include <linux/cpuhotplug.h>
2929#include <linux/device.h>
30+ #include <linux/hashtable.h>
3031#include <linux/interrupt.h>
3132#include <linux/io.h>
3233#include <linux/kernel.h>
3334#include <linux/module.h>
3435#include <linux/mm.h>
36+ #include <linux/mutex.h>
3537#include <linux/of_irq.h>
3638#include <linux/scatterlist.h>
3739#include <linux/slab.h>
5759 */
5860#define RXTX_BUFFER_SIZE SZ_4K
5961
62+ #define FFA_MAX_NOTIFICATIONS 64
63+
6064static ffa_fn * invoke_ffa_fn ;
6165
6266static const int ffa_linux_errmap [] = {
@@ -102,6 +106,8 @@ struct ffa_drv_info {
102106 struct work_struct irq_work ;
103107 struct xarray partition_info ;
104108 unsigned int partition_count ;
109+ DECLARE_HASHTABLE (notifier_hash , ilog2 (FFA_MAX_NOTIFICATIONS ));
110+ struct mutex notify_lock ; /* lock to protect notifier hashtable */
105111};
106112
107113static struct ffa_drv_info * drv_info ;
@@ -626,6 +632,8 @@ static int ffa_notification_bitmap_destroy(void)
626632#define MAX_IDS_64 20
627633#define MAX_IDS_32 10
628634
635+ #define PER_VCPU_NOTIFICATION_FLAG BIT(0)
636+
629637static int ffa_notification_bind_common (u16 dst_id , u64 bitmap ,
630638 u32 flags , bool is_bind )
631639{
@@ -865,6 +873,21 @@ static int ffa_memory_lend(struct ffa_mem_ops_args *args)
865873 return ffa_memory_ops (FFA_MEM_LEND , args );
866874}
867875
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+
868891static int ffa_sched_recv_cb_update (u16 part_id , ffa_sched_recv_cb callback ,
869892 void * cb_data , bool is_registration )
870893{
@@ -898,6 +921,123 @@ static int ffa_sched_recv_cb_unregister(struct ffa_device *dev)
898921 return ffa_sched_recv_cb_update (dev -> vm_id , NULL , NULL , false);
899922}
900923
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+
9011041static const struct ffa_info_ops ffa_drv_info_ops = {
9021042 .api_version_get = ffa_api_version_get ,
9031043 .partition_info_get = ffa_partition_info_get ,
@@ -921,6 +1061,8 @@ static const struct ffa_cpu_ops ffa_drv_cpu_ops = {
9211061static const struct ffa_notifier_ops ffa_drv_notifier_ops = {
9221062 .sched_recv_cb_register = ffa_sched_recv_cb_register ,
9231063 .sched_recv_cb_unregister = ffa_sched_recv_cb_unregister ,
1064+ .notify_request = ffa_notify_request ,
1065+ .notify_relinquish = ffa_notify_relinquish ,
9241066};
9251067
9261068static const struct ffa_ops ffa_drv_ops = {
@@ -1194,6 +1336,9 @@ static int ffa_notifications_setup(void)
11941336 if (ret )
11951337 goto cleanup ;
11961338
1339+ hash_init (drv_info -> notifier_hash );
1340+ mutex_init (& drv_info -> notify_lock );
1341+
11971342 return 0 ;
11981343cleanup :
11991344 ffa_notifications_cleanup ();
0 commit comments