]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From b9d5b89b487517cbd4cb4702da829e07ef9e4432 Mon Sep 17 00:00:00 2001 |
2 | From: Tejun Heo <tj@kernel.org> | |
3 | Date: Wed, 22 Oct 2008 00:46:36 +0900 | |
4 | Subject: [PATCH] sata_via: fix support for 5287 | |
5 | References: bnc#441718 | |
6 | ||
7 | 5287 used to be treated as vt6420 but it didn't work. It's new family | |
8 | of controllers called vt8251 which hosts four SATA ports as M/S of the | |
9 | two ATA ports. This configuration is rather peculiar in that although | |
10 | the M/S devices are on the same port, each have its own SCR (or | |
11 | equivalent link status/control) registers which screws up the | |
12 | port-link-device hierarchy assumed by libata. Another controller | |
13 | which falls into this category is ata_piix w/ SIDPR access. | |
14 | ||
15 | libata now has facility to deal with this class of controllers named | |
16 | slave_link. A low level driver for such controllers can just call | |
17 | ata_slave_link_init() on the respective ports and libata will handle | |
18 | all the difficult parts like following up with single SRST after | |
19 | hardresetting both ports. | |
20 | ||
21 | This patch creates new controller class vt8251, implements slave_link | |
22 | aware init sequence and config space based SCR access for it and moves | |
23 | 5287 to the new class. | |
24 | ||
25 | This patch is based on Joseph Chan's larger patch which was created | |
26 | before slave_link was implemented in libata. | |
27 | ||
28 | http://thread.gmane.org/gmane.linux.kernel.commits.mm/40640 | |
29 | ||
30 | Signed-off-by: Tejun Heo <tj@kernel.org> | |
31 | Cc: Joseph Chan <JosephChan@via.com.tw> | |
32 | Signed-off-by: Jeff Garzik <jgarzik@redhat.com> | |
33 | Signed-off-by: Tejun Heo <teheo@suse.de> | |
34 | --- | |
35 | drivers/ata/sata_via.c | 155 ++++++++++++++++++++++++++++++++++++++++++++---- | |
36 | 1 files changed, 143 insertions(+), 12 deletions(-) | |
37 | ||
38 | diff --git a/drivers/ata/sata_via.c b/drivers/ata/sata_via.c | |
39 | index 5b72e73..62367fe 100644 | |
40 | --- a/drivers/ata/sata_via.c | |
41 | +++ b/drivers/ata/sata_via.c | |
42 | @@ -44,11 +44,16 @@ | |
43 | #include <linux/libata.h> | |
44 | ||
45 | #define DRV_NAME "sata_via" | |
46 | -#define DRV_VERSION "2.3" | |
47 | +#define DRV_VERSION "2.4" | |
48 | ||
49 | +/* | |
50 | + * vt8251 is different from other sata controllers of VIA. It has two | |
51 | + * channels, each channel has both Master and Slave slot. | |
52 | + */ | |
53 | enum board_ids_enum { | |
54 | vt6420, | |
55 | vt6421, | |
56 | + vt8251, | |
57 | }; | |
58 | ||
59 | enum { | |
60 | @@ -70,6 +75,8 @@ enum { | |
61 | static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent); | |
62 | static int svia_scr_read(struct ata_link *link, unsigned int sc_reg, u32 *val); | |
63 | static int svia_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val); | |
64 | +static int vt8251_scr_read(struct ata_link *link, unsigned int scr, u32 *val); | |
65 | +static int vt8251_scr_write(struct ata_link *link, unsigned int scr, u32 val); | |
66 | static void svia_tf_load(struct ata_port *ap, const struct ata_taskfile *tf); | |
67 | static void svia_noop_freeze(struct ata_port *ap); | |
68 | static int vt6420_prereset(struct ata_link *link, unsigned long deadline); | |
69 | @@ -79,12 +86,12 @@ static void vt6421_set_dma_mode(struct ata_port *ap, struct ata_device *adev); | |
70 | ||
71 | static const struct pci_device_id svia_pci_tbl[] = { | |
72 | { PCI_VDEVICE(VIA, 0x5337), vt6420 }, | |
73 | - { PCI_VDEVICE(VIA, 0x0591), vt6420 }, | |
74 | - { PCI_VDEVICE(VIA, 0x3149), vt6420 }, | |
75 | - { PCI_VDEVICE(VIA, 0x3249), vt6421 }, | |
76 | - { PCI_VDEVICE(VIA, 0x5287), vt6420 }, | |
77 | + { PCI_VDEVICE(VIA, 0x0591), vt6420 }, /* 2 sata chnls (Master) */ | |
78 | + { PCI_VDEVICE(VIA, 0x3149), vt6420 }, /* 2 sata chnls (Master) */ | |
79 | + { PCI_VDEVICE(VIA, 0x3249), vt6421 }, /* 2 sata chnls, 1 pata chnl */ | |
80 | { PCI_VDEVICE(VIA, 0x5372), vt6420 }, | |
81 | { PCI_VDEVICE(VIA, 0x7372), vt6420 }, | |
82 | + { PCI_VDEVICE(VIA, 0x5287), vt8251 }, /* 2 sata chnls (Master/Slave) */ | |
83 | ||
84 | { } /* terminate list */ | |
85 | }; | |
86 | @@ -128,6 +135,13 @@ static struct ata_port_operations vt6421_sata_ops = { | |
87 | .scr_write = svia_scr_write, | |
88 | }; | |
89 | ||
90 | +static struct ata_port_operations vt8251_ops = { | |
91 | + .inherits = &svia_base_ops, | |
92 | + .hardreset = sata_std_hardreset, | |
93 | + .scr_read = vt8251_scr_read, | |
94 | + .scr_write = vt8251_scr_write, | |
95 | +}; | |
96 | + | |
97 | static const struct ata_port_info vt6420_port_info = { | |
98 | .flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, | |
99 | .pio_mask = 0x1f, | |
100 | @@ -152,6 +166,15 @@ static struct ata_port_info vt6421_pport_info = { | |
101 | .port_ops = &vt6421_pata_ops, | |
102 | }; | |
103 | ||
104 | +static struct ata_port_info vt8251_port_info = { | |
105 | + .flags = ATA_FLAG_SATA | ATA_FLAG_SLAVE_POSS | | |
106 | + ATA_FLAG_NO_LEGACY, | |
107 | + .pio_mask = 0x1f, | |
108 | + .mwdma_mask = 0x07, | |
109 | + .udma_mask = ATA_UDMA6, | |
110 | + .port_ops = &vt8251_ops, | |
111 | +}; | |
112 | + | |
113 | MODULE_AUTHOR("Jeff Garzik"); | |
114 | MODULE_DESCRIPTION("SCSI low-level driver for VIA SATA controllers"); | |
115 | MODULE_LICENSE("GPL"); | |
116 | @@ -174,6 +197,83 @@ static int svia_scr_write(struct ata_link *link, unsigned int sc_reg, u32 val) | |
117 | return 0; | |
118 | } | |
119 | ||
120 | +static int vt8251_scr_read(struct ata_link *link, unsigned int scr, u32 *val) | |
121 | +{ | |
122 | + static const u8 ipm_tbl[] = { 1, 2, 6, 0 }; | |
123 | + struct pci_dev *pdev = to_pci_dev(link->ap->host->dev); | |
124 | + int slot = 2 * link->ap->port_no + link->pmp; | |
125 | + u32 v = 0; | |
126 | + u8 raw; | |
127 | + | |
128 | + switch (scr) { | |
129 | + case SCR_STATUS: | |
130 | + pci_read_config_byte(pdev, 0xA0 + slot, &raw); | |
131 | + | |
132 | + /* read the DET field, bit0 and 1 of the config byte */ | |
133 | + v |= raw & 0x03; | |
134 | + | |
135 | + /* read the SPD field, bit4 of the configure byte */ | |
136 | + if (raw & (1 << 4)) | |
137 | + v |= 0x02 << 4; | |
138 | + else | |
139 | + v |= 0x01 << 4; | |
140 | + | |
141 | + /* read the IPM field, bit2 and 3 of the config byte */ | |
142 | + v |= ipm_tbl[(raw >> 2) & 0x3]; | |
143 | + break; | |
144 | + | |
145 | + case SCR_ERROR: | |
146 | + /* devices other than 5287 uses 0xA8 as base */ | |
147 | + WARN_ON(pdev->device != 0x5287); | |
148 | + pci_read_config_dword(pdev, 0xB0 + slot * 4, &v); | |
149 | + break; | |
150 | + | |
151 | + case SCR_CONTROL: | |
152 | + pci_read_config_byte(pdev, 0xA4 + slot, &raw); | |
153 | + | |
154 | + /* read the DET field, bit0 and bit1 */ | |
155 | + v |= ((raw & 0x02) << 1) | (raw & 0x01); | |
156 | + | |
157 | + /* read the IPM field, bit2 and bit3 */ | |
158 | + v |= ((raw >> 2) & 0x03) << 8; | |
159 | + break; | |
160 | + | |
161 | + default: | |
162 | + return -EINVAL; | |
163 | + } | |
164 | + | |
165 | + *val = v; | |
166 | + return 0; | |
167 | +} | |
168 | + | |
169 | +static int vt8251_scr_write(struct ata_link *link, unsigned int scr, u32 val) | |
170 | +{ | |
171 | + struct pci_dev *pdev = to_pci_dev(link->ap->host->dev); | |
172 | + int slot = 2 * link->ap->port_no + link->pmp; | |
173 | + u32 v = 0; | |
174 | + | |
175 | + switch (scr) { | |
176 | + case SCR_ERROR: | |
177 | + /* devices other than 5287 uses 0xA8 as base */ | |
178 | + WARN_ON(pdev->device != 0x5287); | |
179 | + pci_write_config_dword(pdev, 0xB0 + slot * 4, val); | |
180 | + return 0; | |
181 | + | |
182 | + case SCR_CONTROL: | |
183 | + /* set the DET field */ | |
184 | + v |= ((val & 0x4) >> 1) | (val & 0x1); | |
185 | + | |
186 | + /* set the IPM field */ | |
187 | + v |= ((val >> 8) & 0x3) << 2; | |
188 | + | |
189 | + pci_write_config_byte(pdev, 0xA4 + slot, v); | |
190 | + return 0; | |
191 | + | |
192 | + default: | |
193 | + return -EINVAL; | |
194 | + } | |
195 | +} | |
196 | + | |
197 | /** | |
198 | * svia_tf_load - send taskfile registers to host controller | |
199 | * @ap: Port to which output is sent | |
200 | @@ -396,6 +496,30 @@ static int vt6421_prepare_host(struct pci_dev *pdev, struct ata_host **r_host) | |
201 | return 0; | |
202 | } | |
203 | ||
204 | +static int vt8251_prepare_host(struct pci_dev *pdev, struct ata_host **r_host) | |
205 | +{ | |
206 | + const struct ata_port_info *ppi[] = { &vt8251_port_info, NULL }; | |
207 | + struct ata_host *host; | |
208 | + int i, rc; | |
209 | + | |
210 | + rc = ata_pci_sff_prepare_host(pdev, ppi, &host); | |
211 | + if (rc) | |
212 | + return rc; | |
213 | + *r_host = host; | |
214 | + | |
215 | + rc = pcim_iomap_regions(pdev, 1 << 5, DRV_NAME); | |
216 | + if (rc) { | |
217 | + dev_printk(KERN_ERR, &pdev->dev, "failed to iomap PCI BAR 5\n"); | |
218 | + return rc; | |
219 | + } | |
220 | + | |
221 | + /* 8251 hosts four sata ports as M/S of the two channels */ | |
222 | + for (i = 0; i < host->n_ports; i++) | |
223 | + ata_slave_link_init(host->ports[i]); | |
224 | + | |
225 | + return 0; | |
226 | +} | |
227 | + | |
228 | static void svia_configure(struct pci_dev *pdev) | |
229 | { | |
230 | u8 tmp8; | |
231 | @@ -451,10 +575,10 @@ static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |
232 | if (rc) | |
233 | return rc; | |
234 | ||
235 | - if (board_id == vt6420) | |
236 | - bar_sizes = &svia_bar_sizes[0]; | |
237 | - else | |
238 | + if (board_id == vt6421) | |
239 | bar_sizes = &vt6421_bar_sizes[0]; | |
240 | + else | |
241 | + bar_sizes = &svia_bar_sizes[0]; | |
242 | ||
243 | for (i = 0; i < ARRAY_SIZE(svia_bar_sizes); i++) | |
244 | if ((pci_resource_start(pdev, i) == 0) || | |
245 | @@ -467,12 +591,19 @@ static int svia_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) | |
246 | return -ENODEV; | |
247 | } | |
248 | ||
249 | - if (board_id == vt6420) | |
250 | + switch (board_id) { | |
251 | + case vt6420: | |
252 | rc = vt6420_prepare_host(pdev, &host); | |
253 | - else | |
254 | + break; | |
255 | + case vt6421: | |
256 | rc = vt6421_prepare_host(pdev, &host); | |
257 | - if (rc) | |
258 | - return rc; | |
259 | + break; | |
260 | + case vt8251: | |
261 | + rc = vt8251_prepare_host(pdev, &host); | |
262 | + break; | |
263 | + default: | |
264 | + return -EINVAL; | |
265 | + } | |
266 | ||
267 | svia_configure(pdev); | |
268 | ||
269 | -- | |
270 | 1.5.4.5 | |
271 |