From 7af9d670371de868f0642148fe2d594bc9a7dea3 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Tue, 26 Jun 2007 13:05:29 -0700 Subject: Initial XP10 code drop from XGI. See attachment 10246 on https://bugs.freedesktop.org/show_bug.cgi?id=5921 --- linux-core/xgi_drv.c | 1610 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1610 insertions(+) create mode 100644 linux-core/xgi_drv.c (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c new file mode 100644 index 00000000..5e80d417 --- /dev/null +++ b/linux-core/xgi_drv.c @@ -0,0 +1,1610 @@ + +/**************************************************************************** + * Copyright (C) 2003-2006 by XGI Technology, Taiwan. + * * + * All Rights Reserved. * + * * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL XGI AND/OR + * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ***************************************************************************/ +#include "xgi_types.h" +#include "xgi_linux.h" +#include "xgi_drv.h" +#include "xgi_regs.h" +#include "xgi_pcie.h" +#include "xgi_misc.h" +#include "xgi_cmdlist.h" + +/* for debug */ +static int xgi_temp = 1; +/* + * global parameters + */ +static struct xgi_dev { + u16 vendor; + u16 device; + const char *name; +} xgidev_list[] = { + {PCI_VENDOR_ID_XGI, PCI_DEVICE_ID_XP5, "XP5"}, + {PCI_VENDOR_ID_XGI, PCI_DEVICE_ID_XG47, "XG47"}, + {0, 0, NULL} +}; + +int xgi_major = XGI_DEV_MAJOR; /* xgi reserved major device number. */ + +static int xgi_num_devices = 0; + +xgi_info_t xgi_devices[XGI_MAX_DEVICES]; + +#if defined(XGI_PM_SUPPORT_APM) +static struct pm_dev *apm_xgi_dev[XGI_MAX_DEVICES] = { 0 }; +#endif + +/* add one for the control device */ +xgi_info_t xgi_ctl_device; +wait_queue_head_t xgi_ctl_waitqueue; + +#ifdef CONFIG_PROC_FS +struct proc_dir_entry *proc_xgi; +#endif + +#ifdef CONFIG_DEVFS_FS +devfs_handle_t xgi_devfs_handles[XGI_MAX_DEVICES]; +#endif + +struct list_head xgi_mempid_list; + +/* xgi_ functions.. do not take a state device parameter */ +static int xgi_post_vbios(xgi_ioctl_post_vbios_t *info); +static void xgi_proc_create(void); +static void xgi_proc_remove_all(struct proc_dir_entry *); +static void xgi_proc_remove(void); + +/* xgi_kern_ functions, interfaces used by linux kernel */ +int xgi_kern_probe(struct pci_dev *, const struct pci_device_id *); + +unsigned int xgi_kern_poll(struct file *, poll_table *); +int xgi_kern_ioctl(struct inode *, struct file *, unsigned int, unsigned long); +int xgi_kern_mmap(struct file *, struct vm_area_struct *); +int xgi_kern_open(struct inode *, struct file *); +int xgi_kern_release(struct inode *inode, struct file *filp); + +void xgi_kern_vma_open(struct vm_area_struct *vma); +void xgi_kern_vma_release(struct vm_area_struct *vma); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 1)) +struct page *xgi_kern_vma_nopage(struct vm_area_struct *vma, + unsigned long address, int *type); +#else +struct page *xgi_kern_vma_nopage(struct vm_area_struct *vma, + unsigned long address, int write_access); +#endif + +int xgi_kern_read_card_info(char *, char **, off_t off, int, int *, void *); +int xgi_kern_read_status(char *, char **, off_t off, int, int *, void *); +int xgi_kern_read_pcie_info(char *, char **, off_t off, int, int *, void *); +int xgi_kern_read_version(char *, char **, off_t off, int, int *, void *); + +int xgi_kern_ctl_open(struct inode *, struct file *); +int xgi_kern_ctl_close(struct inode *, struct file *); +unsigned int xgi_kern_ctl_poll(struct file *, poll_table *); + +void xgi_kern_isr_bh(unsigned long); +irqreturn_t xgi_kern_isr(int, void *, struct pt_regs *); + +static void xgi_lock_init(xgi_info_t *info); + +#if defined(XGI_PM_SUPPORT_ACPI) +int xgi_kern_acpi_standby(struct pci_dev *, u32); +int xgi_kern_acpi_resume(struct pci_dev *); +#endif + +/* + * verify access to pci config space wasn't disabled behind our back + * unfortunately, XFree86 enables/disables memory access in pci config space at + * various times (such as restoring initial pci config space settings during vt + * switches or when doing mulicard). As a result, all of our register accesses + * are garbage at this point. add a check to see if access was disabled and + * reenable any such access. + */ +#define XGI_CHECK_PCI_CONFIG(xgi) \ + xgi_check_pci_config(xgi, __LINE__) + +static inline void xgi_check_pci_config(xgi_info_t *info, int line) +{ + unsigned short cmd, flag = 0; + + // don't do this on the control device, only the actual devices + if (info->flags & XGI_FLAG_CONTROL) + return; + + pci_read_config_word(info->dev, PCI_COMMAND, &cmd); + if (!(cmd & PCI_COMMAND_MASTER)) + { + XGI_INFO("restoring bus mastering! (%d)\n", line); + cmd |= PCI_COMMAND_MASTER; + flag = 1; + } + + if (!(cmd & PCI_COMMAND_MEMORY)) + { + XGI_INFO("restoring MEM access! (%d)\n", line); + cmd |= PCI_COMMAND_MEMORY; + flag = 1; + } + + if (flag) + pci_write_config_word(info->dev, PCI_COMMAND, cmd); +} + +static int xgi_post_vbios(xgi_ioctl_post_vbios_t *info) +{ + return 1; +} + +/* + * struct pci_device_id { + * unsigned int vendor, device; // Vendor and device ID or PCI_ANY_ID + * unsigned int subvendor, subdevice; // Subsystem ID's or PCI_ANY_ID + * unsigned int class, class_mask; // (class,subclass,prog-if) triplet + * unsigned long driver_data; // Data private to the driver + * }; + */ + +static struct pci_device_id xgi_dev_table[] = { + { + .vendor = PCI_VENDOR_ID_XGI, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .class = (PCI_CLASS_DISPLAY_VGA << 8), + .class_mask = ~0, + }, + { } +}; + +/* + * #define MODULE_DEVICE_TABLE(type,name) \ + * MODULE_GENERIC_TABLE(type##_device,name) + */ + MODULE_DEVICE_TABLE(pci, xgi_dev_table); + +/* + * struct pci_driver { + * struct list_head node; + * char *name; + * const struct pci_device_id *id_table; // NULL if wants all devices + * int (*probe)(struct pci_dev *dev, const struct pci_device_id *id); // New device inserted + * void (*remove)(struct pci_dev *dev); // Device removed (NULL if not a hot-plug capable driver) + * int (*save_state)(struct pci_dev *dev, u32 state); // Save Device Context + * int (*suspend)(struct pci_dev *dev, u32 state); // Device suspended + * int (*resume)(struct pci_dev *dev); // Device woken up + * int (*enable_wake)(struct pci_dev *dev, u32 state, int enable); // Enable wake event + * }; + */ +static struct pci_driver xgi_pci_driver = { + .name = "xgi", + .id_table = xgi_dev_table, + .probe = xgi_kern_probe, +#if defined(XGI_SUPPORT_ACPI) + .suspend = xgi_kern_acpi_standby, + .resume = xgi_kern_acpi_resume, +#endif +}; + +/* + * find xgi devices and set initial state + */ +int xgi_kern_probe(struct pci_dev *dev, const struct pci_device_id *id_table) +{ + xgi_info_t *info; + + if ((dev->vendor != PCI_VENDOR_ID_XGI) + || (dev->class != (PCI_CLASS_DISPLAY_VGA << 8))) + { + return -1; + } + + if (xgi_num_devices == XGI_MAX_DEVICES) + { + XGI_INFO("maximum device number (%d) reached!\n", xgi_num_devices); + return -1; + } + + /* enable io, mem, and bus-mastering in pci config space */ + if (pci_enable_device(dev) != 0) + { + XGI_INFO("pci_enable_device failed, aborting\n"); + return -1; + } + + XGI_INFO("maximum device number (%d) reached \n", xgi_num_devices); + + pci_set_master(dev); + + info = &xgi_devices[xgi_num_devices]; + info->dev = dev; + info->vendor_id = dev->vendor; + info->device_id = dev->device; + info->bus = dev->bus->number; + info->slot = PCI_SLOT((dev)->devfn); + + xgi_lock_init(info); + + info->mmio.base = XGI_PCI_RESOURCE_START(dev, 1); + info->mmio.size = XGI_PCI_RESOURCE_SIZE(dev, 1); + + /* check IO region */ + if (!request_mem_region(info->mmio.base, info->mmio.size, "xgi")) + { + XGI_ERROR("cannot reserve MMIO memory\n"); + goto error_disable_dev; + } + + XGI_INFO("info->mmio.base: 0x%lx \n", info->mmio.base); + XGI_INFO("info->mmio.size: 0x%lx \n", info->mmio.size); + + info->mmio.vbase = (unsigned char *)ioremap_nocache(info->mmio.base, + info->mmio.size); + if (!info->mmio.vbase) + { + release_mem_region(info->mmio.base, info->mmio.size); + XGI_ERROR("info->mmio.vbase failed\n"); + goto error_disable_dev; + } + xgi_enable_mmio(info); + + //xgi_enable_ge(info); + + XGI_INFO("info->mmio.vbase: 0x%p \n", info->mmio.vbase); + + info->fb.base = XGI_PCI_RESOURCE_START(dev, 0); + info->fb.size = XGI_PCI_RESOURCE_SIZE(dev, 0); + + XGI_INFO("info->fb.base: 0x%lx \n", info->fb.base); + XGI_INFO("info->fb.size: 0x%lx \n", info->fb.size); + + info->fb.size = bIn3cf(0x54) * 8 * 1024 * 1024; + XGI_INFO("info->fb.size: 0x%lx \n", info->fb.size); + + /* check frame buffer region + if (!request_mem_region(info->fb.base, info->fb.size, "xgi")) + { + release_mem_region(info->mmio.base, info->mmio.size); + XGI_ERROR("cannot reserve frame buffer memory\n"); + goto error_disable_dev; + } + + + info->fb.vbase = (unsigned char *)ioremap_nocache(info->fb.base, + info->fb.size); + + if (!info->fb.vbase) + { + release_mem_region(info->mmio.base, info->mmio.size); + release_mem_region(info->fb.base, info->fb.size); + XGI_ERROR("info->fb.vbase failed\n"); + goto error_disable_dev; + } + */ + info->fb.vbase = NULL; + XGI_INFO("info->fb.vbase: 0x%p \n", info->fb.vbase); + + info->irq = dev->irq; + + /* check common error condition */ + if (info->irq == 0) + { + XGI_ERROR("Can't find an IRQ for your XGI card! \n"); + goto error_zero_dev; + } + XGI_INFO("info->irq: %lx \n", info->irq); + + //xgi_enable_dvi_interrupt(info); + + /* sanity check the IO apertures */ + if ((info->mmio.base == 0) || (info->mmio.size == 0) + || (info->fb.base == 0) || (info->fb.size == 0)) + { + XGI_ERROR("The IO regions for your XGI card are invalid.\n"); + + if ((info->mmio.base == 0) || (info->mmio.size == 0)) + { + XGI_ERROR("mmio appears to be wrong: 0x%lx 0x%lx\n", + info->mmio.base, + info->mmio.size); + } + + if ((info->fb.base == 0) || (info->fb.size == 0)) + { + XGI_ERROR("frame buffer appears to be wrong: 0x%lx 0x%lx\n", + info->fb.base, + info->fb.size); + } + + goto error_zero_dev; + } + + //xgi_num_devices++; + + return 0; + +error_zero_dev: + release_mem_region(info->fb.base, info->fb.size); + release_mem_region(info->mmio.base, info->mmio.size); + +error_disable_dev: + pci_disable_device(dev); + return -1; + +} + +/* + * vma operations... + * this is only called when the vmas are duplicated. this + * appears to only happen when the process is cloned to create + * a new process, and not when the process is threaded. + * + * increment the usage count for the physical pages, so when + * this clone unmaps the mappings, the pages are not + * deallocated under the original process. + */ +struct vm_operations_struct xgi_vm_ops = { + .open = xgi_kern_vma_open, + .close = xgi_kern_vma_release, + .nopage = xgi_kern_vma_nopage, +}; + +void xgi_kern_vma_open(struct vm_area_struct *vma) +{ + XGI_INFO("VM: vma_open for 0x%lx - 0x%lx, offset 0x%lx\n", + vma->vm_start, + vma->vm_end, + XGI_VMA_OFFSET(vma)); + + if (XGI_VMA_PRIVATE(vma)) + { + xgi_pcie_block_t *block = (xgi_pcie_block_t *)XGI_VMA_PRIVATE(vma); + XGI_ATOMIC_INC(block->use_count); + } +} + +void xgi_kern_vma_release(struct vm_area_struct *vma) +{ + XGI_INFO("VM: vma_release for 0x%lx - 0x%lx, offset 0x%lx\n", + vma->vm_start, + vma->vm_end, + XGI_VMA_OFFSET(vma)); + + if (XGI_VMA_PRIVATE(vma)) + { + xgi_pcie_block_t *block = (xgi_pcie_block_t *)XGI_VMA_PRIVATE(vma); + XGI_ATOMIC_DEC(block->use_count); + + /* + * if use_count is down to 0, the kernel virtual mapping was freed + * but the underlying physical pages were not, we need to clear the + * bit and free the physical pages. + */ + if (XGI_ATOMIC_READ(block->use_count) == 0) + { + // Need TO Finish + XGI_VMA_PRIVATE(vma) = NULL; + } + } +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 1)) +struct page *xgi_kern_vma_nopage(struct vm_area_struct *vma, + unsigned long address, int *type) +{ + xgi_pcie_block_t *block = (xgi_pcie_block_t *)XGI_VMA_PRIVATE(vma); + struct page *page = NOPAGE_SIGBUS; + unsigned long offset = 0; + unsigned long page_addr = 0; +/* + XGI_INFO("VM: mmap([0x%lx-0x%lx] off=0x%lx) address: 0x%lx \n", + vma->vm_start, + vma->vm_end, + XGI_VMA_OFFSET(vma), + address); +*/ + offset = (address - vma->vm_start) + XGI_VMA_OFFSET(vma); + + offset = offset - block->bus_addr; + + offset >>= PAGE_SHIFT; + + page_addr = block->page_table[offset].virt_addr; + + if (xgi_temp) + { + XGI_INFO("block->bus_addr: 0x%lx block->hw_addr: 0x%lx" + "block->page_count: 0x%lx block->page_order: 0x%lx" + "block->page_table[0x%lx].virt_addr: 0x%lx\n", + block->bus_addr, block->hw_addr, + block->page_count, block->page_order, + offset, + block->page_table[offset].virt_addr); + xgi_temp = 0; + } + + if (!page_addr) goto out; /* hole or end-of-file */ + page = virt_to_page(page_addr); + + /* got it, now increment the count */ + get_page(page); +out: + return page; + +} +#else +struct page *xgi_kern_vma_nopage(struct vm_area_struct *vma, + unsigned long address, int write_access) +{ + xgi_pcie_block_t *block = (xgi_pcie_block_t *)XGI_VMA_PRIVATE(vma); + struct page *page = NOPAGE_SIGBUS; + unsigned long offset = 0; + unsigned long page_addr = 0; +/* + XGI_INFO("VM: mmap([0x%lx-0x%lx] off=0x%lx) address: 0x%lx \n", + vma->vm_start, + vma->vm_end, + XGI_VMA_OFFSET(vma), + address); +*/ + offset = (address - vma->vm_start) + XGI_VMA_OFFSET(vma); + + offset = offset - block->bus_addr; + + offset >>= PAGE_SHIFT; + + page_addr = block->page_table[offset].virt_addr; + + if (xgi_temp) + { + XGI_INFO("block->bus_addr: 0x%lx block->hw_addr: 0x%lx" + "block->page_count: 0x%lx block->page_order: 0x%lx" + "block->page_table[0x%lx].virt_addr: 0x%lx\n", + block->bus_addr, block->hw_addr, + block->page_count, block->page_order, + offset, + block->page_table[offset].virt_addr); + xgi_temp = 0; + } + + if (!page_addr) goto out; /* hole or end-of-file */ + page = virt_to_page(page_addr); + + /* got it, now increment the count */ + get_page(page); +out: + return page; +} +#endif + +#if 0 +static struct file_operations xgi_fops = { + /* owner: THIS_MODULE, */ + poll: xgi_kern_poll, + ioctl: xgi_kern_ioctl, + mmap: xgi_kern_mmap, + open: xgi_kern_open, + release: xgi_kern_release, +}; +#endif + +static struct file_operations xgi_fops = { + .owner = THIS_MODULE, + .poll = xgi_kern_poll, + .ioctl = xgi_kern_ioctl, + .mmap = xgi_kern_mmap, + .open = xgi_kern_open, + .release = xgi_kern_release, +}; + +static xgi_file_private_t * xgi_alloc_file_private(void) +{ + xgi_file_private_t *fp; + + XGI_KMALLOC(fp, sizeof(xgi_file_private_t)); + if (!fp) + return NULL; + + memset(fp, 0, sizeof(xgi_file_private_t)); + + /* initialize this file's event queue */ + init_waitqueue_head(&fp->wait_queue); + + xgi_init_lock(fp->fp_lock); + + return fp; +} + +static void xgi_free_file_private(xgi_file_private_t *fp) +{ + if (fp == NULL) + return; + + XGI_KFREE(fp, sizeof(xgi_file_private_t)); +} + +int xgi_kern_open(struct inode *inode, struct file *filp) +{ + xgi_info_t *info = NULL; + int dev_num; + int result = 0, status; + + /* + * the type and num values are only valid if we are not using devfs. + * However, since we use them to retrieve the device pointer, we + * don't need them with devfs as filp->private_data is already + * initialized + */ + filp->private_data = xgi_alloc_file_private(); + if (filp->private_data == NULL) + return -ENOMEM; + + XGI_INFO("filp->private_data %p\n", filp->private_data); + /* + * for control device, just jump to its open routine + * after setting up the private data + */ + if (XGI_IS_CONTROL_DEVICE(inode)) + return xgi_kern_ctl_open(inode, filp); + + /* what device are we talking about? */ + dev_num = XGI_DEVICE_NUMBER(inode); + if (dev_num >= XGI_MAX_DEVICES) + { + xgi_free_file_private(filp->private_data); + filp->private_data = NULL; + return -ENODEV; + } + + info = &xgi_devices[dev_num]; + + XGI_INFO("Jong-xgi_kern_open on device %d\n", dev_num); + + xgi_down(info->info_sem); + XGI_CHECK_PCI_CONFIG(info); + + XGI_INFO_FROM_FP(filp) = info; + + /* + * map the memory and allocate isr on first open + */ + + if (!(info->flags & XGI_FLAG_OPEN)) + { + XGI_INFO("info->flags & XGI_FLAG_OPEN \n"); + + if (info->device_id == 0) + { + XGI_INFO("open of nonexistent device %d\n", dev_num); + result = -ENXIO; + goto failed; + } + + /* initialize struct irqaction */ + status = request_irq(info->irq, xgi_kern_isr, + SA_INTERRUPT | SA_SHIRQ, "xgi", + (void *) info); + if (status != 0) + { + if (info->irq && (status == -EBUSY)) + { + XGI_ERROR("Tried to get irq %d, but another driver", + (unsigned int) info->irq); + XGI_ERROR("has it and is not sharing it.\n"); + } + XGI_ERROR("isr request failed 0x%x\n", status); + result = -EIO; + goto failed; + } + + /* + * #define DECLARE_TASKLET(name, func, data) \ + * struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data } + */ + info->tasklet.func = xgi_kern_isr_bh; + info->tasklet.data = (unsigned long) info; + tasklet_enable(&info->tasklet); + + /* Alloc 1M bytes for cmdbuffer which is flush2D batch array */ + xgi_cmdlist_initialize(info, 0x100000); + + info->flags |= XGI_FLAG_OPEN; + } + + XGI_ATOMIC_INC(info->use_count); + +failed: + xgi_up(info->info_sem); + + if ((result) && filp->private_data) + { + xgi_free_file_private(filp->private_data); + filp->private_data = NULL; + } + + return result; +} + +int xgi_kern_release(struct inode *inode, struct file *filp) +{ + xgi_info_t *info = XGI_INFO_FROM_FP(filp); + + XGI_CHECK_PCI_CONFIG(info); + + /* + * for control device, just jump to its open routine + * after setting up the private data + */ + if (XGI_IS_CONTROL_DEVICE(inode)) + return xgi_kern_ctl_close(inode, filp); + + XGI_INFO("Jong-xgi_kern_release on device %d\n", XGI_DEVICE_NUMBER(inode)); + + xgi_down(info->info_sem); + if (XGI_ATOMIC_DEC_AND_TEST(info->use_count)) + { + + /* + * The usage count for this device has dropped to zero, it can be shut + * down safely; disable its interrupts. + */ + + /* + * Disable this device's tasklet to make sure that no bottom half will + * run with undefined device state. + */ + tasklet_disable(&info->tasklet); + + /* + * Free the IRQ, which may block until all pending interrupt processing + * has completed. + */ + free_irq(info->irq, (void *)info); + + xgi_cmdlist_cleanup(info); + + /* leave INIT flag alone so we don't reinit every time */ + info->flags &= ~XGI_FLAG_OPEN; + } + + xgi_up(info->info_sem); + + if (FILE_PRIVATE(filp)) + { + xgi_free_file_private(FILE_PRIVATE(filp)); + FILE_PRIVATE(filp) = NULL; + } + + return 0; +} + +int xgi_kern_mmap(struct file *filp, struct vm_area_struct *vma) +{ + //struct inode *inode = INODE_FROM_FP(filp); + xgi_info_t *info = XGI_INFO_FROM_FP(filp); + xgi_pcie_block_t *block; + int pages = 0; + unsigned long prot; + + XGI_INFO("Jong-VM: mmap([0x%lx-0x%lx] off=0x%lx)\n", + vma->vm_start, + vma->vm_end, + XGI_VMA_OFFSET(vma)); + + XGI_CHECK_PCI_CONFIG(info); + + if (XGI_MASK_OFFSET(vma->vm_start) + || XGI_MASK_OFFSET(vma->vm_end)) + { + XGI_ERROR("VM: bad mmap range: %lx - %lx\n", + vma->vm_start, vma->vm_end); + return -ENXIO; + } + + pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; + + vma->vm_ops = &xgi_vm_ops; + + /* XGI IO(reg) space */ + if (IS_IO_OFFSET(info, XGI_VMA_OFFSET(vma), vma->vm_end - vma->vm_start)) + { + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + if (XGI_REMAP_PAGE_RANGE(vma->vm_start, + XGI_VMA_OFFSET(vma), + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) + return -EAGAIN; + + /* mark it as IO so that we don't dump it on core dump */ + vma->vm_flags |= VM_IO; + XGI_INFO("VM: mmap io space \n"); + } + /* XGI fb space */ + /* Jong 06/14/2006; moved behind PCIE or modify IS_FB_OFFSET */ + else if (IS_FB_OFFSET(info, XGI_VMA_OFFSET(vma), vma->vm_end - vma->vm_start)) + { + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + if (XGI_REMAP_PAGE_RANGE(vma->vm_start, + XGI_VMA_OFFSET(vma), + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) + return -EAGAIN; + + // mark it as IO so that we don't dump it on core dump + vma->vm_flags |= VM_IO; + XGI_INFO("VM: mmap fb space \n"); + } + /* PCIE allocator */ + /* XGI_VMA_OFFSET(vma) is offset based on pcie.base (HW address space) */ + else if (IS_PCIE_OFFSET(info, XGI_VMA_OFFSET(vma), vma->vm_end - vma->vm_start)) + { + xgi_down(info->pcie_sem); + + block = (xgi_pcie_block_t *)xgi_find_pcie_block(info, XGI_VMA_OFFSET(vma)); + + if (block == NULL) + { + XGI_ERROR("couldn't find pre-allocated PCIE memory!\n"); + xgi_up(info->pcie_sem); + return -EAGAIN; + } + + if (block->page_count != pages) + { + XGI_ERROR("pre-allocated PCIE memory has wrong number of pages!\n"); + xgi_up(info->pcie_sem); + return -EAGAIN; + } + + vma->vm_private_data = block; + XGI_ATOMIC_INC(block->use_count); + xgi_up(info->pcie_sem); + + /* + * prevent the swapper from swapping it out + * mark the memory i/o so the buffers aren't + * dumped on core dumps */ + vma->vm_flags |= (VM_LOCKED | VM_IO); + + /* un-cached */ + prot = pgprot_val(vma->vm_page_prot); + /* + if (boot_cpu_data.x86 > 3) + prot |= _PAGE_PCD | _PAGE_PWT; + */ + vma->vm_page_prot = __pgprot(prot); + + XGI_INFO("VM: mmap pcie space \n"); + } +#if 0 + else if (IS_FB_OFFSET(info, XGI_VMA_OFFSET(vma), vma->vm_end - vma->vm_start)) + { + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + if (XGI_REMAP_PAGE_RANGE(vma->vm_start, + XGI_VMA_OFFSET(vma), + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) + return -EAGAIN; + + // mark it as IO so that we don't dump it on core dump + vma->vm_flags |= VM_IO; + XGI_INFO("VM: mmap fb space \n"); + } +#endif + else + { + vma->vm_flags |= (VM_IO | VM_LOCKED); + XGI_ERROR("VM: mmap wrong range \n"); + } + + vma->vm_file = filp; + + return 0; +} + +unsigned int xgi_kern_poll(struct file *filp, struct poll_table_struct *wait) +{ + xgi_file_private_t *fp; + xgi_info_t *info; + unsigned int mask = 0; + unsigned long eflags; + + info = XGI_INFO_FROM_FP(filp); + + if (info->device_number == XGI_CONTROL_DEVICE_NUMBER) + return xgi_kern_ctl_poll(filp, wait); + + fp = XGI_GET_FP(filp); + + if (!(filp->f_flags & O_NONBLOCK)) + { + /* add us to the list */ + poll_wait(filp, &fp->wait_queue, wait); + } + + xgi_lock_irqsave(fp->fp_lock, eflags); + + /* wake the user on any event */ + if (fp->num_events) + { + XGI_INFO("Hey, an event occured!\n"); + /* + * trigger the client, when they grab the event, + * we'll decrement the event count + */ + mask |= (POLLPRI|POLLIN); + } + xgi_unlock_irqsave(fp->fp_lock, eflags); + + return mask; +} + +int xgi_kern_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + xgi_info_t *info; + xgi_mem_alloc_t *alloc = NULL; + + int status = 0; + void *arg_copy; + int arg_size; + int err = 0; + + info = XGI_INFO_FROM_FP(filp); + + XGI_INFO("Jong-ioctl(0x%x, 0x%x, 0x%lx, 0x%x)\n", _IOC_TYPE(cmd), _IOC_NR(cmd), arg, _IOC_SIZE(cmd)); + /* + * extract the type and number bitfields, and don't decode + * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok() + */ + if (_IOC_TYPE(cmd) != XGI_IOCTL_MAGIC) return -ENOTTY; + if (_IOC_NR(cmd) > XGI_IOCTL_MAXNR) return -ENOTTY; + + /* + * the direction is a bitmask, and VERIFY_WRITE catches R/W + * transfers. `Type' is user-oriented, while + * access_ok is kernel-oriented, so the concept of "read" and + * "write" is reversed + */ + if (_IOC_DIR(cmd) & _IOC_READ) + { + err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd)); + } + else if (_IOC_DIR(cmd) & _IOC_WRITE) + { + err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd)); + } + if (err) return -EFAULT; + + XGI_CHECK_PCI_CONFIG(info); + + arg_size = _IOC_SIZE(cmd); + XGI_KMALLOC(arg_copy, arg_size); + if (arg_copy == NULL) + { + XGI_ERROR("failed to allocate ioctl memory\n"); + return -ENOMEM; + } + + /* Jong 05/25/2006 */ + /* copy_from_user(arg_copy, (void *)arg, arg_size); */ + if(copy_from_user(arg_copy, (void *)arg, arg_size)) + { + XGI_ERROR("failed to copyin ioctl data\n"); + XGI_INFO("Jong-copy_from_user-fail! \n"); + } + else + XGI_INFO("Jong-copy_from_user-OK! \n"); + + alloc = (xgi_mem_alloc_t *)arg_copy; + XGI_INFO("Jong-succeeded in copy_from_user 0x%lx, 0x%x bytes.\n", arg, arg_size); + + switch (_IOC_NR(cmd)) + { + case XGI_ESC_DEVICE_INFO: + XGI_INFO("Jong-xgi_ioctl_get_device_info \n"); + xgi_get_device_info(info, (struct xgi_chip_info_s *) arg_copy); + break; + case XGI_ESC_POST_VBIOS: + XGI_INFO("Jong-xgi_ioctl_post_vbios \n"); + break; + case XGI_ESC_FB_ALLOC: + XGI_INFO("Jong-xgi_ioctl_fb_alloc \n"); + xgi_fb_alloc(info, (struct xgi_mem_req_s *)arg_copy, alloc); + break; + case XGI_ESC_FB_FREE: + XGI_INFO("Jong-xgi_ioctl_fb_free \n"); + xgi_fb_free(info, *(unsigned long *) arg_copy); + break; + case XGI_ESC_MEM_COLLECT: + XGI_INFO("Jong-xgi_ioctl_mem_collect \n"); + xgi_mem_collect(info, (unsigned int *) arg_copy); + break; + case XGI_ESC_PCIE_ALLOC: + XGI_INFO("Jong-xgi_ioctl_pcie_alloc \n"); + xgi_pcie_alloc(info, ((xgi_mem_req_t *)arg_copy)->size, + ((xgi_mem_req_t *)arg_copy)->owner, alloc); + break; + case XGI_ESC_PCIE_FREE: + XGI_INFO("Jong-xgi_ioctl_pcie_free: bus_addr = 0x%lx \n", *((unsigned long *) arg_copy)); + xgi_pcie_free(info, *((unsigned long *) arg_copy)); + break; + case XGI_ESC_PCIE_CHECK: + XGI_INFO("Jong-xgi_pcie_heap_check \n"); + xgi_pcie_heap_check(); + break; + case XGI_ESC_GET_SCREEN_INFO: + XGI_INFO("Jong-xgi_get_screen_info \n"); + xgi_get_screen_info(info, (struct xgi_screen_info_s *) arg_copy); + break; + case XGI_ESC_PUT_SCREEN_INFO: + XGI_INFO("Jong-xgi_put_screen_info \n"); + xgi_put_screen_info(info, (struct xgi_screen_info_s *) arg_copy); + break; + case XGI_ESC_MMIO_INFO: + XGI_INFO("Jong-xgi_ioctl_get_mmio_info \n"); + xgi_get_mmio_info(info, (struct xgi_mmio_info_s *) arg_copy); + break; + case XGI_ESC_GE_RESET: + XGI_INFO("Jong-xgi_ioctl_ge_reset \n"); + xgi_ge_reset(info); + break; + case XGI_ESC_SAREA_INFO: + XGI_INFO("Jong-xgi_ioctl_sarea_info \n"); + xgi_sarea_info(info, (struct xgi_sarea_info_s *) arg_copy); + break; + case XGI_ESC_DUMP_REGISTER: + XGI_INFO("Jong-xgi_ioctl_dump_register \n"); + xgi_dump_register(info); + break; + case XGI_ESC_DEBUG_INFO: + XGI_INFO("Jong-xgi_ioctl_restore_registers \n"); + xgi_restore_registers(info); + //xgi_write_pcie_mem(info, (struct xgi_mem_req_s *) arg_copy); + //xgi_read_pcie_mem(info, (struct xgi_mem_req_s *) arg_copy); + break; + case XGI_ESC_SUBMIT_CMDLIST: + XGI_INFO("Jong-xgi_ioctl_submit_cmdlist \n"); + xgi_submit_cmdlist(info, (xgi_cmd_info_t *) arg_copy); + break; + case XGI_ESC_TEST_RWINKERNEL: + XGI_INFO("Jong-xgi_test_rwinkernel \n"); + xgi_test_rwinkernel(info, *(unsigned long*) arg_copy); + break; + case XGI_ESC_STATE_CHANGE: + XGI_INFO("Jong-xgi_state_change \n"); + xgi_state_change(info, (xgi_state_info_t *) arg_copy); + break; + case XGI_ESC_CPUID: + XGI_INFO("Jong-XGI_ESC_CPUID \n"); + xgi_get_cpu_id((struct cpu_info_s*) arg_copy); + break; + default: + XGI_INFO("Jong-xgi_ioctl_default \n"); + status = -EINVAL; + break; + } + + if (copy_to_user((void *)arg, arg_copy, arg_size)) + { + XGI_ERROR("failed to copyout ioctl data\n"); + XGI_INFO("Jong-copy_to_user-fail! \n"); + } + else + XGI_INFO("Jong-copy_to_user-OK! \n"); + + XGI_KFREE(arg_copy, arg_size); + return status; +} + + +/* + * xgi control driver operations defined here + */ +int xgi_kern_ctl_open(struct inode *inode, struct file *filp) +{ + xgi_info_t *info = &xgi_ctl_device; + + int rc = 0; + + XGI_INFO("Jong-xgi_kern_ctl_open\n"); + + xgi_down(info->info_sem); + info->device_number = XGI_CONTROL_DEVICE_NUMBER; + + /* save the xgi info in file->private_data */ + filp->private_data = info; + + if (XGI_ATOMIC_READ(info->use_count) == 0) + { + init_waitqueue_head(&xgi_ctl_waitqueue); + } + + info->flags |= XGI_FLAG_OPEN + XGI_FLAG_CONTROL; + + XGI_ATOMIC_INC(info->use_count); + xgi_up(info->info_sem); + + return rc; +} + +int xgi_kern_ctl_close(struct inode *inode, struct file *filp) +{ + xgi_info_t *info = XGI_INFO_FROM_FP(filp); + + XGI_INFO("Jong-xgi_kern_ctl_close\n"); + + xgi_down(info->info_sem); + if (XGI_ATOMIC_DEC_AND_TEST(info->use_count)) + { + info->flags = 0; + } + xgi_up(info->info_sem); + + if (FILE_PRIVATE(filp)) + { + xgi_free_file_private(FILE_PRIVATE(filp)); + FILE_PRIVATE(filp) = NULL; + } + + return 0; +} + +unsigned int xgi_kern_ctl_poll(struct file *filp, poll_table *wait) +{ + //xgi_info_t *info = XGI_INFO_FROM_FP(filp);; + unsigned int ret = 0; + + if (!(filp->f_flags & O_NONBLOCK)) + { + poll_wait(filp, &xgi_ctl_waitqueue, wait); + } + + return ret; +} + +/* + * xgi proc system + */ +static u8 xgi_find_pcie_capability(struct pci_dev *dev) +{ + u16 status; + u8 cap_ptr, cap_id; + + pci_read_config_word(dev, PCI_STATUS, &status); + status &= PCI_STATUS_CAP_LIST; + if (!status) + return 0; + + switch (dev->hdr_type) + { + case PCI_HEADER_TYPE_NORMAL: + case PCI_HEADER_TYPE_BRIDGE: + pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &cap_ptr); + break; + default: + return 0; + } + + do + { + cap_ptr &= 0xFC; + pci_read_config_byte(dev, cap_ptr + PCI_CAP_LIST_ID, &cap_id); + pci_read_config_byte(dev, cap_ptr + PCI_CAP_LIST_NEXT, &cap_ptr); + } while (cap_ptr && cap_id != 0xFF); + + return 0; +} + +static struct pci_dev* xgi_get_pci_device(xgi_info_t *info) +{ + struct pci_dev *dev; + + dev = XGI_PCI_GET_DEVICE(info->vendor_id, info->device_id, NULL); + while (dev) + { + if (XGI_PCI_SLOT_NUMBER(dev) == info->slot + && XGI_PCI_BUS_NUMBER(dev) == info->bus) + return dev; + dev = XGI_PCI_GET_DEVICE(info->vendor_id, info->device_id, dev); + } + + return NULL; +} + +int xgi_kern_read_card_info(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct pci_dev *dev; + char *type; + int len = 0; + + xgi_info_t *info; + info = (xgi_info_t *) data; + + dev = xgi_get_pci_device(info); + if (!dev) + return 0; + + type = xgi_find_pcie_capability(dev) ? "PCIE" : "PCI"; + len += sprintf(page+len, "Card Type: \t %s\n", type); + + XGI_PCI_DEV_PUT(dev); + return len; +} + +int xgi_kern_read_version(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = 0; + + len += sprintf(page+len, "XGI version: %s\n", "1.0"); + len += sprintf(page+len, "GCC version: %s\n", "3.0"); + + return len; +} + +int xgi_kern_read_pcie_info(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + return 0; +} + +int xgi_kern_read_status(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + return 0; +} + + +static void xgi_proc_create(void) +{ +#ifdef CONFIG_PROC_FS + + struct pci_dev *dev; + int i = 0; + char name[6]; + + struct proc_dir_entry *entry; + struct proc_dir_entry *proc_xgi_pcie, *proc_xgi_cards; + + xgi_info_t *info; + xgi_info_t *xgi_max_devices; + + /* world readable directory */ + int flags = S_IFDIR | S_IRUGO | S_IXUGO; + + proc_xgi = create_proc_entry("xgi", flags, proc_root_driver); + if (!proc_xgi) + goto failed; + + proc_xgi_cards = create_proc_entry("cards", flags, proc_xgi); + if (!proc_xgi_cards) + goto failed; + + proc_xgi_pcie = create_proc_entry("pcie", flags, proc_xgi); + if (!proc_xgi_pcie) + goto failed; + + /* + * Set the module owner to ensure that the reference + * count reflects accesses to the proc files. + */ + proc_xgi->owner = THIS_MODULE; + proc_xgi_cards->owner = THIS_MODULE; + proc_xgi_pcie->owner = THIS_MODULE; + + xgi_max_devices = xgi_devices + XGI_MAX_DEVICES; + for (info = xgi_devices; info < xgi_max_devices; info++) + { + if (info->device_id == 0) + break; + + /* world readable file */ + flags = S_IFREG | S_IRUGO; + + dev = xgi_get_pci_device(info); + if (!dev) + break; + + sprintf(name, "%d", i++); + entry = create_proc_entry(name, flags, proc_xgi_cards); + if (!entry) + { + XGI_PCI_DEV_PUT(dev); + goto failed; + } + + entry->data = info; + entry->read_proc = xgi_kern_read_card_info; + entry->owner = THIS_MODULE; + + if (xgi_find_pcie_capability(dev)) + { + entry = create_proc_entry("status", flags, proc_xgi_pcie); + if (!entry) + { + XGI_PCI_DEV_PUT(dev); + goto failed; + } + + entry->data = info; + entry->read_proc = xgi_kern_read_status; + entry->owner = THIS_MODULE; + + entry = create_proc_entry("card", flags, proc_xgi_pcie); + if (!entry) + { + XGI_PCI_DEV_PUT(dev); + goto failed; + } + + entry->data = info; + entry->read_proc = xgi_kern_read_pcie_info; + entry->owner = THIS_MODULE; + } + + XGI_PCI_DEV_PUT(dev); + } + + entry = create_proc_entry("version", flags, proc_xgi); + if (!entry) + goto failed; + + entry->read_proc = xgi_kern_read_version; + entry->owner = THIS_MODULE; + + entry = create_proc_entry("host-bridge", flags, proc_xgi_pcie); + if (!entry) + goto failed; + + entry->data = NULL; + entry->read_proc = xgi_kern_read_pcie_info; + entry->owner = THIS_MODULE; + + return; + +failed: + XGI_ERROR("failed to create /proc entries!\n"); + xgi_proc_remove_all(proc_xgi); +#endif +} + +#ifdef CONFIG_PROC_FS +static void xgi_proc_remove_all(struct proc_dir_entry *entry) +{ + while (entry) + { + struct proc_dir_entry *next = entry->next; + if (entry->subdir) + xgi_proc_remove_all(entry->subdir); + remove_proc_entry(entry->name, entry->parent); + if (entry == proc_xgi) + break; + entry = next; + } +} +#endif + +static void xgi_proc_remove(void) +{ +#ifdef CONFIG_PROC_FS + xgi_proc_remove_all(proc_xgi); +#endif +} + +/* + * driver receives an interrupt if someone waiting, then hand it off. + */ +irqreturn_t xgi_kern_isr(int irq, void *dev_id, struct pt_regs *regs) +{ + xgi_info_t *info = (xgi_info_t *) dev_id; + u32 need_to_run_bottom_half = 0; + + //XGI_INFO("xgi_kern_isr \n"); + + //XGI_CHECK_PCI_CONFIG(info); + + //xgi_dvi_irq_handler(info); + + if (need_to_run_bottom_half) + { + tasklet_schedule(&info->tasklet); + } + + return IRQ_HANDLED; +} + +void xgi_kern_isr_bh(unsigned long data) +{ + xgi_info_t *info = (xgi_info_t *) data; + + XGI_INFO("xgi_kern_isr_bh \n"); + + //xgi_dvi_irq_handler(info); + + XGI_CHECK_PCI_CONFIG(info); +} + +static void xgi_lock_init(xgi_info_t *info) +{ + if (info == NULL) return; + + spin_lock_init(&info->info_lock); + + sema_init(&info->info_sem, 1); + sema_init(&info->fb_sem, 1); + sema_init(&info->pcie_sem, 1); + + XGI_ATOMIC_SET(info->use_count, 0); +} + +static void xgi_dev_init(xgi_info_t *info) +{ + struct pci_dev *pdev = NULL; + struct xgi_dev *dev; + int found = 0; + u16 pci_cmd; + + XGI_INFO("Enter xgi_dev_init \n"); + + //XGI_PCI_FOR_EACH_DEV(pdev) + { + for (dev = xgidev_list; dev->vendor; dev++) + { + if ((dev->vendor == pdev->vendor) && (dev->device == pdev->device)) + { + XGI_INFO("dev->vendor = pdev->vendor= %x \n", dev->vendor); + XGI_INFO("dev->device = pdev->device= %x \n", dev->device); + + xgi_devices[found].device_id = pdev->device; + + pci_read_config_byte(pdev, PCI_REVISION_ID, &xgi_devices[found].revision_id); + + XGI_INFO("PCI_REVISION_ID= %x \n", xgi_devices[found].revision_id); + + pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd); + + XGI_INFO("PCI_COMMAND = %x \n", pci_cmd); + + break; + } + } + } +} +/* + * Export to Linux Kernel + */ + +static int __init xgi_init_module(void) +{ + xgi_info_t *info = &xgi_devices[xgi_num_devices]; + int i, result; + + XGI_INFO("Jong-xgi kernel driver %s initializing\n", XGI_DRV_VERSION); + //SET_MODULE_OWNER(&xgi_fops); + + memset(xgi_devices, 0, sizeof(xgi_devices)); + + if (pci_register_driver(&xgi_pci_driver) < 0) + { + pci_unregister_driver(&xgi_pci_driver); + XGI_ERROR("no XGI graphics adapter found\n"); + return -ENODEV; + } + + XGI_INFO("Jong-xgi_devices[%d].fb.base.: 0x%lx \n", xgi_num_devices, xgi_devices[xgi_num_devices].fb.base); + XGI_INFO("Jong-xgi_devices[%d].fb.size.: 0x%lx \n", xgi_num_devices, xgi_devices[xgi_num_devices].fb.size); + +/* Jong 07/27/2006; test for ubuntu */ +/* +#ifdef CONFIG_DEVFS_FS + + XGI_INFO("Jong-Use devfs \n"); + do + { + xgi_devfs_handles[0] = XGI_DEVFS_REGISTER("xgi", 0); + if (xgi_devfs_handles[0] == NULL) + { + result = -ENOMEM; + XGI_ERROR("devfs register failed\n"); + goto failed; + } + } while(0); +#else */ /* no devfs, do it the "classic" way */ + + + XGI_INFO("Jong-Use non-devfs \n"); + /* + * Register your major, and accept a dynamic number. This is the + * first thing to do, in order to avoid releasing other module's + * fops in scull_cleanup_module() + */ + result = XGI_REGISTER_CHRDEV(xgi_major, "xgi", &xgi_fops); + if (result < 0) + { + XGI_ERROR("register chrdev failed\n"); + pci_unregister_driver(&xgi_pci_driver); + return result; + } + if (xgi_major == 0) xgi_major = result; /* dynamic */ + +/* #endif */ /* CONFIG_DEVFS_FS */ + + XGI_INFO("Jong-major number %d\n", xgi_major); + + /* instantiate tasklets */ + for (i = 0; i < XGI_MAX_DEVICES; i++) + { + /* + * We keep one tasklet per card to avoid latency issues with more + * than one device; no two instances of a single tasklet are ever + * executed concurrently. + */ + XGI_ATOMIC_SET(xgi_devices[i].tasklet.count, 1); + } + + /* init the xgi control device */ + { + xgi_info_t *info_ctl = &xgi_ctl_device; + xgi_lock_init(info_ctl); + } + + /* Init the resource manager */ + INIT_LIST_HEAD(&xgi_mempid_list); + if (!xgi_fb_heap_init(info)) + { + XGI_ERROR("xgi_fb_heap_init() failed\n"); + result = -EIO; + goto failed; + } + + /* Init the resource manager */ + if (!xgi_pcie_heap_init(info)) + { + XGI_ERROR("xgi_pcie_heap_init() failed\n"); + result = -EIO; + goto failed; + } + + /* create /proc/driver/xgi */ + xgi_proc_create(); + +#if defined(DEBUG) + inter_module_register("xgi_devices", THIS_MODULE, xgi_devices); +#endif + + return 0; + +failed: +#ifdef CONFIG_DEVFS_FS + XGI_DEVFS_REMOVE_CONTROL(); + XGI_DEVFS_REMOVE_DEVICE(xgi_num_devices); +#endif + + if (XGI_UNREGISTER_CHRDEV(xgi_major, "xgi") < 0) + XGI_ERROR("unregister xgi chrdev failed\n"); + + for (i = 0; i < xgi_num_devices; i++) + { + if (xgi_devices[i].dev) + { + release_mem_region(xgi_devices[i].fb.base, xgi_devices[i].fb.size); + release_mem_region(xgi_devices[i].mmio.base, xgi_devices[i].mmio.size); + } + } + + pci_unregister_driver(&xgi_pci_driver); + return result; + + return 1; +} + +void __exit xgi_exit_module(void) +{ + int i; + xgi_info_t *info, *max_devices; + +#ifdef CONFIG_DEVFS_FS + /* + XGI_DEVFS_REMOVE_CONTROL(); + for (i = 0; i < XGI_MAX_DEVICES; i++) + XGI_DEVFS_REMOVE_DEVICE(i); + */ + XGI_DEVFS_REMOVE_DEVICE(xgi_num_devices); +#endif + + if (XGI_UNREGISTER_CHRDEV(xgi_major, "xgi") < 0) + XGI_ERROR("unregister xgi chrdev failed\n"); + + XGI_INFO("Jong-unregister xgi chrdev scceeded\n"); + for (i = 0; i < XGI_MAX_DEVICES; i++) + { + if (xgi_devices[i].dev) + { + /* clean up the flush2D batch array */ + xgi_cmdlist_cleanup(&xgi_devices[i]); + + if(xgi_devices[i].fb.vbase != NULL) + { + iounmap((void *)xgi_devices[i].fb.vbase); + xgi_devices[i].fb.vbase = NULL; + } + if(xgi_devices[i].mmio.vbase != NULL) + { + iounmap((void *)xgi_devices[i].mmio.vbase); + xgi_devices[i].mmio.vbase = NULL; + } + + //release_mem_region(xgi_devices[i].fb.base, xgi_devices[i].fb.size); + //XGI_INFO("release frame buffer mem region scceeded\n"); + + release_mem_region(xgi_devices[i].mmio.base, xgi_devices[i].mmio.size); + XGI_INFO("release MMIO mem region scceeded\n"); + + xgi_fb_heap_cleanup(&xgi_devices[i]); + XGI_INFO("xgi_fb_heap_cleanup scceeded\n"); + + xgi_pcie_heap_cleanup(&xgi_devices[i]); + XGI_INFO("xgi_pcie_heap_cleanup scceeded\n"); + + XGI_PCI_DISABLE_DEVICE(xgi_devices[i].dev); + } + } + + pci_unregister_driver(&xgi_pci_driver); + + /* remove /proc/driver/xgi */ + xgi_proc_remove(); + +#if defined(DEBUG) + inter_module_unregister("xgi_devices"); +#endif +} + +module_init(xgi_init_module); +module_exit(xgi_exit_module); + +#if defined(XGI_PM_SUPPORT_ACPI) +int xgi_acpi_event(struct pci_dev *dev, u32 state) +{ + return 1; +} + +int xgi_kern_acpi_standby(struct pci_dev *dev, u32 state) +{ + return 1; +} + +int xgi_kern_acpi_resume(struct pci_dev *dev) +{ + return 1; +} +#endif + +MODULE_AUTHOR("Andrea Zhang "); +MODULE_DESCRIPTION("xgi kernel driver for xgi cards"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 434657a2582362367ba2a94f827511252001368f Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Tue, 26 Jun 2007 13:10:30 -0700 Subject: dos2unix and Lindent --- linux-core/xgi_drv.c | 3174 +++++++++++++++++++++++++------------------------- 1 file changed, 1564 insertions(+), 1610 deletions(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index 5e80d417..0c37d00e 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -1,1610 +1,1564 @@ - -/**************************************************************************** - * Copyright (C) 2003-2006 by XGI Technology, Taiwan. - * * - * All Rights Reserved. * - * * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation on the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NON-INFRINGEMENT. IN NO EVENT SHALL XGI AND/OR - * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. - ***************************************************************************/ -#include "xgi_types.h" -#include "xgi_linux.h" -#include "xgi_drv.h" -#include "xgi_regs.h" -#include "xgi_pcie.h" -#include "xgi_misc.h" -#include "xgi_cmdlist.h" - -/* for debug */ -static int xgi_temp = 1; -/* - * global parameters - */ -static struct xgi_dev { - u16 vendor; - u16 device; - const char *name; -} xgidev_list[] = { - {PCI_VENDOR_ID_XGI, PCI_DEVICE_ID_XP5, "XP5"}, - {PCI_VENDOR_ID_XGI, PCI_DEVICE_ID_XG47, "XG47"}, - {0, 0, NULL} -}; - -int xgi_major = XGI_DEV_MAJOR; /* xgi reserved major device number. */ - -static int xgi_num_devices = 0; - -xgi_info_t xgi_devices[XGI_MAX_DEVICES]; - -#if defined(XGI_PM_SUPPORT_APM) -static struct pm_dev *apm_xgi_dev[XGI_MAX_DEVICES] = { 0 }; -#endif - -/* add one for the control device */ -xgi_info_t xgi_ctl_device; -wait_queue_head_t xgi_ctl_waitqueue; - -#ifdef CONFIG_PROC_FS -struct proc_dir_entry *proc_xgi; -#endif - -#ifdef CONFIG_DEVFS_FS -devfs_handle_t xgi_devfs_handles[XGI_MAX_DEVICES]; -#endif - -struct list_head xgi_mempid_list; - -/* xgi_ functions.. do not take a state device parameter */ -static int xgi_post_vbios(xgi_ioctl_post_vbios_t *info); -static void xgi_proc_create(void); -static void xgi_proc_remove_all(struct proc_dir_entry *); -static void xgi_proc_remove(void); - -/* xgi_kern_ functions, interfaces used by linux kernel */ -int xgi_kern_probe(struct pci_dev *, const struct pci_device_id *); - -unsigned int xgi_kern_poll(struct file *, poll_table *); -int xgi_kern_ioctl(struct inode *, struct file *, unsigned int, unsigned long); -int xgi_kern_mmap(struct file *, struct vm_area_struct *); -int xgi_kern_open(struct inode *, struct file *); -int xgi_kern_release(struct inode *inode, struct file *filp); - -void xgi_kern_vma_open(struct vm_area_struct *vma); -void xgi_kern_vma_release(struct vm_area_struct *vma); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 1)) -struct page *xgi_kern_vma_nopage(struct vm_area_struct *vma, - unsigned long address, int *type); -#else -struct page *xgi_kern_vma_nopage(struct vm_area_struct *vma, - unsigned long address, int write_access); -#endif - -int xgi_kern_read_card_info(char *, char **, off_t off, int, int *, void *); -int xgi_kern_read_status(char *, char **, off_t off, int, int *, void *); -int xgi_kern_read_pcie_info(char *, char **, off_t off, int, int *, void *); -int xgi_kern_read_version(char *, char **, off_t off, int, int *, void *); - -int xgi_kern_ctl_open(struct inode *, struct file *); -int xgi_kern_ctl_close(struct inode *, struct file *); -unsigned int xgi_kern_ctl_poll(struct file *, poll_table *); - -void xgi_kern_isr_bh(unsigned long); -irqreturn_t xgi_kern_isr(int, void *, struct pt_regs *); - -static void xgi_lock_init(xgi_info_t *info); - -#if defined(XGI_PM_SUPPORT_ACPI) -int xgi_kern_acpi_standby(struct pci_dev *, u32); -int xgi_kern_acpi_resume(struct pci_dev *); -#endif - -/* - * verify access to pci config space wasn't disabled behind our back - * unfortunately, XFree86 enables/disables memory access in pci config space at - * various times (such as restoring initial pci config space settings during vt - * switches or when doing mulicard). As a result, all of our register accesses - * are garbage at this point. add a check to see if access was disabled and - * reenable any such access. - */ -#define XGI_CHECK_PCI_CONFIG(xgi) \ - xgi_check_pci_config(xgi, __LINE__) - -static inline void xgi_check_pci_config(xgi_info_t *info, int line) -{ - unsigned short cmd, flag = 0; - - // don't do this on the control device, only the actual devices - if (info->flags & XGI_FLAG_CONTROL) - return; - - pci_read_config_word(info->dev, PCI_COMMAND, &cmd); - if (!(cmd & PCI_COMMAND_MASTER)) - { - XGI_INFO("restoring bus mastering! (%d)\n", line); - cmd |= PCI_COMMAND_MASTER; - flag = 1; - } - - if (!(cmd & PCI_COMMAND_MEMORY)) - { - XGI_INFO("restoring MEM access! (%d)\n", line); - cmd |= PCI_COMMAND_MEMORY; - flag = 1; - } - - if (flag) - pci_write_config_word(info->dev, PCI_COMMAND, cmd); -} - -static int xgi_post_vbios(xgi_ioctl_post_vbios_t *info) -{ - return 1; -} - -/* - * struct pci_device_id { - * unsigned int vendor, device; // Vendor and device ID or PCI_ANY_ID - * unsigned int subvendor, subdevice; // Subsystem ID's or PCI_ANY_ID - * unsigned int class, class_mask; // (class,subclass,prog-if) triplet - * unsigned long driver_data; // Data private to the driver - * }; - */ - -static struct pci_device_id xgi_dev_table[] = { - { - .vendor = PCI_VENDOR_ID_XGI, - .device = PCI_ANY_ID, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .class = (PCI_CLASS_DISPLAY_VGA << 8), - .class_mask = ~0, - }, - { } -}; - -/* - * #define MODULE_DEVICE_TABLE(type,name) \ - * MODULE_GENERIC_TABLE(type##_device,name) - */ - MODULE_DEVICE_TABLE(pci, xgi_dev_table); - -/* - * struct pci_driver { - * struct list_head node; - * char *name; - * const struct pci_device_id *id_table; // NULL if wants all devices - * int (*probe)(struct pci_dev *dev, const struct pci_device_id *id); // New device inserted - * void (*remove)(struct pci_dev *dev); // Device removed (NULL if not a hot-plug capable driver) - * int (*save_state)(struct pci_dev *dev, u32 state); // Save Device Context - * int (*suspend)(struct pci_dev *dev, u32 state); // Device suspended - * int (*resume)(struct pci_dev *dev); // Device woken up - * int (*enable_wake)(struct pci_dev *dev, u32 state, int enable); // Enable wake event - * }; - */ -static struct pci_driver xgi_pci_driver = { - .name = "xgi", - .id_table = xgi_dev_table, - .probe = xgi_kern_probe, -#if defined(XGI_SUPPORT_ACPI) - .suspend = xgi_kern_acpi_standby, - .resume = xgi_kern_acpi_resume, -#endif -}; - -/* - * find xgi devices and set initial state - */ -int xgi_kern_probe(struct pci_dev *dev, const struct pci_device_id *id_table) -{ - xgi_info_t *info; - - if ((dev->vendor != PCI_VENDOR_ID_XGI) - || (dev->class != (PCI_CLASS_DISPLAY_VGA << 8))) - { - return -1; - } - - if (xgi_num_devices == XGI_MAX_DEVICES) - { - XGI_INFO("maximum device number (%d) reached!\n", xgi_num_devices); - return -1; - } - - /* enable io, mem, and bus-mastering in pci config space */ - if (pci_enable_device(dev) != 0) - { - XGI_INFO("pci_enable_device failed, aborting\n"); - return -1; - } - - XGI_INFO("maximum device number (%d) reached \n", xgi_num_devices); - - pci_set_master(dev); - - info = &xgi_devices[xgi_num_devices]; - info->dev = dev; - info->vendor_id = dev->vendor; - info->device_id = dev->device; - info->bus = dev->bus->number; - info->slot = PCI_SLOT((dev)->devfn); - - xgi_lock_init(info); - - info->mmio.base = XGI_PCI_RESOURCE_START(dev, 1); - info->mmio.size = XGI_PCI_RESOURCE_SIZE(dev, 1); - - /* check IO region */ - if (!request_mem_region(info->mmio.base, info->mmio.size, "xgi")) - { - XGI_ERROR("cannot reserve MMIO memory\n"); - goto error_disable_dev; - } - - XGI_INFO("info->mmio.base: 0x%lx \n", info->mmio.base); - XGI_INFO("info->mmio.size: 0x%lx \n", info->mmio.size); - - info->mmio.vbase = (unsigned char *)ioremap_nocache(info->mmio.base, - info->mmio.size); - if (!info->mmio.vbase) - { - release_mem_region(info->mmio.base, info->mmio.size); - XGI_ERROR("info->mmio.vbase failed\n"); - goto error_disable_dev; - } - xgi_enable_mmio(info); - - //xgi_enable_ge(info); - - XGI_INFO("info->mmio.vbase: 0x%p \n", info->mmio.vbase); - - info->fb.base = XGI_PCI_RESOURCE_START(dev, 0); - info->fb.size = XGI_PCI_RESOURCE_SIZE(dev, 0); - - XGI_INFO("info->fb.base: 0x%lx \n", info->fb.base); - XGI_INFO("info->fb.size: 0x%lx \n", info->fb.size); - - info->fb.size = bIn3cf(0x54) * 8 * 1024 * 1024; - XGI_INFO("info->fb.size: 0x%lx \n", info->fb.size); - - /* check frame buffer region - if (!request_mem_region(info->fb.base, info->fb.size, "xgi")) - { - release_mem_region(info->mmio.base, info->mmio.size); - XGI_ERROR("cannot reserve frame buffer memory\n"); - goto error_disable_dev; - } - - - info->fb.vbase = (unsigned char *)ioremap_nocache(info->fb.base, - info->fb.size); - - if (!info->fb.vbase) - { - release_mem_region(info->mmio.base, info->mmio.size); - release_mem_region(info->fb.base, info->fb.size); - XGI_ERROR("info->fb.vbase failed\n"); - goto error_disable_dev; - } - */ - info->fb.vbase = NULL; - XGI_INFO("info->fb.vbase: 0x%p \n", info->fb.vbase); - - info->irq = dev->irq; - - /* check common error condition */ - if (info->irq == 0) - { - XGI_ERROR("Can't find an IRQ for your XGI card! \n"); - goto error_zero_dev; - } - XGI_INFO("info->irq: %lx \n", info->irq); - - //xgi_enable_dvi_interrupt(info); - - /* sanity check the IO apertures */ - if ((info->mmio.base == 0) || (info->mmio.size == 0) - || (info->fb.base == 0) || (info->fb.size == 0)) - { - XGI_ERROR("The IO regions for your XGI card are invalid.\n"); - - if ((info->mmio.base == 0) || (info->mmio.size == 0)) - { - XGI_ERROR("mmio appears to be wrong: 0x%lx 0x%lx\n", - info->mmio.base, - info->mmio.size); - } - - if ((info->fb.base == 0) || (info->fb.size == 0)) - { - XGI_ERROR("frame buffer appears to be wrong: 0x%lx 0x%lx\n", - info->fb.base, - info->fb.size); - } - - goto error_zero_dev; - } - - //xgi_num_devices++; - - return 0; - -error_zero_dev: - release_mem_region(info->fb.base, info->fb.size); - release_mem_region(info->mmio.base, info->mmio.size); - -error_disable_dev: - pci_disable_device(dev); - return -1; - -} - -/* - * vma operations... - * this is only called when the vmas are duplicated. this - * appears to only happen when the process is cloned to create - * a new process, and not when the process is threaded. - * - * increment the usage count for the physical pages, so when - * this clone unmaps the mappings, the pages are not - * deallocated under the original process. - */ -struct vm_operations_struct xgi_vm_ops = { - .open = xgi_kern_vma_open, - .close = xgi_kern_vma_release, - .nopage = xgi_kern_vma_nopage, -}; - -void xgi_kern_vma_open(struct vm_area_struct *vma) -{ - XGI_INFO("VM: vma_open for 0x%lx - 0x%lx, offset 0x%lx\n", - vma->vm_start, - vma->vm_end, - XGI_VMA_OFFSET(vma)); - - if (XGI_VMA_PRIVATE(vma)) - { - xgi_pcie_block_t *block = (xgi_pcie_block_t *)XGI_VMA_PRIVATE(vma); - XGI_ATOMIC_INC(block->use_count); - } -} - -void xgi_kern_vma_release(struct vm_area_struct *vma) -{ - XGI_INFO("VM: vma_release for 0x%lx - 0x%lx, offset 0x%lx\n", - vma->vm_start, - vma->vm_end, - XGI_VMA_OFFSET(vma)); - - if (XGI_VMA_PRIVATE(vma)) - { - xgi_pcie_block_t *block = (xgi_pcie_block_t *)XGI_VMA_PRIVATE(vma); - XGI_ATOMIC_DEC(block->use_count); - - /* - * if use_count is down to 0, the kernel virtual mapping was freed - * but the underlying physical pages were not, we need to clear the - * bit and free the physical pages. - */ - if (XGI_ATOMIC_READ(block->use_count) == 0) - { - // Need TO Finish - XGI_VMA_PRIVATE(vma) = NULL; - } - } -} - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 1)) -struct page *xgi_kern_vma_nopage(struct vm_area_struct *vma, - unsigned long address, int *type) -{ - xgi_pcie_block_t *block = (xgi_pcie_block_t *)XGI_VMA_PRIVATE(vma); - struct page *page = NOPAGE_SIGBUS; - unsigned long offset = 0; - unsigned long page_addr = 0; -/* - XGI_INFO("VM: mmap([0x%lx-0x%lx] off=0x%lx) address: 0x%lx \n", - vma->vm_start, - vma->vm_end, - XGI_VMA_OFFSET(vma), - address); -*/ - offset = (address - vma->vm_start) + XGI_VMA_OFFSET(vma); - - offset = offset - block->bus_addr; - - offset >>= PAGE_SHIFT; - - page_addr = block->page_table[offset].virt_addr; - - if (xgi_temp) - { - XGI_INFO("block->bus_addr: 0x%lx block->hw_addr: 0x%lx" - "block->page_count: 0x%lx block->page_order: 0x%lx" - "block->page_table[0x%lx].virt_addr: 0x%lx\n", - block->bus_addr, block->hw_addr, - block->page_count, block->page_order, - offset, - block->page_table[offset].virt_addr); - xgi_temp = 0; - } - - if (!page_addr) goto out; /* hole or end-of-file */ - page = virt_to_page(page_addr); - - /* got it, now increment the count */ - get_page(page); -out: - return page; - -} -#else -struct page *xgi_kern_vma_nopage(struct vm_area_struct *vma, - unsigned long address, int write_access) -{ - xgi_pcie_block_t *block = (xgi_pcie_block_t *)XGI_VMA_PRIVATE(vma); - struct page *page = NOPAGE_SIGBUS; - unsigned long offset = 0; - unsigned long page_addr = 0; -/* - XGI_INFO("VM: mmap([0x%lx-0x%lx] off=0x%lx) address: 0x%lx \n", - vma->vm_start, - vma->vm_end, - XGI_VMA_OFFSET(vma), - address); -*/ - offset = (address - vma->vm_start) + XGI_VMA_OFFSET(vma); - - offset = offset - block->bus_addr; - - offset >>= PAGE_SHIFT; - - page_addr = block->page_table[offset].virt_addr; - - if (xgi_temp) - { - XGI_INFO("block->bus_addr: 0x%lx block->hw_addr: 0x%lx" - "block->page_count: 0x%lx block->page_order: 0x%lx" - "block->page_table[0x%lx].virt_addr: 0x%lx\n", - block->bus_addr, block->hw_addr, - block->page_count, block->page_order, - offset, - block->page_table[offset].virt_addr); - xgi_temp = 0; - } - - if (!page_addr) goto out; /* hole or end-of-file */ - page = virt_to_page(page_addr); - - /* got it, now increment the count */ - get_page(page); -out: - return page; -} -#endif - -#if 0 -static struct file_operations xgi_fops = { - /* owner: THIS_MODULE, */ - poll: xgi_kern_poll, - ioctl: xgi_kern_ioctl, - mmap: xgi_kern_mmap, - open: xgi_kern_open, - release: xgi_kern_release, -}; -#endif - -static struct file_operations xgi_fops = { - .owner = THIS_MODULE, - .poll = xgi_kern_poll, - .ioctl = xgi_kern_ioctl, - .mmap = xgi_kern_mmap, - .open = xgi_kern_open, - .release = xgi_kern_release, -}; - -static xgi_file_private_t * xgi_alloc_file_private(void) -{ - xgi_file_private_t *fp; - - XGI_KMALLOC(fp, sizeof(xgi_file_private_t)); - if (!fp) - return NULL; - - memset(fp, 0, sizeof(xgi_file_private_t)); - - /* initialize this file's event queue */ - init_waitqueue_head(&fp->wait_queue); - - xgi_init_lock(fp->fp_lock); - - return fp; -} - -static void xgi_free_file_private(xgi_file_private_t *fp) -{ - if (fp == NULL) - return; - - XGI_KFREE(fp, sizeof(xgi_file_private_t)); -} - -int xgi_kern_open(struct inode *inode, struct file *filp) -{ - xgi_info_t *info = NULL; - int dev_num; - int result = 0, status; - - /* - * the type and num values are only valid if we are not using devfs. - * However, since we use them to retrieve the device pointer, we - * don't need them with devfs as filp->private_data is already - * initialized - */ - filp->private_data = xgi_alloc_file_private(); - if (filp->private_data == NULL) - return -ENOMEM; - - XGI_INFO("filp->private_data %p\n", filp->private_data); - /* - * for control device, just jump to its open routine - * after setting up the private data - */ - if (XGI_IS_CONTROL_DEVICE(inode)) - return xgi_kern_ctl_open(inode, filp); - - /* what device are we talking about? */ - dev_num = XGI_DEVICE_NUMBER(inode); - if (dev_num >= XGI_MAX_DEVICES) - { - xgi_free_file_private(filp->private_data); - filp->private_data = NULL; - return -ENODEV; - } - - info = &xgi_devices[dev_num]; - - XGI_INFO("Jong-xgi_kern_open on device %d\n", dev_num); - - xgi_down(info->info_sem); - XGI_CHECK_PCI_CONFIG(info); - - XGI_INFO_FROM_FP(filp) = info; - - /* - * map the memory and allocate isr on first open - */ - - if (!(info->flags & XGI_FLAG_OPEN)) - { - XGI_INFO("info->flags & XGI_FLAG_OPEN \n"); - - if (info->device_id == 0) - { - XGI_INFO("open of nonexistent device %d\n", dev_num); - result = -ENXIO; - goto failed; - } - - /* initialize struct irqaction */ - status = request_irq(info->irq, xgi_kern_isr, - SA_INTERRUPT | SA_SHIRQ, "xgi", - (void *) info); - if (status != 0) - { - if (info->irq && (status == -EBUSY)) - { - XGI_ERROR("Tried to get irq %d, but another driver", - (unsigned int) info->irq); - XGI_ERROR("has it and is not sharing it.\n"); - } - XGI_ERROR("isr request failed 0x%x\n", status); - result = -EIO; - goto failed; - } - - /* - * #define DECLARE_TASKLET(name, func, data) \ - * struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data } - */ - info->tasklet.func = xgi_kern_isr_bh; - info->tasklet.data = (unsigned long) info; - tasklet_enable(&info->tasklet); - - /* Alloc 1M bytes for cmdbuffer which is flush2D batch array */ - xgi_cmdlist_initialize(info, 0x100000); - - info->flags |= XGI_FLAG_OPEN; - } - - XGI_ATOMIC_INC(info->use_count); - -failed: - xgi_up(info->info_sem); - - if ((result) && filp->private_data) - { - xgi_free_file_private(filp->private_data); - filp->private_data = NULL; - } - - return result; -} - -int xgi_kern_release(struct inode *inode, struct file *filp) -{ - xgi_info_t *info = XGI_INFO_FROM_FP(filp); - - XGI_CHECK_PCI_CONFIG(info); - - /* - * for control device, just jump to its open routine - * after setting up the private data - */ - if (XGI_IS_CONTROL_DEVICE(inode)) - return xgi_kern_ctl_close(inode, filp); - - XGI_INFO("Jong-xgi_kern_release on device %d\n", XGI_DEVICE_NUMBER(inode)); - - xgi_down(info->info_sem); - if (XGI_ATOMIC_DEC_AND_TEST(info->use_count)) - { - - /* - * The usage count for this device has dropped to zero, it can be shut - * down safely; disable its interrupts. - */ - - /* - * Disable this device's tasklet to make sure that no bottom half will - * run with undefined device state. - */ - tasklet_disable(&info->tasklet); - - /* - * Free the IRQ, which may block until all pending interrupt processing - * has completed. - */ - free_irq(info->irq, (void *)info); - - xgi_cmdlist_cleanup(info); - - /* leave INIT flag alone so we don't reinit every time */ - info->flags &= ~XGI_FLAG_OPEN; - } - - xgi_up(info->info_sem); - - if (FILE_PRIVATE(filp)) - { - xgi_free_file_private(FILE_PRIVATE(filp)); - FILE_PRIVATE(filp) = NULL; - } - - return 0; -} - -int xgi_kern_mmap(struct file *filp, struct vm_area_struct *vma) -{ - //struct inode *inode = INODE_FROM_FP(filp); - xgi_info_t *info = XGI_INFO_FROM_FP(filp); - xgi_pcie_block_t *block; - int pages = 0; - unsigned long prot; - - XGI_INFO("Jong-VM: mmap([0x%lx-0x%lx] off=0x%lx)\n", - vma->vm_start, - vma->vm_end, - XGI_VMA_OFFSET(vma)); - - XGI_CHECK_PCI_CONFIG(info); - - if (XGI_MASK_OFFSET(vma->vm_start) - || XGI_MASK_OFFSET(vma->vm_end)) - { - XGI_ERROR("VM: bad mmap range: %lx - %lx\n", - vma->vm_start, vma->vm_end); - return -ENXIO; - } - - pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; - - vma->vm_ops = &xgi_vm_ops; - - /* XGI IO(reg) space */ - if (IS_IO_OFFSET(info, XGI_VMA_OFFSET(vma), vma->vm_end - vma->vm_start)) - { - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - if (XGI_REMAP_PAGE_RANGE(vma->vm_start, - XGI_VMA_OFFSET(vma), - vma->vm_end - vma->vm_start, - vma->vm_page_prot)) - return -EAGAIN; - - /* mark it as IO so that we don't dump it on core dump */ - vma->vm_flags |= VM_IO; - XGI_INFO("VM: mmap io space \n"); - } - /* XGI fb space */ - /* Jong 06/14/2006; moved behind PCIE or modify IS_FB_OFFSET */ - else if (IS_FB_OFFSET(info, XGI_VMA_OFFSET(vma), vma->vm_end - vma->vm_start)) - { - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - if (XGI_REMAP_PAGE_RANGE(vma->vm_start, - XGI_VMA_OFFSET(vma), - vma->vm_end - vma->vm_start, - vma->vm_page_prot)) - return -EAGAIN; - - // mark it as IO so that we don't dump it on core dump - vma->vm_flags |= VM_IO; - XGI_INFO("VM: mmap fb space \n"); - } - /* PCIE allocator */ - /* XGI_VMA_OFFSET(vma) is offset based on pcie.base (HW address space) */ - else if (IS_PCIE_OFFSET(info, XGI_VMA_OFFSET(vma), vma->vm_end - vma->vm_start)) - { - xgi_down(info->pcie_sem); - - block = (xgi_pcie_block_t *)xgi_find_pcie_block(info, XGI_VMA_OFFSET(vma)); - - if (block == NULL) - { - XGI_ERROR("couldn't find pre-allocated PCIE memory!\n"); - xgi_up(info->pcie_sem); - return -EAGAIN; - } - - if (block->page_count != pages) - { - XGI_ERROR("pre-allocated PCIE memory has wrong number of pages!\n"); - xgi_up(info->pcie_sem); - return -EAGAIN; - } - - vma->vm_private_data = block; - XGI_ATOMIC_INC(block->use_count); - xgi_up(info->pcie_sem); - - /* - * prevent the swapper from swapping it out - * mark the memory i/o so the buffers aren't - * dumped on core dumps */ - vma->vm_flags |= (VM_LOCKED | VM_IO); - - /* un-cached */ - prot = pgprot_val(vma->vm_page_prot); - /* - if (boot_cpu_data.x86 > 3) - prot |= _PAGE_PCD | _PAGE_PWT; - */ - vma->vm_page_prot = __pgprot(prot); - - XGI_INFO("VM: mmap pcie space \n"); - } -#if 0 - else if (IS_FB_OFFSET(info, XGI_VMA_OFFSET(vma), vma->vm_end - vma->vm_start)) - { - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - if (XGI_REMAP_PAGE_RANGE(vma->vm_start, - XGI_VMA_OFFSET(vma), - vma->vm_end - vma->vm_start, - vma->vm_page_prot)) - return -EAGAIN; - - // mark it as IO so that we don't dump it on core dump - vma->vm_flags |= VM_IO; - XGI_INFO("VM: mmap fb space \n"); - } -#endif - else - { - vma->vm_flags |= (VM_IO | VM_LOCKED); - XGI_ERROR("VM: mmap wrong range \n"); - } - - vma->vm_file = filp; - - return 0; -} - -unsigned int xgi_kern_poll(struct file *filp, struct poll_table_struct *wait) -{ - xgi_file_private_t *fp; - xgi_info_t *info; - unsigned int mask = 0; - unsigned long eflags; - - info = XGI_INFO_FROM_FP(filp); - - if (info->device_number == XGI_CONTROL_DEVICE_NUMBER) - return xgi_kern_ctl_poll(filp, wait); - - fp = XGI_GET_FP(filp); - - if (!(filp->f_flags & O_NONBLOCK)) - { - /* add us to the list */ - poll_wait(filp, &fp->wait_queue, wait); - } - - xgi_lock_irqsave(fp->fp_lock, eflags); - - /* wake the user on any event */ - if (fp->num_events) - { - XGI_INFO("Hey, an event occured!\n"); - /* - * trigger the client, when they grab the event, - * we'll decrement the event count - */ - mask |= (POLLPRI|POLLIN); - } - xgi_unlock_irqsave(fp->fp_lock, eflags); - - return mask; -} - -int xgi_kern_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - xgi_info_t *info; - xgi_mem_alloc_t *alloc = NULL; - - int status = 0; - void *arg_copy; - int arg_size; - int err = 0; - - info = XGI_INFO_FROM_FP(filp); - - XGI_INFO("Jong-ioctl(0x%x, 0x%x, 0x%lx, 0x%x)\n", _IOC_TYPE(cmd), _IOC_NR(cmd), arg, _IOC_SIZE(cmd)); - /* - * extract the type and number bitfields, and don't decode - * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok() - */ - if (_IOC_TYPE(cmd) != XGI_IOCTL_MAGIC) return -ENOTTY; - if (_IOC_NR(cmd) > XGI_IOCTL_MAXNR) return -ENOTTY; - - /* - * the direction is a bitmask, and VERIFY_WRITE catches R/W - * transfers. `Type' is user-oriented, while - * access_ok is kernel-oriented, so the concept of "read" and - * "write" is reversed - */ - if (_IOC_DIR(cmd) & _IOC_READ) - { - err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd)); - } - else if (_IOC_DIR(cmd) & _IOC_WRITE) - { - err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd)); - } - if (err) return -EFAULT; - - XGI_CHECK_PCI_CONFIG(info); - - arg_size = _IOC_SIZE(cmd); - XGI_KMALLOC(arg_copy, arg_size); - if (arg_copy == NULL) - { - XGI_ERROR("failed to allocate ioctl memory\n"); - return -ENOMEM; - } - - /* Jong 05/25/2006 */ - /* copy_from_user(arg_copy, (void *)arg, arg_size); */ - if(copy_from_user(arg_copy, (void *)arg, arg_size)) - { - XGI_ERROR("failed to copyin ioctl data\n"); - XGI_INFO("Jong-copy_from_user-fail! \n"); - } - else - XGI_INFO("Jong-copy_from_user-OK! \n"); - - alloc = (xgi_mem_alloc_t *)arg_copy; - XGI_INFO("Jong-succeeded in copy_from_user 0x%lx, 0x%x bytes.\n", arg, arg_size); - - switch (_IOC_NR(cmd)) - { - case XGI_ESC_DEVICE_INFO: - XGI_INFO("Jong-xgi_ioctl_get_device_info \n"); - xgi_get_device_info(info, (struct xgi_chip_info_s *) arg_copy); - break; - case XGI_ESC_POST_VBIOS: - XGI_INFO("Jong-xgi_ioctl_post_vbios \n"); - break; - case XGI_ESC_FB_ALLOC: - XGI_INFO("Jong-xgi_ioctl_fb_alloc \n"); - xgi_fb_alloc(info, (struct xgi_mem_req_s *)arg_copy, alloc); - break; - case XGI_ESC_FB_FREE: - XGI_INFO("Jong-xgi_ioctl_fb_free \n"); - xgi_fb_free(info, *(unsigned long *) arg_copy); - break; - case XGI_ESC_MEM_COLLECT: - XGI_INFO("Jong-xgi_ioctl_mem_collect \n"); - xgi_mem_collect(info, (unsigned int *) arg_copy); - break; - case XGI_ESC_PCIE_ALLOC: - XGI_INFO("Jong-xgi_ioctl_pcie_alloc \n"); - xgi_pcie_alloc(info, ((xgi_mem_req_t *)arg_copy)->size, - ((xgi_mem_req_t *)arg_copy)->owner, alloc); - break; - case XGI_ESC_PCIE_FREE: - XGI_INFO("Jong-xgi_ioctl_pcie_free: bus_addr = 0x%lx \n", *((unsigned long *) arg_copy)); - xgi_pcie_free(info, *((unsigned long *) arg_copy)); - break; - case XGI_ESC_PCIE_CHECK: - XGI_INFO("Jong-xgi_pcie_heap_check \n"); - xgi_pcie_heap_check(); - break; - case XGI_ESC_GET_SCREEN_INFO: - XGI_INFO("Jong-xgi_get_screen_info \n"); - xgi_get_screen_info(info, (struct xgi_screen_info_s *) arg_copy); - break; - case XGI_ESC_PUT_SCREEN_INFO: - XGI_INFO("Jong-xgi_put_screen_info \n"); - xgi_put_screen_info(info, (struct xgi_screen_info_s *) arg_copy); - break; - case XGI_ESC_MMIO_INFO: - XGI_INFO("Jong-xgi_ioctl_get_mmio_info \n"); - xgi_get_mmio_info(info, (struct xgi_mmio_info_s *) arg_copy); - break; - case XGI_ESC_GE_RESET: - XGI_INFO("Jong-xgi_ioctl_ge_reset \n"); - xgi_ge_reset(info); - break; - case XGI_ESC_SAREA_INFO: - XGI_INFO("Jong-xgi_ioctl_sarea_info \n"); - xgi_sarea_info(info, (struct xgi_sarea_info_s *) arg_copy); - break; - case XGI_ESC_DUMP_REGISTER: - XGI_INFO("Jong-xgi_ioctl_dump_register \n"); - xgi_dump_register(info); - break; - case XGI_ESC_DEBUG_INFO: - XGI_INFO("Jong-xgi_ioctl_restore_registers \n"); - xgi_restore_registers(info); - //xgi_write_pcie_mem(info, (struct xgi_mem_req_s *) arg_copy); - //xgi_read_pcie_mem(info, (struct xgi_mem_req_s *) arg_copy); - break; - case XGI_ESC_SUBMIT_CMDLIST: - XGI_INFO("Jong-xgi_ioctl_submit_cmdlist \n"); - xgi_submit_cmdlist(info, (xgi_cmd_info_t *) arg_copy); - break; - case XGI_ESC_TEST_RWINKERNEL: - XGI_INFO("Jong-xgi_test_rwinkernel \n"); - xgi_test_rwinkernel(info, *(unsigned long*) arg_copy); - break; - case XGI_ESC_STATE_CHANGE: - XGI_INFO("Jong-xgi_state_change \n"); - xgi_state_change(info, (xgi_state_info_t *) arg_copy); - break; - case XGI_ESC_CPUID: - XGI_INFO("Jong-XGI_ESC_CPUID \n"); - xgi_get_cpu_id((struct cpu_info_s*) arg_copy); - break; - default: - XGI_INFO("Jong-xgi_ioctl_default \n"); - status = -EINVAL; - break; - } - - if (copy_to_user((void *)arg, arg_copy, arg_size)) - { - XGI_ERROR("failed to copyout ioctl data\n"); - XGI_INFO("Jong-copy_to_user-fail! \n"); - } - else - XGI_INFO("Jong-copy_to_user-OK! \n"); - - XGI_KFREE(arg_copy, arg_size); - return status; -} - - -/* - * xgi control driver operations defined here - */ -int xgi_kern_ctl_open(struct inode *inode, struct file *filp) -{ - xgi_info_t *info = &xgi_ctl_device; - - int rc = 0; - - XGI_INFO("Jong-xgi_kern_ctl_open\n"); - - xgi_down(info->info_sem); - info->device_number = XGI_CONTROL_DEVICE_NUMBER; - - /* save the xgi info in file->private_data */ - filp->private_data = info; - - if (XGI_ATOMIC_READ(info->use_count) == 0) - { - init_waitqueue_head(&xgi_ctl_waitqueue); - } - - info->flags |= XGI_FLAG_OPEN + XGI_FLAG_CONTROL; - - XGI_ATOMIC_INC(info->use_count); - xgi_up(info->info_sem); - - return rc; -} - -int xgi_kern_ctl_close(struct inode *inode, struct file *filp) -{ - xgi_info_t *info = XGI_INFO_FROM_FP(filp); - - XGI_INFO("Jong-xgi_kern_ctl_close\n"); - - xgi_down(info->info_sem); - if (XGI_ATOMIC_DEC_AND_TEST(info->use_count)) - { - info->flags = 0; - } - xgi_up(info->info_sem); - - if (FILE_PRIVATE(filp)) - { - xgi_free_file_private(FILE_PRIVATE(filp)); - FILE_PRIVATE(filp) = NULL; - } - - return 0; -} - -unsigned int xgi_kern_ctl_poll(struct file *filp, poll_table *wait) -{ - //xgi_info_t *info = XGI_INFO_FROM_FP(filp);; - unsigned int ret = 0; - - if (!(filp->f_flags & O_NONBLOCK)) - { - poll_wait(filp, &xgi_ctl_waitqueue, wait); - } - - return ret; -} - -/* - * xgi proc system - */ -static u8 xgi_find_pcie_capability(struct pci_dev *dev) -{ - u16 status; - u8 cap_ptr, cap_id; - - pci_read_config_word(dev, PCI_STATUS, &status); - status &= PCI_STATUS_CAP_LIST; - if (!status) - return 0; - - switch (dev->hdr_type) - { - case PCI_HEADER_TYPE_NORMAL: - case PCI_HEADER_TYPE_BRIDGE: - pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &cap_ptr); - break; - default: - return 0; - } - - do - { - cap_ptr &= 0xFC; - pci_read_config_byte(dev, cap_ptr + PCI_CAP_LIST_ID, &cap_id); - pci_read_config_byte(dev, cap_ptr + PCI_CAP_LIST_NEXT, &cap_ptr); - } while (cap_ptr && cap_id != 0xFF); - - return 0; -} - -static struct pci_dev* xgi_get_pci_device(xgi_info_t *info) -{ - struct pci_dev *dev; - - dev = XGI_PCI_GET_DEVICE(info->vendor_id, info->device_id, NULL); - while (dev) - { - if (XGI_PCI_SLOT_NUMBER(dev) == info->slot - && XGI_PCI_BUS_NUMBER(dev) == info->bus) - return dev; - dev = XGI_PCI_GET_DEVICE(info->vendor_id, info->device_id, dev); - } - - return NULL; -} - -int xgi_kern_read_card_info(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - struct pci_dev *dev; - char *type; - int len = 0; - - xgi_info_t *info; - info = (xgi_info_t *) data; - - dev = xgi_get_pci_device(info); - if (!dev) - return 0; - - type = xgi_find_pcie_capability(dev) ? "PCIE" : "PCI"; - len += sprintf(page+len, "Card Type: \t %s\n", type); - - XGI_PCI_DEV_PUT(dev); - return len; -} - -int xgi_kern_read_version(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int len = 0; - - len += sprintf(page+len, "XGI version: %s\n", "1.0"); - len += sprintf(page+len, "GCC version: %s\n", "3.0"); - - return len; -} - -int xgi_kern_read_pcie_info(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - return 0; -} - -int xgi_kern_read_status(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - return 0; -} - - -static void xgi_proc_create(void) -{ -#ifdef CONFIG_PROC_FS - - struct pci_dev *dev; - int i = 0; - char name[6]; - - struct proc_dir_entry *entry; - struct proc_dir_entry *proc_xgi_pcie, *proc_xgi_cards; - - xgi_info_t *info; - xgi_info_t *xgi_max_devices; - - /* world readable directory */ - int flags = S_IFDIR | S_IRUGO | S_IXUGO; - - proc_xgi = create_proc_entry("xgi", flags, proc_root_driver); - if (!proc_xgi) - goto failed; - - proc_xgi_cards = create_proc_entry("cards", flags, proc_xgi); - if (!proc_xgi_cards) - goto failed; - - proc_xgi_pcie = create_proc_entry("pcie", flags, proc_xgi); - if (!proc_xgi_pcie) - goto failed; - - /* - * Set the module owner to ensure that the reference - * count reflects accesses to the proc files. - */ - proc_xgi->owner = THIS_MODULE; - proc_xgi_cards->owner = THIS_MODULE; - proc_xgi_pcie->owner = THIS_MODULE; - - xgi_max_devices = xgi_devices + XGI_MAX_DEVICES; - for (info = xgi_devices; info < xgi_max_devices; info++) - { - if (info->device_id == 0) - break; - - /* world readable file */ - flags = S_IFREG | S_IRUGO; - - dev = xgi_get_pci_device(info); - if (!dev) - break; - - sprintf(name, "%d", i++); - entry = create_proc_entry(name, flags, proc_xgi_cards); - if (!entry) - { - XGI_PCI_DEV_PUT(dev); - goto failed; - } - - entry->data = info; - entry->read_proc = xgi_kern_read_card_info; - entry->owner = THIS_MODULE; - - if (xgi_find_pcie_capability(dev)) - { - entry = create_proc_entry("status", flags, proc_xgi_pcie); - if (!entry) - { - XGI_PCI_DEV_PUT(dev); - goto failed; - } - - entry->data = info; - entry->read_proc = xgi_kern_read_status; - entry->owner = THIS_MODULE; - - entry = create_proc_entry("card", flags, proc_xgi_pcie); - if (!entry) - { - XGI_PCI_DEV_PUT(dev); - goto failed; - } - - entry->data = info; - entry->read_proc = xgi_kern_read_pcie_info; - entry->owner = THIS_MODULE; - } - - XGI_PCI_DEV_PUT(dev); - } - - entry = create_proc_entry("version", flags, proc_xgi); - if (!entry) - goto failed; - - entry->read_proc = xgi_kern_read_version; - entry->owner = THIS_MODULE; - - entry = create_proc_entry("host-bridge", flags, proc_xgi_pcie); - if (!entry) - goto failed; - - entry->data = NULL; - entry->read_proc = xgi_kern_read_pcie_info; - entry->owner = THIS_MODULE; - - return; - -failed: - XGI_ERROR("failed to create /proc entries!\n"); - xgi_proc_remove_all(proc_xgi); -#endif -} - -#ifdef CONFIG_PROC_FS -static void xgi_proc_remove_all(struct proc_dir_entry *entry) -{ - while (entry) - { - struct proc_dir_entry *next = entry->next; - if (entry->subdir) - xgi_proc_remove_all(entry->subdir); - remove_proc_entry(entry->name, entry->parent); - if (entry == proc_xgi) - break; - entry = next; - } -} -#endif - -static void xgi_proc_remove(void) -{ -#ifdef CONFIG_PROC_FS - xgi_proc_remove_all(proc_xgi); -#endif -} - -/* - * driver receives an interrupt if someone waiting, then hand it off. - */ -irqreturn_t xgi_kern_isr(int irq, void *dev_id, struct pt_regs *regs) -{ - xgi_info_t *info = (xgi_info_t *) dev_id; - u32 need_to_run_bottom_half = 0; - - //XGI_INFO("xgi_kern_isr \n"); - - //XGI_CHECK_PCI_CONFIG(info); - - //xgi_dvi_irq_handler(info); - - if (need_to_run_bottom_half) - { - tasklet_schedule(&info->tasklet); - } - - return IRQ_HANDLED; -} - -void xgi_kern_isr_bh(unsigned long data) -{ - xgi_info_t *info = (xgi_info_t *) data; - - XGI_INFO("xgi_kern_isr_bh \n"); - - //xgi_dvi_irq_handler(info); - - XGI_CHECK_PCI_CONFIG(info); -} - -static void xgi_lock_init(xgi_info_t *info) -{ - if (info == NULL) return; - - spin_lock_init(&info->info_lock); - - sema_init(&info->info_sem, 1); - sema_init(&info->fb_sem, 1); - sema_init(&info->pcie_sem, 1); - - XGI_ATOMIC_SET(info->use_count, 0); -} - -static void xgi_dev_init(xgi_info_t *info) -{ - struct pci_dev *pdev = NULL; - struct xgi_dev *dev; - int found = 0; - u16 pci_cmd; - - XGI_INFO("Enter xgi_dev_init \n"); - - //XGI_PCI_FOR_EACH_DEV(pdev) - { - for (dev = xgidev_list; dev->vendor; dev++) - { - if ((dev->vendor == pdev->vendor) && (dev->device == pdev->device)) - { - XGI_INFO("dev->vendor = pdev->vendor= %x \n", dev->vendor); - XGI_INFO("dev->device = pdev->device= %x \n", dev->device); - - xgi_devices[found].device_id = pdev->device; - - pci_read_config_byte(pdev, PCI_REVISION_ID, &xgi_devices[found].revision_id); - - XGI_INFO("PCI_REVISION_ID= %x \n", xgi_devices[found].revision_id); - - pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd); - - XGI_INFO("PCI_COMMAND = %x \n", pci_cmd); - - break; - } - } - } -} -/* - * Export to Linux Kernel - */ - -static int __init xgi_init_module(void) -{ - xgi_info_t *info = &xgi_devices[xgi_num_devices]; - int i, result; - - XGI_INFO("Jong-xgi kernel driver %s initializing\n", XGI_DRV_VERSION); - //SET_MODULE_OWNER(&xgi_fops); - - memset(xgi_devices, 0, sizeof(xgi_devices)); - - if (pci_register_driver(&xgi_pci_driver) < 0) - { - pci_unregister_driver(&xgi_pci_driver); - XGI_ERROR("no XGI graphics adapter found\n"); - return -ENODEV; - } - - XGI_INFO("Jong-xgi_devices[%d].fb.base.: 0x%lx \n", xgi_num_devices, xgi_devices[xgi_num_devices].fb.base); - XGI_INFO("Jong-xgi_devices[%d].fb.size.: 0x%lx \n", xgi_num_devices, xgi_devices[xgi_num_devices].fb.size); - -/* Jong 07/27/2006; test for ubuntu */ -/* -#ifdef CONFIG_DEVFS_FS - - XGI_INFO("Jong-Use devfs \n"); - do - { - xgi_devfs_handles[0] = XGI_DEVFS_REGISTER("xgi", 0); - if (xgi_devfs_handles[0] == NULL) - { - result = -ENOMEM; - XGI_ERROR("devfs register failed\n"); - goto failed; - } - } while(0); -#else */ /* no devfs, do it the "classic" way */ - - - XGI_INFO("Jong-Use non-devfs \n"); - /* - * Register your major, and accept a dynamic number. This is the - * first thing to do, in order to avoid releasing other module's - * fops in scull_cleanup_module() - */ - result = XGI_REGISTER_CHRDEV(xgi_major, "xgi", &xgi_fops); - if (result < 0) - { - XGI_ERROR("register chrdev failed\n"); - pci_unregister_driver(&xgi_pci_driver); - return result; - } - if (xgi_major == 0) xgi_major = result; /* dynamic */ - -/* #endif */ /* CONFIG_DEVFS_FS */ - - XGI_INFO("Jong-major number %d\n", xgi_major); - - /* instantiate tasklets */ - for (i = 0; i < XGI_MAX_DEVICES; i++) - { - /* - * We keep one tasklet per card to avoid latency issues with more - * than one device; no two instances of a single tasklet are ever - * executed concurrently. - */ - XGI_ATOMIC_SET(xgi_devices[i].tasklet.count, 1); - } - - /* init the xgi control device */ - { - xgi_info_t *info_ctl = &xgi_ctl_device; - xgi_lock_init(info_ctl); - } - - /* Init the resource manager */ - INIT_LIST_HEAD(&xgi_mempid_list); - if (!xgi_fb_heap_init(info)) - { - XGI_ERROR("xgi_fb_heap_init() failed\n"); - result = -EIO; - goto failed; - } - - /* Init the resource manager */ - if (!xgi_pcie_heap_init(info)) - { - XGI_ERROR("xgi_pcie_heap_init() failed\n"); - result = -EIO; - goto failed; - } - - /* create /proc/driver/xgi */ - xgi_proc_create(); - -#if defined(DEBUG) - inter_module_register("xgi_devices", THIS_MODULE, xgi_devices); -#endif - - return 0; - -failed: -#ifdef CONFIG_DEVFS_FS - XGI_DEVFS_REMOVE_CONTROL(); - XGI_DEVFS_REMOVE_DEVICE(xgi_num_devices); -#endif - - if (XGI_UNREGISTER_CHRDEV(xgi_major, "xgi") < 0) - XGI_ERROR("unregister xgi chrdev failed\n"); - - for (i = 0; i < xgi_num_devices; i++) - { - if (xgi_devices[i].dev) - { - release_mem_region(xgi_devices[i].fb.base, xgi_devices[i].fb.size); - release_mem_region(xgi_devices[i].mmio.base, xgi_devices[i].mmio.size); - } - } - - pci_unregister_driver(&xgi_pci_driver); - return result; - - return 1; -} - -void __exit xgi_exit_module(void) -{ - int i; - xgi_info_t *info, *max_devices; - -#ifdef CONFIG_DEVFS_FS - /* - XGI_DEVFS_REMOVE_CONTROL(); - for (i = 0; i < XGI_MAX_DEVICES; i++) - XGI_DEVFS_REMOVE_DEVICE(i); - */ - XGI_DEVFS_REMOVE_DEVICE(xgi_num_devices); -#endif - - if (XGI_UNREGISTER_CHRDEV(xgi_major, "xgi") < 0) - XGI_ERROR("unregister xgi chrdev failed\n"); - - XGI_INFO("Jong-unregister xgi chrdev scceeded\n"); - for (i = 0; i < XGI_MAX_DEVICES; i++) - { - if (xgi_devices[i].dev) - { - /* clean up the flush2D batch array */ - xgi_cmdlist_cleanup(&xgi_devices[i]); - - if(xgi_devices[i].fb.vbase != NULL) - { - iounmap((void *)xgi_devices[i].fb.vbase); - xgi_devices[i].fb.vbase = NULL; - } - if(xgi_devices[i].mmio.vbase != NULL) - { - iounmap((void *)xgi_devices[i].mmio.vbase); - xgi_devices[i].mmio.vbase = NULL; - } - - //release_mem_region(xgi_devices[i].fb.base, xgi_devices[i].fb.size); - //XGI_INFO("release frame buffer mem region scceeded\n"); - - release_mem_region(xgi_devices[i].mmio.base, xgi_devices[i].mmio.size); - XGI_INFO("release MMIO mem region scceeded\n"); - - xgi_fb_heap_cleanup(&xgi_devices[i]); - XGI_INFO("xgi_fb_heap_cleanup scceeded\n"); - - xgi_pcie_heap_cleanup(&xgi_devices[i]); - XGI_INFO("xgi_pcie_heap_cleanup scceeded\n"); - - XGI_PCI_DISABLE_DEVICE(xgi_devices[i].dev); - } - } - - pci_unregister_driver(&xgi_pci_driver); - - /* remove /proc/driver/xgi */ - xgi_proc_remove(); - -#if defined(DEBUG) - inter_module_unregister("xgi_devices"); -#endif -} - -module_init(xgi_init_module); -module_exit(xgi_exit_module); - -#if defined(XGI_PM_SUPPORT_ACPI) -int xgi_acpi_event(struct pci_dev *dev, u32 state) -{ - return 1; -} - -int xgi_kern_acpi_standby(struct pci_dev *dev, u32 state) -{ - return 1; -} - -int xgi_kern_acpi_resume(struct pci_dev *dev) -{ - return 1; -} -#endif - -MODULE_AUTHOR("Andrea Zhang "); -MODULE_DESCRIPTION("xgi kernel driver for xgi cards"); -MODULE_LICENSE("GPL"); + +/**************************************************************************** + * Copyright (C) 2003-2006 by XGI Technology, Taiwan. + * * + * All Rights Reserved. * + * * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NON-INFRINGEMENT. IN NO EVENT SHALL XGI AND/OR + * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + ***************************************************************************/ +#include "xgi_types.h" +#include "xgi_linux.h" +#include "xgi_drv.h" +#include "xgi_regs.h" +#include "xgi_pcie.h" +#include "xgi_misc.h" +#include "xgi_cmdlist.h" + +/* for debug */ +static int xgi_temp = 1; +/* + * global parameters + */ +static struct xgi_dev { + u16 vendor; + u16 device; + const char *name; +} xgidev_list[] = { + { + PCI_VENDOR_ID_XGI, PCI_DEVICE_ID_XP5, "XP5"}, { + PCI_VENDOR_ID_XGI, PCI_DEVICE_ID_XG47, "XG47"}, { + 0, 0, NULL} +}; + +int xgi_major = XGI_DEV_MAJOR; /* xgi reserved major device number. */ + +static int xgi_num_devices = 0; + +xgi_info_t xgi_devices[XGI_MAX_DEVICES]; + +#if defined(XGI_PM_SUPPORT_APM) +static struct pm_dev *apm_xgi_dev[XGI_MAX_DEVICES] = { 0 }; +#endif + +/* add one for the control device */ +xgi_info_t xgi_ctl_device; +wait_queue_head_t xgi_ctl_waitqueue; + +#ifdef CONFIG_PROC_FS +struct proc_dir_entry *proc_xgi; +#endif + +#ifdef CONFIG_DEVFS_FS +devfs_handle_t xgi_devfs_handles[XGI_MAX_DEVICES]; +#endif + +struct list_head xgi_mempid_list; + +/* xgi_ functions.. do not take a state device parameter */ +static int xgi_post_vbios(xgi_ioctl_post_vbios_t * info); +static void xgi_proc_create(void); +static void xgi_proc_remove_all(struct proc_dir_entry *); +static void xgi_proc_remove(void); + +/* xgi_kern_ functions, interfaces used by linux kernel */ +int xgi_kern_probe(struct pci_dev *, const struct pci_device_id *); + +unsigned int xgi_kern_poll(struct file *, poll_table *); +int xgi_kern_ioctl(struct inode *, struct file *, unsigned int, unsigned long); +int xgi_kern_mmap(struct file *, struct vm_area_struct *); +int xgi_kern_open(struct inode *, struct file *); +int xgi_kern_release(struct inode *inode, struct file *filp); + +void xgi_kern_vma_open(struct vm_area_struct *vma); +void xgi_kern_vma_release(struct vm_area_struct *vma); +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 1)) +struct page *xgi_kern_vma_nopage(struct vm_area_struct *vma, + unsigned long address, int *type); +#else +struct page *xgi_kern_vma_nopage(struct vm_area_struct *vma, + unsigned long address, int write_access); +#endif + +int xgi_kern_read_card_info(char *, char **, off_t off, int, int *, void *); +int xgi_kern_read_status(char *, char **, off_t off, int, int *, void *); +int xgi_kern_read_pcie_info(char *, char **, off_t off, int, int *, void *); +int xgi_kern_read_version(char *, char **, off_t off, int, int *, void *); + +int xgi_kern_ctl_open(struct inode *, struct file *); +int xgi_kern_ctl_close(struct inode *, struct file *); +unsigned int xgi_kern_ctl_poll(struct file *, poll_table *); + +void xgi_kern_isr_bh(unsigned long); +irqreturn_t xgi_kern_isr(int, void *, struct pt_regs *); + +static void xgi_lock_init(xgi_info_t * info); + +#if defined(XGI_PM_SUPPORT_ACPI) +int xgi_kern_acpi_standby(struct pci_dev *, u32); +int xgi_kern_acpi_resume(struct pci_dev *); +#endif + +/* + * verify access to pci config space wasn't disabled behind our back + * unfortunately, XFree86 enables/disables memory access in pci config space at + * various times (such as restoring initial pci config space settings during vt + * switches or when doing mulicard). As a result, all of our register accesses + * are garbage at this point. add a check to see if access was disabled and + * reenable any such access. + */ +#define XGI_CHECK_PCI_CONFIG(xgi) \ + xgi_check_pci_config(xgi, __LINE__) + +static inline void xgi_check_pci_config(xgi_info_t * info, int line) +{ + unsigned short cmd, flag = 0; + + // don't do this on the control device, only the actual devices + if (info->flags & XGI_FLAG_CONTROL) + return; + + pci_read_config_word(info->dev, PCI_COMMAND, &cmd); + if (!(cmd & PCI_COMMAND_MASTER)) { + XGI_INFO("restoring bus mastering! (%d)\n", line); + cmd |= PCI_COMMAND_MASTER; + flag = 1; + } + + if (!(cmd & PCI_COMMAND_MEMORY)) { + XGI_INFO("restoring MEM access! (%d)\n", line); + cmd |= PCI_COMMAND_MEMORY; + flag = 1; + } + + if (flag) + pci_write_config_word(info->dev, PCI_COMMAND, cmd); +} + +static int xgi_post_vbios(xgi_ioctl_post_vbios_t * info) +{ + return 1; +} + +/* + * struct pci_device_id { + * unsigned int vendor, device; // Vendor and device ID or PCI_ANY_ID + * unsigned int subvendor, subdevice; // Subsystem ID's or PCI_ANY_ID + * unsigned int class, class_mask; // (class,subclass,prog-if) triplet + * unsigned long driver_data; // Data private to the driver + * }; + */ + +static struct pci_device_id xgi_dev_table[] = { + { + .vendor = PCI_VENDOR_ID_XGI, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .class = (PCI_CLASS_DISPLAY_VGA << 8), + .class_mask = ~0, + }, + {} +}; + +/* + * #define MODULE_DEVICE_TABLE(type,name) \ + * MODULE_GENERIC_TABLE(type##_device,name) + */ +MODULE_DEVICE_TABLE(pci, xgi_dev_table); + +/* + * struct pci_driver { + * struct list_head node; + * char *name; + * const struct pci_device_id *id_table; // NULL if wants all devices + * int (*probe)(struct pci_dev *dev, const struct pci_device_id *id); // New device inserted + * void (*remove)(struct pci_dev *dev); // Device removed (NULL if not a hot-plug capable driver) + * int (*save_state)(struct pci_dev *dev, u32 state); // Save Device Context + * int (*suspend)(struct pci_dev *dev, u32 state); // Device suspended + * int (*resume)(struct pci_dev *dev); // Device woken up + * int (*enable_wake)(struct pci_dev *dev, u32 state, int enable); // Enable wake event + * }; + */ +static struct pci_driver xgi_pci_driver = { + .name = "xgi", + .id_table = xgi_dev_table, + .probe = xgi_kern_probe, +#if defined(XGI_SUPPORT_ACPI) + .suspend = xgi_kern_acpi_standby, + .resume = xgi_kern_acpi_resume, +#endif +}; + +/* + * find xgi devices and set initial state + */ +int xgi_kern_probe(struct pci_dev *dev, const struct pci_device_id *id_table) +{ + xgi_info_t *info; + + if ((dev->vendor != PCI_VENDOR_ID_XGI) + || (dev->class != (PCI_CLASS_DISPLAY_VGA << 8))) { + return -1; + } + + if (xgi_num_devices == XGI_MAX_DEVICES) { + XGI_INFO("maximum device number (%d) reached!\n", + xgi_num_devices); + return -1; + } + + /* enable io, mem, and bus-mastering in pci config space */ + if (pci_enable_device(dev) != 0) { + XGI_INFO("pci_enable_device failed, aborting\n"); + return -1; + } + + XGI_INFO("maximum device number (%d) reached \n", xgi_num_devices); + + pci_set_master(dev); + + info = &xgi_devices[xgi_num_devices]; + info->dev = dev; + info->vendor_id = dev->vendor; + info->device_id = dev->device; + info->bus = dev->bus->number; + info->slot = PCI_SLOT((dev)->devfn); + + xgi_lock_init(info); + + info->mmio.base = XGI_PCI_RESOURCE_START(dev, 1); + info->mmio.size = XGI_PCI_RESOURCE_SIZE(dev, 1); + + /* check IO region */ + if (!request_mem_region(info->mmio.base, info->mmio.size, "xgi")) { + XGI_ERROR("cannot reserve MMIO memory\n"); + goto error_disable_dev; + } + + XGI_INFO("info->mmio.base: 0x%lx \n", info->mmio.base); + XGI_INFO("info->mmio.size: 0x%lx \n", info->mmio.size); + + info->mmio.vbase = (unsigned char *)ioremap_nocache(info->mmio.base, + info->mmio.size); + if (!info->mmio.vbase) { + release_mem_region(info->mmio.base, info->mmio.size); + XGI_ERROR("info->mmio.vbase failed\n"); + goto error_disable_dev; + } + xgi_enable_mmio(info); + + //xgi_enable_ge(info); + + XGI_INFO("info->mmio.vbase: 0x%p \n", info->mmio.vbase); + + info->fb.base = XGI_PCI_RESOURCE_START(dev, 0); + info->fb.size = XGI_PCI_RESOURCE_SIZE(dev, 0); + + XGI_INFO("info->fb.base: 0x%lx \n", info->fb.base); + XGI_INFO("info->fb.size: 0x%lx \n", info->fb.size); + + info->fb.size = bIn3cf(0x54) * 8 * 1024 * 1024; + XGI_INFO("info->fb.size: 0x%lx \n", info->fb.size); + + /* check frame buffer region + if (!request_mem_region(info->fb.base, info->fb.size, "xgi")) + { + release_mem_region(info->mmio.base, info->mmio.size); + XGI_ERROR("cannot reserve frame buffer memory\n"); + goto error_disable_dev; + } + + info->fb.vbase = (unsigned char *)ioremap_nocache(info->fb.base, + info->fb.size); + + if (!info->fb.vbase) + { + release_mem_region(info->mmio.base, info->mmio.size); + release_mem_region(info->fb.base, info->fb.size); + XGI_ERROR("info->fb.vbase failed\n"); + goto error_disable_dev; + } + */ + info->fb.vbase = NULL; + XGI_INFO("info->fb.vbase: 0x%p \n", info->fb.vbase); + + info->irq = dev->irq; + + /* check common error condition */ + if (info->irq == 0) { + XGI_ERROR("Can't find an IRQ for your XGI card! \n"); + goto error_zero_dev; + } + XGI_INFO("info->irq: %lx \n", info->irq); + + //xgi_enable_dvi_interrupt(info); + + /* sanity check the IO apertures */ + if ((info->mmio.base == 0) || (info->mmio.size == 0) + || (info->fb.base == 0) || (info->fb.size == 0)) { + XGI_ERROR("The IO regions for your XGI card are invalid.\n"); + + if ((info->mmio.base == 0) || (info->mmio.size == 0)) { + XGI_ERROR("mmio appears to be wrong: 0x%lx 0x%lx\n", + info->mmio.base, info->mmio.size); + } + + if ((info->fb.base == 0) || (info->fb.size == 0)) { + XGI_ERROR + ("frame buffer appears to be wrong: 0x%lx 0x%lx\n", + info->fb.base, info->fb.size); + } + + goto error_zero_dev; + } + //xgi_num_devices++; + + return 0; + + error_zero_dev: + release_mem_region(info->fb.base, info->fb.size); + release_mem_region(info->mmio.base, info->mmio.size); + + error_disable_dev: + pci_disable_device(dev); + return -1; + +} + +/* + * vma operations... + * this is only called when the vmas are duplicated. this + * appears to only happen when the process is cloned to create + * a new process, and not when the process is threaded. + * + * increment the usage count for the physical pages, so when + * this clone unmaps the mappings, the pages are not + * deallocated under the original process. + */ +struct vm_operations_struct xgi_vm_ops = { + .open = xgi_kern_vma_open, + .close = xgi_kern_vma_release, + .nopage = xgi_kern_vma_nopage, +}; + +void xgi_kern_vma_open(struct vm_area_struct *vma) +{ + XGI_INFO("VM: vma_open for 0x%lx - 0x%lx, offset 0x%lx\n", + vma->vm_start, vma->vm_end, XGI_VMA_OFFSET(vma)); + + if (XGI_VMA_PRIVATE(vma)) { + xgi_pcie_block_t *block = + (xgi_pcie_block_t *) XGI_VMA_PRIVATE(vma); + XGI_ATOMIC_INC(block->use_count); + } +} + +void xgi_kern_vma_release(struct vm_area_struct *vma) +{ + XGI_INFO("VM: vma_release for 0x%lx - 0x%lx, offset 0x%lx\n", + vma->vm_start, vma->vm_end, XGI_VMA_OFFSET(vma)); + + if (XGI_VMA_PRIVATE(vma)) { + xgi_pcie_block_t *block = + (xgi_pcie_block_t *) XGI_VMA_PRIVATE(vma); + XGI_ATOMIC_DEC(block->use_count); + + /* + * if use_count is down to 0, the kernel virtual mapping was freed + * but the underlying physical pages were not, we need to clear the + * bit and free the physical pages. + */ + if (XGI_ATOMIC_READ(block->use_count) == 0) { + // Need TO Finish + XGI_VMA_PRIVATE(vma) = NULL; + } + } +} + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 1)) +struct page *xgi_kern_vma_nopage(struct vm_area_struct *vma, + unsigned long address, int *type) +{ + xgi_pcie_block_t *block = (xgi_pcie_block_t *) XGI_VMA_PRIVATE(vma); + struct page *page = NOPAGE_SIGBUS; + unsigned long offset = 0; + unsigned long page_addr = 0; +/* + XGI_INFO("VM: mmap([0x%lx-0x%lx] off=0x%lx) address: 0x%lx \n", + vma->vm_start, + vma->vm_end, + XGI_VMA_OFFSET(vma), + address); +*/ + offset = (address - vma->vm_start) + XGI_VMA_OFFSET(vma); + + offset = offset - block->bus_addr; + + offset >>= PAGE_SHIFT; + + page_addr = block->page_table[offset].virt_addr; + + if (xgi_temp) { + XGI_INFO("block->bus_addr: 0x%lx block->hw_addr: 0x%lx" + "block->page_count: 0x%lx block->page_order: 0x%lx" + "block->page_table[0x%lx].virt_addr: 0x%lx\n", + block->bus_addr, block->hw_addr, + block->page_count, block->page_order, + offset, block->page_table[offset].virt_addr); + xgi_temp = 0; + } + + if (!page_addr) + goto out; /* hole or end-of-file */ + page = virt_to_page(page_addr); + + /* got it, now increment the count */ + get_page(page); + out: + return page; + +} +#else +struct page *xgi_kern_vma_nopage(struct vm_area_struct *vma, + unsigned long address, int write_access) +{ + xgi_pcie_block_t *block = (xgi_pcie_block_t *) XGI_VMA_PRIVATE(vma); + struct page *page = NOPAGE_SIGBUS; + unsigned long offset = 0; + unsigned long page_addr = 0; +/* + XGI_INFO("VM: mmap([0x%lx-0x%lx] off=0x%lx) address: 0x%lx \n", + vma->vm_start, + vma->vm_end, + XGI_VMA_OFFSET(vma), + address); +*/ + offset = (address - vma->vm_start) + XGI_VMA_OFFSET(vma); + + offset = offset - block->bus_addr; + + offset >>= PAGE_SHIFT; + + page_addr = block->page_table[offset].virt_addr; + + if (xgi_temp) { + XGI_INFO("block->bus_addr: 0x%lx block->hw_addr: 0x%lx" + "block->page_count: 0x%lx block->page_order: 0x%lx" + "block->page_table[0x%lx].virt_addr: 0x%lx\n", + block->bus_addr, block->hw_addr, + block->page_count, block->page_order, + offset, block->page_table[offset].virt_addr); + xgi_temp = 0; + } + + if (!page_addr) + goto out; /* hole or end-of-file */ + page = virt_to_page(page_addr); + + /* got it, now increment the count */ + get_page(page); + out: + return page; +} +#endif + +#if 0 +static struct file_operations xgi_fops = { + /* owner: THIS_MODULE, */ + poll:xgi_kern_poll, + ioctl:xgi_kern_ioctl, + mmap:xgi_kern_mmap, + open:xgi_kern_open, + release:xgi_kern_release, +}; +#endif + +static struct file_operations xgi_fops = { + .owner = THIS_MODULE, + .poll = xgi_kern_poll, + .ioctl = xgi_kern_ioctl, + .mmap = xgi_kern_mmap, + .open = xgi_kern_open, + .release = xgi_kern_release, +}; + +static xgi_file_private_t *xgi_alloc_file_private(void) +{ + xgi_file_private_t *fp; + + XGI_KMALLOC(fp, sizeof(xgi_file_private_t)); + if (!fp) + return NULL; + + memset(fp, 0, sizeof(xgi_file_private_t)); + + /* initialize this file's event queue */ + init_waitqueue_head(&fp->wait_queue); + + xgi_init_lock(fp->fp_lock); + + return fp; +} + +static void xgi_free_file_private(xgi_file_private_t * fp) +{ + if (fp == NULL) + return; + + XGI_KFREE(fp, sizeof(xgi_file_private_t)); +} + +int xgi_kern_open(struct inode *inode, struct file *filp) +{ + xgi_info_t *info = NULL; + int dev_num; + int result = 0, status; + + /* + * the type and num values are only valid if we are not using devfs. + * However, since we use them to retrieve the device pointer, we + * don't need them with devfs as filp->private_data is already + * initialized + */ + filp->private_data = xgi_alloc_file_private(); + if (filp->private_data == NULL) + return -ENOMEM; + + XGI_INFO("filp->private_data %p\n", filp->private_data); + /* + * for control device, just jump to its open routine + * after setting up the private data + */ + if (XGI_IS_CONTROL_DEVICE(inode)) + return xgi_kern_ctl_open(inode, filp); + + /* what device are we talking about? */ + dev_num = XGI_DEVICE_NUMBER(inode); + if (dev_num >= XGI_MAX_DEVICES) { + xgi_free_file_private(filp->private_data); + filp->private_data = NULL; + return -ENODEV; + } + + info = &xgi_devices[dev_num]; + + XGI_INFO("Jong-xgi_kern_open on device %d\n", dev_num); + + xgi_down(info->info_sem); + XGI_CHECK_PCI_CONFIG(info); + + XGI_INFO_FROM_FP(filp) = info; + + /* + * map the memory and allocate isr on first open + */ + + if (!(info->flags & XGI_FLAG_OPEN)) { + XGI_INFO("info->flags & XGI_FLAG_OPEN \n"); + + if (info->device_id == 0) { + XGI_INFO("open of nonexistent device %d\n", dev_num); + result = -ENXIO; + goto failed; + } + + /* initialize struct irqaction */ + status = request_irq(info->irq, xgi_kern_isr, + SA_INTERRUPT | SA_SHIRQ, "xgi", + (void *)info); + if (status != 0) { + if (info->irq && (status == -EBUSY)) { + XGI_ERROR + ("Tried to get irq %d, but another driver", + (unsigned int)info->irq); + XGI_ERROR("has it and is not sharing it.\n"); + } + XGI_ERROR("isr request failed 0x%x\n", status); + result = -EIO; + goto failed; + } + + /* + * #define DECLARE_TASKLET(name, func, data) \ + * struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data } + */ + info->tasklet.func = xgi_kern_isr_bh; + info->tasklet.data = (unsigned long)info; + tasklet_enable(&info->tasklet); + + /* Alloc 1M bytes for cmdbuffer which is flush2D batch array */ + xgi_cmdlist_initialize(info, 0x100000); + + info->flags |= XGI_FLAG_OPEN; + } + + XGI_ATOMIC_INC(info->use_count); + + failed: + xgi_up(info->info_sem); + + if ((result) && filp->private_data) { + xgi_free_file_private(filp->private_data); + filp->private_data = NULL; + } + + return result; +} + +int xgi_kern_release(struct inode *inode, struct file *filp) +{ + xgi_info_t *info = XGI_INFO_FROM_FP(filp); + + XGI_CHECK_PCI_CONFIG(info); + + /* + * for control device, just jump to its open routine + * after setting up the private data + */ + if (XGI_IS_CONTROL_DEVICE(inode)) + return xgi_kern_ctl_close(inode, filp); + + XGI_INFO("Jong-xgi_kern_release on device %d\n", + XGI_DEVICE_NUMBER(inode)); + + xgi_down(info->info_sem); + if (XGI_ATOMIC_DEC_AND_TEST(info->use_count)) { + + /* + * The usage count for this device has dropped to zero, it can be shut + * down safely; disable its interrupts. + */ + + /* + * Disable this device's tasklet to make sure that no bottom half will + * run with undefined device state. + */ + tasklet_disable(&info->tasklet); + + /* + * Free the IRQ, which may block until all pending interrupt processing + * has completed. + */ + free_irq(info->irq, (void *)info); + + xgi_cmdlist_cleanup(info); + + /* leave INIT flag alone so we don't reinit every time */ + info->flags &= ~XGI_FLAG_OPEN; + } + + xgi_up(info->info_sem); + + if (FILE_PRIVATE(filp)) { + xgi_free_file_private(FILE_PRIVATE(filp)); + FILE_PRIVATE(filp) = NULL; + } + + return 0; +} + +int xgi_kern_mmap(struct file *filp, struct vm_area_struct *vma) +{ + //struct inode *inode = INODE_FROM_FP(filp); + xgi_info_t *info = XGI_INFO_FROM_FP(filp); + xgi_pcie_block_t *block; + int pages = 0; + unsigned long prot; + + XGI_INFO("Jong-VM: mmap([0x%lx-0x%lx] off=0x%lx)\n", + vma->vm_start, vma->vm_end, XGI_VMA_OFFSET(vma)); + + XGI_CHECK_PCI_CONFIG(info); + + if (XGI_MASK_OFFSET(vma->vm_start) + || XGI_MASK_OFFSET(vma->vm_end)) { + XGI_ERROR("VM: bad mmap range: %lx - %lx\n", + vma->vm_start, vma->vm_end); + return -ENXIO; + } + + pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; + + vma->vm_ops = &xgi_vm_ops; + + /* XGI IO(reg) space */ + if (IS_IO_OFFSET + (info, XGI_VMA_OFFSET(vma), vma->vm_end - vma->vm_start)) { + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + if (XGI_REMAP_PAGE_RANGE(vma->vm_start, + XGI_VMA_OFFSET(vma), + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) + return -EAGAIN; + + /* mark it as IO so that we don't dump it on core dump */ + vma->vm_flags |= VM_IO; + XGI_INFO("VM: mmap io space \n"); + } + /* XGI fb space */ + /* Jong 06/14/2006; moved behind PCIE or modify IS_FB_OFFSET */ + else if (IS_FB_OFFSET + (info, XGI_VMA_OFFSET(vma), vma->vm_end - vma->vm_start)) { + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + if (XGI_REMAP_PAGE_RANGE(vma->vm_start, + XGI_VMA_OFFSET(vma), + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) + return -EAGAIN; + + // mark it as IO so that we don't dump it on core dump + vma->vm_flags |= VM_IO; + XGI_INFO("VM: mmap fb space \n"); + } + /* PCIE allocator */ + /* XGI_VMA_OFFSET(vma) is offset based on pcie.base (HW address space) */ + else if (IS_PCIE_OFFSET + (info, XGI_VMA_OFFSET(vma), vma->vm_end - vma->vm_start)) { + xgi_down(info->pcie_sem); + + block = + (xgi_pcie_block_t *) xgi_find_pcie_block(info, + XGI_VMA_OFFSET + (vma)); + + if (block == NULL) { + XGI_ERROR("couldn't find pre-allocated PCIE memory!\n"); + xgi_up(info->pcie_sem); + return -EAGAIN; + } + + if (block->page_count != pages) { + XGI_ERROR + ("pre-allocated PCIE memory has wrong number of pages!\n"); + xgi_up(info->pcie_sem); + return -EAGAIN; + } + + vma->vm_private_data = block; + XGI_ATOMIC_INC(block->use_count); + xgi_up(info->pcie_sem); + + /* + * prevent the swapper from swapping it out + * mark the memory i/o so the buffers aren't + * dumped on core dumps */ + vma->vm_flags |= (VM_LOCKED | VM_IO); + + /* un-cached */ + prot = pgprot_val(vma->vm_page_prot); + /* + if (boot_cpu_data.x86 > 3) + prot |= _PAGE_PCD | _PAGE_PWT; + */ + vma->vm_page_prot = __pgprot(prot); + + XGI_INFO("VM: mmap pcie space \n"); + } +#if 0 + else if (IS_FB_OFFSET + (info, XGI_VMA_OFFSET(vma), vma->vm_end - vma->vm_start)) { + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + if (XGI_REMAP_PAGE_RANGE(vma->vm_start, + XGI_VMA_OFFSET(vma), + vma->vm_end - vma->vm_start, + vma->vm_page_prot)) + return -EAGAIN; + + // mark it as IO so that we don't dump it on core dump + vma->vm_flags |= VM_IO; + XGI_INFO("VM: mmap fb space \n"); + } +#endif + else { + vma->vm_flags |= (VM_IO | VM_LOCKED); + XGI_ERROR("VM: mmap wrong range \n"); + } + + vma->vm_file = filp; + + return 0; +} + +unsigned int xgi_kern_poll(struct file *filp, struct poll_table_struct *wait) +{ + xgi_file_private_t *fp; + xgi_info_t *info; + unsigned int mask = 0; + unsigned long eflags; + + info = XGI_INFO_FROM_FP(filp); + + if (info->device_number == XGI_CONTROL_DEVICE_NUMBER) + return xgi_kern_ctl_poll(filp, wait); + + fp = XGI_GET_FP(filp); + + if (!(filp->f_flags & O_NONBLOCK)) { + /* add us to the list */ + poll_wait(filp, &fp->wait_queue, wait); + } + + xgi_lock_irqsave(fp->fp_lock, eflags); + + /* wake the user on any event */ + if (fp->num_events) { + XGI_INFO("Hey, an event occured!\n"); + /* + * trigger the client, when they grab the event, + * we'll decrement the event count + */ + mask |= (POLLPRI | POLLIN); + } + xgi_unlock_irqsave(fp->fp_lock, eflags); + + return mask; +} + +int xgi_kern_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + xgi_info_t *info; + xgi_mem_alloc_t *alloc = NULL; + + int status = 0; + void *arg_copy; + int arg_size; + int err = 0; + + info = XGI_INFO_FROM_FP(filp); + + XGI_INFO("Jong-ioctl(0x%x, 0x%x, 0x%lx, 0x%x)\n", _IOC_TYPE(cmd), + _IOC_NR(cmd), arg, _IOC_SIZE(cmd)); + /* + * extract the type and number bitfields, and don't decode + * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok() + */ + if (_IOC_TYPE(cmd) != XGI_IOCTL_MAGIC) + return -ENOTTY; + if (_IOC_NR(cmd) > XGI_IOCTL_MAXNR) + return -ENOTTY; + + /* + * the direction is a bitmask, and VERIFY_WRITE catches R/W + * transfers. `Type' is user-oriented, while + * access_ok is kernel-oriented, so the concept of "read" and + * "write" is reversed + */ + if (_IOC_DIR(cmd) & _IOC_READ) { + err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd)); + } else if (_IOC_DIR(cmd) & _IOC_WRITE) { + err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd)); + } + if (err) + return -EFAULT; + + XGI_CHECK_PCI_CONFIG(info); + + arg_size = _IOC_SIZE(cmd); + XGI_KMALLOC(arg_copy, arg_size); + if (arg_copy == NULL) { + XGI_ERROR("failed to allocate ioctl memory\n"); + return -ENOMEM; + } + + /* Jong 05/25/2006 */ + /* copy_from_user(arg_copy, (void *)arg, arg_size); */ + if (copy_from_user(arg_copy, (void *)arg, arg_size)) { + XGI_ERROR("failed to copyin ioctl data\n"); + XGI_INFO("Jong-copy_from_user-fail! \n"); + } else + XGI_INFO("Jong-copy_from_user-OK! \n"); + + alloc = (xgi_mem_alloc_t *) arg_copy; + XGI_INFO("Jong-succeeded in copy_from_user 0x%lx, 0x%x bytes.\n", arg, + arg_size); + + switch (_IOC_NR(cmd)) { + case XGI_ESC_DEVICE_INFO: + XGI_INFO("Jong-xgi_ioctl_get_device_info \n"); + xgi_get_device_info(info, (struct xgi_chip_info_s *)arg_copy); + break; + case XGI_ESC_POST_VBIOS: + XGI_INFO("Jong-xgi_ioctl_post_vbios \n"); + break; + case XGI_ESC_FB_ALLOC: + XGI_INFO("Jong-xgi_ioctl_fb_alloc \n"); + xgi_fb_alloc(info, (struct xgi_mem_req_s *)arg_copy, alloc); + break; + case XGI_ESC_FB_FREE: + XGI_INFO("Jong-xgi_ioctl_fb_free \n"); + xgi_fb_free(info, *(unsigned long *)arg_copy); + break; + case XGI_ESC_MEM_COLLECT: + XGI_INFO("Jong-xgi_ioctl_mem_collect \n"); + xgi_mem_collect(info, (unsigned int *)arg_copy); + break; + case XGI_ESC_PCIE_ALLOC: + XGI_INFO("Jong-xgi_ioctl_pcie_alloc \n"); + xgi_pcie_alloc(info, ((xgi_mem_req_t *) arg_copy)->size, + ((xgi_mem_req_t *) arg_copy)->owner, alloc); + break; + case XGI_ESC_PCIE_FREE: + XGI_INFO("Jong-xgi_ioctl_pcie_free: bus_addr = 0x%lx \n", + *((unsigned long *)arg_copy)); + xgi_pcie_free(info, *((unsigned long *)arg_copy)); + break; + case XGI_ESC_PCIE_CHECK: + XGI_INFO("Jong-xgi_pcie_heap_check \n"); + xgi_pcie_heap_check(); + break; + case XGI_ESC_GET_SCREEN_INFO: + XGI_INFO("Jong-xgi_get_screen_info \n"); + xgi_get_screen_info(info, (struct xgi_screen_info_s *)arg_copy); + break; + case XGI_ESC_PUT_SCREEN_INFO: + XGI_INFO("Jong-xgi_put_screen_info \n"); + xgi_put_screen_info(info, (struct xgi_screen_info_s *)arg_copy); + break; + case XGI_ESC_MMIO_INFO: + XGI_INFO("Jong-xgi_ioctl_get_mmio_info \n"); + xgi_get_mmio_info(info, (struct xgi_mmio_info_s *)arg_copy); + break; + case XGI_ESC_GE_RESET: + XGI_INFO("Jong-xgi_ioctl_ge_reset \n"); + xgi_ge_reset(info); + break; + case XGI_ESC_SAREA_INFO: + XGI_INFO("Jong-xgi_ioctl_sarea_info \n"); + xgi_sarea_info(info, (struct xgi_sarea_info_s *)arg_copy); + break; + case XGI_ESC_DUMP_REGISTER: + XGI_INFO("Jong-xgi_ioctl_dump_register \n"); + xgi_dump_register(info); + break; + case XGI_ESC_DEBUG_INFO: + XGI_INFO("Jong-xgi_ioctl_restore_registers \n"); + xgi_restore_registers(info); + //xgi_write_pcie_mem(info, (struct xgi_mem_req_s *) arg_copy); + //xgi_read_pcie_mem(info, (struct xgi_mem_req_s *) arg_copy); + break; + case XGI_ESC_SUBMIT_CMDLIST: + XGI_INFO("Jong-xgi_ioctl_submit_cmdlist \n"); + xgi_submit_cmdlist(info, (xgi_cmd_info_t *) arg_copy); + break; + case XGI_ESC_TEST_RWINKERNEL: + XGI_INFO("Jong-xgi_test_rwinkernel \n"); + xgi_test_rwinkernel(info, *(unsigned long *)arg_copy); + break; + case XGI_ESC_STATE_CHANGE: + XGI_INFO("Jong-xgi_state_change \n"); + xgi_state_change(info, (xgi_state_info_t *) arg_copy); + break; + case XGI_ESC_CPUID: + XGI_INFO("Jong-XGI_ESC_CPUID \n"); + xgi_get_cpu_id((struct cpu_info_s *)arg_copy); + break; + default: + XGI_INFO("Jong-xgi_ioctl_default \n"); + status = -EINVAL; + break; + } + + if (copy_to_user((void *)arg, arg_copy, arg_size)) { + XGI_ERROR("failed to copyout ioctl data\n"); + XGI_INFO("Jong-copy_to_user-fail! \n"); + } else + XGI_INFO("Jong-copy_to_user-OK! \n"); + + XGI_KFREE(arg_copy, arg_size); + return status; +} + +/* + * xgi control driver operations defined here + */ +int xgi_kern_ctl_open(struct inode *inode, struct file *filp) +{ + xgi_info_t *info = &xgi_ctl_device; + + int rc = 0; + + XGI_INFO("Jong-xgi_kern_ctl_open\n"); + + xgi_down(info->info_sem); + info->device_number = XGI_CONTROL_DEVICE_NUMBER; + + /* save the xgi info in file->private_data */ + filp->private_data = info; + + if (XGI_ATOMIC_READ(info->use_count) == 0) { + init_waitqueue_head(&xgi_ctl_waitqueue); + } + + info->flags |= XGI_FLAG_OPEN + XGI_FLAG_CONTROL; + + XGI_ATOMIC_INC(info->use_count); + xgi_up(info->info_sem); + + return rc; +} + +int xgi_kern_ctl_close(struct inode *inode, struct file *filp) +{ + xgi_info_t *info = XGI_INFO_FROM_FP(filp); + + XGI_INFO("Jong-xgi_kern_ctl_close\n"); + + xgi_down(info->info_sem); + if (XGI_ATOMIC_DEC_AND_TEST(info->use_count)) { + info->flags = 0; + } + xgi_up(info->info_sem); + + if (FILE_PRIVATE(filp)) { + xgi_free_file_private(FILE_PRIVATE(filp)); + FILE_PRIVATE(filp) = NULL; + } + + return 0; +} + +unsigned int xgi_kern_ctl_poll(struct file *filp, poll_table * wait) +{ + //xgi_info_t *info = XGI_INFO_FROM_FP(filp);; + unsigned int ret = 0; + + if (!(filp->f_flags & O_NONBLOCK)) { + poll_wait(filp, &xgi_ctl_waitqueue, wait); + } + + return ret; +} + +/* + * xgi proc system + */ +static u8 xgi_find_pcie_capability(struct pci_dev *dev) +{ + u16 status; + u8 cap_ptr, cap_id; + + pci_read_config_word(dev, PCI_STATUS, &status); + status &= PCI_STATUS_CAP_LIST; + if (!status) + return 0; + + switch (dev->hdr_type) { + case PCI_HEADER_TYPE_NORMAL: + case PCI_HEADER_TYPE_BRIDGE: + pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &cap_ptr); + break; + default: + return 0; + } + + do { + cap_ptr &= 0xFC; + pci_read_config_byte(dev, cap_ptr + PCI_CAP_LIST_ID, &cap_id); + pci_read_config_byte(dev, cap_ptr + PCI_CAP_LIST_NEXT, + &cap_ptr); + } while (cap_ptr && cap_id != 0xFF); + + return 0; +} + +static struct pci_dev *xgi_get_pci_device(xgi_info_t * info) +{ + struct pci_dev *dev; + + dev = XGI_PCI_GET_DEVICE(info->vendor_id, info->device_id, NULL); + while (dev) { + if (XGI_PCI_SLOT_NUMBER(dev) == info->slot + && XGI_PCI_BUS_NUMBER(dev) == info->bus) + return dev; + dev = XGI_PCI_GET_DEVICE(info->vendor_id, info->device_id, dev); + } + + return NULL; +} + +int xgi_kern_read_card_info(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct pci_dev *dev; + char *type; + int len = 0; + + xgi_info_t *info; + info = (xgi_info_t *) data; + + dev = xgi_get_pci_device(info); + if (!dev) + return 0; + + type = xgi_find_pcie_capability(dev) ? "PCIE" : "PCI"; + len += sprintf(page + len, "Card Type: \t %s\n", type); + + XGI_PCI_DEV_PUT(dev); + return len; +} + +int xgi_kern_read_version(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + int len = 0; + + len += sprintf(page + len, "XGI version: %s\n", "1.0"); + len += sprintf(page + len, "GCC version: %s\n", "3.0"); + + return len; +} + +int xgi_kern_read_pcie_info(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + return 0; +} + +int xgi_kern_read_status(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + return 0; +} + +static void xgi_proc_create(void) +{ +#ifdef CONFIG_PROC_FS + + struct pci_dev *dev; + int i = 0; + char name[6]; + + struct proc_dir_entry *entry; + struct proc_dir_entry *proc_xgi_pcie, *proc_xgi_cards; + + xgi_info_t *info; + xgi_info_t *xgi_max_devices; + + /* world readable directory */ + int flags = S_IFDIR | S_IRUGO | S_IXUGO; + + proc_xgi = create_proc_entry("xgi", flags, proc_root_driver); + if (!proc_xgi) + goto failed; + + proc_xgi_cards = create_proc_entry("cards", flags, proc_xgi); + if (!proc_xgi_cards) + goto failed; + + proc_xgi_pcie = create_proc_entry("pcie", flags, proc_xgi); + if (!proc_xgi_pcie) + goto failed; + + /* + * Set the module owner to ensure that the reference + * count reflects accesses to the proc files. + */ + proc_xgi->owner = THIS_MODULE; + proc_xgi_cards->owner = THIS_MODULE; + proc_xgi_pcie->owner = THIS_MODULE; + + xgi_max_devices = xgi_devices + XGI_MAX_DEVICES; + for (info = xgi_devices; info < xgi_max_devices; info++) { + if (info->device_id == 0) + break; + + /* world readable file */ + flags = S_IFREG | S_IRUGO; + + dev = xgi_get_pci_device(info); + if (!dev) + break; + + sprintf(name, "%d", i++); + entry = create_proc_entry(name, flags, proc_xgi_cards); + if (!entry) { + XGI_PCI_DEV_PUT(dev); + goto failed; + } + + entry->data = info; + entry->read_proc = xgi_kern_read_card_info; + entry->owner = THIS_MODULE; + + if (xgi_find_pcie_capability(dev)) { + entry = + create_proc_entry("status", flags, proc_xgi_pcie); + if (!entry) { + XGI_PCI_DEV_PUT(dev); + goto failed; + } + + entry->data = info; + entry->read_proc = xgi_kern_read_status; + entry->owner = THIS_MODULE; + + entry = create_proc_entry("card", flags, proc_xgi_pcie); + if (!entry) { + XGI_PCI_DEV_PUT(dev); + goto failed; + } + + entry->data = info; + entry->read_proc = xgi_kern_read_pcie_info; + entry->owner = THIS_MODULE; + } + + XGI_PCI_DEV_PUT(dev); + } + + entry = create_proc_entry("version", flags, proc_xgi); + if (!entry) + goto failed; + + entry->read_proc = xgi_kern_read_version; + entry->owner = THIS_MODULE; + + entry = create_proc_entry("host-bridge", flags, proc_xgi_pcie); + if (!entry) + goto failed; + + entry->data = NULL; + entry->read_proc = xgi_kern_read_pcie_info; + entry->owner = THIS_MODULE; + + return; + + failed: + XGI_ERROR("failed to create /proc entries!\n"); + xgi_proc_remove_all(proc_xgi); +#endif +} + +#ifdef CONFIG_PROC_FS +static void xgi_proc_remove_all(struct proc_dir_entry *entry) +{ + while (entry) { + struct proc_dir_entry *next = entry->next; + if (entry->subdir) + xgi_proc_remove_all(entry->subdir); + remove_proc_entry(entry->name, entry->parent); + if (entry == proc_xgi) + break; + entry = next; + } +} +#endif + +static void xgi_proc_remove(void) +{ +#ifdef CONFIG_PROC_FS + xgi_proc_remove_all(proc_xgi); +#endif +} + +/* + * driver receives an interrupt if someone waiting, then hand it off. + */ +irqreturn_t xgi_kern_isr(int irq, void *dev_id, struct pt_regs *regs) +{ + xgi_info_t *info = (xgi_info_t *) dev_id; + u32 need_to_run_bottom_half = 0; + + //XGI_INFO("xgi_kern_isr \n"); + + //XGI_CHECK_PCI_CONFIG(info); + + //xgi_dvi_irq_handler(info); + + if (need_to_run_bottom_half) { + tasklet_schedule(&info->tasklet); + } + + return IRQ_HANDLED; +} + +void xgi_kern_isr_bh(unsigned long data) +{ + xgi_info_t *info = (xgi_info_t *) data; + + XGI_INFO("xgi_kern_isr_bh \n"); + + //xgi_dvi_irq_handler(info); + + XGI_CHECK_PCI_CONFIG(info); +} + +static void xgi_lock_init(xgi_info_t * info) +{ + if (info == NULL) + return; + + spin_lock_init(&info->info_lock); + + sema_init(&info->info_sem, 1); + sema_init(&info->fb_sem, 1); + sema_init(&info->pcie_sem, 1); + + XGI_ATOMIC_SET(info->use_count, 0); +} + +static void xgi_dev_init(xgi_info_t * info) +{ + struct pci_dev *pdev = NULL; + struct xgi_dev *dev; + int found = 0; + u16 pci_cmd; + + XGI_INFO("Enter xgi_dev_init \n"); + + //XGI_PCI_FOR_EACH_DEV(pdev) + { + for (dev = xgidev_list; dev->vendor; dev++) { + if ((dev->vendor == pdev->vendor) + && (dev->device == pdev->device)) { + XGI_INFO("dev->vendor = pdev->vendor= %x \n", + dev->vendor); + XGI_INFO("dev->device = pdev->device= %x \n", + dev->device); + + xgi_devices[found].device_id = pdev->device; + + pci_read_config_byte(pdev, PCI_REVISION_ID, + &xgi_devices[found]. + revision_id); + + XGI_INFO("PCI_REVISION_ID= %x \n", + xgi_devices[found].revision_id); + + pci_read_config_word(pdev, PCI_COMMAND, + &pci_cmd); + + XGI_INFO("PCI_COMMAND = %x \n", pci_cmd); + + break; + } + } + } +} + +/* + * Export to Linux Kernel + */ + +static int __init xgi_init_module(void) +{ + xgi_info_t *info = &xgi_devices[xgi_num_devices]; + int i, result; + + XGI_INFO("Jong-xgi kernel driver %s initializing\n", XGI_DRV_VERSION); + //SET_MODULE_OWNER(&xgi_fops); + + memset(xgi_devices, 0, sizeof(xgi_devices)); + + if (pci_register_driver(&xgi_pci_driver) < 0) { + pci_unregister_driver(&xgi_pci_driver); + XGI_ERROR("no XGI graphics adapter found\n"); + return -ENODEV; + } + + XGI_INFO("Jong-xgi_devices[%d].fb.base.: 0x%lx \n", xgi_num_devices, + xgi_devices[xgi_num_devices].fb.base); + XGI_INFO("Jong-xgi_devices[%d].fb.size.: 0x%lx \n", xgi_num_devices, + xgi_devices[xgi_num_devices].fb.size); + +/* Jong 07/27/2006; test for ubuntu */ +/* +#ifdef CONFIG_DEVFS_FS + + XGI_INFO("Jong-Use devfs \n"); + do + { + xgi_devfs_handles[0] = XGI_DEVFS_REGISTER("xgi", 0); + if (xgi_devfs_handles[0] == NULL) + { + result = -ENOMEM; + XGI_ERROR("devfs register failed\n"); + goto failed; + } + } while(0); + #else *//* no devfs, do it the "classic" way */ + + XGI_INFO("Jong-Use non-devfs \n"); + /* + * Register your major, and accept a dynamic number. This is the + * first thing to do, in order to avoid releasing other module's + * fops in scull_cleanup_module() + */ + result = XGI_REGISTER_CHRDEV(xgi_major, "xgi", &xgi_fops); + if (result < 0) { + XGI_ERROR("register chrdev failed\n"); + pci_unregister_driver(&xgi_pci_driver); + return result; + } + if (xgi_major == 0) + xgi_major = result; /* dynamic */ + + /* #endif *//* CONFIG_DEVFS_FS */ + + XGI_INFO("Jong-major number %d\n", xgi_major); + + /* instantiate tasklets */ + for (i = 0; i < XGI_MAX_DEVICES; i++) { + /* + * We keep one tasklet per card to avoid latency issues with more + * than one device; no two instances of a single tasklet are ever + * executed concurrently. + */ + XGI_ATOMIC_SET(xgi_devices[i].tasklet.count, 1); + } + + /* init the xgi control device */ + { + xgi_info_t *info_ctl = &xgi_ctl_device; + xgi_lock_init(info_ctl); + } + + /* Init the resource manager */ + INIT_LIST_HEAD(&xgi_mempid_list); + if (!xgi_fb_heap_init(info)) { + XGI_ERROR("xgi_fb_heap_init() failed\n"); + result = -EIO; + goto failed; + } + + /* Init the resource manager */ + if (!xgi_pcie_heap_init(info)) { + XGI_ERROR("xgi_pcie_heap_init() failed\n"); + result = -EIO; + goto failed; + } + + /* create /proc/driver/xgi */ + xgi_proc_create(); + +#if defined(DEBUG) + inter_module_register("xgi_devices", THIS_MODULE, xgi_devices); +#endif + + return 0; + + failed: +#ifdef CONFIG_DEVFS_FS + XGI_DEVFS_REMOVE_CONTROL(); + XGI_DEVFS_REMOVE_DEVICE(xgi_num_devices); +#endif + + if (XGI_UNREGISTER_CHRDEV(xgi_major, "xgi") < 0) + XGI_ERROR("unregister xgi chrdev failed\n"); + + for (i = 0; i < xgi_num_devices; i++) { + if (xgi_devices[i].dev) { + release_mem_region(xgi_devices[i].fb.base, + xgi_devices[i].fb.size); + release_mem_region(xgi_devices[i].mmio.base, + xgi_devices[i].mmio.size); + } + } + + pci_unregister_driver(&xgi_pci_driver); + return result; + + return 1; +} + +void __exit xgi_exit_module(void) +{ + int i; + xgi_info_t *info, *max_devices; + +#ifdef CONFIG_DEVFS_FS + /* + XGI_DEVFS_REMOVE_CONTROL(); + for (i = 0; i < XGI_MAX_DEVICES; i++) + XGI_DEVFS_REMOVE_DEVICE(i); + */ + XGI_DEVFS_REMOVE_DEVICE(xgi_num_devices); +#endif + + if (XGI_UNREGISTER_CHRDEV(xgi_major, "xgi") < 0) + XGI_ERROR("unregister xgi chrdev failed\n"); + + XGI_INFO("Jong-unregister xgi chrdev scceeded\n"); + for (i = 0; i < XGI_MAX_DEVICES; i++) { + if (xgi_devices[i].dev) { + /* clean up the flush2D batch array */ + xgi_cmdlist_cleanup(&xgi_devices[i]); + + if (xgi_devices[i].fb.vbase != NULL) { + iounmap((void *)xgi_devices[i].fb.vbase); + xgi_devices[i].fb.vbase = NULL; + } + if (xgi_devices[i].mmio.vbase != NULL) { + iounmap((void *)xgi_devices[i].mmio.vbase); + xgi_devices[i].mmio.vbase = NULL; + } + //release_mem_region(xgi_devices[i].fb.base, xgi_devices[i].fb.size); + //XGI_INFO("release frame buffer mem region scceeded\n"); + + release_mem_region(xgi_devices[i].mmio.base, + xgi_devices[i].mmio.size); + XGI_INFO("release MMIO mem region scceeded\n"); + + xgi_fb_heap_cleanup(&xgi_devices[i]); + XGI_INFO("xgi_fb_heap_cleanup scceeded\n"); + + xgi_pcie_heap_cleanup(&xgi_devices[i]); + XGI_INFO("xgi_pcie_heap_cleanup scceeded\n"); + + XGI_PCI_DISABLE_DEVICE(xgi_devices[i].dev); + } + } + + pci_unregister_driver(&xgi_pci_driver); + + /* remove /proc/driver/xgi */ + xgi_proc_remove(); + +#if defined(DEBUG) + inter_module_unregister("xgi_devices"); +#endif +} + +module_init(xgi_init_module); +module_exit(xgi_exit_module); + +#if defined(XGI_PM_SUPPORT_ACPI) +int xgi_acpi_event(struct pci_dev *dev, u32 state) +{ + return 1; +} + +int xgi_kern_acpi_standby(struct pci_dev *dev, u32 state) +{ + return 1; +} + +int xgi_kern_acpi_resume(struct pci_dev *dev) +{ + return 1; +} +#endif + +MODULE_AUTHOR("Andrea Zhang "); +MODULE_DESCRIPTION("xgi kernel driver for xgi cards"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 8cee7dca95bc2114eb90640cf83ac87c29243683 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Tue, 26 Jun 2007 13:46:36 -0700 Subject: Clean up warnings about unused variables and functions. --- linux-core/xgi_drv.c | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index 0c37d00e..75204283 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -153,11 +153,6 @@ static inline void xgi_check_pci_config(xgi_info_t * info, int line) pci_write_config_word(info->dev, PCI_COMMAND, cmd); } -static int xgi_post_vbios(xgi_ioctl_post_vbios_t * info) -{ - return 1; -} - /* * struct pci_device_id { * unsigned int vendor, device; // Vendor and device ID or PCI_ANY_ID @@ -1484,14 +1479,8 @@ static int __init xgi_init_module(void) void __exit xgi_exit_module(void) { int i; - xgi_info_t *info, *max_devices; #ifdef CONFIG_DEVFS_FS - /* - XGI_DEVFS_REMOVE_CONTROL(); - for (i = 0; i < XGI_MAX_DEVICES; i++) - XGI_DEVFS_REMOVE_DEVICE(i); - */ XGI_DEVFS_REMOVE_DEVICE(xgi_num_devices); #endif -- cgit v1.2.3 From 33b8476dfb0f9b5045103c3a9781ba82bcae4a9d Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Fri, 29 Jun 2007 09:30:02 -0700 Subject: Fix return type of xgi_find_pcie_block. This function used to return 'void *', which was then cast to 'xgi_pcie_block_t *' at the only caller. I changed the return type to 'struct xgi_pcie_block_s *' and removed the explicit cast. --- linux-core/xgi_drv.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index 75204283..a01b3c22 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -730,10 +730,7 @@ int xgi_kern_mmap(struct file *filp, struct vm_area_struct *vma) (info, XGI_VMA_OFFSET(vma), vma->vm_end - vma->vm_start)) { xgi_down(info->pcie_sem); - block = - (xgi_pcie_block_t *) xgi_find_pcie_block(info, - XGI_VMA_OFFSET - (vma)); + block = xgi_find_pcie_block(info, XGI_VMA_OFFSET(vma)); if (block == NULL) { XGI_ERROR("couldn't find pre-allocated PCIE memory!\n"); -- cgit v1.2.3 From 88328d4ef007c781874aafedfef59aae0d21a37c Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Fri, 29 Jun 2007 15:27:38 -0700 Subject: Eliminate structure typedefs Documentation/CodingStyle says that 'typedef struct foo foo_t' is evil. I tend to agree. Elminate all uses of such construct. --- linux-core/xgi_drv.c | 108 +++++++++++++++++++++++++-------------------------- 1 file changed, 54 insertions(+), 54 deletions(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index a01b3c22..44b003a8 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -53,14 +53,14 @@ int xgi_major = XGI_DEV_MAJOR; /* xgi reserved major device number. */ static int xgi_num_devices = 0; -xgi_info_t xgi_devices[XGI_MAX_DEVICES]; +struct xgi_info xgi_devices[XGI_MAX_DEVICES]; #if defined(XGI_PM_SUPPORT_APM) static struct pm_dev *apm_xgi_dev[XGI_MAX_DEVICES] = { 0 }; #endif /* add one for the control device */ -xgi_info_t xgi_ctl_device; +struct xgi_info xgi_ctl_device; wait_queue_head_t xgi_ctl_waitqueue; #ifdef CONFIG_PROC_FS @@ -74,7 +74,7 @@ devfs_handle_t xgi_devfs_handles[XGI_MAX_DEVICES]; struct list_head xgi_mempid_list; /* xgi_ functions.. do not take a state device parameter */ -static int xgi_post_vbios(xgi_ioctl_post_vbios_t * info); +static int xgi_post_vbios(struct xgi_ioctl_post_vbios * info); static void xgi_proc_create(void); static void xgi_proc_remove_all(struct proc_dir_entry *); static void xgi_proc_remove(void); @@ -110,7 +110,7 @@ unsigned int xgi_kern_ctl_poll(struct file *, poll_table *); void xgi_kern_isr_bh(unsigned long); irqreturn_t xgi_kern_isr(int, void *, struct pt_regs *); -static void xgi_lock_init(xgi_info_t * info); +static void xgi_lock_init(struct xgi_info * info); #if defined(XGI_PM_SUPPORT_ACPI) int xgi_kern_acpi_standby(struct pci_dev *, u32); @@ -128,7 +128,7 @@ int xgi_kern_acpi_resume(struct pci_dev *); #define XGI_CHECK_PCI_CONFIG(xgi) \ xgi_check_pci_config(xgi, __LINE__) -static inline void xgi_check_pci_config(xgi_info_t * info, int line) +static inline void xgi_check_pci_config(struct xgi_info * info, int line) { unsigned short cmd, flag = 0; @@ -208,7 +208,7 @@ static struct pci_driver xgi_pci_driver = { */ int xgi_kern_probe(struct pci_dev *dev, const struct pci_device_id *id_table) { - xgi_info_t *info; + struct xgi_info *info; if ((dev->vendor != PCI_VENDOR_ID_XGI) || (dev->class != (PCI_CLASS_DISPLAY_VGA << 8))) { @@ -361,8 +361,8 @@ void xgi_kern_vma_open(struct vm_area_struct *vma) vma->vm_start, vma->vm_end, XGI_VMA_OFFSET(vma)); if (XGI_VMA_PRIVATE(vma)) { - xgi_pcie_block_t *block = - (xgi_pcie_block_t *) XGI_VMA_PRIVATE(vma); + struct xgi_pcie_block *block = + (struct xgi_pcie_block *) XGI_VMA_PRIVATE(vma); XGI_ATOMIC_INC(block->use_count); } } @@ -373,8 +373,8 @@ void xgi_kern_vma_release(struct vm_area_struct *vma) vma->vm_start, vma->vm_end, XGI_VMA_OFFSET(vma)); if (XGI_VMA_PRIVATE(vma)) { - xgi_pcie_block_t *block = - (xgi_pcie_block_t *) XGI_VMA_PRIVATE(vma); + struct xgi_pcie_block *block = + (struct xgi_pcie_block *) XGI_VMA_PRIVATE(vma); XGI_ATOMIC_DEC(block->use_count); /* @@ -393,7 +393,7 @@ void xgi_kern_vma_release(struct vm_area_struct *vma) struct page *xgi_kern_vma_nopage(struct vm_area_struct *vma, unsigned long address, int *type) { - xgi_pcie_block_t *block = (xgi_pcie_block_t *) XGI_VMA_PRIVATE(vma); + struct xgi_pcie_block *block = (struct xgi_pcie_block *) XGI_VMA_PRIVATE(vma); struct page *page = NOPAGE_SIGBUS; unsigned long offset = 0; unsigned long page_addr = 0; @@ -436,7 +436,7 @@ struct page *xgi_kern_vma_nopage(struct vm_area_struct *vma, struct page *xgi_kern_vma_nopage(struct vm_area_struct *vma, unsigned long address, int write_access) { - xgi_pcie_block_t *block = (xgi_pcie_block_t *) XGI_VMA_PRIVATE(vma); + struct xgi_pcie_block *block = (struct xgi_pcie_block *) XGI_VMA_PRIVATE(vma); struct page *page = NOPAGE_SIGBUS; unsigned long offset = 0; unsigned long page_addr = 0; @@ -496,15 +496,15 @@ static struct file_operations xgi_fops = { .release = xgi_kern_release, }; -static xgi_file_private_t *xgi_alloc_file_private(void) +static struct xgi_file_private *xgi_alloc_file_private(void) { - xgi_file_private_t *fp; + struct xgi_file_private *fp; - XGI_KMALLOC(fp, sizeof(xgi_file_private_t)); + XGI_KMALLOC(fp, sizeof(struct xgi_file_private)); if (!fp) return NULL; - memset(fp, 0, sizeof(xgi_file_private_t)); + memset(fp, 0, sizeof(struct xgi_file_private)); /* initialize this file's event queue */ init_waitqueue_head(&fp->wait_queue); @@ -514,17 +514,17 @@ static xgi_file_private_t *xgi_alloc_file_private(void) return fp; } -static void xgi_free_file_private(xgi_file_private_t * fp) +static void xgi_free_file_private(struct xgi_file_private * fp) { if (fp == NULL) return; - XGI_KFREE(fp, sizeof(xgi_file_private_t)); + XGI_KFREE(fp, sizeof(struct xgi_file_private)); } int xgi_kern_open(struct inode *inode, struct file *filp) { - xgi_info_t *info = NULL; + struct xgi_info *info = NULL; int dev_num; int result = 0, status; @@ -621,7 +621,7 @@ int xgi_kern_open(struct inode *inode, struct file *filp) int xgi_kern_release(struct inode *inode, struct file *filp) { - xgi_info_t *info = XGI_INFO_FROM_FP(filp); + struct xgi_info *info = XGI_INFO_FROM_FP(filp); XGI_CHECK_PCI_CONFIG(info); @@ -674,8 +674,8 @@ int xgi_kern_release(struct inode *inode, struct file *filp) int xgi_kern_mmap(struct file *filp, struct vm_area_struct *vma) { //struct inode *inode = INODE_FROM_FP(filp); - xgi_info_t *info = XGI_INFO_FROM_FP(filp); - xgi_pcie_block_t *block; + struct xgi_info *info = XGI_INFO_FROM_FP(filp); + struct xgi_pcie_block *block; int pages = 0; unsigned long prot; @@ -792,8 +792,8 @@ int xgi_kern_mmap(struct file *filp, struct vm_area_struct *vma) unsigned int xgi_kern_poll(struct file *filp, struct poll_table_struct *wait) { - xgi_file_private_t *fp; - xgi_info_t *info; + struct xgi_file_private *fp; + struct xgi_info *info; unsigned int mask = 0; unsigned long eflags; @@ -828,8 +828,8 @@ unsigned int xgi_kern_poll(struct file *filp, struct poll_table_struct *wait) int xgi_kern_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { - xgi_info_t *info; - xgi_mem_alloc_t *alloc = NULL; + struct xgi_info *info; + struct xgi_mem_alloc *alloc = NULL; int status = 0; void *arg_copy; @@ -880,21 +880,21 @@ int xgi_kern_ioctl(struct inode *inode, struct file *filp, } else XGI_INFO("Jong-copy_from_user-OK! \n"); - alloc = (xgi_mem_alloc_t *) arg_copy; + alloc = (struct xgi_mem_alloc *) arg_copy; XGI_INFO("Jong-succeeded in copy_from_user 0x%lx, 0x%x bytes.\n", arg, arg_size); switch (_IOC_NR(cmd)) { case XGI_ESC_DEVICE_INFO: XGI_INFO("Jong-xgi_ioctl_get_device_info \n"); - xgi_get_device_info(info, (struct xgi_chip_info_s *)arg_copy); + xgi_get_device_info(info, (struct xgi_chip_info *)arg_copy); break; case XGI_ESC_POST_VBIOS: XGI_INFO("Jong-xgi_ioctl_post_vbios \n"); break; case XGI_ESC_FB_ALLOC: XGI_INFO("Jong-xgi_ioctl_fb_alloc \n"); - xgi_fb_alloc(info, (struct xgi_mem_req_s *)arg_copy, alloc); + xgi_fb_alloc(info, (struct xgi_mem_req *)arg_copy, alloc); break; case XGI_ESC_FB_FREE: XGI_INFO("Jong-xgi_ioctl_fb_free \n"); @@ -906,8 +906,8 @@ int xgi_kern_ioctl(struct inode *inode, struct file *filp, break; case XGI_ESC_PCIE_ALLOC: XGI_INFO("Jong-xgi_ioctl_pcie_alloc \n"); - xgi_pcie_alloc(info, ((xgi_mem_req_t *) arg_copy)->size, - ((xgi_mem_req_t *) arg_copy)->owner, alloc); + xgi_pcie_alloc(info, ((struct xgi_mem_req *) arg_copy)->size, + ((struct xgi_mem_req *) arg_copy)->owner, alloc); break; case XGI_ESC_PCIE_FREE: XGI_INFO("Jong-xgi_ioctl_pcie_free: bus_addr = 0x%lx \n", @@ -920,15 +920,15 @@ int xgi_kern_ioctl(struct inode *inode, struct file *filp, break; case XGI_ESC_GET_SCREEN_INFO: XGI_INFO("Jong-xgi_get_screen_info \n"); - xgi_get_screen_info(info, (struct xgi_screen_info_s *)arg_copy); + xgi_get_screen_info(info, (struct xgi_screen_info *)arg_copy); break; case XGI_ESC_PUT_SCREEN_INFO: XGI_INFO("Jong-xgi_put_screen_info \n"); - xgi_put_screen_info(info, (struct xgi_screen_info_s *)arg_copy); + xgi_put_screen_info(info, (struct xgi_screen_info *)arg_copy); break; case XGI_ESC_MMIO_INFO: XGI_INFO("Jong-xgi_ioctl_get_mmio_info \n"); - xgi_get_mmio_info(info, (struct xgi_mmio_info_s *)arg_copy); + xgi_get_mmio_info(info, (struct xgi_mmio_info *)arg_copy); break; case XGI_ESC_GE_RESET: XGI_INFO("Jong-xgi_ioctl_ge_reset \n"); @@ -936,7 +936,7 @@ int xgi_kern_ioctl(struct inode *inode, struct file *filp, break; case XGI_ESC_SAREA_INFO: XGI_INFO("Jong-xgi_ioctl_sarea_info \n"); - xgi_sarea_info(info, (struct xgi_sarea_info_s *)arg_copy); + xgi_sarea_info(info, (struct xgi_sarea_info *)arg_copy); break; case XGI_ESC_DUMP_REGISTER: XGI_INFO("Jong-xgi_ioctl_dump_register \n"); @@ -945,12 +945,12 @@ int xgi_kern_ioctl(struct inode *inode, struct file *filp, case XGI_ESC_DEBUG_INFO: XGI_INFO("Jong-xgi_ioctl_restore_registers \n"); xgi_restore_registers(info); - //xgi_write_pcie_mem(info, (struct xgi_mem_req_s *) arg_copy); - //xgi_read_pcie_mem(info, (struct xgi_mem_req_s *) arg_copy); + //xgi_write_pcie_mem(info, (struct xgi_mem_req *) arg_copy); + //xgi_read_pcie_mem(info, (struct xgi_mem_req *) arg_copy); break; case XGI_ESC_SUBMIT_CMDLIST: XGI_INFO("Jong-xgi_ioctl_submit_cmdlist \n"); - xgi_submit_cmdlist(info, (xgi_cmd_info_t *) arg_copy); + xgi_submit_cmdlist(info, (struct xgi_cmd_info *) arg_copy); break; case XGI_ESC_TEST_RWINKERNEL: XGI_INFO("Jong-xgi_test_rwinkernel \n"); @@ -958,11 +958,11 @@ int xgi_kern_ioctl(struct inode *inode, struct file *filp, break; case XGI_ESC_STATE_CHANGE: XGI_INFO("Jong-xgi_state_change \n"); - xgi_state_change(info, (xgi_state_info_t *) arg_copy); + xgi_state_change(info, (struct xgi_state_info *) arg_copy); break; case XGI_ESC_CPUID: XGI_INFO("Jong-XGI_ESC_CPUID \n"); - xgi_get_cpu_id((struct cpu_info_s *)arg_copy); + xgi_get_cpu_id((struct cpu_info *)arg_copy); break; default: XGI_INFO("Jong-xgi_ioctl_default \n"); @@ -985,7 +985,7 @@ int xgi_kern_ioctl(struct inode *inode, struct file *filp, */ int xgi_kern_ctl_open(struct inode *inode, struct file *filp) { - xgi_info_t *info = &xgi_ctl_device; + struct xgi_info *info = &xgi_ctl_device; int rc = 0; @@ -1011,7 +1011,7 @@ int xgi_kern_ctl_open(struct inode *inode, struct file *filp) int xgi_kern_ctl_close(struct inode *inode, struct file *filp) { - xgi_info_t *info = XGI_INFO_FROM_FP(filp); + struct xgi_info *info = XGI_INFO_FROM_FP(filp); XGI_INFO("Jong-xgi_kern_ctl_close\n"); @@ -1031,7 +1031,7 @@ int xgi_kern_ctl_close(struct inode *inode, struct file *filp) unsigned int xgi_kern_ctl_poll(struct file *filp, poll_table * wait) { - //xgi_info_t *info = XGI_INFO_FROM_FP(filp);; + //struct xgi_info *info = XGI_INFO_FROM_FP(filp);; unsigned int ret = 0; if (!(filp->f_flags & O_NONBLOCK)) { @@ -1073,7 +1073,7 @@ static u8 xgi_find_pcie_capability(struct pci_dev *dev) return 0; } -static struct pci_dev *xgi_get_pci_device(xgi_info_t * info) +static struct pci_dev *xgi_get_pci_device(struct xgi_info * info) { struct pci_dev *dev; @@ -1095,8 +1095,8 @@ int xgi_kern_read_card_info(char *page, char **start, off_t off, char *type; int len = 0; - xgi_info_t *info; - info = (xgi_info_t *) data; + struct xgi_info *info; + info = (struct xgi_info *) data; dev = xgi_get_pci_device(info); if (!dev) @@ -1143,8 +1143,8 @@ static void xgi_proc_create(void) struct proc_dir_entry *entry; struct proc_dir_entry *proc_xgi_pcie, *proc_xgi_cards; - xgi_info_t *info; - xgi_info_t *xgi_max_devices; + struct xgi_info *info; + struct xgi_info *xgi_max_devices; /* world readable directory */ int flags = S_IFDIR | S_IRUGO | S_IXUGO; @@ -1268,7 +1268,7 @@ static void xgi_proc_remove(void) */ irqreturn_t xgi_kern_isr(int irq, void *dev_id, struct pt_regs *regs) { - xgi_info_t *info = (xgi_info_t *) dev_id; + struct xgi_info *info = (struct xgi_info *) dev_id; u32 need_to_run_bottom_half = 0; //XGI_INFO("xgi_kern_isr \n"); @@ -1286,7 +1286,7 @@ irqreturn_t xgi_kern_isr(int irq, void *dev_id, struct pt_regs *regs) void xgi_kern_isr_bh(unsigned long data) { - xgi_info_t *info = (xgi_info_t *) data; + struct xgi_info *info = (struct xgi_info *) data; XGI_INFO("xgi_kern_isr_bh \n"); @@ -1295,7 +1295,7 @@ void xgi_kern_isr_bh(unsigned long data) XGI_CHECK_PCI_CONFIG(info); } -static void xgi_lock_init(xgi_info_t * info) +static void xgi_lock_init(struct xgi_info * info) { if (info == NULL) return; @@ -1309,7 +1309,7 @@ static void xgi_lock_init(xgi_info_t * info) XGI_ATOMIC_SET(info->use_count, 0); } -static void xgi_dev_init(xgi_info_t * info) +static void xgi_dev_init(struct xgi_info * info) { struct pci_dev *pdev = NULL; struct xgi_dev *dev; @@ -1354,7 +1354,7 @@ static void xgi_dev_init(xgi_info_t * info) static int __init xgi_init_module(void) { - xgi_info_t *info = &xgi_devices[xgi_num_devices]; + struct xgi_info *info = &xgi_devices[xgi_num_devices]; int i, result; XGI_INFO("Jong-xgi kernel driver %s initializing\n", XGI_DRV_VERSION); @@ -1421,7 +1421,7 @@ static int __init xgi_init_module(void) /* init the xgi control device */ { - xgi_info_t *info_ctl = &xgi_ctl_device; + struct xgi_info *info_ctl = &xgi_ctl_device; xgi_lock_init(info_ctl); } -- cgit v1.2.3 From 86e75b7f7f64643c6ef2c0fef353b38753df8239 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Thu, 5 Jul 2007 17:49:13 -0700 Subject: Remove XGI_IOCTL_CPUID and associated cruft. --- linux-core/xgi_drv.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index 44b003a8..081db19e 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -960,10 +960,6 @@ int xgi_kern_ioctl(struct inode *inode, struct file *filp, XGI_INFO("Jong-xgi_state_change \n"); xgi_state_change(info, (struct xgi_state_info *) arg_copy); break; - case XGI_ESC_CPUID: - XGI_INFO("Jong-XGI_ESC_CPUID \n"); - xgi_get_cpu_id((struct cpu_info *)arg_copy); - break; default: XGI_INFO("Jong-xgi_ioctl_default \n"); status = -EINVAL; -- cgit v1.2.3 From 2f2d8b9688743ac6367bf13c3c023310a257ceb7 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Mon, 9 Jul 2007 15:59:09 -0700 Subject: Merge xgi_mem_req and xgi_mem_alloc into a single type. These two structures were used as the request and reply for certain ioctls. Having a different type for an ioctl's input and output is just wierd. In addition, each structure contained fields (e.g., pid) that had no business being there. This change requires updates to user-space. --- linux-core/xgi_drv.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index 081db19e..3608c747 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -894,7 +894,7 @@ int xgi_kern_ioctl(struct inode *inode, struct file *filp, break; case XGI_ESC_FB_ALLOC: XGI_INFO("Jong-xgi_ioctl_fb_alloc \n"); - xgi_fb_alloc(info, (struct xgi_mem_req *)arg_copy, alloc); + xgi_fb_alloc(info, alloc, 0); break; case XGI_ESC_FB_FREE: XGI_INFO("Jong-xgi_ioctl_fb_free \n"); @@ -906,8 +906,7 @@ int xgi_kern_ioctl(struct inode *inode, struct file *filp, break; case XGI_ESC_PCIE_ALLOC: XGI_INFO("Jong-xgi_ioctl_pcie_alloc \n"); - xgi_pcie_alloc(info, ((struct xgi_mem_req *) arg_copy)->size, - ((struct xgi_mem_req *) arg_copy)->owner, alloc); + xgi_pcie_alloc(info, alloc, 0); break; case XGI_ESC_PCIE_FREE: XGI_INFO("Jong-xgi_ioctl_pcie_free: bus_addr = 0x%lx \n", @@ -945,8 +944,6 @@ int xgi_kern_ioctl(struct inode *inode, struct file *filp, case XGI_ESC_DEBUG_INFO: XGI_INFO("Jong-xgi_ioctl_restore_registers \n"); xgi_restore_registers(info); - //xgi_write_pcie_mem(info, (struct xgi_mem_req *) arg_copy); - //xgi_read_pcie_mem(info, (struct xgi_mem_req *) arg_copy); break; case XGI_ESC_SUBMIT_CMDLIST: XGI_INFO("Jong-xgi_ioctl_submit_cmdlist \n"); -- cgit v1.2.3 From a3f56dc3d0620633c7719a01e6e578661d65edfc Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Mon, 9 Jul 2007 16:07:27 -0700 Subject: Adjust the types of the fields of xgi_aperture. --- linux-core/xgi_drv.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index 3608c747..2f0218e8 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -252,8 +252,7 @@ int xgi_kern_probe(struct pci_dev *dev, const struct pci_device_id *id_table) XGI_INFO("info->mmio.base: 0x%lx \n", info->mmio.base); XGI_INFO("info->mmio.size: 0x%lx \n", info->mmio.size); - info->mmio.vbase = (unsigned char *)ioremap_nocache(info->mmio.base, - info->mmio.size); + info->mmio.vbase = ioremap_nocache(info->mmio.base, info->mmio.size); if (!info->mmio.vbase) { release_mem_region(info->mmio.base, info->mmio.size); XGI_ERROR("info->mmio.vbase failed\n"); @@ -282,8 +281,7 @@ int xgi_kern_probe(struct pci_dev *dev, const struct pci_device_id *id_table) goto error_disable_dev; } - info->fb.vbase = (unsigned char *)ioremap_nocache(info->fb.base, - info->fb.size); + info->fb.vbase = ioremap_nocache(info->fb.base, info->fb.size); if (!info->fb.vbase) { @@ -1484,11 +1482,11 @@ void __exit xgi_exit_module(void) xgi_cmdlist_cleanup(&xgi_devices[i]); if (xgi_devices[i].fb.vbase != NULL) { - iounmap((void *)xgi_devices[i].fb.vbase); + iounmap(xgi_devices[i].fb.vbase); xgi_devices[i].fb.vbase = NULL; } if (xgi_devices[i].mmio.vbase != NULL) { - iounmap((void *)xgi_devices[i].mmio.vbase); + iounmap(xgi_devices[i].mmio.vbase); xgi_devices[i].mmio.vbase = NULL; } //release_mem_region(xgi_devices[i].fb.base, xgi_devices[i].fb.size); -- cgit v1.2.3 From 5c481d0a4284ec7311a47fbeab1680d007769668 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Mon, 9 Jul 2007 16:43:48 -0700 Subject: Eliminiate fields in xgi_info that are duplicates of fields in pci_dev. --- linux-core/xgi_drv.c | 51 ++++++++++++++------------------------------------- 1 file changed, 14 insertions(+), 37 deletions(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index 2f0218e8..c4cc8900 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -233,10 +233,6 @@ int xgi_kern_probe(struct pci_dev *dev, const struct pci_device_id *id_table) info = &xgi_devices[xgi_num_devices]; info->dev = dev; - info->vendor_id = dev->vendor; - info->device_id = dev->device; - info->bus = dev->bus->number; - info->slot = PCI_SLOT((dev)->devfn); xgi_lock_init(info); @@ -294,14 +290,13 @@ int xgi_kern_probe(struct pci_dev *dev, const struct pci_device_id *id_table) info->fb.vbase = NULL; XGI_INFO("info->fb.vbase: 0x%p \n", info->fb.vbase); - info->irq = dev->irq; /* check common error condition */ - if (info->irq == 0) { + if (info->dev->irq == 0) { XGI_ERROR("Can't find an IRQ for your XGI card! \n"); goto error_zero_dev; } - XGI_INFO("info->irq: %lx \n", info->irq); + XGI_INFO("info->irq: %lx \n", info->dev->irq); //xgi_enable_dvi_interrupt(info); @@ -568,21 +563,21 @@ int xgi_kern_open(struct inode *inode, struct file *filp) if (!(info->flags & XGI_FLAG_OPEN)) { XGI_INFO("info->flags & XGI_FLAG_OPEN \n"); - if (info->device_id == 0) { + if (info->dev->device == 0) { XGI_INFO("open of nonexistent device %d\n", dev_num); result = -ENXIO; goto failed; } /* initialize struct irqaction */ - status = request_irq(info->irq, xgi_kern_isr, + status = request_irq(info->dev->irq, xgi_kern_isr, SA_INTERRUPT | SA_SHIRQ, "xgi", (void *)info); if (status != 0) { - if (info->irq && (status == -EBUSY)) { + if (info->dev->irq && (status == -EBUSY)) { XGI_ERROR ("Tried to get irq %d, but another driver", - (unsigned int)info->irq); + (unsigned int)info->dev->irq); XGI_ERROR("has it and is not sharing it.\n"); } XGI_ERROR("isr request failed 0x%x\n", status); @@ -651,7 +646,7 @@ int xgi_kern_release(struct inode *inode, struct file *filp) * Free the IRQ, which may block until all pending interrupt processing * has completed. */ - free_irq(info->irq, (void *)info); + free_irq(info->dev->irq, (void *)info); xgi_cmdlist_cleanup(info); @@ -1064,21 +1059,6 @@ static u8 xgi_find_pcie_capability(struct pci_dev *dev) return 0; } -static struct pci_dev *xgi_get_pci_device(struct xgi_info * info) -{ - struct pci_dev *dev; - - dev = XGI_PCI_GET_DEVICE(info->vendor_id, info->device_id, NULL); - while (dev) { - if (XGI_PCI_SLOT_NUMBER(dev) == info->slot - && XGI_PCI_BUS_NUMBER(dev) == info->bus) - return dev; - dev = XGI_PCI_GET_DEVICE(info->vendor_id, info->device_id, dev); - } - - return NULL; -} - int xgi_kern_read_card_info(char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -1089,7 +1069,7 @@ int xgi_kern_read_card_info(char *page, char **start, off_t off, struct xgi_info *info; info = (struct xgi_info *) data; - dev = xgi_get_pci_device(info); + dev = info->dev; if (!dev) return 0; @@ -1162,13 +1142,10 @@ static void xgi_proc_create(void) xgi_max_devices = xgi_devices + XGI_MAX_DEVICES; for (info = xgi_devices; info < xgi_max_devices; info++) { - if (info->device_id == 0) - break; - /* world readable file */ flags = S_IFREG | S_IRUGO; - dev = xgi_get_pci_device(info); + dev = info->dev; if (!dev) break; @@ -1314,19 +1291,19 @@ static void xgi_dev_init(struct xgi_info * info) for (dev = xgidev_list; dev->vendor; dev++) { if ((dev->vendor == pdev->vendor) && (dev->device == pdev->device)) { + u8 rev_id; + XGI_INFO("dev->vendor = pdev->vendor= %x \n", dev->vendor); XGI_INFO("dev->device = pdev->device= %x \n", dev->device); - xgi_devices[found].device_id = pdev->device; + xgi_devices[found].dev = pdev; pci_read_config_byte(pdev, PCI_REVISION_ID, - &xgi_devices[found]. - revision_id); + rev_id); - XGI_INFO("PCI_REVISION_ID= %x \n", - xgi_devices[found].revision_id); + XGI_INFO("PCI_REVISION_ID= %x \n", rev_id); pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd); -- cgit v1.2.3 From 76ca1e858fb8e1a65ea49c0c62350d7ca91044a2 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Mon, 9 Jul 2007 18:54:25 -0700 Subject: Convert occurances of U32 to other types. Most occurances of U32 were converted to u32. These are cases where the data represents something that will be written to the hardware. Other cases were converted to 'unsigned int'. U32 was the last type in xgi_types.h, so that file is removed. --- linux-core/xgi_drv.c | 1 - 1 file changed, 1 deletion(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index c4cc8900..b3425c75 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -25,7 +25,6 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ***************************************************************************/ -#include "xgi_types.h" #include "xgi_linux.h" #include "xgi_drv.h" #include "xgi_regs.h" -- cgit v1.2.3 From 658ff2daf3d2a080da2d859f522a627aef841637 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Mon, 16 Jul 2007 20:58:43 -0700 Subject: Eliminate several useless ioctls and associated cruft. The ioctlss XGI_ESC_DEVICE_INFO, XGI_ESC_MEM_COLLECT, XGI_ESC_PCIE_CHECK, XGI_ESC_GET_SCREEN_INFO, XGI_ESC_PUT_SCREEN_INFO, XGI_ESC_MMIO_INFO, and XGI_ESC_SAREA_INFO, are completely unnecessary. The will be doubly useless when the driver is converted to the DRM infrastructure. --- linux-core/xgi_drv.c | 28 ---------------------------- 1 file changed, 28 deletions(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index b3425c75..bd39dfdc 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -877,10 +877,6 @@ int xgi_kern_ioctl(struct inode *inode, struct file *filp, arg_size); switch (_IOC_NR(cmd)) { - case XGI_ESC_DEVICE_INFO: - XGI_INFO("Jong-xgi_ioctl_get_device_info \n"); - xgi_get_device_info(info, (struct xgi_chip_info *)arg_copy); - break; case XGI_ESC_POST_VBIOS: XGI_INFO("Jong-xgi_ioctl_post_vbios \n"); break; @@ -892,10 +888,6 @@ int xgi_kern_ioctl(struct inode *inode, struct file *filp, XGI_INFO("Jong-xgi_ioctl_fb_free \n"); xgi_fb_free(info, *(unsigned long *)arg_copy); break; - case XGI_ESC_MEM_COLLECT: - XGI_INFO("Jong-xgi_ioctl_mem_collect \n"); - xgi_mem_collect(info, (unsigned int *)arg_copy); - break; case XGI_ESC_PCIE_ALLOC: XGI_INFO("Jong-xgi_ioctl_pcie_alloc \n"); xgi_pcie_alloc(info, alloc, 0); @@ -905,30 +897,10 @@ int xgi_kern_ioctl(struct inode *inode, struct file *filp, *((unsigned long *)arg_copy)); xgi_pcie_free(info, *((unsigned long *)arg_copy)); break; - case XGI_ESC_PCIE_CHECK: - XGI_INFO("Jong-xgi_pcie_heap_check \n"); - xgi_pcie_heap_check(); - break; - case XGI_ESC_GET_SCREEN_INFO: - XGI_INFO("Jong-xgi_get_screen_info \n"); - xgi_get_screen_info(info, (struct xgi_screen_info *)arg_copy); - break; - case XGI_ESC_PUT_SCREEN_INFO: - XGI_INFO("Jong-xgi_put_screen_info \n"); - xgi_put_screen_info(info, (struct xgi_screen_info *)arg_copy); - break; - case XGI_ESC_MMIO_INFO: - XGI_INFO("Jong-xgi_ioctl_get_mmio_info \n"); - xgi_get_mmio_info(info, (struct xgi_mmio_info *)arg_copy); - break; case XGI_ESC_GE_RESET: XGI_INFO("Jong-xgi_ioctl_ge_reset \n"); xgi_ge_reset(info); break; - case XGI_ESC_SAREA_INFO: - XGI_INFO("Jong-xgi_ioctl_sarea_info \n"); - xgi_sarea_info(info, (struct xgi_sarea_info *)arg_copy); - break; case XGI_ESC_DUMP_REGISTER: XGI_INFO("Jong-xgi_ioctl_dump_register \n"); xgi_dump_register(info); -- cgit v1.2.3 From 5ba94c2ab8be350fee495e5cfe94afb8f663956a Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Thu, 19 Jul 2007 10:29:18 -0700 Subject: Initial pass at converting driver to DRM infrastructure. --- linux-core/xgi_drv.c | 1522 +++++++------------------------------------------- 1 file changed, 195 insertions(+), 1327 deletions(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index bd39dfdc..3b9f4cb1 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -25,96 +25,119 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ***************************************************************************/ -#include "xgi_linux.h" + +#include "drmP.h" +#include "drm.h" #include "xgi_drv.h" #include "xgi_regs.h" -#include "xgi_pcie.h" #include "xgi_misc.h" #include "xgi_cmdlist.h" -/* for debug */ -static int xgi_temp = 1; -/* - * global parameters - */ -static struct xgi_dev { - u16 vendor; - u16 device; - const char *name; -} xgidev_list[] = { - { - PCI_VENDOR_ID_XGI, PCI_DEVICE_ID_XP5, "XP5"}, { - PCI_VENDOR_ID_XGI, PCI_DEVICE_ID_XG47, "XG47"}, { - 0, 0, NULL} -}; - -int xgi_major = XGI_DEV_MAJOR; /* xgi reserved major device number. */ +#include "drm_pciids.h" -static int xgi_num_devices = 0; +static struct pci_device_id pciidlist[] = { + xgi_PCI_IDS +}; -struct xgi_info xgi_devices[XGI_MAX_DEVICES]; +static int xgi_bootstrap(DRM_IOCTL_ARGS); -#if defined(XGI_PM_SUPPORT_APM) -static struct pm_dev *apm_xgi_dev[XGI_MAX_DEVICES] = { 0 }; -#endif +static drm_ioctl_desc_t xgi_ioctls[] = { + [DRM_IOCTL_NR(DRM_XGI_BOOTSTRAP)] = {xgi_bootstrap, DRM_AUTH}, -/* add one for the control device */ -struct xgi_info xgi_ctl_device; -wait_queue_head_t xgi_ctl_waitqueue; + [DRM_IOCTL_NR(DRM_XGI_FB_ALLOC)] = {xgi_fb_alloc_ioctl, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_XGI_FB_FREE)] = {xgi_fb_free_ioctl, DRM_AUTH}, -#ifdef CONFIG_PROC_FS -struct proc_dir_entry *proc_xgi; -#endif + [DRM_IOCTL_NR(DRM_XGI_PCIE_ALLOC)] = {xgi_pcie_alloc_ioctl, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_XGI_PCIE_FREE)] = {xgi_pcie_free_ioctl, DRM_AUTH}, -#ifdef CONFIG_DEVFS_FS -devfs_handle_t xgi_devfs_handles[XGI_MAX_DEVICES]; -#endif + [DRM_IOCTL_NR(DRM_XGI_GE_RESET)] = {xgi_ge_reset_ioctl, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_XGI_DUMP_REGISTER)] = {xgi_dump_register_ioctl, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_XGI_DEBUG_INFO)] = {xgi_restore_registers_ioctl, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_XGI_SUBMIT_CMDLIST)] = {xgi_submit_cmdlist_ioctl, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_XGI_TEST_RWINKERNEL)] = {xgi_test_rwinkernel_ioctl, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_XGI_STATE_CHANGE)] = {xgi_state_change_ioctl, DRM_AUTH}, +}; -struct list_head xgi_mempid_list; +static const int xgi_max_ioctl = DRM_ARRAY_SIZE(xgi_ioctls); + +static int probe(struct pci_dev *pdev, const struct pci_device_id *ent); +static int xgi_driver_load(struct drm_device *dev, unsigned long flags); +static int xgi_driver_unload(struct drm_device *dev); +static void xgi_driver_preclose(struct drm_device * dev, DRMFILE filp); +static irqreturn_t xgi_kern_isr(DRM_IRQ_ARGS); + + +static struct drm_driver driver = { + .driver_features = + DRIVER_PCI_DMA | DRIVER_HAVE_DMA | DRIVER_HAVE_IRQ | + DRIVER_IRQ_SHARED | DRIVER_SG, + .dev_priv_size = sizeof(struct xgi_info), + .load = xgi_driver_load, + .unload = xgi_driver_unload, + .preclose = xgi_driver_preclose, + .dma_quiescent = NULL, + .irq_preinstall = NULL, + .irq_postinstall = NULL, + .irq_uninstall = NULL, + .irq_handler = xgi_kern_isr, + .reclaim_buffers = drm_core_reclaim_buffers, + .get_map_ofs = drm_core_get_map_ofs, + .get_reg_ofs = drm_core_get_reg_ofs, + .ioctls = xgi_ioctls, + .dma_ioctl = NULL, + + .fops = { + .owner = THIS_MODULE, + .open = drm_open, + .release = drm_release, + .ioctl = drm_ioctl, + .mmap = drm_mmap, + .poll = drm_poll, + .fasync = drm_fasync, + }, + + .pci_driver = { + .name = DRIVER_NAME, + .id_table = pciidlist, + .probe = probe, + .remove = __devexit_p(drm_cleanup_pci), + }, + + .name = DRIVER_NAME, + .desc = DRIVER_DESC, + .date = DRIVER_DATE, + .major = DRIVER_MAJOR, + .minor = DRIVER_MINOR, + .patchlevel = DRIVER_PATCHLEVEL, -/* xgi_ functions.. do not take a state device parameter */ -static int xgi_post_vbios(struct xgi_ioctl_post_vbios * info); -static void xgi_proc_create(void); -static void xgi_proc_remove_all(struct proc_dir_entry *); -static void xgi_proc_remove(void); +}; -/* xgi_kern_ functions, interfaces used by linux kernel */ -int xgi_kern_probe(struct pci_dev *, const struct pci_device_id *); +static int probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + return drm_get_dev(pdev, ent, &driver); +} -unsigned int xgi_kern_poll(struct file *, poll_table *); -int xgi_kern_ioctl(struct inode *, struct file *, unsigned int, unsigned long); -int xgi_kern_mmap(struct file *, struct vm_area_struct *); -int xgi_kern_open(struct inode *, struct file *); -int xgi_kern_release(struct inode *inode, struct file *filp); -void xgi_kern_vma_open(struct vm_area_struct *vma); -void xgi_kern_vma_release(struct vm_area_struct *vma); -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 1)) -struct page *xgi_kern_vma_nopage(struct vm_area_struct *vma, - unsigned long address, int *type); -#else -struct page *xgi_kern_vma_nopage(struct vm_area_struct *vma, - unsigned long address, int write_access); -#endif +static int __init xgi_init(void) +{ + driver.num_ioctls = xgi_max_ioctl; + return drm_init(&driver, pciidlist); +} -int xgi_kern_read_card_info(char *, char **, off_t off, int, int *, void *); -int xgi_kern_read_status(char *, char **, off_t off, int, int *, void *); -int xgi_kern_read_pcie_info(char *, char **, off_t off, int, int *, void *); -int xgi_kern_read_version(char *, char **, off_t off, int, int *, void *); +static void __exit xgi_exit(void) +{ + drm_exit(&driver); +} -int xgi_kern_ctl_open(struct inode *, struct file *); -int xgi_kern_ctl_close(struct inode *, struct file *); -unsigned int xgi_kern_ctl_poll(struct file *, poll_table *); +module_init(xgi_init); +module_exit(xgi_exit); -void xgi_kern_isr_bh(unsigned long); -irqreturn_t xgi_kern_isr(int, void *, struct pt_regs *); +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL and additional rights"); -static void xgi_lock_init(struct xgi_info * info); -#if defined(XGI_PM_SUPPORT_ACPI) -int xgi_kern_acpi_standby(struct pci_dev *, u32); -int xgi_kern_acpi_resume(struct pci_dev *); -#endif +void xgi_kern_isr_bh(struct drm_device *dev); /* * verify access to pci config space wasn't disabled behind our back @@ -129,1361 +152,206 @@ int xgi_kern_acpi_resume(struct pci_dev *); static inline void xgi_check_pci_config(struct xgi_info * info, int line) { - unsigned short cmd, flag = 0; - - // don't do this on the control device, only the actual devices - if (info->flags & XGI_FLAG_CONTROL) - return; + u16 cmd; + bool flag = 0; - pci_read_config_word(info->dev, PCI_COMMAND, &cmd); + pci_read_config_word(info->dev->pdev, PCI_COMMAND, &cmd); if (!(cmd & PCI_COMMAND_MASTER)) { - XGI_INFO("restoring bus mastering! (%d)\n", line); + DRM_INFO("restoring bus mastering! (%d)\n", line); cmd |= PCI_COMMAND_MASTER; flag = 1; } if (!(cmd & PCI_COMMAND_MEMORY)) { - XGI_INFO("restoring MEM access! (%d)\n", line); + DRM_INFO("restoring MEM access! (%d)\n", line); cmd |= PCI_COMMAND_MEMORY; flag = 1; } if (flag) - pci_write_config_word(info->dev, PCI_COMMAND, cmd); + pci_write_config_word(info->dev->pdev, PCI_COMMAND, cmd); } -/* - * struct pci_device_id { - * unsigned int vendor, device; // Vendor and device ID or PCI_ANY_ID - * unsigned int subvendor, subdevice; // Subsystem ID's or PCI_ANY_ID - * unsigned int class, class_mask; // (class,subclass,prog-if) triplet - * unsigned long driver_data; // Data private to the driver - * }; - */ -static struct pci_device_id xgi_dev_table[] = { - { - .vendor = PCI_VENDOR_ID_XGI, - .device = PCI_ANY_ID, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .class = (PCI_CLASS_DISPLAY_VGA << 8), - .class_mask = ~0, - }, - {} -}; - -/* - * #define MODULE_DEVICE_TABLE(type,name) \ - * MODULE_GENERIC_TABLE(type##_device,name) - */ -MODULE_DEVICE_TABLE(pci, xgi_dev_table); - -/* - * struct pci_driver { - * struct list_head node; - * char *name; - * const struct pci_device_id *id_table; // NULL if wants all devices - * int (*probe)(struct pci_dev *dev, const struct pci_device_id *id); // New device inserted - * void (*remove)(struct pci_dev *dev); // Device removed (NULL if not a hot-plug capable driver) - * int (*save_state)(struct pci_dev *dev, u32 state); // Save Device Context - * int (*suspend)(struct pci_dev *dev, u32 state); // Device suspended - * int (*resume)(struct pci_dev *dev); // Device woken up - * int (*enable_wake)(struct pci_dev *dev, u32 state, int enable); // Enable wake event - * }; - */ -static struct pci_driver xgi_pci_driver = { - .name = "xgi", - .id_table = xgi_dev_table, - .probe = xgi_kern_probe, -#if defined(XGI_SUPPORT_ACPI) - .suspend = xgi_kern_acpi_standby, - .resume = xgi_kern_acpi_resume, -#endif -}; - -/* - * find xgi devices and set initial state - */ -int xgi_kern_probe(struct pci_dev *dev, const struct pci_device_id *id_table) +int xgi_bootstrap(DRM_IOCTL_ARGS) { - struct xgi_info *info; - - if ((dev->vendor != PCI_VENDOR_ID_XGI) - || (dev->class != (PCI_CLASS_DISPLAY_VGA << 8))) { - return -1; - } - - if (xgi_num_devices == XGI_MAX_DEVICES) { - XGI_INFO("maximum device number (%d) reached!\n", - xgi_num_devices); - return -1; - } - - /* enable io, mem, and bus-mastering in pci config space */ - if (pci_enable_device(dev) != 0) { - XGI_INFO("pci_enable_device failed, aborting\n"); - return -1; - } - - XGI_INFO("maximum device number (%d) reached \n", xgi_num_devices); - - pci_set_master(dev); - - info = &xgi_devices[xgi_num_devices]; - info->dev = dev; + DRM_DEVICE; + struct xgi_info *info = dev->dev_private; + struct xgi_bootstrap bs; + int err; - xgi_lock_init(info); - info->mmio.base = XGI_PCI_RESOURCE_START(dev, 1); - info->mmio.size = XGI_PCI_RESOURCE_SIZE(dev, 1); + DRM_COPY_FROM_USER_IOCTL(bs, (struct xgi_bootstrap __user *) data, + sizeof(bs)); - /* check IO region */ - if (!request_mem_region(info->mmio.base, info->mmio.size, "xgi")) { - XGI_ERROR("cannot reserve MMIO memory\n"); - goto error_disable_dev; + if (info->bootstrap_done) { + return 0; } - XGI_INFO("info->mmio.base: 0x%lx \n", info->mmio.base); - XGI_INFO("info->mmio.size: 0x%lx \n", info->mmio.size); - - info->mmio.vbase = ioremap_nocache(info->mmio.base, info->mmio.size); - if (!info->mmio.vbase) { - release_mem_region(info->mmio.base, info->mmio.size); - XGI_ERROR("info->mmio.vbase failed\n"); - goto error_disable_dev; - } xgi_enable_mmio(info); - //xgi_enable_ge(info); - - XGI_INFO("info->mmio.vbase: 0x%p \n", info->mmio.vbase); - - info->fb.base = XGI_PCI_RESOURCE_START(dev, 0); - info->fb.size = XGI_PCI_RESOURCE_SIZE(dev, 0); - - XGI_INFO("info->fb.base: 0x%lx \n", info->fb.base); - XGI_INFO("info->fb.size: 0x%lx \n", info->fb.size); - - info->fb.size = bIn3cf(0x54) * 8 * 1024 * 1024; - XGI_INFO("info->fb.size: 0x%lx \n", info->fb.size); - - /* check frame buffer region - if (!request_mem_region(info->fb.base, info->fb.size, "xgi")) - { - release_mem_region(info->mmio.base, info->mmio.size); - XGI_ERROR("cannot reserve frame buffer memory\n"); - goto error_disable_dev; - } - - info->fb.vbase = ioremap_nocache(info->fb.base, info->fb.size); - - if (!info->fb.vbase) - { - release_mem_region(info->mmio.base, info->mmio.size); - release_mem_region(info->fb.base, info->fb.size); - XGI_ERROR("info->fb.vbase failed\n"); - goto error_disable_dev; - } - */ - info->fb.vbase = NULL; - XGI_INFO("info->fb.vbase: 0x%p \n", info->fb.vbase); - - - /* check common error condition */ - if (info->dev->irq == 0) { - XGI_ERROR("Can't find an IRQ for your XGI card! \n"); - goto error_zero_dev; - } - XGI_INFO("info->irq: %lx \n", info->dev->irq); - - //xgi_enable_dvi_interrupt(info); - - /* sanity check the IO apertures */ - if ((info->mmio.base == 0) || (info->mmio.size == 0) - || (info->fb.base == 0) || (info->fb.size == 0)) { - XGI_ERROR("The IO regions for your XGI card are invalid.\n"); - - if ((info->mmio.base == 0) || (info->mmio.size == 0)) { - XGI_ERROR("mmio appears to be wrong: 0x%lx 0x%lx\n", - info->mmio.base, info->mmio.size); - } - - if ((info->fb.base == 0) || (info->fb.size == 0)) { - XGI_ERROR - ("frame buffer appears to be wrong: 0x%lx 0x%lx\n", - info->fb.base, info->fb.size); - } - - goto error_zero_dev; - } - //xgi_num_devices++; - - return 0; - - error_zero_dev: - release_mem_region(info->fb.base, info->fb.size); - release_mem_region(info->mmio.base, info->mmio.size); - - error_disable_dev: - pci_disable_device(dev); - return -1; + info->pcie.size = bs.gart_size * (1024 * 1024); -} - -/* - * vma operations... - * this is only called when the vmas are duplicated. this - * appears to only happen when the process is cloned to create - * a new process, and not when the process is threaded. - * - * increment the usage count for the physical pages, so when - * this clone unmaps the mappings, the pages are not - * deallocated under the original process. - */ -struct vm_operations_struct xgi_vm_ops = { - .open = xgi_kern_vma_open, - .close = xgi_kern_vma_release, - .nopage = xgi_kern_vma_nopage, -}; - -void xgi_kern_vma_open(struct vm_area_struct *vma) -{ - XGI_INFO("VM: vma_open for 0x%lx - 0x%lx, offset 0x%lx\n", - vma->vm_start, vma->vm_end, XGI_VMA_OFFSET(vma)); - - if (XGI_VMA_PRIVATE(vma)) { - struct xgi_pcie_block *block = - (struct xgi_pcie_block *) XGI_VMA_PRIVATE(vma); - XGI_ATOMIC_INC(block->use_count); - } -} - -void xgi_kern_vma_release(struct vm_area_struct *vma) -{ - XGI_INFO("VM: vma_release for 0x%lx - 0x%lx, offset 0x%lx\n", - vma->vm_start, vma->vm_end, XGI_VMA_OFFSET(vma)); - - if (XGI_VMA_PRIVATE(vma)) { - struct xgi_pcie_block *block = - (struct xgi_pcie_block *) XGI_VMA_PRIVATE(vma); - XGI_ATOMIC_DEC(block->use_count); - - /* - * if use_count is down to 0, the kernel virtual mapping was freed - * but the underlying physical pages were not, we need to clear the - * bit and free the physical pages. - */ - if (XGI_ATOMIC_READ(block->use_count) == 0) { - // Need TO Finish - XGI_VMA_PRIVATE(vma) = NULL; - } - } -} - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 1)) -struct page *xgi_kern_vma_nopage(struct vm_area_struct *vma, - unsigned long address, int *type) -{ - struct xgi_pcie_block *block = (struct xgi_pcie_block *) XGI_VMA_PRIVATE(vma); - struct page *page = NOPAGE_SIGBUS; - unsigned long offset = 0; - unsigned long page_addr = 0; -/* - XGI_INFO("VM: mmap([0x%lx-0x%lx] off=0x%lx) address: 0x%lx \n", - vma->vm_start, - vma->vm_end, - XGI_VMA_OFFSET(vma), - address); -*/ - offset = (address - vma->vm_start) + XGI_VMA_OFFSET(vma); - - offset = offset - block->bus_addr; - - offset >>= PAGE_SHIFT; - - page_addr = block->page_table[offset].virt_addr; - - if (xgi_temp) { - XGI_INFO("block->bus_addr: 0x%lx block->hw_addr: 0x%lx" - "block->page_count: 0x%lx block->page_order: 0x%lx" - "block->page_table[0x%lx].virt_addr: 0x%lx\n", - block->bus_addr, block->hw_addr, - block->page_count, block->page_order, - offset, block->page_table[offset].virt_addr); - xgi_temp = 0; - } - - if (!page_addr) - goto out; /* hole or end-of-file */ - page = virt_to_page(page_addr); - - /* got it, now increment the count */ - get_page(page); - out: - return page; - -} -#else -struct page *xgi_kern_vma_nopage(struct vm_area_struct *vma, - unsigned long address, int write_access) -{ - struct xgi_pcie_block *block = (struct xgi_pcie_block *) XGI_VMA_PRIVATE(vma); - struct page *page = NOPAGE_SIGBUS; - unsigned long offset = 0; - unsigned long page_addr = 0; -/* - XGI_INFO("VM: mmap([0x%lx-0x%lx] off=0x%lx) address: 0x%lx \n", - vma->vm_start, - vma->vm_end, - XGI_VMA_OFFSET(vma), - address); -*/ - offset = (address - vma->vm_start) + XGI_VMA_OFFSET(vma); - - offset = offset - block->bus_addr; - - offset >>= PAGE_SHIFT; - - page_addr = block->page_table[offset].virt_addr; - - if (xgi_temp) { - XGI_INFO("block->bus_addr: 0x%lx block->hw_addr: 0x%lx" - "block->page_count: 0x%lx block->page_order: 0x%lx" - "block->page_table[0x%lx].virt_addr: 0x%lx\n", - block->bus_addr, block->hw_addr, - block->page_count, block->page_order, - offset, block->page_table[offset].virt_addr); - xgi_temp = 0; - } - - if (!page_addr) - goto out; /* hole or end-of-file */ - page = virt_to_page(page_addr); - - /* got it, now increment the count */ - get_page(page); - out: - return page; -} -#endif - -#if 0 -static struct file_operations xgi_fops = { - /* owner: THIS_MODULE, */ - poll:xgi_kern_poll, - ioctl:xgi_kern_ioctl, - mmap:xgi_kern_mmap, - open:xgi_kern_open, - release:xgi_kern_release, -}; -#endif - -static struct file_operations xgi_fops = { - .owner = THIS_MODULE, - .poll = xgi_kern_poll, - .ioctl = xgi_kern_ioctl, - .mmap = xgi_kern_mmap, - .open = xgi_kern_open, - .release = xgi_kern_release, -}; - -static struct xgi_file_private *xgi_alloc_file_private(void) -{ - struct xgi_file_private *fp; - - XGI_KMALLOC(fp, sizeof(struct xgi_file_private)); - if (!fp) - return NULL; - - memset(fp, 0, sizeof(struct xgi_file_private)); - - /* initialize this file's event queue */ - init_waitqueue_head(&fp->wait_queue); - - xgi_init_lock(fp->fp_lock); - - return fp; -} - -static void xgi_free_file_private(struct xgi_file_private * fp) -{ - if (fp == NULL) - return; - - XGI_KFREE(fp, sizeof(struct xgi_file_private)); -} - -int xgi_kern_open(struct inode *inode, struct file *filp) -{ - struct xgi_info *info = NULL; - int dev_num; - int result = 0, status; - - /* - * the type and num values are only valid if we are not using devfs. - * However, since we use them to retrieve the device pointer, we - * don't need them with devfs as filp->private_data is already - * initialized - */ - filp->private_data = xgi_alloc_file_private(); - if (filp->private_data == NULL) - return -ENOMEM; - - XGI_INFO("filp->private_data %p\n", filp->private_data); - /* - * for control device, just jump to its open routine - * after setting up the private data - */ - if (XGI_IS_CONTROL_DEVICE(inode)) - return xgi_kern_ctl_open(inode, filp); - - /* what device are we talking about? */ - dev_num = XGI_DEVICE_NUMBER(inode); - if (dev_num >= XGI_MAX_DEVICES) { - xgi_free_file_private(filp->private_data); - filp->private_data = NULL; - return -ENODEV; - } - - info = &xgi_devices[dev_num]; - - XGI_INFO("Jong-xgi_kern_open on device %d\n", dev_num); - - xgi_down(info->info_sem); - XGI_CHECK_PCI_CONFIG(info); - - XGI_INFO_FROM_FP(filp) = info; - - /* - * map the memory and allocate isr on first open - */ - - if (!(info->flags & XGI_FLAG_OPEN)) { - XGI_INFO("info->flags & XGI_FLAG_OPEN \n"); - - if (info->dev->device == 0) { - XGI_INFO("open of nonexistent device %d\n", dev_num); - result = -ENXIO; - goto failed; - } - - /* initialize struct irqaction */ - status = request_irq(info->dev->irq, xgi_kern_isr, - SA_INTERRUPT | SA_SHIRQ, "xgi", - (void *)info); - if (status != 0) { - if (info->dev->irq && (status == -EBUSY)) { - XGI_ERROR - ("Tried to get irq %d, but another driver", - (unsigned int)info->dev->irq); - XGI_ERROR("has it and is not sharing it.\n"); - } - XGI_ERROR("isr request failed 0x%x\n", status); - result = -EIO; - goto failed; - } - - /* - * #define DECLARE_TASKLET(name, func, data) \ - * struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data } - */ - info->tasklet.func = xgi_kern_isr_bh; - info->tasklet.data = (unsigned long)info; - tasklet_enable(&info->tasklet); - - /* Alloc 1M bytes for cmdbuffer which is flush2D batch array */ - xgi_cmdlist_initialize(info, 0x100000); - - info->flags |= XGI_FLAG_OPEN; - } - - XGI_ATOMIC_INC(info->use_count); - - failed: - xgi_up(info->info_sem); - - if ((result) && filp->private_data) { - xgi_free_file_private(filp->private_data); - filp->private_data = NULL; - } - - return result; -} - -int xgi_kern_release(struct inode *inode, struct file *filp) -{ - struct xgi_info *info = XGI_INFO_FROM_FP(filp); - - XGI_CHECK_PCI_CONFIG(info); - - /* - * for control device, just jump to its open routine - * after setting up the private data - */ - if (XGI_IS_CONTROL_DEVICE(inode)) - return xgi_kern_ctl_close(inode, filp); - - XGI_INFO("Jong-xgi_kern_release on device %d\n", - XGI_DEVICE_NUMBER(inode)); - - xgi_down(info->info_sem); - if (XGI_ATOMIC_DEC_AND_TEST(info->use_count)) { - - /* - * The usage count for this device has dropped to zero, it can be shut - * down safely; disable its interrupts. - */ - - /* - * Disable this device's tasklet to make sure that no bottom half will - * run with undefined device state. - */ - tasklet_disable(&info->tasklet); - - /* - * Free the IRQ, which may block until all pending interrupt processing - * has completed. - */ - free_irq(info->dev->irq, (void *)info); - - xgi_cmdlist_cleanup(info); - - /* leave INIT flag alone so we don't reinit every time */ - info->flags &= ~XGI_FLAG_OPEN; - } - - xgi_up(info->info_sem); - - if (FILE_PRIVATE(filp)) { - xgi_free_file_private(FILE_PRIVATE(filp)); - FILE_PRIVATE(filp) = NULL; - } - - return 0; -} - -int xgi_kern_mmap(struct file *filp, struct vm_area_struct *vma) -{ - //struct inode *inode = INODE_FROM_FP(filp); - struct xgi_info *info = XGI_INFO_FROM_FP(filp); - struct xgi_pcie_block *block; - int pages = 0; - unsigned long prot; - - XGI_INFO("Jong-VM: mmap([0x%lx-0x%lx] off=0x%lx)\n", - vma->vm_start, vma->vm_end, XGI_VMA_OFFSET(vma)); - - XGI_CHECK_PCI_CONFIG(info); - - if (XGI_MASK_OFFSET(vma->vm_start) - || XGI_MASK_OFFSET(vma->vm_end)) { - XGI_ERROR("VM: bad mmap range: %lx - %lx\n", - vma->vm_start, vma->vm_end); - return -ENXIO; - } - - pages = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; - - vma->vm_ops = &xgi_vm_ops; - - /* XGI IO(reg) space */ - if (IS_IO_OFFSET - (info, XGI_VMA_OFFSET(vma), vma->vm_end - vma->vm_start)) { - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - if (XGI_REMAP_PAGE_RANGE(vma->vm_start, - XGI_VMA_OFFSET(vma), - vma->vm_end - vma->vm_start, - vma->vm_page_prot)) - return -EAGAIN; - - /* mark it as IO so that we don't dump it on core dump */ - vma->vm_flags |= VM_IO; - XGI_INFO("VM: mmap io space \n"); - } - /* XGI fb space */ - /* Jong 06/14/2006; moved behind PCIE or modify IS_FB_OFFSET */ - else if (IS_FB_OFFSET - (info, XGI_VMA_OFFSET(vma), vma->vm_end - vma->vm_start)) { - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - if (XGI_REMAP_PAGE_RANGE(vma->vm_start, - XGI_VMA_OFFSET(vma), - vma->vm_end - vma->vm_start, - vma->vm_page_prot)) - return -EAGAIN; - - // mark it as IO so that we don't dump it on core dump - vma->vm_flags |= VM_IO; - XGI_INFO("VM: mmap fb space \n"); - } - /* PCIE allocator */ - /* XGI_VMA_OFFSET(vma) is offset based on pcie.base (HW address space) */ - else if (IS_PCIE_OFFSET - (info, XGI_VMA_OFFSET(vma), vma->vm_end - vma->vm_start)) { - xgi_down(info->pcie_sem); - - block = xgi_find_pcie_block(info, XGI_VMA_OFFSET(vma)); - - if (block == NULL) { - XGI_ERROR("couldn't find pre-allocated PCIE memory!\n"); - xgi_up(info->pcie_sem); - return -EAGAIN; - } - - if (block->page_count != pages) { - XGI_ERROR - ("pre-allocated PCIE memory has wrong number of pages!\n"); - xgi_up(info->pcie_sem); - return -EAGAIN; - } - - vma->vm_private_data = block; - XGI_ATOMIC_INC(block->use_count); - xgi_up(info->pcie_sem); - - /* - * prevent the swapper from swapping it out - * mark the memory i/o so the buffers aren't - * dumped on core dumps */ - vma->vm_flags |= (VM_LOCKED | VM_IO); - - /* un-cached */ - prot = pgprot_val(vma->vm_page_prot); - /* - if (boot_cpu_data.x86 > 3) - prot |= _PAGE_PCD | _PAGE_PWT; - */ - vma->vm_page_prot = __pgprot(prot); - - XGI_INFO("VM: mmap pcie space \n"); - } -#if 0 - else if (IS_FB_OFFSET - (info, XGI_VMA_OFFSET(vma), vma->vm_end - vma->vm_start)) { - vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - if (XGI_REMAP_PAGE_RANGE(vma->vm_start, - XGI_VMA_OFFSET(vma), - vma->vm_end - vma->vm_start, - vma->vm_page_prot)) - return -EAGAIN; - - // mark it as IO so that we don't dump it on core dump - vma->vm_flags |= VM_IO; - XGI_INFO("VM: mmap fb space \n"); - } -#endif - else { - vma->vm_flags |= (VM_IO | VM_LOCKED); - XGI_ERROR("VM: mmap wrong range \n"); - } - - vma->vm_file = filp; - - return 0; -} - -unsigned int xgi_kern_poll(struct file *filp, struct poll_table_struct *wait) -{ - struct xgi_file_private *fp; - struct xgi_info *info; - unsigned int mask = 0; - unsigned long eflags; - - info = XGI_INFO_FROM_FP(filp); - - if (info->device_number == XGI_CONTROL_DEVICE_NUMBER) - return xgi_kern_ctl_poll(filp, wait); - - fp = XGI_GET_FP(filp); - - if (!(filp->f_flags & O_NONBLOCK)) { - /* add us to the list */ - poll_wait(filp, &fp->wait_queue, wait); - } - - xgi_lock_irqsave(fp->fp_lock, eflags); - - /* wake the user on any event */ - if (fp->num_events) { - XGI_INFO("Hey, an event occured!\n"); - /* - * trigger the client, when they grab the event, - * we'll decrement the event count - */ - mask |= (POLLPRI | POLLIN); - } - xgi_unlock_irqsave(fp->fp_lock, eflags); - - return mask; -} - -int xgi_kern_ioctl(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - struct xgi_info *info; - struct xgi_mem_alloc *alloc = NULL; - - int status = 0; - void *arg_copy; - int arg_size; - int err = 0; - - info = XGI_INFO_FROM_FP(filp); - - XGI_INFO("Jong-ioctl(0x%x, 0x%x, 0x%lx, 0x%x)\n", _IOC_TYPE(cmd), - _IOC_NR(cmd), arg, _IOC_SIZE(cmd)); - /* - * extract the type and number bitfields, and don't decode - * wrong cmds: return ENOTTY (inappropriate ioctl) before access_ok() - */ - if (_IOC_TYPE(cmd) != XGI_IOCTL_MAGIC) - return -ENOTTY; - if (_IOC_NR(cmd) > XGI_IOCTL_MAXNR) - return -ENOTTY; - - /* - * the direction is a bitmask, and VERIFY_WRITE catches R/W - * transfers. `Type' is user-oriented, while - * access_ok is kernel-oriented, so the concept of "read" and - * "write" is reversed - */ - if (_IOC_DIR(cmd) & _IOC_READ) { - err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd)); - } else if (_IOC_DIR(cmd) & _IOC_WRITE) { - err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd)); - } - if (err) - return -EFAULT; - - XGI_CHECK_PCI_CONFIG(info); - - arg_size = _IOC_SIZE(cmd); - XGI_KMALLOC(arg_copy, arg_size); - if (arg_copy == NULL) { - XGI_ERROR("failed to allocate ioctl memory\n"); - return -ENOMEM; - } - - /* Jong 05/25/2006 */ - /* copy_from_user(arg_copy, (void *)arg, arg_size); */ - if (copy_from_user(arg_copy, (void *)arg, arg_size)) { - XGI_ERROR("failed to copyin ioctl data\n"); - XGI_INFO("Jong-copy_from_user-fail! \n"); - } else - XGI_INFO("Jong-copy_from_user-OK! \n"); - - alloc = (struct xgi_mem_alloc *) arg_copy; - XGI_INFO("Jong-succeeded in copy_from_user 0x%lx, 0x%x bytes.\n", arg, - arg_size); - - switch (_IOC_NR(cmd)) { - case XGI_ESC_POST_VBIOS: - XGI_INFO("Jong-xgi_ioctl_post_vbios \n"); - break; - case XGI_ESC_FB_ALLOC: - XGI_INFO("Jong-xgi_ioctl_fb_alloc \n"); - xgi_fb_alloc(info, alloc, 0); - break; - case XGI_ESC_FB_FREE: - XGI_INFO("Jong-xgi_ioctl_fb_free \n"); - xgi_fb_free(info, *(unsigned long *)arg_copy); - break; - case XGI_ESC_PCIE_ALLOC: - XGI_INFO("Jong-xgi_ioctl_pcie_alloc \n"); - xgi_pcie_alloc(info, alloc, 0); - break; - case XGI_ESC_PCIE_FREE: - XGI_INFO("Jong-xgi_ioctl_pcie_free: bus_addr = 0x%lx \n", - *((unsigned long *)arg_copy)); - xgi_pcie_free(info, *((unsigned long *)arg_copy)); - break; - case XGI_ESC_GE_RESET: - XGI_INFO("Jong-xgi_ioctl_ge_reset \n"); - xgi_ge_reset(info); - break; - case XGI_ESC_DUMP_REGISTER: - XGI_INFO("Jong-xgi_ioctl_dump_register \n"); - xgi_dump_register(info); - break; - case XGI_ESC_DEBUG_INFO: - XGI_INFO("Jong-xgi_ioctl_restore_registers \n"); - xgi_restore_registers(info); - break; - case XGI_ESC_SUBMIT_CMDLIST: - XGI_INFO("Jong-xgi_ioctl_submit_cmdlist \n"); - xgi_submit_cmdlist(info, (struct xgi_cmd_info *) arg_copy); - break; - case XGI_ESC_TEST_RWINKERNEL: - XGI_INFO("Jong-xgi_test_rwinkernel \n"); - xgi_test_rwinkernel(info, *(unsigned long *)arg_copy); - break; - case XGI_ESC_STATE_CHANGE: - XGI_INFO("Jong-xgi_state_change \n"); - xgi_state_change(info, (struct xgi_state_info *) arg_copy); - break; - default: - XGI_INFO("Jong-xgi_ioctl_default \n"); - status = -EINVAL; - break; - } - - if (copy_to_user((void *)arg, arg_copy, arg_size)) { - XGI_ERROR("failed to copyout ioctl data\n"); - XGI_INFO("Jong-copy_to_user-fail! \n"); - } else - XGI_INFO("Jong-copy_to_user-OK! \n"); - - XGI_KFREE(arg_copy, arg_size); - return status; -} - -/* - * xgi control driver operations defined here - */ -int xgi_kern_ctl_open(struct inode *inode, struct file *filp) -{ - struct xgi_info *info = &xgi_ctl_device; - - int rc = 0; - - XGI_INFO("Jong-xgi_kern_ctl_open\n"); - - xgi_down(info->info_sem); - info->device_number = XGI_CONTROL_DEVICE_NUMBER; - - /* save the xgi info in file->private_data */ - filp->private_data = info; - - if (XGI_ATOMIC_READ(info->use_count) == 0) { - init_waitqueue_head(&xgi_ctl_waitqueue); - } - - info->flags |= XGI_FLAG_OPEN + XGI_FLAG_CONTROL; - - XGI_ATOMIC_INC(info->use_count); - xgi_up(info->info_sem); - - return rc; -} - -int xgi_kern_ctl_close(struct inode *inode, struct file *filp) -{ - struct xgi_info *info = XGI_INFO_FROM_FP(filp); - - XGI_INFO("Jong-xgi_kern_ctl_close\n"); - - xgi_down(info->info_sem); - if (XGI_ATOMIC_DEC_AND_TEST(info->use_count)) { - info->flags = 0; - } - xgi_up(info->info_sem); - - if (FILE_PRIVATE(filp)) { - xgi_free_file_private(FILE_PRIVATE(filp)); - FILE_PRIVATE(filp) = NULL; - } - - return 0; -} - -unsigned int xgi_kern_ctl_poll(struct file *filp, poll_table * wait) -{ - //struct xgi_info *info = XGI_INFO_FROM_FP(filp);; - unsigned int ret = 0; - - if (!(filp->f_flags & O_NONBLOCK)) { - poll_wait(filp, &xgi_ctl_waitqueue, wait); - } - - return ret; -} - -/* - * xgi proc system - */ -static u8 xgi_find_pcie_capability(struct pci_dev *dev) -{ - u16 status; - u8 cap_ptr, cap_id; - - pci_read_config_word(dev, PCI_STATUS, &status); - status &= PCI_STATUS_CAP_LIST; - if (!status) - return 0; - - switch (dev->hdr_type) { - case PCI_HEADER_TYPE_NORMAL: - case PCI_HEADER_TYPE_BRIDGE: - pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &cap_ptr); - break; - default: - return 0; + /* Init the resource manager */ + err = xgi_pcie_heap_init(info); + if (err) { + DRM_ERROR("xgi_pcie_heap_init() failed\n"); + return err; } - do { - cap_ptr &= 0xFC; - pci_read_config_byte(dev, cap_ptr + PCI_CAP_LIST_ID, &cap_id); - pci_read_config_byte(dev, cap_ptr + PCI_CAP_LIST_NEXT, - &cap_ptr); - } while (cap_ptr && cap_id != 0xFF); - - return 0; -} - -int xgi_kern_read_card_info(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - struct pci_dev *dev; - char *type; - int len = 0; - - struct xgi_info *info; - info = (struct xgi_info *) data; - - dev = info->dev; - if (!dev) - return 0; - - type = xgi_find_pcie_capability(dev) ? "PCIE" : "PCI"; - len += sprintf(page + len, "Card Type: \t %s\n", type); - - XGI_PCI_DEV_PUT(dev); - return len; -} - -int xgi_kern_read_version(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - int len = 0; - - len += sprintf(page + len, "XGI version: %s\n", "1.0"); - len += sprintf(page + len, "GCC version: %s\n", "3.0"); + /* Alloc 1M bytes for cmdbuffer which is flush2D batch array */ + xgi_cmdlist_initialize(info, 0x100000); - return len; -} - -int xgi_kern_read_pcie_info(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ + info->bootstrap_done = 1; return 0; } -int xgi_kern_read_status(char *page, char **start, off_t off, - int count, int *eof, void *data) -{ - return 0; -} -static void xgi_proc_create(void) +void xgi_driver_preclose(struct drm_device * dev, DRMFILE filp) { -#ifdef CONFIG_PROC_FS - - struct pci_dev *dev; - int i = 0; - char name[6]; - - struct proc_dir_entry *entry; - struct proc_dir_entry *proc_xgi_pcie, *proc_xgi_cards; - - struct xgi_info *info; - struct xgi_info *xgi_max_devices; - - /* world readable directory */ - int flags = S_IFDIR | S_IRUGO | S_IXUGO; - - proc_xgi = create_proc_entry("xgi", flags, proc_root_driver); - if (!proc_xgi) - goto failed; - - proc_xgi_cards = create_proc_entry("cards", flags, proc_xgi); - if (!proc_xgi_cards) - goto failed; - - proc_xgi_pcie = create_proc_entry("pcie", flags, proc_xgi); - if (!proc_xgi_pcie) - goto failed; - - /* - * Set the module owner to ensure that the reference - * count reflects accesses to the proc files. - */ - proc_xgi->owner = THIS_MODULE; - proc_xgi_cards->owner = THIS_MODULE; - proc_xgi_pcie->owner = THIS_MODULE; - - xgi_max_devices = xgi_devices + XGI_MAX_DEVICES; - for (info = xgi_devices; info < xgi_max_devices; info++) { - /* world readable file */ - flags = S_IFREG | S_IRUGO; - - dev = info->dev; - if (!dev) - break; - - sprintf(name, "%d", i++); - entry = create_proc_entry(name, flags, proc_xgi_cards); - if (!entry) { - XGI_PCI_DEV_PUT(dev); - goto failed; - } - - entry->data = info; - entry->read_proc = xgi_kern_read_card_info; - entry->owner = THIS_MODULE; - - if (xgi_find_pcie_capability(dev)) { - entry = - create_proc_entry("status", flags, proc_xgi_pcie); - if (!entry) { - XGI_PCI_DEV_PUT(dev); - goto failed; - } - - entry->data = info; - entry->read_proc = xgi_kern_read_status; - entry->owner = THIS_MODULE; - - entry = create_proc_entry("card", flags, proc_xgi_pcie); - if (!entry) { - XGI_PCI_DEV_PUT(dev); - goto failed; - } - - entry->data = info; - entry->read_proc = xgi_kern_read_pcie_info; - entry->owner = THIS_MODULE; - } - - XGI_PCI_DEV_PUT(dev); - } - - entry = create_proc_entry("version", flags, proc_xgi); - if (!entry) - goto failed; - - entry->read_proc = xgi_kern_read_version; - entry->owner = THIS_MODULE; - - entry = create_proc_entry("host-bridge", flags, proc_xgi_pcie); - if (!entry) - goto failed; + struct xgi_info * info = dev->dev_private; - entry->data = NULL; - entry->read_proc = xgi_kern_read_pcie_info; - entry->owner = THIS_MODULE; - - return; - - failed: - XGI_ERROR("failed to create /proc entries!\n"); - xgi_proc_remove_all(proc_xgi); -#endif + xgi_pcie_free_all(info, filp); + xgi_fb_free_all(info, filp); } -#ifdef CONFIG_PROC_FS -static void xgi_proc_remove_all(struct proc_dir_entry *entry) -{ - while (entry) { - struct proc_dir_entry *next = entry->next; - if (entry->subdir) - xgi_proc_remove_all(entry->subdir); - remove_proc_entry(entry->name, entry->parent); - if (entry == proc_xgi) - break; - entry = next; - } -} -#endif - -static void xgi_proc_remove(void) -{ -#ifdef CONFIG_PROC_FS - xgi_proc_remove_all(proc_xgi); -#endif -} /* * driver receives an interrupt if someone waiting, then hand it off. */ -irqreturn_t xgi_kern_isr(int irq, void *dev_id, struct pt_regs *regs) +irqreturn_t xgi_kern_isr(DRM_IRQ_ARGS) { - struct xgi_info *info = (struct xgi_info *) dev_id; + struct drm_device *dev = (struct drm_device *) arg; +// struct xgi_info *info = dev->dev_private; u32 need_to_run_bottom_half = 0; - //XGI_INFO("xgi_kern_isr \n"); + //DRM_INFO("xgi_kern_isr \n"); //XGI_CHECK_PCI_CONFIG(info); //xgi_dvi_irq_handler(info); if (need_to_run_bottom_half) { - tasklet_schedule(&info->tasklet); + drm_locked_tasklet(dev, xgi_kern_isr_bh); } return IRQ_HANDLED; } -void xgi_kern_isr_bh(unsigned long data) +void xgi_kern_isr_bh(struct drm_device *dev) { - struct xgi_info *info = (struct xgi_info *) data; + struct xgi_info *info = dev->dev_private; - XGI_INFO("xgi_kern_isr_bh \n"); + DRM_INFO("xgi_kern_isr_bh \n"); //xgi_dvi_irq_handler(info); XGI_CHECK_PCI_CONFIG(info); } -static void xgi_lock_init(struct xgi_info * info) +int xgi_driver_load(struct drm_device *dev, unsigned long flags) { - if (info == NULL) - return; - - spin_lock_init(&info->info_lock); - - sema_init(&info->info_sem, 1); - sema_init(&info->fb_sem, 1); - sema_init(&info->pcie_sem, 1); - - XGI_ATOMIC_SET(info->use_count, 0); -} + struct xgi_info *info; + int err; -static void xgi_dev_init(struct xgi_info * info) -{ - struct pci_dev *pdev = NULL; - struct xgi_dev *dev; - int found = 0; - u16 pci_cmd; - XGI_INFO("Enter xgi_dev_init \n"); + info = drm_alloc(sizeof(*info), DRM_MEM_DRIVER); + if (!info) + return DRM_ERR(ENOMEM); - //XGI_PCI_FOR_EACH_DEV(pdev) - { - for (dev = xgidev_list; dev->vendor; dev++) { - if ((dev->vendor == pdev->vendor) - && (dev->device == pdev->device)) { - u8 rev_id; + (void) memset(info, 0, sizeof(*info)); + dev->dev_private = info; + info->dev = dev; - XGI_INFO("dev->vendor = pdev->vendor= %x \n", - dev->vendor); - XGI_INFO("dev->device = pdev->device= %x \n", - dev->device); + sema_init(&info->fb_sem, 1); + sema_init(&info->pcie_sem, 1); - xgi_devices[found].dev = pdev; + info->mmio.base = drm_get_resource_start(dev, 1); + info->mmio.size = drm_get_resource_len(dev, 1); - pci_read_config_byte(pdev, PCI_REVISION_ID, - rev_id); + DRM_INFO("mmio base: 0x%lx, size: 0x%x\n", + (unsigned long) info->mmio.base, info->mmio.size); - XGI_INFO("PCI_REVISION_ID= %x \n", rev_id); - pci_read_config_word(pdev, PCI_COMMAND, - &pci_cmd); + if ((info->mmio.base == 0) || (info->mmio.size == 0)) { + DRM_ERROR("mmio appears to be wrong: 0x%lx 0x%x\n", + (unsigned long) info->mmio.base, info->mmio.size); + return DRM_ERR(EINVAL); + } - XGI_INFO("PCI_COMMAND = %x \n", pci_cmd); - break; - } - } + err = drm_addmap(dev, info->mmio.base, info->mmio.size, + _DRM_REGISTERS, _DRM_KERNEL | _DRM_READ_ONLY, + &info->mmio_map); + if (err) { + DRM_ERROR("Unable to map MMIO region: %d\n", err); + return err; } -} -/* - * Export to Linux Kernel - */ + xgi_enable_mmio(info); + //xgi_enable_ge(info); -static int __init xgi_init_module(void) -{ - struct xgi_info *info = &xgi_devices[xgi_num_devices]; - int i, result; + info->fb.base = drm_get_resource_start(dev, 0); + info->fb.size = drm_get_resource_len(dev, 0); - XGI_INFO("Jong-xgi kernel driver %s initializing\n", XGI_DRV_VERSION); - //SET_MODULE_OWNER(&xgi_fops); + DRM_INFO("fb base: 0x%lx, size: 0x%x\n", + (unsigned long) info->fb.base, info->fb.size); - memset(xgi_devices, 0, sizeof(xgi_devices)); + info->fb.size = IN3CFB(info->mmio_map, 0x54) * 8 * 1024 * 1024; - if (pci_register_driver(&xgi_pci_driver) < 0) { - pci_unregister_driver(&xgi_pci_driver); - XGI_ERROR("no XGI graphics adapter found\n"); - return -ENODEV; - } + DRM_INFO("fb base: 0x%lx, size: 0x%x (probed)\n", + (unsigned long) info->fb.base, info->fb.size); - XGI_INFO("Jong-xgi_devices[%d].fb.base.: 0x%lx \n", xgi_num_devices, - xgi_devices[xgi_num_devices].fb.base); - XGI_INFO("Jong-xgi_devices[%d].fb.size.: 0x%lx \n", xgi_num_devices, - xgi_devices[xgi_num_devices].fb.size); -/* Jong 07/27/2006; test for ubuntu */ -/* -#ifdef CONFIG_DEVFS_FS - - XGI_INFO("Jong-Use devfs \n"); - do - { - xgi_devfs_handles[0] = XGI_DEVFS_REGISTER("xgi", 0); - if (xgi_devfs_handles[0] == NULL) - { - result = -ENOMEM; - XGI_ERROR("devfs register failed\n"); - goto failed; - } - } while(0); - #else *//* no devfs, do it the "classic" way */ - - XGI_INFO("Jong-Use non-devfs \n"); - /* - * Register your major, and accept a dynamic number. This is the - * first thing to do, in order to avoid releasing other module's - * fops in scull_cleanup_module() - */ - result = XGI_REGISTER_CHRDEV(xgi_major, "xgi", &xgi_fops); - if (result < 0) { - XGI_ERROR("register chrdev failed\n"); - pci_unregister_driver(&xgi_pci_driver); - return result; + if ((info->fb.base == 0) || (info->fb.size == 0)) { + DRM_ERROR("frame buffer appears to be wrong: 0x%lx 0x%x\n", + (unsigned long) info->fb.base, info->fb.size); + return DRM_ERR(EINVAL); } - if (xgi_major == 0) - xgi_major = result; /* dynamic */ - /* #endif *//* CONFIG_DEVFS_FS */ - XGI_INFO("Jong-major number %d\n", xgi_major); - /* instantiate tasklets */ - for (i = 0; i < XGI_MAX_DEVICES; i++) { - /* - * We keep one tasklet per card to avoid latency issues with more - * than one device; no two instances of a single tasklet are ever - * executed concurrently. - */ - XGI_ATOMIC_SET(xgi_devices[i].tasklet.count, 1); + xgi_mem_block_cache = kmem_cache_create("xgi_mem_block", + sizeof(struct xgi_mem_block), + 0, + SLAB_HWCACHE_ALIGN, + NULL, NULL); + if (xgi_mem_block_cache == NULL) { + return DRM_ERR(ENOMEM); } - /* init the xgi control device */ - { - struct xgi_info *info_ctl = &xgi_ctl_device; - xgi_lock_init(info_ctl); - } /* Init the resource manager */ - INIT_LIST_HEAD(&xgi_mempid_list); - if (!xgi_fb_heap_init(info)) { - XGI_ERROR("xgi_fb_heap_init() failed\n"); - result = -EIO; - goto failed; + err = xgi_fb_heap_init(info); + if (err) { + DRM_ERROR("xgi_fb_heap_init() failed\n"); + return err; } - /* Init the resource manager */ - if (!xgi_pcie_heap_init(info)) { - XGI_ERROR("xgi_pcie_heap_init() failed\n"); - result = -EIO; - goto failed; - } - - /* create /proc/driver/xgi */ - xgi_proc_create(); - -#if defined(DEBUG) - inter_module_register("xgi_devices", THIS_MODULE, xgi_devices); -#endif - return 0; - - failed: -#ifdef CONFIG_DEVFS_FS - XGI_DEVFS_REMOVE_CONTROL(); - XGI_DEVFS_REMOVE_DEVICE(xgi_num_devices); -#endif - - if (XGI_UNREGISTER_CHRDEV(xgi_major, "xgi") < 0) - XGI_ERROR("unregister xgi chrdev failed\n"); - - for (i = 0; i < xgi_num_devices; i++) { - if (xgi_devices[i].dev) { - release_mem_region(xgi_devices[i].fb.base, - xgi_devices[i].fb.size); - release_mem_region(xgi_devices[i].mmio.base, - xgi_devices[i].mmio.size); - } - } - - pci_unregister_driver(&xgi_pci_driver); - return result; - - return 1; } -void __exit xgi_exit_module(void) +int xgi_driver_unload(struct drm_device *dev) { - int i; - -#ifdef CONFIG_DEVFS_FS - XGI_DEVFS_REMOVE_DEVICE(xgi_num_devices); -#endif - - if (XGI_UNREGISTER_CHRDEV(xgi_major, "xgi") < 0) - XGI_ERROR("unregister xgi chrdev failed\n"); - - XGI_INFO("Jong-unregister xgi chrdev scceeded\n"); - for (i = 0; i < XGI_MAX_DEVICES; i++) { - if (xgi_devices[i].dev) { - /* clean up the flush2D batch array */ - xgi_cmdlist_cleanup(&xgi_devices[i]); - - if (xgi_devices[i].fb.vbase != NULL) { - iounmap(xgi_devices[i].fb.vbase); - xgi_devices[i].fb.vbase = NULL; - } - if (xgi_devices[i].mmio.vbase != NULL) { - iounmap(xgi_devices[i].mmio.vbase); - xgi_devices[i].mmio.vbase = NULL; - } - //release_mem_region(xgi_devices[i].fb.base, xgi_devices[i].fb.size); - //XGI_INFO("release frame buffer mem region scceeded\n"); - - release_mem_region(xgi_devices[i].mmio.base, - xgi_devices[i].mmio.size); - XGI_INFO("release MMIO mem region scceeded\n"); - - xgi_fb_heap_cleanup(&xgi_devices[i]); - XGI_INFO("xgi_fb_heap_cleanup scceeded\n"); - - xgi_pcie_heap_cleanup(&xgi_devices[i]); - XGI_INFO("xgi_pcie_heap_cleanup scceeded\n"); - - XGI_PCI_DISABLE_DEVICE(xgi_devices[i].dev); - } - } - - pci_unregister_driver(&xgi_pci_driver); - - /* remove /proc/driver/xgi */ - xgi_proc_remove(); + struct xgi_info * info = dev->dev_private; -#if defined(DEBUG) - inter_module_unregister("xgi_devices"); -#endif -} + xgi_cmdlist_cleanup(info); + if (info->fb_map != NULL) { + drm_rmmap(info->dev, info->fb_map); + } -module_init(xgi_init_module); -module_exit(xgi_exit_module); + if (info->mmio_map != NULL) { + drm_rmmap(info->dev, info->mmio_map); + } -#if defined(XGI_PM_SUPPORT_ACPI) -int xgi_acpi_event(struct pci_dev *dev, u32 state) -{ - return 1; -} + xgi_mem_heap_cleanup(&info->fb_heap); + xgi_mem_heap_cleanup(&info->pcie_heap); + xgi_pcie_lut_cleanup(info); -int xgi_kern_acpi_standby(struct pci_dev *dev, u32 state) -{ - return 1; -} + if (xgi_mem_block_cache) { + kmem_cache_destroy(xgi_mem_block_cache); + xgi_mem_block_cache = NULL; + } -int xgi_kern_acpi_resume(struct pci_dev *dev) -{ - return 1; + return 0; } -#endif - -MODULE_AUTHOR("Andrea Zhang "); -MODULE_DESCRIPTION("xgi kernel driver for xgi cards"); -MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 2f53ce4af2f7db911d908ff382738f30be004e8b Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Thu, 19 Jul 2007 11:05:13 -0700 Subject: Move MMIO drm_addmap (and code that depends on it) to xgi_bootstrap. For reasons that I don't understand, the drm_addmap call would succeed in xgi_driver_load, but writes to the map later would oops. Moving it to xgi_bootstrap fixes this problem. --- linux-core/xgi_drv.c | 62 ++++++++++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 31 deletions(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index 3b9f4cb1..13e79169 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -188,7 +188,38 @@ int xgi_bootstrap(DRM_IOCTL_ARGS) return 0; } + err = drm_addmap(dev, info->mmio.base, info->mmio.size, + _DRM_REGISTERS, _DRM_KERNEL, + &info->mmio_map); + if (err) { + DRM_ERROR("Unable to map MMIO region: %d\n", err); + return err; + } + xgi_enable_mmio(info); + //xgi_enable_ge(info); + + info->fb.size = IN3CFB(info->mmio_map, 0x54) * 8 * 1024 * 1024; + + DRM_INFO("fb base: 0x%lx, size: 0x%x (probed)\n", + (unsigned long) info->fb.base, info->fb.size); + + + if ((info->fb.base == 0) || (info->fb.size == 0)) { + DRM_ERROR("frame buffer appears to be wrong: 0x%lx 0x%x\n", + (unsigned long) info->fb.base, info->fb.size); + return DRM_ERR(EINVAL); + } + + + /* Init the resource manager */ + err = xgi_fb_heap_init(info); + if (err) { + DRM_ERROR("xgi_fb_heap_init() failed\n"); + return err; + } + + info->pcie.size = bs.gart_size * (1024 * 1024); @@ -280,36 +311,12 @@ int xgi_driver_load(struct drm_device *dev, unsigned long flags) } - err = drm_addmap(dev, info->mmio.base, info->mmio.size, - _DRM_REGISTERS, _DRM_KERNEL | _DRM_READ_ONLY, - &info->mmio_map); - if (err) { - DRM_ERROR("Unable to map MMIO region: %d\n", err); - return err; - } - - xgi_enable_mmio(info); - //xgi_enable_ge(info); - info->fb.base = drm_get_resource_start(dev, 0); info->fb.size = drm_get_resource_len(dev, 0); DRM_INFO("fb base: 0x%lx, size: 0x%x\n", (unsigned long) info->fb.base, info->fb.size); - info->fb.size = IN3CFB(info->mmio_map, 0x54) * 8 * 1024 * 1024; - - DRM_INFO("fb base: 0x%lx, size: 0x%x (probed)\n", - (unsigned long) info->fb.base, info->fb.size); - - - if ((info->fb.base == 0) || (info->fb.size == 0)) { - DRM_ERROR("frame buffer appears to be wrong: 0x%lx 0x%x\n", - (unsigned long) info->fb.base, info->fb.size); - return DRM_ERR(EINVAL); - } - - xgi_mem_block_cache = kmem_cache_create("xgi_mem_block", sizeof(struct xgi_mem_block), @@ -321,13 +328,6 @@ int xgi_driver_load(struct drm_device *dev, unsigned long flags) } - /* Init the resource manager */ - err = xgi_fb_heap_init(info); - if (err) { - DRM_ERROR("xgi_fb_heap_init() failed\n"); - return err; - } - return 0; } -- cgit v1.2.3 From 970674f4867d65bd16cf3585d46930b72a827cce Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Thu, 19 Jul 2007 19:08:47 -0700 Subject: Fix error handing related to xgi_cmdlist_initialize. xgi_cmdlist_initialize wasn't correctly checking for errors from xgi_pcie_alloc. Furthermore, xgi_bootstrap, the one caller of xgi_cmdlist_initialize, wasn't check its return value. --- linux-core/xgi_drv.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index 13e79169..c4e7daae 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -231,7 +231,11 @@ int xgi_bootstrap(DRM_IOCTL_ARGS) } /* Alloc 1M bytes for cmdbuffer which is flush2D batch array */ - xgi_cmdlist_initialize(info, 0x100000); + err = xgi_cmdlist_initialize(info, 0x100000); + if (err) { + DRM_ERROR("xgi_cmdlist_initialize() failed\n"); + return err; + } info->bootstrap_done = 1; return 0; -- cgit v1.2.3 From 56665a42f470d5cf8cb4865558cb658dff15a9dd Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Thu, 19 Jul 2007 19:09:24 -0700 Subject: Delete unused variable in xgi_driver_load. --- linux-core/xgi_drv.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index c4e7daae..bcb6946d 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -286,11 +286,8 @@ void xgi_kern_isr_bh(struct drm_device *dev) int xgi_driver_load(struct drm_device *dev, unsigned long flags) { - struct xgi_info *info; - int err; - + struct xgi_info *info = drm_alloc(sizeof(*info), DRM_MEM_DRIVER); - info = drm_alloc(sizeof(*info), DRM_MEM_DRIVER); if (!info) return DRM_ERR(ENOMEM); -- cgit v1.2.3 From 2097d743f287d994bd001baedd39e3bc808999c6 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Mon, 23 Jul 2007 13:26:28 -0700 Subject: Eliminate XGI_CHECK_PCI_CONFIG. Based on review comments from airlied, XGI_CHECK_PCI_CONFIG is removed. He believes (and I tend to agree) that this is a largely unnecessary workaround for a bug elsewhere. --- linux-core/xgi_drv.c | 38 -------------------------------------- 1 file changed, 38 deletions(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index bcb6946d..19a9a10d 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -139,40 +139,6 @@ MODULE_LICENSE("GPL and additional rights"); void xgi_kern_isr_bh(struct drm_device *dev); -/* - * verify access to pci config space wasn't disabled behind our back - * unfortunately, XFree86 enables/disables memory access in pci config space at - * various times (such as restoring initial pci config space settings during vt - * switches or when doing mulicard). As a result, all of our register accesses - * are garbage at this point. add a check to see if access was disabled and - * reenable any such access. - */ -#define XGI_CHECK_PCI_CONFIG(xgi) \ - xgi_check_pci_config(xgi, __LINE__) - -static inline void xgi_check_pci_config(struct xgi_info * info, int line) -{ - u16 cmd; - bool flag = 0; - - pci_read_config_word(info->dev->pdev, PCI_COMMAND, &cmd); - if (!(cmd & PCI_COMMAND_MASTER)) { - DRM_INFO("restoring bus mastering! (%d)\n", line); - cmd |= PCI_COMMAND_MASTER; - flag = 1; - } - - if (!(cmd & PCI_COMMAND_MEMORY)) { - DRM_INFO("restoring MEM access! (%d)\n", line); - cmd |= PCI_COMMAND_MEMORY; - flag = 1; - } - - if (flag) - pci_write_config_word(info->dev->pdev, PCI_COMMAND, cmd); -} - - int xgi_bootstrap(DRM_IOCTL_ARGS) { DRM_DEVICE; @@ -262,8 +228,6 @@ irqreturn_t xgi_kern_isr(DRM_IRQ_ARGS) //DRM_INFO("xgi_kern_isr \n"); - //XGI_CHECK_PCI_CONFIG(info); - //xgi_dvi_irq_handler(info); if (need_to_run_bottom_half) { @@ -280,8 +244,6 @@ void xgi_kern_isr_bh(struct drm_device *dev) DRM_INFO("xgi_kern_isr_bh \n"); //xgi_dvi_irq_handler(info); - - XGI_CHECK_PCI_CONFIG(info); } int xgi_driver_load(struct drm_device *dev, unsigned long flags) -- cgit v1.2.3 From 887cb31ee9ec04e45829500f095aa4a3bc1095ea Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Tue, 24 Jul 2007 13:27:44 -0700 Subject: Fix bug preventing X server from restarting. The core DRM lastclose routine automatically destroys all mappings and releases SG memory. XP10 DRM and DDX assumed this data stayed around until module unload. xgi_bootstrap was reworked to recreate all these mappings. In addition, the drm_addmap for the GART backing store was moved into the kernel. This causes a change to the ioctl protocol and a version bump. --- linux-core/xgi_drv.c | 126 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 85 insertions(+), 41 deletions(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index 19a9a10d..11d6e950 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -64,6 +64,7 @@ static int probe(struct pci_dev *pdev, const struct pci_device_id *ent); static int xgi_driver_load(struct drm_device *dev, unsigned long flags); static int xgi_driver_unload(struct drm_device *dev); static void xgi_driver_preclose(struct drm_device * dev, DRMFILE filp); +static void xgi_driver_lastclose(drm_device_t * dev); static irqreturn_t xgi_kern_isr(DRM_IRQ_ARGS); @@ -75,6 +76,7 @@ static struct drm_driver driver = { .load = xgi_driver_load, .unload = xgi_driver_unload, .preclose = xgi_driver_preclose, + .lastclose = xgi_driver_lastclose, .dma_quiescent = NULL, .irq_preinstall = NULL, .irq_postinstall = NULL, @@ -144,26 +146,25 @@ int xgi_bootstrap(DRM_IOCTL_ARGS) DRM_DEVICE; struct xgi_info *info = dev->dev_private; struct xgi_bootstrap bs; + struct drm_map_list *maplist; int err; DRM_COPY_FROM_USER_IOCTL(bs, (struct xgi_bootstrap __user *) data, sizeof(bs)); - if (info->bootstrap_done) { - return 0; - } + if (info->mmio_map == NULL) { + err = drm_addmap(dev, info->mmio.base, info->mmio.size, + _DRM_REGISTERS, _DRM_KERNEL, + &info->mmio_map); + if (err) { + DRM_ERROR("Unable to map MMIO region: %d\n", err); + return err; + } - err = drm_addmap(dev, info->mmio.base, info->mmio.size, - _DRM_REGISTERS, _DRM_KERNEL, - &info->mmio_map); - if (err) { - DRM_ERROR("Unable to map MMIO region: %d\n", err); - return err; + xgi_enable_mmio(info); } - xgi_enable_mmio(info); - //xgi_enable_ge(info); info->fb.size = IN3CFB(info->mmio_map, 0x54) * 8 * 1024 * 1024; @@ -172,38 +173,64 @@ int xgi_bootstrap(DRM_IOCTL_ARGS) if ((info->fb.base == 0) || (info->fb.size == 0)) { - DRM_ERROR("frame buffer appears to be wrong: 0x%lx 0x%x\n", + DRM_ERROR("framebuffer appears to be wrong: 0x%lx 0x%x\n", (unsigned long) info->fb.base, info->fb.size); return DRM_ERR(EINVAL); } /* Init the resource manager */ - err = xgi_fb_heap_init(info); - if (err) { - DRM_ERROR("xgi_fb_heap_init() failed\n"); - return err; + if (!info->fb_heap.initialized) { + err = xgi_fb_heap_init(info); + if (err) { + DRM_ERROR("Unable to initialize FB heap.\n"); + return err; + } } - - info->pcie.size = bs.gart_size * (1024 * 1024); + info->pcie.size = bs.gart.size; /* Init the resource manager */ - err = xgi_pcie_heap_init(info); - if (err) { - DRM_ERROR("xgi_pcie_heap_init() failed\n"); - return err; + if (!info->pcie_heap.initialized) { + err = xgi_pcie_heap_init(info); + if (err) { + DRM_ERROR("Unable to initialize GART heap.\n"); + return err; + } + + /* Alloc 1M bytes for cmdbuffer which is flush2D batch array */ + err = xgi_cmdlist_initialize(info, 0x100000); + if (err) { + DRM_ERROR("xgi_cmdlist_initialize() failed\n"); + return err; + } } - /* Alloc 1M bytes for cmdbuffer which is flush2D batch array */ - err = xgi_cmdlist_initialize(info, 0x100000); - if (err) { - DRM_ERROR("xgi_cmdlist_initialize() failed\n"); - return err; + + if (info->pcie_map == NULL) { + err = drm_addmap(info->dev, 0, info->pcie.size, + _DRM_SCATTER_GATHER, _DRM_LOCKED, + & info->pcie_map); + if (err) { + DRM_ERROR("Could not add map for GART backing " + "store.\n"); + return err; + } } - info->bootstrap_done = 1; + + maplist = drm_find_matching_map(dev, info->pcie_map); + if (maplist == NULL) { + DRM_ERROR("Could not find GART backing store map.\n"); + return DRM_ERR(EINVAL); + } + + bs.gart = *info->pcie_map; + bs.gart.handle = (void *)(unsigned long) maplist->user_token; + DRM_COPY_TO_USER_IOCTL((struct xgi_bootstrap __user *) data, + bs, sizeof(bs)); + return 0; } @@ -217,6 +244,33 @@ void xgi_driver_preclose(struct drm_device * dev, DRMFILE filp) } +void xgi_driver_lastclose(drm_device_t * dev) +{ + struct xgi_info * info = dev->dev_private; + + if (info != NULL) { + /* The core DRM lastclose routine will destroy all of our + * mappings for us. NULL out the pointers here so that + * xgi_bootstrap can do the right thing. + */ + info->pcie_map = NULL; + info->mmio_map = NULL; + info->fb_map = NULL; + + xgi_cmdlist_cleanup(info); + + if (info->fb_heap.initialized) { + xgi_mem_heap_cleanup(&info->fb_heap); + } + + if (info->pcie_heap.initialized) { + xgi_mem_heap_cleanup(&info->pcie_heap); + xgi_pcie_lut_cleanup(info); + } + } +} + + /* * driver receives an interrupt if someone waiting, then hand it off. */ @@ -298,23 +352,13 @@ int xgi_driver_unload(struct drm_device *dev) { struct xgi_info * info = dev->dev_private; - xgi_cmdlist_cleanup(info); - if (info->fb_map != NULL) { - drm_rmmap(info->dev, info->fb_map); - } - - if (info->mmio_map != NULL) { - drm_rmmap(info->dev, info->mmio_map); - } - - xgi_mem_heap_cleanup(&info->fb_heap); - xgi_mem_heap_cleanup(&info->pcie_heap); - xgi_pcie_lut_cleanup(info); - if (xgi_mem_block_cache) { kmem_cache_destroy(xgi_mem_block_cache); xgi_mem_block_cache = NULL; } + drm_free(info, sizeof(*info), DRM_MEM_DRIVER); + dev->dev_private = NULL; + return 0; } -- cgit v1.2.3 From 2ef2997ee38ff359c331b6a3febf194bd46e4962 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Tue, 24 Jul 2007 13:29:29 -0700 Subject: Fix flags for serveral ioctls. --- linux-core/xgi_drv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index 11d6e950..3b520850 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -42,7 +42,7 @@ static struct pci_device_id pciidlist[] = { static int xgi_bootstrap(DRM_IOCTL_ARGS); static drm_ioctl_desc_t xgi_ioctls[] = { - [DRM_IOCTL_NR(DRM_XGI_BOOTSTRAP)] = {xgi_bootstrap, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_XGI_BOOTSTRAP)] = {xgi_bootstrap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, [DRM_IOCTL_NR(DRM_XGI_FB_ALLOC)] = {xgi_fb_alloc_ioctl, DRM_AUTH}, [DRM_IOCTL_NR(DRM_XGI_FB_FREE)] = {xgi_fb_free_ioctl, DRM_AUTH}, @@ -55,7 +55,7 @@ static drm_ioctl_desc_t xgi_ioctls[] = { [DRM_IOCTL_NR(DRM_XGI_DEBUG_INFO)] = {xgi_restore_registers_ioctl, DRM_AUTH}, [DRM_IOCTL_NR(DRM_XGI_SUBMIT_CMDLIST)] = {xgi_submit_cmdlist_ioctl, DRM_AUTH}, [DRM_IOCTL_NR(DRM_XGI_TEST_RWINKERNEL)] = {xgi_test_rwinkernel_ioctl, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_XGI_STATE_CHANGE)] = {xgi_state_change_ioctl, DRM_AUTH}, + [DRM_IOCTL_NR(DRM_XGI_STATE_CHANGE)] = {xgi_state_change_ioctl, DRM_AUTH|DRM_MASTER}, }; static const int xgi_max_ioctl = DRM_ARRAY_SIZE(xgi_ioctls); -- cgit v1.2.3 From 8e64d2ae862d5fa02e23c68db6b55393e1f86005 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Tue, 24 Jul 2007 13:36:02 -0700 Subject: Fix license formatting. --- linux-core/xgi_drv.c | 46 ++++++++++++++++++++++------------------------ 1 file changed, 22 insertions(+), 24 deletions(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index 3b520850..2c3384b0 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -1,29 +1,27 @@ - /**************************************************************************** - * Copyright (C) 2003-2006 by XGI Technology, Taiwan. - * * - * All Rights Reserved. * - * * + * Copyright (C) 2003-2006 by XGI Technology, Taiwan. + * + * All Rights Reserved. + * * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation on the rights to use, copy, modify, merge, - * publish, distribute, sublicense, and/or sell copies of the Software, - * and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial - * portions of the Software. - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NON-INFRINGEMENT. IN NO EVENT SHALL XGI AND/OR - * ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, - * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - * DEALINGS IN THE SOFTWARE. + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation on the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL + * XGI AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. ***************************************************************************/ #include "drmP.h" -- cgit v1.2.3 From c37ed9eca57a42b98cc67ca98dbf5135f5ab7aba Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Thu, 26 Jul 2007 17:01:16 -0700 Subject: Eliminate use of DRM_ERR. --- linux-core/xgi_drv.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index 2c3384b0..ec87df0a 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -173,7 +173,7 @@ int xgi_bootstrap(DRM_IOCTL_ARGS) if ((info->fb.base == 0) || (info->fb.size == 0)) { DRM_ERROR("framebuffer appears to be wrong: 0x%lx 0x%x\n", (unsigned long) info->fb.base, info->fb.size); - return DRM_ERR(EINVAL); + return -EINVAL; } @@ -221,7 +221,7 @@ int xgi_bootstrap(DRM_IOCTL_ARGS) maplist = drm_find_matching_map(dev, info->pcie_map); if (maplist == NULL) { DRM_ERROR("Could not find GART backing store map.\n"); - return DRM_ERR(EINVAL); + return -EINVAL; } bs.gart = *info->pcie_map; @@ -303,7 +303,7 @@ int xgi_driver_load(struct drm_device *dev, unsigned long flags) struct xgi_info *info = drm_alloc(sizeof(*info), DRM_MEM_DRIVER); if (!info) - return DRM_ERR(ENOMEM); + return -ENOMEM; (void) memset(info, 0, sizeof(*info)); dev->dev_private = info; @@ -322,7 +322,7 @@ int xgi_driver_load(struct drm_device *dev, unsigned long flags) if ((info->mmio.base == 0) || (info->mmio.size == 0)) { DRM_ERROR("mmio appears to be wrong: 0x%lx 0x%x\n", (unsigned long) info->mmio.base, info->mmio.size); - return DRM_ERR(EINVAL); + return -EINVAL; } @@ -339,7 +339,7 @@ int xgi_driver_load(struct drm_device *dev, unsigned long flags) SLAB_HWCACHE_ALIGN, NULL, NULL); if (xgi_mem_block_cache == NULL) { - return DRM_ERR(ENOMEM); + return -ENOMEM; } -- cgit v1.2.3 From cd51f131389297f923798daef6c734ba93f4422b Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Fri, 27 Jul 2007 15:45:59 -0700 Subject: Convert to new ioctl interface between core DRM and device-specific module. --- linux-core/xgi_drv.c | 53 ++++++++++++++++++++++++---------------------------- 1 file changed, 24 insertions(+), 29 deletions(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index ec87df0a..0b094a31 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -37,23 +37,23 @@ static struct pci_device_id pciidlist[] = { xgi_PCI_IDS }; -static int xgi_bootstrap(DRM_IOCTL_ARGS); +static int xgi_bootstrap(struct drm_device *, void *, struct drm_file *); -static drm_ioctl_desc_t xgi_ioctls[] = { - [DRM_IOCTL_NR(DRM_XGI_BOOTSTRAP)] = {xgi_bootstrap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY}, +static struct drm_ioctl_desc xgi_ioctls[] = { + DRM_IOCTL_DEF(DRM_XGI_BOOTSTRAP, xgi_bootstrap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - [DRM_IOCTL_NR(DRM_XGI_FB_ALLOC)] = {xgi_fb_alloc_ioctl, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_XGI_FB_FREE)] = {xgi_fb_free_ioctl, DRM_AUTH}, + DRM_IOCTL_DEF(DRM_XGI_FB_ALLOC, xgi_fb_alloc_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_XGI_FB_FREE, xgi_fb_free_ioctl, DRM_AUTH), - [DRM_IOCTL_NR(DRM_XGI_PCIE_ALLOC)] = {xgi_pcie_alloc_ioctl, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_XGI_PCIE_FREE)] = {xgi_pcie_free_ioctl, DRM_AUTH}, + DRM_IOCTL_DEF(DRM_XGI_PCIE_ALLOC, xgi_pcie_alloc_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_XGI_PCIE_FREE, xgi_pcie_free_ioctl, DRM_AUTH), - [DRM_IOCTL_NR(DRM_XGI_GE_RESET)] = {xgi_ge_reset_ioctl, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_XGI_DUMP_REGISTER)] = {xgi_dump_register_ioctl, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_XGI_DEBUG_INFO)] = {xgi_restore_registers_ioctl, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_XGI_SUBMIT_CMDLIST)] = {xgi_submit_cmdlist_ioctl, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_XGI_TEST_RWINKERNEL)] = {xgi_test_rwinkernel_ioctl, DRM_AUTH}, - [DRM_IOCTL_NR(DRM_XGI_STATE_CHANGE)] = {xgi_state_change_ioctl, DRM_AUTH|DRM_MASTER}, + DRM_IOCTL_DEF(DRM_XGI_GE_RESET, xgi_ge_reset_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_XGI_DUMP_REGISTER, xgi_dump_register_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_XGI_DEBUG_INFO, xgi_restore_registers_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_XGI_SUBMIT_CMDLIST, xgi_submit_cmdlist, DRM_AUTH), + DRM_IOCTL_DEF(DRM_XGI_TEST_RWINKERNEL, xgi_test_rwinkernel_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_XGI_STATE_CHANGE, xgi_state_change_ioctl, DRM_AUTH|DRM_MASTER), }; static const int xgi_max_ioctl = DRM_ARRAY_SIZE(xgi_ioctls); @@ -61,8 +61,9 @@ static const int xgi_max_ioctl = DRM_ARRAY_SIZE(xgi_ioctls); static int probe(struct pci_dev *pdev, const struct pci_device_id *ent); static int xgi_driver_load(struct drm_device *dev, unsigned long flags); static int xgi_driver_unload(struct drm_device *dev); -static void xgi_driver_preclose(struct drm_device * dev, DRMFILE filp); -static void xgi_driver_lastclose(drm_device_t * dev); +static void xgi_driver_preclose(struct drm_device * dev, + struct drm_file * filp); +static void xgi_driver_lastclose(struct drm_device * dev); static irqreturn_t xgi_kern_isr(DRM_IRQ_ARGS); @@ -139,18 +140,15 @@ MODULE_LICENSE("GPL and additional rights"); void xgi_kern_isr_bh(struct drm_device *dev); -int xgi_bootstrap(DRM_IOCTL_ARGS) +int xgi_bootstrap(struct drm_device * dev, void * data, + struct drm_file * filp) { - DRM_DEVICE; struct xgi_info *info = dev->dev_private; - struct xgi_bootstrap bs; + struct xgi_bootstrap * bs = (struct xgi_bootstrap *) data; struct drm_map_list *maplist; int err; - DRM_COPY_FROM_USER_IOCTL(bs, (struct xgi_bootstrap __user *) data, - sizeof(bs)); - if (info->mmio_map == NULL) { err = drm_addmap(dev, info->mmio.base, info->mmio.size, _DRM_REGISTERS, _DRM_KERNEL, @@ -187,7 +185,7 @@ int xgi_bootstrap(DRM_IOCTL_ARGS) } - info->pcie.size = bs.gart.size; + info->pcie.size = bs->gart.size; /* Init the resource manager */ if (!info->pcie_heap.initialized) { @@ -224,16 +222,13 @@ int xgi_bootstrap(DRM_IOCTL_ARGS) return -EINVAL; } - bs.gart = *info->pcie_map; - bs.gart.handle = (void *)(unsigned long) maplist->user_token; - DRM_COPY_TO_USER_IOCTL((struct xgi_bootstrap __user *) data, - bs, sizeof(bs)); - + bs->gart = *info->pcie_map; + bs->gart.handle = (void *)(unsigned long) maplist->user_token; return 0; } -void xgi_driver_preclose(struct drm_device * dev, DRMFILE filp) +void xgi_driver_preclose(struct drm_device * dev, struct drm_file * filp) { struct xgi_info * info = dev->dev_private; @@ -242,7 +237,7 @@ void xgi_driver_preclose(struct drm_device * dev, DRMFILE filp) } -void xgi_driver_lastclose(drm_device_t * dev) +void xgi_driver_lastclose(struct drm_device * dev) { struct xgi_info * info = dev->dev_private; -- cgit v1.2.3 From 2fc697a7d270d57463eb5a16a0c65bd8e14c9893 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Mon, 30 Jul 2007 10:20:15 -0700 Subject: Fix GE shut-down sequence. When the GE is shut down, an empty command packet without a begin-link must be sent. After this command is sent, wait for the hardware to go idle. Finally, turn off the GE and disable MMIO. --- linux-core/xgi_drv.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index 0b094a31..201062ee 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -242,6 +242,12 @@ void xgi_driver_lastclose(struct drm_device * dev) struct xgi_info * info = dev->dev_private; if (info != NULL) { + if (info->mmio_map != NULL) { + xgi_cmdlist_cleanup(info); + xgi_disable_ge(info); + xgi_disable_mmio(info); + } + /* The core DRM lastclose routine will destroy all of our * mappings for us. NULL out the pointers here so that * xgi_bootstrap can do the right thing. @@ -250,8 +256,6 @@ void xgi_driver_lastclose(struct drm_device * dev) info->mmio_map = NULL; info->fb_map = NULL; - xgi_cmdlist_cleanup(info); - if (info->fb_heap.initialized) { xgi_mem_heap_cleanup(&info->fb_heap); } -- cgit v1.2.3 From 08919d8a70558dc61c430be5ed6e4a2bed7429b2 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Mon, 30 Jul 2007 12:01:52 -0700 Subject: Move additional GE initialization into the kernel. This code comes directly from the X server. --- linux-core/xgi_drv.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index 201062ee..33b3a51d 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -138,6 +138,57 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL and additional rights"); +void xgi_engine_init(struct xgi_info * info) +{ + u8 temp; + + + OUT3C5B(info->mmio_map, 0x11, 0x92); + + /* -------> copy from OT2D + * PCI Retry Control Register. + * disable PCI read retry & enable write retry in mem. (10xx xxxx)b + */ + temp = IN3X5B(info->mmio_map, 0x55); + OUT3X5B(info->mmio_map, 0x55, (temp & 0xbf) | 0x80); + + xgi_enable_ge(info); + + /* Enable linear addressing of the card. */ + temp = IN3X5B(info->mmio_map, 0x21); + OUT3X5B(info->mmio_map, 0x21, temp | 0x20); + + /* Enable 32-bit internal data path */ + temp = IN3X5B(info->mmio_map, 0x2A); + OUT3X5B(info->mmio_map, 0x2A, temp | 0x40); + + /* Enable PCI burst write ,disable burst read and enable MMIO. */ + /* + * 0x3D4.39 Enable PCI burst write, disable burst read and enable MMIO. + * 7 ---- Pixel Data Format 1: big endian 0: little endian + * 6 5 4 3---- Memory Data with Big Endian Format, BE[3:0]# with Big Endian Format + * 2 ---- PCI Burst Write Enable + * 1 ---- PCI Burst Read Enable + * 0 ---- MMIO Control + */ + temp = IN3X5B(info->mmio_map, 0x39); + OUT3X5B(info->mmio_map, 0x39, (temp | 0x05) & 0xfd); + + /* enable GEIO decode */ + /* temp = IN3X5B(info->mmio_map, 0x29); + * OUT3X5B(info->mmio_map, 0x29, temp | 0x08); + */ + + /* Enable graphic engine I/O PCI retry function*/ + /* temp = IN3X5B(info->mmio_map, 0x62); + * OUT3X5B(info->mmio_map, 0x62, temp | 0x50); + */ + + /* protect all register except which protected by 3c5.0e.7 */ + /* OUT3C5B(info->mmio_map, 0x11, 0x87); */ +} + + void xgi_kern_isr_bh(struct drm_device *dev); int xgi_bootstrap(struct drm_device * dev, void * data, @@ -159,6 +210,7 @@ int xgi_bootstrap(struct drm_device * dev, void * data, } xgi_enable_mmio(info); + xgi_engine_init(info); } -- cgit v1.2.3 From 90907c59152f628d6f0efea4927a06e547f4a3c7 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Mon, 6 Aug 2007 16:17:23 -0700 Subject: Replace per-heap semaphores with drm_device::struct_mutex. --- linux-core/xgi_drv.c | 3 --- 1 file changed, 3 deletions(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index 33b3a51d..e98fd608 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -360,9 +360,6 @@ int xgi_driver_load(struct drm_device *dev, unsigned long flags) dev->dev_private = info; info->dev = dev; - sema_init(&info->fb_sem, 1); - sema_init(&info->pcie_sem, 1); - info->mmio.base = drm_get_resource_start(dev, 1); info->mmio.size = drm_get_resource_len(dev, 1); -- cgit v1.2.3 From f3072becda3a2d5fe587f20e155d4d4f9ace60a2 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Mon, 6 Aug 2007 16:35:07 -0700 Subject: Refactor xgi_(fb|pcie)_free_all into xgi_free_all. --- linux-core/xgi_drv.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index e98fd608..f6e7b550 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -284,8 +284,10 @@ void xgi_driver_preclose(struct drm_device * dev, struct drm_file * filp) { struct xgi_info * info = dev->dev_private; - xgi_pcie_free_all(info, filp); - xgi_fb_free_all(info, filp); + mutex_lock(&info->dev->struct_mutex); + xgi_free_all(info, &info->pcie_heap, filp); + xgi_free_all(info, &info->fb_heap, filp); + mutex_unlock(&info->dev->struct_mutex); } -- cgit v1.2.3 From 6718198897ef9e275506d3fcb497641e1b09d3b1 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Mon, 6 Aug 2007 16:56:20 -0700 Subject: Release client memory in reclaim_buffers_idlelocked instead of preclose. --- linux-core/xgi_drv.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index f6e7b550..b6fea437 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -61,9 +61,9 @@ static const int xgi_max_ioctl = DRM_ARRAY_SIZE(xgi_ioctls); static int probe(struct pci_dev *pdev, const struct pci_device_id *ent); static int xgi_driver_load(struct drm_device *dev, unsigned long flags); static int xgi_driver_unload(struct drm_device *dev); -static void xgi_driver_preclose(struct drm_device * dev, - struct drm_file * filp); static void xgi_driver_lastclose(struct drm_device * dev); +static void xgi_reclaim_buffers_locked(struct drm_device * dev, + struct drm_file * filp); static irqreturn_t xgi_kern_isr(DRM_IRQ_ARGS); @@ -74,7 +74,6 @@ static struct drm_driver driver = { .dev_priv_size = sizeof(struct xgi_info), .load = xgi_driver_load, .unload = xgi_driver_unload, - .preclose = xgi_driver_preclose, .lastclose = xgi_driver_lastclose, .dma_quiescent = NULL, .irq_preinstall = NULL, @@ -82,6 +81,7 @@ static struct drm_driver driver = { .irq_uninstall = NULL, .irq_handler = xgi_kern_isr, .reclaim_buffers = drm_core_reclaim_buffers, + .reclaim_buffers_idlelocked = xgi_reclaim_buffers_locked, .get_map_ofs = drm_core_get_map_ofs, .get_reg_ofs = drm_core_get_reg_ofs, .ioctls = xgi_ioctls, @@ -280,17 +280,6 @@ int xgi_bootstrap(struct drm_device * dev, void * data, } -void xgi_driver_preclose(struct drm_device * dev, struct drm_file * filp) -{ - struct xgi_info * info = dev->dev_private; - - mutex_lock(&info->dev->struct_mutex); - xgi_free_all(info, &info->pcie_heap, filp); - xgi_free_all(info, &info->fb_heap, filp); - mutex_unlock(&info->dev->struct_mutex); -} - - void xgi_driver_lastclose(struct drm_device * dev) { struct xgi_info * info = dev->dev_private; @@ -322,6 +311,23 @@ void xgi_driver_lastclose(struct drm_device * dev) } +void xgi_reclaim_buffers_locked(struct drm_device * dev, + struct drm_file * filp) +{ + struct xgi_info * info = dev->dev_private; + + mutex_lock(&info->dev->struct_mutex); + if (dev->driver->dma_quiescent) { + dev->driver->dma_quiescent(dev); + } + + xgi_free_all(info, &info->pcie_heap, filp); + xgi_free_all(info, &info->fb_heap, filp); + mutex_unlock(&info->dev->struct_mutex); + return; +} + + /* * driver receives an interrupt if someone waiting, then hand it off. */ -- cgit v1.2.3 From 25cb876f8513d02d4d189371eaa8b7b9a88e860d Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Thu, 9 Aug 2007 15:23:13 -0700 Subject: Associate master file pointer with command list buffer. Pass the master's file pointer, as supplied to xgi_bootstrap, to xgi_cmdlist_initialize. Associate that pointer with the memory allocated for the command list buffer. By doing this the memory will be automatically cleaned up when the master closes the device. This allows the removal of some clean up code. --- linux-core/xgi_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index b6fea437..9aaeb467 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -248,7 +248,7 @@ int xgi_bootstrap(struct drm_device * dev, void * data, } /* Alloc 1M bytes for cmdbuffer which is flush2D batch array */ - err = xgi_cmdlist_initialize(info, 0x100000); + err = xgi_cmdlist_initialize(info, 0x100000, filp); if (err) { DRM_ERROR("xgi_cmdlist_initialize() failed\n"); return err; -- cgit v1.2.3 From aea6b4dea9708f66f5fc2068fe84407682570aca Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Thu, 9 Aug 2007 15:30:36 -0700 Subject: Unify alloc and free ioctls. The DRM_XGI_PCIE_ALLOC and DRM_XGI_FB_ALLOC ioctls (and the matching free ioctls) are unified to DRM_XGI_ALLOC. The desired memory region is selected by xgi_mem_alloc::location. The region is magically encoded in xgi_mem_alloc::index, which is used to release the memory. Bump to version 0.11.0. This update requires a new DDX. --- linux-core/xgi_drv.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index 9aaeb467..997051fb 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -42,11 +42,8 @@ static int xgi_bootstrap(struct drm_device *, void *, struct drm_file *); static struct drm_ioctl_desc xgi_ioctls[] = { DRM_IOCTL_DEF(DRM_XGI_BOOTSTRAP, xgi_bootstrap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_XGI_FB_ALLOC, xgi_fb_alloc_ioctl, DRM_AUTH), - DRM_IOCTL_DEF(DRM_XGI_FB_FREE, xgi_fb_free_ioctl, DRM_AUTH), - - DRM_IOCTL_DEF(DRM_XGI_PCIE_ALLOC, xgi_pcie_alloc_ioctl, DRM_AUTH), - DRM_IOCTL_DEF(DRM_XGI_PCIE_FREE, xgi_pcie_free_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_XGI_ALLOC, xgi_alloc_ioctl, DRM_AUTH), + DRM_IOCTL_DEF(DRM_XGI_FREE, xgi_free_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_XGI_GE_RESET, xgi_ge_reset_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_XGI_DUMP_REGISTER, xgi_dump_register_ioctl, DRM_AUTH), -- cgit v1.2.3 From dbd4d0597ff32458bbe4347bdea0e4b9e55a14da Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Thu, 9 Aug 2007 16:01:14 -0700 Subject: Use sman memory manager instead of internal version. --- linux-core/xgi_drv.c | 46 ++++++++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 22 deletions(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index 997051fb..b0f84c81 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -225,7 +225,7 @@ int xgi_bootstrap(struct drm_device * dev, void * data, /* Init the resource manager */ - if (!info->fb_heap.initialized) { + if (!info->fb_heap_initialized) { err = xgi_fb_heap_init(info); if (err) { DRM_ERROR("Unable to initialize FB heap.\n"); @@ -237,7 +237,7 @@ int xgi_bootstrap(struct drm_device * dev, void * data, info->pcie.size = bs->gart.size; /* Init the resource manager */ - if (!info->pcie_heap.initialized) { + if (!info->pcie_heap_initialized) { err = xgi_pcie_heap_init(info); if (err) { DRM_ERROR("Unable to initialize GART heap.\n"); @@ -296,13 +296,13 @@ void xgi_driver_lastclose(struct drm_device * dev) info->mmio_map = NULL; info->fb_map = NULL; - if (info->fb_heap.initialized) { - xgi_mem_heap_cleanup(&info->fb_heap); + if (info->pcie_heap_initialized) { + xgi_pcie_lut_cleanup(info); } - if (info->pcie_heap.initialized) { - xgi_mem_heap_cleanup(&info->pcie_heap); - xgi_pcie_lut_cleanup(info); + if (info->fb_heap_initialized + || info->pcie_heap_initialized) { + drm_sman_cleanup(&info->sman); } } } @@ -314,12 +314,16 @@ void xgi_reclaim_buffers_locked(struct drm_device * dev, struct xgi_info * info = dev->dev_private; mutex_lock(&info->dev->struct_mutex); + if (drm_sman_owner_clean(&info->sman, (unsigned long) filp)) { + mutex_unlock(&info->dev->struct_mutex); + return; + } + if (dev->driver->dma_quiescent) { dev->driver->dma_quiescent(dev); } - xgi_free_all(info, &info->pcie_heap, filp); - xgi_free_all(info, &info->fb_heap, filp); + drm_sman_owner_cleanup(&info->sman, (unsigned long) filp); mutex_unlock(&info->dev->struct_mutex); return; } @@ -357,6 +361,7 @@ void xgi_kern_isr_bh(struct drm_device *dev) int xgi_driver_load(struct drm_device *dev, unsigned long flags) { struct xgi_info *info = drm_alloc(sizeof(*info), DRM_MEM_DRIVER); + int err; if (!info) return -ENOMEM; @@ -375,7 +380,8 @@ int xgi_driver_load(struct drm_device *dev, unsigned long flags) if ((info->mmio.base == 0) || (info->mmio.size == 0)) { DRM_ERROR("mmio appears to be wrong: 0x%lx 0x%x\n", (unsigned long) info->mmio.base, info->mmio.size); - return -EINVAL; + err = -EINVAL; + goto fail; } @@ -386,28 +392,24 @@ int xgi_driver_load(struct drm_device *dev, unsigned long flags) (unsigned long) info->fb.base, info->fb.size); - xgi_mem_block_cache = kmem_cache_create("xgi_mem_block", - sizeof(struct xgi_mem_block), - 0, - SLAB_HWCACHE_ALIGN, - NULL, NULL); - if (xgi_mem_block_cache == NULL) { - return -ENOMEM; + err = drm_sman_init(&info->sman, 2, 12, 8); + if (err) { + goto fail; } return 0; + +fail: + drm_free(info, sizeof(*info), DRM_MEM_DRIVER); + return err; } int xgi_driver_unload(struct drm_device *dev) { struct xgi_info * info = dev->dev_private; - if (xgi_mem_block_cache) { - kmem_cache_destroy(xgi_mem_block_cache); - xgi_mem_block_cache = NULL; - } - + drm_sman_takedown(&info->sman); drm_free(info, sizeof(*info), DRM_MEM_DRIVER); dev->dev_private = NULL; -- cgit v1.2.3 From 6dd97099ea5c6dc7931c6b482eb5935f7dd9ed2d Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Thu, 9 Aug 2007 16:20:44 -0700 Subject: Minor clean up of IRQ code. Much, much more to come. --- linux-core/xgi_drv.c | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index b0f84c81..d0878184 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -186,8 +186,6 @@ void xgi_engine_init(struct xgi_info * info) } -void xgi_kern_isr_bh(struct drm_device *dev); - int xgi_bootstrap(struct drm_device * dev, void * data, struct drm_file * filp) { @@ -335,28 +333,19 @@ void xgi_reclaim_buffers_locked(struct drm_device * dev, irqreturn_t xgi_kern_isr(DRM_IRQ_ARGS) { struct drm_device *dev = (struct drm_device *) arg; -// struct xgi_info *info = dev->dev_private; - u32 need_to_run_bottom_half = 0; - - //DRM_INFO("xgi_kern_isr \n"); + struct xgi_info *info = dev->dev_private; + const u32 irq_bits = DRM_READ32(info->mmio_map, 0x2810); - //xgi_dvi_irq_handler(info); - if (need_to_run_bottom_half) { - drm_locked_tasklet(dev, xgi_kern_isr_bh); + if ((irq_bits & 0x00000000) != 0) { + DRM_WRITE32(info->mmio_map, 0x2810, + 0x04000000 | irq_bits); + return IRQ_HANDLED; + } else { + return IRQ_NONE; } - - return IRQ_HANDLED; } -void xgi_kern_isr_bh(struct drm_device *dev) -{ - struct xgi_info *info = dev->dev_private; - - DRM_INFO("xgi_kern_isr_bh \n"); - - //xgi_dvi_irq_handler(info); -} int xgi_driver_load(struct drm_device *dev, unsigned long flags) { -- cgit v1.2.3 From 371f0a4d410f02d8db050b51fd2e714f888a71e0 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Thu, 9 Aug 2007 18:15:42 -0700 Subject: Mask off correct bits in M2REG_AUTO_LINK_STATUS for interrupt handling. --- linux-core/xgi_drv.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index d0878184..f20df585 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -334,12 +334,19 @@ irqreturn_t xgi_kern_isr(DRM_IRQ_ARGS) { struct drm_device *dev = (struct drm_device *) arg; struct xgi_info *info = dev->dev_private; - const u32 irq_bits = DRM_READ32(info->mmio_map, 0x2810); - - - if ((irq_bits & 0x00000000) != 0) { - DRM_WRITE32(info->mmio_map, 0x2810, - 0x04000000 | irq_bits); + const u32 irq_bits = DRM_READ32(info->mmio_map, + (0x2800 + + M2REG_AUTO_LINK_STATUS_ADDRESS)) + & (M2REG_ACTIVE_TIMER_INTERRUPT_MASK + | M2REG_ACTIVE_INTERRUPT_0_MASK + | M2REG_ACTIVE_INTERRUPT_2_MASK + | M2REG_ACTIVE_INTERRUPT_3_MASK); + + + if (irq_bits != 0) { + DRM_WRITE32(info->mmio_map, + 0x2800 + M2REG_AUTO_LINK_SETTING_ADDRESS, + M2REG_AUTO_LINK_SETTING_COMMAND | irq_bits); return IRQ_HANDLED; } else { return IRQ_NONE; -- cgit v1.2.3 From 20a0e5e4298761ae6005399e45d66b93109d2121 Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Thu, 9 Aug 2007 18:57:15 -0700 Subject: After calling drm_sman_cleanup, mark both heaps as uninitialized. Since the heaps weren't marked as uninitialized, SG memory was never re-allocated. This prevented the X-server from being able to restart without re-loading the kernel module. --- linux-core/xgi_drv.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index f20df585..fa418c0d 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -301,6 +301,9 @@ void xgi_driver_lastclose(struct drm_device * dev) if (info->fb_heap_initialized || info->pcie_heap_initialized) { drm_sman_cleanup(&info->sman); + + info->fb_heap_initialized = FALSE; + info->pcie_heap_initialized = FALSE; } } } -- cgit v1.2.3 From f563a50d145848ed296b63c63422caff80232ddf Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Tue, 14 Aug 2007 13:44:51 -0700 Subject: Eliminate unused / useless ioctls. --- linux-core/xgi_drv.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index fa418c0d..0e77d4cd 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -41,15 +41,9 @@ static int xgi_bootstrap(struct drm_device *, void *, struct drm_file *); static struct drm_ioctl_desc xgi_ioctls[] = { DRM_IOCTL_DEF(DRM_XGI_BOOTSTRAP, xgi_bootstrap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), - DRM_IOCTL_DEF(DRM_XGI_ALLOC, xgi_alloc_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_XGI_FREE, xgi_free_ioctl, DRM_AUTH), - - DRM_IOCTL_DEF(DRM_XGI_GE_RESET, xgi_ge_reset_ioctl, DRM_AUTH), - DRM_IOCTL_DEF(DRM_XGI_DUMP_REGISTER, xgi_dump_register_ioctl, DRM_AUTH), - DRM_IOCTL_DEF(DRM_XGI_DEBUG_INFO, xgi_restore_registers_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_XGI_SUBMIT_CMDLIST, xgi_submit_cmdlist, DRM_AUTH), - DRM_IOCTL_DEF(DRM_XGI_TEST_RWINKERNEL, xgi_test_rwinkernel_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_XGI_STATE_CHANGE, xgi_state_change_ioctl, DRM_AUTH|DRM_MASTER), }; -- cgit v1.2.3 From d8a800b63de09f41d482d2b3367e4da67ed0f92b Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Wed, 15 Aug 2007 21:05:26 -0700 Subject: Implement fence support. --- linux-core/xgi_drv.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index 0e77d4cd..241cd39f 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -37,6 +37,17 @@ static struct pci_device_id pciidlist[] = { xgi_PCI_IDS }; +static struct drm_fence_driver xgi_fence_driver = { + .num_classes = 1, + .wrap_diff = BEGIN_BEGIN_IDENTIFICATION_MASK, + .flush_diff = BEGIN_BEGIN_IDENTIFICATION_MASK - 1, + .sequence_mask = BEGIN_BEGIN_IDENTIFICATION_MASK, + .lazy_capable = 1, + .emit = xgi_fence_emit_sequence, + .poke_flush = xgi_poke_flush, + .has_irq = xgi_fence_has_irq +}; + static int xgi_bootstrap(struct drm_device *, void *, struct drm_file *); static struct drm_ioctl_desc xgi_ioctls[] = { @@ -95,6 +106,8 @@ static struct drm_driver driver = { .remove = __devexit_p(drm_cleanup_pci), }, + .fence_driver = &xgi_fence_driver, + .name = DRIVER_NAME, .desc = DRIVER_DESC, .date = DRIVER_DATE, @@ -189,6 +202,10 @@ int xgi_bootstrap(struct drm_device * dev, void * data, int err; + spin_lock_init(&info->fence_lock); + info->next_sequence = 0; + info->complete_sequence = 0; + if (info->mmio_map == NULL) { err = drm_addmap(dev, info->mmio.base, info->mmio.size, _DRM_REGISTERS, _DRM_KERNEL, @@ -344,6 +361,7 @@ irqreturn_t xgi_kern_isr(DRM_IRQ_ARGS) DRM_WRITE32(info->mmio_map, 0x2800 + M2REG_AUTO_LINK_SETTING_ADDRESS, M2REG_AUTO_LINK_SETTING_COMMAND | irq_bits); + xgi_fence_handler(dev); return IRQ_HANDLED; } else { return IRQ_NONE; -- cgit v1.2.3 From 2bcd5b5e330843e1e1a5f0a19105ecd33e76b00b Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Wed, 29 Aug 2007 00:04:18 -0700 Subject: Use DRM_SPINLOCK / DRM_UNSPINLOCK macros. --- linux-core/xgi_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index 241cd39f..6b576558 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -202,7 +202,7 @@ int xgi_bootstrap(struct drm_device * dev, void * data, int err; - spin_lock_init(&info->fence_lock); + DRM_SPINLOCK_INIT(&info->fence_lock); info->next_sequence = 0; info->complete_sequence = 0; -- cgit v1.2.3 From c46ffd6b2943332a88589fb525305ffd09d35b8d Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Wed, 29 Aug 2007 00:23:30 -0700 Subject: Fix late night dumb-dumb mistake. --- linux-core/xgi_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index 6b576558..4b90579e 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -202,7 +202,7 @@ int xgi_bootstrap(struct drm_device * dev, void * data, int err; - DRM_SPINLOCK_INIT(&info->fence_lock); + DRM_SPININIT(&info->fence_lock, "fence lock"); info->next_sequence = 0; info->complete_sequence = 0; -- cgit v1.2.3 From 9c5b9d458bc618fb9d7d8590c866655e92f9cb0b Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Wed, 29 Aug 2007 14:41:49 -0700 Subject: Use ati_pcigart for PCI-e GART table handling. --- linux-core/xgi_drv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index 4b90579e..84547f62 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -306,7 +306,7 @@ void xgi_driver_lastclose(struct drm_device * dev) info->fb_map = NULL; if (info->pcie_heap_initialized) { - xgi_pcie_lut_cleanup(info); + drm_ati_pcigart_cleanup(dev, &info->gart_info); } if (info->fb_heap_initialized -- cgit v1.2.3 From a3881ad2fef99aaf0a863609a847020ea822798c Mon Sep 17 00:00:00 2001 From: Ian Romanick Date: Tue, 18 Sep 2007 11:03:49 -0700 Subject: Add ioc32 compat layer for XGI DRM. --- linux-core/xgi_drv.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'linux-core/xgi_drv.c') diff --git a/linux-core/xgi_drv.c b/linux-core/xgi_drv.c index 84547f62..bc6873a9 100644 --- a/linux-core/xgi_drv.c +++ b/linux-core/xgi_drv.c @@ -48,7 +48,7 @@ static struct drm_fence_driver xgi_fence_driver = { .has_irq = xgi_fence_has_irq }; -static int xgi_bootstrap(struct drm_device *, void *, struct drm_file *); +int xgi_bootstrap(struct drm_device *, void *, struct drm_file *); static struct drm_ioctl_desc xgi_ioctls[] = { DRM_IOCTL_DEF(DRM_XGI_BOOTSTRAP, xgi_bootstrap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY), @@ -97,6 +97,9 @@ static struct drm_driver driver = { .mmap = drm_mmap, .poll = drm_poll, .fasync = drm_fasync, +#if defined(CONFIG_COMPAT) && LINUX_VERSION_CODE > KERNEL_VERSION(2,6,9) + .compat_ioctl = xgi_compat_ioctl, +#endif }, .pci_driver = { -- cgit v1.2.3