diff options
Diffstat (limited to 'drivers/scsi/sata_nv.c')
-rw-r--r-- | drivers/scsi/sata_nv.c | 535 |
1 files changed, 285 insertions, 250 deletions
diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c index 9f553081b5e8..d18e7e0932ef 100644 --- a/drivers/scsi/sata_nv.c +++ b/drivers/scsi/sata_nv.c | |||
@@ -44,7 +44,7 @@ | |||
44 | #include <linux/libata.h> | 44 | #include <linux/libata.h> |
45 | 45 | ||
46 | #define DRV_NAME "sata_nv" | 46 | #define DRV_NAME "sata_nv" |
47 | #define DRV_VERSION "0.8" | 47 | #define DRV_VERSION "0.9" |
48 | 48 | ||
49 | enum { | 49 | enum { |
50 | NV_PORTS = 2, | 50 | NV_PORTS = 2, |
@@ -54,40 +54,25 @@ enum { | |||
54 | NV_PORT0_SCR_REG_OFFSET = 0x00, | 54 | NV_PORT0_SCR_REG_OFFSET = 0x00, |
55 | NV_PORT1_SCR_REG_OFFSET = 0x40, | 55 | NV_PORT1_SCR_REG_OFFSET = 0x40, |
56 | 56 | ||
57 | /* INT_STATUS/ENABLE */ | ||
57 | NV_INT_STATUS = 0x10, | 58 | NV_INT_STATUS = 0x10, |
58 | NV_INT_STATUS_CK804 = 0x440, | ||
59 | NV_INT_STATUS_PDEV_INT = 0x01, | ||
60 | NV_INT_STATUS_PDEV_PM = 0x02, | ||
61 | NV_INT_STATUS_PDEV_ADDED = 0x04, | ||
62 | NV_INT_STATUS_PDEV_REMOVED = 0x08, | ||
63 | NV_INT_STATUS_SDEV_INT = 0x10, | ||
64 | NV_INT_STATUS_SDEV_PM = 0x20, | ||
65 | NV_INT_STATUS_SDEV_ADDED = 0x40, | ||
66 | NV_INT_STATUS_SDEV_REMOVED = 0x80, | ||
67 | NV_INT_STATUS_PDEV_HOTPLUG = (NV_INT_STATUS_PDEV_ADDED | | ||
68 | NV_INT_STATUS_PDEV_REMOVED), | ||
69 | NV_INT_STATUS_SDEV_HOTPLUG = (NV_INT_STATUS_SDEV_ADDED | | ||
70 | NV_INT_STATUS_SDEV_REMOVED), | ||
71 | NV_INT_STATUS_HOTPLUG = (NV_INT_STATUS_PDEV_HOTPLUG | | ||
72 | NV_INT_STATUS_SDEV_HOTPLUG), | ||
73 | |||
74 | NV_INT_ENABLE = 0x11, | 59 | NV_INT_ENABLE = 0x11, |
60 | NV_INT_STATUS_CK804 = 0x440, | ||
75 | NV_INT_ENABLE_CK804 = 0x441, | 61 | NV_INT_ENABLE_CK804 = 0x441, |
76 | NV_INT_ENABLE_PDEV_MASK = 0x01, | ||
77 | NV_INT_ENABLE_PDEV_PM = 0x02, | ||
78 | NV_INT_ENABLE_PDEV_ADDED = 0x04, | ||
79 | NV_INT_ENABLE_PDEV_REMOVED = 0x08, | ||
80 | NV_INT_ENABLE_SDEV_MASK = 0x10, | ||
81 | NV_INT_ENABLE_SDEV_PM = 0x20, | ||
82 | NV_INT_ENABLE_SDEV_ADDED = 0x40, | ||
83 | NV_INT_ENABLE_SDEV_REMOVED = 0x80, | ||
84 | NV_INT_ENABLE_PDEV_HOTPLUG = (NV_INT_ENABLE_PDEV_ADDED | | ||
85 | NV_INT_ENABLE_PDEV_REMOVED), | ||
86 | NV_INT_ENABLE_SDEV_HOTPLUG = (NV_INT_ENABLE_SDEV_ADDED | | ||
87 | NV_INT_ENABLE_SDEV_REMOVED), | ||
88 | NV_INT_ENABLE_HOTPLUG = (NV_INT_ENABLE_PDEV_HOTPLUG | | ||
89 | NV_INT_ENABLE_SDEV_HOTPLUG), | ||
90 | 62 | ||
63 | /* INT_STATUS/ENABLE bits */ | ||
64 | NV_INT_DEV = 0x01, | ||
65 | NV_INT_PM = 0x02, | ||
66 | NV_INT_ADDED = 0x04, | ||
67 | NV_INT_REMOVED = 0x08, | ||
68 | |||
69 | NV_INT_PORT_SHIFT = 4, /* each port occupies 4 bits */ | ||
70 | |||
71 | NV_INT_ALL = 0x0f, | ||
72 | NV_INT_MASK = NV_INT_DEV | | ||
73 | NV_INT_ADDED | NV_INT_REMOVED, | ||
74 | |||
75 | /* INT_CONFIG */ | ||
91 | NV_INT_CONFIG = 0x12, | 76 | NV_INT_CONFIG = 0x12, |
92 | NV_INT_CONFIG_METHD = 0x01, // 0 = INT, 1 = SMI | 77 | NV_INT_CONFIG_METHD = 0x01, // 0 = INT, 1 = SMI |
93 | 78 | ||
@@ -97,23 +82,27 @@ enum { | |||
97 | }; | 82 | }; |
98 | 83 | ||
99 | static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); | 84 | static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); |
100 | static irqreturn_t nv_interrupt (int irq, void *dev_instance, | 85 | static void nv_ck804_host_stop(struct ata_host_set *host_set); |
101 | struct pt_regs *regs); | 86 | static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance, |
87 | struct pt_regs *regs); | ||
88 | static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance, | ||
89 | struct pt_regs *regs); | ||
90 | static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance, | ||
91 | struct pt_regs *regs); | ||
102 | static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg); | 92 | static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg); |
103 | static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); | 93 | static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); |
104 | static void nv_host_stop (struct ata_host_set *host_set); | 94 | |
105 | static void nv_enable_hotplug(struct ata_probe_ent *probe_ent); | 95 | static void nv_nf2_freeze(struct ata_port *ap); |
106 | static void nv_disable_hotplug(struct ata_host_set *host_set); | 96 | static void nv_nf2_thaw(struct ata_port *ap); |
107 | static int nv_check_hotplug(struct ata_host_set *host_set); | 97 | static void nv_ck804_freeze(struct ata_port *ap); |
108 | static void nv_enable_hotplug_ck804(struct ata_probe_ent *probe_ent); | 98 | static void nv_ck804_thaw(struct ata_port *ap); |
109 | static void nv_disable_hotplug_ck804(struct ata_host_set *host_set); | 99 | static void nv_error_handler(struct ata_port *ap); |
110 | static int nv_check_hotplug_ck804(struct ata_host_set *host_set); | ||
111 | 100 | ||
112 | enum nv_host_type | 101 | enum nv_host_type |
113 | { | 102 | { |
114 | GENERIC, | 103 | GENERIC, |
115 | NFORCE2, | 104 | NFORCE2, |
116 | NFORCE3, | 105 | NFORCE3 = NFORCE2, /* NF2 == NF3 as far as sata_nv is concerned */ |
117 | CK804 | 106 | CK804 |
118 | }; | 107 | }; |
119 | 108 | ||
@@ -140,6 +129,16 @@ static const struct pci_device_id nv_pci_tbl[] = { | |||
140 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC }, | 129 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC }, |
141 | { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2, | 130 | { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2, |
142 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC }, | 131 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC }, |
132 | { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA, | ||
133 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC }, | ||
134 | { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA2, | ||
135 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC }, | ||
136 | { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP61_SATA3, | ||
137 | PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC }, | ||
138 | { PCI_VENDOR_ID_NVIDIA, 0x045c, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC }, | ||
139 | { PCI_VENDOR_ID_NVIDIA, 0x045d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC }, | ||
140 | { PCI_VENDOR_ID_NVIDIA, 0x045e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC }, | ||
141 | { PCI_VENDOR_ID_NVIDIA, 0x045f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC }, | ||
143 | { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, | 142 | { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, |
144 | PCI_ANY_ID, PCI_ANY_ID, | 143 | PCI_ANY_ID, PCI_ANY_ID, |
145 | PCI_CLASS_STORAGE_IDE<<8, 0xffff00, GENERIC }, | 144 | PCI_CLASS_STORAGE_IDE<<8, 0xffff00, GENERIC }, |
@@ -149,46 +148,6 @@ static const struct pci_device_id nv_pci_tbl[] = { | |||
149 | { 0, } /* terminate list */ | 148 | { 0, } /* terminate list */ |
150 | }; | 149 | }; |
151 | 150 | ||
152 | struct nv_host_desc | ||
153 | { | ||
154 | enum nv_host_type host_type; | ||
155 | void (*enable_hotplug)(struct ata_probe_ent *probe_ent); | ||
156 | void (*disable_hotplug)(struct ata_host_set *host_set); | ||
157 | int (*check_hotplug)(struct ata_host_set *host_set); | ||
158 | |||
159 | }; | ||
160 | static struct nv_host_desc nv_device_tbl[] = { | ||
161 | { | ||
162 | .host_type = GENERIC, | ||
163 | .enable_hotplug = NULL, | ||
164 | .disable_hotplug= NULL, | ||
165 | .check_hotplug = NULL, | ||
166 | }, | ||
167 | { | ||
168 | .host_type = NFORCE2, | ||
169 | .enable_hotplug = nv_enable_hotplug, | ||
170 | .disable_hotplug= nv_disable_hotplug, | ||
171 | .check_hotplug = nv_check_hotplug, | ||
172 | }, | ||
173 | { | ||
174 | .host_type = NFORCE3, | ||
175 | .enable_hotplug = nv_enable_hotplug, | ||
176 | .disable_hotplug= nv_disable_hotplug, | ||
177 | .check_hotplug = nv_check_hotplug, | ||
178 | }, | ||
179 | { .host_type = CK804, | ||
180 | .enable_hotplug = nv_enable_hotplug_ck804, | ||
181 | .disable_hotplug= nv_disable_hotplug_ck804, | ||
182 | .check_hotplug = nv_check_hotplug_ck804, | ||
183 | }, | ||
184 | }; | ||
185 | |||
186 | struct nv_host | ||
187 | { | ||
188 | struct nv_host_desc *host_desc; | ||
189 | unsigned long host_flags; | ||
190 | }; | ||
191 | |||
192 | static struct pci_driver nv_pci_driver = { | 151 | static struct pci_driver nv_pci_driver = { |
193 | .name = DRV_NAME, | 152 | .name = DRV_NAME, |
194 | .id_table = nv_pci_tbl, | 153 | .id_table = nv_pci_tbl, |
@@ -210,51 +169,119 @@ static struct scsi_host_template nv_sht = { | |||
210 | .proc_name = DRV_NAME, | 169 | .proc_name = DRV_NAME, |
211 | .dma_boundary = ATA_DMA_BOUNDARY, | 170 | .dma_boundary = ATA_DMA_BOUNDARY, |
212 | .slave_configure = ata_scsi_slave_config, | 171 | .slave_configure = ata_scsi_slave_config, |
172 | .slave_destroy = ata_scsi_slave_destroy, | ||
213 | .bios_param = ata_std_bios_param, | 173 | .bios_param = ata_std_bios_param, |
214 | }; | 174 | }; |
215 | 175 | ||
216 | static const struct ata_port_operations nv_ops = { | 176 | static const struct ata_port_operations nv_generic_ops = { |
217 | .port_disable = ata_port_disable, | 177 | .port_disable = ata_port_disable, |
218 | .tf_load = ata_tf_load, | 178 | .tf_load = ata_tf_load, |
219 | .tf_read = ata_tf_read, | 179 | .tf_read = ata_tf_read, |
220 | .exec_command = ata_exec_command, | 180 | .exec_command = ata_exec_command, |
221 | .check_status = ata_check_status, | 181 | .check_status = ata_check_status, |
222 | .dev_select = ata_std_dev_select, | 182 | .dev_select = ata_std_dev_select, |
223 | .phy_reset = sata_phy_reset, | ||
224 | .bmdma_setup = ata_bmdma_setup, | 183 | .bmdma_setup = ata_bmdma_setup, |
225 | .bmdma_start = ata_bmdma_start, | 184 | .bmdma_start = ata_bmdma_start, |
226 | .bmdma_stop = ata_bmdma_stop, | 185 | .bmdma_stop = ata_bmdma_stop, |
227 | .bmdma_status = ata_bmdma_status, | 186 | .bmdma_status = ata_bmdma_status, |
228 | .qc_prep = ata_qc_prep, | 187 | .qc_prep = ata_qc_prep, |
229 | .qc_issue = ata_qc_issue_prot, | 188 | .qc_issue = ata_qc_issue_prot, |
230 | .eng_timeout = ata_eng_timeout, | 189 | .freeze = ata_bmdma_freeze, |
231 | .irq_handler = nv_interrupt, | 190 | .thaw = ata_bmdma_thaw, |
191 | .error_handler = nv_error_handler, | ||
192 | .post_internal_cmd = ata_bmdma_post_internal_cmd, | ||
193 | .data_xfer = ata_pio_data_xfer, | ||
194 | .irq_handler = nv_generic_interrupt, | ||
232 | .irq_clear = ata_bmdma_irq_clear, | 195 | .irq_clear = ata_bmdma_irq_clear, |
233 | .scr_read = nv_scr_read, | 196 | .scr_read = nv_scr_read, |
234 | .scr_write = nv_scr_write, | 197 | .scr_write = nv_scr_write, |
235 | .port_start = ata_port_start, | 198 | .port_start = ata_port_start, |
236 | .port_stop = ata_port_stop, | 199 | .port_stop = ata_port_stop, |
237 | .host_stop = nv_host_stop, | 200 | .host_stop = ata_pci_host_stop, |
238 | }; | 201 | }; |
239 | 202 | ||
240 | /* FIXME: The hardware provides the necessary SATA PHY controls | 203 | static const struct ata_port_operations nv_nf2_ops = { |
241 | * to support ATA_FLAG_SATA_RESET. However, it is currently | 204 | .port_disable = ata_port_disable, |
242 | * necessary to disable that flag, to solve misdetection problems. | 205 | .tf_load = ata_tf_load, |
243 | * See http://bugme.osdl.org/show_bug.cgi?id=3352 for more info. | 206 | .tf_read = ata_tf_read, |
244 | * | 207 | .exec_command = ata_exec_command, |
245 | * This problem really needs to be investigated further. But in the | 208 | .check_status = ata_check_status, |
246 | * meantime, we avoid ATA_FLAG_SATA_RESET to get people working. | 209 | .dev_select = ata_std_dev_select, |
247 | */ | 210 | .bmdma_setup = ata_bmdma_setup, |
248 | static struct ata_port_info nv_port_info = { | 211 | .bmdma_start = ata_bmdma_start, |
249 | .sht = &nv_sht, | 212 | .bmdma_stop = ata_bmdma_stop, |
250 | .host_flags = ATA_FLAG_SATA | | 213 | .bmdma_status = ata_bmdma_status, |
251 | /* ATA_FLAG_SATA_RESET | */ | 214 | .qc_prep = ata_qc_prep, |
252 | ATA_FLAG_SRST | | 215 | .qc_issue = ata_qc_issue_prot, |
253 | ATA_FLAG_NO_LEGACY, | 216 | .freeze = nv_nf2_freeze, |
254 | .pio_mask = NV_PIO_MASK, | 217 | .thaw = nv_nf2_thaw, |
255 | .mwdma_mask = NV_MWDMA_MASK, | 218 | .error_handler = nv_error_handler, |
256 | .udma_mask = NV_UDMA_MASK, | 219 | .post_internal_cmd = ata_bmdma_post_internal_cmd, |
257 | .port_ops = &nv_ops, | 220 | .data_xfer = ata_pio_data_xfer, |
221 | .irq_handler = nv_nf2_interrupt, | ||
222 | .irq_clear = ata_bmdma_irq_clear, | ||
223 | .scr_read = nv_scr_read, | ||
224 | .scr_write = nv_scr_write, | ||
225 | .port_start = ata_port_start, | ||
226 | .port_stop = ata_port_stop, | ||
227 | .host_stop = ata_pci_host_stop, | ||
228 | }; | ||
229 | |||
230 | static const struct ata_port_operations nv_ck804_ops = { | ||
231 | .port_disable = ata_port_disable, | ||
232 | .tf_load = ata_tf_load, | ||
233 | .tf_read = ata_tf_read, | ||
234 | .exec_command = ata_exec_command, | ||
235 | .check_status = ata_check_status, | ||
236 | .dev_select = ata_std_dev_select, | ||
237 | .bmdma_setup = ata_bmdma_setup, | ||
238 | .bmdma_start = ata_bmdma_start, | ||
239 | .bmdma_stop = ata_bmdma_stop, | ||
240 | .bmdma_status = ata_bmdma_status, | ||
241 | .qc_prep = ata_qc_prep, | ||
242 | .qc_issue = ata_qc_issue_prot, | ||
243 | .freeze = nv_ck804_freeze, | ||
244 | .thaw = nv_ck804_thaw, | ||
245 | .error_handler = nv_error_handler, | ||
246 | .post_internal_cmd = ata_bmdma_post_internal_cmd, | ||
247 | .data_xfer = ata_pio_data_xfer, | ||
248 | .irq_handler = nv_ck804_interrupt, | ||
249 | .irq_clear = ata_bmdma_irq_clear, | ||
250 | .scr_read = nv_scr_read, | ||
251 | .scr_write = nv_scr_write, | ||
252 | .port_start = ata_port_start, | ||
253 | .port_stop = ata_port_stop, | ||
254 | .host_stop = nv_ck804_host_stop, | ||
255 | }; | ||
256 | |||
257 | static struct ata_port_info nv_port_info[] = { | ||
258 | /* generic */ | ||
259 | { | ||
260 | .sht = &nv_sht, | ||
261 | .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, | ||
262 | .pio_mask = NV_PIO_MASK, | ||
263 | .mwdma_mask = NV_MWDMA_MASK, | ||
264 | .udma_mask = NV_UDMA_MASK, | ||
265 | .port_ops = &nv_generic_ops, | ||
266 | }, | ||
267 | /* nforce2/3 */ | ||
268 | { | ||
269 | .sht = &nv_sht, | ||
270 | .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, | ||
271 | .pio_mask = NV_PIO_MASK, | ||
272 | .mwdma_mask = NV_MWDMA_MASK, | ||
273 | .udma_mask = NV_UDMA_MASK, | ||
274 | .port_ops = &nv_nf2_ops, | ||
275 | }, | ||
276 | /* ck804 */ | ||
277 | { | ||
278 | .sht = &nv_sht, | ||
279 | .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY, | ||
280 | .pio_mask = NV_PIO_MASK, | ||
281 | .mwdma_mask = NV_MWDMA_MASK, | ||
282 | .udma_mask = NV_UDMA_MASK, | ||
283 | .port_ops = &nv_ck804_ops, | ||
284 | }, | ||
258 | }; | 285 | }; |
259 | 286 | ||
260 | MODULE_AUTHOR("NVIDIA"); | 287 | MODULE_AUTHOR("NVIDIA"); |
@@ -263,11 +290,10 @@ MODULE_LICENSE("GPL"); | |||
263 | MODULE_DEVICE_TABLE(pci, nv_pci_tbl); | 290 | MODULE_DEVICE_TABLE(pci, nv_pci_tbl); |
264 | MODULE_VERSION(DRV_VERSION); | 291 | MODULE_VERSION(DRV_VERSION); |
265 | 292 | ||
266 | static irqreturn_t nv_interrupt (int irq, void *dev_instance, | 293 | static irqreturn_t nv_generic_interrupt(int irq, void *dev_instance, |
267 | struct pt_regs *regs) | 294 | struct pt_regs *regs) |
268 | { | 295 | { |
269 | struct ata_host_set *host_set = dev_instance; | 296 | struct ata_host_set *host_set = dev_instance; |
270 | struct nv_host *host = host_set->private_data; | ||
271 | unsigned int i; | 297 | unsigned int i; |
272 | unsigned int handled = 0; | 298 | unsigned int handled = 0; |
273 | unsigned long flags; | 299 | unsigned long flags; |
@@ -279,11 +305,11 @@ static irqreturn_t nv_interrupt (int irq, void *dev_instance, | |||
279 | 305 | ||
280 | ap = host_set->ports[i]; | 306 | ap = host_set->ports[i]; |
281 | if (ap && | 307 | if (ap && |
282 | !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) { | 308 | !(ap->flags & ATA_FLAG_DISABLED)) { |
283 | struct ata_queued_cmd *qc; | 309 | struct ata_queued_cmd *qc; |
284 | 310 | ||
285 | qc = ata_qc_from_tag(ap, ap->active_tag); | 311 | qc = ata_qc_from_tag(ap, ap->active_tag); |
286 | if (qc && (!(qc->tf.ctl & ATA_NIEN))) | 312 | if (qc && (!(qc->tf.flags & ATA_TFLAG_POLLING))) |
287 | handled += ata_host_intr(ap, qc); | 313 | handled += ata_host_intr(ap, qc); |
288 | else | 314 | else |
289 | // No request pending? Clear interrupt status | 315 | // No request pending? Clear interrupt status |
@@ -293,14 +319,88 @@ static irqreturn_t nv_interrupt (int irq, void *dev_instance, | |||
293 | 319 | ||
294 | } | 320 | } |
295 | 321 | ||
296 | if (host->host_desc->check_hotplug) | ||
297 | handled += host->host_desc->check_hotplug(host_set); | ||
298 | |||
299 | spin_unlock_irqrestore(&host_set->lock, flags); | 322 | spin_unlock_irqrestore(&host_set->lock, flags); |
300 | 323 | ||
301 | return IRQ_RETVAL(handled); | 324 | return IRQ_RETVAL(handled); |
302 | } | 325 | } |
303 | 326 | ||
327 | static int nv_host_intr(struct ata_port *ap, u8 irq_stat) | ||
328 | { | ||
329 | struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->active_tag); | ||
330 | int handled; | ||
331 | |||
332 | /* freeze if hotplugged */ | ||
333 | if (unlikely(irq_stat & (NV_INT_ADDED | NV_INT_REMOVED))) { | ||
334 | ata_port_freeze(ap); | ||
335 | return 1; | ||
336 | } | ||
337 | |||
338 | /* bail out if not our interrupt */ | ||
339 | if (!(irq_stat & NV_INT_DEV)) | ||
340 | return 0; | ||
341 | |||
342 | /* DEV interrupt w/ no active qc? */ | ||
343 | if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) { | ||
344 | ata_check_status(ap); | ||
345 | return 1; | ||
346 | } | ||
347 | |||
348 | /* handle interrupt */ | ||
349 | handled = ata_host_intr(ap, qc); | ||
350 | if (unlikely(!handled)) { | ||
351 | /* spurious, clear it */ | ||
352 | ata_check_status(ap); | ||
353 | } | ||
354 | |||
355 | return 1; | ||
356 | } | ||
357 | |||
358 | static irqreturn_t nv_do_interrupt(struct ata_host_set *host_set, u8 irq_stat) | ||
359 | { | ||
360 | int i, handled = 0; | ||
361 | |||
362 | for (i = 0; i < host_set->n_ports; i++) { | ||
363 | struct ata_port *ap = host_set->ports[i]; | ||
364 | |||
365 | if (ap && !(ap->flags & ATA_FLAG_DISABLED)) | ||
366 | handled += nv_host_intr(ap, irq_stat); | ||
367 | |||
368 | irq_stat >>= NV_INT_PORT_SHIFT; | ||
369 | } | ||
370 | |||
371 | return IRQ_RETVAL(handled); | ||
372 | } | ||
373 | |||
374 | static irqreturn_t nv_nf2_interrupt(int irq, void *dev_instance, | ||
375 | struct pt_regs *regs) | ||
376 | { | ||
377 | struct ata_host_set *host_set = dev_instance; | ||
378 | u8 irq_stat; | ||
379 | irqreturn_t ret; | ||
380 | |||
381 | spin_lock(&host_set->lock); | ||
382 | irq_stat = inb(host_set->ports[0]->ioaddr.scr_addr + NV_INT_STATUS); | ||
383 | ret = nv_do_interrupt(host_set, irq_stat); | ||
384 | spin_unlock(&host_set->lock); | ||
385 | |||
386 | return ret; | ||
387 | } | ||
388 | |||
389 | static irqreturn_t nv_ck804_interrupt(int irq, void *dev_instance, | ||
390 | struct pt_regs *regs) | ||
391 | { | ||
392 | struct ata_host_set *host_set = dev_instance; | ||
393 | u8 irq_stat; | ||
394 | irqreturn_t ret; | ||
395 | |||
396 | spin_lock(&host_set->lock); | ||
397 | irq_stat = readb(host_set->mmio_base + NV_INT_STATUS_CK804); | ||
398 | ret = nv_do_interrupt(host_set, irq_stat); | ||
399 | spin_unlock(&host_set->lock); | ||
400 | |||
401 | return ret; | ||
402 | } | ||
403 | |||
304 | static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg) | 404 | static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg) |
305 | { | 405 | { |
306 | if (sc_reg > SCR_CONTROL) | 406 | if (sc_reg > SCR_CONTROL) |
@@ -317,23 +417,74 @@ static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) | |||
317 | iowrite32(val, (void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4)); | 417 | iowrite32(val, (void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4)); |
318 | } | 418 | } |
319 | 419 | ||
320 | static void nv_host_stop (struct ata_host_set *host_set) | 420 | static void nv_nf2_freeze(struct ata_port *ap) |
321 | { | 421 | { |
322 | struct nv_host *host = host_set->private_data; | 422 | unsigned long scr_addr = ap->host_set->ports[0]->ioaddr.scr_addr; |
423 | int shift = ap->port_no * NV_INT_PORT_SHIFT; | ||
424 | u8 mask; | ||
323 | 425 | ||
324 | // Disable hotplug event interrupts. | 426 | mask = inb(scr_addr + NV_INT_ENABLE); |
325 | if (host->host_desc->disable_hotplug) | 427 | mask &= ~(NV_INT_ALL << shift); |
326 | host->host_desc->disable_hotplug(host_set); | 428 | outb(mask, scr_addr + NV_INT_ENABLE); |
429 | } | ||
327 | 430 | ||
328 | kfree(host); | 431 | static void nv_nf2_thaw(struct ata_port *ap) |
432 | { | ||
433 | unsigned long scr_addr = ap->host_set->ports[0]->ioaddr.scr_addr; | ||
434 | int shift = ap->port_no * NV_INT_PORT_SHIFT; | ||
435 | u8 mask; | ||
329 | 436 | ||
330 | ata_pci_host_stop(host_set); | 437 | outb(NV_INT_ALL << shift, scr_addr + NV_INT_STATUS); |
438 | |||
439 | mask = inb(scr_addr + NV_INT_ENABLE); | ||
440 | mask |= (NV_INT_MASK << shift); | ||
441 | outb(mask, scr_addr + NV_INT_ENABLE); | ||
442 | } | ||
443 | |||
444 | static void nv_ck804_freeze(struct ata_port *ap) | ||
445 | { | ||
446 | void __iomem *mmio_base = ap->host_set->mmio_base; | ||
447 | int shift = ap->port_no * NV_INT_PORT_SHIFT; | ||
448 | u8 mask; | ||
449 | |||
450 | mask = readb(mmio_base + NV_INT_ENABLE_CK804); | ||
451 | mask &= ~(NV_INT_ALL << shift); | ||
452 | writeb(mask, mmio_base + NV_INT_ENABLE_CK804); | ||
453 | } | ||
454 | |||
455 | static void nv_ck804_thaw(struct ata_port *ap) | ||
456 | { | ||
457 | void __iomem *mmio_base = ap->host_set->mmio_base; | ||
458 | int shift = ap->port_no * NV_INT_PORT_SHIFT; | ||
459 | u8 mask; | ||
460 | |||
461 | writeb(NV_INT_ALL << shift, mmio_base + NV_INT_STATUS_CK804); | ||
462 | |||
463 | mask = readb(mmio_base + NV_INT_ENABLE_CK804); | ||
464 | mask |= (NV_INT_MASK << shift); | ||
465 | writeb(mask, mmio_base + NV_INT_ENABLE_CK804); | ||
466 | } | ||
467 | |||
468 | static int nv_hardreset(struct ata_port *ap, unsigned int *class) | ||
469 | { | ||
470 | unsigned int dummy; | ||
471 | |||
472 | /* SATA hardreset fails to retrieve proper device signature on | ||
473 | * some controllers. Don't classify on hardreset. For more | ||
474 | * info, see http://bugme.osdl.org/show_bug.cgi?id=3352 | ||
475 | */ | ||
476 | return sata_std_hardreset(ap, &dummy); | ||
477 | } | ||
478 | |||
479 | static void nv_error_handler(struct ata_port *ap) | ||
480 | { | ||
481 | ata_bmdma_drive_eh(ap, ata_std_prereset, ata_std_softreset, | ||
482 | nv_hardreset, ata_std_postreset); | ||
331 | } | 483 | } |
332 | 484 | ||
333 | static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) | 485 | static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) |
334 | { | 486 | { |
335 | static int printed_version = 0; | 487 | static int printed_version = 0; |
336 | struct nv_host *host; | ||
337 | struct ata_port_info *ppi; | 488 | struct ata_port_info *ppi; |
338 | struct ata_probe_ent *probe_ent; | 489 | struct ata_probe_ent *probe_ent; |
339 | int pci_dev_busy = 0; | 490 | int pci_dev_busy = 0; |
@@ -370,24 +521,15 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) | |||
370 | 521 | ||
371 | rc = -ENOMEM; | 522 | rc = -ENOMEM; |
372 | 523 | ||
373 | ppi = &nv_port_info; | 524 | ppi = &nv_port_info[ent->driver_data]; |
374 | probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); | 525 | probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); |
375 | if (!probe_ent) | 526 | if (!probe_ent) |
376 | goto err_out_regions; | 527 | goto err_out_regions; |
377 | 528 | ||
378 | host = kmalloc(sizeof(struct nv_host), GFP_KERNEL); | ||
379 | if (!host) | ||
380 | goto err_out_free_ent; | ||
381 | |||
382 | memset(host, 0, sizeof(struct nv_host)); | ||
383 | host->host_desc = &nv_device_tbl[ent->driver_data]; | ||
384 | |||
385 | probe_ent->private_data = host; | ||
386 | |||
387 | probe_ent->mmio_base = pci_iomap(pdev, 5, 0); | 529 | probe_ent->mmio_base = pci_iomap(pdev, 5, 0); |
388 | if (!probe_ent->mmio_base) { | 530 | if (!probe_ent->mmio_base) { |
389 | rc = -EIO; | 531 | rc = -EIO; |
390 | goto err_out_free_host; | 532 | goto err_out_free_ent; |
391 | } | 533 | } |
392 | 534 | ||
393 | base = (unsigned long)probe_ent->mmio_base; | 535 | base = (unsigned long)probe_ent->mmio_base; |
@@ -395,24 +537,27 @@ static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) | |||
395 | probe_ent->port[0].scr_addr = base + NV_PORT0_SCR_REG_OFFSET; | 537 | probe_ent->port[0].scr_addr = base + NV_PORT0_SCR_REG_OFFSET; |
396 | probe_ent->port[1].scr_addr = base + NV_PORT1_SCR_REG_OFFSET; | 538 | probe_ent->port[1].scr_addr = base + NV_PORT1_SCR_REG_OFFSET; |
397 | 539 | ||
540 | /* enable SATA space for CK804 */ | ||
541 | if (ent->driver_data == CK804) { | ||
542 | u8 regval; | ||
543 | |||
544 | pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, ®val); | ||
545 | regval |= NV_MCP_SATA_CFG_20_SATA_SPACE_EN; | ||
546 | pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval); | ||
547 | } | ||
548 | |||
398 | pci_set_master(pdev); | 549 | pci_set_master(pdev); |
399 | 550 | ||
400 | rc = ata_device_add(probe_ent); | 551 | rc = ata_device_add(probe_ent); |
401 | if (rc != NV_PORTS) | 552 | if (rc != NV_PORTS) |
402 | goto err_out_iounmap; | 553 | goto err_out_iounmap; |
403 | 554 | ||
404 | // Enable hotplug event interrupts. | ||
405 | if (host->host_desc->enable_hotplug) | ||
406 | host->host_desc->enable_hotplug(probe_ent); | ||
407 | |||
408 | kfree(probe_ent); | 555 | kfree(probe_ent); |
409 | 556 | ||
410 | return 0; | 557 | return 0; |
411 | 558 | ||
412 | err_out_iounmap: | 559 | err_out_iounmap: |
413 | pci_iounmap(pdev, probe_ent->mmio_base); | 560 | pci_iounmap(pdev, probe_ent->mmio_base); |
414 | err_out_free_host: | ||
415 | kfree(host); | ||
416 | err_out_free_ent: | 561 | err_out_free_ent: |
417 | kfree(probe_ent); | 562 | kfree(probe_ent); |
418 | err_out_regions: | 563 | err_out_regions: |
@@ -424,127 +569,17 @@ err_out: | |||
424 | return rc; | 569 | return rc; |
425 | } | 570 | } |
426 | 571 | ||
427 | static void nv_enable_hotplug(struct ata_probe_ent *probe_ent) | 572 | static void nv_ck804_host_stop(struct ata_host_set *host_set) |
428 | { | ||
429 | u8 intr_mask; | ||
430 | |||
431 | outb(NV_INT_STATUS_HOTPLUG, | ||
432 | probe_ent->port[0].scr_addr + NV_INT_STATUS); | ||
433 | |||
434 | intr_mask = inb(probe_ent->port[0].scr_addr + NV_INT_ENABLE); | ||
435 | intr_mask |= NV_INT_ENABLE_HOTPLUG; | ||
436 | |||
437 | outb(intr_mask, probe_ent->port[0].scr_addr + NV_INT_ENABLE); | ||
438 | } | ||
439 | |||
440 | static void nv_disable_hotplug(struct ata_host_set *host_set) | ||
441 | { | ||
442 | u8 intr_mask; | ||
443 | |||
444 | intr_mask = inb(host_set->ports[0]->ioaddr.scr_addr + NV_INT_ENABLE); | ||
445 | |||
446 | intr_mask &= ~(NV_INT_ENABLE_HOTPLUG); | ||
447 | |||
448 | outb(intr_mask, host_set->ports[0]->ioaddr.scr_addr + NV_INT_ENABLE); | ||
449 | } | ||
450 | |||
451 | static int nv_check_hotplug(struct ata_host_set *host_set) | ||
452 | { | ||
453 | u8 intr_status; | ||
454 | |||
455 | intr_status = inb(host_set->ports[0]->ioaddr.scr_addr + NV_INT_STATUS); | ||
456 | |||
457 | // Clear interrupt status. | ||
458 | outb(0xff, host_set->ports[0]->ioaddr.scr_addr + NV_INT_STATUS); | ||
459 | |||
460 | if (intr_status & NV_INT_STATUS_HOTPLUG) { | ||
461 | if (intr_status & NV_INT_STATUS_PDEV_ADDED) | ||
462 | printk(KERN_WARNING "nv_sata: " | ||
463 | "Primary device added\n"); | ||
464 | |||
465 | if (intr_status & NV_INT_STATUS_PDEV_REMOVED) | ||
466 | printk(KERN_WARNING "nv_sata: " | ||
467 | "Primary device removed\n"); | ||
468 | |||
469 | if (intr_status & NV_INT_STATUS_SDEV_ADDED) | ||
470 | printk(KERN_WARNING "nv_sata: " | ||
471 | "Secondary device added\n"); | ||
472 | |||
473 | if (intr_status & NV_INT_STATUS_SDEV_REMOVED) | ||
474 | printk(KERN_WARNING "nv_sata: " | ||
475 | "Secondary device removed\n"); | ||
476 | |||
477 | return 1; | ||
478 | } | ||
479 | |||
480 | return 0; | ||
481 | } | ||
482 | |||
483 | static void nv_enable_hotplug_ck804(struct ata_probe_ent *probe_ent) | ||
484 | { | ||
485 | struct pci_dev *pdev = to_pci_dev(probe_ent->dev); | ||
486 | u8 intr_mask; | ||
487 | u8 regval; | ||
488 | |||
489 | pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, ®val); | ||
490 | regval |= NV_MCP_SATA_CFG_20_SATA_SPACE_EN; | ||
491 | pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval); | ||
492 | |||
493 | writeb(NV_INT_STATUS_HOTPLUG, probe_ent->mmio_base + NV_INT_STATUS_CK804); | ||
494 | |||
495 | intr_mask = readb(probe_ent->mmio_base + NV_INT_ENABLE_CK804); | ||
496 | intr_mask |= NV_INT_ENABLE_HOTPLUG; | ||
497 | |||
498 | writeb(intr_mask, probe_ent->mmio_base + NV_INT_ENABLE_CK804); | ||
499 | } | ||
500 | |||
501 | static void nv_disable_hotplug_ck804(struct ata_host_set *host_set) | ||
502 | { | 573 | { |
503 | struct pci_dev *pdev = to_pci_dev(host_set->dev); | 574 | struct pci_dev *pdev = to_pci_dev(host_set->dev); |
504 | u8 intr_mask; | ||
505 | u8 regval; | 575 | u8 regval; |
506 | 576 | ||
507 | intr_mask = readb(host_set->mmio_base + NV_INT_ENABLE_CK804); | 577 | /* disable SATA space for CK804 */ |
508 | |||
509 | intr_mask &= ~(NV_INT_ENABLE_HOTPLUG); | ||
510 | |||
511 | writeb(intr_mask, host_set->mmio_base + NV_INT_ENABLE_CK804); | ||
512 | |||
513 | pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, ®val); | 578 | pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, ®val); |
514 | regval &= ~NV_MCP_SATA_CFG_20_SATA_SPACE_EN; | 579 | regval &= ~NV_MCP_SATA_CFG_20_SATA_SPACE_EN; |
515 | pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval); | 580 | pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval); |
516 | } | ||
517 | |||
518 | static int nv_check_hotplug_ck804(struct ata_host_set *host_set) | ||
519 | { | ||
520 | u8 intr_status; | ||
521 | 581 | ||
522 | intr_status = readb(host_set->mmio_base + NV_INT_STATUS_CK804); | 582 | ata_pci_host_stop(host_set); |
523 | |||
524 | // Clear interrupt status. | ||
525 | writeb(0xff, host_set->mmio_base + NV_INT_STATUS_CK804); | ||
526 | |||
527 | if (intr_status & NV_INT_STATUS_HOTPLUG) { | ||
528 | if (intr_status & NV_INT_STATUS_PDEV_ADDED) | ||
529 | printk(KERN_WARNING "nv_sata: " | ||
530 | "Primary device added\n"); | ||
531 | |||
532 | if (intr_status & NV_INT_STATUS_PDEV_REMOVED) | ||
533 | printk(KERN_WARNING "nv_sata: " | ||
534 | "Primary device removed\n"); | ||
535 | |||
536 | if (intr_status & NV_INT_STATUS_SDEV_ADDED) | ||
537 | printk(KERN_WARNING "nv_sata: " | ||
538 | "Secondary device added\n"); | ||
539 | |||
540 | if (intr_status & NV_INT_STATUS_SDEV_REMOVED) | ||
541 | printk(KERN_WARNING "nv_sata: " | ||
542 | "Secondary device removed\n"); | ||
543 | |||
544 | return 1; | ||
545 | } | ||
546 | |||
547 | return 0; | ||
548 | } | 583 | } |
549 | 584 | ||
550 | static int __init nv_init(void) | 585 | static int __init nv_init(void) |