Commit b0b2981c authored by Arnd Bergmann's avatar Arnd Bergmann

Merge tag 'ffa-fixes-6.7' of...

Merge tag 'ffa-fixes-6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux into arm/fixes

Arm FF-A fixes for v6.7

A bunch of fixes addressing issues around the notification support that
was added this cycle. They address issue in partition IDs handling in
ffa_notification_info_get(), notifications cleanup path and the size of
the allocation in ffa_partitions_cleanup().

It also adds check for the notification enabled state so that the drivers
registering the callbacks can be rejected if not enabled/supported.

It also moves the partitions setup operation after the notification
initialisation so that the driver has the correct state for notification
enabled/supported before the partitions are initialised/setup.

It also now allows FF-A initialisation to complete successfully even
when the notification initialisation fails as it is an optional support
in the specification. Initial support just allowed it only if the
firmware didn't support notifications.

Finally, it also adds a fix for smatch warning by declaring ffa_bus_type
structure in the header.

* tag 'ffa-fixes-6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux:
  firmware: arm_ffa: Fix ffa_notification_info_get() IDs handling
  firmware: arm_ffa: Fix the size of the allocation in ffa_partitions_cleanup()
  firmware: arm_ffa: Fix FFA notifications cleanup path
  firmware: arm_ffa: Add checks for the notification enabled state
  firmware: arm_ffa: Setup the partitions after the notification initialisation
  firmware: arm_ffa: Allow FF-A initialisation even when notification fails
  firmware: arm_ffa: Declare ffa_bus_type structure in the header

