diff options
Diffstat (limited to 'drivers/ide/icside.c')
-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 26b6c0a1f772..4a697a238e28 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. |
@@ -229,6 +278,7 @@ static void icside_set_dma_mode(ide_hwif_t *hwif, ide_drive_t *drive) | |||
229 | 278 | ||
230 | static const struct ide_port_ops icside_v6_port_ops = { | 279 | static const struct ide_port_ops icside_v6_port_ops = { |
231 | .set_dma_mode = icside_set_dma_mode, | 280 | .set_dma_mode = icside_set_dma_mode, |
281 | .maskproc = icside_maskproc, | ||
232 | }; | 282 | }; |
233 | 283 | ||
234 | static void icside_dma_host_set(ide_drive_t *drive, int on) | 284 | static void icside_dma_host_set(ide_drive_t *drive, int on) |
@@ -273,6 +323,11 @@ static int icside_dma_setup(ide_drive_t *drive, struct ide_cmd *cmd) | |||
273 | BUG_ON(dma_channel_active(ec->dma)); | 323 | BUG_ON(dma_channel_active(ec->dma)); |
274 | 324 | ||
275 | /* | 325 | /* |
326 | * Ensure that we have the right interrupt routed. | ||
327 | */ | ||
328 | icside_maskproc(drive, 0); | ||
329 | |||
330 | /* | ||
276 | * Route the DMA signals to the correct interface. | 331 | * Route the DMA signals to the correct interface. |
277 | */ | 332 | */ |
278 | writeb(state->sel | hwif->channel, state->ioc_base); | 333 | writeb(state->sel | hwif->channel, state->ioc_base); |
@@ -400,6 +455,7 @@ err_free: | |||
400 | 455 | ||
401 | static const struct ide_port_info icside_v6_port_info __initdata = { | 456 | static const struct ide_port_info icside_v6_port_info __initdata = { |
402 | .init_dma = icside_dma_off_init, | 457 | .init_dma = icside_dma_off_init, |
458 | .port_ops = &icside_v6_no_dma_port_ops, | ||
403 | .dma_ops = &icside_v6_dma_ops, | 459 | .dma_ops = &icside_v6_dma_ops, |
404 | .host_flags = IDE_HFLAG_SERIALIZE | IDE_HFLAG_MMIO, | 460 | .host_flags = IDE_HFLAG_SERIALIZE | IDE_HFLAG_MMIO, |
405 | .mwdma_mask = ATA_MWDMA2, | 461 | .mwdma_mask = ATA_MWDMA2, |