Blame view

drivers/ata/pata_oldpiix.c 7.36 KB
669a5db41   Jeff Garzik   [libata] Add a bu...
1
2
3
  /*
   *    pata_oldpiix.c - Intel PATA/SATA controllers
   *
ab7716300   Alan Cox   ata: Switch all m...
4
   *	(C) 2005 Red Hat
669a5db41   Jeff Garzik   [libata] Add a bu...
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
   *
   *    Some parts based on ata_piix.c by Jeff Garzik and others.
   *
   *    Early PIIX differs significantly from the later PIIX as it lacks
   *    SITRE and the slave timing registers. This means that you have to
   *    set timing per channel, or be clever. Libata tells us whenever it
   *    does drive selection and we use this to reload the timings.
   *
   *    Because of these behaviour differences PIIX gets its own driver module.
   */
  
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/pci.h>
  #include <linux/init.h>
  #include <linux/blkdev.h>
  #include <linux/delay.h>
  #include <linux/device.h>
  #include <scsi/scsi_host.h>
  #include <linux/libata.h>
  #include <linux/ata.h>
  
  #define DRV_NAME	"pata_oldpiix"
a0fcdc025   Jeff Garzik   [libata] Update s...
28
  #define DRV_VERSION	"0.5.5"
669a5db41   Jeff Garzik   [libata] Add a bu...
29
30
31
  
  /**
   *	oldpiix_pre_reset		-	probe begin
cc0680a58   Tejun Heo   libata-link: link...
32
   *	@link: ATA link
d4b2bab4f   Tejun Heo   libata: add deadl...
33
   *	@deadline: deadline jiffies for the operation
669a5db41   Jeff Garzik   [libata] Add a bu...
34
35
36
   *
   *	Set up cable type and use generic probe init
   */
cc0680a58   Tejun Heo   libata-link: link...
37
  static int oldpiix_pre_reset(struct ata_link *link, unsigned long deadline)
