diff --git a/device/3dfx_driver.c b/device/3dfx_driver.c new file mode 100644 index 0000000..32148a1 --- /dev/null +++ b/device/3dfx_driver.c @@ -0,0 +1,753 @@ +/* + + /dev/3dfx device for 2.x kernels with MTRR settings enabled. + + Compile with : + + gcc -O2 -DMODULE -D__KERNEL__ -I/usr/src/linux/include -pipe + -fno-strength-reduce -malign-loops=2 -malign-jumps=2 + -malign-functions=2 -c -o 3dfx.o 3dfx_driver.c + + Add -D__SMP__ if you're running of an multi-processor system. + Add -DHAVE_MTRR if you have and want MTRR settings. + Add -g -Wall -Wstrict-prototypes -DDEBUG, if you are debugging. + + Original by Daryll Straus. + Port to 2.1 kernel by Jon Taylor. + setmtrr_3dfx() added by Jens Axboe. + Combining 2.0 and 2.1/2.2 kernels into one rpm, + resetmtrr_3df(), and using correct pci calls for + 2.1/2.2 kernels by Carlo Wood. + + ChangeLog + + 2000/02/04 Joseph Kain + + * Updated Carlo Woord's email address. + + 1999/12/22 Joseph Kain + + * Support for new VMA structure in Kernels 2.3.14 and higher. + This patch is based on Dieter Nuetzel's work. + + 1999/11/09 Joseph Kain + + * Made cards static to remove conflict with hisax ISDN driver. + + 1998/10/30 Carlo Wood + + * Re-included module versions (this source was based on the + source by Jon Taylor which was based on an older version + by Daryll Straus. I now included the later changes made + by Daryll in this source too). + * Use pci_find_device for 2.1/2.2 kernels instead of the old + pcibios_find_device. Idem pci_present(). + + 1998/10/21 Carlo Wood + + * Fixed compile bugs related to 2.0 kernels. + + 1998/10/21 Carlo Wood + + * `struct file_operations' was changed as of kernel 2.1.118, + fixed this module to also work with versions > 2.1.117. + + * Machines that don't have mtrr still need . + + 1998/10/20 Carlo Wood + + * Finally fixed in init_module() the right way. This time I tested + it too (it now really works). + + * Added resetmtrr_3dfx() to clean up the MTRR settings when the + module is unloaded. This is not really necessary but its clean. + It allows to compare using this device WITH MTRR with another + method WITHOUT MTRR, without being confused by sticky MTRR settings + for instance. + + 1998/10/18 Carlo Wood + + * Forgot the '== -EBUSY' in init_module(), causing the registration of + character device to always fail. You need to reboot if you tried + the previous version (if there is junk in `cat /proc/devices' major 107). + + 1998/10/18 Carlo Wood + + * struct file_operations fops_3dfx was initialized wrong: + `release_3dfx' was put on the place of `fsync', causing weird + behaviour :). + + * Several warning fixes. + + * setmtrr_3dfx did not always return a value, and the value was + ignored, effectively ignoring errors returned by mtrr_add(). + + */ + +/* Include this first as it defines things that affect the kernel headers */ +#include +#include + +#ifndef KERNEL_VERSION +#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) +#endif + +#define KERNEL_MIN_VER(a,b,c) (LINUX_VERSION_CODE >= KERNEL_VERSION(a,b,c)) + +#if !KERNEL_MIN_VER (2, 1, 115) +/* It might work with smaller kernels, but I never tested that */ +#error "Upgrade your kernel" +#endif + +#ifdef MODULE +#include +#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) +#define MODVERSIONS +#endif +#ifdef MODVERSIONS +#include +#endif +#else +#define MOD_INC_USE_COUNT +#define MOD_DEC_USE_COUNT +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#ifdef HAVE_MTRR +#include +#endif + +#define MAJOR_3DFX 107 +#define DEVICE_VOODOO 0 + +#define PCI_VENDOR_ID_LINUX 0x0 +#define PCI_DEVICE_ID_LINUX 0x2 +#define PCI_COMMAND_LINUX 0x4 +#define PCI_REVISION_ID_LINUX 0x8 +#define PCI_BASE_ADDRESS_0_LINUX 0x10 +#define PCI_BASE_ADDRESS_1_LINUX 0x14 +#define SST1_PCI_SPECIAL1_LINUX 0x40 +#define SST1_PCI_SPECIAL2_LINUX 0x44 +#define SST1_PCI_SPECIAL3_LINUX 0x48 +#define SST1_PCI_SPECIAL4_LINUX 0x54 + +#define VGA_INPUT_STATUS_1C 0x3DA +#define VGA_MISC_OUTPUT_READ 0x3cc +#define VGA_MISC_OUTPUT_WRITE 0x3c2 +#define SC_INDEX 0x3c4 +#define SC_DATA 0x3c5 + +#ifndef PCI_VENDOR_ID_3DFX +#define PCI_VENDOR_ID_3DFX 0x121a +#endif + +#ifndef PCI_VENDOR_ID_ALLIANCE +#define PCI_VENDOR_ID_ALLIANCE 0x1142 +#endif + +#ifndef PCI_DEVICE_ID_3DFX_VOODOO2 +#define PCI_DEVICE_ID_3DFX_VOODOO2 2 +#endif + +#ifndef PCI_DEVICE_ID_ALLIANCE_AT3D +#define PCI_DEVICE_ID_ALLIANCE_AT3D 0x643d +#endif + +#ifndef PCI_DEVICE_ID_3DFX_BANSHEE +#define PCI_DEVICE_ID_3DFX_BANSHEE 3 +#endif + +#ifndef PCI_DEVICE_ID_3DFX_VOODOO3 +#define PCI_DEVICE_ID_3DFX_VOODOO3 5 +#endif + +#ifdef DEBUG +#define DEBUGMSG(x) printk x +#else +#define DEBUGMSG(x) +#endif + +/* This macro is for accessing vma->vm_offset or vma->vm_pgoff depending + * on kernel version */ +#if !KERNEL_MIN_VER(2, 3, 14) +#define VM_OFFSET(vma) (vma->vm_offset) +#else +#define VM_OFFSET(vma) (vma->vm_pgoff << PAGE_SHIFT) +#endif + +struct pioData_t { + short port; + short size; + int device; + void *value; +}; + +struct cardInfo_t { + int vendor; + int type; + int addr0; + int addr1; + unsigned char bus; + unsigned char dev; + struct file *curFile; +#ifdef HAVE_MTRR + int mtrr_buf; + int mtrr_ctl; +#endif +}; + +typedef struct pioData_t pioData; +typedef struct cardInfo_t cardInfo; + +#ifdef MODULE +void cleanup_module(void); +#endif + +#define MAXCARDS 16 + +static cardInfo cards[MAXCARDS]; +static int numCards = 0; + +static void findCardType(int vendor, int device) +{ + struct pci_dev *dev = NULL; + while (numCards < MAXCARDS && (dev = pci_find_device(vendor, device, dev))) { + pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &cards[numCards].addr0); + pci_read_config_dword(dev, PCI_BASE_ADDRESS_1, &cards[numCards].addr1); + cards[numCards].bus = dev->bus->number; + cards[numCards].dev = dev->devfn; + + cards[numCards].addr0 &= ~0xF; + cards[numCards].addr1 &= ~0xF; + cards[numCards].vendor = vendor; + cards[numCards].type = device; + cards[numCards].curFile = 0; + + DEBUGMSG(("3dfx: board vendor %d type %d located at %x/%x bus %d dev %d\n", + vendor, device, cards[numCards].addr0, cards[numCards].addr1, cards[numCards].bus, cards[numCards].dev)); + + ++numCards; + } +} + +static int findCards(void) +{ + if (!pci_present()) + return 0; + numCards = 0; + findCardType(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO); + findCardType(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO2); + findCardType(PCI_VENDOR_ID_ALLIANCE, 0x643d); + findCardType(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_BANSHEE); + findCardType(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO3); + return numCards; +} + +static int open_3dfx(struct inode *inode, struct file *file) +{ + DEBUGMSG(("3dfx: Entering open_3dfx\n")); + if (!numCards) { + printk("3dfx: No 3Dfx cards found\n"); + return -ENODEV; + } + MOD_INC_USE_COUNT; + return 0; +} + +static int release_3dfx(struct inode *inode, struct file *file) +{ + int i; + + DEBUGMSG(("3dfx: Entering release_3dfx\n")); + for (i = 0; i < numCards; ++i) + if (cards[i].curFile == file) + cards[i].curFile = 0; + MOD_DEC_USE_COUNT; + + return 0; +} + +static int mmap_3dfx(struct file *file, struct vm_area_struct *vma) +{ + size_t len; + int i; + + DEBUGMSG(("3dfx: Entering mmap_3dfx\n")); + for (i = 0; i < numCards; ++i) { + if ((cards[i].addr0 == VM_OFFSET(vma)) || + (cards[i].addr1 == VM_OFFSET(vma))) + break; + } + if (i == numCards) { + DEBUGMSG(("3dfx: Couldn't match address %lx to a card\n", + VM_OFFSET(vma))); + return -EPERM; + } + /* This one is a special case, the macro doesn't help */ +#if !KERNEL_MIN_VER(2, 3, 14) + if ((vma->vm_offset) & ~PAGE_MASK) { + DEBUGMSG(("3dfx: Map request not page aligned\n")); + return -ENXIO; + } +#else + if ((vma->vm_pgoff) & ~PAGE_MASK) { + DEBUGMSG(("3dfx: Map request not page aligned\n")); + return -ENXIO; + } +#endif + len = vma->vm_end - vma->vm_start; + if ((len < 0) || (len > 0x2000000)) { + DEBUGMSG(("3dfx: Invalid mapping size requested\n")); + return -EINVAL; + } +#if defined(__i386__) + pgprot_val(vma->vm_page_prot) |= _PAGE_PCD; +#endif + if (remap_page_range(vma->vm_start, VM_OFFSET(vma), len, + vma->vm_page_prot)) { + DEBUGMSG(("3dfx: Page remap failed\n")); + return -EAGAIN; + } + return 0; +} + +static int doQueryBoards(void) +{ + return numCards; +} + +static int doQueryFetch(pioData *desc) +{ + int retval; + char retchar; + short retword; + int retlong; + + if (desc->device < 0 || desc->device >= numCards) + return -EINVAL; + if ((retval = verify_area(VERIFY_WRITE, desc->value, desc->size))) + return retval; + switch (desc->port) { + case PCI_VENDOR_ID_LINUX: + if (desc->size != 2) + return -EINVAL; + copy_to_user(desc->value, &cards[desc->device].vendor, desc->size); + return 0; + case PCI_DEVICE_ID_LINUX: + if (desc->size != 2) + return -EINVAL; + copy_to_user(desc->value, &cards[desc->device].type, desc->size); + return 0; + case PCI_BASE_ADDRESS_0_LINUX: + if (desc->size != 4) + return -EINVAL; + copy_to_user(desc->value, &cards[desc->device].addr0, desc->size); + return 0; + case PCI_BASE_ADDRESS_1_LINUX: + if (desc->size != 4) + return -EINVAL; + copy_to_user(desc->value, &cards[desc->device].addr1, desc->size); + return 0; + case SST1_PCI_SPECIAL1_LINUX: + if (desc->size != 4) + return -EINVAL; + break; + case PCI_REVISION_ID: + if (desc->size != 1) + return -EINVAL; + break; + case SST1_PCI_SPECIAL4_LINUX: + if (desc->size != 4) + return -EINVAL; + break; + default: + return -EINVAL; + } + switch (desc->size) { + case 1: + pcibios_read_config_byte(cards[desc->device].bus, cards[desc->device].dev, desc->port, &retchar); + copy_to_user(desc->value, &retchar, 1); + break; + case 2: + pcibios_read_config_word(cards[desc->device].bus, cards[desc->device].dev, desc->port, &retword); + copy_to_user(desc->value, &retword, 2); + break; + case 4: + pcibios_read_config_dword(cards[desc->device].bus, cards[desc->device].dev, desc->port, &retlong); + copy_to_user(desc->value, &retlong, 4); + break; + default: + return -EINVAL; + } + return 0; +} + +static int doQueryUpdate(pioData *desc) +{ + int retval; + int preval; + int mask; + char retchar; + short retword; + int retlong; + + if (desc->device < 0 || desc->device >= numCards) + return -EINVAL; + if ((retval = verify_area(VERIFY_WRITE, desc->value, desc->size))) + return retval; + switch (desc->port) { + case PCI_COMMAND_LINUX: + if (desc->size != 2) + return -EINVAL; + break; + case SST1_PCI_SPECIAL1_LINUX: + if (desc->size != 4) + return -EINVAL; + break; + case SST1_PCI_SPECIAL2_LINUX: + if (desc->size != 4) + return -EINVAL; + break; + case SST1_PCI_SPECIAL3_LINUX: + if (desc->size != 4) + return -EINVAL; + break; + case SST1_PCI_SPECIAL4_LINUX: + if (desc->size != 4) + return -EINVAL; + break; + default: + return -EINVAL; + } + pcibios_read_config_dword(cards[desc->device].bus, cards[desc->device].dev, desc->port & ~0x3, &retval); + switch (desc->size) { + case 1: + copy_from_user(&retchar, desc->value, 1); + preval = retchar << (8 * (desc->port & 0x3)); + mask = 0xFF << (8 * (desc->port & 0x3)); + break; + case 2: + copy_from_user(&retword, desc->value, 2); + preval = retword << (8 * (desc->port & 0x3)); + mask = 0xFFFF << (8 * (desc->port & 0x3)); + break; + case 4: + copy_from_user(&retlong, desc->value, 4); + preval = retlong; + mask = ~0; + break; + default: + return -EINVAL; + } + retval = (retval & ~mask) | preval; + pcibios_write_config_dword(cards[desc->device].bus, cards[desc->device].dev, desc->port, retval); + return 0; +} + +static int doQuery(unsigned int cmd, unsigned long arg) +{ + pioData desc; + int retval; + + if (_IOC_NR(cmd) == 2) + return doQueryBoards(); + if ((retval = verify_area(VERIFY_READ, (void *)arg, sizeof(pioData)))) + return retval; + copy_from_user(&desc, (void *)arg, sizeof(pioData)); + if (_IOC_NR(cmd) == 3) + return doQueryFetch(&desc); + if (_IOC_NR(cmd) == 4) + return doQueryUpdate(&desc); + return -EINVAL; +} + +static int doPIORead(pioData *desc) +{ + int retval; + char retchar; + + if ((retval = verify_area(VERIFY_WRITE, desc->value, desc->size))) + return retval; + switch (desc->port) { + case VGA_INPUT_STATUS_1C: + break; + case SC_INDEX: + break; + case SC_DATA: + break; + case VGA_MISC_OUTPUT_READ: + break; + default: + return -EPERM; + } + + if (desc->size != 1) + return -EINVAL; + + retchar = inb(desc->port); + copy_to_user(desc->value, &retchar, sizeof(char)); + + return 0; +} + +static int doPIOWrite(pioData *desc) +{ + int retval; + char retchar; + + if ((retval = verify_area(VERIFY_READ, desc->value, desc->size))) + return retval; + + switch (desc->port) { + case SC_INDEX: + break; + case SC_DATA: + break; + case VGA_MISC_OUTPUT_WRITE: + break; + default: + return -EPERM; + } + + if (desc->size != 1) + return -EINVAL; + + copy_from_user(&retchar, desc->value, sizeof(char)); + outb(retchar, desc->port); + + return 0; +} + +static int doPIO(unsigned int cmd, unsigned long arg) +{ + pioData desc; + int retval; + + if ((retval = verify_area(VERIFY_READ, (void *)arg, sizeof(pioData)))) + return retval; + copy_from_user(&desc, (void *)arg, sizeof(pioData)); + if (_IOC_DIR(cmd) == _IOC_READ) + return doPIORead(&desc); + if (_IOC_DIR(cmd) == _IOC_WRITE) + return doPIOWrite(&desc); + + return -EINVAL; +} + +static int ioctl_3dfx(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + DEBUGMSG(("3dfx: Entering ioctl_3dfx, inode %p file %p cmd %x arg %lx\n", inode, file, cmd, arg)); + switch (_IOC_TYPE(cmd)) { + case '3': + return doQuery(cmd, arg); + case 0: + return doPIO(cmd, arg); + default: + DEBUGMSG(("3dfx: Unknown 3dfx request made\n")); + return -EINVAL; + } +} + +#ifdef HAVE_MTRR +int setmtrr_3dfx(void) +{ + int i = 0, retval = -2; + unsigned char dlc; + + /* First do a bios fixup if this system has a 82441FX chipset */ + struct pci_dev *dev = NULL; + if ((dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, dev))) { + pci_read_config_byte(dev, 0x82, &dlc); + if (!(dlc & 1 << 1)) { + dlc |= 1 << 1; + pci_write_config_byte(dev, 0x82, dlc); + printk("3dfx: PIIX3: Enabling Passive Release\n"); + } + } + + /* Set up the mtrr's */ + if (numCards == 0) + return -EIO; + for (i = 0; i < numCards; i++) { + if ((cards[i].vendor != PCI_VENDOR_ID_3DFX) || + (cards[i].type>PCI_DEVICE_ID_3DFX_VOODOO3)) + { + cards[i].mtrr_buf = -1; /* Used as flag in resetmtrr_3dfx() */ + continue; + } + switch (cards[i].type) { + case PCI_DEVICE_ID_3DFX_VOODOO: + case PCI_DEVICE_ID_3DFX_VOODOO2: + /* Frame buffer to write combining */ + retval = cards[i].mtrr_buf = mtrr_add(cards[i].addr0, 0x400000, MTRR_TYPE_WRCOMB, 1); + if (retval>=0) { + retval = cards[i].mtrr_ctl = mtrr_add(cards[i].addr0, 0x1000, MTRR_TYPE_UNCACHABLE, 1); + if (retval<0) { + mtrr_del(cards[i].mtrr_buf, 0, 0); + cards[i].mtrr_buf=-1; + } + } + if (retval < 0) { + printk("3dfx: Could not set MTRR for Voodoo card\n"); + /* Can still run */ + return 0; + } + break; + case PCI_DEVICE_ID_3DFX_BANSHEE: + case PCI_DEVICE_ID_3DFX_VOODOO3: + retval = cards[i].mtrr_buf = mtrr_add(cards[i].addr1, 0x1000000, MTRR_TYPE_WRCOMB, 1); + if (retval < 0) { + printk("3dfx: Could not set MTRR for Voodoo card\n"); + /* Can still run */ + return 0; + } + cards[i].mtrr_ctl=-1; + break; + default: + /* We should never hit this */ + } + } + if (retval == -2) + { + DEBUGMSG(("3dfx: Could not set MTRR for this graphics card\n")); + retval = 0; /* Can still run */ + } +#ifdef DEBUG + else if (retval >= 0) + DEBUGMSG(("3dfx: Successfully set MTRR, mtrr register: %d\n", retval)); +#endif + + return retval; +} + +int resetmtrr_3dfx(void) +{ + int i, ret, retval = 0; + for (i = 0; i < numCards; i++) { + if (cards[i].mtrr_buf >= 0) { + ret = mtrr_del(cards[i].mtrr_buf, 0, 0); + if (ret < 0) + retval = ret; + cards[i].mtrr_buf = -1; + if (cards[i].mtrr_ctl >= 0) { + ret = mtrr_del(cards[i].mtrr_ctl, 0, 0); + if (ret < 0) + retval = ret; + cards[i].mtrr_ctl = -1; + } + } + } + return retval; +} + +#endif /* HAVE_MTRR */ + +static struct file_operations fops_3dfx = { +#if KERNEL_MIN_VER(2, 4, 0) + owner: THIS_MODULE, +#endif + ioctl: ioctl_3dfx, /* ioctl */ + mmap: mmap_3dfx, /* mmap */ + open: open_3dfx, /* open */ + release: release_3dfx, /* release */ +}; + +#ifdef MODULE +int init_module(void) +{ + int ret; + DEBUGMSG(("3dfx: Entering init_module()\n")); + + if ((ret = register_chrdev(MAJOR_3DFX, "3dfx", &fops_3dfx)) < 0) { + printk("3dfx: Unable to register character device with major %d\n", MAJOR_3DFX); + return ret; + } + DEBUGMSG(("3dfx: Successfully registered device 3dfx\n")); + findCards(); + +#ifdef HAVE_MTRR + ret = setmtrr_3dfx(); + if (ret < 0) + { + DEBUGMSG(("setmtrr_3dfx() failed, returned %d\n", ret)); + /* + unregister_chrdev(MAJOR_3DFX, "3dfx"); + return ret; + */ + } +#endif + + return 0; +} + +void cleanup_module(void) +{ + DEBUGMSG(("3dfx: Entering cleanup_module\n")); + +#ifdef HAVE_MTRR + resetmtrr_3dfx(); +#endif + if (unregister_chrdev(MAJOR_3DFX, "3dfx")) + { + DEBUGMSG(("3dfx: unregister_chrdev failed\n")); + return; + } +} +#else /* !MODULE */ + +long init_3dfx(long mem_start, long mem_end) +{ + if (register_chrdev(MAJOR_3DFX, "3dfx", &fops_3dfx)) + { + DEBUGMSG(("3dfx: Unable to register_chrdev with major %d\n", MAJOR_3DFX)); + return 0; + } + findCards(); + + return mem_start; +} +#endif /* !MODULE */ + + +#if defined(DEBUG) +/* + * Kludge to get rid of: + * ./3dfx.o: unresolved symbol inb + * ./3dfx.o: unresolved symbol inl + * ./3dfx.o: unresolved symbol inw + * ./3dfx.o: unresolved symbol outb + * ./3dfx.o: unresolved symbol outl + * ./3dfx.o: unresolved symbol outw + * when compiling this module with -g during debugging. + */ +#undef __KERNEL__ +#define extern +#undef _ASM_IO_H +#include +/* + * And this is copied from asm/uaccess.h + * in order to get rid of + * ./3dfx.o: unresolved symbol verify_area + * when compiling this module with -g during debugging. + */ +inline int verify_area(int type, const void * addr, unsigned long size) +{ + return access_ok(type,addr,size) ? 0 : -EFAULT; +} + +int a_last_dummy_function(int a) +{ + return a; +} +#endif diff --git a/device/Device3Dfx.spec b/device/Device3Dfx.spec new file mode 100644 index 0000000..14bbf56 --- /dev/null +++ b/device/Device3Dfx.spec @@ -0,0 +1,160 @@ +Summary: Device driver for 3Dfx boards for 2.x kernels +Name: Device3Dfx +Version: 2.3 +Release: 5 +Icon: 3dfx.gif +Source: Device3Dfx.tar.gz +License: GPL +Group: Drivers + +%changelog + +* Sat Apr 08 2000 Joseph Kain + Release 2.3-5 +- Check both the kernel and the processor for MTRR support before enabling. + +* Wed Jan 04 2000 Joseph Kain + Release 2.3-4 + +- Forgot to include kinfo.h in 3dfx_driver.c in the last release. This + fixes some build problems for SMP kernels. + +* Wed Dec 22 1999 Joseph Kain + Release 2.3-3 + +- Fixes to the Makefile to stop grepping the header files. Changes to + mtrr.c and 3dfx_driver.c to support these Makefile changes. +- 3dfx_driver.c now supports 2.3.14+ kernels. + +* Mon Dec 13 1999 Joseph Kain + Release 2.3-2 + +- Removed depmod -a from the Makefile. This elliminates errors in the + build on systems with modules with broken depedancies (Happens on Madrake) +- Changed depmod -a to depmod -a > /dev/null in the post and postun to + elliminate any warnings/errors with modules that don't have anything + to do with Device3Dfx. Warnings scare people. + +* Tue Nov 09 1999 Joseph Kain + Release 2.3: + +- Made cards static to remove conflict with hisax ISDN driver. +- Removed 3dfx.o from the source distribution + +* Fri Jun 25 1999 Daryll Strauss + + Release 2.2: + +- Set MTRR for VB/V3 boards +- Allow build without kernel sources installed +- Code cleanup +- Improvements in /etc/conf.modules setup + +* Sun May 16 1999 Daryll Strauss + + Release 2.1: + +- Added support for multiple board mappings +- Enlarged size of mappings +- Changes to support VB/V3 boards + +* Sun Apr 4 1999 Daryll Strauss + + Release 2.0-1: + +- This is just a rename of Michael's version to return it to my original + naming scheme. +- Added the License field to the spec file. + +* Thu Mar 11 1999 Michael Vance + + Release 2.5-2: + +- Fixed for 2.2.3 kernels because of an mmap() update + +* Fri Oct 30 1998 Carlo Wood + + Release 2.5-1: + +- Upped source to Dev3Dfx-2.5.tar.gz +- Boosted version number of rpm to the version of the tar.gz. + Moved everything to the Makefile, so Dev3Dfx-2.5.tar.gz is + self containing and will work without rpm too. + +* Wed Oct 21 1998 Carlo Wood + + Release 1.2-5: + +- Upped source to Dev3Dfx-2.4.tar.gz +- Removed dangerous and confusing use of /lib/modules/preferred +- Removed the use of `uname': It now will compile for the kernel + version in /usr/src/linux and not be bothered by the running + kernel version. + +* Wed Oct 21 1998 Carlo Wood + + Release 1.2-4: + +- Upped source to Dev3Dfx-2.3.tar.gz + +* Mon Oct 19 1998 Carlo Wood + + Release 1.2-3: + +- Corrected Summary and Description to refer to 2.x rather + then 2.1 kernels. +- Removed script lines that write an `option' line to /etc/conf.modules. +- Upped source to Dev3Dfx-2.2.tar.gz + +* Sun Oct 18 1998 Carlo Wood + + Release 1.2-2: + +- Added OPT_CFLAGS stuff. + +* Sun Oct 18 1998 Carlo Wood + + Release 1.2-1: + +- Packaged version 1.2 with support for 2.1 kernels by John Taylor and + MTRR settings added by Jens Axboe. + +%description +This package installs the 3Dfx device driver to allow access to 3Dfx +boards without the user having root privledges. It should work on both +2.0 and 2.1/2.2 kernels and set the MTRR settings correctly. It should +also work with SMP kernels (2.1/2.2). + +%prep +%setup -c + +%build +make OPT_CFLAGS="$RPM_OPT_FLAGS" + +%install +make RPM_INSTALL="1" install | grep '^/lib/modules/' > modules-file-list + +%post +if [ "$1" = 1 ]; then + grep -v 3dfx /etc/conf.modules > /etc/conf.modules.tmp + echo alias char-major-107 3dfx >> /etc/conf.modules.tmp + mv /etc/conf.modules.tmp /etc/conf.modules +fi +/sbin/depmod -a > /dev/null + +%postun +if [ "$1" = 0 ]; then + grep -v 3dfx /etc/conf.modules > /etc/conf.modules.tmp + mv /etc/conf.modules.tmp /etc/conf.modules +fi +/sbin/depmod -a > /dev/null + +%verifyscript +inconf=`grep 'alias char-major-107 3dfx' /etc/conf.modules` +if [ "x$inconf" = "x" ]; then + echo "3dfx entry not included in /etc/conf.modules" +fi + +%files -f modules-file-list +%verify(not mode user group) /dev/3dfx + diff --git a/device/Makefile b/device/Makefile new file mode 100644 index 0000000..31f5239 --- /dev/null +++ b/device/Makefile @@ -0,0 +1,110 @@ +############################################################################### +# Makefile by Carlo Wood (and others) + +ifeq ($(OPT_CFLAGS),) + +# Determine the machine type +ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) + +# Setup machine dependant compiler flags +ifeq ($(ARCH), i386) +OPT_CFLAGS = -O2 -m486 -fomit-frame-pointer \ + -fno-strength-reduce \ + -malign-loops=2 -malign-jumps=2 -malign-functions=2 +endif + +ifeq ($(ARCH), alpha) +OPT_CFLAGS = -O2 -mno-fp-regs -mcpu=ev4 \ + -ffixed-8 \ + -Wa,-mev6 \ + -fomit-frame-pointer -fno-strict-aliasing +endif + +endif # ifeq ($OPT_CFLAGS),) + +CFLAGS := -DMODULE -D__KERNEL__ -I/usr/src/linux/include $(OPT_CFLAGS) + +############################################################################### +# You should never need to change anything below. + +all: sanity 3dfx.o + +# Sanity checks +sanity: + @( \ + if [ ! -e /usr/src/linux ]; then \ + echo "Expect kernel source at location /usr/src/linux"; \ + echo "Sym.link /usr/src/linux -> where you have your sources"; \ + exit -1; \ + fi; \ + if [ ! -r /usr/src/linux/include ]; then \ + echo "Expect readable headers in /usr/src/linux/include"; \ + exit -1; \ + fi; \ + if [ ! -r /usr/src/linux/include/linux/version.h ]; then \ + echo "Missing /usr/src/linux/include/linux/version.h"; \ + echo "Configure and install the kernel first"; \ + exit -1; \ + fi; \ + if [ ! -e /proc/cpuinfo ]; then \ + echo "You need the /proc file system"; \ + echo "Reconfigure kernel and say Yes to CONFIG_PROC_FS"; \ + exit -1; \ + fi; \ + ) + +kinfo: kinfo.c + $(CC) -o kinfo kinfo.c + +kinfo.h: kinfo + ./kinfo + +############################################################################### +# kernel 2.1+ + +3dfx.o: kinfo.h 3dfx_driver.c Makefile + $(CC) $(CFLAGS) -c -o $@ 3dfx_driver.c + +############################################################################### + +install: + mkdir -p /lib/modules/$(shell ./kinfo --UTS)/misc + cp 3dfx.o /lib/modules/$(shell ./kinfo --UTS)/misc/3dfx.o + @( \ + if [ -e /lib/modules/$(shell ./kinfo --UTS)/modules.dep ]; then \ + indep=`grep 'misc/3dfx.o:' /lib/modules/$(shell ./kinfo --UTS)/modules.dep`; \ + if [ -z "$$indep" ]; then \ + echo "/lib/modules/$(shell ./kinfo --UTS)/misc/3dfx.o:" >> /lib/modules/$(shell ./kinfo --UTS)/modules.dep; \ + echo "" >> /lib/modules/$(shell ./kinfo --UTS)/modules.dep; \ + fi; \ + fi; \ + if [ ! -c /dev/3dfx ]; then \ + mknod /dev/3dfx c 107 0; \ + chmod go+w /dev/3dfx; \ + fi; \ + if [ "$(RPM_INSTALL)" = "1" ]; then \ + echo "/lib/modules/$(shell ./kinfo --UTS)/misc/3dfx.o"; \ + else \ + inconf=`grep 'alias char-major-107 3dfx' /etc/conf.modules`; \ + if [ -z "$$inconf" ]; then \ + echo "alias char-major-107 3dfx" >> /etc/conf.modules; \ + fi; \ + fi; \ + ) + +############################################################################### +# This is for debugging purposes by the developers: + +clean: + rm -f *.o *.s kinfo kinfo.h + +3dfx.s: 3dfx_driver.c Makefile + $(CC) $(CFLAGS) -S -c 3dfx_driver.c + +tar: + tar czf ../../SOURCES/Dev3Dfx-2.5.tar.gz 3dfx_driver.c Makefile + + +debug: + make OPT_CFLAGS="-g -Wall -Wstrict-prototypes -DDEBUG" + diff --git a/device/kinfo.c b/device/kinfo.c new file mode 100644 index 0000000..908c65c --- /dev/null +++ b/device/kinfo.c @@ -0,0 +1,67 @@ +/* + kinfo.c: A small program that includes several kernel heades + and builds a header defining options for 3dfx_driver.c. + + 1999/12/22 Joseph Kain + + * Initial version +*/ + +#include + +/* These include files will bring in the information we need */ +#include +#include + + +int +main (int argc, char **argv) +{ + /* Here is the strategy. The old Makefile would have grepped the kernel + * headers and put these defines on the command line. Now we include + * the kernel headers and extract the information. Then we create a + * new header with all of the options we need. */ + + if (argc == 1) + { + FILE *f = fopen ("kinfo.h", "w"); + FILE *p = NULL; + int result; + char temp[1000]; + +#ifdef CONFIG_MTRR + /* It is not enough to just check if the kernel supports MTRRs, if the + * processor doesn't have MTRRs then its possible (and likely) that + * the kernel was still compiled with MTRR support. So we also have to + * check the processor has MTRRs. */ + + result = system ("grep mtrr /proc/cpuinfo > /dev/null"); + + /* See if grep found anything */ + if (result == 0) /* Grep reported a match */ + { + fprintf (f, "#define HAVE_MTRR\n"); + } + +#endif + +#ifdef CONFIG_SMP + fprintf (f, "#define __SMP__\n"); +#endif + +#ifdef CONFIG_MODVERSIONS + fprintf (f, "#define MODVERSIONS\n"); +#endif + + fclose (f); + } + else + { + if (strcmp (argv[1], "--UTS") == 0) + { + printf ("%s", UTS_RELEASE); + } + } +} + + diff --git a/device/mtrrs.c b/device/mtrrs.c new file mode 100644 index 0000000..3ffa1bd --- /dev/null +++ b/device/mtrrs.c @@ -0,0 +1,935 @@ +/* Generic MTRR (Memory Type Range Register) driver. + + Copyright (C) 1997-1998 Richard Gooch + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + Richard Gooch may be reached by email at rgooch@atnf.csiro.au + The postal address is: + Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia. + + Source: "Pentium Pro Family Developer's Manual, Volume 3: + Operating System Writer's Guide" (Intel document number 242692), + section 11.11.7 + + ChangeLog + + Prehistory Martin Tischhäuser + Initial register-setting code (from proform-1.0). + 19971216 Richard Gooch + Original version for /proc/mtrr interface, SMP-safe. + v1.0 + 19971217 Richard Gooch + Bug fix for ioctls()'s. + Added sample code in Documentation/mtrr.txt + v1.1 + 19971218 Richard Gooch + Disallow overlapping regions. + 19971219 Jens Maurer + Register-setting fixups. + v1.2 + 19971222 Richard Gooch + Fixups for kernel 2.1.75. + v1.3 + 19971229 David Wragg + Register-setting fixups and conformity with Intel conventions. + 19971229 Richard Gooch + Cosmetic changes and wrote this ChangeLog ;-) + 19980106 Richard Gooch + Fixups for kernel 2.1.78. + v1.4 + 19980119 David Wragg + Included passive-release enable code (elsewhere in PCI setup). + v1.5 + 19980131 Richard Gooch + Replaced global kernel lock with private spinlock. + v1.6 + 19980201 Richard Gooch + Added wait for other CPUs to complete changes. + v1.7 + 19980202 Richard Gooch + Bug fix in definition of for UP. + v1.8 + 19980319 Richard Gooch + Fixups for kernel 2.1.90. + 19980323 Richard Gooch + Move SMP BIOS fixup before secondary CPUs call + v1.9 + 19980325 Richard Gooch + Fixed test for overlapping regions: confused by adjacent regions + 19980326 Richard Gooch + Added wbinvd in . + 19980401 Richard Gooch + Bug fix for non-SMP compilation. + 19980418 David Wragg + Fixed-MTRR synchronisation for SMP and use atomic operations + instead of spinlocks. + 19980418 Richard Gooch + Differentiate different MTRR register classes for BIOS fixup. + v1.10 + 19980419 David Wragg + Bug fix in variable MTRR synchronisation. + v1.11 + 19980419 Richard Gooch + Fixups for kernel 2.1.97. + v1.12 + 19980421 Richard Gooch + Safer synchronisation across CPUs when changing MTRRs. + v1.13 + 19980423 Richard Gooch + Bugfix for SMP systems without MTRR support. + v1.14 + 19980427 Richard Gooch + Trap calls to and on non-MTRR machines. + v1.15 + 19980427 Richard Gooch + Use atomic bitops for setting SMP change mask. + v1.16 + 19980428 Richard Gooch + Removed spurious diagnostic message. + v1.17 + 19980429 Richard Gooch + Moved register-setting macros into this file. + Moved setup code from init/main.c to i386-specific areas. + v1.18 + 19980502 Richard Gooch + Moved MTRR detection outside conditionals in . + v1.19 + 19980502 Richard Gooch + Documentation improvement: mention Pentium II and AGP. + v1.20 + 19980521 Richard Gooch + Only manipulate interrupt enable flag on local CPU. + Allow enclosed uncachable regions. + v1.21 + + v1.21-- Emil Briggs + Backported to 2.0.x kernels, /proc and ioctl + interfaces removed and the result incorporated + into the 3dfx device driver. Not SMP safe. If + you have an SMP use the 2.2 series kernels. + + v1.22 + 19991222 Joseph Kain + Do kernel version checks here instead of in + Makefile. The Makefile now only needs the + kernel version for install. +*/ + + +/* Include this first as it defines things that affect the kernel headers */ +#include "kinfo.h" + +/* MTRR support is only available in kerenls versioned 2.1.0 or higher. + * For earlier kernels this code compiles to nothing. */ +#include + +#ifndef KERNEL_VERSION +#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) +#endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 1, 0) + + +#ifndef _LINUX_MTRR_H +#define _LINUX_MTRR_H + +struct mtrr_sentry +{ + unsigned long base; /* Base address */ + unsigned long size; /* Size of region */ + unsigned int type; /* Type of region */ +}; + +struct mtrr_gentry +{ + unsigned int regnum; /* Register number */ + unsigned long base; /* Base address */ + unsigned long size; /* Size of region */ + unsigned int type; /* Type of region */ +}; + + +/* These are the region types */ +#define MTRR_TYPE_UNCACHABLE 0 +#define MTRR_TYPE_WRCOMB 1 +/*#define MTRR_TYPE_ 2*/ +/*#define MTRR_TYPE_ 3*/ +#define MTRR_TYPE_WRTHROUGH 4 +#define MTRR_TYPE_WRPROT 5 +#define MTRR_TYPE_WRBACK 6 +#define MTRR_NUM_TYPES 7 + +static char *mtrr_strings[MTRR_NUM_TYPES] = +{ + "uncachable", /* 0 */ + "write-combining", /* 1 */ + "?", /* 2 */ + "?", /* 3 */ + "write-through", /* 4 */ + "write-protect", /* 5 */ + "write-back", /* 6 */ +}; + +#ifdef __KERNEL__ + +/* The following functions are for use by other drivers */ +extern int mtrr_add (unsigned long base, unsigned long size, + unsigned int type, char increment); +extern int mtrr_del (int reg, unsigned long base, unsigned long size); + +#endif + +#endif /* _LINUX_MTRR_H */ + +#ifdef MODULE +#include +#if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS) +#define MODVERSIONS +#endif +#ifdef MODVERSIONS +#include +#endif +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define MTRR_NEED_STRINGS + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef __SMP__ + +#define MTRR_VERSION "1.21 (19980521)" + +#define TRUE 1 +#define FALSE 0 + +#define X86_FEATURE_MTRR 0x1000 /* memory type registers */ + +#define MTRRcap_MSR 0x0fe +#define MTRRdefType_MSR 0x2ff + +#define MTRRphysBase_MSR(reg) (0x200 + 2 * (reg)) +#define MTRRphysMask_MSR(reg) (0x200 + 2 * (reg) + 1) + +#define NUM_FIXED_RANGES 88 +#define MTRRfix64K_00000_MSR 0x250 +#define MTRRfix16K_80000_MSR 0x258 +#define MTRRfix16K_A0000_MSR 0x259 +#define MTRRfix4K_C0000_MSR 0x268 +#define MTRRfix4K_C8000_MSR 0x269 +#define MTRRfix4K_D0000_MSR 0x26a +#define MTRRfix4K_D8000_MSR 0x26b +#define MTRRfix4K_E0000_MSR 0x26c +#define MTRRfix4K_E8000_MSR 0x26d +#define MTRRfix4K_F0000_MSR 0x26e +#define MTRRfix4K_F8000_MSR 0x26f + + +#ifdef __SMP__ +# define MTRR_CHANGE_MASK_FIXED 0x01 +# define MTRR_CHANGE_MASK_VARIABLE 0x02 +# define MTRR_CHANGE_MASK_DEFTYPE 0x04 +#endif + +/* In the processor's MTRR interface, the MTRR type is always held in + an 8 bit field: */ +typedef u8 mtrr_type; + +#define LINE_SIZE 80 +#define JIFFIE_TIMEOUT 100 + +#define set_mtrr(reg,base,size,type) set_mtrr_up (reg, base, size, type,TRUE) + + +static unsigned int *usage_table = NULL; + + +struct set_mtrr_context +{ + unsigned long flags; + unsigned long deftype_lo; + unsigned long deftype_hi; + unsigned long cr4val; +}; + +/* + * Access to machine-specific registers (available on 586 and better only) + * Note: the rd* operations modify the parameters directly (without using + * pointer indirection), this allows gcc to optimize better + */ +#define rdmsr(msr,val1,val2) \ + __asm__ __volatile__("rdmsr" \ + : "=a" (val1), "=d" (val2) \ + : "c" (msr)) + +#define wrmsr(msr,val1,val2) \ + __asm__ __volatile__("wrmsr" \ + : /* no outputs */ \ + : "c" (msr), "a" (val1), "d" (val2)) + +#define rdtsc(low,high) \ + __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high)) + +#define rdpmc(counter,low,high) \ + __asm__ __volatile__("rdpmc" \ + : "=a" (low), "=d" (high) \ + : "c" (counter)) + + +/* Put the processor into a state where MTRRs can be safely set. */ +static void set_mtrr_prepare(struct set_mtrr_context *ctxt) +{ + unsigned long tmp; + + /* disable interrupts locally */ + save_flags (ctxt->flags); cli (); + + /* save value of CR4 and clear Page Global Enable (bit 7) */ + asm volatile ("movl %%cr4, %0\n\t" + "movl %0, %1\n\t" + "andb $0x7f, %b1\n\t" + "movl %1, %%cr4\n\t" + : "=r" (ctxt->cr4val), "=q" (tmp) : : "memory"); + + /* disable and flush caches. Note that wbinvd flushes the TLBs as + a side-effect. */ + asm volatile ("movl %%cr0, %0\n\t" + "orl $0x40000000, %0\n\t" + "wbinvd\n\t" + "movl %0, %%cr0\n\t" + "wbinvd\n\t" + : "=r" (tmp) : : "memory"); + + /* disable MTRRs, and set the default type to uncached. */ + rdmsr(MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi); + wrmsr(MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi); +} /* End Function set_mtrr_prepare */ + + +/* Restore the processor after a set_mtrr_prepare */ +static void set_mtrr_done(struct set_mtrr_context *ctxt) +{ + unsigned long tmp; + + /* flush caches and TLBs */ + asm volatile ("wbinvd" : : : "memory" ); + + /* restore MTRRdefType */ + wrmsr(MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi); + + /* enable caches */ + asm volatile ("movl %%cr0, %0\n\t" + "andl $0xbfffffff, %0\n\t" + "movl %0, %%cr0\n\t" + : "=r" (tmp) : : "memory"); + + /* restore value of CR4 */ + asm volatile ("movl %0, %%cr4" + : : "r" (ctxt->cr4val) : "memory"); + + /* re-enable interrupts locally (if enabled previously) */ + restore_flags (ctxt->flags); +} /* End Function set_mtrr_done */ + + +/* this function returns the number of variable MTRRs */ +static unsigned int get_num_var_ranges (void) +{ + unsigned long config, dummy; + + rdmsr(MTRRcap_MSR, config, dummy); + return (config & 0xff); +} /* End Function get_num_var_ranges */ + + +/* non-zero if we have the write-combining memory type. */ +static int have_wrcomb (void) +{ + unsigned long config, dummy; + + rdmsr(MTRRcap_MSR, config, dummy); + return (config & (1<<10)); +} + + +static void get_mtrr (unsigned int reg, unsigned long *base, + unsigned long *size, mtrr_type *type) +{ + unsigned long dummy, mask_lo, base_lo; + + rdmsr(MTRRphysMask_MSR(reg), mask_lo, dummy); + if ((mask_lo & 0x800) == 0) { + /* Invalid (i.e. free) range. */ + *base = 0; + *size = 0; + *type = 0; + return; + } + + rdmsr(MTRRphysBase_MSR(reg), base_lo, dummy); + + /* We ignore the extra address bits (32-35). If someone wants to + run x86 Linux on a machine with >4GB memory, this will be the + least of their problems. */ + + /* Clean up mask_lo so it gives the real address mask. */ + mask_lo = (mask_lo & 0xfffff000UL); + + /* This works correctly if size is a power of two, i.e. a + contiguous range. */ + *size = ~(mask_lo - 1); + + *base = (base_lo & 0xfffff000UL); + *type = (base_lo & 0xff); +} /* End Function get_mtrr */ + + +static void set_mtrr_up (unsigned int reg, unsigned long base, + unsigned long size, mtrr_type type, int do_safe) +/* [SUMMARY] Set variable MTRR register on the local CPU. + The register to set. + The base address of the region. + The size of the region. If this is 0 the region is disabled. + The type of the region. + If TRUE, do the change safely. If FALSE, safety measures should + be done externally. +*/ +{ + struct set_mtrr_context ctxt; + + if (do_safe) set_mtrr_prepare (&ctxt); + if (size == 0) + { + /* The invalid bit is kept in the mask, so we simply clear the + relevant mask register to disable a range. */ + wrmsr (MTRRphysMask_MSR (reg), 0, 0); + } + else + { + wrmsr (MTRRphysBase_MSR (reg), base | type, 0); + wrmsr (MTRRphysMask_MSR (reg), ~(size - 1) | 0x800, 0); + } + if (do_safe) set_mtrr_done (&ctxt); +} /* End Function set_mtrr_up */ + + +#ifdef __SMP__ + +struct mtrr_var_range +{ + unsigned long base_lo; + unsigned long base_hi; + unsigned long mask_lo; + unsigned long mask_hi; +}; + + +/* Get the MSR pair relating to a var range. */ +static void get_mtrr_var_range (unsigned int index, + struct mtrr_var_range *vr) +{ + rdmsr (MTRRphysBase_MSR (index), vr->base_lo, vr->base_hi); + rdmsr (MTRRphysMask_MSR (index), vr->mask_lo, vr->mask_hi); +} /* End Function get_mtrr_var_range */ + + +/* Set the MSR pair relating to a var range. Returns TRUE if + changes are made. */ +static int set_mtrr_var_range_testing (unsigned int index, + struct mtrr_var_range *vr) +{ + unsigned int lo, hi; + int changed = FALSE; + + rdmsr(MTRRphysBase_MSR(index), lo, hi); + + if ((vr->base_lo & 0xfffff0ffUL) != (lo & 0xfffff0ffUL) + || (vr->base_hi & 0xfUL) != (hi & 0xfUL)) { + wrmsr(MTRRphysBase_MSR(index), vr->base_lo, vr->base_hi); + changed = TRUE; + } + + rdmsr(MTRRphysMask_MSR(index), lo, hi); + + if ((vr->mask_lo & 0xfffff800UL) != (lo & 0xfffff800UL) + || (vr->mask_hi & 0xfUL) != (hi & 0xfUL)) { + wrmsr(MTRRphysMask_MSR(index), vr->mask_lo, vr->mask_hi); + changed = TRUE; + } + + return changed; +} + + +static void get_fixed_ranges(mtrr_type *frs) +{ + unsigned long *p = (unsigned long *)frs; + int i; + + rdmsr(MTRRfix64K_00000_MSR, p[0], p[1]); + + for (i = 0; i < 2; i++) + rdmsr(MTRRfix16K_80000_MSR + i, p[2 + i*2], p[3 + i*2]); + + for (i = 0; i < 8; i++) + rdmsr(MTRRfix4K_C0000_MSR + i, p[6 + i*2], p[7 + i*2]); +} + + +static int set_fixed_ranges_testing(mtrr_type *frs) +{ + unsigned long *p = (unsigned long *)frs; + int changed = FALSE; + int i; + unsigned long lo, hi; + + rdmsr(MTRRfix64K_00000_MSR, lo, hi); + if (p[0] != lo || p[1] != hi) { + wrmsr(MTRRfix64K_00000_MSR, p[0], p[1]); + changed = TRUE; + } + + for (i = 0; i < 2; i++) { + rdmsr(MTRRfix16K_80000_MSR + i, lo, hi); + if (p[2 + i*2] != lo || p[3 + i*2] != hi) { + wrmsr(MTRRfix16K_80000_MSR + i, p[2 + i*2], p[3 + i*2]); + changed = TRUE; + } + } + + for (i = 0; i < 8; i++) { + rdmsr(MTRRfix4K_C0000_MSR + i, lo, hi); + if (p[6 + i*2] != lo || p[7 + i*2] != hi) { + wrmsr(MTRRfix4K_C0000_MSR + i, p[6 + i*2], p[7 + i*2]); + changed = TRUE; + } + } + + return changed; +} + + +struct mtrr_state +{ + unsigned int num_var_ranges; + struct mtrr_var_range *var_ranges; + mtrr_type fixed_ranges[NUM_FIXED_RANGES]; + unsigned char enabled; + mtrr_type def_type; +}; + + +/* Grab all of the MTRR state for this CPU into *state. */ +static void get_mtrr_state(struct mtrr_state *state) +{ + unsigned int nvrs, i; + struct mtrr_var_range *vrs; + unsigned long lo, dummy; + + nvrs = state->num_var_ranges = get_num_var_ranges(); + vrs = state->var_ranges + = kmalloc(nvrs * sizeof(struct mtrr_var_range), GFP_KERNEL); + if (vrs == NULL) + nvrs = state->num_var_ranges = 0; + + for (i = 0; i < nvrs; i++) + get_mtrr_var_range(i, &vrs[i]); + + get_fixed_ranges(state->fixed_ranges); + + rdmsr(MTRRdefType_MSR, lo, dummy); + state->def_type = (lo & 0xff); + state->enabled = (lo & 0xc00) >> 10; +} /* End Function get_mtrr_state */ + + +/* Free resources associated with a struct mtrr_state */ +static void finalize_mtrr_state(struct mtrr_state *state) +{ + if (state->var_ranges) kfree (state->var_ranges); +} /* End Function finalize_mtrr_state */ + + +static unsigned long set_mtrr_state (struct mtrr_state *state, + struct set_mtrr_context *ctxt) +/* [SUMMARY] Set the MTRR state for this CPU. + The MTRR state information to read. + Some relevant CPU context. + [NOTE] The CPU must already be in a safe state for MTRR changes. + [RETURNS] 0 if no changes made, else a mask indication what was changed. +*/ +{ + unsigned int i; + unsigned long change_mask = 0; + + for (i = 0; i < state->num_var_ranges; i++) + if (set_mtrr_var_range_testing(i, &state->var_ranges[i])) + change_mask |= MTRR_CHANGE_MASK_VARIABLE; + + if (set_fixed_ranges_testing(state->fixed_ranges)) + change_mask |= MTRR_CHANGE_MASK_FIXED; + + /* set_mtrr_restore restores the old value of MTRRdefType, + so to set it we fiddle with the saved value. */ + if ((ctxt->deftype_lo & 0xff) != state->def_type + || ((ctxt->deftype_lo & 0xc00) >> 10) != state->enabled) + { + ctxt->deftype_lo |= (state->def_type | state->enabled << 10); + change_mask |= MTRR_CHANGE_MASK_DEFTYPE; + } + + return change_mask; +} /* End Function set_mtrr_state */ + + +static atomic_t undone_count; +static void (*handler_func) (struct set_mtrr_context *ctxt, void *info); +static void *handler_info; +static volatile int wait_barrier_execute = FALSE; +static volatile int wait_barrier_cache_enable = FALSE; + +static void sync_handler (void) +/* [SUMMARY] Synchronisation handler. Executed by "other" CPUs. + [RETURNS] Nothing. +*/ +{ + struct set_mtrr_context ctxt; + + set_mtrr_prepare (&ctxt); + /* Notify master CPU that I'm at the barrier and then wait */ + atomic_dec (&undone_count); + while (wait_barrier_execute) barrier (); + /* The master has cleared me to execute */ + (*handler_func) (&ctxt, handler_info); + /* Notify master CPU that I've executed the function */ + atomic_dec (&undone_count); + /* Wait for master to clear me to enable cache and return */ + while (wait_barrier_cache_enable) barrier (); + set_mtrr_done (&ctxt); +} /* End Function sync_handler */ + +static void do_all_cpus (void (*handler) (struct set_mtrr_context *ctxt, + void *info), + void *info, int local) +/* [SUMMARY] Execute a function on all CPUs, with caches flushed and disabled. + [PURPOSE] This function will synchronise all CPUs, flush and disable caches + on all CPUs, then call a specified function. When the specified function + finishes on all CPUs, caches are enabled on all CPUs. + The function to execute. + An arbitrary information pointer which is passed to <>. + If TRUE <> is executed locally. + [RETURNS] Nothing. +*/ +{ + unsigned long timeout; + struct set_mtrr_context ctxt; + + mtrr_hook = sync_handler; + handler_func = handler; + handler_info = info; + wait_barrier_execute = TRUE; + wait_barrier_cache_enable = TRUE; + /* Send a message to all other CPUs and wait for them to enter the + barrier */ + atomic_set (&undone_count, smp_num_cpus - 1); + smp_message_pass (MSG_ALL_BUT_SELF, MSG_MTRR_CHANGE, 0, 0); + /* Wait for it to be done */ + timeout = jiffies + JIFFIE_TIMEOUT; + while ( (atomic_read (&undone_count) > 0) && (jiffies < timeout) ) + barrier (); + if (atomic_read (&undone_count) > 0) + { + panic ("mtrr: timed out waiting for other CPUs\n"); + } + mtrr_hook = NULL; + /* All other CPUs should be waiting for the barrier, with their caches + already flushed and disabled. Prepare for function completion + notification */ + atomic_set (&undone_count, smp_num_cpus - 1); + /* Flush and disable the local CPU's cache and release the barier, which + should cause the other CPUs to execute the function. Also execute it + locally if required */ + set_mtrr_prepare (&ctxt); + wait_barrier_execute = FALSE; + if (local) (*handler) (&ctxt, info); + /* Now wait for other CPUs to complete the function */ + while (atomic_read (&undone_count) > 0) barrier (); + /* Now all CPUs should have finished the function. Release the barrier to + allow them to re-enable their caches and return from their interrupt, + then enable the local cache and return */ + wait_barrier_cache_enable = FALSE; + set_mtrr_done (&ctxt); + handler_func = NULL; + handler_info = NULL; +} /* End Function do_all_cpus */ + + +struct set_mtrr_data +{ + unsigned long smp_base; + unsigned long smp_size; + unsigned int smp_reg; + mtrr_type smp_type; +}; + +static void set_mtrr_handler (struct set_mtrr_context *ctxt, void *info) +{ + struct set_mtrr_data *data = info; + + set_mtrr_up (data->smp_reg, data->smp_base, data->smp_size, data->smp_type, + FALSE); +} /* End Function set_mtrr_handler */ + + + +/* A warning that is common to the module and non-module cases. */ +/* Some BIOS's are fucked and don't set all MTRRs the same! */ +#ifdef MODULE +static void mtrr_state_warn (unsigned long mask) +#else +static void mtrr_state_warn (unsigned long mask) +#endif +{ + if (!mask) return; + if (mask & MTRR_CHANGE_MASK_FIXED) + printk ("mtrr: your CPUs had inconsistent fixed MTRR settings\n"); + if (mask & MTRR_CHANGE_MASK_VARIABLE) + printk ("mtrr: your CPUs had inconsistent variable MTRR settings\n"); + if (mask & MTRR_CHANGE_MASK_DEFTYPE) + printk ("mtrr: your CPUs had inconsistent MTRRdefType settings\n"); + printk ("mtrr: probably your BIOS does not setup all CPUs\n"); +} /* End Function mtrr_state_warn */ + +#ifdef MODULE +/* As a module, copy the MTRR state using an IPI handler. */ + +static volatile unsigned long smp_changes_mask = 0; + +static void copy_mtrr_state_handler (struct set_mtrr_context *ctxt, void *info) +{ + unsigned long mask, count; + struct mtrr_state *smp_mtrr_state = info; + + mask = set_mtrr_state (smp_mtrr_state, ctxt); + /* Use the atomic bitops to update the global mask */ + for (count = 0; count < sizeof mask * 8; ++count) + { + if (mask & 0x01) set_bit (count, &smp_changes_mask); + mask >>= 1; + } +} /* End Function copy_mtrr_state_handler */ + +/* Copies the entire MTRR state of this CPU to all the others. */ +static void copy_mtrr_state (void) +{ + struct mtrr_state ms; + + get_mtrr_state (&ms); + do_all_cpus (copy_mtrr_state_handler, &ms, FALSE); + finalize_mtrr_state (&ms); + mtrr_state_warn (smp_changes_mask); +} /* End Function copy_mtrr_state */ + +#endif /* MODULE */ +#endif /* __SMP__ */ + +static char *attrib_to_str (int x) +{ + return (x <= 6) ? mtrr_strings[x] : "?"; +} /* End Function attrib_to_str */ + +static void init_table (void) +{ + int i, max; + + max = get_num_var_ranges (); + if ( ( usage_table = kmalloc (max * sizeof *usage_table, GFP_KERNEL) ) + == NULL ) + { + printk ("mtrr: could not allocate\n"); + return; + } + for (i = 0; i < max; i++) usage_table[i] = 1; + +} /* End Function init_table */ + +int mtrr_add (unsigned long base, unsigned long size, unsigned int type, + char increment) +/* [SUMMARY] Add an MTRR entry. + The starting (base) address of the region. + The size (in bytes) of the region. + The type of the new region. + If true and the region already exists, the usage count will be + incremented. + [RETURNS] The MTRR register on success, else a negative number indicating + the error code. + [NOTE] This routine uses a spinlock. +*/ +{ + int i, max; + mtrr_type ltype; + unsigned long lbase, lsize, last; + + if (!usage_table) init_table(); + if ( (base & 0xfff) || (size & 0xfff) ) + { + printk ("mtrr: size and base must be multiples of 4kB\n"); + printk ("mtrr: size: %lx base: %lx\n", size, base); + return -EINVAL; + } + if (base + size < 0x100000) + { + printk ("mtrr: cannot set region below 1 MByte (0x%lx,0x%lx)\n", + base, size); + return -EINVAL; + } + /* Check upper bits of base and last are equal and lower bits are 0 for + base and 1 for last */ + last = base + size - 1; + for (lbase = base; !(lbase & 1) && (last & 1); + lbase = lbase >> 1, last = last >> 1); + if (lbase != last) + { + printk ("mtrr: base(0x%lx) is not aligned on a size(0x%lx) boundary\n", + base, size); + return -EINVAL; + } + if (type >= MTRR_NUM_TYPES) + { + printk ("mtrr: type: %u illegal\n", type); + return -EINVAL; + } + /* If the type is WC, check that this processor supports it */ + if ( (type == MTRR_TYPE_WRCOMB) && !have_wrcomb () ) + { + printk ("mtrr: your processor doesn't support write-combining\n"); + return -ENOSYS; + } + increment = increment ? 1 : 0; + max = get_num_var_ranges (); + /* Search for existing MTRR */ + + for (i = 0; i < max; ++i) + { + get_mtrr (i, &lbase, &lsize, <ype); + if (base >= lbase + lsize) continue; + if ( (base < lbase) && (base + size <= lbase) ) continue; + /* At this point we know there is some kind of overlap/enclosure */ + if ( (base < lbase) || (base + size > lbase + lsize) ) + { + printk ("mtrr: 0x%lx,0x%lx overlaps existing 0x%lx,0x%lx\n", + base, size, lbase, lsize); + return -EINVAL; + } + /* New region is enclosed by an existing region */ + if (ltype != type) + { + if (type == MTRR_TYPE_UNCACHABLE) continue; + printk ( "mtrr: type mismatch for %lx,%lx old: %s new: %s\n", + base, size, attrib_to_str (ltype), attrib_to_str (type) ); + return -EINVAL; + } + if (increment) ++usage_table[i]; + return i; + } + /* Search for an empty MTRR */ + for (i = 0; i < max; ++i) + { + get_mtrr (i, &lbase, &lsize, <ype); + if (lsize > 0) continue; + set_mtrr (i, base, size, type); + usage_table[i] = 1; + return i; + } + printk ("mtrr: no more MTRRs available\n"); + return -ENOSPC; +} /* End Function mtrr_add */ + +int mtrr_del (int reg, unsigned long base, unsigned long size) +/* [SUMMARY] Delete MTRR/decrement usage count. + The register. If this is less than 0 then <> and <> must + be supplied. + The base address of the region. This is ignored if <> is >= 0. + The size of the region. This is ignored if <> is >= 0. + [RETURNS] The register on success, else a negative number indicating + the error code. + [NOTE] This routine uses a spinlock. +*/ +{ + int i, max; + mtrr_type ltype; + unsigned long lbase, lsize; + + if (!usage_table) init_table(); + max = get_num_var_ranges (); + if (reg < 0) + { + /* Search for existing MTRR */ + for (i = 0; i < max; ++i) + { + get_mtrr (i, &lbase, &lsize, <ype); + if ( (lbase == base) && (lsize == size) ) + { + reg = i; + break; + } + } + if (reg < 0) + { + printk ("mtrr: no MTRR for %lx,%lx found\n", base, size); + return -EINVAL; + } + } + if (reg >= max) + { + printk ("mtrr: register: %d too big\n", reg); + return -EINVAL; + } + get_mtrr (reg, &lbase, &lsize, <ype); + if (lsize < 1) + { + printk ("mtrr: MTRR %d not used\n", reg); + return -EINVAL; + } + if (usage_table[reg] < 1) + { + printk ("mtrr: reg: %d has count=0\n", reg); + return -EINVAL; + } + if (--usage_table[reg] < 1) set_mtrr (reg, 0, 0, 0); + return reg; +} /* End Function mtrr_del */ + +#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2, 1, 0) */ diff --git a/glide/Glide_SDK-2.2-16.i386.rpm.html b/glide/Glide_SDK-2.2-16.i386.rpm.html new file mode 100644 index 0000000..61513e1 Binary files /dev/null and b/glide/Glide_SDK-2.2-16.i386.rpm.html differ diff --git a/glide/Glide_V3-2.60-16.i386.rpm.html b/glide/Glide_V3-2.60-16.i386.rpm.html new file mode 100644 index 0000000..58408f1 Binary files /dev/null and b/glide/Glide_V3-2.60-16.i386.rpm.html differ diff --git a/glide/XFree86_3DFX-SVGA-3.3.3-5.i386.rpm.html b/glide/XFree86_3DFX-SVGA-3.3.3-5.i386.rpm.html new file mode 100644 index 0000000..496bacd Binary files /dev/null and b/glide/XFree86_3DFX-SVGA-3.3.3-5.i386.rpm.html differ