Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f4d29ca7 authored by Jag Raman's avatar Jag Raman Committed by David S. Miller
Browse files

sparc64: Enhance search for VIO device in MDESC



Enhances search for VIO device in MDESC by leveraging already existing
MDESC APIs. Enhances changes in earlier patch,
"sparc: Machine description indices can vary", by using existing MD
search functions. It also specifies a match function, thereby
enabling device_find_child() to use it for the purpose of matching
device nodes in MDESC.

An API to find VDEV node in MDESC based on its md_node_info is also
added. It is planned to be used by VIO device clients in the future.

Signed-off-by: default avatarJagannathan Raman <jag.raman@oracle.com>
Reviewed-by: default avatarLiam Merwick <liam.merwick@oracle.com>
Reviewed-by: default avatarShannon Nelson <shannon.nelson@oracle.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent aa512d5e
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -329,7 +329,6 @@ struct vio_dev {
	int			compat_len;

	u64			dev_no;
	u64			id;

	unsigned long		channel_id;

@@ -341,6 +340,9 @@ struct vio_dev {
	/* Handle to the root of "channel-devices" sub-tree in MDESC */
	u64			cdev_handle;

	/* MD specific data used to identify the vdev in MD */
	union md_node_info	md_node_info;

	struct device		dev;
};

@@ -497,5 +499,6 @@ int vio_driver_init(struct vio_driver_state *vio, struct vio_dev *vdev,

void vio_port_up(struct vio_driver_state *vio);
int vio_set_intr(unsigned long dev_ino, int state);
u64 vio_vdev_node(struct mdesc_handle *hp, struct vio_dev *vdev);

#endif /* _SPARC64_VIO_H */
+2 −0
Original line number Diff line number Diff line
@@ -574,6 +574,7 @@ u64 mdesc_get_node(struct mdesc_handle *hp, const char *node_name,

	return hp_node;
}
EXPORT_SYMBOL(mdesc_get_node);

int mdesc_get_node_info(struct mdesc_handle *hp, u64 node,
			const char *node_name, union md_node_info *node_info)
@@ -603,6 +604,7 @@ int mdesc_get_node_info(struct mdesc_handle *hp, u64 node,

	return 0;
}
EXPORT_SYMBOL(mdesc_get_node_info);

static struct mdesc_elem *node_block(struct mdesc_hdr *mdesc)
{
+58 −62
Original line number Diff line number Diff line
@@ -217,6 +217,32 @@ static const u64 *vio_cfg_handle(struct mdesc_handle *hp, u64 node)
	return cfg_handle;
}

/**
 * vio_vdev_node() - Find VDEV node in MD
 * @hp:  Handle to the MD
 * @vdev:  Pointer to VDEV
 *
 * Find the node in the current MD which matches the given vio_dev. This
 * must be done dynamically since the node value can change if the MD
 * is updated.
 *
 * NOTE: the MD must be locked, using mdesc_grab(), when calling this routine
 *
 * Return: The VDEV node in MDESC
 */
u64 vio_vdev_node(struct mdesc_handle *hp, struct vio_dev *vdev)
{
	u64 node;

	if (vdev == NULL)
		return MDESC_NODE_NULL;

	node = mdesc_get_node(hp, (const char *)vdev->node_name,
			      &vdev->md_node_info);

	return node;
}

static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp,
				  struct vio_dev *vdev)
{
@@ -316,16 +342,13 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
	if (!id) {
		dev_set_name(&vdev->dev, "%s", type);
		vdev->dev_no = ~(u64)0;
		vdev->id = ~(u64)0;
	} else if (!cfg_handle) {
		dev_set_name(&vdev->dev, "%s-%llu", type, *id);
		vdev->dev_no = *id;
		vdev->id = ~(u64)0;
	} else {
		dev_set_name(&vdev->dev, "%s-%llu-%llu", type,
			     *cfg_handle, *id);
		vdev->dev_no = *cfg_handle;
		vdev->id = *id;
	}

	vdev->dev.parent = parent;
@@ -347,11 +370,24 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
	}
	vdev->dp = dp;

	/* node_name is NULL for the parent/channel-devices node */
	if (node_name != NULL)
	/*
	 * node_name is NULL for the parent/channel-devices node and
	 * the parent doesn't require the MD node info.
	 */
	if (node_name != NULL) {
		(void) snprintf(vdev->node_name, VIO_MAX_NAME_LEN, "%s",
				node_name);

		err = mdesc_get_node_info(hp, mp, node_name,
					  &vdev->md_node_info);
		if (err) {
			pr_err("VIO: Could not get MD node info %s, err=%d\n",
			       dev_name(&vdev->dev), err);
			kfree(vdev);
			return NULL;
		}
	}

	pr_info("VIO: Adding device %s (tx_ino = %llx, rx_ino = %llx)\n",
		dev_name(&vdev->dev), vdev->tx_ino, vdev->rx_ino);

@@ -375,68 +411,36 @@ static void vio_add(struct mdesc_handle *hp, u64 node,
	(void) vio_create_one(hp, node, node_name, &root_vdev->dev);
}

struct vio_md_node_query {
	const char *type;
	u64 dev_no;
	u64 id;
struct vio_remove_node_data {
	struct mdesc_handle *hp;
	u64 node;
};

static int vio_md_node_match(struct device *dev, void *arg)
{
	struct vio_md_node_query *query = (struct vio_md_node_query *) arg;
	struct vio_dev *vdev = to_vio_dev(dev);
	struct vio_remove_node_data *node_data;
	u64 node;

	if (vdev->dev_no != query->dev_no)
		return 0;
	if (vdev->id != query->id)
		return 0;
	if (strcmp(vdev->type, query->type))
		return 0;
	node_data = (struct vio_remove_node_data *)arg;

	node = vio_vdev_node(node_data->hp, vdev);

	if (node == node_data->node)
		return 1;
	else
		return 0;
}

static void vio_remove(struct mdesc_handle *hp, u64 node, const char *node_name)
{
	const char *type;
	const u64 *id, *cfg_handle;
	u64 a;
	struct vio_md_node_query query;
	struct vio_remove_node_data node_data;
	struct device *dev;

	type = mdesc_get_property(hp, node, "device-type", NULL);
	if (!type) {
		type = mdesc_get_property(hp, node, "name", NULL);
		if (!type)
			type = mdesc_node_name(hp, node);
	}

	query.type = type;

	id = mdesc_get_property(hp, node, "id", NULL);
	cfg_handle = NULL;
	mdesc_for_each_arc(a, hp, node, MDESC_ARC_TYPE_BACK) {
		u64 target;

		target = mdesc_arc_target(hp, a);
		cfg_handle = mdesc_get_property(hp, target,
						"cfg-handle", NULL);
		if (cfg_handle)
			break;
	}

	if (!id) {
		query.dev_no = ~(u64)0;
		query.id = ~(u64)0;
	} else if (!cfg_handle) {
		query.dev_no = *id;
		query.id = ~(u64)0;
	} else {
		query.dev_no = *cfg_handle;
		query.id = *id;
	}
	node_data.hp = hp;
	node_data.node = node;

	dev = device_find_child(&root_vdev->dev, &query,
	dev = device_find_child(&root_vdev->dev, (void *)&node_data,
				vio_md_node_match);
	if (dev) {
		printk(KERN_INFO "VIO: Removing device %s\n", dev_name(dev));
@@ -444,15 +448,7 @@ static void vio_remove(struct mdesc_handle *hp, u64 node, const char *node_name)
		device_unregister(dev);
		put_device(dev);
	} else {
		if (!id)
			printk(KERN_ERR "VIO: Removed unknown %s node.\n",
			       type);
		else if (!cfg_handle)
			printk(KERN_ERR "VIO: Removed unknown %s node %llu.\n",
			       type, *id);
		else
			printk(KERN_ERR "VIO: Removed unknown %s node %llu-%llu.\n",
			       type, *cfg_handle, *id);
		pr_err("VIO: %s node not found in MDESC\n", node_name);
	}
}