aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBartlomiej Zolnierkiewicz <bzolnier@gmail.com>2010-01-05 02:07:27 -0500
committerDavid S. Miller <davem@davemloft.net>2010-01-12 04:49:23 -0500
commitf75d4a238770d83d3a0475ce7f34e3fa37de161e (patch)
tree522f9aa82d79993fb670e638757bae1240c03ca8
parent4cd7d9247ffa2a27508c69563b66713519c196f5 (diff)
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 <rmk@arm.linux.org.uk> Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/ide/icside.c64
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
67struct icside_state { 67struct 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 */
167static 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
197static 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
229static const struct ide_port_ops icside_v6_port_ops = { 278static 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
233static void icside_dma_host_set(ide_drive_t *drive, int on) 283static 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
400static const struct ide_port_info icside_v6_port_info __initdata = { 455static 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,