669a5db41   Jeff Garzik   [libata] Add a bu...
38
  {
cc0680a58   Tejun Heo   libata-link: link...
39
  	struct ata_port *ap = link->ap;
669a5db41   Jeff Garzik   [libata] Add a bu...
40
41
42
43
44
  	struct pci_dev *pdev = to_pci_dev(ap->host->dev);
  	static const struct pci_bits oldpiix_enable_bits[] = {
  		{ 0x41U, 1U, 0x80UL, 0x80UL },	/* port 0 */
  		{ 0x43U, 1U, 0x80UL, 0x80UL },	/* port 1 */
  	};
c961922b7   Alan Cox   [PATCH] libata-eh...
45
46
  	if (!pci_test_config_bits(pdev, &oldpiix_enable_bits[ap->port_no]))
  		return -ENOENT;
d4b2bab4f   Tejun Heo   libata: add deadl...
47

9363c3825   Tejun Heo   libata: rename SF...
48
  	return ata_sff_prereset(link, deadline);
669a5db41   Jeff Garzik   [libata] Add a bu...
49
50
51
  }
  
  /**
669a5db41   Jeff Garzik   [libata] Add a bu...
52
53
   *	oldpiix_set_piomode - Initialize host controller PATA PIO timings
   *	@ap: Port whose timings we are configuring
a0fcdc025   Jeff Garzik   [libata] Update s...
54
   *	@adev: Device whose timings we are configuring
669a5db41   Jeff Garzik   [libata] Add a bu...
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
   *
   *	Set PIO mode for device, in host controller PCI config space.
   *
   *	LOCKING:
   *	None (inherited from caller).
   */
  
  static void oldpiix_set_piomode (struct ata_port *ap, struct ata_device *adev)
  {
  	unsigned int pio	= adev->pio_mode - XFER_PIO_0;
  	struct pci_dev *dev	= to_pci_dev(ap->host->dev);
  	unsigned int idetm_port= ap->port_no ? 0x42 : 0x40;
  	u16 idetm_data;
  	int control = 0;
  
  	/*
  	 *	See Intel Document 298600-004 for the timing programing rules
  	 *	for PIIX/ICH. Note that the early PIIX does not have the slave
  	 *	timing port at 0x44.
  	 */
  
  	static const	 /* ISP  RTC */
  	u8 timings[][2]	= { { 0, 0 },
  			    { 0, 0 },
  			    { 1, 0 },
  			    { 2, 1 },
  			    { 2, 3 }, };
409ba47c2   Sergei Shtylyov   (2.6.20) pata_old...
82
83
  	if (pio > 1)
  		control |= 1;	/* TIME */
669a5db41   Jeff Garzik   [libata] Add a bu...
84
  	if (ata_pio_need_iordy(adev))
409ba47c2   Sergei Shtylyov   (2.6.20) pata_old...
85
  		control |= 2;	/* IE */
669a5db41   Jeff Garzik   [libata] Add a bu...
86

409ba47c2   Sergei Shtylyov   (2.6.20) pata_old...
87
  	/* Intel specifies that the prefetch/posting is for disk only */
669a5db41   Jeff Garzik   [libata] Add a bu...
88
  	if (adev->class == ATA_DEV_ATA)
409ba47c2   Sergei Shtylyov   (2.6.20) pata_old...
89
  		control |= 4;	/* PPE */
669a5db41   Jeff Garzik   [libata] Add a bu...
90
91
  
  	pci_read_config_word(dev, idetm_port, &idetm_data);
409ba47c2   Sergei Shtylyov   (2.6.20) pata_old...
92
93
94
95
  	/*
  	 * Set PPE, IE and TIME as appropriate.
  	 * Clear the other drive's timing bits.
  	 */
669a5db41   Jeff Garzik   [libata] Add a bu...
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
  	if (adev->devno == 0) {
  		idetm_data &= 0xCCE0;
  		idetm_data |= control;
  	} else {
  		idetm_data &= 0xCC0E;
  		idetm_data |= (control << 4);
  	}
  	idetm_data |= (timings[pio][0] << 12) |
  			(timings[pio][1] << 8);
  	pci_write_config_word(dev, idetm_port, idetm_data);
  
  	/* Track which port is configured */
  	ap->private_data = adev;
  }
  
  /**
   *	oldpiix_set_dmamode - Initialize host controller PATA DMA timings
   *	@ap: Port whose timings we are configuring
   *	@adev: Device to program
669a5db41   Jeff Garzik   [libata] Add a bu...
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
   *
   *	Set MWDMA mode for device, in host controller PCI config space.
   *
   *	LOCKING:
   *	None (inherited from caller).
   */
  
  static void oldpiix_set_dmamode (struct ata_port *ap, struct ata_device *adev)
  {
  	struct pci_dev *dev	= to_pci_dev(ap->host->dev);
  	u8 idetm_port		= ap->port_no ? 0x42 : 0x40;
  	u16 idetm_data;
  
  	static const	 /* ISP  RTC */
  	u8 timings[][2]	= { { 0, 0 },
  			    { 0, 0 },
  			    { 1, 0 },
  			    { 2, 1 },
  			    { 2, 3 }, };
  
  	/*
  	 * MWDMA is driven by the PIO timings. We must also enable
  	 * IORDY unconditionally along with TIME1. PPE has already
  	 * been set when the PIO timing was set.
  	 */
  
  	unsigned int mwdma	= adev->dma_mode - XFER_MW_DMA_0;
  	unsigned int control;
  	const unsigned int needed_pio[3] = {
  		XFER_PIO_0, XFER_PIO_3, XFER_PIO_4
  	};
  	int pio = needed_pio[mwdma] - XFER_PIO_0;
  
  	pci_read_config_word(dev, idetm_port, &idetm_data);
  
  	control = 3;	/* IORDY|TIME0 */
  	/* Intel specifies that the PPE functionality is for disk only */
  	if (adev->class == ATA_DEV_ATA)
  		control |= 4;	/* PPE enable */
  
  	/* If the drive MWDMA is faster than it can do PIO then
  	   we must force PIO into PIO0 */
  
  	if (adev->pio_mode < needed_pio[mwdma])
  		/* Enable DMA timing only */
  		control |= 8;	/* PIO cycles in PIO0 */
  
  	/* Mask out the relevant control and timing bits we will load. Also
  	   clear the other drive TIME register as a precaution */
  	if (adev->devno == 0) {
  		idetm_data &= 0xCCE0;
  		idetm_data |= control;
  	} else {
  		idetm_data &= 0xCC0E;
  		idetm_data |= (control << 4);
  	}
  	idetm_data |= (timings[pio][0] << 12) | (timings[pio][1] << 8);
  	pci_write_config_word(dev, idetm_port, idetm_data);
  
  	/* Track which port is configured */
  	ap->private_data = adev;
  }
  
  /**
9363c3825   Tejun Heo   libata: rename SF...
179
   *	oldpiix_qc_issue	-	command issue
669a5db41   Jeff Garzik   [libata] Add a bu...
180
181
182
183
   *	@qc: command pending
   *
   *	Called when the libata layer is about to issue a command. We wrap
   *	this interface so that we can load the correct ATA timings if
3a4fa0a25   Robert P. J. Day   Fix misspellings ...
184
   *	necessary. Our logic also clears TIME0/TIME1 for the other device so
669a5db41   Jeff Garzik   [libata] Add a bu...
185
186
187
   *	that, even if we get this wrong, cycles to the other device will
   *	be made PIO0.
   */
9363c3825   Tejun Heo   libata: rename SF...
188
  static unsigned int oldpiix_qc_issue(struct ata_queued_cmd *qc)
669a5db41   Jeff Garzik   [libata] Add a bu...
189
190
191
192
193
  {
  	struct ata_port *ap = qc->ap;
  	struct ata_device *adev = qc->dev;
  
  	if (adev != ap->private_data) {
b7939b14d   Alan Cox   pata_oldpiix: Cal...
194
  		oldpiix_set_piomode(ap, adev);
b15b3ebae   Alan Cox   libata: Fix a lar...
195
  		if (ata_dma_enabled(adev))
669a5db41   Jeff Garzik   [libata] Add a bu...
196
  			oldpiix_set_dmamode(ap, adev);
669a5db41   Jeff Garzik   [libata] Add a bu...
197
  	}
360ff7833   Tejun Heo   libata-sff: separ...
198
  	return ata_bmdma_qc_issue(qc);
669a5db41   Jeff Garzik   [libata] Add a bu...
199
200
201
202
  }
  
  
  static struct scsi_host_template oldpiix_sht = {
68d1d07b5   Tejun Heo   libata: implement...
203
  	ATA_BMDMA_SHT(DRV_NAME),
669a5db41   Jeff Garzik   [libata] Add a bu...
204
  };