Link: https://lore.kernel.org/r/20231116191603.929767-1-sudeep.holla@arm.comSigned-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parents 94ea0ed3 f1ed48ef
...@@ -99,6 +99,7 @@ struct ffa_drv_info { ...@@ -99,6 +99,7 @@ struct ffa_drv_info {
void *tx_buffer; void *tx_buffer;
bool mem_ops_native; bool mem_ops_native;
bool bitmap_created; bool bitmap_created;
bool notif_enabled;
unsigned int sched_recv_irq; unsigned int sched_recv_irq;
unsigned int cpuhp_state; unsigned int cpuhp_state;
struct ffa_pcpu_irq __percpu *irq_pcpu; struct ffa_pcpu_irq __percpu *irq_pcpu;
...@@ -782,7 +783,7 @@ static void ffa_notification_info_get(void) ...@@ -782,7 +783,7 @@ static void ffa_notification_info_get(void)
if (ids_processed >= max_ids - 1) if (ids_processed >= max_ids - 1)
break; break;
part_id = packed_id_list[++ids_processed]; part_id = packed_id_list[ids_processed++];
if (!ids_count[list]) { /* Global Notification */ if (!ids_count[list]) { /* Global Notification */
__do_sched_recv_cb(part_id, 0, false); __do_sched_recv_cb(part_id, 0, false);
...@@ -794,7 +795,7 @@ static void ffa_notification_info_get(void) ...@@ -794,7 +795,7 @@ static void ffa_notification_info_get(void)
if (ids_processed >= max_ids - 1) if (ids_processed >= max_ids - 1)
break; break;
vcpu_id = packed_id_list[++ids_processed]; vcpu_id = packed_id_list[ids_processed++];
__do_sched_recv_cb(part_id, vcpu_id, true); __do_sched_recv_cb(part_id, vcpu_id, true);
} }
...@@ -889,6 +890,8 @@ static int ffa_memory_lend(struct ffa_mem_ops_args *args) ...@@ -889,6 +890,8 @@ static int ffa_memory_lend(struct ffa_mem_ops_args *args)
#define FFA_SECURE_PARTITION_ID_FLAG BIT(15) #define FFA_SECURE_PARTITION_ID_FLAG BIT(15)
#define ffa_notifications_disabled() (!drv_info->notif_enabled)
enum notify_type { enum notify_type {
NON_SECURE_VM, NON_SECURE_VM,
SECURE_PARTITION, SECURE_PARTITION,
...@@ -908,6 +911,9 @@ static int ffa_sched_recv_cb_update(u16 part_id, ffa_sched_recv_cb callback, ...@@ -908,6 +911,9 @@ static int ffa_sched_recv_cb_update(u16 part_id, ffa_sched_recv_cb callback,
struct ffa_dev_part_info *partition; struct ffa_dev_part_info *partition;
bool cb_valid; bool cb_valid;
if (ffa_notifications_disabled())
return -EOPNOTSUPP;
partition = xa_load(&drv_info->partition_info, part_id); partition = xa_load(&drv_info->partition_info, part_id);
write_lock(&partition->rw_lock); write_lock(&partition->rw_lock);
...@@ -1001,6 +1007,9 @@ static int ffa_notify_relinquish(struct ffa_device *dev, int notify_id) ...@@ -1001,6 +1007,9 @@ static int ffa_notify_relinquish(struct ffa_device *dev, int notify_id)
int rc; int rc;
enum notify_type type = ffa_notify_type_get(dev->vm_id); enum notify_type type = ffa_notify_type_get(dev->vm_id);
if (ffa_notifications_disabled())
return -EOPNOTSUPP;
if (notify_id >= FFA_MAX_NOTIFICATIONS) if (notify_id >= FFA_MAX_NOTIFICATIONS)
return -EINVAL; return -EINVAL;
...@@ -1027,6 +1036,9 @@ static int ffa_notify_request(struct ffa_device *dev, bool is_per_vcpu, ...@@ -1027,6 +1036,9 @@ static int ffa_notify_request(struct ffa_device *dev, bool is_per_vcpu,
u32 flags = 0; u32 flags = 0;
enum notify_type type = ffa_notify_type_get(dev->vm_id); enum notify_type type = ffa_notify_type_get(dev->vm_id);
if (ffa_notifications_disabled())
return -EOPNOTSUPP;
if (notify_id >= FFA_MAX_NOTIFICATIONS) if (notify_id >= FFA_MAX_NOTIFICATIONS)
return -EINVAL; return -EINVAL;
...@@ -1057,6 +1069,9 @@ static int ffa_notify_send(struct ffa_device *dev, int notify_id, ...@@ -1057,6 +1069,9 @@ static int ffa_notify_send(struct ffa_device *dev, int notify_id,
{ {
u32 flags = 0; u32 flags = 0;
if (ffa_notifications_disabled())
return -EOPNOTSUPP;
if (is_per_vcpu) if (is_per_vcpu)
flags |= (PER_VCPU_NOTIFICATION_FLAG | vcpu << 16); flags |= (PER_VCPU_NOTIFICATION_FLAG | vcpu << 16);
...@@ -1233,7 +1248,7 @@ static void ffa_partitions_cleanup(void) ...@@ -1233,7 +1248,7 @@ static void ffa_partitions_cleanup(void)
if (!count) if (!count)
return; return;
info = kcalloc(count, sizeof(**info), GFP_KERNEL); info = kcalloc(count, sizeof(*info), GFP_KERNEL);
if (!info) if (!info)
return; return;
...@@ -1311,8 +1326,10 @@ static int ffa_sched_recv_irq_map(void) ...@@ -1311,8 +1326,10 @@ static int ffa_sched_recv_irq_map(void)
static void ffa_sched_recv_irq_unmap(void) static void ffa_sched_recv_irq_unmap(void)
{ {
if (drv_info->sched_recv_irq) if (drv_info->sched_recv_irq) {
irq_dispose_mapping(drv_info->sched_recv_irq); irq_dispose_mapping(drv_info->sched_recv_irq);
drv_info->sched_recv_irq = 0;
}
} }
static int ffa_cpuhp_pcpu_irq_enable(unsigned int cpu) static int ffa_cpuhp_pcpu_irq_enable(unsigned int cpu)
...@@ -1329,17 +1346,23 @@ static int ffa_cpuhp_pcpu_irq_disable(unsigned int cpu) ...@@ -1329,17 +1346,23 @@ static int ffa_cpuhp_pcpu_irq_disable(unsigned int cpu)
static void ffa_uninit_pcpu_irq(void) static void ffa_uninit_pcpu_irq(void)
{ {
if (drv_info->cpuhp_state) if (drv_info->cpuhp_state) {
cpuhp_remove_state(drv_info->cpuhp_state); cpuhp_remove_state(drv_info->cpuhp_state);
drv_info->cpuhp_state = 0;
}
if (drv_info->notif_pcpu_wq) if (drv_info->notif_pcpu_wq) {
destroy_workqueue(drv_info->notif_pcpu_wq); destroy_workqueue(drv_info->notif_pcpu_wq);
drv_info->notif_pcpu_wq = NULL;
}
if (drv_info->sched_recv_irq) if (drv_info->sched_recv_irq)
free_percpu_irq(drv_info->sched_recv_irq, drv_info->irq_pcpu); free_percpu_irq(drv_info->sched_recv_irq, drv_info->irq_pcpu);
if (drv_info->irq_pcpu) if (drv_info->irq_pcpu) {
free_percpu(drv_info->irq_pcpu); free_percpu(drv_info->irq_pcpu);
drv_info->irq_pcpu = NULL;
}
} }
static int ffa_init_pcpu_irq(unsigned int irq) static int ffa_init_pcpu_irq(unsigned int irq)
...@@ -1388,22 +1411,23 @@ static void ffa_notifications_cleanup(void) ...@@ -1388,22 +1411,23 @@ static void ffa_notifications_cleanup(void)
ffa_notification_bitmap_destroy(); ffa_notification_bitmap_destroy();
drv_info->bitmap_created = false; drv_info->bitmap_created = false;
} }
drv_info->notif_enabled = false;
} }
static int ffa_notifications_setup(void) static void ffa_notifications_setup(void)
{ {
int ret, irq; int ret, irq;
ret = ffa_features(FFA_NOTIFICATION_BITMAP_CREATE, 0, NULL, NULL); ret = ffa_features(FFA_NOTIFICATION_BITMAP_CREATE, 0, NULL, NULL);
if (ret) { if (ret) {
pr_err("Notifications not supported, continuing with it ..\n"); pr_info("Notifications not supported, continuing with it ..\n");
return 0; return;
} }
ret = ffa_notification_bitmap_create(); ret = ffa_notification_bitmap_create();
if (ret) { if (ret) {
pr_err("notification_bitmap_create error %d\n", ret); pr_info("Notification bitmap create error %d\n", ret);
return ret; return;
} }
drv_info->bitmap_created = true; drv_info->bitmap_created = true;
...@@ -1422,14 +1446,11 @@ static int ffa_notifications_setup(void) ...@@ -1422,14 +1446,11 @@ static int ffa_notifications_setup(void)
hash_init(drv_info->notifier_hash); hash_init(drv_info->notifier_hash);
mutex_init(&drv_info->notify_lock); mutex_init(&drv_info->notify_lock);
/* Register internal scheduling callback */ drv_info->notif_enabled = true;
ret = ffa_sched_recv_cb_update(drv_info->vm_id, ffa_self_notif_handle, return;
drv_info, true);
if (!ret)
return ret;
cleanup: cleanup:
pr_info("Notification setup failed %d, not enabled\n", ret);
ffa_notifications_cleanup(); ffa_notifications_cleanup();
return ret;
} }
static int __init ffa_init(void) static int __init ffa_init(void)
...@@ -1483,17 +1504,18 @@ static int __init ffa_init(void) ...@@ -1483,17 +1504,18 @@ static int __init ffa_init(void)
mutex_init(&drv_info->rx_lock); mutex_init(&drv_info->rx_lock);
mutex_init(&drv_info->tx_lock); mutex_init(&drv_info->tx_lock);
ffa_setup_partitions();
ffa_set_up_mem_ops_native_flag(); ffa_set_up_mem_ops_native_flag();
ret = ffa_notifications_setup(); ffa_notifications_setup();
ffa_setup_partitions();
ret = ffa_sched_recv_cb_update(drv_info->vm_id, ffa_self_notif_handle,
drv_info, true);
if (ret) if (ret)
goto partitions_cleanup; pr_info("Failed to register driver sched callback %d\n", ret);
return 0; return 0;
partitions_cleanup:
ffa_partitions_cleanup();
free_pages: free_pages:
if (drv_info->tx_buffer) if (drv_info->tx_buffer)
free_pages_exact(drv_info->tx_buffer, RXTX_BUFFER_SIZE); free_pages_exact(drv_info->tx_buffer, RXTX_BUFFER_SIZE);
......
...@@ -209,6 +209,8 @@ bool ffa_device_is_valid(struct ffa_device *ffa_dev) { return false; } ...@@ -209,6 +209,8 @@ bool ffa_device_is_valid(struct ffa_device *ffa_dev) { return false; }
#define module_ffa_driver(__ffa_driver) \ #define module_ffa_driver(__ffa_driver) \
module_driver(__ffa_driver, ffa_register, ffa_unregister) module_driver(__ffa_driver, ffa_register, ffa_unregister)
extern struct bus_type ffa_bus_type;
/* FFA transport related */ /* FFA transport related */
struct ffa_partition_info { struct ffa_partition_info {
u16 id; u16 id;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment