SCMI fixes for v5.15

A few fixes addressing:
 - Kconfig dependency between VIRTIO and ARM_SCMI_PROTOCOL
 - Link-time error with __exit annotation for virtio_scmi_exit
 - Unnecessary nested irqsave/irqrestore spinlocks in virtio transport
 - Missing SMP barriers to protect accesses to SCMI virtio device
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEunHlEgbzHrJD3ZPhAEG6vDF+4pgFAmFdfQ0ACgkQAEG6vDF+
 4piS7g//TS0lhdY7oFWb2XpyQtcY7oudREtfV76pcrtYrdepKrfa3SzfjNVwTmq6
 Tp2W+viRD1fLtqx0tPhO6YurgMFPUke+j7njS/yTMTitPhgzqm93l9Re+TxI7XiU
 qEuSoC+fenQhrhqNTXRaEkGFLWiQrENw5SUjz+ZcE/3QKUv35PU6HG5Od9gywssB
 wQ69Slr4AAHyPBPD3CVj5QUQhRvfp+YwOqSY/DwngjRCg/zDidWBFZ8XVLYRZ1Dl
 rAgdPsnnLTZ9sPgscIHciR/lyQdDqkY6A++U85oDLXjs7vZ27mlq+bFq3Rp6um3M
 WTbw89Fcvu8cQUMjEHFtGblEPgVn/BrK5po6DZA8RbSowcp7AMj87Gi0IhSRakPE
 ALN8qb9W84CbgzwcmCqCZiVzeEgy+uCVqtPIc4feupu4ukrah/+TPlAeM29JPVOO
 D5CtWushTxabRDb+/xGIBuww0qXiXm0he7I0QpVfW7JGBr+Bo62G2OWmNvwMlor0
 Gc0ecz47P+vywra4Spa9w6VzvfDFOk0xmHp07RyyWXdbLL1IqvWW+DBW2E9fJMrf
 b4m65V822fTOv19mUIPzcou5erzL8wtfN9kSR+8gJ9iIlJ+0Xs/UoIT7fY3CAgpu
 xBUhBjcOD/Zjv607tO3XsJyRj5VgU88Dqod3k5oJfqXzg97fAH4=
 =4s/W
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEo6/YBQwIrVS28WGKmmx57+YAGNkFAmFfRvwACgkQmmx57+YA
 GNlnGA/+N9u/OQlwfB2kMoV/4iGGFUzQ0gCN+F+uKitS3hNnR8ke6npDV/wjytRC
 EAbUvnecdJvwXCOSRVm+HRZMbHtmeKi+wm9CzOzBlUH6wjDuDQ3aSjMwlDeWNVVS
 EAhvFojqFZQAk2QbnUfWAvM4gTtdY8UOrSXsrFI2y4J5ukzeCWDJ5OlJ3/qs0k/5
 zmAHbgubvQYhg2wFhDx4Z/4YdT2mkZj6gyz7bX2qPJDPQb1mQUYbVYXhbkqXlQ96
 9b76F3x+4/KO6OqM7lZFI1yNBBaRR9clqVQWClCEXTbXLyTG/q56KWGQww3sdY94
 oi+ZfoiK4y+P/0oareBJq1Epp+c8A4RXy04ovV92OvxnM7qcmkNFZskYXhK1wnnc
 2R0UyNWEq9o3V2KT/3q94PSXppFVDe918hMvEq3qPaF/8wTQ/ZrpuLOmCtZi/OmH
 dl3M36lZNbQyvXg9jX2ZKGJgw7j2Ig6aTnpjsbxW4O5KmTLKskDV7PoFNeVnfokI
 7mJ6WWYTFUK0WnyCVI+t1AIKnWBDu80puhna5shWVaIQaxW0AlyA+Rhf5YRHqNga
 GUHNJatzL5iMyplV2TUbDNmFwHt9wYxGUN4hgfK0z0YsATjf6zbtixLVHb4ZBI/M
 bsNMiys5ZCQ+u0Btwk3blXSQwK/Gr6m/9HKWPpDnol4b/LBA2dM=
 =UP9E
 -----END PGP SIGNATURE-----

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

SCMI fixes for v5.15

A few fixes addressing:
- Kconfig dependency between VIRTIO and ARM_SCMI_PROTOCOL
- Link-time error with __exit annotation for virtio_scmi_exit
- Unnecessary nested irqsave/irqrestore spinlocks in virtio transport
- Missing SMP barriers to protect accesses to SCMI virtio device

* tag 'scmi-fixes-5.15' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux:
  firmware: arm_scmi: Add proper barriers to scmi virtio device
  firmware: arm_scmi: Simplify spinlocks in virtio transport
  firmware: arm_scmi: Remove __exit annotation
  firmware: arm_scmi: Fix virtio transport Kconfig dependency

