162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * sata_sil.c - Silicon Image SATA 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Maintained by: Tejun Heo <tj@kernel.org> 662306a36Sopenharmony_ci * Please ALWAYS copy linux-ide@vger.kernel.org 762306a36Sopenharmony_ci * on emails. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Copyright 2003-2005 Red Hat, Inc. 1062306a36Sopenharmony_ci * Copyright 2003 Benjamin Herrenschmidt 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * libata documentation is available via 'make {ps|pdf}docs', 1362306a36Sopenharmony_ci * as Documentation/driver-api/libata.rst 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * Documentation for SiI 3112: 1662306a36Sopenharmony_ci * http://gkernel.sourceforge.net/specs/sii/3112A_SiI-DS-0095-B2.pdf.bz2 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * Other errata and documentation available under NDA. 1962306a36Sopenharmony_ci */ 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <linux/kernel.h> 2262306a36Sopenharmony_ci#include <linux/module.h> 2362306a36Sopenharmony_ci#include <linux/pci.h> 2462306a36Sopenharmony_ci#include <linux/blkdev.h> 2562306a36Sopenharmony_ci#include <linux/delay.h> 2662306a36Sopenharmony_ci#include <linux/interrupt.h> 2762306a36Sopenharmony_ci#include <linux/device.h> 2862306a36Sopenharmony_ci#include <scsi/scsi_host.h> 2962306a36Sopenharmony_ci#include <linux/libata.h> 3062306a36Sopenharmony_ci#include <linux/dmi.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#define DRV_NAME "sata_sil" 3362306a36Sopenharmony_ci#define DRV_VERSION "2.4" 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#define SIL_DMA_BOUNDARY 0x7fffffffUL 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_cienum { 3862306a36Sopenharmony_ci SIL_MMIO_BAR = 5, 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci /* 4162306a36Sopenharmony_ci * host flags 4262306a36Sopenharmony_ci */ 4362306a36Sopenharmony_ci SIL_FLAG_NO_SATA_IRQ = (1 << 28), 4462306a36Sopenharmony_ci SIL_FLAG_RERR_ON_DMA_ACT = (1 << 29), 4562306a36Sopenharmony_ci SIL_FLAG_MOD15WRITE = (1 << 30), 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci SIL_DFL_PORT_FLAGS = ATA_FLAG_SATA, 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci /* 5062306a36Sopenharmony_ci * Controller IDs 5162306a36Sopenharmony_ci */ 5262306a36Sopenharmony_ci sil_3112 = 0, 5362306a36Sopenharmony_ci sil_3112_no_sata_irq = 1, 5462306a36Sopenharmony_ci sil_3512 = 2, 5562306a36Sopenharmony_ci sil_3114 = 3, 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci /* 5862306a36Sopenharmony_ci * Register offsets 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_ci SIL_SYSCFG = 0x48, 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci /* 6362306a36Sopenharmony_ci * Register bits 6462306a36Sopenharmony_ci */ 6562306a36Sopenharmony_ci /* SYSCFG */ 6662306a36Sopenharmony_ci SIL_MASK_IDE0_INT = (1 << 22), 6762306a36Sopenharmony_ci SIL_MASK_IDE1_INT = (1 << 23), 6862306a36Sopenharmony_ci SIL_MASK_IDE2_INT = (1 << 24), 6962306a36Sopenharmony_ci SIL_MASK_IDE3_INT = (1 << 25), 7062306a36Sopenharmony_ci SIL_MASK_2PORT = SIL_MASK_IDE0_INT | SIL_MASK_IDE1_INT, 7162306a36Sopenharmony_ci SIL_MASK_4PORT = SIL_MASK_2PORT | 7262306a36Sopenharmony_ci SIL_MASK_IDE2_INT | SIL_MASK_IDE3_INT, 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci /* BMDMA/BMDMA2 */ 7562306a36Sopenharmony_ci SIL_INTR_STEERING = (1 << 1), 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci SIL_DMA_ENABLE = (1 << 0), /* DMA run switch */ 7862306a36Sopenharmony_ci SIL_DMA_RDWR = (1 << 3), /* DMA Rd-Wr */ 7962306a36Sopenharmony_ci SIL_DMA_SATA_IRQ = (1 << 4), /* OR of all SATA IRQs */ 8062306a36Sopenharmony_ci SIL_DMA_ACTIVE = (1 << 16), /* DMA running */ 8162306a36Sopenharmony_ci SIL_DMA_ERROR = (1 << 17), /* PCI bus error */ 8262306a36Sopenharmony_ci SIL_DMA_COMPLETE = (1 << 18), /* cmd complete / IRQ pending */ 8362306a36Sopenharmony_ci SIL_DMA_N_SATA_IRQ = (1 << 6), /* SATA_IRQ for the next channel */ 8462306a36Sopenharmony_ci SIL_DMA_N_ACTIVE = (1 << 24), /* ACTIVE for the next channel */ 8562306a36Sopenharmony_ci SIL_DMA_N_ERROR = (1 << 25), /* ERROR for the next channel */ 8662306a36Sopenharmony_ci SIL_DMA_N_COMPLETE = (1 << 26), /* COMPLETE for the next channel */ 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci /* SIEN */ 8962306a36Sopenharmony_ci SIL_SIEN_N = (1 << 16), /* triggered by SError.N */ 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci /* 9262306a36Sopenharmony_ci * Others 9362306a36Sopenharmony_ci */ 9462306a36Sopenharmony_ci SIL_QUIRK_MOD15WRITE = (1 << 0), 9562306a36Sopenharmony_ci SIL_QUIRK_UDMA5MAX = (1 << 1), 9662306a36Sopenharmony_ci}; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic int sil_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); 9962306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 10062306a36Sopenharmony_cistatic int sil_pci_device_resume(struct pci_dev *pdev); 10162306a36Sopenharmony_ci#endif 10262306a36Sopenharmony_cistatic void sil_dev_config(struct ata_device *dev); 10362306a36Sopenharmony_cistatic int sil_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); 10462306a36Sopenharmony_cistatic int sil_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val); 10562306a36Sopenharmony_cistatic int sil_set_mode(struct ata_link *link, struct ata_device **r_failed); 10662306a36Sopenharmony_cistatic enum ata_completion_errors sil_qc_prep(struct ata_queued_cmd *qc); 10762306a36Sopenharmony_cistatic void sil_bmdma_setup(struct ata_queued_cmd *qc); 10862306a36Sopenharmony_cistatic void sil_bmdma_start(struct ata_queued_cmd *qc); 10962306a36Sopenharmony_cistatic void sil_bmdma_stop(struct ata_queued_cmd *qc); 11062306a36Sopenharmony_cistatic void sil_freeze(struct ata_port *ap); 11162306a36Sopenharmony_cistatic void sil_thaw(struct ata_port *ap); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_cistatic const struct pci_device_id sil_pci_tbl[] = { 11562306a36Sopenharmony_ci { PCI_VDEVICE(CMD, 0x3112), sil_3112 }, 11662306a36Sopenharmony_ci { PCI_VDEVICE(CMD, 0x0240), sil_3112 }, 11762306a36Sopenharmony_ci { PCI_VDEVICE(CMD, 0x3512), sil_3512 }, 11862306a36Sopenharmony_ci { PCI_VDEVICE(CMD, 0x3114), sil_3114 }, 11962306a36Sopenharmony_ci { PCI_VDEVICE(ATI, 0x436e), sil_3112 }, 12062306a36Sopenharmony_ci { PCI_VDEVICE(ATI, 0x4379), sil_3112_no_sata_irq }, 12162306a36Sopenharmony_ci { PCI_VDEVICE(ATI, 0x437a), sil_3112_no_sata_irq }, 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci { } /* terminate list */ 12462306a36Sopenharmony_ci}; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci/* TODO firmware versions should be added - eric */ 12862306a36Sopenharmony_cistatic const struct sil_drivelist { 12962306a36Sopenharmony_ci const char *product; 13062306a36Sopenharmony_ci unsigned int quirk; 13162306a36Sopenharmony_ci} sil_blacklist [] = { 13262306a36Sopenharmony_ci { "ST320012AS", SIL_QUIRK_MOD15WRITE }, 13362306a36Sopenharmony_ci { "ST330013AS", SIL_QUIRK_MOD15WRITE }, 13462306a36Sopenharmony_ci { "ST340017AS", SIL_QUIRK_MOD15WRITE }, 13562306a36Sopenharmony_ci { "ST360015AS", SIL_QUIRK_MOD15WRITE }, 13662306a36Sopenharmony_ci { "ST380023AS", SIL_QUIRK_MOD15WRITE }, 13762306a36Sopenharmony_ci { "ST3120023AS", SIL_QUIRK_MOD15WRITE }, 13862306a36Sopenharmony_ci { "ST340014ASL", SIL_QUIRK_MOD15WRITE }, 13962306a36Sopenharmony_ci { "ST360014ASL", SIL_QUIRK_MOD15WRITE }, 14062306a36Sopenharmony_ci { "ST380011ASL", SIL_QUIRK_MOD15WRITE }, 14162306a36Sopenharmony_ci { "ST3120022ASL", SIL_QUIRK_MOD15WRITE }, 14262306a36Sopenharmony_ci { "ST3160021ASL", SIL_QUIRK_MOD15WRITE }, 14362306a36Sopenharmony_ci { "TOSHIBA MK2561GSYN", SIL_QUIRK_MOD15WRITE }, 14462306a36Sopenharmony_ci { "Maxtor 4D060H3", SIL_QUIRK_UDMA5MAX }, 14562306a36Sopenharmony_ci { } 14662306a36Sopenharmony_ci}; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic struct pci_driver sil_pci_driver = { 14962306a36Sopenharmony_ci .name = DRV_NAME, 15062306a36Sopenharmony_ci .id_table = sil_pci_tbl, 15162306a36Sopenharmony_ci .probe = sil_init_one, 15262306a36Sopenharmony_ci .remove = ata_pci_remove_one, 15362306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 15462306a36Sopenharmony_ci .suspend = ata_pci_device_suspend, 15562306a36Sopenharmony_ci .resume = sil_pci_device_resume, 15662306a36Sopenharmony_ci#endif 15762306a36Sopenharmony_ci}; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cistatic const struct scsi_host_template sil_sht = { 16062306a36Sopenharmony_ci ATA_BASE_SHT(DRV_NAME), 16162306a36Sopenharmony_ci /** These controllers support Large Block Transfer which allows 16262306a36Sopenharmony_ci transfer chunks up to 2GB and which cross 64KB boundaries, 16362306a36Sopenharmony_ci therefore the DMA limits are more relaxed than standard ATA SFF. */ 16462306a36Sopenharmony_ci .dma_boundary = SIL_DMA_BOUNDARY, 16562306a36Sopenharmony_ci .sg_tablesize = ATA_MAX_PRD 16662306a36Sopenharmony_ci}; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic struct ata_port_operations sil_ops = { 16962306a36Sopenharmony_ci .inherits = &ata_bmdma32_port_ops, 17062306a36Sopenharmony_ci .dev_config = sil_dev_config, 17162306a36Sopenharmony_ci .set_mode = sil_set_mode, 17262306a36Sopenharmony_ci .bmdma_setup = sil_bmdma_setup, 17362306a36Sopenharmony_ci .bmdma_start = sil_bmdma_start, 17462306a36Sopenharmony_ci .bmdma_stop = sil_bmdma_stop, 17562306a36Sopenharmony_ci .qc_prep = sil_qc_prep, 17662306a36Sopenharmony_ci .freeze = sil_freeze, 17762306a36Sopenharmony_ci .thaw = sil_thaw, 17862306a36Sopenharmony_ci .scr_read = sil_scr_read, 17962306a36Sopenharmony_ci .scr_write = sil_scr_write, 18062306a36Sopenharmony_ci}; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic const struct ata_port_info sil_port_info[] = { 18362306a36Sopenharmony_ci /* sil_3112 */ 18462306a36Sopenharmony_ci { 18562306a36Sopenharmony_ci .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE, 18662306a36Sopenharmony_ci .pio_mask = ATA_PIO4, 18762306a36Sopenharmony_ci .mwdma_mask = ATA_MWDMA2, 18862306a36Sopenharmony_ci .udma_mask = ATA_UDMA5, 18962306a36Sopenharmony_ci .port_ops = &sil_ops, 19062306a36Sopenharmony_ci }, 19162306a36Sopenharmony_ci /* sil_3112_no_sata_irq */ 19262306a36Sopenharmony_ci { 19362306a36Sopenharmony_ci .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE | 19462306a36Sopenharmony_ci SIL_FLAG_NO_SATA_IRQ, 19562306a36Sopenharmony_ci .pio_mask = ATA_PIO4, 19662306a36Sopenharmony_ci .mwdma_mask = ATA_MWDMA2, 19762306a36Sopenharmony_ci .udma_mask = ATA_UDMA5, 19862306a36Sopenharmony_ci .port_ops = &sil_ops, 19962306a36Sopenharmony_ci }, 20062306a36Sopenharmony_ci /* sil_3512 */ 20162306a36Sopenharmony_ci { 20262306a36Sopenharmony_ci .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT, 20362306a36Sopenharmony_ci .pio_mask = ATA_PIO4, 20462306a36Sopenharmony_ci .mwdma_mask = ATA_MWDMA2, 20562306a36Sopenharmony_ci .udma_mask = ATA_UDMA5, 20662306a36Sopenharmony_ci .port_ops = &sil_ops, 20762306a36Sopenharmony_ci }, 20862306a36Sopenharmony_ci /* sil_3114 */ 20962306a36Sopenharmony_ci { 21062306a36Sopenharmony_ci .flags = SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT, 21162306a36Sopenharmony_ci .pio_mask = ATA_PIO4, 21262306a36Sopenharmony_ci .mwdma_mask = ATA_MWDMA2, 21362306a36Sopenharmony_ci .udma_mask = ATA_UDMA5, 21462306a36Sopenharmony_ci .port_ops = &sil_ops, 21562306a36Sopenharmony_ci }, 21662306a36Sopenharmony_ci}; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci/* per-port register offsets */ 21962306a36Sopenharmony_ci/* TODO: we can probably calculate rather than use a table */ 22062306a36Sopenharmony_cistatic const struct { 22162306a36Sopenharmony_ci unsigned long tf; /* ATA taskfile register block */ 22262306a36Sopenharmony_ci unsigned long ctl; /* ATA control/altstatus register block */ 22362306a36Sopenharmony_ci unsigned long bmdma; /* DMA register block */ 22462306a36Sopenharmony_ci unsigned long bmdma2; /* DMA register block #2 */ 22562306a36Sopenharmony_ci unsigned long fifo_cfg; /* FIFO Valid Byte Count and Control */ 22662306a36Sopenharmony_ci unsigned long scr; /* SATA control register block */ 22762306a36Sopenharmony_ci unsigned long sien; /* SATA Interrupt Enable register */ 22862306a36Sopenharmony_ci unsigned long xfer_mode;/* data transfer mode register */ 22962306a36Sopenharmony_ci unsigned long sfis_cfg; /* SATA FIS reception config register */ 23062306a36Sopenharmony_ci} sil_port[] = { 23162306a36Sopenharmony_ci /* port 0 ... */ 23262306a36Sopenharmony_ci /* tf ctl bmdma bmdma2 fifo scr sien mode sfis */ 23362306a36Sopenharmony_ci { 0x80, 0x8A, 0x0, 0x10, 0x40, 0x100, 0x148, 0xb4, 0x14c }, 23462306a36Sopenharmony_ci { 0xC0, 0xCA, 0x8, 0x18, 0x44, 0x180, 0x1c8, 0xf4, 0x1cc }, 23562306a36Sopenharmony_ci { 0x280, 0x28A, 0x200, 0x210, 0x240, 0x300, 0x348, 0x2b4, 0x34c }, 23662306a36Sopenharmony_ci { 0x2C0, 0x2CA, 0x208, 0x218, 0x244, 0x380, 0x3c8, 0x2f4, 0x3cc }, 23762306a36Sopenharmony_ci /* ... port 3 */ 23862306a36Sopenharmony_ci}; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ciMODULE_AUTHOR("Jeff Garzik"); 24162306a36Sopenharmony_ciMODULE_DESCRIPTION("low-level driver for Silicon Image SATA controller"); 24262306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 24362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, sil_pci_tbl); 24462306a36Sopenharmony_ciMODULE_VERSION(DRV_VERSION); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic int slow_down; 24762306a36Sopenharmony_cimodule_param(slow_down, int, 0444); 24862306a36Sopenharmony_ciMODULE_PARM_DESC(slow_down, "Sledgehammer used to work around random problems, by limiting commands to 15 sectors (0=off, 1=on)"); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic void sil_bmdma_stop(struct ata_queued_cmd *qc) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci struct ata_port *ap = qc->ap; 25462306a36Sopenharmony_ci void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR]; 25562306a36Sopenharmony_ci void __iomem *bmdma2 = mmio_base + sil_port[ap->port_no].bmdma2; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci /* clear start/stop bit - can safely always write 0 */ 25862306a36Sopenharmony_ci iowrite8(0, bmdma2); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci /* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */ 26162306a36Sopenharmony_ci ata_sff_dma_pause(ap); 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_cistatic void sil_bmdma_setup(struct ata_queued_cmd *qc) 26562306a36Sopenharmony_ci{ 26662306a36Sopenharmony_ci struct ata_port *ap = qc->ap; 26762306a36Sopenharmony_ci void __iomem *bmdma = ap->ioaddr.bmdma_addr; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci /* load PRD table addr. */ 27062306a36Sopenharmony_ci iowrite32(ap->bmdma_prd_dma, bmdma + ATA_DMA_TABLE_OFS); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* issue r/w command */ 27362306a36Sopenharmony_ci ap->ops->sff_exec_command(ap, &qc->tf); 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_cistatic void sil_bmdma_start(struct ata_queued_cmd *qc) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); 27962306a36Sopenharmony_ci struct ata_port *ap = qc->ap; 28062306a36Sopenharmony_ci void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR]; 28162306a36Sopenharmony_ci void __iomem *bmdma2 = mmio_base + sil_port[ap->port_no].bmdma2; 28262306a36Sopenharmony_ci u8 dmactl = ATA_DMA_START; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* set transfer direction, start host DMA transaction 28562306a36Sopenharmony_ci Note: For Large Block Transfer to work, the DMA must be started 28662306a36Sopenharmony_ci using the bmdma2 register. */ 28762306a36Sopenharmony_ci if (!rw) 28862306a36Sopenharmony_ci dmactl |= ATA_DMA_WR; 28962306a36Sopenharmony_ci iowrite8(dmactl, bmdma2); 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci/* The way God intended PCI IDE scatter/gather lists to look and behave... */ 29362306a36Sopenharmony_cistatic void sil_fill_sg(struct ata_queued_cmd *qc) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci struct scatterlist *sg; 29662306a36Sopenharmony_ci struct ata_port *ap = qc->ap; 29762306a36Sopenharmony_ci struct ata_bmdma_prd *prd, *last_prd = NULL; 29862306a36Sopenharmony_ci unsigned int si; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci prd = &ap->bmdma_prd[0]; 30162306a36Sopenharmony_ci for_each_sg(qc->sg, sg, qc->n_elem, si) { 30262306a36Sopenharmony_ci /* Note h/w doesn't support 64-bit, so we unconditionally 30362306a36Sopenharmony_ci * truncate dma_addr_t to u32. 30462306a36Sopenharmony_ci */ 30562306a36Sopenharmony_ci u32 addr = (u32) sg_dma_address(sg); 30662306a36Sopenharmony_ci u32 sg_len = sg_dma_len(sg); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci prd->addr = cpu_to_le32(addr); 30962306a36Sopenharmony_ci prd->flags_len = cpu_to_le32(sg_len); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci last_prd = prd; 31262306a36Sopenharmony_ci prd++; 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (likely(last_prd)) 31662306a36Sopenharmony_ci last_prd->flags_len |= cpu_to_le32(ATA_PRD_EOT); 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistatic enum ata_completion_errors sil_qc_prep(struct ata_queued_cmd *qc) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci if (!(qc->flags & ATA_QCFLAG_DMAMAP)) 32262306a36Sopenharmony_ci return AC_ERR_OK; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci sil_fill_sg(qc); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci return AC_ERR_OK; 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cistatic unsigned char sil_get_device_cache_line(struct pci_dev *pdev) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci u8 cache_line = 0; 33262306a36Sopenharmony_ci pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache_line); 33362306a36Sopenharmony_ci return cache_line; 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci/** 33762306a36Sopenharmony_ci * sil_set_mode - wrap set_mode functions 33862306a36Sopenharmony_ci * @link: link to set up 33962306a36Sopenharmony_ci * @r_failed: returned device when we fail 34062306a36Sopenharmony_ci * 34162306a36Sopenharmony_ci * Wrap the libata method for device setup as after the setup we need 34262306a36Sopenharmony_ci * to inspect the results and do some configuration work 34362306a36Sopenharmony_ci */ 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_cistatic int sil_set_mode(struct ata_link *link, struct ata_device **r_failed) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci struct ata_port *ap = link->ap; 34862306a36Sopenharmony_ci void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR]; 34962306a36Sopenharmony_ci void __iomem *addr = mmio_base + sil_port[ap->port_no].xfer_mode; 35062306a36Sopenharmony_ci struct ata_device *dev; 35162306a36Sopenharmony_ci u32 tmp, dev_mode[2] = { }; 35262306a36Sopenharmony_ci int rc; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci rc = ata_do_set_mode(link, r_failed); 35562306a36Sopenharmony_ci if (rc) 35662306a36Sopenharmony_ci return rc; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci ata_for_each_dev(dev, link, ALL) { 35962306a36Sopenharmony_ci if (!ata_dev_enabled(dev)) 36062306a36Sopenharmony_ci dev_mode[dev->devno] = 0; /* PIO0/1/2 */ 36162306a36Sopenharmony_ci else if (dev->flags & ATA_DFLAG_PIO) 36262306a36Sopenharmony_ci dev_mode[dev->devno] = 1; /* PIO3/4 */ 36362306a36Sopenharmony_ci else 36462306a36Sopenharmony_ci dev_mode[dev->devno] = 3; /* UDMA */ 36562306a36Sopenharmony_ci /* value 2 indicates MDMA */ 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci tmp = readl(addr); 36962306a36Sopenharmony_ci tmp &= ~((1<<5) | (1<<4) | (1<<1) | (1<<0)); 37062306a36Sopenharmony_ci tmp |= dev_mode[0]; 37162306a36Sopenharmony_ci tmp |= (dev_mode[1] << 4); 37262306a36Sopenharmony_ci writel(tmp, addr); 37362306a36Sopenharmony_ci readl(addr); /* flush */ 37462306a36Sopenharmony_ci return 0; 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_cistatic inline void __iomem *sil_scr_addr(struct ata_port *ap, 37862306a36Sopenharmony_ci unsigned int sc_reg) 37962306a36Sopenharmony_ci{ 38062306a36Sopenharmony_ci void __iomem *offset = ap->ioaddr.scr_addr; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci switch (sc_reg) { 38362306a36Sopenharmony_ci case SCR_STATUS: 38462306a36Sopenharmony_ci return offset + 4; 38562306a36Sopenharmony_ci case SCR_ERROR: 38662306a36Sopenharmony_ci return offset + 8; 38762306a36Sopenharmony_ci case SCR_CONTROL: 38862306a36Sopenharmony_ci return offset; 38962306a36Sopenharmony_ci default: 39062306a36Sopenharmony_ci /* do nothing */ 39162306a36Sopenharmony_ci break; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci return NULL; 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_cistatic int sil_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci void __iomem *mmio = sil_scr_addr(link->ap, sc_reg); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci if (mmio) { 40262306a36Sopenharmony_ci *val = readl(mmio); 40362306a36Sopenharmony_ci return 0; 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci return -EINVAL; 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistatic int sil_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci void __iomem *mmio = sil_scr_addr(link->ap, sc_reg); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci if (mmio) { 41362306a36Sopenharmony_ci writel(val, mmio); 41462306a36Sopenharmony_ci return 0; 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci return -EINVAL; 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_cistatic void sil_host_intr(struct ata_port *ap, u32 bmdma2) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci struct ata_eh_info *ehi = &ap->link.eh_info; 42262306a36Sopenharmony_ci struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag); 42362306a36Sopenharmony_ci u8 status; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci if (unlikely(bmdma2 & SIL_DMA_SATA_IRQ)) { 42662306a36Sopenharmony_ci u32 serror = 0xffffffff; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci /* SIEN doesn't mask SATA IRQs on some 3112s. Those 42962306a36Sopenharmony_ci * controllers continue to assert IRQ as long as 43062306a36Sopenharmony_ci * SError bits are pending. Clear SError immediately. 43162306a36Sopenharmony_ci */ 43262306a36Sopenharmony_ci sil_scr_read(&ap->link, SCR_ERROR, &serror); 43362306a36Sopenharmony_ci sil_scr_write(&ap->link, SCR_ERROR, serror); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci /* Sometimes spurious interrupts occur, double check 43662306a36Sopenharmony_ci * it's PHYRDY CHG. 43762306a36Sopenharmony_ci */ 43862306a36Sopenharmony_ci if (serror & SERR_PHYRDY_CHG) { 43962306a36Sopenharmony_ci ap->link.eh_info.serror |= serror; 44062306a36Sopenharmony_ci goto freeze; 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci if (!(bmdma2 & SIL_DMA_COMPLETE)) 44462306a36Sopenharmony_ci return; 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) { 44862306a36Sopenharmony_ci /* this sometimes happens, just clear IRQ */ 44962306a36Sopenharmony_ci ap->ops->sff_check_status(ap); 45062306a36Sopenharmony_ci return; 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci /* Check whether we are expecting interrupt in this state */ 45462306a36Sopenharmony_ci switch (ap->hsm_task_state) { 45562306a36Sopenharmony_ci case HSM_ST_FIRST: 45662306a36Sopenharmony_ci /* Some pre-ATAPI-4 devices assert INTRQ 45762306a36Sopenharmony_ci * at this state when ready to receive CDB. 45862306a36Sopenharmony_ci */ 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci /* Check the ATA_DFLAG_CDB_INTR flag is enough here. 46162306a36Sopenharmony_ci * The flag was turned on only for atapi devices. No 46262306a36Sopenharmony_ci * need to check ata_is_atapi(qc->tf.protocol) again. 46362306a36Sopenharmony_ci */ 46462306a36Sopenharmony_ci if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR)) 46562306a36Sopenharmony_ci goto err_hsm; 46662306a36Sopenharmony_ci break; 46762306a36Sopenharmony_ci case HSM_ST_LAST: 46862306a36Sopenharmony_ci if (ata_is_dma(qc->tf.protocol)) { 46962306a36Sopenharmony_ci /* clear DMA-Start bit */ 47062306a36Sopenharmony_ci ap->ops->bmdma_stop(qc); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci if (bmdma2 & SIL_DMA_ERROR) { 47362306a36Sopenharmony_ci qc->err_mask |= AC_ERR_HOST_BUS; 47462306a36Sopenharmony_ci ap->hsm_task_state = HSM_ST_ERR; 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci break; 47862306a36Sopenharmony_ci case HSM_ST: 47962306a36Sopenharmony_ci break; 48062306a36Sopenharmony_ci default: 48162306a36Sopenharmony_ci goto err_hsm; 48262306a36Sopenharmony_ci } 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci /* check main status, clearing INTRQ */ 48562306a36Sopenharmony_ci status = ap->ops->sff_check_status(ap); 48662306a36Sopenharmony_ci if (unlikely(status & ATA_BUSY)) 48762306a36Sopenharmony_ci goto err_hsm; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci /* ack bmdma irq events */ 49062306a36Sopenharmony_ci ata_bmdma_irq_clear(ap); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci /* kick HSM in the ass */ 49362306a36Sopenharmony_ci ata_sff_hsm_move(ap, qc, status, 0); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci if (unlikely(qc->err_mask) && ata_is_dma(qc->tf.protocol)) 49662306a36Sopenharmony_ci ata_ehi_push_desc(ehi, "BMDMA2 stat 0x%x", bmdma2); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci return; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci err_hsm: 50162306a36Sopenharmony_ci qc->err_mask |= AC_ERR_HSM; 50262306a36Sopenharmony_ci freeze: 50362306a36Sopenharmony_ci ata_port_freeze(ap); 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_cistatic irqreturn_t sil_interrupt(int irq, void *dev_instance) 50762306a36Sopenharmony_ci{ 50862306a36Sopenharmony_ci struct ata_host *host = dev_instance; 50962306a36Sopenharmony_ci void __iomem *mmio_base = host->iomap[SIL_MMIO_BAR]; 51062306a36Sopenharmony_ci int handled = 0; 51162306a36Sopenharmony_ci int i; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci spin_lock(&host->lock); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci for (i = 0; i < host->n_ports; i++) { 51662306a36Sopenharmony_ci struct ata_port *ap = host->ports[i]; 51762306a36Sopenharmony_ci u32 bmdma2 = readl(mmio_base + sil_port[ap->port_no].bmdma2); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci /* turn off SATA_IRQ if not supported */ 52062306a36Sopenharmony_ci if (ap->flags & SIL_FLAG_NO_SATA_IRQ) 52162306a36Sopenharmony_ci bmdma2 &= ~SIL_DMA_SATA_IRQ; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci if (bmdma2 == 0xffffffff || 52462306a36Sopenharmony_ci !(bmdma2 & (SIL_DMA_COMPLETE | SIL_DMA_SATA_IRQ))) 52562306a36Sopenharmony_ci continue; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci sil_host_intr(ap, bmdma2); 52862306a36Sopenharmony_ci handled = 1; 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci spin_unlock(&host->lock); 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci return IRQ_RETVAL(handled); 53462306a36Sopenharmony_ci} 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_cistatic void sil_freeze(struct ata_port *ap) 53762306a36Sopenharmony_ci{ 53862306a36Sopenharmony_ci void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR]; 53962306a36Sopenharmony_ci u32 tmp; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci /* global IRQ mask doesn't block SATA IRQ, turn off explicitly */ 54262306a36Sopenharmony_ci writel(0, mmio_base + sil_port[ap->port_no].sien); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci /* plug IRQ */ 54562306a36Sopenharmony_ci tmp = readl(mmio_base + SIL_SYSCFG); 54662306a36Sopenharmony_ci tmp |= SIL_MASK_IDE0_INT << ap->port_no; 54762306a36Sopenharmony_ci writel(tmp, mmio_base + SIL_SYSCFG); 54862306a36Sopenharmony_ci readl(mmio_base + SIL_SYSCFG); /* flush */ 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci /* Ensure DMA_ENABLE is off. 55162306a36Sopenharmony_ci * 55262306a36Sopenharmony_ci * This is because the controller will not give us access to the 55362306a36Sopenharmony_ci * taskfile registers while a DMA is in progress 55462306a36Sopenharmony_ci */ 55562306a36Sopenharmony_ci iowrite8(ioread8(ap->ioaddr.bmdma_addr) & ~SIL_DMA_ENABLE, 55662306a36Sopenharmony_ci ap->ioaddr.bmdma_addr); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci /* According to ata_bmdma_stop, an HDMA transition requires 55962306a36Sopenharmony_ci * on PIO cycle. But we can't read a taskfile register. 56062306a36Sopenharmony_ci */ 56162306a36Sopenharmony_ci ioread8(ap->ioaddr.bmdma_addr); 56262306a36Sopenharmony_ci} 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_cistatic void sil_thaw(struct ata_port *ap) 56562306a36Sopenharmony_ci{ 56662306a36Sopenharmony_ci void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR]; 56762306a36Sopenharmony_ci u32 tmp; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci /* clear IRQ */ 57062306a36Sopenharmony_ci ap->ops->sff_check_status(ap); 57162306a36Sopenharmony_ci ata_bmdma_irq_clear(ap); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci /* turn on SATA IRQ if supported */ 57462306a36Sopenharmony_ci if (!(ap->flags & SIL_FLAG_NO_SATA_IRQ)) 57562306a36Sopenharmony_ci writel(SIL_SIEN_N, mmio_base + sil_port[ap->port_no].sien); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci /* turn on IRQ */ 57862306a36Sopenharmony_ci tmp = readl(mmio_base + SIL_SYSCFG); 57962306a36Sopenharmony_ci tmp &= ~(SIL_MASK_IDE0_INT << ap->port_no); 58062306a36Sopenharmony_ci writel(tmp, mmio_base + SIL_SYSCFG); 58162306a36Sopenharmony_ci} 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci/** 58462306a36Sopenharmony_ci * sil_dev_config - Apply device/host-specific errata fixups 58562306a36Sopenharmony_ci * @dev: Device to be examined 58662306a36Sopenharmony_ci * 58762306a36Sopenharmony_ci * After the IDENTIFY [PACKET] DEVICE step is complete, and a 58862306a36Sopenharmony_ci * device is known to be present, this function is called. 58962306a36Sopenharmony_ci * We apply two errata fixups which are specific to Silicon Image, 59062306a36Sopenharmony_ci * a Seagate and a Maxtor fixup. 59162306a36Sopenharmony_ci * 59262306a36Sopenharmony_ci * For certain Seagate devices, we must limit the maximum sectors 59362306a36Sopenharmony_ci * to under 8K. 59462306a36Sopenharmony_ci * 59562306a36Sopenharmony_ci * For certain Maxtor devices, we must not program the drive 59662306a36Sopenharmony_ci * beyond udma5. 59762306a36Sopenharmony_ci * 59862306a36Sopenharmony_ci * Both fixups are unfairly pessimistic. As soon as I get more 59962306a36Sopenharmony_ci * information on these errata, I will create a more exhaustive 60062306a36Sopenharmony_ci * list, and apply the fixups to only the specific 60162306a36Sopenharmony_ci * devices/hosts/firmwares that need it. 60262306a36Sopenharmony_ci * 60362306a36Sopenharmony_ci * 20040111 - Seagate drives affected by the Mod15Write bug are blacklisted 60462306a36Sopenharmony_ci * The Maxtor quirk is in the blacklist, but I'm keeping the original 60562306a36Sopenharmony_ci * pessimistic fix for the following reasons... 60662306a36Sopenharmony_ci * - There seems to be less info on it, only one device gleaned off the 60762306a36Sopenharmony_ci * Windows driver, maybe only one is affected. More info would be greatly 60862306a36Sopenharmony_ci * appreciated. 60962306a36Sopenharmony_ci * - But then again UDMA5 is hardly anything to complain about 61062306a36Sopenharmony_ci */ 61162306a36Sopenharmony_cistatic void sil_dev_config(struct ata_device *dev) 61262306a36Sopenharmony_ci{ 61362306a36Sopenharmony_ci struct ata_port *ap = dev->link->ap; 61462306a36Sopenharmony_ci int print_info = ap->link.eh_context.i.flags & ATA_EHI_PRINTINFO; 61562306a36Sopenharmony_ci unsigned int n, quirks = 0; 61662306a36Sopenharmony_ci unsigned char model_num[ATA_ID_PROD_LEN + 1]; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci /* This controller doesn't support trim */ 61962306a36Sopenharmony_ci dev->horkage |= ATA_HORKAGE_NOTRIM; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num)); 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci for (n = 0; sil_blacklist[n].product; n++) 62462306a36Sopenharmony_ci if (!strcmp(sil_blacklist[n].product, model_num)) { 62562306a36Sopenharmony_ci quirks = sil_blacklist[n].quirk; 62662306a36Sopenharmony_ci break; 62762306a36Sopenharmony_ci } 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci /* limit requests to 15 sectors */ 63062306a36Sopenharmony_ci if (slow_down || 63162306a36Sopenharmony_ci ((ap->flags & SIL_FLAG_MOD15WRITE) && 63262306a36Sopenharmony_ci (quirks & SIL_QUIRK_MOD15WRITE))) { 63362306a36Sopenharmony_ci if (print_info) 63462306a36Sopenharmony_ci ata_dev_info(dev, 63562306a36Sopenharmony_ci "applying Seagate errata fix (mod15write workaround)\n"); 63662306a36Sopenharmony_ci dev->max_sectors = 15; 63762306a36Sopenharmony_ci return; 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci /* limit to udma5 */ 64162306a36Sopenharmony_ci if (quirks & SIL_QUIRK_UDMA5MAX) { 64262306a36Sopenharmony_ci if (print_info) 64362306a36Sopenharmony_ci ata_dev_info(dev, "applying Maxtor errata fix %s\n", 64462306a36Sopenharmony_ci model_num); 64562306a36Sopenharmony_ci dev->udma_mask &= ATA_UDMA5; 64662306a36Sopenharmony_ci return; 64762306a36Sopenharmony_ci } 64862306a36Sopenharmony_ci} 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_cistatic void sil_init_controller(struct ata_host *host) 65162306a36Sopenharmony_ci{ 65262306a36Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(host->dev); 65362306a36Sopenharmony_ci void __iomem *mmio_base = host->iomap[SIL_MMIO_BAR]; 65462306a36Sopenharmony_ci u8 cls; 65562306a36Sopenharmony_ci u32 tmp; 65662306a36Sopenharmony_ci int i; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci /* Initialize FIFO PCI bus arbitration */ 65962306a36Sopenharmony_ci cls = sil_get_device_cache_line(pdev); 66062306a36Sopenharmony_ci if (cls) { 66162306a36Sopenharmony_ci cls >>= 3; 66262306a36Sopenharmony_ci cls++; /* cls = (line_size/8)+1 */ 66362306a36Sopenharmony_ci for (i = 0; i < host->n_ports; i++) 66462306a36Sopenharmony_ci writew(cls << 8 | cls, 66562306a36Sopenharmony_ci mmio_base + sil_port[i].fifo_cfg); 66662306a36Sopenharmony_ci } else 66762306a36Sopenharmony_ci dev_warn(&pdev->dev, 66862306a36Sopenharmony_ci "cache line size not set. Driver may not function\n"); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci /* Apply R_ERR on DMA activate FIS errata workaround */ 67162306a36Sopenharmony_ci if (host->ports[0]->flags & SIL_FLAG_RERR_ON_DMA_ACT) { 67262306a36Sopenharmony_ci int cnt; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci for (i = 0, cnt = 0; i < host->n_ports; i++) { 67562306a36Sopenharmony_ci tmp = readl(mmio_base + sil_port[i].sfis_cfg); 67662306a36Sopenharmony_ci if ((tmp & 0x3) != 0x01) 67762306a36Sopenharmony_ci continue; 67862306a36Sopenharmony_ci if (!cnt) 67962306a36Sopenharmony_ci dev_info(&pdev->dev, 68062306a36Sopenharmony_ci "Applying R_ERR on DMA activate FIS errata fix\n"); 68162306a36Sopenharmony_ci writel(tmp & ~0x3, mmio_base + sil_port[i].sfis_cfg); 68262306a36Sopenharmony_ci cnt++; 68362306a36Sopenharmony_ci } 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci if (host->n_ports == 4) { 68762306a36Sopenharmony_ci /* flip the magic "make 4 ports work" bit */ 68862306a36Sopenharmony_ci tmp = readl(mmio_base + sil_port[2].bmdma); 68962306a36Sopenharmony_ci if ((tmp & SIL_INTR_STEERING) == 0) 69062306a36Sopenharmony_ci writel(tmp | SIL_INTR_STEERING, 69162306a36Sopenharmony_ci mmio_base + sil_port[2].bmdma); 69262306a36Sopenharmony_ci } 69362306a36Sopenharmony_ci} 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_cistatic bool sil_broken_system_poweroff(struct pci_dev *pdev) 69662306a36Sopenharmony_ci{ 69762306a36Sopenharmony_ci static const struct dmi_system_id broken_systems[] = { 69862306a36Sopenharmony_ci { 69962306a36Sopenharmony_ci .ident = "HP Compaq nx6325", 70062306a36Sopenharmony_ci .matches = { 70162306a36Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"), 70262306a36Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6325"), 70362306a36Sopenharmony_ci }, 70462306a36Sopenharmony_ci /* PCI slot number of the controller */ 70562306a36Sopenharmony_ci .driver_data = (void *)0x12UL, 70662306a36Sopenharmony_ci }, 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci { } /* terminate list */ 70962306a36Sopenharmony_ci }; 71062306a36Sopenharmony_ci const struct dmi_system_id *dmi = dmi_first_match(broken_systems); 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci if (dmi) { 71362306a36Sopenharmony_ci unsigned long slot = (unsigned long)dmi->driver_data; 71462306a36Sopenharmony_ci /* apply the quirk only to on-board controllers */ 71562306a36Sopenharmony_ci return slot == PCI_SLOT(pdev->devfn); 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci return false; 71962306a36Sopenharmony_ci} 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_cistatic int sil_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci int board_id = ent->driver_data; 72462306a36Sopenharmony_ci struct ata_port_info pi = sil_port_info[board_id]; 72562306a36Sopenharmony_ci const struct ata_port_info *ppi[] = { &pi, NULL }; 72662306a36Sopenharmony_ci struct ata_host *host; 72762306a36Sopenharmony_ci void __iomem *mmio_base; 72862306a36Sopenharmony_ci int n_ports, rc; 72962306a36Sopenharmony_ci unsigned int i; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci ata_print_version_once(&pdev->dev, DRV_VERSION); 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci /* allocate host */ 73462306a36Sopenharmony_ci n_ports = 2; 73562306a36Sopenharmony_ci if (board_id == sil_3114) 73662306a36Sopenharmony_ci n_ports = 4; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci if (sil_broken_system_poweroff(pdev)) { 73962306a36Sopenharmony_ci pi.flags |= ATA_FLAG_NO_POWEROFF_SPINDOWN | 74062306a36Sopenharmony_ci ATA_FLAG_NO_HIBERNATE_SPINDOWN; 74162306a36Sopenharmony_ci dev_info(&pdev->dev, "quirky BIOS, skipping spindown " 74262306a36Sopenharmony_ci "on poweroff and hibernation\n"); 74362306a36Sopenharmony_ci } 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports); 74662306a36Sopenharmony_ci if (!host) 74762306a36Sopenharmony_ci return -ENOMEM; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci /* acquire resources and fill host */ 75062306a36Sopenharmony_ci rc = pcim_enable_device(pdev); 75162306a36Sopenharmony_ci if (rc) 75262306a36Sopenharmony_ci return rc; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci rc = pcim_iomap_regions(pdev, 1 << SIL_MMIO_BAR, DRV_NAME); 75562306a36Sopenharmony_ci if (rc == -EBUSY) 75662306a36Sopenharmony_ci pcim_pin_device(pdev); 75762306a36Sopenharmony_ci if (rc) 75862306a36Sopenharmony_ci return rc; 75962306a36Sopenharmony_ci host->iomap = pcim_iomap_table(pdev); 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci rc = dma_set_mask_and_coherent(&pdev->dev, ATA_DMA_MASK); 76262306a36Sopenharmony_ci if (rc) 76362306a36Sopenharmony_ci return rc; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci mmio_base = host->iomap[SIL_MMIO_BAR]; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci for (i = 0; i < host->n_ports; i++) { 76862306a36Sopenharmony_ci struct ata_port *ap = host->ports[i]; 76962306a36Sopenharmony_ci struct ata_ioports *ioaddr = &ap->ioaddr; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci ioaddr->cmd_addr = mmio_base + sil_port[i].tf; 77262306a36Sopenharmony_ci ioaddr->altstatus_addr = 77362306a36Sopenharmony_ci ioaddr->ctl_addr = mmio_base + sil_port[i].ctl; 77462306a36Sopenharmony_ci ioaddr->bmdma_addr = mmio_base + sil_port[i].bmdma; 77562306a36Sopenharmony_ci ioaddr->scr_addr = mmio_base + sil_port[i].scr; 77662306a36Sopenharmony_ci ata_sff_std_ports(ioaddr); 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci ata_port_pbar_desc(ap, SIL_MMIO_BAR, -1, "mmio"); 77962306a36Sopenharmony_ci ata_port_pbar_desc(ap, SIL_MMIO_BAR, sil_port[i].tf, "tf"); 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci /* initialize and activate */ 78362306a36Sopenharmony_ci sil_init_controller(host); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci pci_set_master(pdev); 78662306a36Sopenharmony_ci return ata_host_activate(host, pdev->irq, sil_interrupt, IRQF_SHARED, 78762306a36Sopenharmony_ci &sil_sht); 78862306a36Sopenharmony_ci} 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 79162306a36Sopenharmony_cistatic int sil_pci_device_resume(struct pci_dev *pdev) 79262306a36Sopenharmony_ci{ 79362306a36Sopenharmony_ci struct ata_host *host = pci_get_drvdata(pdev); 79462306a36Sopenharmony_ci int rc; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci rc = ata_pci_device_do_resume(pdev); 79762306a36Sopenharmony_ci if (rc) 79862306a36Sopenharmony_ci return rc; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci sil_init_controller(host); 80162306a36Sopenharmony_ci ata_host_resume(host); 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci return 0; 80462306a36Sopenharmony_ci} 80562306a36Sopenharmony_ci#endif 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_cimodule_pci_driver(sil_pci_driver); 808