2 /****************************************************************************
3 * Copyright (C) 2003-2006 by XGI Technology, Taiwan.
5 * All Rights Reserved. *
7 * Permission is hereby granted, free of charge, to any person obtaining
8 * a copy of this software and associated documentation files (the
9 * "Software"), to deal in the Software without restriction, including
10 * without limitation on the rights to use, copy, modify, merge,
11 * publish, distribute, sublicense, and/or sell copies of the Software,
12 * and to permit persons to whom the Software is furnished to do so,
13 * subject to the following conditions:
15 * The above copyright notice and this permission notice (including the
16 * next paragraph) shall be included in all copies or substantial
17 * portions of the Software.
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 * NON-INFRINGEMENT. IN NO EVENT SHALL XGI AND/OR
23 * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 * DEALINGS IN THE SOFTWARE.
27 ***************************************************************************/
32 #ifndef LINUX_VERSION_CODE
33 #include <linux/version.h>
36 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
37 # error "This driver does not support pre-2.6 kernels!"
40 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10)
41 # define XGI_REMAP_PFN_RANGE_PRESENT
43 # define XGI_REMAP_PAGE_RANGE_5
46 #if defined (CONFIG_SMP) && !defined (__SMP__)
50 #if defined (CONFIG_MODVERSIONS) && !defined (MODVERSIONS)
54 #include <linux/kernel.h> /* printk */
55 #include <linux/module.h>
57 #include <linux/init.h> /* module_init, module_exit */
58 #include <linux/types.h> /* pic_t, size_t, __u32, etc */
59 #include <linux/errno.h> /* error codes */
60 #include <linux/list.h> /* circular linked list */
61 #include <linux/stddef.h> /* NULL, offsetof */
62 #include <linux/wait.h> /* wait queues */
64 #include <linux/slab.h> /* kmalloc, kfree, etc */
65 #include <linux/vmalloc.h> /* vmalloc, vfree, etc */
67 #include <linux/poll.h> /* poll_wait */
68 #include <linux/delay.h> /* mdelay, udelay */
69 #include <asm/msr.h> /* rdtsc rdtscl */
71 #include <linux/sched.h> /* suser(), capable() replacement
72 for_each_task, for_each_process */
73 #ifdef for_each_process
74 #define XGI_SCAN_PROCESS(p) for_each_process(p)
76 #define XGI_SCAN_PROCESS(p) for_each_task(p)
79 #include <linux/moduleparam.h> /* module_param() */
80 #include <linux/smp_lock.h> /* kernel_locked */
81 #include <asm/tlbflush.h> /* flush_tlb(), flush_tlb_all() */
82 #include <asm/kmap_types.h> /* page table entry lookup */
84 #include <linux/pci.h> /* pci_find_class, etc */
85 #include <linux/interrupt.h> /* tasklets, interrupt helpers */
86 #include <linux/timer.h>
88 #include <asm/system.h> /* cli, sli, save_flags */
89 #include <asm/io.h> /* ioremap, virt_to_phys */
90 #include <asm/uaccess.h> /* access_ok */
91 #include <asm/page.h> /* PAGE_OFFSET */
92 #include <asm/pgtable.h> /* pte bit definitions */
94 #include <linux/spinlock.h>
95 #include <asm/semaphore.h>
96 #include <linux/highmem.h>
99 #include <linux/proc_fs.h>
102 #ifdef CONFIG_DEVFS_FS
103 #include <linux/devfs_fs_kernel.h>
107 #include <linux/kmod.h>
111 #include <linux/pm.h>
115 #include <asm/mtrr.h>
119 #include <linux/kdb.h>
123 #if defined (CONFIG_AGP) || defined (CONFIG_AGP_MODULE)
125 #include <linux/agp_backend.h>
126 #include <linux/agpgart.h>
134 #define module_init(x) int init_module(void) { return x(); }
135 #define module_exit(x) void cleanup_module(void) { x(); }
139 #define minor(x) MINOR(x)
143 typedef void irqreturn_t;
146 #define IRQ_RETVAL(x)
149 #if !defined (list_for_each)
150 #define list_for_each(pos, head) \
151 for (pos = (head)->next, prefetch(pos->next); pos != (head); \
152 pos = pos->next, prefetch(pos->next))
155 extern struct list_head pci_devices; /* list of all devices */
156 #define XGI_PCI_FOR_EACH_DEV(dev) \
157 for(dev = pci_dev_g(pci_devices.next); dev != pci_dev_g(&pci_devices); dev = pci_dev_g(dev->global_list.next))
160 * the following macro causes problems when used in the same module
161 * as module_param(); undef it so we don't accidentally mix the two
165 #ifdef EXPORT_NO_SYMBOLS
169 #define XGI_IS_SUSER() capable(CAP_SYS_ADMIN)
170 #define XGI_PCI_DEVICE_NAME(dev) ((dev)->pretty_name)
171 #define XGI_NUM_CPUS() num_online_cpus()
172 #define XGI_CLI() local_irq_disable()
173 #define XGI_SAVE_FLAGS(eflags) local_save_flags(eflags)
174 #define XGI_RESTORE_FLAGS(eflags) local_irq_restore(eflags)
175 #define XGI_MAY_SLEEP() (!in_interrupt() && !in_atomic())
176 #define XGI_MODULE_PARAMETER(x) module_param(x, int, 0)
179 #define XGI_PCI_DISABLE_DEVICE(dev) pci_disable_device(dev)
182 #define GET_MODULE_SYMBOL(mod,sym) (const void *) inter_module_get(sym)
183 #define PUT_MODULE_SYMBOL(sym) inter_module_put((char *) sym)
185 #define XGI_GET_PAGE_STRUCT(phys_page) virt_to_page(__va(phys_page))
186 #define XGI_VMA_OFFSET(vma) (((vma)->vm_pgoff) << PAGE_SHIFT)
187 #define XGI_VMA_PRIVATE(vma) ((vma)->vm_private_data)
189 #define XGI_DEVICE_NUMBER(x) minor((x)->i_rdev)
190 #define XGI_IS_CONTROL_DEVICE(x) (minor((x)->i_rdev) == 255)
192 #define XGI_PCI_RESOURCE_START(dev, bar) ((dev)->resource[bar].start)
193 #define XGI_PCI_RESOURCE_SIZE(dev, bar) ((dev)->resource[bar].end - (dev)->resource[bar].start + 1)
195 #define XGI_PCI_BUS_NUMBER(dev) (dev)->bus->number
196 #define XGI_PCI_SLOT_NUMBER(dev) PCI_SLOT((dev)->devfn)
198 #define XGI_PCI_GET_CLASS_PRESENT
199 #ifdef XGI_PCI_GET_CLASS_PRESENT
200 #define XGI_PCI_DEV_PUT(dev) pci_dev_put(dev)
201 #define XGI_PCI_GET_DEVICE(vendor,device,from) pci_get_device(vendor,device,from)
203 #define XGI_PCI_DEV_PUT(dev)
204 #define XGI_PCI_GET_DEVICE(vendor,device,from) pci_find_device(vendor,device,from)
208 * acpi support has been back-ported to the 2.4 kernel, but the 2.4 driver
209 * model is not sufficient for full acpi support. it may work in some cases,
210 * but not enough for us to officially support this configuration.
212 #if defined(CONFIG_ACPI)
213 #define XGI_PM_SUPPORT_ACPI
216 #if defined(CONFIG_APM) || defined(CONFIG_APM_MODULE)
217 #define XGI_PM_SUPPORT_APM
220 #if defined(CONFIG_DEVFS_FS)
221 typedef void *devfs_handle_t;
222 #define XGI_DEVFS_REGISTER(_name, _minor) \
224 devfs_handle_t __handle = NULL; \
225 if (devfs_mk_cdev(MKDEV(XGI_DEV_MAJOR, _minor), \
226 S_IFCHR | S_IRUGO | S_IWUGO, _name) == 0) \
228 __handle = (void *) 1; /* XXX Fix me! (boolean) */ \
233 #define XGI_DEVFS_REMOVE_DEVICE(i) devfs_remove("xgi%d", i)
235 #define XGI_DEVFS_REMOVE_CONTROL() devfs_remove("xgi_ctl")
236 #define XGI_DEVFS_REMOVE_DEVICE(i) devfs_remove("xgi")
237 #endif /* defined(CONFIG_DEVFS_FS) */
239 #define XGI_REGISTER_CHRDEV(x...) register_chrdev(x)
240 #define XGI_UNREGISTER_CHRDEV(x...) unregister_chrdev(x)
242 #if defined(XGI_REMAP_PFN_RANGE_PRESENT)
243 #define XGI_REMAP_PAGE_RANGE(from, offset, x...) \
244 remap_pfn_range(vma, from, ((offset) >> PAGE_SHIFT), x)
245 #elif defined(XGI_REMAP_PAGE_RANGE_5)
246 #define XGI_REMAP_PAGE_RANGE(x...) remap_page_range(vma, x)
247 #elif defined(XGI_REMAP_PAGE_RANGE_4)
248 #define XGI_REMAP_PAGE_RANGE(x...) remap_page_range(x)
250 #warning "xgi_configure.sh failed, assuming remap_page_range(5)!"
251 #define XGI_REMAP_PAGE_RANGE(x...) remap_page_range(vma, x)
254 #if defined(pmd_offset_map)
255 #define XGI_PMD_OFFSET(addres, pg_dir, pg_mid_dir) \
257 pg_mid_dir = pmd_offset_map(pg_dir, address); \
259 #define XGI_PMD_UNMAP(pg_mid_dir) \
261 pmd_unmap(pg_mid_dir); \
264 #define XGI_PMD_OFFSET(addres, pg_dir, pg_mid_dir) \
266 pg_mid_dir = pmd_offset(pg_dir, address); \
268 #define XGI_PMD_UNMAP(pg_mid_dir)
271 #define XGI_PMD_PRESENT(pg_mid_dir) \
273 if ((pg_mid_dir) && (pmd_none(*pg_mid_dir))) \
275 XGI_PMD_UNMAP(pg_mid_dir); \
278 pg_mid_dir != NULL; \
281 #if defined(pte_offset_atomic)
282 #define XGI_PTE_OFFSET(addres, pg_mid_dir, pte) \
284 pte = pte_offset_atomic(pg_mid_dir, address); \
285 XGI_PMD_UNMAP(pg_mid_dir); \
287 #define XGI_PTE_UNMAP(pte) \
291 #elif defined(pte_offset)
292 #define XGI_PTE_OFFSET(addres, pg_mid_dir, pte) \
294 pte = pte_offset(pg_mid_dir, address); \
295 XGI_PMD_UNMAP(pg_mid_dir); \
297 #define XGI_PTE_UNMAP(pte)
299 #define XGI_PTE_OFFSET(addres, pg_mid_dir, pte) \
301 pte = pte_offset_map(pg_mid_dir, address); \
302 XGI_PMD_UNMAP(pg_mid_dir); \
304 #define XGI_PTE_UNMAP(pte) \
310 #define XGI_PTE_PRESENT(pte) \
314 if (!pte_present(*pte)) \
316 XGI_PTE_UNMAP(pte); pte = NULL; \
322 #define XGI_PTE_VALUE(pte) \
324 unsigned long __pte_value = pte_val(*pte); \
325 XGI_PTE_UNMAP(pte); \
329 #define XGI_PAGE_ALIGN(addr) (((addr) + PAGE_SIZE - 1) / PAGE_SIZE)
330 #define XGI_MASK_OFFSET(addr) ((addr) & (PAGE_SIZE - 1))
332 #if !defined (pgprot_noncached)
333 static inline pgprot_t pgprot_noncached(pgprot_t old_prot)
335 pgprot_t new_prot = old_prot;
336 if (boot_cpu_data.x86 > 3)
337 new_prot = __pgprot(pgprot_val(old_prot) | _PAGE_PCD);
342 #if defined(XGI_BUILD_XGI_PAT_SUPPORT) && !defined (pgprot_writecombined)
343 /* Added define for write combining page, only valid if pat enabled. */
344 #define _PAGE_WRTCOMB _PAGE_PWT
345 #define __PAGE_KERNEL_WRTCOMB \
346 (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_WRTCOMB | _PAGE_ACCESSED)
347 #define PAGE_KERNEL_WRTCOMB MAKE_GLOBAL(__PAGE_KERNEL_WRTCOMB)
349 static inline pgprot_t pgprot_writecombined(pgprot_t old_prot)
351 pgprot_t new_prot = old_prot;
352 if (boot_cpu_data.x86 > 3) {
353 pgprot_val(old_prot) &= ~(_PAGE_PCD | _PAGE_PWT);
354 new_prot = __pgprot(pgprot_val(old_prot) | _PAGE_WRTCOMB);
360 #if !defined(page_to_pfn)
361 #define page_to_pfn(page) ((page) - mem_map)
364 #define XGI_VMALLOC(ptr, size) \
366 (ptr) = vmalloc_32(size); \
369 #define XGI_VFREE(ptr, size) \
371 vfree((void *) (ptr)); \
374 #define XGI_IOREMAP(ptr, physaddr, size) \
376 (ptr) = ioremap(physaddr, size); \
379 #define XGI_IOREMAP_NOCACHE(ptr, physaddr, size) \
381 (ptr) = ioremap_nocache(physaddr, size); \
384 #define XGI_IOUNMAP(ptr, size) \
390 * only use this because GFP_KERNEL may sleep..
391 * GFP_ATOMIC is ok, it won't sleep
393 #define XGI_KMALLOC(ptr, size) \
395 (ptr) = kmalloc(size, GFP_KERNEL); \
398 #define XGI_KMALLOC_ATOMIC(ptr, size) \
400 (ptr) = kmalloc(size, GFP_ATOMIC); \
403 #define XGI_KFREE(ptr, size) \
405 kfree((void *) (ptr)); \
408 #define XGI_GET_FREE_PAGES(ptr, order) \
410 (ptr) = __get_free_pages(GFP_KERNEL, order); \
413 #define XGI_FREE_PAGES(ptr, order) \
415 free_pages(ptr, order); \
418 typedef struct xgi_pte_s {
419 unsigned long phys_addr;
420 unsigned long virt_addr;
424 * AMD Athlon processors expose a subtle bug in the Linux
425 * kernel, that may lead to AGP memory corruption. Recent
426 * kernel versions had a workaround for this problem, but
427 * 2.4.20 is the first kernel to address it properly. The
428 * page_attr API provides the means to solve the problem.
430 static inline void XGI_SET_PAGE_ATTRIB_UNCACHED(xgi_pte_t * page_ptr)
432 struct page *page = virt_to_page(__va(page_ptr->phys_addr));
433 change_page_attr(page, 1, PAGE_KERNEL_NOCACHE);
435 static inline void XGI_SET_PAGE_ATTRIB_CACHED(xgi_pte_t * page_ptr)
437 struct page *page = virt_to_page(__va(page_ptr->phys_addr));
438 change_page_attr(page, 1, PAGE_KERNEL);
441 /* add for SUSE 9, Jill*/
442 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 4)
443 #define XGI_INC_PAGE_COUNT(page) atomic_inc(&(page)->count)
444 #define XGI_DEC_PAGE_COUNT(page) atomic_dec(&(page)->count)
445 #define XGI_PAGE_COUNT(page) atomic_read(&(page)->count)
446 #define XGI_SET_PAGE_COUNT(page,v) atomic_set(&(page)->count, v)
448 #define XGI_INC_PAGE_COUNT(page) atomic_inc(&(page)->_count)
449 #define XGI_DEC_PAGE_COUNT(page) atomic_dec(&(page)->_count)
450 #define XGI_PAGE_COUNT(page) atomic_read(&(page)->_count)
451 #define XGI_SET_PAGE_COUNT(page,v) atomic_set(&(page)->_count, v)
453 #define XGILockPage(page) SetPageLocked(page)
454 #define XGIUnlockPage(page) ClearPageLocked(page)
457 * hide a pointer to struct xgi_info_t in a file-private info
464 wait_queue_head_t wait_queue;
465 } xgi_file_private_t;
467 #define FILE_PRIVATE(filp) ((filp)->private_data)
469 #define XGI_GET_FP(filp) ((xgi_file_private_t *) FILE_PRIVATE(filp))
471 /* for the card devices */
472 #define XGI_INFO_FROM_FP(filp) (XGI_GET_FP(filp)->info)
474 #define INODE_FROM_FP(filp) ((filp)->f_dentry->d_inode)
476 #define XGI_ATOMIC_SET(data,val) atomic_set(&(data), (val))
477 #define XGI_ATOMIC_INC(data) atomic_inc(&(data))
478 #define XGI_ATOMIC_DEC(data) atomic_dec(&(data))
479 #define XGI_ATOMIC_DEC_AND_TEST(data) atomic_dec_and_test(&(data))
480 #define XGI_ATOMIC_READ(data) atomic_read(&(data))
483 * lock-related functions that should only be called from this file
485 #define xgi_init_lock(lock) spin_lock_init(&lock)
486 #define xgi_lock(lock) spin_lock(&lock)
487 #define xgi_unlock(lock) spin_unlock(&lock)
488 #define xgi_down(lock) down(&lock)
489 #define xgi_up(lock) up(&lock)
491 #define xgi_lock_irqsave(lock,flags) spin_lock_irqsave(&lock,flags)
492 #define xgi_unlock_irqsave(lock,flags) spin_unlock_irqrestore(&lock,flags)