|
@@ -75,6 +75,74 @@ struct mdesc_handle {
|
|
struct mdesc_hdr mdesc;
|
|
struct mdesc_hdr mdesc;
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+typedef int (*mdesc_node_info_get_f)(struct mdesc_handle *, u64,
|
|
|
|
+ union md_node_info *);
|
|
|
|
+typedef void (*mdesc_node_info_rel_f)(union md_node_info *);
|
|
|
|
+typedef bool (*mdesc_node_match_f)(union md_node_info *, union md_node_info *);
|
|
|
|
+
|
|
|
|
+struct md_node_ops {
|
|
|
|
+ char *name;
|
|
|
|
+ mdesc_node_info_get_f get_info;
|
|
|
|
+ mdesc_node_info_rel_f rel_info;
|
|
|
|
+ mdesc_node_match_f node_match;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static int get_vdev_port_node_info(struct mdesc_handle *md, u64 node,
|
|
|
|
+ union md_node_info *node_info);
|
|
|
|
+static void rel_vdev_port_node_info(union md_node_info *node_info);
|
|
|
|
+static bool vdev_port_node_match(union md_node_info *a_node_info,
|
|
|
|
+ union md_node_info *b_node_info);
|
|
|
|
+
|
|
|
|
+static int get_ds_port_node_info(struct mdesc_handle *md, u64 node,
|
|
|
|
+ union md_node_info *node_info);
|
|
|
|
+static void rel_ds_port_node_info(union md_node_info *node_info);
|
|
|
|
+static bool ds_port_node_match(union md_node_info *a_node_info,
|
|
|
|
+ union md_node_info *b_node_info);
|
|
|
|
+
|
|
|
|
+/* supported node types which can be registered */
|
|
|
|
+static struct md_node_ops md_node_ops_table[] = {
|
|
|
|
+ {"virtual-device-port", get_vdev_port_node_info,
|
|
|
|
+ rel_vdev_port_node_info, vdev_port_node_match},
|
|
|
|
+ {"domain-services-port", get_ds_port_node_info,
|
|
|
|
+ rel_ds_port_node_info, ds_port_node_match},
|
|
|
|
+ {NULL, NULL, NULL, NULL}
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static void mdesc_get_node_ops(const char *node_name,
|
|
|
|
+ mdesc_node_info_get_f *get_info_f,
|
|
|
|
+ mdesc_node_info_rel_f *rel_info_f,
|
|
|
|
+ mdesc_node_match_f *match_f)
|
|
|
|
+{
|
|
|
|
+ int i;
|
|
|
|
+
|
|
|
|
+ if (get_info_f)
|
|
|
|
+ *get_info_f = NULL;
|
|
|
|
+
|
|
|
|
+ if (rel_info_f)
|
|
|
|
+ *rel_info_f = NULL;
|
|
|
|
+
|
|
|
|
+ if (match_f)
|
|
|
|
+ *match_f = NULL;
|
|
|
|
+
|
|
|
|
+ if (!node_name)
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+ for (i = 0; md_node_ops_table[i].name != NULL; i++) {
|
|
|
|
+ if (strcmp(md_node_ops_table[i].name, node_name) == 0) {
|
|
|
|
+ if (get_info_f)
|
|
|
|
+ *get_info_f = md_node_ops_table[i].get_info;
|
|
|
|
+
|
|
|
|
+ if (rel_info_f)
|
|
|
|
+ *rel_info_f = md_node_ops_table[i].rel_info;
|
|
|
|
+
|
|
|
|
+ if (match_f)
|
|
|
|
+ *match_f = md_node_ops_table[i].node_match;
|
|
|
|
+
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
static void mdesc_handle_init(struct mdesc_handle *hp,
|
|
static void mdesc_handle_init(struct mdesc_handle *hp,
|
|
unsigned int handle_size,
|
|
unsigned int handle_size,
|
|
void *base)
|
|
void *base)
|
|
@@ -249,6 +317,86 @@ static const u64 *parent_cfg_handle(struct mdesc_handle *hp, u64 node)
|
|
return id;
|
|
return id;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int get_vdev_port_node_info(struct mdesc_handle *md, u64 node,
|
|
|
|
+ union md_node_info *node_info)
|
|
|
|
+{
|
|
|
|
+ const u64 *parent_cfg_hdlp;
|
|
|
|
+ const char *name;
|
|
|
|
+ const u64 *idp;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Virtual device nodes are distinguished by:
|
|
|
|
+ * 1. "id" property
|
|
|
|
+ * 2. "name" property
|
|
|
|
+ * 3. parent node "cfg-handle" property
|
|
|
|
+ */
|
|
|
|
+ idp = mdesc_get_property(md, node, "id", NULL);
|
|
|
|
+ name = mdesc_get_property(md, node, "name", NULL);
|
|
|
|
+ parent_cfg_hdlp = parent_cfg_handle(md, node);
|
|
|
|
+
|
|
|
|
+ if (!idp || !name || !parent_cfg_hdlp)
|
|
|
|
+ return -1;
|
|
|
|
+
|
|
|
|
+ node_info->vdev_port.id = *idp;
|
|
|
|
+ node_info->vdev_port.name = kstrdup_const(name, GFP_KERNEL);
|
|
|
|
+ node_info->vdev_port.parent_cfg_hdl = *parent_cfg_hdlp;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void rel_vdev_port_node_info(union md_node_info *node_info)
|
|
|
|
+{
|
|
|
|
+ if (node_info && node_info->vdev_port.name) {
|
|
|
|
+ kfree_const(node_info->vdev_port.name);
|
|
|
|
+ node_info->vdev_port.name = NULL;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static bool vdev_port_node_match(union md_node_info *a_node_info,
|
|
|
|
+ union md_node_info *b_node_info)
|
|
|
|
+{
|
|
|
|
+ if (a_node_info->vdev_port.id != b_node_info->vdev_port.id)
|
|
|
|
+ return false;
|
|
|
|
+
|
|
|
|
+ if (a_node_info->vdev_port.parent_cfg_hdl !=
|
|
|
|
+ b_node_info->vdev_port.parent_cfg_hdl)
|
|
|
|
+ return false;
|
|
|
|
+
|
|
|
|
+ if (strncmp(a_node_info->vdev_port.name,
|
|
|
|
+ b_node_info->vdev_port.name, MDESC_MAX_STR_LEN) != 0)
|
|
|
|
+ return false;
|
|
|
|
+
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int get_ds_port_node_info(struct mdesc_handle *md, u64 node,
|
|
|
|
+ union md_node_info *node_info)
|
|
|
|
+{
|
|
|
|
+ const u64 *idp;
|
|
|
|
+
|
|
|
|
+ /* DS port nodes use the "id" property to distinguish them */
|
|
|
|
+ idp = mdesc_get_property(md, node, "id", NULL);
|
|
|
|
+ if (!idp)
|
|
|
|
+ return -1;
|
|
|
|
+
|
|
|
|
+ node_info->ds_port.id = *idp;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void rel_ds_port_node_info(union md_node_info *node_info)
|
|
|
|
+{
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static bool ds_port_node_match(union md_node_info *a_node_info,
|
|
|
|
+ union md_node_info *b_node_info)
|
|
|
|
+{
|
|
|
|
+ if (a_node_info->ds_port.id != b_node_info->ds_port.id)
|
|
|
|
+ return false;
|
|
|
|
+
|
|
|
|
+ return true;
|
|
|
|
+}
|
|
|
|
+
|
|
/* Run 'func' on nodes which are in A but not in B. */
|
|
/* Run 'func' on nodes which are in A but not in B. */
|
|
static void invoke_on_missing(const char *name,
|
|
static void invoke_on_missing(const char *name,
|
|
struct mdesc_handle *a,
|
|
struct mdesc_handle *a,
|
|
@@ -367,6 +515,74 @@ out:
|
|
mutex_unlock(&mdesc_mutex);
|
|
mutex_unlock(&mdesc_mutex);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+u64 mdesc_get_node(struct mdesc_handle *hp, const char *node_name,
|
|
|
|
+ union md_node_info *node_info)
|
|
|
|
+{
|
|
|
|
+ mdesc_node_info_get_f get_info_func;
|
|
|
|
+ mdesc_node_info_rel_f rel_info_func;
|
|
|
|
+ mdesc_node_match_f node_match_func;
|
|
|
|
+ union md_node_info hp_node_info;
|
|
|
|
+ u64 hp_node;
|
|
|
|
+ int rv;
|
|
|
|
+
|
|
|
|
+ if (hp == NULL || node_name == NULL || node_info == NULL)
|
|
|
|
+ return MDESC_NODE_NULL;
|
|
|
|
+
|
|
|
|
+ /* Find the ops for the given node name */
|
|
|
|
+ mdesc_get_node_ops(node_name, &get_info_func, &rel_info_func,
|
|
|
|
+ &node_match_func);
|
|
|
|
+
|
|
|
|
+ /* If we didn't find ops for the given node name, it is not supported */
|
|
|
|
+ if (!get_info_func || !rel_info_func || !node_match_func) {
|
|
|
|
+ pr_err("MD: %s node is not supported\n", node_name);
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ mdesc_for_each_node_by_name(hp, hp_node, node_name) {
|
|
|
|
+ rv = get_info_func(hp, hp_node, &hp_node_info);
|
|
|
|
+ if (rv != 0)
|
|
|
|
+ continue;
|
|
|
|
+
|
|
|
|
+ if (node_match_func(node_info, &hp_node_info))
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ rel_info_func(&hp_node_info);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ rel_info_func(&hp_node_info);
|
|
|
|
+
|
|
|
|
+ return hp_node;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int mdesc_get_node_info(struct mdesc_handle *hp, u64 node,
|
|
|
|
+ const char *node_name, union md_node_info *node_info)
|
|
|
|
+{
|
|
|
|
+ mdesc_node_info_get_f get_info_func;
|
|
|
|
+ int rv;
|
|
|
|
+
|
|
|
|
+ if (hp == NULL || node == MDESC_NODE_NULL ||
|
|
|
|
+ node_name == NULL || node_info == NULL)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ /* Find the get_info op for the given node name */
|
|
|
|
+ mdesc_get_node_ops(node_name, &get_info_func, NULL, NULL);
|
|
|
|
+
|
|
|
|
+ /* If we didn't find a get_info_func, the node name is not supported */
|
|
|
|
+ if (get_info_func == NULL) {
|
|
|
|
+ pr_err("MD: %s node is not supported\n", node_name);
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ rv = get_info_func(hp, node, node_info);
|
|
|
|
+ if (rv != 0) {
|
|
|
|
+ pr_err("MD: Cannot find 1 or more required match properties for %s node.\n",
|
|
|
|
+ node_name);
|
|
|
|
+ return -1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
static struct mdesc_elem *node_block(struct mdesc_hdr *mdesc)
|
|
static struct mdesc_elem *node_block(struct mdesc_hdr *mdesc)
|
|
{
|
|
{
|
|
return (struct mdesc_elem *) (mdesc + 1);
|
|
return (struct mdesc_elem *) (mdesc + 1);
|