On 09/14/2015 05:08 AM, Jiang Liu wrote: > Previously the eata driver just grabs and accesses eata PCI devices > without implementing a PCI device driver, that causes troubles with > latest IRQ related > > Commit 991de2e59090 ("PCI, x86: Implement pcibios_alloc_irq() and > pcibios_free_irq()") changes the way to allocate PCI legacy IRQ > for PCI devices on x86 platforms. Instead of allocating PCI legacy > IRQs when pcibios_enable_device() gets called, now pcibios_alloc_irq() > will be called by pci_device_probe() to allocate PCI legacy IRQs > when binding PCI drivers to PCI devices. > > But the eata driver directly accesses PCI devices without implementing > corresponding PCI drivers, so pcibios_alloc_irq() won't be called for > those PCI devices and wrong IRQ number may be used to manage the PCI > device. > > This patch implements a PCI device driver to manage eata PCI devices, > so eata driver could properly cooperate with the PCI core. It also > provides headroom for PCI hotplug with eata driver. > > Signed-off-by: Jiang Liu <jiang.liu@xxxxxxxxxxxxxxx> > --- > drivers/scsi/eata.c | 170 ++++++++++++++++++++++----------------------------- > 1 file changed, 74 insertions(+), 96 deletions(-) > > diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c > index b45d3b532b70..b92e6856f909 100644 > --- a/drivers/scsi/eata.c > +++ b/drivers/scsi/eata.c > @@ -850,10 +850,6 @@ static unsigned long io_port[] = { > /* First ISA */ > 0x1f0, > > - /* Space for MAX_PCI ports possibly reported by PCI_BIOS */ > - SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, > - SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, > - > /* MAX_EISA ports */ > 0x1c88, 0x2c88, 0x3c88, 0x4c88, 0x5c88, 0x6c88, 0x7c88, 0x8c88, > 0x9c88, 0xac88, 0xbc88, 0xcc88, 0xdc88, 0xec88, 0xfc88, > @@ -1024,60 +1020,13 @@ static int read_pio(unsigned long iobase, ushort * start, ushort * end) > return 0; > } > > -static struct pci_dev *get_pci_dev(unsigned long port_base) > -{ > -#if defined(CONFIG_PCI) > - unsigned int addr; > - struct pci_dev *dev = NULL; > - > - while ((dev = pci_get_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) { > - addr = pci_resource_start(dev, 0); > - > -#if defined(DEBUG_PCI_DETECT) > - printk("%s: get_pci_dev, bus %d, devfn 0x%x, addr 0x%x.\n", > - driver_name, dev->bus->number, dev->devfn, addr); > -#endif > - > - /* we are in so much trouble for a pci hotplug system with this driver > - * anyway, so doing this at least lets people unload the driver and not > - * cause memory problems, but in general this is a bad thing to do (this > - * driver needs to be converted to the proper PCI api someday... */ > - pci_dev_put(dev); > - if (addr + PCI_BASE_ADDRESS_0 == port_base) > - return dev; > - } > -#endif /* end CONFIG_PCI */ > - return NULL; > -} > - > -static void enable_pci_ports(void) > -{ > -#if defined(CONFIG_PCI) > - struct pci_dev *dev = NULL; > - > - while ((dev = pci_get_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) { > -#if defined(DEBUG_PCI_DETECT) > - printk("%s: enable_pci_ports, bus %d, devfn 0x%x.\n", > - driver_name, dev->bus->number, dev->devfn); > -#endif > - > - if (pci_enable_device(dev)) > - printk > - ("%s: warning, pci_enable_device failed, bus %d devfn 0x%x.\n", > - driver_name, dev->bus->number, dev->devfn); > - } > - > -#endif /* end CONFIG_PCI */ > -} > - > static int port_detect(unsigned long port_base, unsigned int j, > - struct scsi_host_template *tpnt) > + struct scsi_host_template *tpnt, struct pci_dev *pdev) > { > unsigned char irq, dma_channel, subversion, i, is_pci = 0; > unsigned char protocol_rev; > struct eata_info info; > char *bus_type, dma_name[16]; > - struct pci_dev *pdev; > /* Allowed DMA channels for ISA (0 indicates reserved) */ > unsigned char dma_channel_table[4] = { 5, 6, 7, 0 }; > struct Scsi_Host *shost; > @@ -1199,15 +1148,8 @@ static int port_detect(unsigned long port_base, unsigned int j, > ("%s: warning, LEVEL triggering is suggested for IRQ %u.\n", > name, irq); > > - if (is_pci) { > - pdev = get_pci_dev(port_base); > - if (!pdev) > - printk > - ("%s: warning, failed to get pci_dev structure.\n", > - name); > - } else > - pdev = NULL; > - > + if (is_pci && !pdev) > + printk("%s: warning, failed to get pci_dev structure.\n", name); > if (pdev && (irq != pdev->irq)) { > printk("%s: IRQ %u mapped to IO-APIC IRQ %u.\n", name, irq, > pdev->irq); > @@ -1510,14 +1452,17 @@ static int option_setup(char *str) > } > > static unsigned int port_probe(unsigned long port_base, > - struct scsi_host_template *tpnt) > + struct scsi_host_template *tpnt, > + struct pci_dev *pdev) > { > int id; > > id = ida_simple_get(&eata_ida, 0, MAX_BOARDS, GFP_KERNEL); > if (id >= 0) { > set_bit(id, eata_board_bitmap); > - if (port_detect(port_base, id, tpnt)) > + if (pdev) > + dev_set_drvdata(&pdev->dev, (void *)(long)id); > + if (port_detect(port_base, id, tpnt, pdev)) > return id; > clear_bit(id, eata_board_bitmap); > ida_simple_remove(&eata_ida, id); > @@ -1526,42 +1471,81 @@ static unsigned int port_probe(unsigned long port_base, > return -1; > } > > -static void add_pci_ports(void) > -{ > -#if defined(CONFIG_PCI) > - unsigned int addr, k; > - struct pci_dev *dev = NULL; > - > - for (k = 0; k < MAX_PCI; k++) { > +#ifdef CONFIG_PCI > +static int eata2x_pci_device_count; > > - if (!(dev = pci_get_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) > - break; > +static int eata2x_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) > +{ > + int i, ret = -ENXIO; > + resource_size_t addr; > + unsigned long port_base; > + struct scsi_host_template *tpnt = (void *)id->driver_data; > > - if (pci_enable_device(dev)) { > + if (pci_enable_device(dev)) { > #if defined(DEBUG_PCI_DETECT) > - printk > - ("%s: detect, bus %d, devfn 0x%x, pci_enable_device failed.\n", > - driver_name, dev->bus->number, dev->devfn); > + pr_warn("%s: detect, bus %d, devfn 0x%x, pci_enable_device failed.\n", > + driver_name, dev->bus->number, dev->devfn); > #endif > + goto out_error; > + } > > - continue; > - } > - > - addr = pci_resource_start(dev, 0); > - > + addr = pci_resource_start(dev, 0); > + port_base = addr + PCI_BASE_ADDRESS_0; > #if defined(DEBUG_PCI_DETECT) > - printk("%s: detect, seq. %d, bus %d, devfn 0x%x, addr 0x%x.\n", > - driver_name, k, dev->bus->number, dev->devfn, addr); > + printk("%s: detect, bus %d, devfn 0x%x, addr 0x%x.\n", > + driver_name, dev->bus->number, dev->devfn, (unsigned int)addr); > #endif > > - /* Order addresses according to rev_scan value */ > - io_port[MAX_INT_PARAM + (rev_scan ? (MAX_PCI - k) : (1 + k))] = > - addr + PCI_BASE_ADDRESS_0; > + if (setup_done) { > + /* > + * Handle kernel or module parameter > + * . probe board if its port is specified by user > + * . otherwise ignore the board > + */ > + for (i = 1; i < MAX_INT_PARAM; i++) > + if (io_port[i] == port_base) { > + io_port[i] = SKIP; > + break; > + } > + if (i >= MAX_INT_PARAM) > + goto out_disable_device; > + } Hmm. I must admit I don't like the 'setup_done' thingie. As the driver is now converted to a 'real' PCI device we should be using driver-core mechanisms to avoid driver binding, not the prefabricated 'setup_done' variable. Can't we just do away with it completely? Cheers, Hannes -- Dr. Hannes Reinecke zSeries & Storage hare@xxxxxxx +49 911 74053 688 SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg) -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html