029cfd6b7   Tejun Heo   libata: implement...
205
206
  static struct ata_port_operations oldpiix_pata_ops = {
  	.inherits		= &ata_bmdma_port_ops,
9363c3825   Tejun Heo   libata: rename SF...
207
  	.qc_issue		= oldpiix_qc_issue,
029cfd6b7   Tejun Heo   libata: implement...
208
  	.cable_detect		= ata_cable_40wire,
669a5db41   Jeff Garzik   [libata] Add a bu...
209
210
  	.set_piomode		= oldpiix_set_piomode,
  	.set_dmamode		= oldpiix_set_dmamode,
a1efdaba2   Tejun Heo   libata: make rese...
211
  	.prereset		= oldpiix_pre_reset,
669a5db41   Jeff Garzik   [libata] Add a bu...
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
  };
  
  
  /**
   *	oldpiix_init_one - Register PIIX ATA PCI device with kernel services
   *	@pdev: PCI device to register
   *	@ent: Entry in oldpiix_pci_tbl matching with @pdev
   *
   *	Called from kernel PCI layer.  We probe for combined mode (sigh),
   *	and then hand over control to libata, for it to do the rest.
   *
   *	LOCKING:
   *	Inherited from PCI layer (may sleep).
   *
   *	RETURNS:
   *	Zero on success, or -ERRNO value.
   */
  
  static int oldpiix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
  {
1626aeb88   Tejun Heo   libata: clean up ...
232
  	static const struct ata_port_info info = {
1d2808fd3   Jeff Garzik   [libata] PATA dri...
233
  		.flags		= ATA_FLAG_SLAVE_POSS,
14bdef982   Erik Inge Bolsø   [libata] convert ...
234
  		.pio_mask	= ATA_PIO4,
82563232c   Bartlomiej Zolnierkiewicz   [libata] MWDMA0 i...
235
  		.mwdma_mask	= ATA_MWDMA12_ONLY,
669a5db41   Jeff Garzik   [libata] Add a bu...
236
237
  		.port_ops	= &oldpiix_pata_ops,
  	};
1626aeb88   Tejun Heo   libata: clean up ...
238
  	const struct ata_port_info *ppi[] = { &info, NULL };
669a5db41   Jeff Garzik   [libata] Add a bu...
239

06296a1e6   Joe Perches   ata: Add and use ...
240
  	ata_print_version_once(&pdev->dev, DRV_VERSION);
669a5db41   Jeff Garzik   [libata] Add a bu...
241

1c5afdf7a   Tejun Heo   libata-sff: separ...
242
  	return ata_pci_bmdma_init_one(pdev, ppi, &oldpiix_sht, NULL, 0);
669a5db41   Jeff Garzik   [libata] Add a bu...
243
244
245
  }
  
  static const struct pci_device_id oldpiix_pci_tbl[] = {
2d2744fc8   Jeff Garzik   [libata] PCI ID t...
246
  	{ PCI_VDEVICE(INTEL, 0x1230), },
669a5db41   Jeff Garzik   [libata] Add a bu...
247
248
249
250
251
252
253
254
  	{ }	/* terminate list */
  };
  
  static struct pci_driver oldpiix_pci_driver = {
  	.name			= DRV_NAME,
  	.id_table		= oldpiix_pci_tbl,
  	.probe			= oldpiix_init_one,
  	.remove			= ata_pci_remove_one,
438ac6d5e   Tejun Heo   libata: add missi...
255
  #ifdef CONFIG_PM
30ced0f0d   Alan Cox   [PATCH] PATA liba...
256
257
  	.suspend		= ata_pci_device_suspend,
  	.resume			= ata_pci_device_resume,
438ac6d5e   Tejun Heo   libata: add missi...
258
  #endif
669a5db41   Jeff Garzik   [libata] Add a bu...
259
260
261
262
263
264
265
266
267
268
269
  };
  
  static int __init oldpiix_init(void)
  {
  	return pci_register_driver(&oldpiix_pci_driver);
  }
  
  static void __exit oldpiix_exit(void)
  {
  	pci_unregister_driver(&oldpiix_pci_driver);
  }
669a5db41   Jeff Garzik   [libata] Add a bu...
270
271
272
273
274
275
276
277
  module_init(oldpiix_init);
  module_exit(oldpiix_exit);
  
  MODULE_AUTHOR("Alan Cox");
  MODULE_DESCRIPTION("SCSI low-level driver for early PIIX series controllers");
  MODULE_LICENSE("GPL");
  MODULE_DEVICE_TABLE(pci, oldpiix_pci_tbl);
  MODULE_VERSION(DRV_VERSION);