aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2006-06-17 02:49:56 -0400
committerJeff Garzik <jeff@garzik.org>2006-06-20 04:59:22 -0400
commitada364e884eb7e60ee96e84cbce07b3c90234c9d (patch)
tree4826b8e6638084e3d248457f5a7319820ccb9b29 /drivers/scsi
parent27e4b2745443cef67220da9a4f5f71b1c5f72442 (diff)
[PATCH] sata_nv: better irq handlers
nf2/3 and ck804 have irq status register. Implement better irq handler for those flavors of nv. This patch makes different flavors of nv controllers use different irq handlers by using separate port_info for each flavor. This change also makes following EH and hotplug updates easier to integrate. Signed-off-by: Tejun Heo <htejun@gmail.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/sata_nv.c211
1 files changed, 194 insertions, 17 deletions
diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c
index 1cb7b44cb660..94cb17903fae 100644
--- a/drivers/scsi/sata_nv.c
+++ b/drivers/scsi/sata_nv.c
@@ -78,8 +78,13 @@ enum {
78}; 78};
79 79
80static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); 80static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
81static irqreturn_t nv_interrupt (int irq, void *dev_instance, 81static void nv_ck804_host_stop(struct ata_host_set *host_set);
82 struct pt_regs *regs); 82static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance,
83 struct pt_regs *regs);
84static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance,
85 struct pt_regs *regs);
86static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance,
87 struct pt_regs *regs);
83static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg); 88static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg);
84static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); 89static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
85 90
@@ -154,7 +159,7 @@ static struct scsi_host_template nv_sht = {
154 .bios_param = ata_std_bios_param, 159 .bios_param = ata_std_bios_param,
155}; 160};
156 161
157static const struct ata_port_operations nv_ops = { 162static const struct ata_port_operations nv_generic_ops = {
158 .port_disable = ata_port_disable, 163 .port_disable = ata_port_disable,
159 .tf_load = ata_tf_load, 164 .tf_load = ata_tf_load,
160 .tf_read = ata_tf_read, 165 .tf_read = ata_tf_read,
@@ -170,7 +175,7 @@ static const struct ata_port_operations nv_ops = {
170 .qc_issue = ata_qc_issue_prot, 175 .qc_issue = ata_qc_issue_prot,
171 .eng_timeout = ata_eng_timeout, 176 .eng_timeout = ata_eng_timeout,
172 .data_xfer = ata_pio_data_xfer, 177 .data_xfer = ata_pio_data_xfer,
173 .irq_handler = nv_interrupt, 178 .irq_handler = nv_generic_interrupt,
174 .irq_clear = ata_bmdma_irq_clear, 179 .irq_clear = ata_bmdma_irq_clear,
175 .scr_read = nv_scr_read, 180 .scr_read = nv_scr_read,
176 .scr_write = nv_scr_write, 181 .scr_write = nv_scr_write,
@@ -179,6 +184,56 @@ static const struct ata_port_operations nv_ops = {
179 .host_stop = ata_pci_host_stop, 184 .host_stop = ata_pci_host_stop,
180}; 185};
181 186
187static const struct ata_port_operations nv_nf2_ops = {
188 .port_disable = ata_port_disable,
189 .tf_load = ata_tf_load,
190 .tf_read = ata_tf_read,
191 .exec_command = ata_exec_command,
192 .check_status = ata_check_status,
193 .dev_select = ata_std_dev_select,
194 .phy_reset = sata_phy_reset,
195 .bmdma_setup = ata_bmdma_setup,
196 .bmdma_start = ata_bmdma_start,
197 .bmdma_stop = ata_bmdma_stop,
198 .bmdma_status = ata_bmdma_status,
199 .qc_prep = ata_qc_prep,
200 .qc_issue = ata_qc_issue_prot,
201 .eng_timeout = ata_eng_timeout,
202 .data_xfer = ata_pio_data_xfer,
203 .irq_handler = nv_nf2_interrupt,
204 .irq_clear = ata_bmdma_irq_clear,
205 .scr_read = nv_scr_read,
206 .scr_write = nv_scr_write,
207 .port_start = ata_port_start,
208 .port_stop = ata_port_stop,
209 .host_stop = ata_pci_host_stop,
210};
211
212static const struct ata_port_operations nv_ck804_ops = {
213 .port_disable = ata_port_disable,
214 .tf_load = ata_tf_load,
215 .tf_read = ata_tf_read,
216 .exec_command = ata_exec_command,
217 .check_status = ata_check_status,
218 .dev_select = ata_std_dev_select,
219 .phy_reset = sata_phy_reset,
220 .bmdma_setup = ata_bmdma_setup,
221 .bmdma_start = ata_bmdma_start,
222 .bmdma_stop = ata_bmdma_stop,
223 .bmdma_status = ata_bmdma_status,
224 .qc_prep = ata_qc_prep,
225 .qc_issue = ata_qc_issue_prot,
226 .eng_timeout = ata_eng_timeout,
227 .data_xfer = ata_pio_data_xfer,
228 .irq_handler = nv_ck804_interrupt,
229 .irq_clear = ata_bmdma_irq_clear,
230 .scr_read = nv_scr_read,
231 .scr_write = nv_scr_write,
232 .port_start = ata_port_start,
233 .port_stop = ata_port_stop,
234 .host_stop = nv_ck804_host_stop,
235};
236
182/* FIXME: The hardware provides the necessary SATA PHY controls 237/* FIXME: The hardware provides the necessary SATA PHY controls
183 * to support ATA_FLAG_SATA_RESET. However, it is currently 238 * to support ATA_FLAG_SATA_RESET. However, it is currently
184 * necessary to disable that flag, to solve misdetection problems. 239 * necessary to disable that flag, to solve misdetection problems.
@@ -187,16 +242,43 @@ static const struct ata_port_operations nv_ops = {
187 * This problem really needs to be investigated further. But in the 242 * This problem really needs to be investigated further. But in the
188 * meantime, we avoid ATA_FLAG_SATA_RESET to get people working. 243 * meantime, we avoid ATA_FLAG_SATA_RESET to get people working.
189 */ 244 */
190static struct ata_port_info nv_port_info = { 245static struct ata_port_info nv_port_info[] = {
191 .sht = &nv_sht, 246 /* generic */
192 .host_flags = ATA_FLAG_SATA | 247 {
193 /* ATA_FLAG_SATA_RESET | */ 248 .sht = &nv_sht,
194 ATA_FLAG_SRST | 249 .host_flags = ATA_FLAG_SATA |
195 ATA_FLAG_NO_LEGACY, 250 /* ATA_FLAG_SATA_RESET | */
196 .pio_mask = NV_PIO_MASK, 251 ATA_FLAG_SRST |
197 .mwdma_mask = NV_MWDMA_MASK, 252 ATA_FLAG_NO_LEGACY,
198 .udma_mask = NV_UDMA_MASK, 253 .pio_mask = NV_PIO_MASK,
199 .port_ops = &nv_ops, 254 .mwdma_mask = NV_MWDMA_MASK,
255 .udma_mask = NV_UDMA_MASK,
256 .port_ops = &nv_generic_ops,
257 },
258 /* nforce2/3 */
259 {
260 .sht = &nv_sht,
261 .host_flags = ATA_FLAG_SATA |
262 /* ATA_FLAG_SATA_RESET | */
263 ATA_FLAG_SRST |
264 ATA_FLAG_NO_LEGACY,
265 .pio_mask = NV_PIO_MASK,
266 .mwdma_mask = NV_MWDMA_MASK,
267 .udma_mask = NV_UDMA_MASK,
268 .port_ops = &nv_nf2_ops,
269 },
270 /* ck804 */
271 {
272 .sht = &nv_sht,
273 .host_flags = ATA_FLAG_SATA |
274 /* ATA_FLAG_SATA_RESET | */
275 ATA_FLAG_SRST |
276 ATA_FLAG_NO_LEGACY,
277 .pio_mask = NV_PIO_MASK,
278 .mwdma_mask = NV_MWDMA_MASK,
279 .udma_mask = NV_UDMA_MASK,
280 .port_ops = &nv_ck804_ops,
281 },
200}; 282};
201 283
202MODULE_AUTHOR("NVIDIA"); 284MODULE_AUTHOR("NVIDIA");
@@ -205,8 +287,8 @@ MODULE_LICENSE("GPL");
205MODULE_DEVICE_TABLE(pci, nv_pci_tbl); 287MODULE_DEVICE_TABLE(pci, nv_pci_tbl);
206MODULE_VERSION(DRV_VERSION); 288MODULE_VERSION(DRV_VERSION);
207 289
208static irqreturn_t nv_interrupt (int irq, void *dev_instance, 290static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance,
209 struct pt_regs *regs) 291 struct pt_regs *regs)
210{ 292{
211 struct ata_host_set *host_set = dev_instance; 293 struct ata_host_set *host_set = dev_instance;
212 unsigned int i; 294 unsigned int i;
@@ -239,6 +321,79 @@ static irqreturn_t nv_interrupt (int irq, void *dev_instance,
239 return IRQ_RETVAL(handled); 321 return IRQ_RETVAL(handled);
240} 322}
241 323
324static int nv_host_intr(struct ata_port *ap, u8 irq_stat)
325{
326 struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag);
327 int handled;
328
329 /* bail out if not our interrupt */
330 if (!(irq_stat & NV_INT_DEV))
331 return 0;
332
333 /* DEV interrupt w/ no active qc? */
334 if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) {
335 ata_check_status(ap);
336 return 1;
337 }
338
339 /* handle interrupt */
340 handled = ata_host_intr(ap, qc);
341 if (unlikely(!handled)) {
342 /* spurious, clear it */
343 ata_check_status(ap);
344 }
345
346 return 1;
347}
348
349static irqreturn_t nv_do_interrupt(struct ata_host_set *host_set, u8 irq_stat)
350{
351 int i, handled = 0;
352
353 for (i = 0; i < host_set->n_ports; i++) {
354 struct ata_port *ap = host_set->ports[i];
355
356 if (ap && !(ap->flags & ATA_FLAG_DISABLED))
357 handled += nv_host_intr(ap, irq_stat);
358
359 irq_stat >>= NV_INT_PORT_SHIFT;
360 }
361
362 return IRQ_RETVAL(handled);
363}
364
365static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance,
366 struct pt_regs *regs)
367{
368 struct ata_host_set *host_set = dev_instance;
369 unsigned long flags;
370 u8 irq_stat;
371 irqreturn_t ret;
372
373 spin_lock_irqsave(&host_set->lock, flags);
374 irq_stat = inb(host_set->ports[0]->ioaddr.scr_addr + NV_INT_STATUS);
375 ret = nv_do_interrupt(host_set, irq_stat);
376 spin_unlock_irqrestore(&host_set->lock, flags);
377
378 return ret;
379}
380
381static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance,
382 struct pt_regs *regs)
383{
384 struct ata_host_set *host_set = dev_instance;
385 unsigned long flags;
386 u8 irq_stat;
387 irqreturn_t ret;
388
389 spin_lock_irqsave(&host_set->lock, flags);
390 irq_stat = readb(host_set->mmio_base + NV_INT_STATUS_CK804);
391 ret = nv_do_interrupt(host_set, irq_stat);
392 spin_unlock_irqrestore(&host_set->lock, flags);
393
394 return ret;
395}
396
242static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg) 397static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg)
243{ 398{
244 if (sc_reg > SCR_CONTROL) 399 if (sc_reg > SCR_CONTROL)
@@ -294,7 +449,7 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
294 449
295 rc = -ENOMEM; 450 rc = -ENOMEM;
296 451
297 ppi = &nv_port_info; 452 ppi = &nv_port_info[ent->driver_data];
298 probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); 453 probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY);
299 if (!probe_ent) 454 if (!probe_ent)
300 goto err_out_regions; 455 goto err_out_regions;
@@ -310,6 +465,15 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
310 probe_ent->port[0].scr_addr = base + NV_PORT0_SCR_REG_OFFSET; 465 probe_ent->port[0].scr_addr = base + NV_PORT0_SCR_REG_OFFSET;
311 probe_ent->port[1].scr_addr = base + NV_PORT1_SCR_REG_OFFSET; 466 probe_ent->port[1].scr_addr = base + NV_PORT1_SCR_REG_OFFSET;
312 467
468 /* enable SATA space for CK804 */
469 if (ent->driver_data == CK804) {
470 u8 regval;
471
472 pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, &regval);
473 regval |= NV_MCP_SATA_CFG_20_SATA_SPACE_EN;
474 pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
475 }
476
313 pci_set_master(pdev); 477 pci_set_master(pdev);
314 478
315 rc = ata_device_add(probe_ent); 479 rc = ata_device_add(probe_ent);
@@ -333,6 +497,19 @@ err_out:
333 return rc; 497 return rc;
334} 498}
335 499
500static void nv_ck804_host_stop(struct ata_host_set *host_set)
501{
502 struct pci_dev *pdev = to_pci_dev(host_set->dev);
503 u8 regval;
504
505 /* disable SATA space for CK804 */
506 pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, &regval);
507 regval &= ~NV_MCP_SATA_CFG_20_SATA_SPACE_EN;
508 pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
509
510 ata_pci_host_stop(host_set);
511}
512
336static int __init nv_init(void) 513static int __init nv_init(void)
337{ 514{
338 return pci_module_init(&nv_pci_driver); 515 return pci_module_init(&nv_pci_driver);