mirror of
https://github.com/torvalds/linux.git
synced 2026-09-24 06:24:02 +02:00
firmware: arm_scmi: Add common notifier helpers
Add a pair of notifier chains and generic empty notifier callbacks. Currently they are still unused but they will be used to act properly on device request and creation events. Signed-off-by: Cristian Marussi <cristian.marussi@arm.com> Link: https://lore.kernel.org/r/20221222185049.737625-5-cristian.marussi@arm.com Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
This commit is contained in:
parent
9115c20ac1
commit
53b8c25df7
|
|
@ -15,6 +15,9 @@
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
|
BLOCKING_NOTIFIER_HEAD(scmi_requested_devices_nh);
|
||||||
|
EXPORT_SYMBOL_GPL(scmi_requested_devices_nh);
|
||||||
|
|
||||||
static DEFINE_IDA(scmi_bus_id);
|
static DEFINE_IDA(scmi_bus_id);
|
||||||
|
|
||||||
static const struct scmi_device_id *
|
static const struct scmi_device_id *
|
||||||
|
|
@ -94,12 +97,13 @@ static void scmi_dev_remove(struct device *dev)
|
||||||
scmi_drv->remove(scmi_dev);
|
scmi_drv->remove(scmi_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct bus_type scmi_bus_type = {
|
struct bus_type scmi_bus_type = {
|
||||||
.name = "scmi_protocol",
|
.name = "scmi_protocol",
|
||||||
.match = scmi_dev_match,
|
.match = scmi_dev_match,
|
||||||
.probe = scmi_dev_probe,
|
.probe = scmi_dev_probe,
|
||||||
.remove = scmi_dev_remove,
|
.remove = scmi_dev_remove,
|
||||||
};
|
};
|
||||||
|
EXPORT_SYMBOL_GPL(scmi_bus_type);
|
||||||
|
|
||||||
int scmi_driver_register(struct scmi_driver *driver, struct module *owner,
|
int scmi_driver_register(struct scmi_driver *driver, struct module *owner,
|
||||||
const char *mod_name)
|
const char *mod_name)
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,11 @@ void scmi_setup_protocol_implemented(const struct scmi_protocol_handle *ph,
|
||||||
|
|
||||||
int __init scmi_bus_init(void);
|
int __init scmi_bus_init(void);
|
||||||
void __exit scmi_bus_exit(void);
|
void __exit scmi_bus_exit(void);
|
||||||
|
extern struct bus_type scmi_bus_type;
|
||||||
|
|
||||||
|
#define SCMI_BUS_NOTIFY_DEVICE_REQUEST 0
|
||||||
|
#define SCMI_BUS_NOTIFY_DEVICE_UNREQUEST 1
|
||||||
|
extern struct blocking_notifier_head scmi_requested_devices_nh;
|
||||||
|
|
||||||
int scmi_protocol_acquire(const struct scmi_handle *handle, u8 protocol_id);
|
int scmi_protocol_acquire(const struct scmi_handle *handle, u8 protocol_id);
|
||||||
void scmi_protocol_release(const struct scmi_handle *handle, u8 protocol_id);
|
void scmi_protocol_release(const struct scmi_handle *handle, u8 protocol_id);
|
||||||
|
|
|
||||||
|
|
@ -150,6 +150,9 @@ struct scmi_protocol_instance {
|
||||||
* @notify_priv: Pointer to private data structure specific to notifications.
|
* @notify_priv: Pointer to private data structure specific to notifications.
|
||||||
* @node: List head
|
* @node: List head
|
||||||
* @users: Number of users of this instance
|
* @users: Number of users of this instance
|
||||||
|
* @bus_nb: A notifier to listen for device bind/unbind on the scmi bus
|
||||||
|
* @dev_req_nb: A notifier to listen for device request/unrequest on the scmi
|
||||||
|
* bus
|
||||||
*/
|
*/
|
||||||
struct scmi_info {
|
struct scmi_info {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
|
@ -169,9 +172,13 @@ struct scmi_info {
|
||||||
void *notify_priv;
|
void *notify_priv;
|
||||||
struct list_head node;
|
struct list_head node;
|
||||||
int users;
|
int users;
|
||||||
|
struct notifier_block bus_nb;
|
||||||
|
struct notifier_block dev_req_nb;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define handle_to_scmi_info(h) container_of(h, struct scmi_info, handle)
|
#define handle_to_scmi_info(h) container_of(h, struct scmi_info, handle)
|
||||||
|
#define bus_nb_to_scmi_info(nb) container_of(nb, struct scmi_info, bus_nb)
|
||||||
|
#define req_nb_to_scmi_info(nb) container_of(nb, struct scmi_info, dev_req_nb)
|
||||||
|
|
||||||
static const int scmi_linux_errmap[] = {
|
static const int scmi_linux_errmap[] = {
|
||||||
/* better than switch case as long as return value is continuous */
|
/* better than switch case as long as return value is continuous */
|
||||||
|
|
@ -2509,6 +2516,60 @@ static void scmi_cleanup_txrx_channels(struct scmi_info *info)
|
||||||
scmi_cleanup_channels(info, &info->rx_idr);
|
scmi_cleanup_channels(info, &info->rx_idr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int scmi_bus_notifier(struct notifier_block *nb,
|
||||||
|
unsigned long action, void *data)
|
||||||
|
{
|
||||||
|
struct scmi_info *info = bus_nb_to_scmi_info(nb);
|
||||||
|
struct scmi_device *sdev = to_scmi_dev(data);
|
||||||
|
|
||||||
|
/* Skip transport devices and devices of different SCMI instances */
|
||||||
|
if (!strncmp(sdev->name, "__scmi_transport_device", 23) ||
|
||||||
|
sdev->dev.parent != info->dev)
|
||||||
|
return NOTIFY_DONE;
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case BUS_NOTIFY_BIND_DRIVER:
|
||||||
|
break;
|
||||||
|
case BUS_NOTIFY_UNBOUND_DRIVER:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return NOTIFY_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_dbg(info->dev, "Device %s (%s) is now %s\n", dev_name(&sdev->dev),
|
||||||
|
sdev->name, action == BUS_NOTIFY_BIND_DRIVER ?
|
||||||
|
"about to be BOUND." : "UNBOUND.");
|
||||||
|
|
||||||
|
return NOTIFY_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int scmi_device_request_notifier(struct notifier_block *nb,
|
||||||
|
unsigned long action, void *data)
|
||||||
|
{
|
||||||
|
struct device_node *np;
|
||||||
|
struct scmi_device_id *id_table = data;
|
||||||
|
struct scmi_info *info = req_nb_to_scmi_info(nb);
|
||||||
|
|
||||||
|
np = idr_find(&info->active_protocols, id_table->protocol_id);
|
||||||
|
if (!np)
|
||||||
|
return NOTIFY_DONE;
|
||||||
|
|
||||||
|
dev_dbg(info->dev, "%sRequested device (%s) for protocol 0x%x\n",
|
||||||
|
action == SCMI_BUS_NOTIFY_DEVICE_REQUEST ? "" : "UN-",
|
||||||
|
id_table->name, id_table->protocol_id);
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case SCMI_BUS_NOTIFY_DEVICE_REQUEST:
|
||||||
|
break;
|
||||||
|
case SCMI_BUS_NOTIFY_DEVICE_UNREQUEST:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return NOTIFY_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NOTIFY_OK;
|
||||||
|
}
|
||||||
|
|
||||||
static int scmi_probe(struct platform_device *pdev)
|
static int scmi_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
@ -2528,6 +2589,8 @@ static int scmi_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
info->dev = dev;
|
info->dev = dev;
|
||||||
info->desc = desc;
|
info->desc = desc;
|
||||||
|
info->bus_nb.notifier_call = scmi_bus_notifier;
|
||||||
|
info->dev_req_nb.notifier_call = scmi_device_request_notifier;
|
||||||
INIT_LIST_HEAD(&info->node);
|
INIT_LIST_HEAD(&info->node);
|
||||||
idr_init(&info->protocols);
|
idr_init(&info->protocols);
|
||||||
mutex_init(&info->protocols_mtx);
|
mutex_init(&info->protocols_mtx);
|
||||||
|
|
@ -2563,10 +2626,19 @@ static int scmi_probe(struct platform_device *pdev)
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
ret = scmi_xfer_info_init(info);
|
ret = bus_register_notifier(&scmi_bus_type, &info->bus_nb);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto clear_txrx_setup;
|
goto clear_txrx_setup;
|
||||||
|
|
||||||
|
ret = blocking_notifier_chain_register(&scmi_requested_devices_nh,
|
||||||
|
&info->dev_req_nb);
|
||||||
|
if (ret)
|
||||||
|
goto clear_bus_notifier;
|
||||||
|
|
||||||
|
ret = scmi_xfer_info_init(info);
|
||||||
|
if (ret)
|
||||||
|
goto clear_dev_req_notifier;
|
||||||
|
|
||||||
if (scmi_notification_init(handle))
|
if (scmi_notification_init(handle))
|
||||||
dev_err(dev, "SCMI Notifications NOT available.\n");
|
dev_err(dev, "SCMI Notifications NOT available.\n");
|
||||||
|
|
||||||
|
|
@ -2624,6 +2696,11 @@ static int scmi_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
notification_exit:
|
notification_exit:
|
||||||
scmi_notification_exit(&info->handle);
|
scmi_notification_exit(&info->handle);
|
||||||
|
clear_dev_req_notifier:
|
||||||
|
blocking_notifier_chain_unregister(&scmi_requested_devices_nh,
|
||||||
|
&info->dev_req_nb);
|
||||||
|
clear_bus_notifier:
|
||||||
|
bus_unregister_notifier(&scmi_bus_type, &info->bus_nb);
|
||||||
clear_txrx_setup:
|
clear_txrx_setup:
|
||||||
scmi_cleanup_txrx_channels(info);
|
scmi_cleanup_txrx_channels(info);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -2652,6 +2729,10 @@ static int scmi_remove(struct platform_device *pdev)
|
||||||
of_node_put(child);
|
of_node_put(child);
|
||||||
idr_destroy(&info->active_protocols);
|
idr_destroy(&info->active_protocols);
|
||||||
|
|
||||||
|
blocking_notifier_chain_unregister(&scmi_requested_devices_nh,
|
||||||
|
&info->dev_req_nb);
|
||||||
|
bus_unregister_notifier(&scmi_bus_type, &info->bus_nb);
|
||||||
|
|
||||||
/* Safe to free channels since no more users */
|
/* Safe to free channels since no more users */
|
||||||
scmi_cleanup_txrx_channels(info);
|
scmi_cleanup_txrx_channels(info);
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user