diff options
| -rw-r--r-- | drivers/ide/icside.c | 64 |
1 files changed, 60 insertions, 4 deletions
diff --git a/drivers/ide/icside.c b/drivers/ide/icside.c index 0f67f1abbbd3..d7e6f09aa86b 100644 --- a/drivers/ide/icside.c +++ b/drivers/ide/icside.c | |||
| @@ -65,6 +65,8 @@ static struct cardinfo icside_cardinfo_v6_2 = { | |||
| 65 | }; | 65 | }; |
| 66 | 66 | ||
| 67 | struct icside_state { | 67 | struct icside_state { |
| 68 | unsigned int channel; | ||
| 69 | unsigned int enabled; | ||
| 68 | void __iomem *irq_port; | 70 | void __iomem *irq_port; |
| 69 | void __iomem *ioc_base; | 71 | void __iomem *ioc_base; |
| 70 | unsigned int sel; | 72 | unsigned int sel; |
| @@ -114,11 +116,18 @@ static void icside_irqenable_arcin_v6 (struct expansion_card *ec, int irqnr) | |||
| 114 | struct icside_state *state = ec->irq_data; | 116 | struct icside_state *state = ec->irq_data; |
| 115 | void __iomem *base = state->irq_port; | 117 | void __iomem *base = state->irq_port; |
| 116 | 118 | ||
| 117 | writeb(0, base + ICS_ARCIN_V6_INTROFFSET_1); | 119 | state->enabled = 1; |
| 118 | readb(base + ICS_ARCIN_V6_INTROFFSET_2); | ||
| 119 | 120 | ||
| 120 | writeb(0, base + ICS_ARCIN_V6_INTROFFSET_2); | 121 | switch (state->channel) { |
| 121 | readb(base + ICS_ARCIN_V6_INTROFFSET_1); | 122 | case 0: |
| 123 | writeb(0, base + ICS_ARCIN_V6_INTROFFSET_1); | ||
| 124 | readb(base + ICS_ARCIN_V6_INTROFFSET_2); | ||
| 125 | break; | ||
| 126 | case 1: | ||
| 127 | writeb(0, base + ICS_ARCIN_V6_INTROFFSET_2); | ||
| 128 | readb(base + ICS_ARCIN_V6_INTROFFSET_1); | ||
| 129 | break; | ||
| 130 | } | ||
| 122 | } | 131 | } |
| 123 | 132 | ||
| 124 | /* Prototype: icside_irqdisable_arcin_v6 (struct expansion_card *ec, int irqnr) | 133 | /* 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) | |||
| 128 | { | 137 | { |
| 129 | struct icside_state *state = ec->irq_data; | 138 | struct icside_state *state = ec->irq_data; |
| 130 | 139 | ||
| 140 | state->enabled = 0; | ||
| 141 | |||
| 131 | readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1); | 142 | readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1); |
| 132 | readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2); | 143 | readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2); |
| 133 | } | 144 | } |
| @@ -149,6 +160,44 @@ static const expansioncard_ops_t icside_ops_arcin_v6 = { | |||
| 149 | .irqpending = icside_irqpending_arcin_v6, | 160 | .irqpending = icside_irqpending_arcin_v6, |
| 150 | }; | 161 | }; |
| 151 | 162 | ||
| 163 | /* | ||
| 164 | * Handle routing of interrupts. This is called before | ||
| 165 | * we write the command to the drive. | ||
| 166 | */ | ||
| 167 | static void icside_maskproc(ide_drive_t *drive, int mask) | ||
| 168 | { | ||
| 169 | ide_hwif_t *hwif = drive->hwif; | ||
| 170 | struct expansion_card *ec = ECARD_DEV(hwif->dev); | ||
| 171 | struct icside_state *state = ecard_get_drvdata(ec); | ||
| 172 | unsigned long flags; | ||
| 173 | |||
| 174 | local_irq_save(flags); | ||
| 175 | |||
| 176 | state->channel = hwif->channel; | ||
| 177 | |||
| 178 | if (state->enabled && !mask) { | ||
| 179 | switch (hwif->channel) { | ||
| 180 | case 0: | ||
| 181 | writeb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_1); | ||
| 182 | readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2); | ||
| 183 | break; | ||
| 184 | case 1: | ||
| 185 | writeb(0, state->irq_port + ICS_ARCIN_V6_INTROFFSET_2); | ||
| 186 | readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1); | ||
| 187 | break; | ||
| 188 | } | ||
| 189 | } else { | ||
| 190 | readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2); | ||
| 191 | readb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1); | ||
| 192 | } | ||
| 193 | |||
| 194 | local_irq_restore(flags); | ||
| 195 | } | ||
| 196 | |||
| 197 | static const struct ide_port_ops icside_v6_no_dma_port_ops = { | ||
| 198 | .maskproc = icside_maskproc, | ||
| 199 | }; | ||
| 200 | |||
| 152 | #ifdef CONFIG_BLK_DEV_IDEDMA_ICS | 201 | #ifdef CONFIG_BLK_DEV_IDEDMA_ICS |
| 153 | /* | 202 | /* |
| 154 | * SG-DMA support. | 203 | * SG-DMA support. |
| @@ -228,6 +277,7 @@ static void icside_set_dma_mode(ide_drive_t *drive, const u8 xfer_mode) | |||
| 228 | 277 | ||
| 229 | static const struct ide_port_ops icside_v6_port_ops = { | 278 | static const struct ide_port_ops icside_v6_port_ops = { |
| 230 | .set_dma_mode = icside_set_dma_mode, | 279 | .set_dma_mode = icside_set_dma_mode, |
| 280 | .maskproc = icside_maskproc, | ||
| 231 | }; | 281 | }; |
| 232 | 282 | ||
| 233 | static void icside_dma_host_set(ide_drive_t *drive, int on) | 283 | static void icside_dma_host_set(ide_drive_t *drive, int on) |
| @@ -272,6 +322,11 @@ static int icside_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) | |||
| 272 | BUG_ON(dma_channel_active(ec->dma)); | 322 | BUG_ON(dma_channel_active(ec->dma)); |
| 273 | 323 | ||
| 274 | /* | 324 | /* |
| 325 | * Ensure that we have the right interrupt routed. | ||
| 326 | */ | ||
| 327 | icside_maskproc(drive, 0); | ||
| 328 | |||
| 329 | /* | ||
| 275 | * Route the DMA signals to the correct interface. | 330 | * Route the DMA signals to the correct interface. |
| 276 | */ | 331 | */ |
| 277 | writeb(state->sel | hwif->channel, state->ioc_base); | 332 | writeb(state->sel | hwif->channel, state->ioc_base); |
| @@ -399,6 +454,7 @@ err_free: | |||
| 399 | 454 | ||
| 400 | static const struct ide_port_info icside_v6_port_info __initdata = { | 455 | static const struct ide_port_info icside_v6_port_info __initdata = { |
| 401 | .init_dma = icside_dma_off_init, | 456 | .init_dma = icside_dma_off_init, |
| 457 | .port_ops = &icside_v6_no_dma_port_ops, | ||
| 402 | .dma_ops = &icside_v6_dma_ops, | 458 | .dma_ops = &icside_v6_dma_ops, |
| 403 | .host_flags = IDE_HFLAG_SERIALIZE | IDE_HFLAG_MMIO, | 459 | .host_flags = IDE_HFLAG_SERIALIZE | IDE_HFLAG_MMIO, |
| 404 | .mwdma_mask = ATA_MWDMA2, | 460 | .mwdma_mask = ATA_MWDMA2, |
