diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c index 732165b77e384..f56a283ea35de 100644 --- a/drivers/dpll/dpll_core.c +++ b/drivers/dpll/dpll_core.c @@ -15,6 +15,7 @@ #include "dpll_core.h" static DEFINE_MUTEX(dpll_device_xa_lock); + static DEFINE_XARRAY_FLAGS(dpll_device_xa, XA_FLAGS_ALLOC); #define DPLL_REGISTERED XA_MARK_1 @@ -23,6 +24,7 @@ static DEFINE_XARRAY_FLAGS(dpll_device_xa, XA_FLAGS_ALLOC); #define ASSERT_DPLL_NOT_REGISTERED(d) \ WARN_ON_ONCE(xa_get_mark(&dpll_device_xa, (d)->id, DPLL_REGISTERED)) +#define IS_TYPE_SOURCE(t) (t == DPLL_PIN_TYPE_SOURCE) int for_each_dpll_device(int id, int (*cb)(struct dpll_device *, void *), void *data) @@ -69,6 +71,7 @@ struct dpll_device *dpll_device_get_by_name(const char *name) return ret; } +EXPORT_SYMBOL_GPL(dpll_device_get_by_name); void *dpll_priv(struct dpll_device *dpll) { @@ -76,6 +79,18 @@ void *dpll_priv(struct dpll_device *dpll) } EXPORT_SYMBOL_GPL(dpll_priv); +void *pin_priv(struct dpll_pin *pin) +{ + return pin->priv; +} +EXPORT_SYMBOL_GPL(pin_priv); + +int pin_id(struct dpll_pin *pin) +{ + return pin->id; +} +EXPORT_SYMBOL_GPL(pin_id); + static void dpll_device_release(struct device *dev) { struct dpll_device *dpll; @@ -92,7 +107,7 @@ static struct class dpll_class = { }; struct dpll_device *dpll_device_alloc(struct dpll_device_ops *ops, const char *name, - int sources_count, int outputs_count, void *priv) + void *priv) { struct dpll_device *dpll; int ret; @@ -104,16 +119,19 @@ struct dpll_device *dpll_device_alloc(struct dpll_device_ops *ops, const char *n mutex_init(&dpll->lock); dpll->ops = ops; dpll->dev.class = &dpll_class; - dpll->sources_count = sources_count; - dpll->outputs_count = outputs_count; mutex_lock(&dpll_device_xa_lock); ret = xa_alloc(&dpll_device_xa, &dpll->id, dpll, xa_limit_16b, GFP_KERNEL); if (ret) goto error; - dev_set_name(&dpll->dev, "%s%d", name ? name : "dpll", dpll->id); + if (name) + dev_set_name(&dpll->dev, "%s", name); + else + dev_set_name(&dpll->dev, "%s%d", "dpll", dpll->id); + mutex_unlock(&dpll_device_xa_lock); dpll->priv = priv; + xa_init_flags(&dpll->pins, XA_FLAGS_ALLOC); dpll_notify_device_create(dpll->id, dev_name(&dpll->dev)); @@ -131,6 +149,11 @@ void dpll_device_free(struct dpll_device *dpll) if (!dpll) return; +// if (!xa_empty(dpll->pins)) +// return; + + xa_destroy(&dpll->pins); + mutex_destroy(&dpll->lock); kfree(dpll); } @@ -157,6 +180,236 @@ void dpll_device_unregister(struct dpll_device *dpll) } EXPORT_SYMBOL_GPL(dpll_device_unregister); +void dpll_init_pin(struct dpll_pin **pin, enum dpll_pin_type type, + struct dpll_pin_ops *ops, void *priv, const char *name, + int id) +{ + *pin = kmalloc(sizeof(**pin), GFP_KERNEL); + + (*pin)->ops = ops; + (*pin)->type = type; + (*pin)->priv = priv; + (*pin)->id = id; + refcount_set(&((*pin)->ref_count), 0); + if (name) + snprintf((*pin)->name, PIN_NAME_LENGTH, "%s", name); + else + snprintf((*pin)->name, PIN_NAME_LENGTH, "%s%d", + IS_TYPE_SOURCE((*pin)->type) ? "source" : "output", + (*pin)->id); +} +EXPORT_SYMBOL_GPL(dpll_init_pin); + +static int pin_register(struct xarray *pins, struct dpll_pin *pin) +{ + struct dpll_pin *pos; + unsigned long index; + int ret; + u32 id; + + xa_for_each(pins, index, pos) { + if (pos == pin) + return -EEXIST; + } + + ret = xa_alloc(pins, &id, pin, xa_limit_16b, GFP_KERNEL); + if (!ret) + xa_set_mark(pins, id, PIN_TYPE_TO_MARK(pin->type)); + + return ret; +} + +static void change_pin_count(struct dpll_device *dpll, struct dpll_pin *pin, + bool increment) +{ + if (IS_TYPE_SOURCE(pin->type)) { + if (increment) + dpll->sources_count++; + else + dpll->sources_count--; + } else { + if (increment) + dpll->outputs_count++; + else + dpll->outputs_count--; + } +} + +int dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin) +{ + int ret; + + mutex_lock(&dpll->lock); + ret = pin_register(&dpll->pins, pin); + if (!ret) { + refcount_inc(&pin->ref_count); + change_pin_count(dpll, pin, true); + xa_set_mark(&dpll->pins, dpll->id, DPLL_REGISTERED); + } + + mutex_unlock(&dpll->lock); + + if (!ret) + dpll_notify_pin_register(dpll->id, pin->id); + + return ret; + +} +EXPORT_SYMBOL_GPL(dpll_pin_register); + +static int pin_deregister(struct xarray *xa_pins, struct dpll_pin *pin) +{ + struct dpll_pin *pos; + unsigned long index; + + xa_for_each(xa_pins, index, pos) { + if (pos == pin) { + if (pin == xa_erase(xa_pins, index)) + return 0; + break; + } + } + + return -ENOENT; +} + +int dpll_pin_deregister(struct dpll_device *dpll, struct dpll_pin *pin) +{ + int ret = 0; + + if (xa_empty(&dpll->pins)) + return -ENOENT; + + mutex_lock(&dpll->lock); + ret = pin_deregister(&dpll->pins, pin); + if (!ret) + change_pin_count(dpll, pin, false); + + mutex_unlock(&dpll->lock); + + if (!ret) { + refcount_dec(&pin->ref_count); + dpll_notify_pin_deregister(dpll->id, pin->id); + } + + return ret; +} +EXPORT_SYMBOL_GPL(dpll_pin_deregister); + +void dpll_pin_free(struct dpll_device *dpll, struct dpll_pin *pin) +{ + struct dpll_pin *pos; + unsigned long index; + bool pin_found; + + xa_for_each(&dpll->pins, index, pos) { + if (pos == pin) + pin_found = true; + } + + if (!pin_found) + return; + + if (refcount_read(&pin->ref_count) != 0) + return; + + xa_destroy(&pin->muxed_pins); + kfree(pin); +} +EXPORT_SYMBOL_GPL(dpll_pin_free); + +void dpll_muxed_pin_free(struct dpll_pin *parent_pin, struct dpll_pin *pin) +{ + struct dpll_pin *pos; + unsigned long index; + bool pin_found; + + xa_for_each(&parent_pin->muxed_pins, index, pos) { + if (pos == pin) + pin_found = true; + } + + if (!pin_found) + return; + + if (refcount_read(&pin->ref_count) != 0) + return; + + xa_destroy(&pin->muxed_pins); + kfree(pin); +} +EXPORT_SYMBOL_GPL(dpll_muxed_pin_free); + +int dpll_muxed_pin_register(struct dpll_pin *parent_pin, struct dpll_pin *pin) +{ + int ret; + + ret = pin_register(&parent_pin->muxed_pins, pin); + + if (!ret) { + refcount_inc(&pin->ref_count); + dpll_notify_muxed_pin_register(parent_pin, pin->id); + } + + return ret; +} +EXPORT_SYMBOL_GPL(dpll_muxed_pin_register); + +int dpll_muxed_pin_deregister(struct dpll_pin *parent_pin, struct dpll_pin *pin) +{ + int ret = 0; + + if (xa_empty(&parent_pin->muxed_pins)) + return -ENOENT; + + mutex_lock(&parent_pin->lock); + ret = pin_deregister(&parent_pin->muxed_pins, pin); + mutex_unlock(&parent_pin->lock); + + if (!ret) { + refcount_dec(&pin->ref_count); + dpll_notify_muxed_pin_deregister(parent_pin, pin->id); + } + + return ret; +} +EXPORT_SYMBOL_GPL(dpll_muxed_pin_deregister); + +struct dpll_pin *dpll_pin_get_by_name(struct dpll_device *dpll, + const char *name) +{ + struct dpll_pin *pos, *pin = NULL; + unsigned long index; + + mutex_lock(&dpll->lock); + xa_for_each(&dpll->pins, index, pos) { + if (!strncmp(pos->name, name, PIN_NAME_LENGTH)) { + pin = pos; + break; + } + } + mutex_unlock(&dpll->lock); + + return pin; +} +EXPORT_SYMBOL_GPL(dpll_pin_get_by_name); + +struct dpll_pin *dpll_pin_get_by_id(struct dpll_device *dpll, int id) +{ + struct dpll_pin *pos, *pin = NULL; + unsigned long index; + + xa_for_each(&dpll->pins, index, pos) { + if (pos->id == id) { + pin = pos; + break; + } + } + + return pin; +} +EXPORT_SYMBOL_GPL(dpll_pin_get_by_id); + static int __init dpll_init(void) { int ret; diff --git a/drivers/dpll/dpll_core.h b/drivers/dpll/dpll_core.h index 4b6fc9eb228fb..7db9b23b4a084 100644 --- a/drivers/dpll/dpll_core.h +++ b/drivers/dpll/dpll_core.h @@ -10,15 +10,50 @@ #include "dpll_netlink.h" +#define PIN_SOURCE XA_MARK_1 +#define PIN_OUTPUT XA_MARK_2 +#define PIN_TYPE_TO_MARK(t) (t == DPLL_PIN_TYPE_SOURCE ? PIN_SOURCE : PIN_OUTPUT) +#define __FOR_EACH_PIN(dpll, index, count, pin, type) \ + count = type == DPLL_PIN_TYPE_SOURCE ? \ + dpll->sources_count : dpll->outputs_count; \ + xa_for_each_marked(&dpll->pins, index, pin, PIN_TYPE_TO_MARK(type)) +#define FOR_EACH_SOURCE(dpll, index, count, pin) \ + __FOR_EACH_PIN(dpll, index, count, pin, DPLL_PIN_TYPE_SOURCE) +#define FOR_EACH_OUTPUT(dpll, index, count, pin) \ + __FOR_EACH_PIN(dpll, index, count, pin, DPLL_PIN_TYPE_OUTPUT) + +/** + * struct dpll_pin - structure for a dpll pin + * @id: unique id number for each pin + * @type: type of the pin + * @ref_count: count number of dpll's that registered this pin + * @ops: operations this &dpll_pin supports + * @lock: mutex to serialize operations + * @priv: pointer to private information of owner + * @muxed_pins: array of muxed pins + * @name: name to distinguish the pin + */ +struct dpll_pin { + int id; + enum dpll_pin_type type; + refcount_t ref_count; + struct dpll_pin_ops *ops; + struct mutex lock; + void *priv; + struct xarray muxed_pins; + char name[PIN_NAME_LENGTH]; +}; + /** * struct dpll_device - structure for a DPLL device * @id: unique id number for each edvice * @dev: &struct device for this dpll device - * @sources_count: amount of input sources this dpll_device supports - * @outputs_count: amount of outputs this dpll_device supports + * @sources_count: amount of input sources this dpll_device supports + * @outputs_count: amount of outputs this dpll_device supports * @ops: operations this &dpll_device supports * @lock: mutex to serialize operations * @priv: pointer to private information of owner + * @pins: list of pointers to pins registered with this dpll */ struct dpll_device { int id; @@ -28,6 +63,7 @@ struct dpll_device { struct dpll_device_ops *ops; struct mutex lock; void *priv; + struct xarray pins; }; #define to_dpll_device(_dev) \ @@ -38,4 +74,7 @@ int for_each_dpll_device(int id, int (*cb)(struct dpll_device *, void *), struct dpll_device *dpll_device_get_by_id(int id); struct dpll_device *dpll_device_get_by_name(const char *name); void dpll_device_unregister(struct dpll_device *dpll); +void dpll_init_pin(struct dpll_pin **pin, enum dpll_pin_type type, + struct dpll_pin_ops *ops, void *priv, + const char *name, int id); #endif diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c index e3604c10b59e2..6b081d19cf0f3 100644 --- a/drivers/dpll/dpll_netlink.c +++ b/drivers/dpll/dpll_netlink.c @@ -23,24 +23,24 @@ static const struct nla_policy dpll_genl_get_policy[] = { [DPLLA_DEVICE_ID] = { .type = NLA_U32 }, [DPLLA_DEVICE_NAME] = { .type = NLA_STRING, .len = DPLL_NAME_LENGTH }, - [DPLLA_DEVICE_SRC_SELECT_MODE] = { .type = NLA_U32 }, [DPLLA_FLAGS] = { .type = NLA_U32 }, }; +static const struct nla_policy dpll_genl_set_pin_type_policy[] = { + [DPLLA_DEVICE_ID] = { .type = NLA_U32 }, + [DPLLA_PIN_ID] = { .type = NLA_U32 }, + [DPLLA_PIN_TYPE] = { .type = NLA_U32 }, +}; + static const struct nla_policy dpll_genl_set_source_policy[] = { [DPLLA_DEVICE_ID] = { .type = NLA_U32 }, - [DPLLA_SOURCE_ID] = { .type = NLA_U32 }, - [DPLLA_SOURCE_TYPE] = { .type = NLA_U32 }, - [DPLLA_SOURCE_NAME] = { .type = NLA_STRING, - .len = DPLL_NAME_LENGTH }, + [DPLLA_PIN_ID] = { .type = NLA_U32 }, }; -static const struct nla_policy dpll_genl_set_output_policy[] = { +static const struct nla_policy dpll_genl_set_pin_flags_policy[] = { [DPLLA_DEVICE_ID] = { .type = NLA_U32 }, - [DPLLA_OUTPUT_ID] = { .type = NLA_U32 }, - [DPLLA_OUTPUT_TYPE] = { .type = NLA_U32 }, - [DPLLA_OUTPUT_NAME] = { .type = NLA_STRING, - .len = DPLL_NAME_LENGTH }, + [DPLLA_PIN_ID] = { .type = NLA_U32 }, + [DPLLA_PIN_FLAGS] = { .type = NLA_U32 }, }; static const struct nla_policy dpll_genl_set_src_select_mode_policy[] = { @@ -50,23 +50,26 @@ static const struct nla_policy dpll_genl_set_src_select_mode_policy[] = { static const struct nla_policy dpll_genl_set_source_prio_policy[] = { [DPLLA_DEVICE_ID] = { .type = NLA_U32 }, - [DPLLA_SOURCE_ID] = { .type = NLA_U32 }, - [DPLLA_SOURCE_PRIO] = { .type = NLA_U32 }, + [DPLLA_PIN_ID] = { .type = NLA_U32 }, + [DPLLA_SOURCE_PIN_PRIO] = { .type = NLA_U32 }, }; struct param { struct netlink_callback *cb; struct dpll_device *dpll; + struct dpll_pin *dpll_shared_pin; struct sk_buff *msg; int dpll_id; int dpll_src_select_mode; - int dpll_source_id; - int dpll_source_type; + int dpll_pin_type; int dpll_source_prio; - int dpll_output_id; - int dpll_output_type; + int dpll_pin_id; + int dpll_pin_flags; + int dpll_parent_pin_id; int dpll_status; int dpll_event_group; + int dpll_event; + const char *dpll_name; }; @@ -102,45 +105,44 @@ static int __dpll_cmd_device_dump_one(struct dpll_device *dpll, static int __dpll_cmd_dump_sources(struct dpll_device *dpll, struct sk_buff *msg) { - int i, ret = 0, type, prio; + int ret = 0, type, prio, count; struct nlattr *src_attr; - const char *name; + struct dpll_pin *pin; + unsigned long i; - for (i = 0; i < dpll->sources_count; i++) { + FOR_EACH_SOURCE(dpll, i, count, pin) { src_attr = nla_nest_start(msg, DPLLA_SOURCE); if (!src_attr) { ret = -EMSGSIZE; break; } - type = dpll->ops->get_source_type(dpll, i); - if (nla_put_u32(msg, DPLLA_SOURCE_ID, i) || - nla_put_u32(msg, DPLLA_SOURCE_TYPE, type)) { + type = pin->ops->get_type(pin); + if (nla_put_u32(msg, DPLLA_PIN_ID, pin->id) || + nla_put_u32(msg, DPLLA_PIN_TYPE, type)) { nla_nest_cancel(msg, src_attr); ret = -EMSGSIZE; break; } - if (dpll->ops->get_source_supported) { + if (pin->ops->is_type_supported) { for (type = 0; type <= DPLL_TYPE_MAX; type++) { - ret = dpll->ops->get_source_supported(dpll, i, type); - if (ret && nla_put_u32(msg, DPLLA_SOURCE_SUPPORTED, type)) { + ret = pin->ops->is_type_supported(pin, type); + if (ret && nla_put_u32(msg, DPLLA_PIN_TYPE_SUPPORTED, type)) { ret = -EMSGSIZE; break; } } ret = 0; } - if (dpll->ops->get_source_prio) { - prio = dpll->ops->get_source_prio(dpll, i); - if (nla_put_u32(msg, DPLLA_SOURCE_PRIO, prio)) { + if (dpll->ops->get_prio) { + prio = dpll->ops->get_prio(dpll, pin); + if (nla_put_u32(msg, DPLLA_SOURCE_PIN_PRIO, prio)) { nla_nest_cancel(msg, src_attr); ret = -EMSGSIZE; break; } } - if (dpll->ops->get_source_name) { - name = dpll->ops->get_source_name(dpll, i); - if (name && nla_put_string(msg, DPLLA_SOURCE_NAME, - name)) { + if (pin->name) { + if (nla_put_string(msg, DPLLA_PIN_NAME, pin->name)) { nla_nest_cancel(msg, src_attr); ret = -EMSGSIZE; break; @@ -155,42 +157,40 @@ static int __dpll_cmd_dump_sources(struct dpll_device *dpll, static int __dpll_cmd_dump_outputs(struct dpll_device *dpll, struct sk_buff *msg) { + int ret = 0, type, count; struct nlattr *out_attr; - int i, ret = 0, type; - const char *name; + struct dpll_pin *pin; + unsigned long i; - for (i = 0; i < dpll->outputs_count; i++) { + FOR_EACH_OUTPUT(dpll, i, count, pin) { out_attr = nla_nest_start(msg, DPLLA_OUTPUT); if (!out_attr) { ret = -EMSGSIZE; break; } - type = dpll->ops->get_output_type(dpll, i); - if (nla_put_u32(msg, DPLLA_OUTPUT_ID, i) || - nla_put_u32(msg, DPLLA_OUTPUT_TYPE, type)) { + type = pin->ops->get_type(pin); + if (nla_put_u32(msg, DPLLA_PIN_ID, pin->id) || + nla_put_u32(msg, DPLLA_PIN_TYPE, type)) { nla_nest_cancel(msg, out_attr); ret = -EMSGSIZE; break; } - if (dpll->ops->get_output_supported) { + if (pin->ops->is_type_supported) { for (type = 0; type <= DPLL_TYPE_MAX; type++) { - ret = dpll->ops->get_output_supported(dpll, i, type); - if (ret && nla_put_u32(msg, DPLLA_OUTPUT_SUPPORTED, type)) { + ret = pin->ops->is_type_supported(pin, type); + if (ret && nla_put_u32(msg, DPLLA_PIN_TYPE_SUPPORTED, type)) { ret = -EMSGSIZE; break; } } ret = 0; } - if (dpll->ops->get_output_name) { - name = dpll->ops->get_output_name(dpll, i); - if (name && nla_put_string(msg, DPLLA_OUTPUT_NAME, - name)) { - nla_nest_cancel(msg, out_attr); - ret = -EMSGSIZE; - break; - } + if (nla_put_string(msg, DPLLA_PIN_NAME, pin->name)) { + nla_nest_cancel(msg, out_attr); + ret = -EMSGSIZE; + break; } + nla_nest_end(msg, out_attr); } @@ -265,13 +265,13 @@ dpll_device_dump_one(struct dpll_device *dpll, struct sk_buff *msg, if (ret) goto out_unlock; - if (flags & DPLL_FLAG_SOURCES && dpll->ops->get_source_type) { + if (flags & DPLL_FLAG_SOURCES) { ret = __dpll_cmd_dump_sources(dpll, msg); if (ret) goto out_unlock; } - if (flags & DPLL_FLAG_OUTPUTS && dpll->ops->get_output_type) { + if (flags & DPLL_FLAG_OUTPUTS) { ret = __dpll_cmd_dump_outputs(dpll, msg); if (ret) goto out_unlock; @@ -294,54 +294,85 @@ dpll_device_dump_one(struct dpll_device *dpll, struct sk_buff *msg, return ret; } -static int dpll_genl_cmd_set_source(struct sk_buff *skb, struct genl_info *info) +static int dpll_genl_cmd_set_pin_type(struct sk_buff *skb, + struct genl_info *info) { struct dpll_device *dpll = info->user_ptr[0]; struct nlattr **attrs = info->attrs; - int ret = 0, src_id, type; + int ret = 0, pin_id, type; + struct dpll_pin *pin; - if (!attrs[DPLLA_SOURCE_ID] || - !attrs[DPLLA_SOURCE_TYPE]) + if (!attrs[DPLLA_PIN_ID] || + !attrs[DPLLA_PIN_TYPE]) return -EINVAL; - if (!dpll->ops->set_source_type) - return -EOPNOTSUPP; - - src_id = nla_get_u32(attrs[DPLLA_SOURCE_ID]); - type = nla_get_u32(attrs[DPLLA_SOURCE_TYPE]); + pin_id = nla_get_u32(attrs[DPLLA_PIN_ID]); + type = nla_get_u32(attrs[DPLLA_PIN_TYPE]); mutex_lock(&dpll->lock); - ret = dpll->ops->set_source_type(dpll, src_id, type); + pin = dpll_pin_get_by_id(dpll, pin_id); + if (!pin || !pin->ops || !pin->ops->set_type) + ret = -EOPNOTSUPP; + else + ret = pin->ops->set_type(pin, type); mutex_unlock(&dpll->lock); if (!ret) - dpll_notify_source_change(dpll->id, src_id, type); + dpll_notify_pin_type_change(dpll->id, pin_id, type); return ret; } -static int dpll_genl_cmd_set_output(struct sk_buff *skb, struct genl_info *info) +static int dpll_genl_cmd_set_source(struct sk_buff *skb, struct genl_info *info) { struct dpll_device *dpll = info->user_ptr[0]; struct nlattr **attrs = info->attrs; - int ret = 0, out_id, type; + int ret = 0, src_id; + struct dpll_pin *pin; - if (!attrs[DPLLA_OUTPUT_ID] || - !attrs[DPLLA_OUTPUT_TYPE]) + if (!attrs[DPLLA_PIN_ID]) return -EINVAL; - if (!dpll->ops->set_output_type) - return -EOPNOTSUPP; + src_id = nla_get_u32(attrs[DPLLA_PIN_ID]); + + mutex_lock(&dpll->lock); + pin = dpll_pin_get_by_id(dpll, src_id); + if (!pin || !pin->ops || !pin->ops->set_source) + ret = -EOPNOTSUPP; + else + ret = pin->ops->set_source(pin, dpll, src_id); + mutex_unlock(&dpll->lock); + + if (!ret) + dpll_notify_source_change(dpll->id, src_id); + + return ret; +} + +static int dpll_genl_cmd_set_pin_flags(struct sk_buff *skb, struct genl_info *info) +{ + struct dpll_device *dpll = info->user_ptr[0]; + struct nlattr **attrs = info->attrs; + int ret = 0, pin_id, flags; + struct dpll_pin *pin; - out_id = nla_get_u32(attrs[DPLLA_OUTPUT_ID]); - type = nla_get_u32(attrs[DPLLA_OUTPUT_TYPE]); + if (!attrs[DPLLA_PIN_ID] || + !attrs[DPLLA_PIN_FLAGS]) + return -EINVAL; + + pin_id = nla_get_u32(attrs[DPLLA_PIN_ID]); + flags = nla_get_u32(attrs[DPLLA_PIN_FLAGS]); mutex_lock(&dpll->lock); - ret = dpll->ops->set_output_type(dpll, out_id, type); + pin = dpll_pin_get_by_id(dpll, pin_id); + if (!pin || !pin->ops || !pin->ops->set_flags) + ret = -EOPNOTSUPP; + else + ret = pin->ops->set_flags(pin, dpll, flags); mutex_unlock(&dpll->lock); if (!ret) - dpll_notify_output_change(dpll->id, out_id, type); + dpll_notify_pin_flags_change(dpll->id, pin_id, flags); return ret; } @@ -351,19 +382,21 @@ static int dpll_genl_cmd_set_source_prio(struct sk_buff *skb, struct genl_info * struct dpll_device *dpll = info->user_ptr[0]; struct nlattr **attrs = info->attrs; int ret = 0, src_id, prio; + struct dpll_pin *pin; - if (!attrs[DPLLA_SOURCE_ID] || - !attrs[DPLLA_SOURCE_PRIO]) + if (!attrs[DPLLA_PIN_ID] || + !attrs[DPLLA_SOURCE_PIN_PRIO]) return -EINVAL; - if (!dpll->ops->set_source_prio) - return -EOPNOTSUPP; - - src_id = nla_get_u32(attrs[DPLLA_SOURCE_ID]); - prio = nla_get_u32(attrs[DPLLA_SOURCE_PRIO]); + src_id = nla_get_u32(attrs[DPLLA_PIN_ID]); + prio = nla_get_u32(attrs[DPLLA_SOURCE_PIN_PRIO]); mutex_lock(&dpll->lock); - ret = dpll->ops->set_source_prio(dpll, src_id, prio); + pin = dpll_pin_get_by_id(dpll, src_id); + if (!dpll->ops || !dpll->ops->set_prio) + ret = -EOPNOTSUPP; + else + ret = dpll->ops->set_prio(dpll, pin, prio); mutex_unlock(&dpll->lock); if (!ret) @@ -505,18 +538,25 @@ static const struct genl_ops dpll_genl_ops[] = { .maxattr = ARRAY_SIZE(dpll_genl_get_policy) - 1, }, { - .cmd = DPLL_CMD_SET_SOURCE_TYPE, + .cmd = DPLL_CMD_SET_SOURCE, .flags = GENL_UNS_ADMIN_PERM, .doit = dpll_genl_cmd_set_source, .policy = dpll_genl_set_source_policy, .maxattr = ARRAY_SIZE(dpll_genl_set_source_policy) - 1, }, { - .cmd = DPLL_CMD_SET_OUTPUT_TYPE, + .cmd = DPLL_CMD_SET_PIN_TYPE, .flags = GENL_UNS_ADMIN_PERM, - .doit = dpll_genl_cmd_set_output, - .policy = dpll_genl_set_output_policy, - .maxattr = ARRAY_SIZE(dpll_genl_set_output_policy) - 1, + .doit = dpll_genl_cmd_set_pin_type, + .policy = dpll_genl_set_pin_type_policy, + .maxattr = ARRAY_SIZE(dpll_genl_set_pin_type_policy) - 1, + }, + { + .cmd = DPLL_CMD_SET_PIN_FLAGS, + .flags = GENL_UNS_ADMIN_PERM, + .doit = dpll_genl_cmd_set_pin_flags, + .policy = dpll_genl_set_pin_flags_policy, + .maxattr = ARRAY_SIZE(dpll_genl_set_pin_flags_policy) - 1, }, { .cmd = DPLL_CMD_SET_SRC_SELECT_MODE, @@ -565,7 +605,7 @@ static int dpll_event_device_delete(struct param *p) static int dpll_event_status(struct param *p) { if (nla_put_u32(p->msg, DPLLA_DEVICE_ID, p->dpll_id) || - nla_put_u32(p->msg, DPLLA_LOCK_STATUS, p->dpll_status)) + nla_put_u32(p->msg, DPLLA_LOCK_STATUS, p->dpll_status)) return -EMSGSIZE; return 0; @@ -574,18 +614,17 @@ static int dpll_event_status(struct param *p) static int dpll_event_source_change(struct param *p) { if (nla_put_u32(p->msg, DPLLA_DEVICE_ID, p->dpll_id) || - nla_put_u32(p->msg, DPLLA_SOURCE_ID, p->dpll_source_id) || - nla_put_u32(p->msg, DPLLA_SOURCE_TYPE, p->dpll_source_type)) + nla_put_u32(p->msg, DPLLA_PIN_ID, p->dpll_pin_id)) return -EMSGSIZE; return 0; } -static int dpll_event_output_change(struct param *p) +static int dpll_event_pin_flags_change(struct param *p) { if (nla_put_u32(p->msg, DPLLA_DEVICE_ID, p->dpll_id) || - nla_put_u32(p->msg, DPLLA_OUTPUT_ID, p->dpll_output_id) || - nla_put_u32(p->msg, DPLLA_OUTPUT_TYPE, p->dpll_output_type)) + nla_put_u32(p->msg, DPLLA_PIN_ID, p->dpll_pin_id) || + nla_put_u32(p->msg, DPLLA_PIN_FLAGS, p->dpll_pin_flags)) return -EMSGSIZE; return 0; @@ -594,8 +633,8 @@ static int dpll_event_output_change(struct param *p) static int dpll_event_source_prio(struct param *p) { if (nla_put_u32(p->msg, DPLLA_DEVICE_ID, p->dpll_id) || - nla_put_u32(p->msg, DPLLA_SOURCE_ID, p->dpll_source_id) || - nla_put_u32(p->msg, DPLLA_SOURCE_PRIO, p->dpll_source_prio)) + nla_put_u32(p->msg, DPLLA_PIN_ID, p->dpll_pin_id) || + nla_put_u32(p->msg, DPLLA_SOURCE_PIN_PRIO, p->dpll_source_prio)) return -EMSGSIZE; return 0; @@ -611,22 +650,46 @@ static int dpll_event_select_mode(struct param *p) return 0; } +static int dpll_event_pin_register(struct param *p) +{ + if (nla_put_u32(p->msg, DPLLA_DEVICE_ID, p->dpll_id) || + nla_put_u32(p->msg, DPLLA_PIN_ID, p->dpll_pin_id)) + return -EMSGSIZE; + + return 0; +} + +static int dpll_event_muxed_pin_register(struct param *p) +{ + if (nla_put_u32(p->msg, DPLLA_DEVICE_ID, p->dpll_id) || + nla_put_u32(p->msg, DPLLA_PIN_ID, p->dpll_pin_id) || + nla_put_u32(p->msg, DPLLA_PARENT_PIN_ID, p->dpll_parent_pin_id)) + return -EMSGSIZE; + + return 0; +} + static const cb_t event_cb[] = { [DPLL_EVENT_DEVICE_CREATE] = dpll_event_device_create, [DPLL_EVENT_DEVICE_DELETE] = dpll_event_device_delete, [DPLL_EVENT_STATUS_LOCKED] = dpll_event_status, [DPLL_EVENT_STATUS_UNLOCKED] = dpll_event_status, [DPLL_EVENT_SOURCE_CHANGE] = dpll_event_source_change, - [DPLL_EVENT_OUTPUT_CHANGE] = dpll_event_output_change, - [DPLL_EVENT_SOURCE_PRIO] = dpll_event_source_prio, - [DPLL_EVENT_SELECT_MODE] = dpll_event_select_mode, + [DPLL_EVENT_PIN_TYPE_CHANGE] = dpll_event_pin_flags_change, + [DPLL_EVENT_PIN_FLAGS_CHANGE] = dpll_event_pin_flags_change, + [DPLL_EVENT_SOURCE_PRIO_CHANGE] = dpll_event_source_prio, + [DPLL_EVENT_SELECT_MODE_CHANGE] = dpll_event_select_mode, + [DPLL_EVENT_PIN_REGISTER] = dpll_event_pin_register, + [DPLL_EVENT_PIN_DEREGISTER] = dpll_event_pin_register, + [DPLL_EVENT_MUXED_PIN_REGISTER] = dpll_event_muxed_pin_register, + [DPLL_EVENT_MUXED_PIN_DEREGISTER] = dpll_event_muxed_pin_register, }; /* * Generic netlink DPLL event encoding */ static int dpll_send_event(enum dpll_genl_event event, - struct param *p) + struct param *p) { struct sk_buff *msg; int ret = -EMSGSIZE; @@ -692,23 +755,33 @@ int dpll_notify_status_unlocked(int dpll_id) } EXPORT_SYMBOL_GPL(dpll_notify_status_unlocked); -int dpll_notify_source_change(int dpll_id, int source_id, int source_type) +int dpll_notify_source_change(int dpll_id, int source_id) { - struct param p = { .dpll_id = dpll_id, .dpll_source_id = source_id, - .dpll_source_type = source_type, .dpll_event_group = 1 }; + struct param p = { .dpll_id = dpll_id, .dpll_pin_id = source_id, + .dpll_event_group = 1 }; return dpll_send_event(DPLL_EVENT_SOURCE_CHANGE, &p); } EXPORT_SYMBOL_GPL(dpll_notify_source_change); -int dpll_notify_output_change(int dpll_id, int output_id, int output_type) + +int dpll_notify_pin_type_change(int dpll_id, int pin_id, int output_type) { - struct param p = { .dpll_id = dpll_id, .dpll_output_id = output_id, - .dpll_output_type = output_type, .dpll_event_group = 2 }; + struct param p = { .dpll_id = dpll_id, .dpll_pin_id = pin_id, + .dpll_pin_type = output_type, .dpll_event_group = 2 }; - return dpll_send_event(DPLL_EVENT_OUTPUT_CHANGE, &p); + return dpll_send_event(DPLL_EVENT_PIN_TYPE_CHANGE, &p); } -EXPORT_SYMBOL_GPL(dpll_notify_output_change); +EXPORT_SYMBOL_GPL(dpll_notify_pin_type_change); + +int dpll_notify_pin_flags_change(int dpll_id, int pin_id, int flags) +{ + struct param p = { .dpll_id = dpll_id, .dpll_pin_id = pin_id, + .dpll_pin_flags = flags, .dpll_event_group = 2 }; + + return dpll_send_event(DPLL_EVENT_PIN_FLAGS_CHANGE, &p); +} +EXPORT_SYMBOL_GPL(dpll_notify_pin_flags_change); int dpll_notify_source_select_mode_change(int dpll_id, int new_mode) { @@ -716,20 +789,77 @@ int dpll_notify_source_select_mode_change(int dpll_id, int new_mode) .dpll_src_select_mode = new_mode, .dpll_event_group = 0 }; - return dpll_send_event(DPLL_EVENT_SELECT_MODE, &p); + return dpll_send_event(DPLL_EVENT_SELECT_MODE_CHANGE, &p); } EXPORT_SYMBOL_GPL(dpll_notify_source_select_mode_change); int dpll_notify_source_prio_change(int dpll_id, int source_id, int prio) { - struct param p = { .dpll_id = dpll_id, .dpll_source_id = source_id, + struct param p = { .dpll_id = dpll_id, .dpll_pin_id = source_id, .dpll_source_prio = prio, .dpll_event_group = 1 }; - return dpll_send_event(DPLL_EVENT_SOURCE_PRIO, &p); + return dpll_send_event(DPLL_EVENT_SOURCE_PRIO_CHANGE, &p); } EXPORT_SYMBOL_GPL(dpll_notify_source_prio_change); +int dpll_notify_pin_register(int dpll_id, int pin_id) +{ + struct param p = { .dpll_id = dpll_id, .dpll_pin_id = pin_id, + .dpll_event_group = 1 }; + + return dpll_send_event(DPLL_EVENT_PIN_REGISTER, &p); +} +EXPORT_SYMBOL_GPL(dpll_notify_pin_register); + +int dpll_notify_pin_deregister(int dpll_id, int pin_id) +{ + struct param p = { .dpll_id = dpll_id, .dpll_pin_id = pin_id, + .dpll_event_group = 1 }; + + return dpll_send_event(DPLL_EVENT_PIN_DEREGISTER, &p); +} +EXPORT_SYMBOL_GPL(dpll_notify_pin_deregister); + +static int dpll_shared_pins_notify_cb(struct dpll_device *dpll, void *data) +{ + struct param *p = data; + struct dpll_pin *pin; + unsigned long i; + + FOR_EACH_SOURCE(dpll, i, dpll->sources_count, pin) + if (pin == p->dpll_shared_pin) { + p->dpll_id = dpll->id; + return dpll_send_event(p->dpll_event, p); + } + + return 0; +} + +int dpll_notify_muxed_pin_register(struct dpll_pin *parent_pin, int pin_id) +{ + struct param p = { .dpll_pin_id = pin_id, + .dpll_shared_pin = parent_pin, + .dpll_parent_pin_id = parent_pin->id, + .dpll_event_group = 1, + .dpll_event = DPLL_EVENT_MUXED_PIN_REGISTER }; + + return for_each_dpll_device(0, dpll_shared_pins_notify_cb, &p); +} +EXPORT_SYMBOL_GPL(dpll_notify_muxed_pin_register); + +int dpll_notify_muxed_pin_deregister(struct dpll_pin *parent_pin, int pin_id) +{ + struct param p = { .dpll_pin_id = pin_id, + .dpll_shared_pin = parent_pin, + .dpll_parent_pin_id = parent_pin->id, + .dpll_event_group = 1, + .dpll_event = DPLL_EVENT_MUXED_PIN_DEREGISTER}; + + return for_each_dpll_device(0, dpll_shared_pins_notify_cb, &p); +} +EXPORT_SYMBOL_GPL(dpll_notify_muxed_pin_deregister); + int __init dpll_netlink_init(void) { return genl_register_family(&dpll_gnl_family); diff --git a/drivers/net/ethernet/intel/ice/ice_synce.c b/drivers/net/ethernet/intel/ice/ice_synce.c index 9b9820fc388f4..523bd998c3b7e 100644 --- a/drivers/net/ethernet/intel/ice/ice_synce.c +++ b/drivers/net/ethernet/intel/ice/ice_synce.c @@ -102,13 +102,19 @@ static int ice_synce_get_lock_status(struct dpll_device *dpll) * Check current type of a given pin. * Return: current type value of a pin. */ -static int ice_synce_get_source_type(struct dpll_device *dpll, int id) +static int ice_synce_get_source_type(struct dpll_pin *pin) { - struct ice_pf *pf = dpll_priv(dpll); + struct ice_pf *pf = pin_priv(pin); int ret; + u8 id; + + if (!pf) + return DPLL_TYPE_NONE; + id = (u8)pin_id(pin); if (id < 0 || id >= pf->synce.num_inputs) return DPLL_TYPE_NONE; + mutex_lock(&pf->synce.lock); ret = pf->synce.inputs[id].type; mutex_unlock(&pf->synce.lock); @@ -127,13 +133,22 @@ static int ice_synce_get_source_type(struct dpll_device *dpll, int id) * * 0 - success, * * negative - failure. */ -static int ice_synce_set_source_type(struct dpll_device *dpll, int id, int type) +static int ice_synce_set_source_type(struct dpll_pin *pin, int type) { - struct ice_pf *pf = dpll_priv(dpll); - struct ice_synce *se = &pf->synce; + struct ice_pf *pf = pin_priv(pin); struct ice_synce_pin *inputs; + struct ice_synce *se; int ret; + u8 id; + if (!pf) + return -ENODEV; + + se = &pf->synce; + if (!se) + return -ENOSPC; + + id = (u8)pin_id(pin); if (id < 0 || id >= se->num_inputs) return -EINVAL; inputs = se->inputs; @@ -171,14 +186,22 @@ static int ice_synce_set_source_type(struct dpll_device *dpll, int id, int type) * dpll subsystem callback. * Check if given type is supported on a given pin. * Return: - * * true - if supported - * * false - if not supported + * * value - if supported + * * 0 - if not supported */ static int -ice_synce_get_source_supported(struct dpll_device *dpll, int id, int type) +ice_synce_get_source_supported(struct dpll_pin *pin, int type) { - struct ice_pf *pf = dpll_priv(dpll); + struct ice_pf *pf = pin_priv(pin); int ret; + u8 id; + + if (!pf) + return 0; + + id = (u8)pin_id(pin); + if (id >= pf->synce.num_outputs) + return 0; mutex_lock(&pf->synce.lock); ret = !!(pf->synce.inputs[id].types_supported & BIT(type)); @@ -196,13 +219,19 @@ ice_synce_get_source_supported(struct dpll_device *dpll, int id, int type) * Check current type of a given pin. * Return: current type value of a pin. */ -static int ice_synce_get_output_type(struct dpll_device *dpll, int id) +static int ice_synce_get_output_type(struct dpll_pin *pin) { - struct ice_pf *pf = dpll_priv(dpll); + struct ice_pf *pf = pin_priv(pin); int ret; + u8 id; + if (!pf) + return DPLL_TYPE_NONE; + + id = (u8)pin_id(pin); if (id < 0 || id >= pf->synce.num_outputs) return DPLL_TYPE_NONE; + mutex_lock(&pf->synce.lock); ret = pf->synce.outputs[id].type; mutex_unlock(&pf->synce.lock); @@ -212,26 +241,35 @@ static int ice_synce_get_output_type(struct dpll_device *dpll, int id) /** * ice_synce_set_output_type - * @dpll: registered dpll pointer - * @id: output pin index + * @pin: registered pin pointer + * @type: type to set * - * dpll subsystem callback. + * pin subsystem callback. * Set type of a given output pin. * Return: * * 0 - success, * * negative - failure. */ -static int ice_synce_set_output_type(struct dpll_device *dpll, int id, int type) +static int ice_synce_set_output_type(struct dpll_pin *pin, int type) { - struct ice_pf *pf = dpll_priv(dpll); - struct ice_synce *se = &pf->synce; + struct ice_pf *pf = pin_priv(pin); struct ice_synce_pin *outputs; + struct ice_synce *se; int ret; + u8 id; + if (!pf) + return -ENODEV; + + se = &pf->synce; + if (!se) + return -ENOSPC; + + id = (u8)pin_id(pin); if (id < 0 || id >= se->num_outputs) return -EINVAL; - outputs = se->outputs; + outputs = se->outputs; if (type == outputs[id].type) return 0; @@ -258,21 +296,28 @@ static int ice_synce_set_output_type(struct dpll_device *dpll, int id, int type) /** * ice_synce_get_output_supported - * @dpll: registered dpll pointer - * @id: output pin index + * @pin: registered pin pointer * @type: id of type * - * dpll subsystem callback. + * pin subsystem callback. * Check if given type is supported on a given pin. * Return: - * * true - if supported - * * false - if not supported + * * value - if supported + * * 0 - if not supported */ static int -ice_synce_get_output_supported(struct dpll_device *dpll, int id, int type) +ice_synce_get_output_supported(struct dpll_pin *pin, int type) { - struct ice_pf *pf = dpll_priv(dpll); + struct ice_pf *pf = pin_priv(pin); int ret; + u8 id; + + if (!pf) + return 0; + + id = (u8)pin_id(pin); + if (id >= pf->synce.num_outputs) + return 0; mutex_lock(&pf->synce.lock); ret = !!(pf->synce.outputs[id].types_supported & BIT(type)); @@ -316,18 +361,21 @@ static int ice_synce_get_src_select_supported(struct dpll_device *dpll, int mode /** * ice_synce_get_source_prio * @dpll: registered dpll pointer - * @id: source index + * @pin: dpll pin object * * dpll subsystem callback. * Get source priority value. * Return: source priority value */ -static int ice_synce_get_source_prio(struct dpll_device *dpll, int id) +static int ice_synce_get_source_prio(struct dpll_device *dpll, struct dpll_pin *pin) { struct ice_pf *pf = dpll_priv(dpll); - u8 idx = (u8)id; + u8 idx = (u8)pin_id(pin); int ret; + if (!pf) + return -ENODEV; + if (idx >= pf->synce.num_inputs) return 0xFF; @@ -341,7 +389,7 @@ static int ice_synce_get_source_prio(struct dpll_device *dpll, int id) /** * ice_synce_set_source_prio * @dpll: registered dpll pointer - * @id: source index + * @pin: dpll pin object * @prio: expected priority value * * dpll subsystem callback. @@ -350,16 +398,22 @@ static int ice_synce_get_source_prio(struct dpll_device *dpll, int id) * * 0 - success * * negative - failure */ -static int ice_synce_set_source_prio(struct dpll_device *dpll, int id, int prio) +static int ice_synce_set_source_prio(struct dpll_device *dpll, + struct dpll_pin *pin, int prio) { struct ice_pf *pf = dpll_priv(dpll); - struct ice_synce *se = &pf->synce; - u8 idx = (u8)id, priov = (u8)prio; + u8 idx, priov = (u8)prio; + struct ice_synce *se; int ret; + if (!pf) + return -ENODEV; + se = &pf->synce; + if (priov > ICE_SYNCE_PRIO_MAX) return -EINVAL; + idx = (u8)pin_id(pin); if (idx >= pf->synce.num_inputs) return -EINVAL; @@ -377,43 +431,25 @@ static int ice_synce_set_source_prio(struct dpll_device *dpll, int id, int prio) return ret; } -const char *ice_synce_get_source_name(struct dpll_device *dpll, int id) -{ - struct ice_pf *pf = dpll_priv(dpll); - u8 idx = (u8)id; - - if (idx >= pf->synce.num_inputs) - return NULL; - - return pf->synce.inputs[idx].name; -} - -const char *ice_synce_get_output_name(struct dpll_device *dpll, int id) -{ - struct ice_pf *pf = dpll_priv(dpll); - u8 idx = (u8)id; - - if (idx >= pf->synce.num_outputs) - return NULL; +static struct dpll_pin_ops ice_synce_source_ops = { + .get_type = ice_synce_get_source_type, + .set_type = ice_synce_set_source_type, + .is_type_supported = ice_synce_get_source_supported, +}; - return pf->synce.outputs[idx].name; -} +static struct dpll_pin_ops ice_synce_output_ops = { + .get_type = ice_synce_get_output_type, + .set_type = ice_synce_set_output_type, + .is_type_supported = ice_synce_get_output_supported, +}; static struct dpll_device_ops ice_synce_dpll_ops = { .get_status = ice_synce_get_status, .get_lock_status = ice_synce_get_lock_status, - .get_source_type = ice_synce_get_source_type, - .set_source_type = ice_synce_set_source_type, - .get_source_supported = ice_synce_get_source_supported, - .get_output_type = ice_synce_get_output_type, - .set_output_type = ice_synce_set_output_type, - .get_output_supported = ice_synce_get_output_supported, .get_source_select_mode = ice_synce_get_source_select_mode, .get_source_select_mode_supported = ice_synce_get_src_select_supported, - .get_source_prio = ice_synce_get_source_prio, - .set_source_prio = ice_synce_set_source_prio, - .get_source_name = ice_synce_get_source_name, - .get_output_name = ice_synce_get_output_name, + .get_prio = ice_synce_get_source_prio, + .set_prio = ice_synce_set_source_prio, }; /** @@ -581,11 +617,76 @@ static int ice_synce_init_pins(struct ice_hw *hw, bool input, int num_pins, return ret; } +/** + * ice_synce_register_pins + * @dpll: dpll pointer + * @pins: pointer to pins array + * @count: no of pins + * + * Release dpll pins from dpll subsystem. + */ +static void ice_synce_release_pins(struct dpll_device *dpll, + struct ice_synce_pin *pins, int count) +{ + int i; + + for (i = 0; i < count; count++) { + if (pins[i].pin) { + dpll_pin_deregister(dpll, pins[i].pin); + dpll_pin_free(dpll, pins[i].pin); + pins[i].pin = NULL; + } + } +} + +/** + * ice_synce_register_pins + * @pf: Board private structure + * @dpll_device: registered dpll pointer + * @pins: pointer to the pins array + * @count: number of pins + * @inputs: pins type + * + * Register pins within a SyncE dpll in dpll subsystem. + * + * Return: + * * 0 - success + * * negative - error + */ +static int ice_synce_register_pins(struct ice_pf *pf, struct dpll_device *dpll, + struct ice_synce_pin *pins, int count, + bool inputs) +{ + struct dpll_pin_ops *ops; + enum dpll_pin_type type; + int ret, i; + + if (inputs) { + type = DPLL_PIN_TYPE_SOURCE; + ops = &ice_synce_source_ops; + + } else { + type = DPLL_PIN_TYPE_OUTPUT; + ops = &ice_synce_output_ops; + } + + for (i = 0; i < count; i++) { + dpll_init_pin(&pins->pin, type, ops, pf, NULL, i); + dpll_pin_register(dpll, pins->pin); + if (ret) { + ice_synce_release_pins(dpll, pins, i + 1); + } + } + + return 0; +} + /** * ice_synce_init_info * @pf: Board private structure * * Acquire (from HW) and set basic dpll information (on pf->synce struct). + * * Return: * * 0 - success * * negative - AQ error @@ -652,8 +753,7 @@ static int ice_synce_init_dpll(struct ice_pf *pf) snprintf(name, DPLL_NAME_LENGTH, "%s-SyncE-%s", dev_driver_string(dev), dev_name(dev)); - se->dpll = dpll_device_alloc(&ice_synce_dpll_ops, name, se->num_inputs, - se->num_outputs, pf); + se->dpll = dpll_device_alloc(&ice_synce_dpll_ops, name, pf); if (!se->dpll) { dev_err(ice_pf_to_dev(pf), "dpll_device_alloc failed\n"); return -ENOMEM; @@ -683,6 +783,7 @@ static int ice_synce_update_dpll_state(struct ice_pf *pf, &se->current_source, &se->ref_state, &se->eec_mode, &se->phase_offset, &se->dpll_state); + if (ret) dev_err(ice_pf_to_dev(pf), "update dpll state failed, ret=%d %s\n", ret, ice_aq_str(pf->hw.adminq.sq_last_status)); @@ -782,6 +883,18 @@ int ice_synce_init(struct ice_pf *pf) err = ice_synce_init_dpll(pf); if (err) goto free_info; + err = ice_synce_register_pins(pf, pf->synce.dpll, pf->synce.inputs, + pf->synce.num_inputs, true); + if (err) + goto free_info; + err = ice_synce_register_pins(pf, pf->synce.dpll, pf->synce.outputs, + pf->synce.num_outputs, false); + if (err) { + ice_synce_release_pins(pf->synce.dpll, pf->synce.inputs, + pf->synce.num_inputs); + goto free_info; + } + dev_dbg(ice_pf_to_dev(pf), "SyncE init successful\n"); mutex_unlock(&pf->synce.lock); @@ -821,4 +934,3 @@ void ice_synce_release(struct ice_pf *pf) mutex_unlock(&se->lock); mutex_destroy(&se->lock); } - diff --git a/drivers/net/ethernet/intel/ice/ice_synce.h b/drivers/net/ethernet/intel/ice/ice_synce.h index 0f2385cdfb3b5..514e218540cba 100644 --- a/drivers/net/ethernet/intel/ice/ice_synce.h +++ b/drivers/net/ethernet/intel/ice/ice_synce.h @@ -21,6 +21,7 @@ struct ice_synce_pin { u8 num_types; u8 flags; u8 prio; + struct dpll_pin *pin; const char *name; }; diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c index a01c0c7218025..8b4bb8e697eeb 100644 --- a/drivers/ptp/ptp_ocp.c +++ b/drivers/ptp/ptp_ocp.c @@ -3851,7 +3851,7 @@ ptp_ocp_probe(struct pci_dev *pdev, const struct pci_device_id *id) ptp_ocp_info(bp); devlink_register(devlink); - bp->dpll = dpll_device_alloc(&dpll_ops, "ocp", ARRAY_SIZE(bp->sma), ARRAY_SIZE(bp->sma), bp); + bp->dpll = dpll_device_alloc(&dpll_ops, "ocp", bp); if (!bp->dpll) { dev_err(&pdev->dev, "dpll_device_alloc failed\n"); return 0; diff --git a/include/linux/dpll.h b/include/linux/dpll.h index 2f4964dc28f05..1e54f56450a0c 100644 --- a/include/linux/dpll.h +++ b/include/linux/dpll.h @@ -6,7 +6,10 @@ #ifndef __DPLL_H__ #define __DPLL_H__ +#define PIN_NAME_LENGTH 20 + struct dpll_device; +struct dpll_pin; struct dpll_device_ops { int (*get_status)(struct dpll_device *dpll); @@ -14,30 +17,197 @@ struct dpll_device_ops { int (*get_lock_status)(struct dpll_device *dpll); int (*get_source_select_mode)(struct dpll_device *dpll); int (*get_source_select_mode_supported)(struct dpll_device *dpll, int type); - int (*get_source_type)(struct dpll_device *dpll, int id); - int (*get_source_supported)(struct dpll_device *dpll, int id, int type); - int (*get_source_prio)(struct dpll_device *dpll, int id); - int (*get_output_type)(struct dpll_device *dpll, int id); - int (*get_output_supported)(struct dpll_device *dpll, int id, int type); - int (*set_source_type)(struct dpll_device *dpll, int id, int val); - int (*set_output_type)(struct dpll_device *dpll, int id, int val); int (*set_source_select_mode)(struct dpll_device *dpll, int mode); - int (*set_source_prio)(struct dpll_device *dpll, int id, int prio); - const char *(*get_source_name)(struct dpll_device *dpll, int id); - const char *(*get_output_name)(struct dpll_device *dpll, int id); + int (*get_source_type)(struct dpll_device *dpll, int sma); + int (*get_source_supported)(struct dpll_device *dpll, int sma, int type); + int (*get_output_type)(struct dpll_device *dpll, int sma); + int (*get_output_supported)(struct dpll_device, int sma, int type); + int (*get_prio)(struct dpll_device *dpll, struct dpll_pin *pin); + int (*set_prio)(struct dpll_device *dpll, struct dpll_pin *pin, int prio); +}; + +struct dpll_pin_ops { + int (*get_type)(struct dpll_pin *pin); + int (*is_type_supported)(struct dpll_pin *pin, int type); + int (*set_type)(struct dpll_pin *pin, int type); + int (*set_source)(struct dpll_pin *pin, struct dpll_device *dpll, int id); + int (*set_flags)(struct dpll_pin *pin, struct dpll_device *dpll, int flags); }; -struct dpll_device *dpll_device_alloc(struct dpll_device_ops *ops, const char *name, - int sources_count, int outputs_count, void *priv); +enum dpll_pin_type { + DPLL_PIN_TYPE_INVALID, + DPLL_PIN_TYPE_SOURCE, + DPLL_PIN_TYPE_OUTPUT, + DPLL_PIN_TYPE_MUX, + __DPLL_PIN_TYPE_MAX, +}; +#define DPLL_PIN_TYPE_MAX (__DPLL_PIN_TYPE_MAX - 1) + +struct dpll_device *dpll_device_alloc(struct dpll_device_ops *ops, + const char *name, void *priv); void dpll_device_register(struct dpll_device *dpll); void dpll_device_unregister(struct dpll_device *dpll); void dpll_device_free(struct dpll_device *dpll); void *dpll_priv(struct dpll_device *dpll); +void *pin_priv(struct dpll_pin *pin); +int pin_id(struct dpll_pin *pin); + +/* + * dpll_pin_alloc - allocate memory for a new dpll_pin object + * @ops: pointer to pin operations structure + * @id: id given by the owner, used to find pin by id + * @dpll_pin_type: type of a pin being allocated + * @name: human readable pin name of allocated pin + * @priv: private data of a registerer + * + * Allocate memory for a new pin and initialize it with its type, name, + * callbacks and private data pointer. + * + * Returns: + * * pointer to initialized pin - success, + * * ERR_PTR(-ENOMEM) - memory failure, + * * ERR_PTR(-EINVAL) - given pin type is invalid. + **/ +struct dpll_pin *dpll_pin_alloc(struct dpll_pin_ops *ops, int id, + enum dpll_pin_type type, + const char *name, void *priv); + +/* + * dpll_pin_register - register pin with a dpll device + * @dpll: pointer to dpll object to register pin with + * @pin: pointer to allocated pin object being registered with dpll + * + * Register previously allocated pin object with a dpll device. + * + * Return: + * * 0 - if pin was registered with a parent pin, + * * -ENOMEM - failed to allocate memory, + * * -EEXIST - pin already registered with this dpll, + * * -EBUSY - couldn't allocate id for a pin. + **/ +int dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin); + +/* + * dpll_pin_deregister - deregister pin from a dpll device + * @dpll: pointer to dpll object to deregister pin from + * @pin: pointer to allocated pin object being deregistered from dpll + * + * Deregister previously registered pin object from a dpll device. + * + * Return: + * * 0 - pin was successfully deregistered from this dpll device, + * * -ENOENT - given pin was not registered with this dpll device, + * * -EINVAL - pin pointer is not valid. + **/ +int dpll_pin_deregister(struct dpll_device *dpll, struct dpll_pin *pin); + +/* + * dpll_pin_free - free memory allocated for a pin + * @dpll: pointer to dpll object that owns the pin + * @pin: pointer to allocated pin object being freed + * + * Shared pins must be deregistered from all dpll devices before freeing them, + * otherwise the memory won't be freed. + **/ +void dpll_pin_free(struct dpll_device *dpll, struct dpll_pin *pin); + +/* + * dpll_muxed_pin_free - free memory allocated for a pin + * @parent_pin: pointer to object that owns the pin + * @pin: pointer to allocated pin object being freed + * + * Free memory of deregistered pin object. + * Shared pins must be deregistered from all dpll devices before freeing them, + * otherwise memory won't be freed. + */ +void dpll_muxed_pin_free(struct dpll_pin *parent_pin, struct dpll_pin *pin); + +/* + * dpll_muxed_pin_register - register a pin to a muxed-type pin + * @parent_pin: pointer to object to deregister pin from + * @pin: pointer to allocated pin object being deregistered from dpll + * + * In case of multiplexed pins, register them under a single parent pin. + * + * Return: + * * 0 - if pin was registered with a parent pin, + * * -ENOMEM - failed to allocate memory, + * * -EEXIST - pin already registered with this parent pin, + * * -EBUSY - couldn't assign id for a pin. + **/ +int dpll_muxed_pin_register(struct dpll_pin *parent_pin, struct dpll_pin *pin); + +/* + * dpll_muxed_pin_deregister - deregister a pin from a muxed-type pin + * @parent_pin: pointer to object to deregister pin from + * @pin: pointer to allocated pin object being deregistered from dpll + * + * In case of multiplexed pins, deregister a pin from a parent pin. + * + * Return: + * * 0 - pin was successfully deregistered from a parent pin, + * * -ENOENT - given pin was not registered with this parent pin, + * * -EINVAL - pin pointer is not valid. + **/ +int dpll_muxed_pin_deregister(struct dpll_pin *parent_pin, struct dpll_pin *pin); + +/* + * dpll_device_get_by_name - find a dpll by its name + * @name: name of device + * + * Allows multiple driver instances using one physical DPLL to find + * and share already registered DPLL device. + * + * Return: pointer if device was found, NULL otherwise. + **/ +struct dpll_device *dpll_device_get_by_name(const char *name); + +/* + * dpll_pin_get_by_name - find a pin belonging to dpll by its name + * @name: name of device + * + * Allows multiple driver instances using one physical DPLL to find + * and share pin already registered with existing dpll device. + * + * Return: + * * pointer to existing pin if pin was found, + * * NULL if pin was not found. + **/ +struct dpll_pin *dpll_pin_get_by_name(struct dpll_device *dpll, const char *name); + +/* + * dpll_pin_get_by_id - find a pin by its id + * @name: name of device + * + * Allows multiple driver instances using one physical DPLL to find + * and share pin already registered with existing dpll device. + * + * Return: pointer if pin was found, NULL otherwise. + **/ +struct dpll_pin *dpll_pin_get_by_id(struct dpll_device *dpll, int id); + +/* + * dpll_init_pins - initialize data of dpll pins + * @pin: pointer to pointer to dpll object to initialize + * @type: the type of dpll pin + * @ops: pointer to dpll ops + * @priv: private data of an dpll pin object + * @name: human readable pin name + * @id: dpll pin id + **/ +void dpll_init_pin(struct dpll_pin **pin, enum dpll_pin_type type, + struct dpll_pin_ops *ops, void *priv, const char *name, + int id); int dpll_notify_status_locked(int dpll_id); int dpll_notify_status_unlocked(int dpll_id); -int dpll_notify_source_change(int dpll_id, int source_id, int source_type); -int dpll_notify_output_change(int dpll_id, int output_id, int output_type); +int dpll_notify_source_change(int dpll_id, int pin_id); +int dpll_notify_pin_type_change(int dpll_id, int pin_id, int type); +int dpll_notify_pin_flags_change(int dpll_id, int pin_id, int flags); int dpll_notify_source_select_mode_change(int dpll_id, int source_select_mode); -int dpll_notify_source_prio_change(int dpll_id, int source_id, int prio); +int dpll_notify_source_prio_change(int dpll_id, int src_id, int prio); +int dpll_notify_pin_register(int dpll_id, int pin_id); +int dpll_notify_pin_deregister(int dpll_id, int pin_id); +int dpll_notify_muxed_pin_register(struct dpll_pin *parent_pin, int pin_id); +int dpll_notify_muxed_pin_deregister(struct dpll_pin *parent_pin, int pin_id); #endif diff --git a/include/uapi/linux/dpll.h b/include/uapi/linux/dpll.h index 59fc6ef81b408..db998ba408729 100644 --- a/include/uapi/linux/dpll.h +++ b/include/uapi/linux/dpll.h @@ -16,6 +16,10 @@ #define DPLL_FLAG_OUTPUTS 2 #define DPLL_FLAG_STATUS 4 +#define DPLL_PIN_FLAG_SOURCE 1 +#define DPLL_PIN_FLAG_OUTPUT 2 +#define DPLL_PIN_FLAG_ENABLED 4 + /* Attributes of dpll_genl_family */ enum dpll_genl_attr { DPLLA_UNSPEC, @@ -24,16 +28,14 @@ enum dpll_genl_attr { DPLLA_DEVICE_SRC_SELECT_MODE, DPLLA_DEVICE_SRC_SELECT_MODE_SUPPORTED, DPLLA_SOURCE, - DPLLA_SOURCE_ID, - DPLLA_SOURCE_TYPE, - DPLLA_SOURCE_NAME, - DPLLA_SOURCE_SUPPORTED, - DPLLA_SOURCE_PRIO, DPLLA_OUTPUT, - DPLLA_OUTPUT_ID, - DPLLA_OUTPUT_TYPE, - DPLLA_OUTPUT_NAME, - DPLLA_OUTPUT_SUPPORTED, + DPLLA_PIN_ID, + DPLLA_PIN_NAME, + DPLLA_PIN_TYPE, + DPLLA_PIN_FLAGS, + DPLLA_PIN_TYPE_SUPPORTED, + DPLLA_PARENT_PIN_ID, + DPLLA_SOURCE_PIN_PRIO, DPLLA_STATUS, DPLLA_TEMP, DPLLA_LOCK_STATUS, @@ -48,6 +50,7 @@ enum dpll_genl_status { DPLL_STATUS_NONE, DPLL_STATUS_CALIBRATING, DPLL_STATUS_LOCKED, + DPLL_STATUS_HOLDOVER, __DPLL_STATUS_MAX, }; @@ -83,14 +86,19 @@ enum dpll_genl_lock_status { /* Events of dpll_genl_family */ enum dpll_genl_event { DPLL_EVENT_UNSPEC, - DPLL_EVENT_DEVICE_CREATE, /* DPLL device creation */ - DPLL_EVENT_DEVICE_DELETE, /* DPLL device deletion */ - DPLL_EVENT_STATUS_LOCKED, /* DPLL device locked to source */ - DPLL_EVENT_STATUS_UNLOCKED, /* DPLL device freerun */ - DPLL_EVENT_SOURCE_CHANGE, /* DPLL device source changed */ - DPLL_EVENT_OUTPUT_CHANGE, /* DPLL device output changed */ - DPLL_EVENT_SOURCE_PRIO, - DPLL_EVENT_SELECT_MODE, + DPLL_EVENT_DEVICE_CREATE, /* DPLL device creation */ + DPLL_EVENT_DEVICE_DELETE, /* DPLL device deletion */ + DPLL_EVENT_STATUS_LOCKED, /* DPLL device locked to source */ + DPLL_EVENT_STATUS_UNLOCKED, /* DPLL device freerun or holdover */ + DPLL_EVENT_SOURCE_CHANGE, /* DPLL device source changed */ + DPLL_EVENT_PIN_TYPE_CHANGE, /* DPLL device pin type changed */ + DPLL_EVENT_PIN_FLAGS_CHANGE, /* DPLL device output changed */ + DPLL_EVENT_SOURCE_PRIO_CHANGE, /* DPLL device source pin prio changed */ + DPLL_EVENT_SELECT_MODE_CHANGE, /* DPLL device select source mode changed */ + DPLL_EVENT_PIN_REGISTER, /* DPLL device registered new pin */ + DPLL_EVENT_PIN_DEREGISTER, /* DPLL device deregistered a pin */ + DPLL_EVENT_MUXED_PIN_REGISTER, /* DPLL device registered new pin within parent pin */ + DPLL_EVENT_MUXED_PIN_DEREGISTER,/* DPLL device deregistered a pin from a parent pin */ __DPLL_EVENT_MAX, }; @@ -100,9 +108,10 @@ enum dpll_genl_event { enum dpll_genl_cmd { DPLL_CMD_UNSPEC, DPLL_CMD_DEVICE_GET, /* List of DPLL devices id */ - DPLL_CMD_SET_SOURCE_TYPE, /* Set the DPLL device source type */ - DPLL_CMD_SET_OUTPUT_TYPE, /* Set the DPLL device output type */ - DPLL_CMD_SET_SRC_SELECT_MODE,/* Set mode for selection of a source */ + DPLL_CMD_SET_SOURCE, /* Set the DPLL device source */ + DPLL_CMD_SET_PIN_TYPE, /* Set the DPLL device source type */ + DPLL_CMD_SET_PIN_FLAGS, /* Set the DPLL device output */ + DPLL_CMD_SET_SRC_SELECT_MODE, /* Set mode for selection of a source */ DPLL_CMD_SET_SOURCE_PRIO, /* Set priority of a source */ __DPLL_CMD_MAX,