|
@@ -2480,6 +2480,134 @@ const struct ti_sci_handle *devm_ti_sci_get_by_phandle(struct device *dev,
|
|
|
}
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(devm_ti_sci_get_by_phandle);
|
|
EXPORT_SYMBOL_GPL(devm_ti_sci_get_by_phandle);
|
|
|
|
|
|
|
|
|
|
+/*
|
|
|
|
|
+ * ti_sci_get_free_resource() - Get a free resource from TISCI resource.
|
|
|
|
|
+ * @res: Pointer to the TISCI resource
|
|
|
|
|
+ *
|
|
|
|
|
+ * Return: resource num if all went ok else TI_SCI_RESOURCE_NULL.
|
|
|
|
|
+ */
|
|
|
|
|
+u16 ti_sci_get_free_resource(struct ti_sci_resource *res)
|
|
|
|
|
+{
|
|
|
|
|
+ unsigned long flags;
|
|
|
|
|
+ u16 set, free_bit;
|
|
|
|
|
+
|
|
|
|
|
+ raw_spin_lock_irqsave(&res->lock, flags);
|
|
|
|
|
+ for (set = 0; set < res->sets; set++) {
|
|
|
|
|
+ free_bit = find_first_zero_bit(res->desc[set].res_map,
|
|
|
|
|
+ res->desc[set].num);
|
|
|
|
|
+ if (free_bit != res->desc[set].num) {
|
|
|
|
|
+ set_bit(free_bit, res->desc[set].res_map);
|
|
|
|
|
+ raw_spin_unlock_irqrestore(&res->lock, flags);
|
|
|
|
|
+ return res->desc[set].start + free_bit;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ raw_spin_unlock_irqrestore(&res->lock, flags);
|
|
|
|
|
+
|
|
|
|
|
+ return TI_SCI_RESOURCE_NULL;
|
|
|
|
|
+}
|
|
|
|
|
+EXPORT_SYMBOL_GPL(ti_sci_get_free_resource);
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * ti_sci_release_resource() - Release a resource from TISCI resource.
|
|
|
|
|
+ * @res: Pointer to the TISCI resource
|
|
|
|
|
+ */
|
|
|
|
|
+void ti_sci_release_resource(struct ti_sci_resource *res, u16 id)
|
|
|
|
|
+{
|
|
|
|
|
+ unsigned long flags;
|
|
|
|
|
+ u16 set;
|
|
|
|
|
+
|
|
|
|
|
+ raw_spin_lock_irqsave(&res->lock, flags);
|
|
|
|
|
+ for (set = 0; set < res->sets; set++) {
|
|
|
|
|
+ if (res->desc[set].start <= id &&
|
|
|
|
|
+ (res->desc[set].num + res->desc[set].start) > id)
|
|
|
|
|
+ clear_bit(id - res->desc[set].start,
|
|
|
|
|
+ res->desc[set].res_map);
|
|
|
|
|
+ }
|
|
|
|
|
+ raw_spin_unlock_irqrestore(&res->lock, flags);
|
|
|
|
|
+}
|
|
|
|
|
+EXPORT_SYMBOL_GPL(ti_sci_release_resource);
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * devm_ti_sci_get_of_resource() - Get a TISCI resource assigned to a device
|
|
|
|
|
+ * @handle: TISCI handle
|
|
|
|
|
+ * @dev: Device pointer to which the resource is assigned
|
|
|
|
|
+ * @of_prop: property name by which the resource are represented
|
|
|
|
|
+ *
|
|
|
|
|
+ * Note: This function expects of_prop to be in the form of tuples
|
|
|
|
|
+ * <type, subtype>. Allocates and initializes ti_sci_resource structure
|
|
|
|
|
+ * for each of_prop. Client driver can directly call
|
|
|
|
|
+ * ti_sci_(get_free, release)_resource apis for handling the resource.
|
|
|
|
|
+ *
|
|
|
|
|
+ * Return: Pointer to ti_sci_resource if all went well else appropriate
|
|
|
|
|
+ * error pointer.
|
|
|
|
|
+ */
|
|
|
|
|
+struct ti_sci_resource *
|
|
|
|
|
+devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle,
|
|
|
|
|
+ struct device *dev, u32 dev_id, char *of_prop)
|
|
|
|
|
+{
|
|
|
|
|
+ u32 resource_subtype;
|
|
|
|
|
+ u16 resource_type;
|
|
|
|
|
+ struct ti_sci_resource *res;
|
|
|
|
|
+ int sets, i, ret;
|
|
|
|
|
+
|
|
|
|
|
+ res = devm_kzalloc(dev, sizeof(*res), GFP_KERNEL);
|
|
|
|
|
+ if (!res)
|
|
|
|
|
+ return ERR_PTR(-ENOMEM);
|
|
|
|
|
+
|
|
|
|
|
+ sets = of_property_count_elems_of_size(dev_of_node(dev), of_prop,
|
|
|
|
|
+ sizeof(u32));
|
|
|
|
|
+ if (sets < 0) {
|
|
|
|
|
+ dev_err(dev, "%s resource type ids not available\n", of_prop);
|
|
|
|
|
+ return ERR_PTR(sets);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ res->sets = sets;
|
|
|
|
|
+
|
|
|
|
|
+ res->desc = devm_kcalloc(dev, res->sets, sizeof(*res->desc),
|
|
|
|
|
+ GFP_KERNEL);
|
|
|
|
|
+ if (!res->desc)
|
|
|
|
|
+ return ERR_PTR(-ENOMEM);
|
|
|
|
|
+
|
|
|
|
|
+ ret = ti_sci_get_resource_type(handle_to_ti_sci_info(handle), dev_id,
|
|
|
|
|
+ &resource_type);
|
|
|
|
|
+ if (ret) {
|
|
|
|
|
+ dev_err(dev, "No valid resource type for %u\n", dev_id);
|
|
|
|
|
+ return ERR_PTR(-EINVAL);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for (i = 0; i < res->sets; i++) {
|
|
|
|
|
+ ret = of_property_read_u32_index(dev_of_node(dev), of_prop, i,
|
|
|
|
|
+ &resource_subtype);
|
|
|
|
|
+ if (ret)
|
|
|
|
|
+ return ERR_PTR(-EINVAL);
|
|
|
|
|
+
|
|
|
|
|
+ ret = handle->ops.rm_core_ops.get_range(handle, dev_id,
|
|
|
|
|
+ resource_subtype,
|
|
|
|
|
+ &res->desc[i].start,
|
|
|
|
|
+ &res->desc[i].num);
|
|
|
|
|
+ if (ret) {
|
|
|
|
|
+ dev_err(dev, "type %d subtype %d not allocated for host %d\n",
|
|
|
|
|
+ resource_type, resource_subtype,
|
|
|
|
|
+ handle_to_ti_sci_info(handle)->host_id);
|
|
|
|
|
+ return ERR_PTR(ret);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ dev_dbg(dev, "res type = %d, subtype = %d, start = %d, num = %d\n",
|
|
|
|
|
+ resource_type, resource_subtype, res->desc[i].start,
|
|
|
|
|
+ res->desc[i].num);
|
|
|
|
|
+
|
|
|
|
|
+ res->desc[i].res_map =
|
|
|
|
|
+ devm_kzalloc(dev, BITS_TO_LONGS(res->desc[i].num) *
|
|
|
|
|
+ sizeof(*res->desc[i].res_map), GFP_KERNEL);
|
|
|
|
|
+ if (!res->desc[i].res_map)
|
|
|
|
|
+ return ERR_PTR(-ENOMEM);
|
|
|
|
|
+ }
|
|
|
|
|
+ raw_spin_lock_init(&res->lock);
|
|
|
|
|
+
|
|
|
|
|
+ return res;
|
|
|
|
|
+}
|
|
|
|
|
+EXPORT_SYMBOL_GPL(devm_ti_sci_get_of_resource);
|
|
|
|
|
+
|
|
|
static int tisci_reboot_handler(struct notifier_block *nb, unsigned long mode,
|
|
static int tisci_reboot_handler(struct notifier_block *nb, unsigned long mode,
|
|
|
void *cmd)
|
|
void *cmd)
|
|
|
{
|
|
{
|