Commit 80cf1f8c authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'pci-v4.14-fixes-4' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci

Pull PCI fixes from Bjorn Helgaas:
 "Fix legacy IDE probe issues exposed by recent PCI core IRQ mapping
  changes (Bartlomiej Zolnierkiewicz, Lorenzo Pieralisi)"

* tag 'pci-v4.14-fixes-4' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci:
  ide: fix IRQ assignment for PCI bus order probing
  ide: pci: free PCI BARs on initialization failure
  ide: free hwif->portdev on hwif_init() failure
parents 27549068 b1f9e5e3
...@@ -1451,6 +1451,7 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d, ...@@ -1451,6 +1451,7 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d,
if (hwif_init(hwif) == 0) { if (hwif_init(hwif) == 0) {
printk(KERN_INFO "%s: failed to initialize IDE " printk(KERN_INFO "%s: failed to initialize IDE "
"interface\n", hwif->name); "interface\n", hwif->name);
device_unregister(hwif->portdev);
device_unregister(&hwif->gendev); device_unregister(&hwif->gendev);
ide_disable_port(hwif); ide_disable_port(hwif);
continue; continue;
......
...@@ -56,6 +56,7 @@ static int __init ide_scan_pcidev(struct pci_dev *dev) ...@@ -56,6 +56,7 @@ static int __init ide_scan_pcidev(struct pci_dev *dev)
{ {
struct list_head *l; struct list_head *l;
struct pci_driver *d; struct pci_driver *d;
int ret;
list_for_each(l, &ide_pci_drivers) { list_for_each(l, &ide_pci_drivers) {
d = list_entry(l, struct pci_driver, node); d = list_entry(l, struct pci_driver, node);
...@@ -63,13 +64,17 @@ static int __init ide_scan_pcidev(struct pci_dev *dev) ...@@ -63,13 +64,17 @@ static int __init ide_scan_pcidev(struct pci_dev *dev)
const struct pci_device_id *id = const struct pci_device_id *id =
pci_match_id(d->id_table, dev); pci_match_id(d->id_table, dev);
if (id != NULL && d->probe(dev, id) >= 0) { if (id != NULL) {
pci_assign_irq(dev);
ret = d->probe(dev, id);
if (ret >= 0) {
dev->driver = d; dev->driver = d;
pci_dev_get(dev); pci_dev_get(dev);
return 1; return 1;
} }
} }
} }
}
return 0; return 0;
} }
......
...@@ -179,6 +179,7 @@ EXPORT_SYMBOL_GPL(ide_setup_pci_noise); ...@@ -179,6 +179,7 @@ EXPORT_SYMBOL_GPL(ide_setup_pci_noise);
/** /**
* ide_pci_enable - do PCI enables * ide_pci_enable - do PCI enables
* @dev: PCI device * @dev: PCI device
* @bars: PCI BARs mask
* @d: IDE port info * @d: IDE port info
* *
* Enable the IDE PCI device. We attempt to enable the device in full * Enable the IDE PCI device. We attempt to enable the device in full
...@@ -189,9 +190,10 @@ EXPORT_SYMBOL_GPL(ide_setup_pci_noise); ...@@ -189,9 +190,10 @@ EXPORT_SYMBOL_GPL(ide_setup_pci_noise);
* Returns zero on success or an error code * Returns zero on success or an error code
*/ */
static int ide_pci_enable(struct pci_dev *dev, const struct ide_port_info *d) static int ide_pci_enable(struct pci_dev *dev, int bars,
const struct ide_port_info *d)
{ {
int ret, bars; int ret;
if (pci_enable_device(dev)) { if (pci_enable_device(dev)) {
ret = pci_enable_device_io(dev); ret = pci_enable_device_io(dev);
...@@ -216,18 +218,6 @@ static int ide_pci_enable(struct pci_dev *dev, const struct ide_port_info *d) ...@@ -216,18 +218,6 @@ static int ide_pci_enable(struct pci_dev *dev, const struct ide_port_info *d)
goto out; goto out;
} }
if (d->host_flags & IDE_HFLAG_SINGLE)
bars = (1 << 2) - 1;
else
bars = (1 << 4) - 1;
if ((d->host_flags & IDE_HFLAG_NO_DMA) == 0) {
if (d->host_flags & IDE_HFLAG_CS5520)
bars |= (1 << 2);
else
bars |= (1 << 4);
}
ret = pci_request_selected_regions(dev, bars, d->name); ret = pci_request_selected_regions(dev, bars, d->name);
if (ret < 0) if (ret < 0)
printk(KERN_ERR "%s %s: can't reserve resources\n", printk(KERN_ERR "%s %s: can't reserve resources\n",
...@@ -403,6 +393,7 @@ int ide_hwif_setup_dma(ide_hwif_t *hwif, const struct ide_port_info *d) ...@@ -403,6 +393,7 @@ int ide_hwif_setup_dma(ide_hwif_t *hwif, const struct ide_port_info *d)
/** /**
* ide_setup_pci_controller - set up IDE PCI * ide_setup_pci_controller - set up IDE PCI
* @dev: PCI device * @dev: PCI device
* @bars: PCI BARs mask
* @d: IDE port info * @d: IDE port info
* @noisy: verbose flag * @noisy: verbose flag
* *
...@@ -411,7 +402,7 @@ int ide_hwif_setup_dma(ide_hwif_t *hwif, const struct ide_port_info *d) ...@@ -411,7 +402,7 @@ int ide_hwif_setup_dma(ide_hwif_t *hwif, const struct ide_port_info *d)
* and enables it if need be * and enables it if need be
*/ */
static int ide_setup_pci_controller(struct pci_dev *dev, static int ide_setup_pci_controller(struct pci_dev *dev, int bars,
const struct ide_port_info *d, int noisy) const struct ide_port_info *d, int noisy)
{ {
int ret; int ret;
...@@ -420,7 +411,7 @@ static int ide_setup_pci_controller(struct pci_dev *dev, ...@@ -420,7 +411,7 @@ static int ide_setup_pci_controller(struct pci_dev *dev,
if (noisy) if (noisy)
ide_setup_pci_noise(dev, d); ide_setup_pci_noise(dev, d);
ret = ide_pci_enable(dev, d); ret = ide_pci_enable(dev, bars, d);
if (ret < 0) if (ret < 0)
goto out; goto out;
...@@ -428,16 +419,20 @@ static int ide_setup_pci_controller(struct pci_dev *dev, ...@@ -428,16 +419,20 @@ static int ide_setup_pci_controller(struct pci_dev *dev,
if (ret < 0) { if (ret < 0) {
printk(KERN_ERR "%s %s: error accessing PCI regs\n", printk(KERN_ERR "%s %s: error accessing PCI regs\n",
d->name, pci_name(dev)); d->name, pci_name(dev));
goto out; goto out_free_bars;
} }
if (!(pcicmd & PCI_COMMAND_IO)) { /* is device disabled? */ if (!(pcicmd & PCI_COMMAND_IO)) { /* is device disabled? */
ret = ide_pci_configure(dev, d); ret = ide_pci_configure(dev, d);
if (ret < 0) if (ret < 0)
goto out; goto out_free_bars;
printk(KERN_INFO "%s %s: device enabled (Linux)\n", printk(KERN_INFO "%s %s: device enabled (Linux)\n",
d->name, pci_name(dev)); d->name, pci_name(dev));
} }
goto out;
out_free_bars:
pci_release_selected_regions(dev, bars);
out: out:
return ret; return ret;
} }
...@@ -540,13 +535,28 @@ int ide_pci_init_two(struct pci_dev *dev1, struct pci_dev *dev2, ...@@ -540,13 +535,28 @@ int ide_pci_init_two(struct pci_dev *dev1, struct pci_dev *dev2,
{ {
struct pci_dev *pdev[] = { dev1, dev2 }; struct pci_dev *pdev[] = { dev1, dev2 };
struct ide_host *host; struct ide_host *host;
int ret, i, n_ports = dev2 ? 4 : 2; int ret, i, n_ports = dev2 ? 4 : 2, bars;
struct ide_hw hw[4], *hws[] = { NULL, NULL, NULL, NULL }; struct ide_hw hw[4], *hws[] = { NULL, NULL, NULL, NULL };
if (d->host_flags & IDE_HFLAG_SINGLE)
bars = (1 << 2) - 1;
else
bars = (1 << 4) - 1;
if ((d->host_flags & IDE_HFLAG_NO_DMA) == 0) {
if (d->host_flags & IDE_HFLAG_CS5520)
bars |= (1 << 2);
else
bars |= (1 << 4);
}
for (i = 0; i < n_ports / 2; i++) { for (i = 0; i < n_ports / 2; i++) {
ret = ide_setup_pci_controller(pdev[i], d, !i); ret = ide_setup_pci_controller(pdev[i], bars, d, !i);
if (ret < 0) if (ret < 0) {
if (i == 1)
pci_release_selected_regions(pdev[0], bars);
goto out; goto out;
}
ide_pci_setup_ports(pdev[i], d, &hw[i*2], &hws[i*2]); ide_pci_setup_ports(pdev[i], d, &hw[i*2], &hws[i*2]);
} }
...@@ -554,7 +564,7 @@ int ide_pci_init_two(struct pci_dev *dev1, struct pci_dev *dev2, ...@@ -554,7 +564,7 @@ int ide_pci_init_two(struct pci_dev *dev1, struct pci_dev *dev2,
host = ide_host_alloc(d, hws, n_ports); host = ide_host_alloc(d, hws, n_ports);
if (host == NULL) { if (host == NULL) {
ret = -ENOMEM; ret = -ENOMEM;
goto out; goto out_free_bars;
} }
host->dev[0] = &dev1->dev; host->dev[0] = &dev1->dev;
...@@ -576,7 +586,7 @@ int ide_pci_init_two(struct pci_dev *dev1, struct pci_dev *dev2, ...@@ -576,7 +586,7 @@ int ide_pci_init_two(struct pci_dev *dev1, struct pci_dev *dev2,
* do_ide_setup_pci_device() on the first device! * do_ide_setup_pci_device() on the first device!
*/ */
if (ret < 0) if (ret < 0)
goto out; goto out_free_bars;
/* fixup IRQ */ /* fixup IRQ */
if (ide_pci_is_in_compatibility_mode(pdev[i])) { if (ide_pci_is_in_compatibility_mode(pdev[i])) {
...@@ -589,6 +599,13 @@ int ide_pci_init_two(struct pci_dev *dev1, struct pci_dev *dev2, ...@@ -589,6 +599,13 @@ int ide_pci_init_two(struct pci_dev *dev1, struct pci_dev *dev2,
ret = ide_host_register(host, d, hws); ret = ide_host_register(host, d, hws);
if (ret) if (ret)
ide_host_free(host); ide_host_free(host);
else
goto out;
out_free_bars:
i = n_ports / 2;
while (i--)
pci_release_selected_regions(pdev[i], bars);
out: out:
return ret; return ret;
} }
......
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