diff options
-rw-r--r-- | drivers/scsi/sata_nv.c | 211 |
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 | ||
80 | static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); | 80 | static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); |
81 | static irqreturn_t nv_interrupt (int irq, void *dev_instance, | 81 | static void nv_ck804_host_stop(struct ata_host_set *host_set); |
82 | struct pt_regs *regs); | 82 | static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance, |
83 | struct pt_regs *regs); | ||
84 | static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance, | ||
85 | struct pt_regs *regs); | ||
86 | static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance, | ||
87 | struct pt_regs *regs); | ||
83 | static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg); | 88 | static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg); |
84 | static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); | 89 | static 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 | ||
157 | static const struct ata_port_operations nv_ops = { | 162 | static 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 | ||
187 | static 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 | |||
212 | static 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 | */ |
190 | static struct ata_port_info nv_port_info = { | 245 | static 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 | ||
202 | MODULE_AUTHOR("NVIDIA"); | 284 | MODULE_AUTHOR("NVIDIA"); |
@@ -205,8 +287,8 @@ MODULE_LICENSE("GPL"); | |||
205 | MODULE_DEVICE_TABLE(pci, nv_pci_tbl); | 287 | MODULE_DEVICE_TABLE(pci, nv_pci_tbl); |
206 | MODULE_VERSION(DRV_VERSION); | 288 | MODULE_VERSION(DRV_VERSION); |
207 | 289 | ||
208 | static irqreturn_t nv_interrupt (int irq, void *dev_instance, | 290 | static 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 | ||
324 | static 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 | |||
349 | static 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 | |||
365 | static 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 | |||
381 | static 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 | |||
242 | static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg) | 397 | static 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, ®val); | ||
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 | ||
500 | static 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, ®val); | ||
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 | |||
336 | static int __init nv_init(void) | 513 | static int __init nv_init(void) |
337 | { | 514 | { |
338 | return pci_module_init(&nv_pci_driver); | 515 | return pci_module_init(&nv_pci_driver); |