Root/drivers/misc/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-2006 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/ktime.h>
33#include <linux/slab.h>
34#include <linux/mutex.h>
35#include <linux/time.h>
36#include <asm/io.h>
37
38/***************
39 * Definitions *
40 ***************/
41
42/* Tweakable values */
43
44/* PCI bus speed detection/calibration */
45#define IOC4_CALIBRATE_COUNT 63 /* Calibration cycle period */
46#define IOC4_CALIBRATE_CYCLES 256 /* Average over this many cycles */
47#define IOC4_CALIBRATE_DISCARD 2 /* Discard first few cycles */
48#define IOC4_CALIBRATE_LOW_MHZ 25 /* Lower bound on bus speed sanity */
49#define IOC4_CALIBRATE_HIGH_MHZ 75 /* Upper bound on bus speed sanity */
50#define IOC4_CALIBRATE_DEFAULT_MHZ 66 /* Assumed if sanity check fails */
51
52/************************
53 * Submodule management *
54 ************************/
55
56static DEFINE_MUTEX(ioc4_mutex);
57
58static LIST_HEAD(ioc4_devices);
59static LIST_HEAD(ioc4_submodules);
60
61/* Register an IOC4 submodule */
62int
63ioc4_register_submodule(struct ioc4_submodule *is)
64{
65    struct ioc4_driver_data *idd;
66
67    mutex_lock(&ioc4_mutex);
68    list_add(&is->is_list, &ioc4_submodules);
69
70    /* Initialize submodule for each IOC4 */
71    if (!is->is_probe)
72        goto out;
73
74    list_for_each_entry(idd, &ioc4_devices, idd_list) {
75        if (is->is_probe(idd)) {
76            printk(KERN_WARNING
77                   "%s: IOC4 submodule %s probe failed "
78                   "for pci_dev %s",
79                   __func__, module_name(is->is_owner),
80                   pci_name(idd->idd_pdev));
81        }
82    }
83 out:
84    mutex_unlock(&ioc4_mutex);
85    return 0;
86}
87
88/* Unregister an IOC4 submodule */
89void
90ioc4_unregister_submodule(struct ioc4_submodule *is)
91{
92    struct ioc4_driver_data *idd;
93
94    mutex_lock(&ioc4_mutex);
95    list_del(&is->is_list);
96
97    /* Remove submodule for each IOC4 */
98    if (!is->is_remove)
99        goto out;
100
101    list_for_each_entry(idd, &ioc4_devices, idd_list) {
102        if (is->is_remove(idd)) {
103            printk(KERN_WARNING
104                   "%s: IOC4 submodule %s remove failed "
105                   "for pci_dev %s.\n",
106                   __func__, module_name(is->is_owner),
107                   pci_name(idd->idd_pdev));
108        }
109    }
110 out:
111    mutex_unlock(&ioc4_mutex);
112}
113
114/*********************
115 * Device management *
116 *********************/
117
118#define IOC4_CALIBRATE_LOW_LIMIT \
119    (1000*IOC4_EXTINT_COUNT_DIVISOR/IOC4_CALIBRATE_LOW_MHZ)
120#define IOC4_CALIBRATE_HIGH_LIMIT \
121    (1000*IOC4_EXTINT_COUNT_DIVISOR/IOC4_CALIBRATE_HIGH_MHZ)
122#define IOC4_CALIBRATE_DEFAULT \
123    (1000*IOC4_EXTINT_COUNT_DIVISOR/IOC4_CALIBRATE_DEFAULT_MHZ)
124
125#define IOC4_CALIBRATE_END \
126    (IOC4_CALIBRATE_CYCLES + IOC4_CALIBRATE_DISCARD)
127
128#define IOC4_INT_OUT_MODE_TOGGLE 0x7 /* Toggle INT_OUT every COUNT+1 ticks */
129
130/* Determines external interrupt output clock period of the PCI bus an
131 * IOC4 is attached to. This value can be used to determine the PCI
132 * bus speed.
133 *
134 * IOC4 has a design feature that various internal timers are derived from
135 * the PCI bus clock. This causes IOC4 device drivers to need to take the
136 * bus speed into account when setting various register values (e.g. INT_OUT
137 * register COUNT field, UART divisors, etc). Since this information is
138 * needed by several subdrivers, it is determined by the main IOC4 driver,
139 * even though the following code utilizes external interrupt registers
140 * to perform the speed calculation.
141 */
142static void __devinit
143ioc4_clock_calibrate(struct ioc4_driver_data *idd)
144{
145    union ioc4_int_out int_out;
146    union ioc4_gpcr gpcr;
147    unsigned int state, last_state = 1;
148    struct timespec start_ts, end_ts;
149    uint64_t start, end, period;
150    unsigned int count = 0;
151
152    /* Enable output */
153    gpcr.raw = 0;
154    gpcr.fields.dir = IOC4_GPCR_DIR_0;
155    gpcr.fields.int_out_en = 1;
156    writel(gpcr.raw, &idd->idd_misc_regs->gpcr_s.raw);
157
158    /* Reset to power-on state */
159    writel(0, &idd->idd_misc_regs->int_out.raw);
160    mmiowb();
161
162    /* Set up square wave */
163    int_out.raw = 0;
164    int_out.fields.count = IOC4_CALIBRATE_COUNT;
165    int_out.fields.mode = IOC4_INT_OUT_MODE_TOGGLE;
166    int_out.fields.diag = 0;
167    writel(int_out.raw, &idd->idd_misc_regs->int_out.raw);
168    mmiowb();
169
170    /* Check square wave period averaged over some number of cycles */
171    do {
172        int_out.raw = readl(&idd->idd_misc_regs->int_out.raw);
173        state = int_out.fields.int_out;
174        if (!last_state && state) {
175            count++;
176            if (count == IOC4_CALIBRATE_END) {
177                ktime_get_ts(&end_ts);
178                break;
179            } else if (count == IOC4_CALIBRATE_DISCARD)
180                ktime_get_ts(&start_ts);
181        }
182        last_state = state;
183    } while (1);
184
185    /* Calculation rearranged to preserve intermediate precision.
186     * Logically:
187     * 1. "end - start" gives us the measurement period over all
188     * the square wave cycles.
189     * 2. Divide by number of square wave cycles to get the period
190     * of a square wave cycle.
191     * 3. Divide by 2*(int_out.fields.count+1), which is the formula
192     * by which the IOC4 generates the square wave, to get the
193     * period of an IOC4 INT_OUT count.
194     */
195    end = end_ts.tv_sec * NSEC_PER_SEC + end_ts.tv_nsec;
196    start = start_ts.tv_sec * NSEC_PER_SEC + start_ts.tv_nsec;
197    period = (end - start) /
198        (IOC4_CALIBRATE_CYCLES * 2 * (IOC4_CALIBRATE_COUNT + 1));
199
200    /* Bounds check the result. */
201    if (period > IOC4_CALIBRATE_LOW_LIMIT ||
202        period < IOC4_CALIBRATE_HIGH_LIMIT) {
203        printk(KERN_INFO
204               "IOC4 %s: Clock calibration failed. Assuming"
205               "PCI clock is %d ns.\n",
206               pci_name(idd->idd_pdev),
207               IOC4_CALIBRATE_DEFAULT / IOC4_EXTINT_COUNT_DIVISOR);
208        period = IOC4_CALIBRATE_DEFAULT;
209    } else {
210        u64 ns = period;
211
212        do_div(ns, IOC4_EXTINT_COUNT_DIVISOR);
213        printk(KERN_DEBUG
214               "IOC4 %s: PCI clock is %llu ns.\n",
215               pci_name(idd->idd_pdev), (unsigned long long)ns);
216    }
217
218    /* Remember results. We store the extint clock period rather
219     * than the PCI clock period so that greater precision is
220     * retained. Divide by IOC4_EXTINT_COUNT_DIVISOR to get
221     * PCI clock period.
222     */
223    idd->count_period = period;
224}
225
226/* There are three variants of IOC4 cards: IO9, IO10, and PCI-RT.
227 * Each brings out different combinations of IOC4 signals, thus.
228 * the IOC4 subdrivers need to know to which we're attached.
229 *
230 * We look for the presence of a SCSI (IO9) or SATA (IO10) controller
231 * on the same PCI bus at slot number 3 to differentiate IO9 from IO10.
232 * If neither is present, it's a PCI-RT.
233 */
234static unsigned int __devinit
235ioc4_variant(struct ioc4_driver_data *idd)
236{
237    struct pci_dev *pdev = NULL;
238    int found = 0;
239
240    /* IO9: Look for a QLogic ISP 12160 at the same bus and slot 3. */
241    do {
242        pdev = pci_get_device(PCI_VENDOR_ID_QLOGIC,
243                      PCI_DEVICE_ID_QLOGIC_ISP12160, pdev);
244        if (pdev &&
245            idd->idd_pdev->bus->number == pdev->bus->number &&
246            3 == PCI_SLOT(pdev->devfn))
247            found = 1;
248    } while (pdev && !found);
249    if (NULL != pdev) {
250        pci_dev_put(pdev);
251        return IOC4_VARIANT_IO9;
252    }
253
254    /* IO10: Look for a Vitesse VSC 7174 at the same bus and slot 3. */
255    pdev = NULL;
256    do {
257        pdev = pci_get_device(PCI_VENDOR_ID_VITESSE,
258                      PCI_DEVICE_ID_VITESSE_VSC7174, pdev);
259        if (pdev &&
260            idd->idd_pdev->bus->number == pdev->bus->number &&
261            3 == PCI_SLOT(pdev->devfn))
262            found = 1;
263    } while (pdev && !found);
264    if (NULL != pdev) {
265        pci_dev_put(pdev);
266        return IOC4_VARIANT_IO10;
267    }
268
269    /* PCI-RT: No SCSI/SATA controller will be present */
270    return IOC4_VARIANT_PCI_RT;
271}
272
273static void
274ioc4_load_modules(struct work_struct *work)
275{
276    request_module("sgiioc4");
277}
278
279static DECLARE_WORK(ioc4_load_modules_work, ioc4_load_modules);
280
281/* Adds a new instance of an IOC4 card */
282static int __devinit
283ioc4_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
284{
285    struct ioc4_driver_data *idd;
286    struct ioc4_submodule *is;
287    uint32_t pcmd;
288    int ret;
289
290    /* Enable IOC4 and take ownership of it */
291    if ((ret = pci_enable_device(pdev))) {
292        printk(KERN_WARNING
293               "%s: Failed to enable IOC4 device for pci_dev %s.\n",
294               __func__, pci_name(pdev));
295        goto out;
296    }
297    pci_set_master(pdev);
298
299    /* Set up per-IOC4 data */
300    idd = kmalloc(sizeof(struct ioc4_driver_data), GFP_KERNEL);
301    if (!idd) {
302        printk(KERN_WARNING
303               "%s: Failed to allocate IOC4 data for pci_dev %s.\n",
304               __func__, pci_name(pdev));
305        ret = -ENODEV;
306        goto out_idd;
307    }
308    idd->idd_pdev = pdev;
309    idd->idd_pci_id = pci_id;
310
311    /* Map IOC4 misc registers. These are shared between subdevices
312     * so the main IOC4 module manages them.
313     */
314    idd->idd_bar0 = pci_resource_start(idd->idd_pdev, 0);
315    if (!idd->idd_bar0) {
316        printk(KERN_WARNING
317               "%s: Unable to find IOC4 misc resource "
318               "for pci_dev %s.\n",
319               __func__, pci_name(idd->idd_pdev));
320        ret = -ENODEV;
321        goto out_pci;
322    }
323    if (!request_mem_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs),
324                "ioc4_misc")) {
325        printk(KERN_WARNING
326               "%s: Unable to request IOC4 misc region "
327               "for pci_dev %s.\n",
328               __func__, pci_name(idd->idd_pdev));
329        ret = -ENODEV;
330        goto out_pci;
331    }
332    idd->idd_misc_regs = ioremap(idd->idd_bar0,
333                     sizeof(struct ioc4_misc_regs));
334    if (!idd->idd_misc_regs) {
335        printk(KERN_WARNING
336               "%s: Unable to remap IOC4 misc region "
337               "for pci_dev %s.\n",
338               __func__, pci_name(idd->idd_pdev));
339        ret = -ENODEV;
340        goto out_misc_region;
341    }
342
343    /* Failsafe portion of per-IOC4 initialization */
344
345    /* Detect card variant */
346    idd->idd_variant = ioc4_variant(idd);
347    printk(KERN_INFO "IOC4 %s: %s card detected.\n", pci_name(pdev),
348           idd->idd_variant == IOC4_VARIANT_IO9 ? "IO9" :
349           idd->idd_variant == IOC4_VARIANT_PCI_RT ? "PCI-RT" :
350           idd->idd_variant == IOC4_VARIANT_IO10 ? "IO10" : "unknown");
351
352    /* Initialize IOC4 */
353    pci_read_config_dword(idd->idd_pdev, PCI_COMMAND, &pcmd);
354    pci_write_config_dword(idd->idd_pdev, PCI_COMMAND,
355                   pcmd | PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
356
357    /* Determine PCI clock */
358    ioc4_clock_calibrate(idd);
359
360    /* Disable/clear all interrupts. Need to do this here lest
361     * one submodule request the shared IOC4 IRQ, but interrupt
362     * is generated by a different subdevice.
363     */
364    /* Disable */
365    writel(~0, &idd->idd_misc_regs->other_iec.raw);
366    writel(~0, &idd->idd_misc_regs->sio_iec);
367    /* Clear (i.e. acknowledge) */
368    writel(~0, &idd->idd_misc_regs->other_ir.raw);
369    writel(~0, &idd->idd_misc_regs->sio_ir);
370
371    /* Track PCI-device specific data */
372    idd->idd_serial_data = NULL;
373    pci_set_drvdata(idd->idd_pdev, idd);
374
375    mutex_lock(&ioc4_mutex);
376    list_add_tail(&idd->idd_list, &ioc4_devices);
377
378    /* Add this IOC4 to all submodules */
379    list_for_each_entry(is, &ioc4_submodules, is_list) {
380        if (is->is_probe && is->is_probe(idd)) {
381            printk(KERN_WARNING
382                   "%s: IOC4 submodule 0x%s probe failed "
383                   "for pci_dev %s.\n",
384                   __func__, module_name(is->is_owner),
385                   pci_name(idd->idd_pdev));
386        }
387    }
388    mutex_unlock(&ioc4_mutex);
389
390    /* Request sgiioc4 IDE driver on boards that bring that functionality
391     * off of IOC4. The root filesystem may be hosted on a drive connected
392     * to IOC4, so we need to make sure the sgiioc4 driver is loaded as it
393     * won't be picked up by modprobes due to the ioc4 module owning the
394     * PCI device.
395     */
396    if (idd->idd_variant != IOC4_VARIANT_PCI_RT) {
397        /* Request the module from a work procedure as the modprobe
398         * goes out to a userland helper and that will hang if done
399         * directly from ioc4_probe().
400         */
401        printk(KERN_INFO "IOC4 loading sgiioc4 submodule\n");
402        schedule_work(&ioc4_load_modules_work);
403    }
404
405    return 0;
406
407out_misc_region:
408    release_mem_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs));
409out_pci:
410    kfree(idd);
411out_idd:
412    pci_disable_device(pdev);
413out:
414    return ret;
415}
416
417/* Removes a particular instance of an IOC4 card. */
418static void __devexit
419ioc4_remove(struct pci_dev *pdev)
420{
421    struct ioc4_submodule *is;
422    struct ioc4_driver_data *idd;
423
424    idd = pci_get_drvdata(pdev);
425
426    /* Remove this IOC4 from all submodules */
427    mutex_lock(&ioc4_mutex);
428    list_for_each_entry(is, &ioc4_submodules, is_list) {
429        if (is->is_remove && is->is_remove(idd)) {
430            printk(KERN_WARNING
431                   "%s: IOC4 submodule 0x%s remove failed "
432                   "for pci_dev %s.\n",
433                   __func__, module_name(is->is_owner),
434                   pci_name(idd->idd_pdev));
435        }
436    }
437    mutex_unlock(&ioc4_mutex);
438
439    /* Release resources */
440    iounmap(idd->idd_misc_regs);
441    if (!idd->idd_bar0) {
442        printk(KERN_WARNING
443               "%s: Unable to get IOC4 misc mapping for pci_dev %s. "
444               "Device removal may be incomplete.\n",
445               __func__, pci_name(idd->idd_pdev));
446    }
447    release_mem_region(idd->idd_bar0, sizeof(struct ioc4_misc_regs));
448
449    /* Disable IOC4 and relinquish */
450    pci_disable_device(pdev);
451
452    /* Remove and free driver data */
453    mutex_lock(&ioc4_mutex);
454    list_del(&idd->idd_list);
455    mutex_unlock(&ioc4_mutex);
456    kfree(idd);
457}
458
459static struct pci_device_id ioc4_id_table[] = {
460    {PCI_VENDOR_ID_SGI, PCI_DEVICE_ID_SGI_IOC4, PCI_ANY_ID,
461     PCI_ANY_ID, 0x0b4000, 0xFFFFFF},
462    {0}
463};
464
465static struct pci_driver ioc4_driver = {
466    .name = "IOC4",
467    .id_table = ioc4_id_table,
468    .probe = ioc4_probe,
469    .remove = __devexit_p(ioc4_remove),
470};
471
472MODULE_DEVICE_TABLE(pci, ioc4_id_table);
473
474/*********************
475 * Module management *
476 *********************/
477
478/* Module load */
479static int __init
480ioc4_init(void)
481{
482    return pci_register_driver(&ioc4_driver);
483}
484
485/* Module unload */
486static void __exit
487ioc4_exit(void)
488{
489    /* Ensure ioc4_load_modules() has completed before exiting */
490    flush_work_sync(&ioc4_load_modules_work);
491    pci_unregister_driver(&ioc4_driver);
492}
493
494module_init(ioc4_init);
495module_exit(ioc4_exit);
496
497MODULE_AUTHOR("Brent Casavant - Silicon Graphics, Inc. <bcasavan@sgi.com>");
498MODULE_DESCRIPTION("PCI driver master module for SGI IOC4 Base-IO Card");
499MODULE_LICENSE("GPL");
500
501EXPORT_SYMBOL(ioc4_register_submodule);
502EXPORT_SYMBOL(ioc4_unregister_submodule);
503

Archive Download this file



interactive