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

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
...@@ -329,7 +329,6 @@ struct vio_dev { ...@@ -329,7 +329,6 @@ struct vio_dev {
int compat_len; int compat_len;
u64 dev_no; u64 dev_no;
u64 id;
unsigned long channel_id; unsigned long channel_id;
...@@ -341,6 +340,9 @@ struct vio_dev { ...@@ -341,6 +340,9 @@ struct vio_dev {
/* Handle to the root of "channel-devices" sub-tree in MDESC */ /* Handle to the root of "channel-devices" sub-tree in MDESC */
u64 cdev_handle; u64 cdev_handle;
/* MD specific data used to identify the vdev in MD */
union md_node_info md_node_info;
struct device dev; struct device dev;
}; };
...@@ -497,5 +499,6 @@ int vio_driver_init(struct vio_driver_state *vio, struct vio_dev *vdev, ...@@ -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); void vio_port_up(struct vio_driver_state *vio);
int vio_set_intr(unsigned long dev_ino, int state); 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 */ #endif /* _SPARC64_VIO_H */
...@@ -574,6 +574,7 @@ u64 mdesc_get_node(struct mdesc_handle *hp, const char *node_name, ...@@ -574,6 +574,7 @@ u64 mdesc_get_node(struct mdesc_handle *hp, const char *node_name,
return hp_node; return hp_node;
} }
EXPORT_SYMBOL(mdesc_get_node);
int mdesc_get_node_info(struct mdesc_handle *hp, u64 node, int mdesc_get_node_info(struct mdesc_handle *hp, u64 node,
const char *node_name, union md_node_info *node_info) 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, ...@@ -603,6 +604,7 @@ int mdesc_get_node_info(struct mdesc_handle *hp, u64 node,
return 0; return 0;
} }
EXPORT_SYMBOL(mdesc_get_node_info);
static struct mdesc_elem *node_block(struct mdesc_hdr *mdesc) static struct mdesc_elem *node_block(struct mdesc_hdr *mdesc)
{ {
......
...@@ -217,6 +217,32 @@ static const u64 *vio_cfg_handle(struct mdesc_handle *hp, u64 node) ...@@ -217,6 +217,32 @@ static const u64 *vio_cfg_handle(struct mdesc_handle *hp, u64 node)
return cfg_handle; 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, static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp,
struct vio_dev *vdev) struct vio_dev *vdev)
{ {
...@@ -316,16 +342,13 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, ...@@ -316,16 +342,13 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
if (!id) { if (!id) {
dev_set_name(&vdev->dev, "%s", type); dev_set_name(&vdev->dev, "%s", type);
vdev->dev_no = ~(u64)0; vdev->dev_no = ~(u64)0;
vdev->id = ~(u64)0;
} else if (!cfg_handle) { } else if (!cfg_handle) {
dev_set_name(&vdev->dev, "%s-%llu", type, *id); dev_set_name(&vdev->dev, "%s-%llu", type, *id);
vdev->dev_no = *id; vdev->dev_no = *id;
vdev->id = ~(u64)0;
} else { } else {
dev_set_name(&vdev->dev, "%s-%llu-%llu", type, dev_set_name(&vdev->dev, "%s-%llu-%llu", type,
*cfg_handle, *id); *cfg_handle, *id);
vdev->dev_no = *cfg_handle; vdev->dev_no = *cfg_handle;
vdev->id = *id;
} }
vdev->dev.parent = parent; vdev->dev.parent = parent;
...@@ -347,11 +370,24 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, ...@@ -347,11 +370,24 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
} }
vdev->dp = dp; 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", (void) snprintf(vdev->node_name, VIO_MAX_NAME_LEN, "%s",
node_name); 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", pr_info("VIO: Adding device %s (tx_ino = %llx, rx_ino = %llx)\n",
dev_name(&vdev->dev), vdev->tx_ino, vdev->rx_ino); dev_name(&vdev->dev), vdev->tx_ino, vdev->rx_ino);
...@@ -375,68 +411,36 @@ static void vio_add(struct mdesc_handle *hp, u64 node, ...@@ -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); (void) vio_create_one(hp, node, node_name, &root_vdev->dev);
} }
struct vio_md_node_query { struct vio_remove_node_data {
const char *type; struct mdesc_handle *hp;
u64 dev_no; u64 node;
u64 id;
}; };
static int vio_md_node_match(struct device *dev, void *arg) 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_dev *vdev = to_vio_dev(dev);
struct vio_remove_node_data *node_data;
u64 node;
if (vdev->dev_no != query->dev_no) node_data = (struct vio_remove_node_data *)arg;
return 0;
if (vdev->id != query->id)
return 0;
if (strcmp(vdev->type, query->type))
return 0;
return 1; 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) static void vio_remove(struct mdesc_handle *hp, u64 node, const char *node_name)
{ {
const char *type; struct vio_remove_node_data node_data;
const u64 *id, *cfg_handle;
u64 a;
struct vio_md_node_query query;
struct device *dev; struct device *dev;
type = mdesc_get_property(hp, node, "device-type", NULL); node_data.hp = hp;
if (!type) { node_data.node = node;
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;
}
dev = device_find_child(&root_vdev->dev, &query, dev = device_find_child(&root_vdev->dev, (void *)&node_data,
vio_md_node_match); vio_md_node_match);
if (dev) { if (dev) {
printk(KERN_INFO "VIO: Removing device %s\n", dev_name(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) ...@@ -444,15 +448,7 @@ static void vio_remove(struct mdesc_handle *hp, u64 node, const char *node_name)
device_unregister(dev); device_unregister(dev);
put_device(dev); put_device(dev);
} else { } else {
if (!id) pr_err("VIO: %s node not found in MDESC\n", node_name);
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);
} }
} }
......
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