Commit 2526112b authored by Arnd Bergmann's avatar Arnd Bergmann

Merge tag 'scmi-fixes-5.14' of...

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

ARM SCMI fixes for v5.14

A small set of fixes:
- adding check for presence of probe while registering the driver to
  prevent NULL pointer access
- dropping the duplicate check as the driver core already takes care of it
- fix for possible scmi_linux_errmap buffer overflow
- fix to avoid sensor message structure padding
- fix the range check for the maximum number of pending SCMI messages
- fix for various kernel-doc warnings

* tag 'scmi-fixes-5.14' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux:
  firmware: arm_scmi: Fix range check for the maximum number of pending messages
  firmware: arm_scmi: Avoid padding in sensor message structure
  firmware: arm_scmi: Fix kernel doc warnings about return values
  firmware: arm_scpi: Fix kernel doc warnings
  firmware: arm_scmi: Fix kernel doc warnings
  firmware: arm_scmi: Fix possible scmi_linux_errmap buffer overflow
  firmware: arm_scmi: Ensure drivers provide a probe function
  firmware: arm_scmi: Simplify device probe function on the bus

Link: https://lore.kernel.org/r/20210714165831.2617437-1-sudeep.holla@arm.comSigned-off-by: default avatarArnd Bergmann <arnd@arndb.de>
parents d28912d6 bdb8742d
...@@ -104,11 +104,6 @@ static int scmi_dev_probe(struct device *dev) ...@@ -104,11 +104,6 @@ static int scmi_dev_probe(struct device *dev)
{ {
struct scmi_driver *scmi_drv = to_scmi_driver(dev->driver); struct scmi_driver *scmi_drv = to_scmi_driver(dev->driver);
struct scmi_device *scmi_dev = to_scmi_dev(dev); struct scmi_device *scmi_dev = to_scmi_dev(dev);
const struct scmi_device_id *id;
id = scmi_dev_match_id(scmi_dev, scmi_drv);
if (!id)
return -ENODEV;
if (!scmi_dev->handle) if (!scmi_dev->handle)
return -EPROBE_DEFER; return -EPROBE_DEFER;
...@@ -139,6 +134,9 @@ int scmi_driver_register(struct scmi_driver *driver, struct module *owner, ...@@ -139,6 +134,9 @@ int scmi_driver_register(struct scmi_driver *driver, struct module *owner,
{ {
int retval; int retval;
if (!driver->probe)
return -EINVAL;
retval = scmi_protocol_device_request(driver->id_table); retval = scmi_protocol_device_request(driver->id_table);
if (retval) if (retval)
return retval; return retval;
......
...@@ -47,7 +47,6 @@ enum scmi_error_codes { ...@@ -47,7 +47,6 @@ enum scmi_error_codes {
SCMI_ERR_GENERIC = -8, /* Generic Error */ SCMI_ERR_GENERIC = -8, /* Generic Error */
SCMI_ERR_HARDWARE = -9, /* Hardware Error */ SCMI_ERR_HARDWARE = -9, /* Hardware Error */
SCMI_ERR_PROTOCOL = -10,/* Protocol Error */ SCMI_ERR_PROTOCOL = -10,/* Protocol Error */
SCMI_ERR_MAX
}; };
/* List of all SCMI devices active in system */ /* List of all SCMI devices active in system */
...@@ -166,8 +165,10 @@ static const int scmi_linux_errmap[] = { ...@@ -166,8 +165,10 @@ static const int scmi_linux_errmap[] = {
static inline int scmi_to_linux_errno(int errno) static inline int scmi_to_linux_errno(int errno)
{ {
if (errno < SCMI_SUCCESS && errno > SCMI_ERR_MAX) int err_idx = -errno;
return scmi_linux_errmap[-errno];
if (err_idx >= SCMI_SUCCESS && err_idx < ARRAY_SIZE(scmi_linux_errmap))
return scmi_linux_errmap[err_idx];
return -EIO; return -EIO;
} }
...@@ -1025,8 +1026,9 @@ static int __scmi_xfer_info_init(struct scmi_info *sinfo, ...@@ -1025,8 +1026,9 @@ static int __scmi_xfer_info_init(struct scmi_info *sinfo,
const struct scmi_desc *desc = sinfo->desc; const struct scmi_desc *desc = sinfo->desc;
/* Pre-allocated messages, no more than what hdr.seq can support */ /* Pre-allocated messages, no more than what hdr.seq can support */
if (WARN_ON(desc->max_msg >= MSG_TOKEN_MAX)) { if (WARN_ON(!desc->max_msg || desc->max_msg > MSG_TOKEN_MAX)) {
dev_err(dev, "Maximum message of %d exceeds supported %ld\n", dev_err(dev,
"Invalid maximum messages %d, not in range [1 - %lu]\n",
desc->max_msg, MSG_TOKEN_MAX); desc->max_msg, MSG_TOKEN_MAX);
return -EINVAL; return -EINVAL;
} }
...@@ -1137,6 +1139,8 @@ scmi_txrx_setup(struct scmi_info *info, struct device *dev, int prot_id) ...@@ -1137,6 +1139,8 @@ scmi_txrx_setup(struct scmi_info *info, struct device *dev, int prot_id)
* @proto_id and @name: if device was still not existent it is created as a * @proto_id and @name: if device was still not existent it is created as a
* child of the specified SCMI instance @info and its transport properly * child of the specified SCMI instance @info and its transport properly
* initialized as usual. * initialized as usual.
*
* Return: A properly initialized scmi device, NULL otherwise.
*/ */
static inline struct scmi_device * static inline struct scmi_device *
scmi_get_protocol_device(struct device_node *np, struct scmi_info *info, scmi_get_protocol_device(struct device_node *np, struct scmi_info *info,
......
...@@ -1457,6 +1457,8 @@ static void scmi_devm_release_notifier(struct device *dev, void *res) ...@@ -1457,6 +1457,8 @@ static void scmi_devm_release_notifier(struct device *dev, void *res)
* *
* Generic devres managed helper to register a notifier_block against a * Generic devres managed helper to register a notifier_block against a
* protocol event. * protocol event.
*
* Return: 0 on Success
*/ */
static int scmi_devm_notifier_register(struct scmi_device *sdev, static int scmi_devm_notifier_register(struct scmi_device *sdev,
u8 proto_id, u8 evt_id, u8 proto_id, u8 evt_id,
...@@ -1523,6 +1525,8 @@ static int scmi_devm_notifier_match(struct device *dev, void *res, void *data) ...@@ -1523,6 +1525,8 @@ static int scmi_devm_notifier_match(struct device *dev, void *res, void *data)
* Generic devres managed helper to explicitly un-register a notifier_block * Generic devres managed helper to explicitly un-register a notifier_block
* against a protocol event, which was previously registered using the above * against a protocol event, which was previously registered using the above
* @scmi_devm_notifier_register. * @scmi_devm_notifier_register.
*
* Return: 0 on Success
*/ */
static int scmi_devm_notifier_unregister(struct scmi_device *sdev, static int scmi_devm_notifier_unregister(struct scmi_device *sdev,
u8 proto_id, u8 evt_id, u8 proto_id, u8 evt_id,
......
...@@ -166,7 +166,8 @@ struct scmi_msg_sensor_reading_get { ...@@ -166,7 +166,8 @@ struct scmi_msg_sensor_reading_get {
struct scmi_resp_sensor_reading_complete { struct scmi_resp_sensor_reading_complete {
__le32 id; __le32 id;
__le64 readings; __le32 readings_low;
__le32 readings_high;
}; };
struct scmi_sensor_reading_resp { struct scmi_sensor_reading_resp {
...@@ -717,7 +718,8 @@ static int scmi_sensor_reading_get(const struct scmi_protocol_handle *ph, ...@@ -717,7 +718,8 @@ static int scmi_sensor_reading_get(const struct scmi_protocol_handle *ph,
resp = t->rx.buf; resp = t->rx.buf;
if (le32_to_cpu(resp->id) == sensor_id) if (le32_to_cpu(resp->id) == sensor_id)
*value = get_unaligned_le64(&resp->readings); *value =
get_unaligned_le64(&resp->readings_low);
else else
ret = -EPROTO; ret = -EPROTO;
} }
......
...@@ -101,6 +101,10 @@ struct scmi_clk_proto_ops { ...@@ -101,6 +101,10 @@ struct scmi_clk_proto_ops {
* to sustained performance level mapping * to sustained performance level mapping
* @est_power_get: gets the estimated power cost for a given performance domain * @est_power_get: gets the estimated power cost for a given performance domain
* at a given frequency * at a given frequency
* @fast_switch_possible: indicates if fast DVFS switching is possible or not
* for a given device
* @power_scale_mw_get: indicates if the power values provided are in milliWatts
* or in some other (abstract) scale
*/ */
struct scmi_perf_proto_ops { struct scmi_perf_proto_ops {
int (*limits_set)(const struct scmi_protocol_handle *ph, u32 domain, int (*limits_set)(const struct scmi_protocol_handle *ph, u32 domain,
...@@ -153,7 +157,7 @@ struct scmi_power_proto_ops { ...@@ -153,7 +157,7 @@ struct scmi_power_proto_ops {
}; };
/** /**
* scmi_sensor_reading - represent a timestamped read * struct scmi_sensor_reading - represent a timestamped read
* *
* Used by @reading_get_timestamped method. * Used by @reading_get_timestamped method.
* *
...@@ -167,7 +171,7 @@ struct scmi_sensor_reading { ...@@ -167,7 +171,7 @@ struct scmi_sensor_reading {
}; };
/** /**
* scmi_range_attrs - specifies a sensor or axis values' range * struct scmi_range_attrs - specifies a sensor or axis values' range
* @min_range: The minimum value which can be represented by the sensor/axis. * @min_range: The minimum value which can be represented by the sensor/axis.
* @max_range: The maximum value which can be represented by the sensor/axis. * @max_range: The maximum value which can be represented by the sensor/axis.
*/ */
...@@ -177,7 +181,7 @@ struct scmi_range_attrs { ...@@ -177,7 +181,7 @@ struct scmi_range_attrs {
}; };
/** /**
* scmi_sensor_axis_info - describes one sensor axes * struct scmi_sensor_axis_info - describes one sensor axes
* @id: The axes ID. * @id: The axes ID.
* @type: Axes type. Chosen amongst one of @enum scmi_sensor_class. * @type: Axes type. Chosen amongst one of @enum scmi_sensor_class.
* @scale: Power-of-10 multiplier applied to the axis unit. * @scale: Power-of-10 multiplier applied to the axis unit.
...@@ -205,8 +209,8 @@ struct scmi_sensor_axis_info { ...@@ -205,8 +209,8 @@ struct scmi_sensor_axis_info {
}; };
/** /**
* scmi_sensor_intervals_info - describes number and type of available update * struct scmi_sensor_intervals_info - describes number and type of available
* intervals * update intervals
* @segmented: Flag for segmented intervals' representation. When True there * @segmented: Flag for segmented intervals' representation. When True there
* will be exactly 3 intervals in @desc, with each entry * will be exactly 3 intervals in @desc, with each entry
* representing a member of a segment in this order: * representing a member of a segment in this order:
......
...@@ -51,6 +51,14 @@ struct scpi_sensor_info { ...@@ -51,6 +51,14 @@ struct scpi_sensor_info {
* OPP is an index to the list return by @dvfs_get_info * OPP is an index to the list return by @dvfs_get_info
* @dvfs_get_info: returns the DVFS capabilities of the given power * @dvfs_get_info: returns the DVFS capabilities of the given power
* domain. It includes the OPP list and the latency information * domain. It includes the OPP list and the latency information
* @device_domain_id: gets the scpi domain id for a given device
* @get_transition_latency: gets the DVFS transition latency for a given device
* @add_opps_to_device: adds all the OPPs for a given device
* @sensor_get_capability: get the list of capabilities for the sensors
* @sensor_get_info: get the information of the specified sensor
* @sensor_get_value: gets the current value of the sensor
* @device_get_power_state: gets the power state of a power domain
* @device_set_power_state: sets the power state of a power domain
*/ */
struct scpi_ops { struct scpi_ops {
u32 (*get_version)(void); u32 (*get_version)(void);
......
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