sata_sil.c revision 41137aa61c1ccb7cd06981807113b7e2d0ad89ed
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  sata_sil.c - Silicon Image SATA
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Maintained by:  Jeff Garzik <jgarzik@pobox.com>
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  		    Please ALWAYS copy linux-ide@vger.kernel.org
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *		    on emails.
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
8af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *  Copyright 2003-2005 Red Hat, Inc.
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *  Copyright 2003 Benjamin Herrenschmidt
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
11af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *
12af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *  This program is free software; you can redistribute it and/or modify
13af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *  it under the terms of the GNU General Public License as published by
14af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *  the Free Software Foundation; either version 2, or (at your option)
15af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *  any later version.
16af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *
17af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *  This program is distributed in the hope that it will be useful,
18af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *  but WITHOUT ANY WARRANTY; without even the implied warranty of
19af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *  GNU General Public License for more details.
21af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *
22af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *  You should have received a copy of the GNU General Public License
23af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *  along with this program; see the file COPYING.  If not, write to
24af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
25af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *
26af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *
27af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *  libata documentation is available via 'make {ps|pdf}docs',
28af36d7f0df56de3e3e4bbfb15d0915097ecb8cabJeff Garzik *  as Documentation/DocBook/libata.*
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
30953d1137fc4aba16deace262e93974913596dcfeJeff Garzik *  Documentation for SiI 3112:
31953d1137fc4aba16deace262e93974913596dcfeJeff Garzik *  http://gkernel.sourceforge.net/specs/sii/3112A_SiI-DS-0095-B2.pdf.bz2
32953d1137fc4aba16deace262e93974913596dcfeJeff Garzik *
33953d1137fc4aba16deace262e93974913596dcfeJeff Garzik *  Other errata and documentation available under NDA.
34953d1137fc4aba16deace262e93974913596dcfeJeff Garzik *
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h>
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/blkdev.h>
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h>
44a9524a76f70f3343e4be27f95a7e92a8ba5f9009Jeff Garzik#include <linux/device.h>
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <scsi/scsi_host.h>
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/libata.h>
471737ef7598d3515fdc11cb9ba7e054f334404e04Alexander Beregalov#include <linux/dmi.h>
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DRV_NAME	"sata_sil"
50c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock#define DRV_VERSION	"2.4"
51c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock
52c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock#define SIL_DMA_BOUNDARY	0x7fffffffUL
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsenum {
550d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	SIL_MMIO_BAR		= 5,
560d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo
57e653a1e6131d0a819288a2e2de654627233604e0Tejun Heo	/*
58e653a1e6131d0a819288a2e2de654627233604e0Tejun Heo	 * host flags
59e653a1e6131d0a819288a2e2de654627233604e0Tejun Heo	 */
60201ce85946504ea0e6bd9a365de26684b437121eTejun Heo	SIL_FLAG_NO_SATA_IRQ	= (1 << 28),
61e4e10e3e7995f5bd481d2720bf30d3a661d110caTejun Heo	SIL_FLAG_RERR_ON_DMA_ACT = (1 << 29),
62e4deec6304cbd5fd08bf573eccc68787945071c2Tejun Heo	SIL_FLAG_MOD15WRITE	= (1 << 30),
6320888d83687d5cb374cdb5b0afa746ab79666f4eTejun Heo
64cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	SIL_DFL_PORT_FLAGS	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
650c88758b5a6325428aaadab619886242db20ceaeTejun Heo				  ATA_FLAG_MMIO,
66e4deec6304cbd5fd08bf573eccc68787945071c2Tejun Heo
67e653a1e6131d0a819288a2e2de654627233604e0Tejun Heo	/*
68e653a1e6131d0a819288a2e2de654627233604e0Tejun Heo	 * Controller IDs
69e653a1e6131d0a819288a2e2de654627233604e0Tejun Heo	 */
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sil_3112		= 0,
71201ce85946504ea0e6bd9a365de26684b437121eTejun Heo	sil_3112_no_sata_irq	= 1,
72201ce85946504ea0e6bd9a365de26684b437121eTejun Heo	sil_3512		= 2,
73201ce85946504ea0e6bd9a365de26684b437121eTejun Heo	sil_3114		= 3,
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
75e653a1e6131d0a819288a2e2de654627233604e0Tejun Heo	/*
76e653a1e6131d0a819288a2e2de654627233604e0Tejun Heo	 * Register offsets
77e653a1e6131d0a819288a2e2de654627233604e0Tejun Heo	 */
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SIL_SYSCFG		= 0x48,
79e653a1e6131d0a819288a2e2de654627233604e0Tejun Heo
80e653a1e6131d0a819288a2e2de654627233604e0Tejun Heo	/*
81e653a1e6131d0a819288a2e2de654627233604e0Tejun Heo	 * Register bits
82e653a1e6131d0a819288a2e2de654627233604e0Tejun Heo	 */
83e653a1e6131d0a819288a2e2de654627233604e0Tejun Heo	/* SYSCFG */
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SIL_MASK_IDE0_INT	= (1 << 22),
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SIL_MASK_IDE1_INT	= (1 << 23),
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SIL_MASK_IDE2_INT	= (1 << 24),
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SIL_MASK_IDE3_INT	= (1 << 25),
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SIL_MASK_2PORT		= SIL_MASK_IDE0_INT | SIL_MASK_IDE1_INT,
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SIL_MASK_4PORT		= SIL_MASK_2PORT |
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  SIL_MASK_IDE2_INT | SIL_MASK_IDE3_INT,
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
92e653a1e6131d0a819288a2e2de654627233604e0Tejun Heo	/* BMDMA/BMDMA2 */
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SIL_INTR_STEERING	= (1 << 1),
94e653a1e6131d0a819288a2e2de654627233604e0Tejun Heo
9520888d83687d5cb374cdb5b0afa746ab79666f4eTejun Heo	SIL_DMA_ENABLE		= (1 << 0),  /* DMA run switch */
9620888d83687d5cb374cdb5b0afa746ab79666f4eTejun Heo	SIL_DMA_RDWR		= (1 << 3),  /* DMA Rd-Wr */
9720888d83687d5cb374cdb5b0afa746ab79666f4eTejun Heo	SIL_DMA_SATA_IRQ	= (1 << 4),  /* OR of all SATA IRQs */
9820888d83687d5cb374cdb5b0afa746ab79666f4eTejun Heo	SIL_DMA_ACTIVE		= (1 << 16), /* DMA running */
9920888d83687d5cb374cdb5b0afa746ab79666f4eTejun Heo	SIL_DMA_ERROR		= (1 << 17), /* PCI bus error */
10020888d83687d5cb374cdb5b0afa746ab79666f4eTejun Heo	SIL_DMA_COMPLETE	= (1 << 18), /* cmd complete / IRQ pending */
10120888d83687d5cb374cdb5b0afa746ab79666f4eTejun Heo	SIL_DMA_N_SATA_IRQ	= (1 << 6),  /* SATA_IRQ for the next channel */
10220888d83687d5cb374cdb5b0afa746ab79666f4eTejun Heo	SIL_DMA_N_ACTIVE	= (1 << 24), /* ACTIVE for the next channel */
10320888d83687d5cb374cdb5b0afa746ab79666f4eTejun Heo	SIL_DMA_N_ERROR		= (1 << 25), /* ERROR for the next channel */
10420888d83687d5cb374cdb5b0afa746ab79666f4eTejun Heo	SIL_DMA_N_COMPLETE	= (1 << 26), /* COMPLETE for the next channel */
10520888d83687d5cb374cdb5b0afa746ab79666f4eTejun Heo
10620888d83687d5cb374cdb5b0afa746ab79666f4eTejun Heo	/* SIEN */
10720888d83687d5cb374cdb5b0afa746ab79666f4eTejun Heo	SIL_SIEN_N		= (1 << 16), /* triggered by SError.N */
10820888d83687d5cb374cdb5b0afa746ab79666f4eTejun Heo
109e653a1e6131d0a819288a2e2de654627233604e0Tejun Heo	/*
110e653a1e6131d0a819288a2e2de654627233604e0Tejun Heo	 * Others
111e653a1e6131d0a819288a2e2de654627233604e0Tejun Heo	 */
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SIL_QUIRK_MOD15WRITE	= (1 << 0),
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	SIL_QUIRK_UDMA5MAX	= (1 << 1),
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1165796d1c4c89efff823259fda35b08ea66ebf8b23Jeff Garzikstatic int sil_init_one(struct pci_dev *pdev, const struct pci_device_id *ent);
117281d426c7e64286f433645e27862e7744b1e9310Alexey Dobriyan#ifdef CONFIG_PM
118afb5a7cb84b1ea8b6045945e3d288303e6b71336Tejun Heostatic int sil_pci_device_resume(struct pci_dev *pdev);
119281d426c7e64286f433645e27862e7744b1e9310Alexey Dobriyan#endif
120cd0d3bbcdd650651b7ccfaf55d107e3fc237d95aAlan Coxstatic void sil_dev_config(struct ata_device *dev);
12182ef04fb4c82542b3eda81cca461f0594ce9cd0bTejun Heostatic int sil_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val);
12282ef04fb4c82542b3eda81cca461f0594ce9cd0bTejun Heostatic int sil_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val);
1230260731f0187840e272bfa10d3ba0f3e417976f5Tejun Heostatic int sil_set_mode(struct ata_link *link, struct ata_device **r_failed);
124c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancockstatic void sil_qc_prep(struct ata_queued_cmd *qc);
125c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancockstatic void sil_bmdma_setup(struct ata_queued_cmd *qc);
126c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancockstatic void sil_bmdma_start(struct ata_queued_cmd *qc);
127c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancockstatic void sil_bmdma_stop(struct ata_queued_cmd *qc);
128f6aae27ed002ba9c0a98aff811dbde32ce749d28Tejun Heostatic void sil_freeze(struct ata_port *ap);
129f6aae27ed002ba9c0a98aff811dbde32ce749d28Tejun Heostatic void sil_thaw(struct ata_port *ap);
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
131374b1873571bf80dc0c1fcceaaad067980f3b9deJeff Garzik
1323b7d697dfb7d03edb87e50b743a7ecff029618e9Jeff Garzikstatic const struct pci_device_id sil_pci_tbl[] = {
13354bb3a94b192be09feb85993b664ff118d6433d0Jeff Garzik	{ PCI_VDEVICE(CMD, 0x3112), sil_3112 },
13454bb3a94b192be09feb85993b664ff118d6433d0Jeff Garzik	{ PCI_VDEVICE(CMD, 0x0240), sil_3112 },
13554bb3a94b192be09feb85993b664ff118d6433d0Jeff Garzik	{ PCI_VDEVICE(CMD, 0x3512), sil_3512 },
13654bb3a94b192be09feb85993b664ff118d6433d0Jeff Garzik	{ PCI_VDEVICE(CMD, 0x3114), sil_3114 },
13754bb3a94b192be09feb85993b664ff118d6433d0Jeff Garzik	{ PCI_VDEVICE(ATI, 0x436e), sil_3112 },
13854bb3a94b192be09feb85993b664ff118d6433d0Jeff Garzik	{ PCI_VDEVICE(ATI, 0x4379), sil_3112_no_sata_irq },
13954bb3a94b192be09feb85993b664ff118d6433d0Jeff Garzik	{ PCI_VDEVICE(ATI, 0x437a), sil_3112_no_sata_irq },
14054bb3a94b192be09feb85993b664ff118d6433d0Jeff Garzik
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ }	/* terminate list */
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* TODO firmware versions should be added - eric */
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct sil_drivelist {
1475796d1c4c89efff823259fda35b08ea66ebf8b23Jeff Garzik	const char *product;
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int quirk;
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} sil_blacklist [] = {
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ "ST320012AS",		SIL_QUIRK_MOD15WRITE },
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ "ST330013AS",		SIL_QUIRK_MOD15WRITE },
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ "ST340017AS",		SIL_QUIRK_MOD15WRITE },
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ "ST360015AS",		SIL_QUIRK_MOD15WRITE },
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ "ST380023AS",		SIL_QUIRK_MOD15WRITE },
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ "ST3120023AS",	SIL_QUIRK_MOD15WRITE },
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ "ST340014ASL",	SIL_QUIRK_MOD15WRITE },
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ "ST360014ASL",	SIL_QUIRK_MOD15WRITE },
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ "ST380011ASL",	SIL_QUIRK_MOD15WRITE },
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ "ST3120022ASL",	SIL_QUIRK_MOD15WRITE },
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ "ST3160021ASL",	SIL_QUIRK_MOD15WRITE },
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ "Maxtor 4D060H3",	SIL_QUIRK_UDMA5MAX },
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{ }
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct pci_driver sil_pci_driver = {
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.name			= DRV_NAME,
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.id_table		= sil_pci_tbl,
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.probe			= sil_init_one,
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.remove			= ata_pci_remove_one,
170281d426c7e64286f433645e27862e7744b1e9310Alexey Dobriyan#ifdef CONFIG_PM
171afb5a7cb84b1ea8b6045945e3d288303e6b71336Tejun Heo	.suspend		= ata_pci_device_suspend,
172afb5a7cb84b1ea8b6045945e3d288303e6b71336Tejun Heo	.resume			= sil_pci_device_resume,
173281d426c7e64286f433645e27862e7744b1e9310Alexey Dobriyan#endif
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
176193515d51ccb363165d6b09e9ba5c21089e34badJeff Garzikstatic struct scsi_host_template sil_sht = {
177c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	ATA_BASE_SHT(DRV_NAME),
178c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	/** These controllers support Large Block Transfer which allows
179c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	    transfer chunks up to 2GB and which cross 64KB boundaries,
180c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	    therefore the DMA limits are more relaxed than standard ATA SFF. */
181c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	.dma_boundary		= SIL_DMA_BOUNDARY,
182c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	.sg_tablesize		= ATA_MAX_PRD
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
185029cfd6b74fc5c517865fad78cf4a3ea8d9b664aTejun Heostatic struct ata_port_operations sil_ops = {
186029cfd6b74fc5c517865fad78cf4a3ea8d9b664aTejun Heo	.inherits		= &ata_bmdma_port_ops,
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.dev_config		= sil_dev_config,
1889d2c7c75f889a3eefad016c71f651b0796e0a6e9Alan Cox	.set_mode		= sil_set_mode,
189c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	.bmdma_setup            = sil_bmdma_setup,
190c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	.bmdma_start            = sil_bmdma_start,
191c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	.bmdma_stop		= sil_bmdma_stop,
192c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	.qc_prep		= sil_qc_prep,
193f6aae27ed002ba9c0a98aff811dbde32ce749d28Tejun Heo	.freeze			= sil_freeze,
194f6aae27ed002ba9c0a98aff811dbde32ce749d28Tejun Heo	.thaw			= sil_thaw,
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.scr_read		= sil_scr_read,
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	.scr_write		= sil_scr_write,
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
19998ac62defe529d04a192688f40d801a2d8fbcf98Arjan van de Venstatic const struct ata_port_info sil_port_info[] = {
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* sil_3112 */
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
202cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik		.flags		= SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE,
203e4deec6304cbd5fd08bf573eccc68787945071c2Tejun Heo		.pio_mask	= 0x1f,			/* pio0-4 */
204e4deec6304cbd5fd08bf573eccc68787945071c2Tejun Heo		.mwdma_mask	= 0x07,			/* mwdma0-2 */
205bf6263a853c9c143bf03f0a6fdcc68ab714fb5f5Jeff Garzik		.udma_mask	= ATA_UDMA5,
206e4deec6304cbd5fd08bf573eccc68787945071c2Tejun Heo		.port_ops	= &sil_ops,
2070ee304d5802dc62746f13f12d4cb4ec4ed285f66Tejun Heo	},
208201ce85946504ea0e6bd9a365de26684b437121eTejun Heo	/* sil_3112_no_sata_irq */
209201ce85946504ea0e6bd9a365de26684b437121eTejun Heo	{
210cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik		.flags		= SIL_DFL_PORT_FLAGS | SIL_FLAG_MOD15WRITE |
211201ce85946504ea0e6bd9a365de26684b437121eTejun Heo				  SIL_FLAG_NO_SATA_IRQ,
212201ce85946504ea0e6bd9a365de26684b437121eTejun Heo		.pio_mask	= 0x1f,			/* pio0-4 */
213201ce85946504ea0e6bd9a365de26684b437121eTejun Heo		.mwdma_mask	= 0x07,			/* mwdma0-2 */
214bf6263a853c9c143bf03f0a6fdcc68ab714fb5f5Jeff Garzik		.udma_mask	= ATA_UDMA5,
215201ce85946504ea0e6bd9a365de26684b437121eTejun Heo		.port_ops	= &sil_ops,
216201ce85946504ea0e6bd9a365de26684b437121eTejun Heo	},
2170ee304d5802dc62746f13f12d4cb4ec4ed285f66Tejun Heo	/* sil_3512 */
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
219cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik		.flags		= SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
2200ee304d5802dc62746f13f12d4cb4ec4ed285f66Tejun Heo		.pio_mask	= 0x1f,			/* pio0-4 */
2210ee304d5802dc62746f13f12d4cb4ec4ed285f66Tejun Heo		.mwdma_mask	= 0x07,			/* mwdma0-2 */
222bf6263a853c9c143bf03f0a6fdcc68ab714fb5f5Jeff Garzik		.udma_mask	= ATA_UDMA5,
2230ee304d5802dc62746f13f12d4cb4ec4ed285f66Tejun Heo		.port_ops	= &sil_ops,
2240ee304d5802dc62746f13f12d4cb4ec4ed285f66Tejun Heo	},
2250ee304d5802dc62746f13f12d4cb4ec4ed285f66Tejun Heo	/* sil_3114 */
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
227cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik		.flags		= SIL_DFL_PORT_FLAGS | SIL_FLAG_RERR_ON_DMA_ACT,
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.pio_mask	= 0x1f,			/* pio0-4 */
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.mwdma_mask	= 0x07,			/* mwdma0-2 */
230bf6263a853c9c143bf03f0a6fdcc68ab714fb5f5Jeff Garzik		.udma_mask	= ATA_UDMA5,
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		.port_ops	= &sil_ops,
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	},
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* per-port register offsets */
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* TODO: we can probably calculate rather than use a table */
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic const struct {
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long tf;	/* ATA taskfile register block */
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long ctl;	/* ATA control/altstatus register block */
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long bmdma;	/* DMA register block */
24120888d83687d5cb374cdb5b0afa746ab79666f4eTejun Heo	unsigned long bmdma2;	/* DMA register block #2 */
24248d4ef2a1df9867c67b515d66732ba028a73735dTejun Heo	unsigned long fifo_cfg;	/* FIFO Valid Byte Count and Control */
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long scr;	/* SATA control register block */
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long sien;	/* SATA Interrupt Enable register */
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long xfer_mode;/* data transfer mode register */
246e4e10e3e7995f5bd481d2720bf30d3a661d110caTejun Heo	unsigned long sfis_cfg;	/* SATA FIS reception config register */
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} sil_port[] = {
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* port 0 ... */
2495bcd7a00a464fd81b4b68847b9b811a635a15b61Jeff Garzik	/*   tf    ctl  bmdma  bmdma2  fifo    scr   sien   mode   sfis */
2505bcd7a00a464fd81b4b68847b9b811a635a15b61Jeff Garzik	{  0x80,  0x8A,   0x0,  0x10,  0x40, 0x100, 0x148,  0xb4, 0x14c },
2515bcd7a00a464fd81b4b68847b9b811a635a15b61Jeff Garzik	{  0xC0,  0xCA,   0x8,  0x18,  0x44, 0x180, 0x1c8,  0xf4, 0x1cc },
25220888d83687d5cb374cdb5b0afa746ab79666f4eTejun Heo	{ 0x280, 0x28A, 0x200, 0x210, 0x240, 0x300, 0x348, 0x2b4, 0x34c },
25320888d83687d5cb374cdb5b0afa746ab79666f4eTejun Heo	{ 0x2C0, 0x2CA, 0x208, 0x218, 0x244, 0x380, 0x3c8, 0x2f4, 0x3cc },
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* ... port 3 */
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Jeff Garzik");
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("low-level driver for Silicon Image SATA controller");
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DEVICE_TABLE(pci, sil_pci_tbl);
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_VERSION(DRV_VERSION);
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2635796d1c4c89efff823259fda35b08ea66ebf8b23Jeff Garzikstatic int slow_down;
26451e9f2ff83df6b1c81c5c44f4486c68ed87aa20eJeff Garzikmodule_param(slow_down, int, 0444);
26551e9f2ff83df6b1c81c5c44f4486c68ed87aa20eJeff GarzikMODULE_PARM_DESC(slow_down, "Sledgehammer used to work around random problems, by limiting commands to 15 sectors (0=off, 1=on)");
26651e9f2ff83df6b1c81c5c44f4486c68ed87aa20eJeff Garzik
267374b1873571bf80dc0c1fcceaaad067980f3b9deJeff Garzik
268c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancockstatic void sil_bmdma_stop(struct ata_queued_cmd *qc)
269c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock{
270c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	struct ata_port *ap = qc->ap;
271c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR];
272c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	void __iomem *bmdma2 = mmio_base + sil_port[ap->port_no].bmdma2;
273c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock
274c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	/* clear start/stop bit - can safely always write 0 */
275c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	iowrite8(0, bmdma2);
276c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock
277c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	/* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
278c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	ata_sff_dma_pause(ap);
279c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock}
280c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock
281c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancockstatic void sil_bmdma_setup(struct ata_queued_cmd *qc)
282c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock{
283c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	struct ata_port *ap = qc->ap;
284c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	void __iomem *bmdma = ap->ioaddr.bmdma_addr;
285c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock
286c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	/* load PRD table addr. */
287c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	iowrite32(ap->prd_dma, bmdma + ATA_DMA_TABLE_OFS);
288c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock
289c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	/* issue r/w command */
290c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	ap->ops->sff_exec_command(ap, &qc->tf);
291c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock}
292c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock
293c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancockstatic void sil_bmdma_start(struct ata_queued_cmd *qc)
294c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock{
295c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
296c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	struct ata_port *ap = qc->ap;
297c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR];
298c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	void __iomem *bmdma2 = mmio_base + sil_port[ap->port_no].bmdma2;
299c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	u8 dmactl = ATA_DMA_START;
300c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock
301c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	/* set transfer direction, start host DMA transaction
302c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	   Note: For Large Block Transfer to work, the DMA must be started
303c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	   using the bmdma2 register. */
304c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	if (!rw)
305c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock		dmactl |= ATA_DMA_WR;
306c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	iowrite8(dmactl, bmdma2);
307c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock}
308c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock
309c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock/* The way God intended PCI IDE scatter/gather lists to look and behave... */
310c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancockstatic void sil_fill_sg(struct ata_queued_cmd *qc)
311c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock{
312c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	struct scatterlist *sg;
313c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	struct ata_port *ap = qc->ap;
314c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	struct ata_prd *prd, *last_prd = NULL;
315c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	unsigned int si;
316c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock
317c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	prd = &ap->prd[0];
318c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	for_each_sg(qc->sg, sg, qc->n_elem, si) {
319c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock		/* Note h/w doesn't support 64-bit, so we unconditionally
320c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock		 * truncate dma_addr_t to u32.
321c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock		 */
322c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock		u32 addr = (u32) sg_dma_address(sg);
323c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock		u32 sg_len = sg_dma_len(sg);
324c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock
325c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock		prd->addr = cpu_to_le32(addr);
326c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock		prd->flags_len = cpu_to_le32(sg_len);
32741137aa61c1ccb7cd06981807113b7e2d0ad89edPasi Kärkkäinen		VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", si, addr, sg_len);
328c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock
329c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock		last_prd = prd;
330c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock		prd++;
331c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	}
332c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock
333c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	if (likely(last_prd))
334c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock		last_prd->flags_len |= cpu_to_le32(ATA_PRD_EOT);
335c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock}
336c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock
337c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancockstatic void sil_qc_prep(struct ata_queued_cmd *qc)
338c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock{
339c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	if (!(qc->flags & ATA_QCFLAG_DMAMAP))
340c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock		return;
341c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock
342c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock	sil_fill_sg(qc);
343c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock}
344c7e324f1bd17b25fcdca33bdad01cf6eb8be4933Robert Hancock
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned char sil_get_device_cache_line(struct pci_dev *pdev)
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	u8 cache_line = 0;
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache_line);
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return cache_line;
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3529d2c7c75f889a3eefad016c71f651b0796e0a6e9Alan Cox/**
3539d2c7c75f889a3eefad016c71f651b0796e0a6e9Alan Cox *	sil_set_mode		-	wrap set_mode functions
3540260731f0187840e272bfa10d3ba0f3e417976f5Tejun Heo *	@link: link to set up
3559d2c7c75f889a3eefad016c71f651b0796e0a6e9Alan Cox *	@r_failed: returned device when we fail
3569d2c7c75f889a3eefad016c71f651b0796e0a6e9Alan Cox *
3579d2c7c75f889a3eefad016c71f651b0796e0a6e9Alan Cox *	Wrap the libata method for device setup as after the setup we need
3589d2c7c75f889a3eefad016c71f651b0796e0a6e9Alan Cox *	to inspect the results and do some configuration work
3599d2c7c75f889a3eefad016c71f651b0796e0a6e9Alan Cox */
3609d2c7c75f889a3eefad016c71f651b0796e0a6e9Alan Cox
3610260731f0187840e272bfa10d3ba0f3e417976f5Tejun Heostatic int sil_set_mode(struct ata_link *link, struct ata_device **r_failed)
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3630260731f0187840e272bfa10d3ba0f3e417976f5Tejun Heo	struct ata_port *ap = link->ap;
3640260731f0187840e272bfa10d3ba0f3e417976f5Tejun Heo	void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR];
3650d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	void __iomem *addr = mmio_base + sil_port[ap->port_no].xfer_mode;
3660260731f0187840e272bfa10d3ba0f3e417976f5Tejun Heo	struct ata_device *dev;
367f58229f8060055b08b34008ea08f31de1e2f003cTejun Heo	u32 tmp, dev_mode[2] = { };
3689d2c7c75f889a3eefad016c71f651b0796e0a6e9Alan Cox	int rc;
369a617c09f6d646b60f31efc8afd9f81b752bf21b7Jeff Garzik
3700260731f0187840e272bfa10d3ba0f3e417976f5Tejun Heo	rc = ata_do_set_mode(link, r_failed);
3719d2c7c75f889a3eefad016c71f651b0796e0a6e9Alan Cox	if (rc)
3729d2c7c75f889a3eefad016c71f651b0796e0a6e9Alan Cox		return rc;
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3741eca4365be25c540650693e941bc06a66cf38f94Tejun Heo	ata_for_each_dev(dev, link, ALL) {
375e1211e3fa7fd05ff0d4f597fd37e40de8acc6784Tejun Heo		if (!ata_dev_enabled(dev))
376f58229f8060055b08b34008ea08f31de1e2f003cTejun Heo			dev_mode[dev->devno] = 0;	/* PIO0/1/2 */
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else if (dev->flags & ATA_DFLAG_PIO)
378f58229f8060055b08b34008ea08f31de1e2f003cTejun Heo			dev_mode[dev->devno] = 1;	/* PIO3/4 */
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
380f58229f8060055b08b34008ea08f31de1e2f003cTejun Heo			dev_mode[dev->devno] = 3;	/* UDMA */
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* value 2 indicates MDMA */
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp = readl(addr);
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp &= ~((1<<5) | (1<<4) | (1<<1) | (1<<0));
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp |= dev_mode[0];
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	tmp |= (dev_mode[1] << 4);
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	writel(tmp, addr);
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	readl(addr);	/* flush */
3909d2c7c75f889a3eefad016c71f651b0796e0a6e9Alan Cox	return 0;
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3935796d1c4c89efff823259fda35b08ea66ebf8b23Jeff Garzikstatic inline void __iomem *sil_scr_addr(struct ata_port *ap,
3945796d1c4c89efff823259fda35b08ea66ebf8b23Jeff Garzik					 unsigned int sc_reg)
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3960d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	void __iomem *offset = ap->ioaddr.scr_addr;
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (sc_reg) {
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SCR_STATUS:
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return offset + 4;
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SCR_ERROR:
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return offset + 8;
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case SCR_CONTROL:
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return offset;
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* do nothing */
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4108d9db2d2fbae9e05022825c32f86e00c8e342860Randy Dunlap	return NULL;
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
41382ef04fb4c82542b3eda81cca461f0594ce9cd0bTejun Heostatic int sil_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val)
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
41582ef04fb4c82542b3eda81cca461f0594ce9cd0bTejun Heo	void __iomem *mmio = sil_scr_addr(link->ap, sc_reg);
416da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo
417da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	if (mmio) {
418da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		*val = readl(mmio);
419da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return 0;
420da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	}
421da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	return -EINVAL;
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
42482ef04fb4c82542b3eda81cca461f0594ce9cd0bTejun Heostatic int sil_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val)
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
42682ef04fb4c82542b3eda81cca461f0594ce9cd0bTejun Heo	void __iomem *mmio = sil_scr_addr(link->ap, sc_reg);
427da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo
428da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	if (mmio) {
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		writel(val, mmio);
430da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo		return 0;
431da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	}
432da3dbb17a0e9a9ec7f5aed95f1fddadb790edc9dTejun Heo	return -EINVAL;
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
435cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heostatic void sil_host_intr(struct ata_port *ap, u32 bmdma2)
436cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo{
4379af5c9c97dc9d599281778864c72b385f0c63341Tejun Heo	struct ata_eh_info *ehi = &ap->link.eh_info;
4389af5c9c97dc9d599281778864c72b385f0c63341Tejun Heo	struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag);
439cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo	u8 status;
440cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo
441e573890b00426189e1e223967a2c46fb758bf06eTejun Heo	if (unlikely(bmdma2 & SIL_DMA_SATA_IRQ)) {
442d4c85325a817d3351e61c4be64b437116e8483b4Tejun Heo		u32 serror;
443d4c85325a817d3351e61c4be64b437116e8483b4Tejun Heo
444d4c85325a817d3351e61c4be64b437116e8483b4Tejun Heo		/* SIEN doesn't mask SATA IRQs on some 3112s.  Those
445d4c85325a817d3351e61c4be64b437116e8483b4Tejun Heo		 * controllers continue to assert IRQ as long as
446d4c85325a817d3351e61c4be64b437116e8483b4Tejun Heo		 * SError bits are pending.  Clear SError immediately.
447d4c85325a817d3351e61c4be64b437116e8483b4Tejun Heo		 */
44882ef04fb4c82542b3eda81cca461f0594ce9cd0bTejun Heo		sil_scr_read(&ap->link, SCR_ERROR, &serror);
44982ef04fb4c82542b3eda81cca461f0594ce9cd0bTejun Heo		sil_scr_write(&ap->link, SCR_ERROR, serror);
450d4c85325a817d3351e61c4be64b437116e8483b4Tejun Heo
4518cf32ac6578a70025be1103466da9d1d6141429eTejun Heo		/* Sometimes spurious interrupts occur, double check
4528cf32ac6578a70025be1103466da9d1d6141429eTejun Heo		 * it's PHYRDY CHG.
453d4c85325a817d3351e61c4be64b437116e8483b4Tejun Heo		 */
4548cf32ac6578a70025be1103466da9d1d6141429eTejun Heo		if (serror & SERR_PHYRDY_CHG) {
455f7fe7ad4bcaba17f05d5cbf1119772c645783b08Tejun Heo			ap->link.eh_info.serror |= serror;
4568cf32ac6578a70025be1103466da9d1d6141429eTejun Heo			goto freeze;
457d4c85325a817d3351e61c4be64b437116e8483b4Tejun Heo		}
458d4c85325a817d3351e61c4be64b437116e8483b4Tejun Heo
4598cf32ac6578a70025be1103466da9d1d6141429eTejun Heo		if (!(bmdma2 & SIL_DMA_COMPLETE))
4608cf32ac6578a70025be1103466da9d1d6141429eTejun Heo			return;
461e573890b00426189e1e223967a2c46fb758bf06eTejun Heo	}
462e573890b00426189e1e223967a2c46fb758bf06eTejun Heo
4638cf32ac6578a70025be1103466da9d1d6141429eTejun Heo	if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) {
464e2f8fb72144a9f38d44ccf3f939e939392eda659Tejun Heo		/* this sometimes happens, just clear IRQ */
4655682ed33aae05d10a25c95633ef9d9c062825888Tejun Heo		ap->ops->sff_check_status(ap);
466e2f8fb72144a9f38d44ccf3f939e939392eda659Tejun Heo		return;
467e2f8fb72144a9f38d44ccf3f939e939392eda659Tejun Heo	}
468e2f8fb72144a9f38d44ccf3f939e939392eda659Tejun Heo
469cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo	/* Check whether we are expecting interrupt in this state */
470cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo	switch (ap->hsm_task_state) {
471cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo	case HSM_ST_FIRST:
472cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo		/* Some pre-ATAPI-4 devices assert INTRQ
473cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo		 * at this state when ready to receive CDB.
474cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo		 */
475cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo
476cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo		/* Check the ATA_DFLAG_CDB_INTR flag is enough here.
477405e66b38797875e80669eaf72d313dbb76533c3Tejun Heo		 * The flag was turned on only for atapi devices.  No
478405e66b38797875e80669eaf72d313dbb76533c3Tejun Heo		 * need to check ata_is_atapi(qc->tf.protocol) again.
479cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo		 */
480cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo		if (!(qc->dev->flags & ATA_DFLAG_CDB_INTR))
481cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo			goto err_hsm;
482cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo		break;
483cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo	case HSM_ST_LAST:
484405e66b38797875e80669eaf72d313dbb76533c3Tejun Heo		if (ata_is_dma(qc->tf.protocol)) {
485cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo			/* clear DMA-Start bit */
486cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo			ap->ops->bmdma_stop(qc);
487cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo
488cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo			if (bmdma2 & SIL_DMA_ERROR) {
489cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo				qc->err_mask |= AC_ERR_HOST_BUS;
490cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo				ap->hsm_task_state = HSM_ST_ERR;
491cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo			}
492cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo		}
493cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo		break;
494cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo	case HSM_ST:
495cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo		break;
496cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo	default:
497cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo		goto err_hsm;
498cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo	}
499cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo
500cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo	/* check main status, clearing INTRQ */
5015682ed33aae05d10a25c95633ef9d9c062825888Tejun Heo	status = ap->ops->sff_check_status(ap);
502cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo	if (unlikely(status & ATA_BUSY))
503cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo		goto err_hsm;
504cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo
505cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo	/* ack bmdma irq events */
5069363c3825ea9ad76561eb48a395349dd29211ed6Tejun Heo	ata_sff_irq_clear(ap);
507cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo
508cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo	/* kick HSM in the ass */
5099363c3825ea9ad76561eb48a395349dd29211ed6Tejun Heo	ata_sff_hsm_move(ap, qc, status, 0);
510cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo
511405e66b38797875e80669eaf72d313dbb76533c3Tejun Heo	if (unlikely(qc->err_mask) && ata_is_dma(qc->tf.protocol))
512ea54763f8a7c51b9f8fcb14431812ae63fcbaf96Tejun Heo		ata_ehi_push_desc(ehi, "BMDMA2 stat 0x%x", bmdma2);
513ea54763f8a7c51b9f8fcb14431812ae63fcbaf96Tejun Heo
514cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo	return;
515cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo
516cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo err_hsm:
517cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo	qc->err_mask |= AC_ERR_HSM;
518cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo freeze:
519cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo	ata_port_freeze(ap);
520cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo}
521cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo
5227d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsstatic irqreturn_t sil_interrupt(int irq, void *dev_instance)
523cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo{
524cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	struct ata_host *host = dev_instance;
5250d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	void __iomem *mmio_base = host->iomap[SIL_MMIO_BAR];
526cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo	int handled = 0;
527cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo	int i;
528cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo
529cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	spin_lock(&host->lock);
530cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo
531cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	for (i = 0; i < host->n_ports; i++) {
532cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik		struct ata_port *ap = host->ports[i];
533cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo		u32 bmdma2 = readl(mmio_base + sil_port[ap->port_no].bmdma2);
534cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo
535cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo		if (unlikely(!ap || ap->flags & ATA_FLAG_DISABLED))
536cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo			continue;
537cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo
538201ce85946504ea0e6bd9a365de26684b437121eTejun Heo		/* turn off SATA_IRQ if not supported */
539201ce85946504ea0e6bd9a365de26684b437121eTejun Heo		if (ap->flags & SIL_FLAG_NO_SATA_IRQ)
540201ce85946504ea0e6bd9a365de26684b437121eTejun Heo			bmdma2 &= ~SIL_DMA_SATA_IRQ;
541201ce85946504ea0e6bd9a365de26684b437121eTejun Heo
54223fa9618094975f803ed0c6a44604b16747b9637Tejun Heo		if (bmdma2 == 0xffffffff ||
54323fa9618094975f803ed0c6a44604b16747b9637Tejun Heo		    !(bmdma2 & (SIL_DMA_COMPLETE | SIL_DMA_SATA_IRQ)))
544cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo			continue;
545cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo
546cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo		sil_host_intr(ap, bmdma2);
547cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo		handled = 1;
548cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo	}
549cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo
550cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	spin_unlock(&host->lock);
551cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo
552cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo	return IRQ_RETVAL(handled);
553cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo}
554cbe88fbc72d9e1aa4a6f994cb6e19fa08ae5a0baTejun Heo
555f6aae27ed002ba9c0a98aff811dbde32ce749d28Tejun Heostatic void sil_freeze(struct ata_port *ap)
556f6aae27ed002ba9c0a98aff811dbde32ce749d28Tejun Heo{
5570d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR];
558f6aae27ed002ba9c0a98aff811dbde32ce749d28Tejun Heo	u32 tmp;
559f6aae27ed002ba9c0a98aff811dbde32ce749d28Tejun Heo
560e573890b00426189e1e223967a2c46fb758bf06eTejun Heo	/* global IRQ mask doesn't block SATA IRQ, turn off explicitly */
561e573890b00426189e1e223967a2c46fb758bf06eTejun Heo	writel(0, mmio_base + sil_port[ap->port_no].sien);
562e573890b00426189e1e223967a2c46fb758bf06eTejun Heo
563f6aae27ed002ba9c0a98aff811dbde32ce749d28Tejun Heo	/* plug IRQ */
564f6aae27ed002ba9c0a98aff811dbde32ce749d28Tejun Heo	tmp = readl(mmio_base + SIL_SYSCFG);
565f6aae27ed002ba9c0a98aff811dbde32ce749d28Tejun Heo	tmp |= SIL_MASK_IDE0_INT << ap->port_no;
566f6aae27ed002ba9c0a98aff811dbde32ce749d28Tejun Heo	writel(tmp, mmio_base + SIL_SYSCFG);
567f6aae27ed002ba9c0a98aff811dbde32ce749d28Tejun Heo	readl(mmio_base + SIL_SYSCFG);	/* flush */
568f6aae27ed002ba9c0a98aff811dbde32ce749d28Tejun Heo}
569f6aae27ed002ba9c0a98aff811dbde32ce749d28Tejun Heo
570f6aae27ed002ba9c0a98aff811dbde32ce749d28Tejun Heostatic void sil_thaw(struct ata_port *ap)
571f6aae27ed002ba9c0a98aff811dbde32ce749d28Tejun Heo{
5720d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	void __iomem *mmio_base = ap->host->iomap[SIL_MMIO_BAR];
573f6aae27ed002ba9c0a98aff811dbde32ce749d28Tejun Heo	u32 tmp;
574f6aae27ed002ba9c0a98aff811dbde32ce749d28Tejun Heo
575f6aae27ed002ba9c0a98aff811dbde32ce749d28Tejun Heo	/* clear IRQ */
5765682ed33aae05d10a25c95633ef9d9c062825888Tejun Heo	ap->ops->sff_check_status(ap);
5779363c3825ea9ad76561eb48a395349dd29211ed6Tejun Heo	ata_sff_irq_clear(ap);
578f6aae27ed002ba9c0a98aff811dbde32ce749d28Tejun Heo
579201ce85946504ea0e6bd9a365de26684b437121eTejun Heo	/* turn on SATA IRQ if supported */
580201ce85946504ea0e6bd9a365de26684b437121eTejun Heo	if (!(ap->flags & SIL_FLAG_NO_SATA_IRQ))
581201ce85946504ea0e6bd9a365de26684b437121eTejun Heo		writel(SIL_SIEN_N, mmio_base + sil_port[ap->port_no].sien);
582e573890b00426189e1e223967a2c46fb758bf06eTejun Heo
583f6aae27ed002ba9c0a98aff811dbde32ce749d28Tejun Heo	/* turn on IRQ */
584f6aae27ed002ba9c0a98aff811dbde32ce749d28Tejun Heo	tmp = readl(mmio_base + SIL_SYSCFG);
585f6aae27ed002ba9c0a98aff811dbde32ce749d28Tejun Heo	tmp &= ~(SIL_MASK_IDE0_INT << ap->port_no);
586f6aae27ed002ba9c0a98aff811dbde32ce749d28Tejun Heo	writel(tmp, mmio_base + SIL_SYSCFG);
587f6aae27ed002ba9c0a98aff811dbde32ce749d28Tejun Heo}
588f6aae27ed002ba9c0a98aff811dbde32ce749d28Tejun Heo
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/**
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	sil_dev_config - Apply device/host-specific errata fixups
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	@dev: Device to be examined
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	After the IDENTIFY [PACKET] DEVICE step is complete, and a
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	device is known to be present, this function is called.
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	We apply two errata fixups which are specific to Silicon Image,
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	a Seagate and a Maxtor fixup.
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	For certain Seagate devices, we must limit the maximum sectors
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	to under 8K.
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	For certain Maxtor devices, we must not program the drive
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	beyond udma5.
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Both fixups are unfairly pessimistic.  As soon as I get more
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	information on these errata, I will create a more exhaustive
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	list, and apply the fixups to only the specific
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	devices/hosts/firmwares that need it.
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	20040111 - Seagate drives affected by the Mod15Write bug are blacklisted
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	The Maxtor quirk is in the blacklist, but I'm keeping the original
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	pessimistic fix for the following reasons...
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- There seems to be less info on it, only one device gleaned off the
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	Windows	driver, maybe only one is affected.  More info would be greatly
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	appreciated.
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *	- But then again UDMA5 is hardly anything to complain about
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
617cd0d3bbcdd650651b7ccfaf55d107e3fc237d95aAlan Coxstatic void sil_dev_config(struct ata_device *dev)
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
6199af5c9c97dc9d599281778864c72b385f0c63341Tejun Heo	struct ata_port *ap = dev->link->ap;
6209af5c9c97dc9d599281778864c72b385f0c63341Tejun Heo	int print_info = ap->link.eh_context.i.flags & ATA_EHI_PRINTINFO;
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int n, quirks = 0;
622a0cf733b333eeeafb7324e2897448006c693c26cTejun Heo	unsigned char model_num[ATA_ID_PROD_LEN + 1];
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
624a0cf733b333eeeafb7324e2897448006c693c26cTejun Heo	ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num));
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6268a60a07129fad60bba779a2a4038c7518b167fc7Jeff Garzik	for (n = 0; sil_blacklist[n].product; n++)
6272e02671daa2cd69d93c828c40579bbe953f17210Tejun Heo		if (!strcmp(sil_blacklist[n].product, model_num)) {
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			quirks = sil_blacklist[n].quirk;
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6318a60a07129fad60bba779a2a4038c7518b167fc7Jeff Garzik
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* limit requests to 15 sectors */
63351e9f2ff83df6b1c81c5c44f4486c68ed87aa20eJeff Garzik	if (slow_down ||
63451e9f2ff83df6b1c81c5c44f4486c68ed87aa20eJeff Garzik	    ((ap->flags & SIL_FLAG_MOD15WRITE) &&
63551e9f2ff83df6b1c81c5c44f4486c68ed87aa20eJeff Garzik	     (quirks & SIL_QUIRK_MOD15WRITE))) {
636efdaedc443e935eda82e9e78a6e65d1f993d242fTejun Heo		if (print_info)
637efdaedc443e935eda82e9e78a6e65d1f993d242fTejun Heo			ata_dev_printk(dev, KERN_INFO, "applying Seagate "
638efdaedc443e935eda82e9e78a6e65d1f993d242fTejun Heo				       "errata fix (mod15write workaround)\n");
639b00eec1d58ee71131375bfeb86e64bceec3f5618Tejun Heo		dev->max_sectors = 15;
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* limit to udma5 */
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (quirks & SIL_QUIRK_UDMA5MAX) {
645efdaedc443e935eda82e9e78a6e65d1f993d242fTejun Heo		if (print_info)
646efdaedc443e935eda82e9e78a6e65d1f993d242fTejun Heo			ata_dev_printk(dev, KERN_INFO, "applying Maxtor "
647efdaedc443e935eda82e9e78a6e65d1f993d242fTejun Heo				       "errata fix %s\n", model_num);
6485a529139554f12cb265715117a2153c936286294Tejun Heo		dev->udma_mask &= ATA_UDMA5;
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6534447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heostatic void sil_init_controller(struct ata_host *host)
6543d8ec91352099b32a400f1952112dc076da28106Tejun Heo{
6554447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct pci_dev *pdev = to_pci_dev(host->dev);
6564447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	void __iomem *mmio_base = host->iomap[SIL_MMIO_BAR];
6573d8ec91352099b32a400f1952112dc076da28106Tejun Heo	u8 cls;
6583d8ec91352099b32a400f1952112dc076da28106Tejun Heo	u32 tmp;
6593d8ec91352099b32a400f1952112dc076da28106Tejun Heo	int i;
6603d8ec91352099b32a400f1952112dc076da28106Tejun Heo
6613d8ec91352099b32a400f1952112dc076da28106Tejun Heo	/* Initialize FIFO PCI bus arbitration */
6623d8ec91352099b32a400f1952112dc076da28106Tejun Heo	cls = sil_get_device_cache_line(pdev);
6633d8ec91352099b32a400f1952112dc076da28106Tejun Heo	if (cls) {
6643d8ec91352099b32a400f1952112dc076da28106Tejun Heo		cls >>= 3;
6653d8ec91352099b32a400f1952112dc076da28106Tejun Heo		cls++;  /* cls = (line_size/8)+1 */
6664447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo		for (i = 0; i < host->n_ports; i++)
6673d8ec91352099b32a400f1952112dc076da28106Tejun Heo			writew(cls << 8 | cls,
6683d8ec91352099b32a400f1952112dc076da28106Tejun Heo			       mmio_base + sil_port[i].fifo_cfg);
6693d8ec91352099b32a400f1952112dc076da28106Tejun Heo	} else
6703d8ec91352099b32a400f1952112dc076da28106Tejun Heo		dev_printk(KERN_WARNING, &pdev->dev,
6713d8ec91352099b32a400f1952112dc076da28106Tejun Heo			   "cache line size not set.  Driver may not function\n");
6723d8ec91352099b32a400f1952112dc076da28106Tejun Heo
6733d8ec91352099b32a400f1952112dc076da28106Tejun Heo	/* Apply R_ERR on DMA activate FIS errata workaround */
6744447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	if (host->ports[0]->flags & SIL_FLAG_RERR_ON_DMA_ACT) {
6753d8ec91352099b32a400f1952112dc076da28106Tejun Heo		int cnt;
6763d8ec91352099b32a400f1952112dc076da28106Tejun Heo
6774447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo		for (i = 0, cnt = 0; i < host->n_ports; i++) {
6783d8ec91352099b32a400f1952112dc076da28106Tejun Heo			tmp = readl(mmio_base + sil_port[i].sfis_cfg);
6793d8ec91352099b32a400f1952112dc076da28106Tejun Heo			if ((tmp & 0x3) != 0x01)
6803d8ec91352099b32a400f1952112dc076da28106Tejun Heo				continue;
6813d8ec91352099b32a400f1952112dc076da28106Tejun Heo			if (!cnt)
6823d8ec91352099b32a400f1952112dc076da28106Tejun Heo				dev_printk(KERN_INFO, &pdev->dev,
6833d8ec91352099b32a400f1952112dc076da28106Tejun Heo					   "Applying R_ERR on DMA activate "
6843d8ec91352099b32a400f1952112dc076da28106Tejun Heo					   "FIS errata fix\n");
6853d8ec91352099b32a400f1952112dc076da28106Tejun Heo			writel(tmp & ~0x3, mmio_base + sil_port[i].sfis_cfg);
6863d8ec91352099b32a400f1952112dc076da28106Tejun Heo			cnt++;
6873d8ec91352099b32a400f1952112dc076da28106Tejun Heo		}
6883d8ec91352099b32a400f1952112dc076da28106Tejun Heo	}
6893d8ec91352099b32a400f1952112dc076da28106Tejun Heo
6904447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	if (host->n_ports == 4) {
6913d8ec91352099b32a400f1952112dc076da28106Tejun Heo		/* flip the magic "make 4 ports work" bit */
6923d8ec91352099b32a400f1952112dc076da28106Tejun Heo		tmp = readl(mmio_base + sil_port[2].bmdma);
6933d8ec91352099b32a400f1952112dc076da28106Tejun Heo		if ((tmp & SIL_INTR_STEERING) == 0)
6943d8ec91352099b32a400f1952112dc076da28106Tejun Heo			writel(tmp | SIL_INTR_STEERING,
6953d8ec91352099b32a400f1952112dc076da28106Tejun Heo			       mmio_base + sil_port[2].bmdma);
6963d8ec91352099b32a400f1952112dc076da28106Tejun Heo	}
6973d8ec91352099b32a400f1952112dc076da28106Tejun Heo}
6983d8ec91352099b32a400f1952112dc076da28106Tejun Heo
699e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysockistatic bool sil_broken_system_poweroff(struct pci_dev *pdev)
700e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki{
701e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki	static const struct dmi_system_id broken_systems[] = {
702e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki		{
703e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki			.ident = "HP Compaq nx6325",
704e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki			.matches = {
705e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki				DMI_MATCH(DMI_SYS_VENDOR, "Hewlett-Packard"),
706e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki				DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq nx6325"),
707e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki			},
708e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki			/* PCI slot number of the controller */
709e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki			.driver_data = (void *)0x12UL,
710e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki		},
711e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki
712e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki		{ }	/* terminate list */
713e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki	};
714e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki	const struct dmi_system_id *dmi = dmi_first_match(broken_systems);
715e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki
716e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki	if (dmi) {
717e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki		unsigned long slot = (unsigned long)dmi->driver_data;
718e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki		/* apply the quirk only to on-board controllers */
719e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki		return slot == PCI_SLOT(pdev->devfn);
720e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki	}
721e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki
722e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki	return false;
723e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki}
724e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki
7255796d1c4c89efff823259fda35b08ea66ebf8b23Jeff Garzikstatic int sil_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static int printed_version;
7284447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	int board_id = ent->driver_data;
729e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki	struct ata_port_info pi = sil_port_info[board_id];
730e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki	const struct ata_port_info *ppi[] = { &pi, NULL };
7314447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	struct ata_host *host;
732ea6ba10bbb88e106f9e2db7dc253993bb3bbbe3bJeff Garzik	void __iomem *mmio_base;
7334447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	int n_ports, rc;
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int i;
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!printed_version++)
737a9524a76f70f3343e4be27f95a7e92a8ba5f9009Jeff Garzik		dev_printk(KERN_DEBUG, &pdev->dev, "version " DRV_VERSION "\n");
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7394447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	/* allocate host */
7404447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	n_ports = 2;
7414447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	if (board_id == sil_3114)
7424447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo		n_ports = 4;
7434447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo
744e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki	if (sil_broken_system_poweroff(pdev)) {
745e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki		pi.flags |= ATA_FLAG_NO_POWEROFF_SPINDOWN |
746e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki					ATA_FLAG_NO_HIBERNATE_SPINDOWN;
747e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki		dev_info(&pdev->dev, "quirky BIOS, skipping spindown "
748e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki				"on poweroff and hibernation\n");
749e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki	}
750e57db7bde7bff95ae812736ca00c73bd5271455bRafael J. Wysocki
7514447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	host = ata_host_alloc_pinfo(&pdev->dev, ppi, n_ports);
7524447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	if (!host)
7534447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo		return -ENOMEM;
7544447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo
7554447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	/* acquire resources and fill host */
75624dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo	rc = pcim_enable_device(pdev);
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc)
7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return rc;
7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7600d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	rc = pcim_iomap_regions(pdev, 1 << SIL_MMIO_BAR, DRV_NAME);
7610d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	if (rc == -EBUSY)
76224dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo		pcim_pin_device(pdev);
7630d5ff566779f894ca9937231a181eb31e4adff0eTejun Heo	if (rc)
76424dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo		return rc;
7654447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	host->iomap = pcim_iomap_table(pdev);
7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc)
76924dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo		return rc;
7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (rc)
77224dc5f33ea4b504cfbd23fa159a4cacba8e4d800Tejun Heo		return rc;
7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7744447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	mmio_base = host->iomap[SIL_MMIO_BAR];
7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7764447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	for (i = 0; i < host->n_ports; i++) {
777cbcdd87593a1d85c5c4b259945a3a09eee12814dTejun Heo		struct ata_port *ap = host->ports[i];
778cbcdd87593a1d85c5c4b259945a3a09eee12814dTejun Heo		struct ata_ioports *ioaddr = &ap->ioaddr;
7794447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo
7804447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo		ioaddr->cmd_addr = mmio_base + sil_port[i].tf;
7814447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo		ioaddr->altstatus_addr =
7824447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo		ioaddr->ctl_addr = mmio_base + sil_port[i].ctl;
7834447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo		ioaddr->bmdma_addr = mmio_base + sil_port[i].bmdma;
7844447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo		ioaddr->scr_addr = mmio_base + sil_port[i].scr;
7859363c3825ea9ad76561eb48a395349dd29211ed6Tejun Heo		ata_sff_std_ports(ioaddr);
786cbcdd87593a1d85c5c4b259945a3a09eee12814dTejun Heo
787cbcdd87593a1d85c5c4b259945a3a09eee12814dTejun Heo		ata_port_pbar_desc(ap, SIL_MMIO_BAR, -1, "mmio");
788cbcdd87593a1d85c5c4b259945a3a09eee12814dTejun Heo		ata_port_pbar_desc(ap, SIL_MMIO_BAR, sil_port[i].tf, "tf");
7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7914447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	/* initialize and activate */
7924447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	sil_init_controller(host);
7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_set_master(pdev);
7954447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	return ata_host_activate(host, pdev->irq, sil_interrupt, IRQF_SHARED,
7964447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo				 &sil_sht);
7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
799281d426c7e64286f433645e27862e7744b1e9310Alexey Dobriyan#ifdef CONFIG_PM
800afb5a7cb84b1ea8b6045945e3d288303e6b71336Tejun Heostatic int sil_pci_device_resume(struct pci_dev *pdev)
801afb5a7cb84b1ea8b6045945e3d288303e6b71336Tejun Heo{
802cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	struct ata_host *host = dev_get_drvdata(&pdev->dev);
803553c4aa630af7bc885e056d0436e4eb7f238579bTejun Heo	int rc;
804553c4aa630af7bc885e056d0436e4eb7f238579bTejun Heo
805553c4aa630af7bc885e056d0436e4eb7f238579bTejun Heo	rc = ata_pci_device_do_resume(pdev);
806553c4aa630af7bc885e056d0436e4eb7f238579bTejun Heo	if (rc)
807553c4aa630af7bc885e056d0436e4eb7f238579bTejun Heo		return rc;
808afb5a7cb84b1ea8b6045945e3d288303e6b71336Tejun Heo
8094447d35156169cf136e829eb6b5cac2d6370f2d9Tejun Heo	sil_init_controller(host);
810cca3974e48607c3775dc73b544a5700b2e37c21aJeff Garzik	ata_host_resume(host);
811afb5a7cb84b1ea8b6045945e3d288303e6b71336Tejun Heo
812afb5a7cb84b1ea8b6045945e3d288303e6b71336Tejun Heo	return 0;
813afb5a7cb84b1ea8b6045945e3d288303e6b71336Tejun Heo}
814281d426c7e64286f433645e27862e7744b1e9310Alexey Dobriyan#endif
815afb5a7cb84b1ea8b6045945e3d288303e6b71336Tejun Heo
8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init sil_init(void)
8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
818b7887196e38da54ff893897b80875d632d1a1114Pavel Roskin	return pci_register_driver(&sil_pci_driver);
8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit sil_exit(void)
8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
8231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pci_unregister_driver(&sil_pci_driver);
8241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
8251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(sil_init);
8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(sil_exit);
829