aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/ata/sata_vsc.c123
1 files changed, 74 insertions, 49 deletions
diff --git a/drivers/ata/sata_vsc.c b/drivers/ata/sata_vsc.c
index 2fd037bde090..f0d86cbe2e59 100644
--- a/drivers/ata/sata_vsc.c
+++ b/drivers/ata/sata_vsc.c
@@ -98,10 +98,6 @@ enum {
98 VSC_SATA_INT_PHY_CHANGE), 98 VSC_SATA_INT_PHY_CHANGE),
99}; 99};
100 100
101#define is_vsc_sata_int_err(port_idx, int_status) \
102 (int_status & (VSC_SATA_INT_ERROR << (8 * port_idx)))
103
104
105static u32 vsc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) 101static u32 vsc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
106{ 102{
107 if (sc_reg > SCR_CONTROL) 103 if (sc_reg > SCR_CONTROL)
@@ -119,6 +115,28 @@ static void vsc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
119} 115}
120 116
121 117
118static void vsc_freeze(struct ata_port *ap)
119{
120 void __iomem *mask_addr;
121
122 mask_addr = ap->host->iomap[VSC_MMIO_BAR] +
123 VSC_SATA_INT_MASK_OFFSET + ap->port_no;
124
125 writeb(0, mask_addr);
126}
127
128
129static void vsc_thaw(struct ata_port *ap)
130{
131 void __iomem *mask_addr;
132
133 mask_addr = ap->host->iomap[VSC_MMIO_BAR] +
134 VSC_SATA_INT_MASK_OFFSET + ap->port_no;
135
136 writeb(0xff, mask_addr);
137}
138
139
122static void vsc_intr_mask_update(struct ata_port *ap, u8 ctl) 140static void vsc_intr_mask_update(struct ata_port *ap, u8 ctl)
123{ 141{
124 void __iomem *mask_addr; 142 void __iomem *mask_addr;
@@ -203,6 +221,36 @@ static void vsc_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
203 } 221 }
204} 222}
205 223
224static inline void vsc_error_intr(u8 port_status, struct ata_port *ap)
225{
226 if (port_status & (VSC_SATA_INT_PHY_CHANGE | VSC_SATA_INT_ERROR_M))
227 ata_port_freeze(ap);
228 else
229 ata_port_abort(ap);
230}
231
232static void vsc_port_intr(u8 port_status, struct ata_port *ap)
233{
234 struct ata_queued_cmd *qc;
235 int handled = 0;
236
237 if (unlikely(port_status & VSC_SATA_INT_ERROR)) {
238 vsc_error_intr(port_status, ap);
239 return;
240 }
241
242 qc = ata_qc_from_tag(ap, ap->active_tag);
243 if (qc && likely(!(qc->tf.flags & ATA_TFLAG_POLLING)))
244 handled = ata_host_intr(ap, qc);
245
246 /* We received an interrupt during a polled command,
247 * or some other spurious condition. Interrupt reporting
248 * with this hardware is fairly reliable so it is safe to
249 * simply clear the interrupt
250 */
251 if (unlikely(!handled))
252 ata_chk_status(ap);
253}
206 254
207/* 255/*
208 * vsc_sata_interrupt 256 * vsc_sata_interrupt
@@ -214,59 +262,36 @@ static irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance)
214 struct ata_host *host = dev_instance; 262 struct ata_host *host = dev_instance;
215 unsigned int i; 263 unsigned int i;
216 unsigned int handled = 0; 264 unsigned int handled = 0;
217 u32 int_status; 265 u32 status;
218
219 spin_lock(&host->lock);
220 266
221 int_status = readl(host->iomap[VSC_MMIO_BAR] + 267 status = readl(host->iomap[VSC_MMIO_BAR] + VSC_SATA_INT_STAT_OFFSET);
222 VSC_SATA_INT_STAT_OFFSET);
223 268
224 for (i = 0; i < host->n_ports; i++) { 269 if (unlikely(status == 0xffffffff || status == 0)) {
225 if (int_status & ((u32) 0xFF << (8 * i))) { 270 if (status)
226 struct ata_port *ap; 271 dev_printk(KERN_ERR, host->dev,
272 ": IRQ status == 0xffffffff, "
273 "PCI fault or device removal?\n");
274 goto out;
275 }
227 276
228 ap = host->ports[i]; 277 spin_lock(&host->lock);
229 278
230 if (is_vsc_sata_int_err(i, int_status)) { 279 for (i = 0; i < host->n_ports; i++) {
231 u32 err_status; 280 u8 port_status = (status >> (8 * i)) & 0xff;
232 printk(KERN_DEBUG "%s: ignoring interrupt(s)\n", __FUNCTION__); 281 if (port_status) {
233 err_status = ap ? vsc_sata_scr_read(ap, SCR_ERROR) : 0; 282 struct ata_port *ap = host->ports[i];
234 vsc_sata_scr_write(ap, SCR_ERROR, err_status);
235 handled++;
236 }
237 283
238 if (ap && !(ap->flags & ATA_FLAG_DISABLED)) { 284 if (ap && !(ap->flags & ATA_FLAG_DISABLED)) {
239 struct ata_queued_cmd *qc; 285 vsc_port_intr(port_status, ap);
240 286 handled++;
241 qc = ata_qc_from_tag(ap, ap->active_tag); 287 } else
242 if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) 288 dev_printk(KERN_ERR, host->dev,
243 handled += ata_host_intr(ap, qc); 289 ": interrupt from disabled port %d\n", i);
244 else if (is_vsc_sata_int_err(i, int_status)) {
245 /*
246 * On some chips (i.e. Intel 31244), an error
247 * interrupt will sneak in at initialization
248 * time (phy state changes). Clearing the SCR
249 * error register is not required, but it prevents
250 * the phy state change interrupts from recurring
251 * later.
252 */
253 u32 err_status;
254 err_status = vsc_sata_scr_read(ap, SCR_ERROR);
255 printk(KERN_DEBUG "%s: clearing interrupt, "
256 "status %x; sata err status %x\n",
257 __FUNCTION__,
258 int_status, err_status);
259 vsc_sata_scr_write(ap, SCR_ERROR, err_status);
260 /* Clear interrupt status */
261 ata_chk_status(ap);
262 handled++;
263 }
264 }
265 } 290 }
266 } 291 }
267 292
268 spin_unlock(&host->lock); 293 spin_unlock(&host->lock);
269 294out:
270 return IRQ_RETVAL(handled); 295 return IRQ_RETVAL(handled);
271} 296}
272 297
@@ -304,8 +329,8 @@ static const struct ata_port_operations vsc_sata_ops = {
304 .qc_prep = ata_qc_prep, 329 .qc_prep = ata_qc_prep,
305 .qc_issue = ata_qc_issue_prot, 330 .qc_issue = ata_qc_issue_prot,
306 .data_xfer = ata_data_xfer, 331 .data_xfer = ata_data_xfer,
307 .freeze = ata_bmdma_freeze, 332 .freeze = vsc_freeze,
308 .thaw = ata_bmdma_thaw, 333 .thaw = vsc_thaw,
309 .error_handler = ata_bmdma_error_handler, 334 .error_handler = ata_bmdma_error_handler,
310 .post_internal_cmd = ata_bmdma_post_internal_cmd, 335 .post_internal_cmd = ata_bmdma_post_internal_cmd,
311 .irq_handler = vsc_sata_interrupt, 336 .irq_handler = vsc_sata_interrupt,