diff options
-rw-r--r-- | drivers/scsi/sata_sis.c | 82 |
1 files changed, 71 insertions, 11 deletions
diff --git a/drivers/scsi/sata_sis.c b/drivers/scsi/sata_sis.c index 43af445b3ad2..7d1aaa99aaae 100644 --- a/drivers/scsi/sata_sis.c +++ b/drivers/scsi/sata_sis.c | |||
@@ -52,7 +52,10 @@ enum { | |||
52 | /* PCI configuration registers */ | 52 | /* PCI configuration registers */ |
53 | SIS_GENCTL = 0x54, /* IDE General Control register */ | 53 | SIS_GENCTL = 0x54, /* IDE General Control register */ |
54 | SIS_SCR_BASE = 0xc0, /* sata0 phy SCR registers */ | 54 | SIS_SCR_BASE = 0xc0, /* sata0 phy SCR registers */ |
55 | SIS_SATA1_OFS = 0x10, /* offset from sata0->sata1 phy regs */ | 55 | SIS180_SATA1_OFS = 0x10, /* offset from sata0->sata1 phy regs */ |
56 | SIS182_SATA1_OFS = 0x20, /* offset from sata0->sata1 phy regs */ | ||
57 | SIS_PMR = 0x90, /* port mapping register */ | ||
58 | SIS_PMR_COMBINED = 0x30, | ||
56 | 59 | ||
57 | /* random bits */ | 60 | /* random bits */ |
58 | SIS_FLAG_CFGSCR = (1 << 30), /* host flag: SCRs via PCI cfg */ | 61 | SIS_FLAG_CFGSCR = (1 << 30), /* host flag: SCRs via PCI cfg */ |
@@ -67,6 +70,7 @@ static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); | |||
67 | static struct pci_device_id sis_pci_tbl[] = { | 70 | static struct pci_device_id sis_pci_tbl[] = { |
68 | { PCI_VENDOR_ID_SI, 0x180, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 }, | 71 | { PCI_VENDOR_ID_SI, 0x180, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 }, |
69 | { PCI_VENDOR_ID_SI, 0x181, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 }, | 72 | { PCI_VENDOR_ID_SI, 0x181, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 }, |
73 | { PCI_VENDOR_ID_SI, 0x182, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 }, | ||
70 | { } /* terminate list */ | 74 | { } /* terminate list */ |
71 | }; | 75 | }; |
72 | 76 | ||
@@ -139,56 +143,94 @@ MODULE_LICENSE("GPL"); | |||
139 | MODULE_DEVICE_TABLE(pci, sis_pci_tbl); | 143 | MODULE_DEVICE_TABLE(pci, sis_pci_tbl); |
140 | MODULE_VERSION(DRV_VERSION); | 144 | MODULE_VERSION(DRV_VERSION); |
141 | 145 | ||
142 | static unsigned int get_scr_cfg_addr(unsigned int port_no, unsigned int sc_reg) | 146 | static unsigned int get_scr_cfg_addr(unsigned int port_no, unsigned int sc_reg, int device) |
143 | { | 147 | { |
144 | unsigned int addr = SIS_SCR_BASE + (4 * sc_reg); | 148 | unsigned int addr = SIS_SCR_BASE + (4 * sc_reg); |
145 | 149 | ||
146 | if (port_no) | 150 | if (port_no) |
147 | addr += SIS_SATA1_OFS; | 151 | if (device == 0x182) |
152 | addr += SIS182_SATA1_OFS; | ||
153 | else | ||
154 | addr += SIS180_SATA1_OFS; | ||
148 | return addr; | 155 | return addr; |
149 | } | 156 | } |
150 | 157 | ||
151 | static u32 sis_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg) | 158 | static u32 sis_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg) |
152 | { | 159 | { |
153 | struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); | 160 | struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); |
154 | unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, sc_reg); | 161 | unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, sc_reg, pdev->device); |
155 | u32 val; | 162 | u32 val, val2; |
163 | u8 pmr; | ||
156 | 164 | ||
157 | if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */ | 165 | if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */ |
158 | return 0xffffffff; | 166 | return 0xffffffff; |
167 | |||
168 | pci_read_config_byte(pdev, SIS_PMR, &pmr); | ||
169 | |||
159 | pci_read_config_dword(pdev, cfg_addr, &val); | 170 | pci_read_config_dword(pdev, cfg_addr, &val); |
160 | return val; | 171 | |
172 | if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED)) | ||
173 | pci_read_config_dword(pdev, cfg_addr+0x10, &val2); | ||
174 | |||
175 | return val|val2; | ||
161 | } | 176 | } |
162 | 177 | ||
163 | static void sis_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val) | 178 | static void sis_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val) |
164 | { | 179 | { |
165 | struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); | 180 | struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); |
166 | unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, scr); | 181 | unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, scr, pdev->device); |
182 | u8 pmr; | ||
167 | 183 | ||
168 | if (scr == SCR_ERROR) /* doesn't exist in PCI cfg space */ | 184 | if (scr == SCR_ERROR) /* doesn't exist in PCI cfg space */ |
169 | return; | 185 | return; |
186 | |||
187 | pci_read_config_byte(pdev, SIS_PMR, &pmr); | ||
188 | |||
170 | pci_write_config_dword(pdev, cfg_addr, val); | 189 | pci_write_config_dword(pdev, cfg_addr, val); |
190 | |||
191 | if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED)) | ||
192 | pci_write_config_dword(pdev, cfg_addr+0x10, val); | ||
171 | } | 193 | } |
172 | 194 | ||
173 | static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg) | 195 | static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg) |
174 | { | 196 | { |
197 | struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); | ||
198 | u32 val,val2; | ||
199 | u8 pmr; | ||
200 | |||
175 | if (sc_reg > SCR_CONTROL) | 201 | if (sc_reg > SCR_CONTROL) |
176 | return 0xffffffffU; | 202 | return 0xffffffffU; |
177 | 203 | ||
178 | if (ap->flags & SIS_FLAG_CFGSCR) | 204 | if (ap->flags & SIS_FLAG_CFGSCR) |
179 | return sis_scr_cfg_read(ap, sc_reg); | 205 | return sis_scr_cfg_read(ap, sc_reg); |
180 | return inl(ap->ioaddr.scr_addr + (sc_reg * 4)); | 206 | |
207 | pci_read_config_byte(pdev, SIS_PMR, &pmr); | ||
208 | |||
209 | val = inl(ap->ioaddr.scr_addr + (sc_reg * 4)); | ||
210 | |||
211 | if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED)) | ||
212 | val2 = inl(ap->ioaddr.scr_addr + (sc_reg * 4)+0x10); | ||
213 | |||
214 | return val|val2; | ||
181 | } | 215 | } |
182 | 216 | ||
183 | static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) | 217 | static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) |
184 | { | 218 | { |
219 | struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); | ||
220 | u8 pmr; | ||
221 | |||
185 | if (sc_reg > SCR_CONTROL) | 222 | if (sc_reg > SCR_CONTROL) |
186 | return; | 223 | return; |
187 | 224 | ||
225 | pci_read_config_byte(pdev, SIS_PMR, &pmr); | ||
226 | |||
188 | if (ap->flags & SIS_FLAG_CFGSCR) | 227 | if (ap->flags & SIS_FLAG_CFGSCR) |
189 | sis_scr_cfg_write(ap, sc_reg, val); | 228 | sis_scr_cfg_write(ap, sc_reg, val); |
190 | else | 229 | else { |
191 | outl(val, ap->ioaddr.scr_addr + (sc_reg * 4)); | 230 | outl(val, ap->ioaddr.scr_addr + (sc_reg * 4)); |
231 | if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED)) | ||
232 | outl(val, ap->ioaddr.scr_addr + (sc_reg * 4)+0x10); | ||
233 | } | ||
192 | } | 234 | } |
193 | 235 | ||
194 | /* move to PCI layer, integrate w/ MSI stuff */ | 236 | /* move to PCI layer, integrate w/ MSI stuff */ |
@@ -210,6 +252,8 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) | |||
210 | u32 genctl; | 252 | u32 genctl; |
211 | struct ata_port_info *ppi; | 253 | struct ata_port_info *ppi; |
212 | int pci_dev_busy = 0; | 254 | int pci_dev_busy = 0; |
255 | u8 pmr; | ||
256 | u8 port2_start; | ||
213 | 257 | ||
214 | rc = pci_enable_device(pdev); | 258 | rc = pci_enable_device(pdev); |
215 | if (rc) | 259 | if (rc) |
@@ -251,11 +295,27 @@ static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) | |||
251 | probe_ent->host_flags |= SIS_FLAG_CFGSCR; | 295 | probe_ent->host_flags |= SIS_FLAG_CFGSCR; |
252 | } | 296 | } |
253 | 297 | ||
298 | pci_read_config_byte(pdev, SIS_PMR, &pmr); | ||
299 | if (ent->device != 0x182) { | ||
300 | if ((pmr & SIS_PMR_COMBINED) == 0) { | ||
301 | printk(KERN_INFO "sata_sis: Detected SiS 180/181 chipset in SATA mode\n"); | ||
302 | port2_start=0x64; | ||
303 | } | ||
304 | else { | ||
305 | printk(KERN_INFO "sata_sis: Detected SiS 180/181 chipset in combined mode\n"); | ||
306 | port2_start=0; | ||
307 | } | ||
308 | } | ||
309 | else { | ||
310 | printk(KERN_INFO "sata_sis: Detected SiS 182 chipset\n"); | ||
311 | port2_start = 0x20; | ||
312 | } | ||
313 | |||
254 | if (!(probe_ent->host_flags & SIS_FLAG_CFGSCR)) { | 314 | if (!(probe_ent->host_flags & SIS_FLAG_CFGSCR)) { |
255 | probe_ent->port[0].scr_addr = | 315 | probe_ent->port[0].scr_addr = |
256 | pci_resource_start(pdev, SIS_SCR_PCI_BAR); | 316 | pci_resource_start(pdev, SIS_SCR_PCI_BAR); |
257 | probe_ent->port[1].scr_addr = | 317 | probe_ent->port[1].scr_addr = |
258 | pci_resource_start(pdev, SIS_SCR_PCI_BAR) + 64; | 318 | pci_resource_start(pdev, SIS_SCR_PCI_BAR) + port2_start; |
259 | } | 319 | } |
260 | 320 | ||
261 | pci_set_master(pdev); | 321 | pci_set_master(pdev); |