@@ -925,27 +925,32 @@ struct ffa_dev_part_info {
925925 ffa_sched_recv_cb callback ;
926926 void * cb_data ;
927927 rwlock_t rw_lock ;
928+ struct ffa_device * dev ;
929+ struct list_head node ;
928930};
929931
930932static void __do_sched_recv_cb (u16 part_id , u16 vcpu , bool is_per_vcpu )
931933{
932- struct ffa_dev_part_info * partition ;
934+ struct ffa_dev_part_info * partition = NULL , * tmp ;
933935 ffa_sched_recv_cb callback ;
936+ struct list_head * phead ;
934937 void * cb_data ;
935938
936- partition = xa_load (& drv_info -> partition_info , part_id );
937- if (!partition ) {
939+ phead = xa_load (& drv_info -> partition_info , part_id );
940+ if (!phead ) {
938941 pr_err ("%s: Invalid partition ID 0x%x\n" , __func__ , part_id );
939942 return ;
940943 }
941944
942- read_lock (& partition -> rw_lock );
943- callback = partition -> callback ;
944- cb_data = partition -> cb_data ;
945- read_unlock (& partition -> rw_lock );
945+ list_for_each_entry_safe (partition , tmp , phead , node ) {
946+ read_lock (& partition -> rw_lock );
947+ callback = partition -> callback ;
948+ cb_data = partition -> cb_data ;
949+ read_unlock (& partition -> rw_lock );
946950
947- if (callback )
948- callback (vcpu , is_per_vcpu , cb_data );
951+ if (callback )
952+ callback (vcpu , is_per_vcpu , cb_data );
953+ }
949954}
950955
951956static void ffa_notification_info_get (void )
@@ -1123,18 +1128,29 @@ struct notifier_cb_info {
11231128 void * cb_data ;
11241129};
11251130
1126- static int ffa_sched_recv_cb_update (u16 part_id , ffa_sched_recv_cb callback ,
1127- void * cb_data , bool is_registration )
1131+ static int
1132+ ffa_sched_recv_cb_update (struct ffa_device * dev , ffa_sched_recv_cb callback ,
1133+ void * cb_data , bool is_registration )
11281134{
1129- struct ffa_dev_part_info * partition ;
1135+ struct ffa_dev_part_info * partition = NULL , * tmp ;
1136+ struct list_head * phead ;
11301137 bool cb_valid ;
11311138
11321139 if (ffa_notifications_disabled ())
11331140 return - EOPNOTSUPP ;
11341141
1135- partition = xa_load (& drv_info -> partition_info , part_id );
1142+ phead = xa_load (& drv_info -> partition_info , dev -> vm_id );
1143+ if (!phead ) {
1144+ pr_err ("%s: Invalid partition ID 0x%x\n" , __func__ , dev -> vm_id );
1145+ return - EINVAL ;
1146+ }
1147+
1148+ list_for_each_entry_safe (partition , tmp , phead , node )
1149+ if (partition -> dev == dev )
1150+ break ;
1151+
11361152 if (!partition ) {
1137- pr_err ("%s: Invalid partition ID 0x%x\n" , __func__ , part_id );
1153+ pr_err ("%s: No such partition ID 0x%x\n" , __func__ , dev -> vm_id );
11381154 return - EINVAL ;
11391155 }
11401156
@@ -1156,12 +1172,12 @@ static int ffa_sched_recv_cb_update(u16 part_id, ffa_sched_recv_cb callback,
11561172static int ffa_sched_recv_cb_register (struct ffa_device * dev ,
11571173 ffa_sched_recv_cb cb , void * cb_data )
11581174{
1159- return ffa_sched_recv_cb_update (dev -> vm_id , cb , cb_data , true);
1175+ return ffa_sched_recv_cb_update (dev , cb , cb_data , true);
11601176}
11611177
11621178static int ffa_sched_recv_cb_unregister (struct ffa_device * dev )
11631179{
1164- return ffa_sched_recv_cb_update (dev -> vm_id , NULL , NULL , false);
1180+ return ffa_sched_recv_cb_update (dev , NULL , NULL , false);
11651181}
11661182
11671183static int ffa_notification_bind (u16 dst_id , u64 bitmap , u32 flags )
@@ -1548,37 +1564,101 @@ static struct notifier_block ffa_bus_nb = {
15481564 .notifier_call = ffa_bus_notifier ,
15491565};
15501566
1551- static int ffa_xa_add_partition_info (int vm_id )
1567+ static int ffa_xa_add_partition_info (struct ffa_device * dev )
15521568{
15531569 struct ffa_dev_part_info * info ;
1554- int ret ;
1570+ struct list_head * head , * phead ;
1571+ int ret = - ENOMEM ;
1572+
1573+ phead = xa_load (& drv_info -> partition_info , dev -> vm_id );
1574+ if (phead ) {
1575+ head = phead ;
1576+ list_for_each_entry (info , head , node ) {
1577+ if (info -> dev == dev ) {
1578+ pr_err ("%s: duplicate dev %p part ID 0x%x\n" ,
1579+ __func__ , dev , dev -> vm_id );
1580+ return - EEXIST ;
1581+ }
1582+ }
1583+ }
15551584
15561585 info = kzalloc (sizeof (* info ), GFP_KERNEL );
15571586 if (!info )
1558- return - ENOMEM ;
1587+ return ret ;
15591588
15601589 rwlock_init (& info -> rw_lock );
1561- ret = xa_insert (& drv_info -> partition_info , vm_id , info , GFP_KERNEL );
1562- if (ret ) {
1563- pr_err ("%s: failed to save partition ID 0x%x - ret:%d. Abort.\n" ,
1564- __func__ , vm_id , ret );
1565- kfree (info );
1590+ info -> dev = dev ;
1591+
1592+ if (!phead ) {
1593+ phead = kzalloc (sizeof (* phead ), GFP_KERNEL );
1594+ if (!phead )
1595+ goto free_out ;
1596+
1597+ INIT_LIST_HEAD (phead );
1598+
1599+ ret = xa_insert (& drv_info -> partition_info , dev -> vm_id , phead ,
1600+ GFP_KERNEL );
1601+ if (ret ) {
1602+ pr_err ("%s: failed to save part ID 0x%x Ret:%d\n" ,
1603+ __func__ , dev -> vm_id , ret );
1604+ goto free_out ;
1605+ }
1606+ }
1607+ list_add (& info -> node , phead );
1608+ return 0 ;
1609+
1610+ free_out :
1611+ kfree (phead );
1612+ kfree (info );
1613+ return ret ;
1614+ }
1615+
1616+ static int ffa_setup_host_partition (int vm_id )
1617+ {
1618+ struct ffa_partition_info buf = { 0 };
1619+ struct ffa_device * ffa_dev ;
1620+ int ret ;
1621+
1622+ buf .id = vm_id ;
1623+ ffa_dev = ffa_device_register (& buf , & ffa_drv_ops );
1624+ if (!ffa_dev ) {
1625+ pr_err ("%s: failed to register host partition ID 0x%x\n" ,
1626+ __func__ , vm_id );
1627+ return - EINVAL ;
15661628 }
15671629
1630+ ret = ffa_xa_add_partition_info (ffa_dev );
1631+ if (ret )
1632+ return ret ;
1633+
1634+ if (ffa_notifications_disabled ())
1635+ return 0 ;
1636+
1637+ ret = ffa_sched_recv_cb_update (ffa_dev , ffa_self_notif_handle ,
1638+ drv_info , true);
1639+ if (ret )
1640+ pr_info ("Failed to register driver sched callback %d\n" , ret );
1641+
15681642 return ret ;
15691643}
15701644
15711645static void ffa_partitions_cleanup (void )
15721646{
1573- struct ffa_dev_part_info * info ;
1647+ struct list_head * phead ;
15741648 unsigned long idx ;
15751649
15761650 /* Clean up/free all registered devices */
15771651 ffa_devices_unregister ();
15781652
1579- xa_for_each (& drv_info -> partition_info , idx , info ) {
1653+ xa_for_each (& drv_info -> partition_info , idx , phead ) {
1654+ struct ffa_dev_part_info * info , * tmp ;
1655+
15801656 xa_erase (& drv_info -> partition_info , idx );
1581- kfree (info );
1657+ list_for_each_entry_safe (info , tmp , phead , node ) {
1658+ list_del (& info -> node );
1659+ kfree (info );
1660+ }
1661+ kfree (phead );
15821662 }
15831663
15841664 xa_destroy (& drv_info -> partition_info );
@@ -1621,20 +1701,24 @@ static int ffa_setup_partitions(void)
16211701 !(tpbuf -> properties & FFA_PARTITION_AARCH64_EXEC ))
16221702 ffa_mode_32bit_set (ffa_dev );
16231703
1624- if (ffa_xa_add_partition_info (ffa_dev -> vm_id )) {
1704+ if (ffa_xa_add_partition_info (ffa_dev )) {
16251705 ffa_device_unregister (ffa_dev );
16261706 continue ;
16271707 }
16281708 }
16291709
16301710 kfree (pbuf );
16311711
1632- /* Check if the host is already added as part of partition info */
1712+ /*
1713+ * Check if the host is already added as part of partition info
1714+ * No multiple UUID possible for the host, so just checking if
1715+ * there is an entry will suffice
1716+ */
16331717 if (xa_load (& drv_info -> partition_info , drv_info -> vm_id ))
16341718 return 0 ;
16351719
16361720 /* Allocate for the host */
1637- ret = ffa_xa_add_partition_info (drv_info -> vm_id );
1721+ ret = ffa_setup_host_partition (drv_info -> vm_id );
16381722 if (ret )
16391723 ffa_partitions_cleanup ();
16401724
@@ -1943,19 +2027,10 @@ static int __init ffa_init(void)
19432027 ffa_notifications_setup ();
19442028
19452029 ret = ffa_setup_partitions ();
1946- if (ret ) {
1947- pr_err ("failed to setup partitions\n" );
1948- goto cleanup_notifs ;
1949- }
1950-
1951- ret = ffa_sched_recv_cb_update (drv_info -> vm_id , ffa_self_notif_handle ,
1952- drv_info , true);
1953- if (ret )
1954- pr_info ("Failed to register driver sched callback %d\n" , ret );
1955-
1956- return 0 ;
2030+ if (!ret )
2031+ return ret ;
19572032
1958- cleanup_notifs :
2033+ pr_err ( "failed to setup partitions\n" );
19592034 ffa_notifications_cleanup ();
19602035free_pages :
19612036 if (drv_info -> tx_buffer )
0 commit comments