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

sparc64: enhance VIO device probing

- Allocate IRQs for VIO devices during probing.
- Allow clients to specify if IRQs would be allocated for a given
  VIO device.
- Cache the device handle of the root node of channel-devices sub-tree in
  Machine Description (MDESC).
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 110f2264
...@@ -336,6 +336,10 @@ struct vio_dev { ...@@ -336,6 +336,10 @@ struct vio_dev {
unsigned int tx_irq; unsigned int tx_irq;
unsigned int rx_irq; unsigned int rx_irq;
u64 rx_ino; u64 rx_ino;
u64 tx_ino;
/* Handle to the root of "channel-devices" sub-tree in MDESC */
u64 cdev_handle;
struct device dev; struct device dev;
}; };
...@@ -349,6 +353,7 @@ struct vio_driver { ...@@ -349,6 +353,7 @@ struct vio_driver {
void (*shutdown)(struct vio_dev *dev); void (*shutdown)(struct vio_dev *dev);
unsigned long driver_data; unsigned long driver_data;
struct device_driver driver; struct device_driver driver;
bool no_irq;
}; };
struct vio_version { struct vio_version {
......
...@@ -70,15 +70,26 @@ static int vio_device_probe(struct device *dev) ...@@ -70,15 +70,26 @@ static int vio_device_probe(struct device *dev)
struct vio_dev *vdev = to_vio_dev(dev); struct vio_dev *vdev = to_vio_dev(dev);
struct vio_driver *drv = to_vio_driver(dev->driver); struct vio_driver *drv = to_vio_driver(dev->driver);
const struct vio_device_id *id; const struct vio_device_id *id;
int error = -ENODEV;
if (drv->probe) { if (!drv->probe)
id = vio_match_device(drv->id_table, vdev); return -ENODEV;
if (id)
error = drv->probe(vdev, id); id = vio_match_device(drv->id_table, vdev);
if (!id)
return -ENODEV;
/* alloc irqs (unless the driver specified not to) */
if (!drv->no_irq) {
if (vdev->tx_irq == 0 && vdev->tx_ino != ~0UL)
vdev->tx_irq = sun4v_build_virq(vdev->cdev_handle,
vdev->tx_ino);
if (vdev->rx_irq == 0 && vdev->rx_ino != ~0UL)
vdev->rx_irq = sun4v_build_virq(vdev->cdev_handle,
vdev->rx_ino);
} }
return error; return drv->probe(vdev, id);
} }
static int vio_device_remove(struct device *dev) static int vio_device_remove(struct device *dev)
...@@ -86,8 +97,15 @@ static int vio_device_remove(struct device *dev) ...@@ -86,8 +97,15 @@ static int vio_device_remove(struct device *dev)
struct vio_dev *vdev = to_vio_dev(dev); struct vio_dev *vdev = to_vio_dev(dev);
struct vio_driver *drv = to_vio_driver(dev->driver); struct vio_driver *drv = to_vio_driver(dev->driver);
if (drv->remove) if (drv->remove) {
/*
* Ideally, we would remove/deallocate tx/rx virqs
* here - however, there are currently no support
* routines to do so at the moment. TBD
*/
return drv->remove(vdev); return drv->remove(vdev);
}
return 1; return 1;
} }
...@@ -204,6 +222,9 @@ static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp, ...@@ -204,6 +222,9 @@ static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp,
{ {
u64 a; u64 a;
vdev->tx_ino = ~0UL;
vdev->rx_ino = ~0UL;
vdev->channel_id = ~0UL;
mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_FWD) { mdesc_for_each_arc(a, hp, mp, MDESC_ARC_TYPE_FWD) {
const u64 *chan_id; const u64 *chan_id;
const u64 *irq; const u64 *irq;
...@@ -213,18 +234,18 @@ static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp, ...@@ -213,18 +234,18 @@ static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp,
irq = mdesc_get_property(hp, target, "tx-ino", NULL); irq = mdesc_get_property(hp, target, "tx-ino", NULL);
if (irq) if (irq)
vdev->tx_irq = sun4v_build_virq(cdev_cfg_handle, *irq); vdev->tx_ino = *irq;
irq = mdesc_get_property(hp, target, "rx-ino", NULL); irq = mdesc_get_property(hp, target, "rx-ino", NULL);
if (irq) { if (irq)
vdev->rx_irq = sun4v_build_virq(cdev_cfg_handle, *irq);
vdev->rx_ino = *irq; vdev->rx_ino = *irq;
}
chan_id = mdesc_get_property(hp, target, "id", NULL); chan_id = mdesc_get_property(hp, target, "id", NULL);
if (chan_id) if (chan_id)
vdev->channel_id = *chan_id; vdev->channel_id = *chan_id;
} }
vdev->cdev_handle = cdev_cfg_handle;
} }
int vio_set_intr(unsigned long dev_ino, int state) int vio_set_intr(unsigned long dev_ino, int state)
...@@ -287,9 +308,8 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, ...@@ -287,9 +308,8 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
memset(vdev->compat, 0, sizeof(vdev->compat)); memset(vdev->compat, 0, sizeof(vdev->compat));
vdev->compat_len = clen; vdev->compat_len = clen;
vdev->channel_id = ~0UL; vdev->tx_irq = 0;
vdev->tx_irq = ~0; vdev->rx_irq = 0;
vdev->rx_irq = ~0;
vio_fill_channel_info(hp, mp, vdev); vio_fill_channel_info(hp, mp, vdev);
...@@ -327,13 +347,14 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, ...@@ -327,13 +347,14 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
} }
vdev->dp = dp; vdev->dp = dp;
printk(KERN_INFO "VIO: Adding device %s\n", dev_name(&vdev->dev));
/* node_name is NULL for the parent/channel-devices node */ /* node_name is NULL for the parent/channel-devices node */
if (node_name != NULL) 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);
pr_info("VIO: Adding device %s (tx_ino = %llx, rx_ino = %llx)\n",
dev_name(&vdev->dev), vdev->tx_ino, vdev->rx_ino);
err = device_register(&vdev->dev); err = device_register(&vdev->dev);
if (err) { if (err) {
printk(KERN_ERR "VIO: Could not register device %s, err=%d\n", printk(KERN_ERR "VIO: Could not register device %s, err=%d\n",
......
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