]> nv-tegra.nvidia Code Review - linux-2.6.git/blob - drivers/sn/ioc4.c
ea75b3d0612b596819fba49a6d17c8e24939e941
[linux-2.6.git] / drivers / sn / ioc4.c
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 2005 Silicon Graphics, Inc.  All Rights Reserved.
7  */
8
9 /* This file contains the master driver module for use by SGI IOC4 subdrivers.
10  *
11  * It allocates any resources shared between multiple subdevices, and
12  * provides accessor functions (where needed) and the like for those
13  * resources.  It also provides a mechanism for the subdevice modules
14  * to support loading and unloading.
15  *
16  * Non-shared resources (e.g. external interrupt A_INT_OUT register page
17  * alias, serial port and UART registers) are handled by the subdevice
18  * modules themselves.
19  *
20  * This is all necessary because IOC4 is not implemented as a multi-function
21  * PCI device, but an amalgamation of disparate registers for several
22  * types of device (ATA, serial, external interrupts).  The normal
23  * resource management in the kernel doesn't have quite the right interfaces
24  * to handle this situation (e.g. multiple modules can't claim the same
25  * PCI ID), thus this IOC4 master module.
26  */
27
28 #include <linux/errno.h>
29 #include <linux/module.h>
30 #include <linux/pci.h>
31 #include <linux/ioc4.h>
32 #include <linux/mmtimer.h>
33 #include <linux/rtc.h>
34 #include <linux/rwsem.h>
35 #include <asm/sn/addrs.h>
36 #include <asm/sn/clksupport.h>
37 #include <asm/sn/shub_mmr.h>
38
39 /***************
40  * Definitions *
41  ***************/
42
43 /* Tweakable values */
44
45 /* PCI bus speed detection/calibration */
46 #define IOC4_CALIBRATE_COUNT 63 /* Calibration cycle period */
47 #define IOC4_CALIBRATE_CYCLES 256       /* Average over this many cycles */
48 #define IOC4_CALIBRATE_DISCARD 2        /* Discard first few cycles */
49 #define IOC4_CALIBRATE_LOW_MHZ 25       /* Lower bound on bus speed sanity */
50 #define IOC4_CALIBRATE_HIGH_MHZ 75      /* Upper bound on bus speed sanity */
51 #define IOC4_CALIBRATE_DEFAULT_MHZ 66   /* Assumed if sanity check fails */
52
53 /************************
54  * Submodule management *
55  ************************/
56
57 static LIST_HEAD(ioc4_devices);
58 static DECLARE_RWSEM(ioc4_devices_rwsem);
59
60 static LIST_HEAD(ioc4_submodules);
61 static DECLARE_RWSEM(ioc4_submodules_rwsem);
62
63 /* Register an IOC4 submodule */
64 int
65 ioc4_register_submodule(struct ioc4_submodule *is)
66 {
67         struct ioc4_driver_data *idd;
68
69         down_write(&ioc4_submodules_rwsem);
70         list_add(&is->is_list, &ioc4_submodules);
71         up_write(&ioc4_submodules_rwsem);
72
73         /* Initialize submodule for each IOC4 */
74         if (!is->is_probe)
75                 return 0;
76
77         down_read(&ioc4_devices_rwsem);
78         list_for_each_entry(idd, &ioc4_devices, idd_list) {
79                 if (is->is_probe(idd)) {
80                         printk(KERN_WARNING
81                                "%s: IOC4 submodule %s probe failed "
82                                "for pci_dev %s",
83                                __FUNCTION__, module_name(is->is_owner),
84                                pci_name(idd->idd_pdev));
85                 }
86         }
87         up_read(&ioc4_devices_rwsem);
88
89         return 0;
90 }
91
92 /* Unregister an IOC4 submodule */
93 void
94 ioc4_unregister_submodule(struct ioc4_submodule *is)
95 {
96         struct ioc4_driver_data *idd;
97
98         down_write(&ioc4_submodules_rwsem);
99         list_del(&is->is_list);
100         up_write(&ioc4_submodules_rwsem);
101
102         /* Remove submodule for each IOC4 */
103         if (!is->is_remove)
104                 return;
105
106         down_read(&ioc4_devices_rwsem);
107         list_for_each_entry(idd, &ioc4_devices, idd_list) {
108                 if (is->is_remove(idd)) {
109                         printk(KERN_WARNING
110                                "%s: IOC4 submodule %s remove failed "
111                                "for pci_dev %s.\n",
112                                __FUNCTION__, module_name(is->is_owner),
113                                pci_name(idd->idd_pdev));
114                 }
115         }
116         up_read(&ioc4_devices_rwsem);
117 }
118
119 /*********************
120  * Device management *
121  *********************/
122
123 #define IOC4_CALIBRATE_LOW_LIMIT \
124         (1000*IOC4_EXTINT_COUNT_DIVISOR/IOC4_CALIBRATE_LOW_MHZ)
125 #define IOC4_CALIBRATE_HIGH_LIMIT \
126         (1000*IOC4_EXTINT_COUNT_DIVISOR/IOC4_CALIBRATE_HIGH_MHZ)
127 #define IOC4_CALIBRATE_DEFAULT \
128         (1000*IOC4_EXTINT_COUNT_DIVISOR/IOC4_CALIBRATE_DEFAULT_MHZ)
129
130 #define IOC4_CALIBRATE_END \
131         (IOC4_CALIBRATE_CYCLES + IOC4_CALIBRATE_DISCARD)
132
133 #define IOC4_INT_OUT_MODE_TOGGLE 0x7    /* Toggle INT_OUT every COUNT+1 ticks */
134
135 /* Determines external interrupt output clock period of the PCI bus an
136  * IOC4 is attached to.  This value can be used to determine the PCI
137  * bus speed.
138  *
139  * IOC4 has a design feature that various internal timers are derived from
140  * the PCI bus clock.  This causes IOC4 device drivers to need to take the
141  * bus speed into account when setting various register values (e.g. INT_OUT
142  * register COUNT field, UART divisors, etc).  Since this information is
143  * needed by several subdrivers, it is determined by the main IOC4 driver,
144  * even though the following code utilizes external interrupt registers
145  * to perform the speed calculation.
146  */
147 static void
148 ioc4_clock_calibrate(struct ioc4_driver_data *idd)
149 {
150         extern unsigned long sn_rtc_cycles_per_second;
151         union ioc4_int_out int_out;
152         union ioc4_gpcr gpcr;
153         unsigned int state, last_state = 1;
154         uint64_t start = 0, end, period;
155         unsigned int count = 0;
156
157         /* Enable output */
158         gpcr.raw = 0;
159         gpcr.fields.dir = IOC4_GPCR_DIR_0;
160         gpcr.fields.int_out_en = 1;
161         writel(gpcr.raw, &idd->idd_misc_regs->gpcr_s.raw);
162
163         /* Reset to power-on state */
164         writel(0, &idd->idd_misc_regs->int_out.raw);
165         mmiowb();
166
167         printk(KERN_INFO
168                "%s: Calibrating PCI bus speed "
169                "for pci_dev %s ... ", __FUNCTION__, pci_name(idd->idd_pdev));
170         /* Set up square wave */
171         int_out.raw = 0;
172         int_out.fields.count = IOC4_CALIBRATE_COUNT;
173         int_out.fields.mode = IOC4_INT_OUT_MODE_TOGGLE;
174         int_out.fields.diag = 0;
175         writel(int_out.raw, &idd->idd_misc_regs->int_out.raw);
176         mmiowb();
177
178         /* Check square wave period averaged over some number of cycles */
179         do {
180                 int_out.raw = readl(&idd->idd_misc_regs->int_out.raw);
181                 state = int_out.fields.int_out;
182                 if (!last_state && state) {
183                         count++;
184                         if (count == IOC4_CALIBRATE_END) {
185                                 end = rtc_time();
186                                 break;
187                         } else if (count == IOC4_CALIBRATE_DISCARD)
188                                 start = rtc_time();
189                 }
190                 last_state = state;
191         } while (1);
192
193         /* Calculation rearranged to preserve intermediate precision.
194          * Logically:
195          * 1. "end - start" gives us number of RTC cycles over all the
196          *    square wave cycles measured.
197          * 2. Divide by number of square wave cycles to get number of
198          *    RTC cycles per square wave cycle.
199          * 3. Divide by 2*(int_out.fields.count+1), which is the formula
200          *    by which the IOC4 generates the square wave, to get the
201          *    number of RTC cycles per IOC4 INT_OUT count.
202          * 4. Divide by sn_rtc_cycles_per_second to get seconds per
203          *    count.
204          * 5. Multiply by 1E9 to get nanoseconds per count.
205          */
206         period = ((end - start) * 1000000000) /
207             (IOC4_CALIBRATE_CYCLES * 2 * (IOC4_CALIBRATE_COUNT + 1)
208              * sn_rtc_cycles_per_second);
209
210         /* Bounds check the result. */
211         if (period > IOC4_CALIBRATE_LOW_LIMIT ||
212             period < IOC4_CALIBRATE_HIGH_LIMIT) {
213                 printk("failed. Assuming PCI clock ticks are %d ns.\n",
214                        IOC4_CALIBRATE_DEFAULT / IOC4_EXTINT_COUNT_DIVISOR);
215                 period = IOC4_CALIBRATE_DEFAULT;
216         } else {
217                 printk("succeeded. PCI clock ticks are %ld ns.\n",
218                        period / IOC4_EXTINT_COUNT_DIVISOR);
219         }
220
221         /* Remember results.  We store the extint clock period rather
222          * than the PCI clock period so that greater precision is
223          * retained.  Divide by IOC4_EXTINT_COUNT_DIVISOR to get
224          * PCI clock period.
225          */
226         idd->count_period = period;
227 }
228
229 /* Adds a new instance of an IOC4 card */
230 static int
231 ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
232 {
233         struct ioc4_driver_data *idd;
234         struct ioc4_submodule *is;
235         uint32_t pcmd;
236         int ret;
237
238         /* Enable IOC4 and take ownership of it */
239         if ((ret = pci_enable_device(pdev))) {
240                 printk(KERN_WARNING
241                        "%s: Failed to enable IOC4 device for pci_dev %s.\n",
242                        __FUNCTION__, pci_name(pdev));
243                 goto out;
244         }
245         pci_set_master(pdev);
246
247         /* Set up per-IOC4 data */
248         idd = kmalloc(sizeof(struct ioc4_driver_data), GFP_KERNEL);
249         if (!idd) {
250                 printk(KERN_WARNING
251                        "%s: Failed to allocate IOC4 data for pci_dev %s.\n",
252                        __FUNCTION__, pci_name(pdev));
253                 ret = -ENODEV;
254                 goto out_idd;
255         }
256         idd->idd_pdev = pdev;
257         idd->idd_pci_id = pci_id;
258
259         /* Map IOC4 misc registers.  These are shared between subdevices
260          * so the main IOC4 module manages them.
261          */
262         idd->idd_bar0 = pci_resource_start(idd->idd_pdev, 0);
263         if (!idd->idd_bar0) {
264                 printk(KERN_WARNING
265                        "%s: Unable to find IOC4 misc resource "
266                        "for pci_dev %s.\n",
267                        __FUNCTION__, pci_name(idd->idd_pdev));
268                 ret = -ENODEV;
269                 goto out_pci;
270         }
271         if (!request_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs),
272                             "ioc4_misc")) {
273                 printk(KERN_WARNING
274                        "%s: Unable to request IOC4 misc region "
275                        "for pci_dev %s.\n",
276                        __FUNCTION__, pci_name(idd->idd_pdev));
277                 ret = -ENODEV;
278                 goto out_pci;
279         }
280         idd->idd_misc_regs = ioremap(idd->idd_bar0,
281                                      sizeof(struct ioc4_misc_regs));
282         if (!idd->idd_misc_regs) {
283                 printk(KERN_WARNING
284                        "%s: Unable to remap IOC4 misc region "
285                        "for pci_dev %s.\n",
286                        __FUNCTION__, pci_name(idd->idd_pdev));
287                 ret = -ENODEV;
288                 goto out_misc_region;
289         }
290
291         /* Failsafe portion of per-IOC4 initialization */
292
293         /* Initialize IOC4 */
294         pci_read_config_dword(idd->idd_pdev, PCI_COMMAND, &pcmd);
295         pci_write_config_dword(idd->idd_pdev, PCI_COMMAND,
296                                pcmd | PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
297
298         /* Determine PCI clock */
299         ioc4_clock_calibrate(idd);
300
301         /* Disable/clear all interrupts.  Need to do this here lest
302          * one submodule request the shared IOC4 IRQ, but interrupt
303          * is generated by a different subdevice.
304          */
305         /* Disable */
306         writel(~0, &idd->idd_misc_regs->other_iec.raw);
307         writel(~0, &idd->idd_misc_regs->sio_iec);
308         /* Clear (i.e. acknowledge) */
309         writel(~0, &idd->idd_misc_regs->other_ir.raw);
310         writel(~0, &idd->idd_misc_regs->sio_ir);
311
312         /* Track PCI-device specific data */
313         idd->idd_serial_data = NULL;
314         pci_set_drvdata(idd->idd_pdev, idd);
315         down_write(&ioc4_devices_rwsem);
316         list_add(&idd->idd_list, &ioc4_devices);
317         up_write(&ioc4_devices_rwsem);
318
319         /* Add this IOC4 to all submodules */
320         down_read(&ioc4_submodules_rwsem);
321         list_for_each_entry(is, &ioc4_submodules, is_list) {
322                 if (is->is_probe && is->is_probe(idd)) {
323                         printk(KERN_WARNING
324                                "%s: IOC4 submodule 0x%s probe failed "
325                                "for pci_dev %s.\n",
326                                __FUNCTION__, module_name(is->is_owner),
327                                pci_name(idd->idd_pdev));
328                 }
329         }
330         up_read(&ioc4_submodules_rwsem);
331
332         return 0;
333
334 out_misc_region:
335         release_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs));
336 out_pci:
337         kfree(idd);
338 out_idd:
339         pci_disable_device(pdev);
340 out:
341         return ret;
342 }
343
344 /* Removes a particular instance of an IOC4 card. */
345 static void
346 ioc4_remove(struct pci_dev *pdev)
347 {
348         struct ioc4_submodule *is;
349         struct ioc4_driver_data *idd;
350
351         idd = pci_get_drvdata(pdev);
352
353         /* Remove this IOC4 from all submodules */
354         down_read(&ioc4_submodules_rwsem);
355         list_for_each_entry(is, &ioc4_submodules, is_list) {
356                 if (is->is_remove && is->is_remove(idd)) {
357                         printk(KERN_WARNING
358                                "%s: IOC4 submodule 0x%s remove failed "
359                                "for pci_dev %s.\n",
360                                __FUNCTION__, module_name(is->is_owner),
361                                pci_name(idd->idd_pdev));
362                 }
363         }
364         up_read(&ioc4_submodules_rwsem);
365
366         /* Release resources */
367         iounmap(idd->idd_misc_regs);
368         if (!idd->idd_bar0) {
369                 printk(KERN_WARNING
370                        "%s: Unable to get IOC4 misc mapping for pci_dev %s. "
371                        "Device removal may be incomplete.\n",
372                        __FUNCTION__, pci_name(idd->idd_pdev));
373         }
374         release_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs));
375
376         /* Disable IOC4 and relinquish */
377         pci_disable_device(pdev);
378
379         /* Remove and free driver data */
380         down_write(&ioc4_devices_rwsem);
381         list_del(&idd->idd_list);
382         up_write(&ioc4_devices_rwsem);
383         kfree(idd);
384 }
385
386 static struct pci_device_id ioc4_id_table[] = {
387         {PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC4, PCI_ANY_ID,
388          PCI_ANY_ID, 0x0b4000, 0xFFFFFF},
389         {0}
390 };
391
392 static struct pci_driver __devinitdata ioc4_driver = {
393         .name = "IOC4",
394         .id_table = ioc4_id_table,
395         .probe = ioc4_probe,
396         .remove = ioc4_remove,
397 };
398
399 MODULE_DEVICE_TABLE(pci, ioc4_id_table);
400
401 /*********************
402  * Module management *
403  *********************/
404
405 /* Module load */
406 static int __devinit
407 ioc4_init(void)
408 {
409         return pci_register_driver(&ioc4_driver);
410 }
411
412 /* Module unload */
413 static void __devexit
414 ioc4_exit(void)
415 {
416         pci_unregister_driver(&ioc4_driver);
417 }
418
419 module_init(ioc4_init);
420 module_exit(ioc4_exit);
421
422 MODULE_AUTHOR("Brent Casavant - Silicon Graphics, Inc. <bcasavan@sgi.com>");
423 MODULE_DESCRIPTION("PCI driver master module for SGI IOC4 Base-IO Card");
424 MODULE_LICENSE("GPL");
425
426 EXPORT_SYMBOL(ioc4_register_submodule);
427 EXPORT_SYMBOL(ioc4_unregister_submodule);