Link: https://lore.kernel.org/r/20211007102822.27886-1-sudeep.holla@arm.com
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
Arnd Bergmann 2021-10-07 21:14:03 +02:00
commit 6aaa843438
2 changed files with 32 additions and 14 deletions

View File

@ -68,7 +68,7 @@ config ARM_SCMI_TRANSPORT_SMC
config ARM_SCMI_TRANSPORT_VIRTIO
bool "SCMI transport based on VirtIO"
depends on VIRTIO
depends on VIRTIO=y || VIRTIO=ARM_SCMI_PROTOCOL
select ARM_SCMI_HAVE_TRANSPORT
select ARM_SCMI_HAVE_MSG
help

View File

@ -110,18 +110,16 @@ static void scmi_finalize_message(struct scmi_vio_channel *vioch,
if (vioch->is_rx) {
scmi_vio_feed_vq_rx(vioch, msg);
} else {
unsigned long flags;
spin_lock_irqsave(&vioch->lock, flags);
/* Here IRQs are assumed to be already disabled by the caller */
spin_lock(&vioch->lock);
list_add(&msg->list, &vioch->free_list);
spin_unlock_irqrestore(&vioch->lock, flags);
spin_unlock(&vioch->lock);
}
}
static void scmi_vio_complete_cb(struct virtqueue *vqueue)
{
unsigned long ready_flags;
unsigned long flags;
unsigned int length;
struct scmi_vio_channel *vioch;
struct scmi_vio_msg *msg;
@ -140,7 +138,8 @@ static void scmi_vio_complete_cb(struct virtqueue *vqueue)
goto unlock_ready_out;
}
spin_lock_irqsave(&vioch->lock, flags);
/* IRQs already disabled here no need to irqsave */
spin_lock(&vioch->lock);
if (cb_enabled) {
virtqueue_disable_cb(vqueue);
cb_enabled = false;
@ -151,7 +150,7 @@ static void scmi_vio_complete_cb(struct virtqueue *vqueue)
goto unlock_out;
cb_enabled = true;
}
spin_unlock_irqrestore(&vioch->lock, flags);
spin_unlock(&vioch->lock);
if (msg) {
msg->rx_len = length;
@ -161,11 +160,18 @@ static void scmi_vio_complete_cb(struct virtqueue *vqueue)
scmi_finalize_message(vioch, msg);
}
/*
* Release ready_lock and re-enable IRQs between loop iterations
* to allow virtio_chan_free() to possibly kick in and set the
* flag vioch->ready to false even in between processing of
* messages, so as to force outstanding messages to be ignored
* when system is shutting down.
*/
spin_unlock_irqrestore(&vioch->ready_lock, ready_flags);
}
unlock_out:
spin_unlock_irqrestore(&vioch->lock, flags);
spin_unlock(&vioch->lock);
unlock_ready_out:
spin_unlock_irqrestore(&vioch->ready_lock, ready_flags);
}
@ -384,8 +390,11 @@ static int scmi_vio_probe(struct virtio_device *vdev)
struct virtqueue *vqs[VIRTIO_SCMI_VQ_MAX_CNT];
/* Only one SCMI VirtiO device allowed */
if (scmi_vdev)
return -EINVAL;
if (scmi_vdev) {
dev_err(dev,
"One SCMI Virtio device was already initialized: only one allowed.\n");
return -EBUSY;
}
have_vq_rx = scmi_vio_have_vq_rx(vdev);
vq_cnt = have_vq_rx ? VIRTIO_SCMI_VQ_MAX_CNT : 1;
@ -428,16 +437,25 @@ static int scmi_vio_probe(struct virtio_device *vdev)
}
vdev->priv = channels;
scmi_vdev = vdev;
/* Ensure initialized scmi_vdev is visible */
smp_store_mb(scmi_vdev, vdev);
return 0;
}
static void scmi_vio_remove(struct virtio_device *vdev)
{
/*
* Once we get here, virtio_chan_free() will have already been called by
* the SCMI core for any existing channel and, as a consequence, all the
* virtio channels will have been already marked NOT ready, causing any
* outstanding message on any vqueue to be ignored by complete_cb: now
* we can just stop processing buffers and destroy the vqueues.
*/
vdev->config->reset(vdev);
vdev->config->del_vqs(vdev);
scmi_vdev = NULL;
/* Ensure scmi_vdev is visible as NULL */
smp_store_mb(scmi_vdev, NULL);
}
static int scmi_vio_validate(struct virtio_device *vdev)
@ -476,7 +494,7 @@ static int __init virtio_scmi_init(void)
return register_virtio_driver(&virtio_scmi_driver);
}
static void __exit virtio_scmi_exit(void)
static void virtio_scmi_exit(void)
{
unregister_virtio_driver(&virtio_scmi_driver);
}