diff -ruN ppc64-linux-2.5/arch/ppc64/kernel/vio.c ppc64-linux-2.5.daveb.sfr.10/arch/ppc64/kernel/vio.c --- ppc64-linux-2.5/arch/ppc64/kernel/vio.c 2004-06-10 14:48:03.000000000 +1000 +++ ppc64-linux-2.5.daveb.sfr.10/arch/ppc64/kernel/vio.c 2004-06-20 01:36:26.000000000 +1000 @@ -26,17 +26,19 @@ #include #include #include +#include #include +#include #define DBGENTER() pr_debug("%s entered\n", __FUNCTION__) extern struct subsystem devices_subsys; /* needed for vio_find_name() */ -static struct iommu_table *vio_build_iommu_table(struct vio_dev *); static const struct vio_device_id *vio_match_device( const struct vio_device_id *, const struct vio_dev *); #ifdef CONFIG_PPC_PSERIES +static struct iommu_table *vio_build_iommu_table(struct vio_dev *); static int vio_num_address_cells; #endif static struct vio_dev *vio_bus_device; /* fake "parent" device */ @@ -45,20 +47,15 @@ static struct iommu_table veth_iommu_table; static struct iommu_table vio_iommu_table; -static struct vio_dev _veth_dev = { - .iommu_table = &veth_iommu_table, - .dev.bus = &vio_bus_type -}; static struct vio_dev _vio_dev = { .iommu_table = &vio_iommu_table, .dev.bus = &vio_bus_type }; - -struct vio_dev *iSeries_veth_dev = &_veth_dev; struct device *iSeries_vio_dev = &_vio_dev.dev; - -EXPORT_SYMBOL(iSeries_veth_dev); EXPORT_SYMBOL(iSeries_vio_dev); + +#define device_is_compatible(a, b) 1 + #endif /* convert from struct device to struct vio_dev and pass to driver. @@ -143,14 +140,12 @@ { DBGENTER(); -#ifdef CONFIG_PPC_PSERIES while (ids->type) { - if ((strncmp(((struct device_node *)dev->dev.platform_data)->type, ids->type, strlen(ids->type)) == 0) && + if ((strncmp(dev->type, ids->type, strlen(ids->type)) == 0) && device_is_compatible(dev->dev.platform_data, ids->compat)) return ids; ids++; } -#endif return NULL; } @@ -196,14 +191,63 @@ } #endif +#ifdef CONFIG_PPC_PSERIES +static void probe_bus_pseries(void) +{ + struct device_node *node_vroot, *of_node; + + node_vroot = find_devices("vdevice"); + if ((node_vroot == NULL) || (node_vroot->child == NULL)) + /* this machine doesn't do virtual IO, and that's ok */ + return; + + vio_num_address_cells = prom_n_addr_cells(node_vroot->child); + + /* + * Create struct vio_devices for each virtual device in the device tree. + * Drivers will associate with them later. + */ + for (of_node = node_vroot->child; of_node != NULL; + of_node = of_node->sibling) { + printk(KERN_DEBUG "%s: processing %p\n", __FUNCTION__, of_node); + vio_register_device(of_node); + } +} +#endif + +#ifdef CONFIG_PPC_ISERIES +static void probe_bus_iseries(void) +{ + HvLpIndexMap vlan_map = HvLpConfig_getVirtualLanIndexMap(); + struct vio_dev *viodev; + int i; + + /* there is only one of each of these */ + vio_register_device("viocons", 0); + vio_register_device("vioscsi", 0); + + vlan_map = HvLpConfig_getVirtualLanIndexMap(); + for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; i++) { + if ((vlan_map & (0x8000 >> i)) == 0) + continue; + viodev = vio_register_device("vlan", i); + /* veth is special and has it own iommu_table */ + viodev->iommu_table = &veth_iommu_table; + } + for (i = 0; i < HVMAXARCHITECTEDVIRTUALDISKS; i++) + vio_register_device("viodasd", i); + for (i = 0; i < HVMAXARCHITECTEDVIRTUALCDROMS; i++) + vio_register_device("viocd", i); + for (i = 0; i < HVMAXARCHITECTEDVIRTUALTAPES; i++) + vio_register_device("viotape", i); +} +#endif + /** * vio_bus_init: - Initialize the virtual IO bus */ static int __init vio_bus_init(void) { -#ifdef CONFIG_PPC_PSERIES - struct device_node *node_vroot, *of_node; -#endif int err; err = bus_register(&vio_bus_type); @@ -229,25 +273,10 @@ } #ifdef CONFIG_PPC_PSERIES - node_vroot = find_devices("vdevice"); - if ((node_vroot == NULL) || (node_vroot->child == NULL)) { - /* this machine doesn't do virtual IO, and that's ok */ - return 0; - } - - vio_num_address_cells = prom_n_addr_cells(node_vroot->child); - - /* - * Create struct vio_devices for each virtual device in the device tree. - * Drivers will associate with them later. - */ - for (of_node = node_vroot->child; - of_node != NULL; - of_node = of_node->sibling) { - printk(KERN_DEBUG "%s: processing %p\n", __FUNCTION__, of_node); - - vio_register_device(of_node); - } + probe_bus_pseries(); +#endif +#ifdef CONFIG_PPC_ISERIES + probe_bus_iseries(); #endif return 0; @@ -255,20 +284,19 @@ __initcall(vio_bus_init); - -#ifdef CONFIG_PPC_PSERIES /* vio_dev refcount hit 0 */ static void __devinit vio_dev_release(struct device *dev) { - struct vio_dev *viodev = to_vio_dev(dev); - DBGENTER(); +#ifdef CONFIG_PPC_PSERIES /* XXX free TCE table */ - of_node_put(viodev->dev.platform_data); - kfree(viodev); + of_node_put(dev->platform_data); +#endif + kfree(to_vio_dev(dev)); } +#ifdef CONFIG_PPC_PSERIES static ssize_t viodev_show_devspec(struct device *dev, char *buf) { struct device_node *of_node = dev->platform_data; @@ -276,15 +304,41 @@ return sprintf(buf, "%s\n", of_node->full_name); } DEVICE_ATTR(devspec, S_IRUSR | S_IRGRP | S_IROTH, viodev_show_devspec, NULL); +#endif static ssize_t viodev_show_name(struct device *dev, char *buf) { - struct device_node *of_node = dev->platform_data; - - return sprintf(buf, "%s\n", of_node->name); + return sprintf(buf, "%s\n", to_vio_dev(dev)->name); } DEVICE_ATTR(name, S_IRUSR | S_IRGRP | S_IROTH, viodev_show_name, NULL); +static struct vio_dev * __devinit vio_register_device_common( + struct vio_dev *viodev, char *name, char *type, + uint32_t unit_address, struct iommu_table *iommu_table) +{ + DBGENTER(); + + viodev->name = name; + viodev->type = type; + viodev->unit_address = unit_address; + viodev->iommu_table = iommu_table; + /* init generic 'struct device' fields: */ + viodev->dev.parent = &vio_bus_device->dev; + viodev->dev.bus = &vio_bus_type; + viodev->dev.release = vio_dev_release; + + /* register with generic device framework */ + if (device_register(&viodev->dev)) { + printk(KERN_ERR "%s: failed to register device %s\n", + __FUNCTION__, viodev->dev.bus_id); + return NULL; + } + device_create_file(&viodev->dev, &dev_attr_name); + + return viodev; +} + +#ifdef CONFIG_PPC_PSERIES /** * vio_register_device: - Register a new vio device. * @of_node: The OF node for this device. @@ -325,8 +379,6 @@ memset(viodev, 0, sizeof(struct vio_dev)); viodev->dev.platform_data = of_node_get(of_node); - viodev->unit_address = *unit_address; - viodev->iommu_table = vio_build_iommu_table(viodev); viodev->irq = NO_IRQ; irq_p = (unsigned int *)get_property(of_node, "interrupts", 0); @@ -339,36 +391,59 @@ viodev->irq = irq_offset_up(virq); } - /* init generic 'struct device' fields: */ - viodev->dev.parent = &vio_bus_device->dev; - viodev->dev.bus = &vio_bus_type; - snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%x", viodev->unit_address); - viodev->dev.release = vio_dev_release; + snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%x", *unit_address); /* register with generic device framework */ - if (device_register(&viodev->dev)) { - printk(KERN_ERR "%s: failed to register device %s\n", __FUNCTION__, - viodev->dev.bus_id); + if (vio_register_device_common(viodev, of_node->name, of_node->type, + *unit_address, vio_build_iommu_table(viodev)) + == NULL) { /* XXX free TCE table */ kfree(viodev); return NULL; } - device_create_file(&viodev->dev, &dev_attr_name); device_create_file(&viodev->dev, &dev_attr_devspec); return viodev; } +#endif + +#ifdef CONFIG_PPC_ISERIES +/** + * vio_register_device: - Register a new vio device. + * @voidev: The device to register. + */ +struct vio_dev *__devinit vio_register_device(char *type, uint32_t unit_num) +{ + struct vio_dev *viodev; + + DBGENTER(); + + /* allocate a vio_dev for this node */ + viodev = kmalloc(sizeof(struct vio_dev), GFP_KERNEL); + if (!viodev) + return NULL; + memset(viodev, 0, sizeof(struct vio_dev)); + + snprintf(viodev->dev.bus_id, BUS_ID_SIZE, "%s%d", type, unit_num); + + return vio_register_device_common(viodev, viodev->dev.bus_id, type, + unit_num, &vio_iommu_table); +} +#endif EXPORT_SYMBOL(vio_register_device); void __devinit vio_unregister_device(struct vio_dev *viodev) { DBGENTER(); +#ifdef CONFIG_PPC_PSERIES device_remove_file(&viodev->dev, &dev_attr_devspec); +#endif device_remove_file(&viodev->dev, &dev_attr_name); device_unregister(&viodev->dev); } EXPORT_SYMBOL(vio_unregister_device); +#ifdef CONFIG_PPC_PSERIES /** * vio_get_attribute: - get attribute for virtual device * @vdev: The vio device to get property. diff -ruN ppc64-linux-2.5/drivers/block/viodasd.c ppc64-linux-2.5.daveb.sfr.10/drivers/block/viodasd.c --- ppc64-linux-2.5/drivers/block/viodasd.c 2004-05-26 16:04:50.000000000 +1000 +++ ppc64-linux-2.5.daveb.sfr.10/drivers/block/viodasd.c 2004-06-19 21:53:41.000000000 +1000 @@ -68,7 +68,7 @@ enum { PARTITION_SHIFT = 3, - MAX_DISKNO = 32, + MAX_DISKNO = HVMAXARCHITECTEDVIRTUALDISKS, MAX_DISK_NAME = sizeof(((struct gendisk *)0)->disk_name) }; @@ -168,6 +168,7 @@ int read_only; spinlock_t q_lock; struct gendisk *disk; + struct device *dev; } viodasd_devices[MAX_DISKNO]; /* @@ -342,7 +343,7 @@ /* Now build the scatter-gather list */ nsg = blk_rq_map_sg(req->q, req, sg); - nsg = dma_map_sg(iSeries_vio_dev, sg, nsg, direction); + nsg = dma_map_sg(d->dev, sg, nsg, direction); spin_lock_irqsave(&viodasd_spinlock, flags); num_req_outstanding++; @@ -422,7 +423,7 @@ error_ret: num_req_outstanding--; spin_unlock_irqrestore(&viodasd_spinlock, flags); - dma_unmap_sg(iSeries_vio_dev, sg, nsg, direction); + dma_unmap_sg(d->dev, sg, nsg, direction); return -1; } @@ -557,6 +558,7 @@ g->fops = &viodasd_fops; g->queue = q; g->private_data = d; + g->driverfs_dev = d->dev; set_capacity(g, d->size >> 9); printk(VIOD_KERN_INFO "disk %d: %lu sectors (%lu MB) " @@ -623,7 +625,7 @@ struct scatterlist sg[VIOMAXBLOCKDMA]; struct HvLpEvent *event = &bevent->event; unsigned long irq_flags; - int device_no; + struct viodasd_device *d; int error; spinlock_t *qlock; @@ -633,7 +635,10 @@ pci_direction = DMA_FROM_DEVICE; else pci_direction = DMA_TO_DEVICE; - dma_unmap_sg(iSeries_vio_dev, sg, num_sg, pci_direction); + req = (struct request *)bevent->event.xCorrelationToken; + d = req->rq_disk->private_data; + + dma_unmap_sg(d->dev, sg, num_sg, pci_direction); /* * Since this is running in interrupt mode, we need to make sure @@ -643,9 +648,6 @@ num_req_outstanding--; spin_unlock_irqrestore(&viodasd_spinlock, irq_flags); - req = (struct request *)bevent->event.xCorrelationToken; - device_no = DEVICE_NO(req->rq_disk->private_data); - error = event->xRc != HvLpEvent_Rc_Good; if (error) { const struct vio_error_entry *err; @@ -660,7 +662,7 @@ spin_unlock_irqrestore(qlock, irq_flags); /* Finally, try to get more requests off of this device's queue */ - viodasd_restart_all_queues_starting_from(device_no); + viodasd_restart_all_queues_starting_from(DEVICE_NO(d)); return 0; } @@ -744,8 +746,47 @@ } static DRIVER_ATTR(probe, S_IWUSR, NULL, probe_disks) +static int viodasd_probe(struct vio_dev *vdev, const struct vio_device_id *id) +{ + struct viodasd_device *d = &viodasd_devices[vdev->unit_address]; + + d->dev = &vdev->dev; + probe_disk(d); + if (d->disk == NULL) + return -ENODEV; + return 0; +} + +static int viodasd_remove(struct vio_dev *vdev) +{ + struct viodasd_device *d; + + d = &viodasd_devices[vdev->unit_address]; + if (d->disk) { + del_gendisk(d->disk); + put_disk(d->disk); + blk_cleanup_queue(d->disk->queue); + d->disk = NULL; + } + d->dev = NULL; + return 0; +} + +/** + * viodasd_device_table: Used by vio.c to match devices that we + * support. + */ +static struct vio_device_id viodasd_device_table[] __devinitdata = { + { "viodasd", "" }, + { 0, } +}; + +MODULE_DEVICE_TABLE(vio, viodasd_device_table); static struct vio_driver viodasd_driver = { - .name = "viodasd" + .name = "viodasd", + .id_table = viodasd_device_table, + .probe = viodasd_probe, + .remove = viodasd_remove }; /* @@ -754,7 +795,7 @@ */ static int __init viodasd_init(void) { - int i; + int rc; /* Try to open to our host lp */ if (viopath_hostLp == HvLpIndexInvalid) @@ -788,33 +829,17 @@ /* Initialize our request handler */ vio_setHandler(viomajorsubtype_blockio, handle_block_event); - for (i = 0; i < MAX_DISKNO; i++) - probe_disk(&viodasd_devices[i]); - - vio_register_driver(&viodasd_driver); /* FIX ME - error checking */ - driver_create_file(&viodasd_driver.driver, &driver_attr_probe); - - return 0; + rc = vio_register_driver(&viodasd_driver); + if (rc == 0) + driver_create_file(&viodasd_driver.driver, &driver_attr_probe); + return rc; } module_init(viodasd_init); void viodasd_exit(void) { - int i; - struct viodasd_device *d; - driver_remove_file(&viodasd_driver.driver, &driver_attr_probe); vio_unregister_driver(&viodasd_driver); - - for (i = 0; i < MAX_DISKNO; i++) { - d = &viodasd_devices[i]; - if (d->disk) { - del_gendisk(d->disk); - put_disk(d->disk); - blk_cleanup_queue(d->disk->queue); - d->disk = NULL; - } - } vio_clearHandler(viomajorsubtype_blockio); unregister_blkdev(VIODASD_MAJOR, VIOD_GENHD_NAME); viopath_close(viopath_hostLp, viomajorsubtype_blockio, VIOMAXREQ + 2); diff -ruN ppc64-linux-2.5/drivers/cdrom/viocd.c ppc64-linux-2.5.daveb.sfr.10/drivers/cdrom/viocd.c --- ppc64-linux-2.5/drivers/cdrom/viocd.c 2004-04-23 13:07:11.000000000 +1000 +++ ppc64-linux-2.5.daveb.sfr.10/drivers/cdrom/viocd.c 2004-06-20 00:11:22.000000000 +1000 @@ -44,6 +44,7 @@ #include +#include #include #include #include @@ -84,7 +85,7 @@ /* * Should probably make this a module parameter....sigh */ -#define VIOCD_MAX_CD 8 +#define VIOCD_MAX_CD HVMAXARCHITECTEDVIRTUALCDROMS static const struct vio_error_entry viocd_err_table[] = { {0x0201, EINVAL, "Invalid Range"}, @@ -144,6 +145,7 @@ struct disk_info { struct gendisk *viocd_disk; struct cdrom_device_info viocd_info; + struct device *dev; }; static struct disk_info viocd_diskinfo[VIOCD_MAX_CD]; @@ -260,13 +262,13 @@ for (i = 0; (i < VIOCD_MAX_CD) && viocd_unitinfo[i].rsrcname[0]; i++) viocd_numdev++; - return; - error_ret: - dma_free_coherent(iSeries_vio_dev, - sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, - viocd_unitinfo, unitinfo_dmaaddr); - viocd_unitinfo = NULL; + if (viocd_numdev == 0) { + dma_free_coherent(iSeries_vio_dev, + sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, + viocd_unitinfo, unitinfo_dmaaddr); + viocd_unitinfo = NULL; + } } static int viocd_open(struct cdrom_device_info *cdi, int purpose) @@ -341,7 +343,7 @@ return -1; } - if (dma_map_sg(iSeries_vio_dev, &sg, 1, DMA_FROM_DEVICE) == 0) { + if (dma_map_sg(diskinfo->dev, &sg, 1, DMA_FROM_DEVICE) == 0) { printk(VIOCD_KERN_WARNING "error allocating sg tce\n"); return -1; } @@ -513,8 +515,9 @@ * Since this is running in interrupt mode, we need to * make sure we're not stepping on any global I/O operations */ + di = &viocd_diskinfo[bevent->disk]; spin_lock_irqsave(&viocd_reqlock, flags); - dma_unmap_single(iSeries_vio_dev, bevent->token, bevent->len, + dma_unmap_single(di->dev, bevent->token, bevent->len, DMA_FROM_DEVICE); req = (struct request *)bevent->event.xCorrelationToken; rwreq--; @@ -565,12 +568,97 @@ return entry->capability; } -static int __init viocd_init(void) +static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id) { struct gendisk *gendisk; int deviceno; - int ret = 0; + struct disk_info *d; + struct cdrom_device_info *c; + struct cdrom_info *ci; + + deviceno = vdev->unit_address; + if (deviceno >= viocd_numdev) + return -ENODEV; + + d = &viocd_diskinfo[deviceno]; + c = &d->viocd_info; + ci = &viocd_unitinfo[deviceno]; + + c->ops = &viocd_dops; + c->speed = 4; + c->capacity = 1; + c->handle = d; + c->mask = ~find_capability(ci->type); + sprintf(c->name, VIOCD_DEVICE "%c", 'a' + deviceno); + + if (register_cdrom(c) != 0) { + printk(VIOCD_KERN_WARNING "Cannot register viocd CD-ROM %s!\n", + c->name); + return 0; + } + printk(VIOCD_KERN_INFO "cd %s is iSeries resource %10.10s " + "type %4.4s, model %3.3s\n", + c->name, ci->rsrcname, ci->type, ci->model); + gendisk = alloc_disk(1); + if (gendisk == NULL) { + printk(VIOCD_KERN_WARNING "Cannot create gendisk for %s!\n", + c->name); + unregister_cdrom(c); + return 0; + } + gendisk->major = VIOCD_MAJOR; + gendisk->first_minor = deviceno; + strncpy(gendisk->disk_name, c->name, + sizeof(gendisk->disk_name)); + snprintf(gendisk->devfs_name, sizeof(gendisk->devfs_name), + VIOCD_DEVICE_DEVFS "%d", deviceno); + gendisk->queue = viocd_queue; + gendisk->fops = &viocd_fops; + gendisk->flags = GENHD_FL_CD|GENHD_FL_REMOVABLE; + set_capacity(gendisk, 0); + gendisk->private_data = d; + d->viocd_disk = gendisk; + d->dev = &vdev->dev; + gendisk->driverfs_dev = d->dev; + add_disk(gendisk); + + return 0; +} + +static int viocd_remove(struct vio_dev *vdev) +{ + struct disk_info *d = &viocd_diskinfo[vdev->unit_address]; + + if (unregister_cdrom(&d->viocd_info) != 0) + printk(VIOCD_KERN_WARNING + "Cannot unregister viocd CD-ROM %s!\n", + d->viocd_info.name); + del_gendisk(d->viocd_disk); + put_disk(d->viocd_disk); + return 0; +} + +/** + * viocd_device_table: Used by vio.c to match devices that we + * support. + */ +static struct vio_device_id viocd_device_table[] __devinitdata = { + { "viocd", "" }, + { 0, } +}; + +MODULE_DEVICE_TABLE(vio, viocd_device_table); +static struct vio_driver viocd_driver = { + .name = "viocd", + .id_table = viocd_device_table, + .probe = viocd_probe, + .remove = viocd_remove +}; + +static int __init viocd_init(void) +{ struct proc_dir_entry *e; + int ret = 0; if (viopath_hostLp == HvLpIndexInvalid) { vio_set_hostlp(); @@ -583,8 +671,7 @@ viopath_hostLp); if (register_blkdev(VIOCD_MAJOR, VIOCD_DEVICE) != 0) { - printk(VIOCD_KERN_WARNING - "Unable to get major %d for %s\n", + printk(VIOCD_KERN_WARNING "Unable to get major %d for %s\n", VIOCD_MAJOR, VIOCD_DEVICE); return -EIO; } @@ -605,59 +692,19 @@ if (viocd_numdev == 0) goto out_undo_vio; - ret = -ENOMEM; spin_lock_init(&viocd_reqlock); viocd_queue = blk_init_queue(do_viocd_request, &viocd_reqlock); - if (viocd_queue == NULL) - goto out_unregister; + if (viocd_queue == NULL) { + ret = -ENOMEM; + goto out_free_info; + } blk_queue_max_hw_segments(viocd_queue, 1); blk_queue_max_phys_segments(viocd_queue, 1); blk_queue_max_sectors(viocd_queue, 4096 / 512); - /* initialize units */ - for (deviceno = 0; deviceno < viocd_numdev; deviceno++) { - struct disk_info *d = &viocd_diskinfo[deviceno]; - struct cdrom_device_info *c = &d->viocd_info; - struct cdrom_info *ci = &viocd_unitinfo[deviceno]; - - c->ops = &viocd_dops; - c->speed = 4; - c->capacity = 1; - c->handle = d; - c->mask = ~find_capability(ci->type); - sprintf(c->name, VIOCD_DEVICE "%c", 'a' + deviceno); - - if (register_cdrom(c) != 0) { - printk(VIOCD_KERN_WARNING - "Cannot register viocd CD-ROM %s!\n", - c->name); - continue; - } - printk(VIOCD_KERN_INFO "cd %s is iSeries resource %10.10s " - "type %4.4s, model %3.3s\n", - c->name, ci->rsrcname, ci->type, ci->model); - gendisk = alloc_disk(1); - if (gendisk == NULL) { - printk(VIOCD_KERN_WARNING - "Cannot create gendisk for %s!\n", - c->name); - unregister_cdrom(c); - continue; - } - gendisk->major = VIOCD_MAJOR; - gendisk->first_minor = deviceno; - strncpy(gendisk->disk_name, c->name, - sizeof(gendisk->disk_name)); - snprintf(gendisk->devfs_name, sizeof(gendisk->devfs_name), - VIOCD_DEVICE_DEVFS "%d", deviceno); - gendisk->queue = viocd_queue; - gendisk->fops = &viocd_fops; - gendisk->flags = GENHD_FL_CD|GENHD_FL_REMOVABLE; - set_capacity(gendisk, 0); - gendisk->private_data = d; - d->viocd_disk = gendisk; - add_disk(gendisk); - } + ret = vio_register_driver(&viocd_driver); + if (ret) + goto out_cleanup_queue; e = create_proc_entry("iSeries/viocd", S_IFREG|S_IRUGO, NULL); if (e) { @@ -667,6 +714,12 @@ return 0; +out_cleanup_queue: + blk_cleanup_queue(viocd_queue); +out_free_info: + dma_free_coherent(iSeries_vio_dev, + sizeof(*viocd_unitinfo) * VIOCD_MAX_CD, + viocd_unitinfo, unitinfo_dmaaddr); out_undo_vio: vio_clearHandler(viomajorsubtype_cdio); viopath_close(viopath_hostLp, viomajorsubtype_cdio, MAX_CD_REQ + 2); @@ -677,18 +730,8 @@ static void __exit viocd_exit(void) { - int deviceno; - remove_proc_entry("iSeries/viocd", NULL); - for (deviceno = 0; deviceno < viocd_numdev; deviceno++) { - struct disk_info *d = &viocd_diskinfo[deviceno]; - if (unregister_cdrom(&d->viocd_info) != 0) - printk(VIOCD_KERN_WARNING - "Cannot unregister viocd CD-ROM %s!\n", - d->viocd_info.name); - del_gendisk(d->viocd_disk); - put_disk(d->viocd_disk); - } + vio_unregister_driver(&viocd_driver); blk_cleanup_queue(viocd_queue); if (viocd_unitinfo != NULL) dma_free_coherent(iSeries_vio_dev, diff -ruN ppc64-linux-2.5/drivers/char/viotape.c ppc64-linux-2.5.daveb.sfr.10/drivers/char/viotape.c --- ppc64-linux-2.5/drivers/char/viotape.c 2004-04-23 13:07:11.000000000 +1000 +++ ppc64-linux-2.5.daveb.sfr.10/drivers/char/viotape.c 2004-06-20 01:17:34.000000000 +1000 @@ -53,6 +53,7 @@ #include #include +#include #include #include #include @@ -216,7 +217,7 @@ }; /* Maximum number of tapes we support */ -#define VIOTAPE_MAX_TAPE 8 +#define VIOTAPE_MAX_TAPE HVMAXARCHITECTEDVIRTUALTAPES #define MAX_PARTITIONS 4 /* defines for current tape state */ @@ -238,6 +239,8 @@ static struct class_simple *tape_class; +static struct device *tape_device[VIOTAPE_MAX_TAPE]; + /* * maintain the current state of each tape (and partition) * so that we know when to write EOF marks. @@ -262,6 +265,7 @@ int rc; int non_blocking; struct completion com; + struct device *dev; struct op_struct *next; }; @@ -459,7 +463,8 @@ down(&reqSem); /* Allocate a DMA buffer */ - op->buffer = dma_alloc_coherent(iSeries_vio_dev, count, &op->dmaaddr, + op->dev = tape_device[devi.devno]; + op->buffer = dma_alloc_coherent(op->dev, count, &op->dmaaddr, GFP_ATOMIC); if (op->buffer == NULL) { @@ -509,7 +514,7 @@ } free_dma: - dma_free_coherent(iSeries_vio_dev, count, op->buffer, op->dmaaddr); + dma_free_coherent(op->dev, count, op->buffer, op->dmaaddr); up_sem: up(&reqSem); free_op: @@ -550,7 +555,8 @@ chg_state(devi.devno, VIOT_READING, file); /* Allocate a DMA buffer */ - op->buffer = dma_alloc_coherent(iSeries_vio_dev, count, &op->dmaaddr, + op->dev = tape_device[devi.devno]; + op->buffer = dma_alloc_coherent(op->dev, count, &op->dmaaddr, GFP_ATOMIC); if (op->buffer == NULL) { ret = -EFAULT; @@ -588,7 +594,7 @@ } free_dma: - dma_free_coherent(iSeries_vio_dev, count, op->buffer, op->dmaaddr); + dma_free_coherent(op->dev, count, op->buffer, op->dmaaddr); up_sem: up(&reqSem); free_op: @@ -910,7 +916,7 @@ break; case viotapewrite: if (op->non_blocking) { - dma_free_coherent(iSeries_vio_dev, op->count, + dma_free_coherent(op->dev, op->count, op->buffer, op->dmaaddr); free_op_struct(op); up(&reqSem); @@ -936,12 +942,70 @@ } } +static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id) +{ + char tapename[32]; + int i = vdev->unit_address; + int j; + + if (i >= viotape_numdev) + return -ENODEV; + + tape_device[i] = &vdev->dev; + + state[i].cur_part = 0; + for (j = 0; j < MAX_PARTITIONS; ++j) + state[i].part_stat_rwi[j] = VIOT_IDLE; + class_simple_device_add(tape_class, MKDEV(VIOTAPE_MAJOR, i), NULL, + "iseries!vt%d", i); + class_simple_device_add(tape_class, MKDEV(VIOTAPE_MAJOR, i | 0x80), + NULL, "iseries!nvt%d", i); + devfs_mk_cdev(MKDEV(VIOTAPE_MAJOR, i), S_IFCHR | S_IRUSR | S_IWUSR, + "iseries/vt%d", i); + devfs_mk_cdev(MKDEV(VIOTAPE_MAJOR, i | 0x80), + S_IFCHR | S_IRUSR | S_IWUSR, "iseries/nvt%d", i); + sprintf(tapename, "iseries/vt%d", i); + state[i].dev_handle = devfs_register_tape(tapename); + printk(VIOTAPE_KERN_INFO "tape %s is iSeries " + "resource %10.10s type %4.4s, model %3.3s\n", + tapename, viotape_unitinfo[i].rsrcname, + viotape_unitinfo[i].type, viotape_unitinfo[i].model); + return 0; +} + +static int viotape_remove(struct vio_dev *vdev) +{ + int i = vdev->unit_address; + + devfs_remove("iseries/nvt%d", i); + devfs_remove("iseries/vt%d", i); + devfs_unregister_tape(state[i].dev_handle); + class_simple_device_remove(MKDEV(VIOTAPE_MAJOR, i | 0x80)); + class_simple_device_remove(MKDEV(VIOTAPE_MAJOR, i)); + return 0; +} + +/** + * viotape_device_table: Used by vio.c to match devices that we + * support. + */ +static struct vio_device_id viotape_device_table[] __devinitdata = { + { "viotape", "" }, + { 0, } +}; + +MODULE_DEVICE_TABLE(vio, viotape_device_table); +static struct vio_driver viotape_driver = { + .name = "viotape", + .id_table = viotape_device_table, + .probe = viotape_probe, + .remove = viotape_remove +}; + int __init viotap_init(void) { int ret; - char tapename[32]; - int i; struct proc_dir_entry *e; op_struct_list = NULL; @@ -993,31 +1057,9 @@ goto unreg_class; } - for (i = 0; i < viotape_numdev; i++) { - int j; - - state[i].cur_part = 0; - for (j = 0; j < MAX_PARTITIONS; ++j) - state[i].part_stat_rwi[j] = VIOT_IDLE; - class_simple_device_add(tape_class, MKDEV(VIOTAPE_MAJOR, i), - NULL, "iseries!vt%d", i); - class_simple_device_add(tape_class, - MKDEV(VIOTAPE_MAJOR, i | 0x80), - NULL, "iseries!nvt%d", i); - devfs_mk_cdev(MKDEV(VIOTAPE_MAJOR, i), - S_IFCHR | S_IRUSR | S_IWUSR, - "iseries/vt%d", i); - devfs_mk_cdev(MKDEV(VIOTAPE_MAJOR, i | 0x80), - S_IFCHR | S_IRUSR | S_IWUSR, - "iseries/nvt%d", i); - sprintf(tapename, "iseries/vt%d", i); - state[i].dev_handle = devfs_register_tape(tapename); - printk(VIOTAPE_KERN_INFO "tape %s is iSeries " - "resource %10.10s type %4.4s, model %3.3s\n", - tapename, viotape_unitinfo[i].rsrcname, - viotape_unitinfo[i].type, - viotape_unitinfo[i].model); - } + ret = vio_register_driver(&viotape_driver); + if (ret) + goto unreg_class; e = create_proc_entry("iSeries/viotape", S_IFREG|S_IRUGO, NULL); if (e) { @@ -1064,17 +1106,10 @@ /* Cleanup */ static void __exit viotap_exit(void) { - int i, ret; + int ret; remove_proc_entry("iSeries/viotape", NULL); - - for (i = 0; i < viotape_numdev; ++i) { - devfs_remove("iseries/nvt%d", i); - devfs_remove("iseries/vt%d", i); - devfs_unregister_tape(state[i].dev_handle); - class_simple_device_remove(MKDEV(VIOTAPE_MAJOR, i | 0x80)); - class_simple_device_remove(MKDEV(VIOTAPE_MAJOR, i)); - } + vio_unregister_driver(&viotape_driver); class_simple_destroy(tape_class); ret = unregister_chrdev(VIOTAPE_MAJOR, "viotape"); if (ret < 0) diff -ruN ppc64-linux-2.5/drivers/net/iseries_veth.c ppc64-linux-2.5.daveb.sfr.10/drivers/net/iseries_veth.c --- ppc64-linux-2.5/drivers/net/iseries_veth.c 2004-06-07 12:05:52.000000000 +1000 +++ ppc64-linux-2.5.daveb.sfr.10/drivers/net/iseries_veth.c 2004-06-20 01:34:46.000000000 +1000 @@ -81,8 +81,6 @@ #include "iseries_veth.h" -extern struct vio_dev *iSeries_veth_dev; - MODULE_AUTHOR("Kyle Lucke "); MODULE_DESCRIPTION("iSeries Virtual ethernet driver"); MODULE_LICENSE("GPL"); @@ -119,6 +117,7 @@ int token; unsigned long in_use; struct sk_buff *skb; + struct device *dev; }; struct veth_lpar_connection { @@ -147,6 +146,7 @@ }; struct veth_port { + struct device *dev; struct net_device_stats stats; u64 mac_addr; HvLpIndexMap lpar_map; @@ -843,7 +843,7 @@ spin_unlock_irqrestore(&port->pending_gate, flags); } -struct net_device * __init veth_probe_one(int vlan) +static struct net_device * __init veth_probe_one(int vlan, struct device *vdev) { struct net_device *dev; struct veth_port *port; @@ -869,6 +869,7 @@ if (map & (0x8000 >> vlan)) port->lpar_map |= (1 << i); } + port->dev = vdev; dev->dev_addr[0] = 0x02; dev->dev_addr[1] = 0x01; @@ -893,6 +894,8 @@ dev->watchdog_timeo = 2 * (VETH_ACKTIMEOUT * HZ / 1000000); dev->tx_timeout = veth_tx_timeout; + SET_NETDEV_DEV(dev, vdev); + rc = register_netdev(dev); if (rc != 0) { veth_printk(KERN_ERR, @@ -945,7 +948,7 @@ } dma_length = skb->len; - dma_address = vio_map_single(iSeries_veth_dev, skb->data, + dma_address = dma_map_single(port->dev, skb->data, dma_length, DMA_TO_DEVICE); if (dma_mapping_error(dma_address)) @@ -954,6 +957,7 @@ /* Is it really necessary to check the length and address * fields of the first entry here? */ msg->skb = skb; + msg->dev = port->dev; msg->data.addr[0] = dma_address; msg->data.len[0] = dma_length; msg->data.eofmask = 1 << VETH_EOF_SHIFT; @@ -1059,7 +1063,7 @@ dma_address = msg->data.addr[0]; dma_length = msg->data.len[0]; - vio_unmap_single(iSeries_veth_dev, dma_address, dma_length, + dma_unmap_single(msg->dev, dma_address, dma_length, DMA_TO_DEVICE); if (msg->skb) { @@ -1327,6 +1331,58 @@ spin_unlock_irqrestore(&cnx->lock, flags); } +static int veth_remove(struct vio_dev *vdev) +{ + int i = vdev->unit_address; + struct net_device *dev; + + dev = veth_dev[i]; + if (dev != NULL) { + veth_dev[i] = NULL; + unregister_netdev(dev); + free_netdev(dev); + } + return 0; +} + +static int veth_probe(struct vio_dev *vdev, const struct vio_device_id *id) +{ + int i = vdev->unit_address; + struct net_device *dev; + + dev = veth_probe_one(i, &vdev->dev); + if (dev == NULL) { + veth_remove(vdev); + return 1; + } + veth_dev[i] = dev; + + /* Start the state machine on each connection, to commence + * link negotiation */ + for (i = 0; i < HVMAXARCHITECTEDLPS; i++) + if (veth_cnx[i]) + veth_kick_statemachine(veth_cnx[i]); + + return 0; +} + +/** + * veth_device_table: Used by vio.c to match devices that we + * support. + */ +static struct vio_device_id veth_device_table[] __devinitdata = { + { "vlan", "" }, + { NULL, NULL } +}; +MODULE_DEVICE_TABLE(vio, veth_device_table); + +static struct vio_driver veth_driver = { + .name = "iseries_veth", + .id_table = veth_device_table, + .probe = veth_probe, + .remove = veth_remove +}; + /* * Module initialization/cleanup */ @@ -1335,27 +1391,17 @@ { int i; + vio_unregister_driver(&veth_driver); + for (i = 0; i < HVMAXARCHITECTEDLPS; ++i) veth_destroy_connection(i); HvLpEvent_unregisterHandler(HvLpEvent_Type_VirtualLan); - - for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; ++i) { - struct net_device *dev = veth_dev[i]; - - if (! dev) - continue; - - veth_dev[i] = NULL; - unregister_netdev(dev); - free_netdev(dev); - } } module_exit(veth_module_cleanup); int __init veth_module_init(void) { - HvLpIndexMap vlan_map = HvLpConfig_getVirtualLanIndexMap(); int i; int rc; @@ -1369,31 +1415,9 @@ } } - for (i = 0; i < HVMAXARCHITECTEDVIRTUALLANS; ++i) { - struct net_device *dev; - - if (! (vlan_map & (0x8000 >> i))) - continue; - - dev = veth_probe_one(i); - - if (! dev) { - veth_module_cleanup(); - return rc; - } - - veth_dev[i] = dev; - } - HvLpEvent_registerHandler(HvLpEvent_Type_VirtualLan, &veth_handle_event); - /* Start the state machine on each connection, to commence - * link negotiation */ - for (i = 0; i < HVMAXARCHITECTEDLPS; i++) - if (veth_cnx[i]) - veth_kick_statemachine(veth_cnx[i]); - - return 0; + return vio_register_driver(&veth_driver); } module_init(veth_module_init); diff -ruN ppc64-linux-2.5/drivers/net/iseries_veth.h ppc64-linux-2.5.daveb.sfr.10/drivers/net/iseries_veth.h --- ppc64-linux-2.5/drivers/net/iseries_veth.h 2004-04-13 03:54:03.000000000 +1000 +++ ppc64-linux-2.5.daveb.sfr.10/drivers/net/iseries_veth.h 2004-06-10 17:23:33.000000000 +1000 @@ -43,6 +43,4 @@ }; -#define HVMAXARCHITECTEDVIRTUALLANS (16) - #endif /* _ISERIES_VETH_H */ diff -ruN ppc64-linux-2.5/drivers/scsi/ibmvscsi/iseries_vscsi.c ppc64-linux-2.5.daveb.sfr.10/drivers/scsi/ibmvscsi/iseries_vscsi.c --- ppc64-linux-2.5/drivers/scsi/ibmvscsi/iseries_vscsi.c 2004-06-10 14:48:03.000000000 +1000 +++ ppc64-linux-2.5.daveb.sfr.10/drivers/scsi/ibmvscsi/iseries_vscsi.c 2004-06-20 01:35:18.000000000 +1000 @@ -36,15 +36,8 @@ #include #include "ibmvscsi.h" -static void noop_release(struct device *dev) {}; - /* global variables */ static struct ibmvscsi_host_data *single_host_data; -static struct vio_dev iseries_vscsi_dev = { - .dev.bus = &vio_bus_type, - .dev.bus_id = "vscsi", - .dev.release = noop_release -}; /* ------------------------------------------------------------ * Routines for direct interpartition interaction @@ -151,23 +144,43 @@ 0); } -int __init ibmvscsi_module_init(void) +static int vscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) { - iseries_vscsi_dev.iommu_table = - to_vio_dev(iSeries_vio_dev)->iommu_table; - if (device_register(&iseries_vscsi_dev.dev)) { - printk(KERN_ERR "ibmvscsi: failed to register device\n"); - return 1; - } - single_host_data = ibmvscsi_probe(&iseries_vscsi_dev.dev); + single_host_data = ibmvscsi_probe(&vdev->dev); return (single_host_data == NULL); } -void __exit ibmvscsi_module_exit(void) +static int vscsi_remove(struct vio_dev *vdev) { if (single_host_data) ibmvscsi_remove(single_host_data); - device_unregister(&iseries_vscsi_dev.dev); + return 0; +} + +/** + * vscsi_device_table: Used by vio.c to match devices that we + * support. + */ +static struct vio_device_id vscsi_device_table[] __devinitdata = { + { "vioscsi", "" }, + { 0, } +}; +MODULE_DEVICE_TABLE(vio, vscsi_device_table); +static struct vio_driver vscsi_driver = { + .name = "vioscsi", + .id_table = vscsi_device_table, + .probe = vscsi_probe, + .remove = vscsi_remove +}; + +int __init ibmvscsi_module_init(void) +{ + return vio_register_driver(&vscsi_driver); +} + +void __exit ibmvscsi_module_exit(void) +{ + vio_unregister_driver(&vscsi_driver); } module_init(ibmvscsi_module_init); diff -ruN ppc64-linux-2.5/include/asm-ppc64/iSeries/HvTypes.h ppc64-linux-2.5.daveb.sfr.10/include/asm-ppc64/iSeries/HvTypes.h --- ppc64-linux-2.5/include/asm-ppc64/iSeries/HvTypes.h 2004-01-20 16:05:55.000000000 +1100 +++ ppc64-linux-2.5.daveb.sfr.10/include/asm-ppc64/iSeries/HvTypes.h 2004-06-19 17:59:21.000000000 +1000 @@ -65,6 +65,10 @@ #define HVMAXARCHITECTEDLPS 32 +#define HVMAXARCHITECTEDVIRTUALLANS 16 +#define HVMAXARCHITECTEDVIRTUALDISKS 32 +#define HVMAXARCHITECTEDVIRTUALCDROMS 8 +#define HVMAXARCHITECTEDVIRTUALTAPES 8 #define HVCHUNKSIZE 256 * 1024 #define HVPAGESIZE 4 * 1024 #define HVLPMINMEGSPRIMARY 256 diff -ruN ppc64-linux-2.5/include/asm-ppc64/vio.h ppc64-linux-2.5.daveb.sfr.10/include/asm-ppc64/vio.h --- ppc64-linux-2.5/include/asm-ppc64/vio.h 2004-06-10 14:48:03.000000000 +1000 +++ ppc64-linux-2.5.daveb.sfr.10/include/asm-ppc64/vio.h 2004-06-20 01:36:47.000000000 +1000 @@ -14,6 +14,7 @@ #ifndef _ASM_VIO_H #define _ASM_VIO_H +#include #include #include #include @@ -44,7 +45,12 @@ int vio_register_driver(struct vio_driver *drv); void vio_unregister_driver(struct vio_driver *drv); +#ifdef CONFIG_PPC_PSERIES struct vio_dev * __devinit vio_register_device(struct device_node *node_vdev); +#endif +#ifdef CONFIG_PPC_ISERIES +struct vio_dev * __devinit vio_register_device(char *type, uint32_t unit_num); +#endif void __devinit vio_unregister_device(struct vio_dev *dev); struct vio_dev *vio_find_node(struct device_node *vnode); @@ -108,6 +114,8 @@ */ struct vio_dev { struct iommu_table *iommu_table; /* vio_map_* uses this */ + char *name; + char *type; uint32_t unit_address; unsigned int irq;