From 4cd7d9247ffa2a27508c69563b66713519c196f5 Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Fri, 8 Jan 2010 00:11:01 -0800 Subject: scc_pata: fix module unloading scc_pata host driver predated module unloading support for IDE host drivers so even though it supports PCI hot-unplug and implements PCI device ->remove method it doesn't allow module removal. Fix it. Add missing __init/__exit tags to module_init/module_exit functions while at it (from Peter Huewe). Noticed-by: Jiri Kosina Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: David S. Miller --- drivers/ide/scc_pata.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'drivers/ide') diff --git a/drivers/ide/scc_pata.c b/drivers/ide/scc_pata.c index 1104bb301eb..8066168992d 100644 --- a/drivers/ide/scc_pata.c +++ b/drivers/ide/scc_pata.c @@ -872,20 +872,18 @@ static struct pci_driver scc_pci_driver = { .remove = __devexit_p(scc_remove), }; -static int scc_ide_init(void) +static int __init scc_ide_init(void) { return ide_pci_register_driver(&scc_pci_driver); } -module_init(scc_ide_init); -/* -- No exit code? -static void scc_ide_exit(void) +static void __exit scc_ide_exit(void) { - ide_pci_unregister_driver(&scc_pci_driver); + pci_unregister_driver(&scc_pci_driver); } -module_exit(scc_ide_exit); - */ +module_init(scc_ide_init); +module_exit(scc_ide_exit); MODULE_DESCRIPTION("PCI driver module for Toshiba SCC IDE"); MODULE_LICENSE("GPL"); -- cgit v1.2.3-70-g09d2 From f75d4a238770d83d3a0475ce7f34e3fa37de161e Mon Sep 17 00:00:00 2001 From: Bartlomiej Zolnierkiewicz Date: Tue, 5 Jan 2010 07:07:27 +0000 Subject: icside: bring back ->maskproc method Bring back ->maskproc method since it is still needed for proper operation, as noticed by Russell King: > This change is bogus. > > writeb(0, base + ICS_ARCIN_V6_INTROFFSET_1); > readb(base + ICS_ARCIN_V6_INTROFFSET_2); > > writeb(0, base + ICS_ARCIN_V6_INTROFFSET_2); > readb(base + ICS_ARCIN_V6_INTROFFSET_1); > > This sequence of code does: > > 1. enable interrupt 1 > 2. disable interrupt 2 > 3. enable interrupt 2 > 4. disable interrupt 1 > > which results in the interrupt for the second channel being enabled - > leaving channel 1 blocked. > > Firstly, icside shares its two IDE channels with one DMA engine - so it's > a simplex interface. IDE supports those (or did when the code was written) > serializing requests between the two interfaces. libata does not. > > Secondly, the interrupt lines on icside float when there's no drive connected > or when the drive has its NIEN bit set, which means that you get spurious > screaming interrupts which can kill off all expansion card interrupts on > the machine unless you disable the channel interrupt on the card. > > Since libata can not serialize the operation of the two channels like IDE > can, the libata version of the icside driver does not contain the interrupt > stearing logic. Instead, it looks at the status after reset, and if > nothing was found on that channel, it masks the interrupt from that > channel. This patch reverts changes done in commit dff8817 (I became confused due to non-standard & undocumented ->maskproc method, anyway sorry about that). Noticed-by: Russell King Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: David S. Miller --- drivers/ide/icside.c | 64 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 4 deletions(-) (limited to 'drivers/ide') diff --git a/drivers/ide/icside.c b/drivers/ide/icside.c index 0f67f1abbbd..d7e6f09aa86 100644 --- a/drivers/ide/icside.c +++ b/drivers/ide/icside.c @@ -65,6 +65,8 @@ static struct cardinfo icside_cardinfo_v6_2 = { }; struct icside_state { + unsigned int channel; + unsigned int enabled; void __iomem *irq_port; void __iomem *ioc_base; unsigned int sel; @@ -114,11 +116,18 @@ static void icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr) struct icside_state *state = ec->irq_data; void __iomem *base = state->irq_port; - writeb(0, base + ICS_ARCIN_V6_INTROFFSET_1); - readb(base + ICS_ARCIN_V6_INTROFFSET_2); + state->enabled = 1; - writeb(0, base + ICS_ARCIN_V6_INTROFFSET_2); - readb(base + ICS_ARCIN_V6_INTROFFSET_1); + switch (state->channel) { + case 0: + writeb(0, base + ICS_ARCIN_V6_INTROFFSET_1); + readb(base + ICS_ARCIN_V6_INTROFFSET_2); + break; + case 1: + writeb(0, base + ICS_ARCIN_V6_INTROFFSET_2); + readb(base + ICS_ARCIN_V6_INTROFFSET_1); + break; + } } /* Prototype: icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr) @@ -128,6 +137,8 @@ static void icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr) { struct icside_state *state = ec->irq_data; + state->enabled = 0; + readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1); readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2); } @@ -149,6 +160,44 @@ static const expansioncard_ops_t icside_ops_arcin_v6 = { .irqpending = icside_irqpending_arcin_v6, }; +/* + * Handle routing of interrupts. This is called before + * we write the command to the drive. + */ +static void icside_maskproc(ide_drive_t *drive, int mask) +{ + ide_hwif_t *hwif = drive->hwif; + struct expansion_card *ec = ECARD_DEV(hwif->dev); + struct icside_state *state = ecard_get_drvdata(ec); + unsigned long flags; + + local_irq_save(flags); + + state->channel = hwif->channel; + + if (state->enabled && !mask) { + switch (hwif->channel) { + case 0: + writeb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_1); + readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2); + break; + case 1: + writeb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_2); + readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1); + break; + } + } else { + readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2); + readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1); + } + + local_irq_restore(flags); +} + +static const struct ide_port_ops icside_v6_no_dma_port_ops = { + .maskproc = icside_maskproc, +}; + #ifdef CONFIG_BLK_DEV_IDEDMA_ICS /* * SG-DMA support. @@ -228,6 +277,7 @@ static void icside_set_dma_mode(ide_drive_t *drive, const u8 xfer_mode) static const struct ide_port_ops icside_v6_port_ops = { .set_dma_mode = icside_set_dma_mode, + .maskproc = icside_maskproc, }; static void icside_dma_host_set(ide_drive_t *drive, int on) @@ -271,6 +321,11 @@ static int icside_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) */ BUG_ON(dma_channel_active(ec->dma)); + /* + * Ensure that we have the right interrupt routed. + */ + icside_maskproc(drive, 0); + /* * Route the DMA signals to the correct interface. */ @@ -399,6 +454,7 @@ err_free: static const struct ide_port_info icside_v6_port_info __initdata = { .init_dma = icside_dma_off_init, + .port_ops = &icside_v6_no_dma_port_ops, .dma_ops = &icside_v6_dma_ops, .host_flags = IDE_HFLAG_SERIALIZE | IDE_HFLAG_MMIO, .mwdma_mask = ATA_MWDMA2, -- cgit v1.2.3-70-g09d2 From c3be57b6f35ef96a980ce84e59d6a5a8ca6184ad Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 3 Jan 2010 12:35:42 +0000 Subject: ide: Fix Promise UDMA33 IDE driver (pdc202xx_old) On Sun, Jan 03, 2010 at 12:23:14AM +0000, Russell King wrote: > - with IDE > - locks the interrupt line, and makes the machine extremely painful - > about an hour to get to the point of being able to unload the > pdc202xx_old module. Having manually bisected kernel versions, I've narrowed it down to some change between 2.6.30 and 2.6.31. There's not much which has changed between the two kernels, but one change stands out like a sore thumb: +static int pdc202xx_test_irq(ide_hwif_t *hwif) +{ + struct pci_dev *dev = to_pci_dev(hwif->dev); + unsigned long high_16 = pci_resource_start(dev, 4); + u8 sc1d = inb(high_16 + 0x1d); + + if (hwif->channel) { + /* + * bit 7: error, bit 6: interrupting, + * bit 5: FIFO full, bit 4: FIFO empty + */ + return ((sc1d & 0x50) == 0x40) ? 1 : 0; + } else { + /* + * bit 3: error, bit 2: interrupting, + * bit 1: FIFO full, bit 0: FIFO empty + */ + return ((sc1d & 0x05) == 0x04) ? 1 : 0; + } +} Reading the (documented as a 32-bit) system control register when the interface is idle gives: 0x01da110c So, the byte at 0x1d is 0x11, which is documented as meaning that the primary and secondary FIFOs are empty. The code above, which is trying to see whether an IRQ is pending, checks for the IRQ bit to be one, and the FIFO bit to be zero - or in English, to be non-empty. Since during a BM-DMA read, the FIFOs will naturally be drained to the PCI bus, the chance of us getting to the interface before this happens are extremely small - and if we don't, it means we decide not to service the interrupt. Hence, the screaming interrupt problem with drivers/ide. Fix this by only indicating an interrupt is ready if both the interrupt and FIFO empty bits are at '1'. This bug only affects PDC20246/PDC20247 (Promise Ultra33) based cards, and has been tested on 2.6.31 and 2.6.33-rc2. Signed-off-by: Russell King Tested-by: Russell King Signed-off-by: David S. Miller --- drivers/ide/pdc202xx_old.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/ide') diff --git a/drivers/ide/pdc202xx_old.c b/drivers/ide/pdc202xx_old.c index 35161dd840a..e3bca38a03f 100644 --- a/drivers/ide/pdc202xx_old.c +++ b/drivers/ide/pdc202xx_old.c @@ -100,13 +100,13 @@ static int pdc202xx_test_irq(ide_hwif_t *hwif) * bit 7: error, bit 6: interrupting, * bit 5: FIFO full, bit 4: FIFO empty */ - return ((sc1d & 0x50) == 0x40) ? 1 : 0; + return ((sc1d & 0x50) == 0x50) ? 1 : 0; } else { /* * bit 3: error, bit 2: interrupting, * bit 1: FIFO full, bit 0: FIFO empty */ - return ((sc1d & 0x05) == 0x04) ? 1 : 0; + return ((sc1d & 0x05) == 0x05) ? 1 : 0; } } -- cgit v1.2.3-70-g09d2 From d4ae5415c6f2dd8f14e027c24f09d708f11a8d60 Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 15 Jan 2010 01:33:08 -0800 Subject: ide/ide-cs: fix order of releasing resources ide_detach() called first ide_release() and then release_region(). This produced the following warnings: Trying to free nonexistent resource <000000000000c10e-000000000000c10e> Trying to free nonexistent resource <000000000000c100-000000000000c107> This is true, because the callchain inside ide_release() is: ide_release -> pcmcia_disable_device -> pcmcia_release_io So, the whole io-block is already gone for release_region(). To fix this, just swap the order of releasing (and remove the now obsolete shadowing). bzolnier: - release resources in ide_release() to fix ordering of events - remove stale FIXME note while at it Signed-off-by: Wolfram Sang Signed-off-by: Bartlomiej Zolnierkiewicz Signed-off-by: David S. Miller --- drivers/ide/ide-cs.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'drivers/ide') diff --git a/drivers/ide/ide-cs.c b/drivers/ide/ide-cs.c index dd6396384c2..ab87e4f7cec 100644 --- a/drivers/ide/ide-cs.c +++ b/drivers/ide/ide-cs.c @@ -121,19 +121,11 @@ static int ide_probe(struct pcmcia_device *link) static void ide_detach(struct pcmcia_device *link) { ide_info_t *info = link->priv; - ide_hwif_t *hwif = info->host->ports[0]; - unsigned long data_addr, ctl_addr; dev_dbg(&link->dev, "ide_detach(0x%p)\n", link); - data_addr = hwif->io_ports.data_addr; - ctl_addr = hwif->io_ports.ctl_addr; - ide_release(link); - release_region(ctl_addr, 1); - release_region(data_addr, 8); - kfree(info); } /* ide_detach */ @@ -354,12 +346,19 @@ static void ide_release(struct pcmcia_device *link) dev_dbg(&link->dev, "ide_release(0x%p)\n", link); - if (info->ndev) - /* FIXME: if this fails we need to queue the cleanup somehow - -- need to investigate the required PCMCIA magic */ + if (info->ndev) { + ide_hwif_t *hwif = host->ports[0]; + unsigned long data_addr, ctl_addr; + + data_addr = hwif->io_ports.data_addr; + ctl_addr = hwif->io_ports.ctl_addr; + ide_host_remove(host); + info->ndev = 0; - info->ndev = 0; + release_region(ctl_addr, 1); + release_region(data_addr, 8); + } pcmcia_disable_device(link); } /* ide_release */ -- cgit v1.2.3-70-g09d2 From 8495fb1b8d016657133c01a2f258c5f192d2a1b7 Mon Sep 17 00:00:00 2001 From: Chris Frey Date: Thu, 28 Jan 2010 06:04:50 -0800 Subject: ide: fixed section mismatch warning in cmd640.c Signed-off-by: Chris Frey Signed-off-by: David S. Miller --- drivers/ide/cmd640.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/ide') diff --git a/drivers/ide/cmd640.c b/drivers/ide/cmd640.c index 1a32d62ed86..cb11938ba68 100644 --- a/drivers/ide/cmd640.c +++ b/drivers/ide/cmd640.c @@ -605,7 +605,7 @@ static void cmd640_set_pio_mode(ide_drive_t *drive, const u8 pio) } #endif /* CONFIG_BLK_DEV_CMD640_ENHANCED */ -static void cmd640_init_dev(ide_drive_t *drive) +static void __init cmd640_init_dev(ide_drive_t *drive) { unsigned int i = drive->hwif->channel * 2 + (drive->dn & 1); -- cgit v1.2.3-70-g09d2