From: Andy P. <at...@us...> - 2002-04-09 17:08:09
|
Update of /cvsroot/linux-vax/kernel-2.4/drivers/pci In directory usw-pr-cvs1:/tmp/cvs-serv6177/pci Modified Files: Makefile compat.c gen-devlist.c names.c pci.c pci.ids proc.c quirks.c setup-bus.c setup-irq.c setup-res.c Log Message: synch 2.4.15 commit 27 Index: Makefile =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/drivers/pci/Makefile,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- Makefile 14 Jan 2001 18:35:34 -0000 1.1.1.1 +++ Makefile 9 Apr 2002 16:45:52 -0000 1.2 @@ -13,14 +13,23 @@ export-objs := pci.o -obj-$(CONFIG_PCI) += pci.o quirks.o compat.o names.o setup-res.o +obj-$(CONFIG_PCI) += pci.o quirks.o compat.o names.o obj-$(CONFIG_PROC_FS) += proc.o +ifndef CONFIG_SPARC64 +obj-$(CONFIG_PCI) += setup-res.o +endif + # # Some architectures use the generic PCI setup functions # obj-$(CONFIG_ALPHA) += setup-bus.o setup-irq.o obj-$(CONFIG_ARM) += setup-bus.o setup-irq.o +obj-$(CONFIG_PARISC) += setup-bus.o +obj-$(CONFIG_SUPERH) += setup-bus.o setup-irq.o +obj-$(CONFIG_ALL_PPC) += setup-bus.o +obj-$(CONFIG_DDB5476) += setup-bus.o +obj-$(CONFIG_SGI_IP27) += setup-irq.o ifndef CONFIG_X86 obj-y += syscall.o Index: compat.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/drivers/pci/compat.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- compat.c 14 Jan 2001 18:35:38 -0000 1.1.1.1 +++ compat.c 9 Apr 2002 16:45:52 -0000 1.2 @@ -3,7 +3,7 @@ * * PCI Bus Services -- Function For Backward Compatibility * - * Copyright 1998--2000 Martin Mares <mj...@su...> + * Copyright 1998--2000 Martin Mares <mj...@uc...> */ #include <linux/types.h> Index: gen-devlist.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/drivers/pci/gen-devlist.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- gen-devlist.c 14 Jan 2001 18:36:02 -0000 1.1.1.1 +++ gen-devlist.c 9 Apr 2002 16:45:52 -0000 1.2 @@ -1,7 +1,7 @@ /* * Generate devlist.h and classlist.h from the PCI ID file. * - * (c) 1999--2000 Martin Mares <mj...@su...> + * (c) 1999--2000 Martin Mares <mj...@uc...> */ #include <stdio.h> @@ -68,6 +68,7 @@ bra[-1] = 0; if (vendor_len + strlen(c) + 1 > MAX_NAME_SIZE) { fprintf(stderr, "Line %d: Device name too long\n", lino); + fprintf(stderr, "%s\n", c); return 1; } } Index: names.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/drivers/pci/names.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- names.c 14 Jan 2001 18:35:42 -0000 1.1.1.1 +++ names.c 9 Apr 2002 16:45:52 -0000 1.2 @@ -32,9 +32,9 @@ * real memory.. Parse the same file multiple times * to get all the info. */ -#define VENDOR( vendor, name ) static const char __vendorstr_##vendor[] __initdata = name; +#define VENDOR( vendor, name ) static char __vendorstr_##vendor[] __initdata = name; #define ENDVENDOR() -#define DEVICE( vendor, device, name ) static const char __devicestr_##vendor##device[] __initdata = name; +#define DEVICE( vendor, device, name ) static char __devicestr_##vendor##device[] __initdata = name; #include "devlist.h" @@ -43,7 +43,7 @@ #define DEVICE( vendor, device, name ) { 0x##device, 0, __devicestr_##vendor##device }, #include "devlist.h" -static const struct pci_vendor_info __initdata pci_vendor_list[] = { +static struct pci_vendor_info __initdata pci_vendor_list[] = { #define VENDOR( vendor, name ) { 0x##vendor, sizeof(__devices_##vendor) / sizeof(struct pci_device_info), __vendorstr_##vendor, __devices_##vendor }, #define ENDVENDOR() #define DEVICE( vendor, device, name ) @@ -52,7 +52,7 @@ #define VENDORS (sizeof(pci_vendor_list)/sizeof(struct pci_vendor_info)) -void __init pci_name_device(struct pci_dev *dev) +void __devinit pci_name_device(struct pci_dev *dev) { const struct pci_vendor_info *vendor_p = pci_vendor_list; int i = VENDORS; Index: pci.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/drivers/pci/pci.c,v retrieving revision 1.1.1.2 retrieving revision 1.2 diff -u -r1.1.1.2 -r1.2 --- pci.c 25 Feb 2001 23:15:09 -0000 1.1.1.2 +++ pci.c 9 Apr 2002 16:45:52 -0000 1.2 @@ -6,7 +6,7 @@ * Copyright 1993 -- 1997 Drew Eckhardt, Frederic Potter, * David Mosberger-Tang * - * Copyright 1997 -- 2000 Martin Mares <mj...@su...> + * Copyright 1997 -- 2000 Martin Mares <mj...@uc...> */ #include <linux/config.h> @@ -21,6 +21,8 @@ #include <linux/spinlock.h> #include <linux/pm.h> [...1360 lines suppressed...] +EXPORT_SYMBOL(pci_set_power_state); +EXPORT_SYMBOL(pci_save_state); +EXPORT_SYMBOL(pci_restore_state); +EXPORT_SYMBOL(pci_enable_wake); + /* Obsolete functions */ EXPORT_SYMBOL(pcibios_present); @@ -1236,4 +2023,11 @@ EXPORT_SYMBOL(isa_dma_bridge_buggy); EXPORT_SYMBOL(pci_pci_problems); + +/* Pool allocator */ + +EXPORT_SYMBOL (pci_pool_create); +EXPORT_SYMBOL (pci_pool_destroy); +EXPORT_SYMBOL (pci_pool_alloc); +EXPORT_SYMBOL (pci_pool_free); Index: pci.ids =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/drivers/pci/pci.ids,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- pci.ids 14 Jan 2001 18:36:00 -0000 1.1.1.1 +++ pci.ids 9 Apr 2002 16:45:52 -0000 1.2 @@ -1,8 +1,11 @@ # # List of PCI ID's # -# Maintained by Martin Mares <pc...@uc...> -# If you have any new entries, send them to the maintainer. +# Maintained by Martin Mares <mj...@uc...> and other volunteers from the +# Linux PCI ID's Project at http://pciids.sf.net/. New data are always +# welcome (if they are accurate), we're eagerly expecting new entries, +# so if you have anything to contribute, please visit the home page or +# send a diff -u against the most recent pci.ids to pc...@uc.... # [...1675 lines suppressed...] 7810 AIC-7810 @@ -4783,6 +5235,7 @@ 00c0 7899A 00c1 7899B 00c3 7899D + 00c5 RAID subsystem HBA 00cf 7899P 907f Atronics 2015 IDE-2015PL @@ -4965,8 +5418,8 @@ 00 UHCI 10 OHCI 80 Unspecified - Fe USB Device - 04 Fiber Channel + fe USB Device + 04 Fibre Channel 05 SMBus 06 InfiniBand C 0d Wireless controller Index: proc.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/drivers/pci/proc.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- proc.c 14 Jan 2001 18:35:40 -0000 1.1.1.1 +++ proc.c 9 Apr 2002 16:45:52 -0000 1.2 @@ -3,7 +3,7 @@ * * Procfs interface for the PCI bus. * - * Copyright (c) 1997--1999 Martin Mares <mj...@su...> + * Copyright (c) 1997--1999 Martin Mares <mj...@uc...> */ #include <linux/types.h> @@ -11,6 +11,7 @@ #include <linux/pci.h> #include <linux/proc_fs.h> #include <linux/init.h> +#include <linux/seq_file.h> #include <asm/uaccess.h> #include <asm/byteorder.h> @@ -191,10 +192,109 @@ return nbytes; } +struct pci_filp_private { + enum pci_mmap_state mmap_state; + int write_combine; +}; + +static int proc_bus_pci_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + const struct proc_dir_entry *dp = inode->u.generic_ip; + struct pci_dev *dev = dp->data; +#ifdef HAVE_PCI_MMAP + struct pci_filp_private *fpriv = file->private_data; +#endif /* HAVE_PCI_MMAP */ + int ret = 0; + + switch (cmd) { + case PCIIOC_CONTROLLER: + ret = pci_controller_num(dev); + break; + +#ifdef HAVE_PCI_MMAP + case PCIIOC_MMAP_IS_IO: + fpriv->mmap_state = pci_mmap_io; + break; + + case PCIIOC_MMAP_IS_MEM: + fpriv->mmap_state = pci_mmap_mem; + break; + + case PCIIOC_WRITE_COMBINE: + if (arg) + fpriv->write_combine = 1; + else + fpriv->write_combine = 0; + break; + +#endif /* HAVE_PCI_MMAP */ + + default: + ret = -EINVAL; + break; + }; + + return ret; +} + +#ifdef HAVE_PCI_MMAP +static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct inode *inode = file->f_dentry->d_inode; + const struct proc_dir_entry *dp = inode->u.generic_ip; + struct pci_dev *dev = dp->data; + struct pci_filp_private *fpriv = file->private_data; + int ret; + + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + + ret = pci_mmap_page_range(dev, vma, + fpriv->mmap_state, + fpriv->write_combine); + if (ret < 0) + return ret; + + return 0; +} + +static int proc_bus_pci_open(struct inode *inode, struct file *file) +{ + struct pci_filp_private *fpriv = kmalloc(sizeof(*fpriv), GFP_KERNEL); + + if (!fpriv) + return -ENOMEM; + + fpriv->mmap_state = pci_mmap_io; + fpriv->write_combine = 0; + + file->private_data = fpriv; + + return 0; +} + +static int proc_bus_pci_release(struct inode *inode, struct file *file) +{ + kfree(file->private_data); + file->private_data = NULL; + + return 0; +} +#endif /* HAVE_PCI_MMAP */ + static struct file_operations proc_bus_pci_operations = { - llseek: proc_bus_pci_lseek, - read: proc_bus_pci_read, - write: proc_bus_pci_write, + llseek: proc_bus_pci_lseek, + read: proc_bus_pci_read, + write: proc_bus_pci_write, + ioctl: proc_bus_pci_ioctl, +#ifdef HAVE_PCI_MMAP + open: proc_bus_pci_open, + release: proc_bus_pci_release, + mmap: proc_bus_pci_mmap, +#ifdef HAVE_ARCH_PCI_GET_UNMAPPED_AREA + get_unmapped_area: get_pci_unmapped_area, +#endif /* HAVE_ARCH_PCI_GET_UNMAPPED_AREA */ +#endif /* HAVE_PCI_MMAP */ }; #if BITS_PER_LONG == 32 @@ -203,53 +303,72 @@ #define LONG_FORMAT "\t%16lx" #endif -static int -get_pci_dev_info(char *buf, char **start, off_t pos, int count) +/* iterator */ +static void *pci_seq_start(struct seq_file *m, loff_t *pos) +{ + struct list_head *p = &pci_devices; + loff_t n = *pos; + + /* XXX: surely we need some locking for traversing the list? */ + while (n--) { + p = p->next; + if (p == &pci_devices) + return NULL; + } + return p; +} +static void *pci_seq_next(struct seq_file *m, void *v, loff_t *pos) +{ + struct list_head *p = v; + (*pos)++; + return p->next != &pci_devices ? p->next : NULL; +} +static void pci_seq_stop(struct seq_file *m, void *v) { + /* release whatever locks we need */ +} + +static int show_device(struct seq_file *m, void *v) +{ + struct list_head *p = v; const struct pci_dev *dev; - off_t at = 0; - int len, i, cnt; + const struct pci_driver *drv; + int i; - cnt = 0; - pci_for_each_dev(dev) { - const struct pci_driver *drv = pci_dev_driver(dev); - len = sprintf(buf, "%02x%02x\t%04x%04x\t%x", + if (p == &pci_devices) + return 0; + + dev = pci_dev_g(p); + drv = pci_dev_driver(dev); + seq_printf(m, "%02x%02x\t%04x%04x\t%x", dev->bus->number, dev->devfn, dev->vendor, dev->device, dev->irq); - /* Here should be 7 and not PCI_NUM_RESOURCES as we need to preserve compatibility */ - for(i=0; i<7; i++) - len += sprintf(buf+len, LONG_FORMAT, - dev->resource[i].start | (dev->resource[i].flags & PCI_REGION_FLAG_MASK)); - for(i=0; i<7; i++) - len += sprintf(buf+len, LONG_FORMAT, dev->resource[i].start < dev->resource[i].end ? - dev->resource[i].end - dev->resource[i].start + 1 : 0); - buf[len++] = '\t'; - if (drv) - len += sprintf(buf+len, "%s", drv->name); - buf[len++] = '\n'; - at += len; - if (at >= pos) { - if (!*start) { - *start = buf + (pos - (at - len)); - cnt = at - pos; - } else - cnt += len; - buf += len; - if (cnt >= count) - /* - * proc_file_read() gives us 1KB of slack so it's OK if the - * above printfs write a little beyond the buffer end (we - * never write more than 1KB beyond the buffer end). - */ - break; - } - } - return (count > cnt) ? cnt : count; + /* Here should be 7 and not PCI_NUM_RESOURCES as we need to preserve compatibility */ + for(i=0; i<7; i++) + seq_printf(m, LONG_FORMAT, + dev->resource[i].start | + (dev->resource[i].flags & PCI_REGION_FLAG_MASK)); + for(i=0; i<7; i++) + seq_printf(m, LONG_FORMAT, + dev->resource[i].start < dev->resource[i].end ? + dev->resource[i].end - dev->resource[i].start + 1 : 0); + seq_putc(m, '\t'); + if (drv) + seq_printf(m, "%s", drv->name); + seq_putc(m, '\n'); + return 0; } +static struct seq_operations proc_bus_pci_devices_op = { + start: pci_seq_start, + next: pci_seq_next, + stop: pci_seq_stop, + show: show_device +}; + static struct proc_dir_entry *proc_bus_pci_dir; int pci_proc_attach_device(struct pci_dev *dev) @@ -287,6 +406,28 @@ return 0; } +int pci_proc_attach_bus(struct pci_bus* bus) +{ + struct proc_dir_entry *de = bus->procdir; + + if (!de) { + char name[16]; + sprintf(name, "%02x", bus->number); + de = bus->procdir = proc_mkdir(name, proc_bus_pci_dir); + if (!de) + return -ENOMEM; + } + return 0; +} + +int pci_proc_detach_bus(struct pci_bus* bus) +{ + struct proc_dir_entry *de = bus->procdir; + if (de) + remove_proc_entry(de->name, proc_bus_pci_dir); + return 0; +} + /* * Backward compatible /proc/pci interface. @@ -298,54 +439,56 @@ * The configuration string is stored starting at buf[len]. If the * string would exceed the size of the buffer (SIZE), 0 is returned. */ -static int sprint_dev_config(struct pci_dev *dev, char *buf, int size) +static int show_dev_config(struct seq_file *m, void *v) { + struct list_head *p = v; + struct pci_dev *dev; + struct pci_driver *drv; u32 class_rev; unsigned char latency, min_gnt, max_lat, *class; - int reg, len = 0; + int reg; + + if (p == &pci_devices) { + seq_puts(m, "PCI devices found:\n"); + return 0; + } + + dev = pci_dev_g(p); + drv = pci_dev_driver(dev); pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); pci_read_config_byte (dev, PCI_LATENCY_TIMER, &latency); pci_read_config_byte (dev, PCI_MIN_GNT, &min_gnt); pci_read_config_byte (dev, PCI_MAX_LAT, &max_lat); - if (len + 160 > size) - return -1; - len += sprintf(buf + len, " Bus %2d, device %3d, function %2d:\n", - dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + seq_printf(m, " Bus %2d, device %3d, function %2d:\n", + dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); class = pci_class_name(class_rev >> 16); if (class) - len += sprintf(buf+len, " %s", class); + seq_printf(m, " %s", class); else - len += sprintf(buf+len, " Class %04x", class_rev >> 16); - len += sprintf(buf+len, ": %s (rev %d).\n", dev->name, class_rev & 0xff); + seq_printf(m, " Class %04x", class_rev >> 16); + seq_printf(m, ": %s (rev %d).\n", dev->name, class_rev & 0xff); - if (dev->irq) { - if (len + 40 > size) - return -1; - len += sprintf(buf + len, " IRQ %d.\n", dev->irq); - } + if (dev->irq) + seq_printf(m, " IRQ %d.\n", dev->irq); if (latency || min_gnt || max_lat) { - if (len + 80 > size) - return -1; - len += sprintf(buf + len, " Master Capable. "); + seq_printf(m, " Master Capable. "); if (latency) - len += sprintf(buf + len, "Latency=%d. ", latency); + seq_printf(m, "Latency=%d. ", latency); else - len += sprintf(buf + len, "No bursts. "); + seq_puts(m, "No bursts. "); if (min_gnt) - len += sprintf(buf + len, "Min Gnt=%d.", min_gnt); + seq_printf(m, "Min Gnt=%d.", min_gnt); if (max_lat) - len += sprintf(buf + len, "Max Lat=%d.", max_lat); - len += sprintf(buf + len, "\n"); + seq_printf(m, "Max Lat=%d.", max_lat); + seq_putc(m, '\n'); } for (reg = 0; reg < 6; reg++) { struct resource *res = dev->resource + reg; unsigned long base, end, flags; - if (len + 40 > size) - return -1; base = res->start; end = res->end; flags = res->flags; @@ -353,9 +496,8 @@ continue; if (flags & PCI_BASE_ADDRESS_SPACE_IO) { - len += sprintf(buf + len, - " I/O at 0x%lx [0x%lx].\n", - base, end); + seq_printf(m, " I/O at 0x%lx [0x%lx].\n", + base, end); } else { const char *pref, *type = "unknown"; @@ -371,65 +513,58 @@ case PCI_BASE_ADDRESS_MEM_TYPE_64: type = "64 bit"; break; } - len += sprintf(buf + len, - " %srefetchable %s memory at " + seq_printf(m, " %srefetchable %s memory at " "0x%lx [0x%lx].\n", pref, type, base, end); } } - - return len; + return 0; } -/* - * Return list of PCI devices as a character string for /proc/pci. - * BUF is a buffer that is PAGE_SIZE bytes long. - */ -static int pci_read_proc(char *buf, char **start, off_t off, - int count, int *eof, void *data) -{ - int nprinted, len, begin = 0; - struct pci_dev *dev; - - len = sprintf(buf, "PCI devices found:\n"); +static struct seq_operations proc_pci_op = { + start: pci_seq_start, + next: pci_seq_next, + stop: pci_seq_stop, + show: show_dev_config +}; - *eof = 1; - pci_for_each_dev(dev) { - nprinted = sprint_dev_config(dev, buf + len, PAGE_SIZE - len); - if (nprinted < 0) { - *eof = 0; - break; - } - len += nprinted; - if (len+begin < off) { - begin += len; - len = 0; - } - if (len+begin >= off+count) - break; - } - off -= begin; - *start = buf + off; - len -= off; - if (len>count) - len = count; - if (len<0) - len = 0; - return len; +static int proc_bus_pci_dev_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &proc_bus_pci_devices_op); } +static struct file_operations proc_bus_pci_dev_operations = { + open: proc_bus_pci_dev_open, + read: seq_read, + llseek: seq_lseek, + release: seq_release, +}; +static int proc_pci_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &proc_pci_op); +} +static struct file_operations proc_pci_operations = { + open: proc_pci_open, + read: seq_read, + llseek: seq_lseek, + release: seq_release, +}; static int __init pci_proc_init(void) { if (pci_present()) { + struct proc_dir_entry *entry; struct pci_dev *dev; proc_bus_pci_dir = proc_mkdir("pci", proc_bus); - create_proc_info_entry("devices", 0, proc_bus_pci_dir, - get_pci_dev_info); + entry = create_proc_entry("devices", 0, proc_bus_pci_dir); + if (entry) + entry->proc_fops = &proc_bus_pci_dev_operations; pci_for_each_dev(dev) { pci_proc_attach_device(dev); } - create_proc_read_entry("pci", 0, NULL, pci_read_proc, NULL); + entry = create_proc_entry("pci", 0, NULL); + if (entry) + entry->proc_fops = &proc_pci_operations; } return 0; } Index: quirks.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/drivers/pci/quirks.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- quirks.c 14 Jan 2001 18:35:41 -0000 1.1.1.1 +++ quirks.c 9 Apr 2002 16:45:52 -0000 1.2 @@ -5,17 +5,19 @@ * bugs. Devices present only on certain architectures (host * bridges et cetera) should be handled in arch-specific code. * - * Copyright (c) 1999 Martin Mares <mj...@su...> + * Copyright (c) 1999 Martin Mares <mj...@uc...> * * The bridge optimization stuff has been removed. If you really * have a silly BIOS which is unable to set your host bridge right, * use the PowerTweak utility (see http://powertweak.sourceforge.net). */ +#include <linux/config.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/pci.h> #include <linux/init.h> +#include <linux/delay.h> #undef DEBUG @@ -31,7 +33,7 @@ while ((d = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_0, d))) { pci_read_config_byte(d, 0x82, &dlc); if (!(dlc & 1<<1)) { - printk("PCI: PIIX3: Enabling Passive Release on %s\n", d->slot_name); + printk(KERN_ERR "PCI: PIIX3: Enabling Passive Release on %s\n", d->slot_name); dlc |= 1<<1; pci_write_config_byte(d, 0x82, dlc); } @@ -85,6 +87,66 @@ } /* + * VIA Apollo KT133 needs PCI latency patch + * Made according to a windows driver based patch by George E. Breese + * see PCI Latency Adjust on http://www.viahardware.com/download/viatweak.shtm + * Also see http://home.tiscalinet.de/au-ja/review-kt133a-1-en.html for + * the info on which Mr Breese based his work. + * + * Updated based on further information from the site and also on + * information provided by VIA + */ +static void __init quirk_vialatency(struct pci_dev *dev) +{ + struct pci_dev *p; + u8 rev; + u8 busarb; + /* Ok we have a potential problem chipset here. Now see if we have + a buggy southbridge */ + + p=pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, NULL); + if(p!=NULL) + { + pci_read_config_byte(p, PCI_CLASS_REVISION, &rev); + /* 0x40 - 0x4f == 686B, 0x10 - 0x2f == 686A; thanks Dan Hollis */ + /* Check for buggy part revisions */ + if (rev < 0x40 || rev > 0x42) + return; + } + else + { + p = pci_find_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231, NULL); + if(p==NULL) /* No problem parts */ + return; + pci_read_config_byte(p, PCI_CLASS_REVISION, &rev); + /* Check for buggy part revisions */ + if (rev < 0x10 || rev > 0x12) + return; + } + + /* + * Ok we have the problem. Now set the PCI master grant to + * occur every master grant. The apparent bug is that under high + * PCI load (quite common in Linux of course) you can get data + * loss when the CPU is held off the bus for 3 bus master requests + * This happens to include the IDE controllers.... + * + * VIA only apply this fix when an SB Live! is present but under + * both Linux and Windows this isnt enough, and we have seen + * corruption without SB Live! but with things like 3 UDMA IDE + * controllers. So we ignore that bit of the VIA recommendation.. + */ + + pci_read_config_byte(dev, 0x76, &busarb); + /* Set bit 4 and bi 5 of byte 76 to 0x01 + "Master priority rotation on every PCI master grant */ + busarb &= ~(1<<5); + busarb |= (1<<4); + pci_write_config_byte(dev, 0x76, busarb); + printk(KERN_INFO "Applying VIA southbridge workaround.\n"); +} + +/* * VIA Apollo VP3 needs ETBF on BT848/878 */ @@ -96,6 +158,15 @@ pci_pci_problems|=PCIPCI_VIAETBF; } } +static void __init quirk_vsfx(struct pci_dev *dev) +{ + if((pci_pci_problems&PCIPCI_VSFX)==0) + { + printk(KERN_INFO "Limiting direct PCI/PCI transfers.\n"); + pci_pci_problems|=PCIPCI_VSFX; + } +} + /* * Natoma has some interesting boundary conditions with Zoran stuff @@ -215,6 +286,86 @@ quirk_io_region(dev, smb, 16, PCI_BRIDGE_RESOURCES + 2); } + +#ifdef CONFIG_X86_IO_APIC +extern int nr_ioapics; + +/* + * VIA 686A/B: If an IO-APIC is active, we need to route all on-chip + * devices to the external APIC. + * + * TODO: When we have device-specific interrupt routers, + * this code will go away from quirks. + */ +static void __init quirk_via_ioapic(struct pci_dev *dev) +{ + u8 tmp; + + if (nr_ioapics < 1) + tmp = 0; /* nothing routed to external APIC */ + else + tmp = 0x1f; /* all known bits (4-0) routed to external APIC */ + + printk(KERN_INFO "PCI: %sbling Via external APIC routing\n", + tmp == 0 ? "Disa" : "Ena"); + + /* Offset 0x58: External APIC IRQ output control */ + pci_write_config_byte (dev, 0x58, tmp); +} + +#endif /* CONFIG_X86_IO_APIC */ + + +/* + * Via 686A/B: The PCI_INTERRUPT_LINE register for the on-chip + * devices, USB0/1, AC97, MC97, and ACPI, has an unusual feature: + * when written, it makes an internal connection to the PIC. + * For these devices, this register is defined to be 4 bits wide. + * Normally this is fine. However for IO-APIC motherboards, or + * non-x86 architectures (yes Via exists on PPC among other places), + * we must mask the PCI_INTERRUPT_LINE value versus 0xf to get + * interrupts delivered properly. + * + * TODO: When we have device-specific interrupt routers, + * quirk_via_irqpic will go away from quirks. + */ + +/* + * FIXME: it is questionable that quirk_via_acpi + * is needed. It shows up as an ISA bridge, and does not + * support the PCI_INTERRUPT_LINE register at all. Therefore + * it seems like setting the pci_dev's 'irq' to the + * value of the ACPI SCI interrupt is only done for convenience. + * -jgarzik + */ +static void __init quirk_via_acpi(struct pci_dev *d) +{ + /* + * VIA ACPI device: SCI IRQ line in PCI config byte 0x42 + */ + u8 irq; + pci_read_config_byte(d, 0x42, &irq); + irq &= 0xf; + if (irq && (irq != 2)) + d->irq = irq; +} + +static void __init quirk_via_irqpic(struct pci_dev *dev) +{ + u8 irq, new_irq = dev->irq & 0xf; + + pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); + + if (new_irq != irq) { + printk(KERN_INFO "PCI: Via IRQ fixup for %s, from %d to %d\n", + dev->slot_name, irq, new_irq); + + udelay(15); + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, new_irq); + } +} + + /* * PIIX3 USB: We have to disable USB interrupts that are * hardwired to PIRQD# and may be shared with an @@ -248,6 +399,62 @@ } /* + * CardBus controllers have a legacy base address that enables them + * to respond as i82365 pcmcia controllers. We don't want them to + * do this even if the Linux CardBus driver is not loaded, because + * the Linux i82365 driver does not (and should not) handle CardBus. + */ +static void __init quirk_cardbus_legacy(struct pci_dev *dev) +{ + if ((PCI_CLASS_BRIDGE_CARDBUS << 8) ^ dev->class) + return; + pci_write_config_dword(dev, PCI_CB_LEGACY_MODE_BASE, 0); +} + +/* + * The AMD io apic can hang the box when an apic irq is masked. + * We check all revs >= B0 (yet not in the pre production!) as the bug + * is currently marked NoFix + * + * We have multiple reports of hangs with this chipset that went away with + * noapic specified. For the moment we assume its the errata. We may be wrong + * of course. However the advice is demonstrably good even if so.. + */ + +static void __init quirk_amd_ioapic(struct pci_dev *dev) +{ + u8 rev; + + pci_read_config_byte(dev, PCI_REVISION_ID, &rev); + if(rev >= 0x02) + { + printk(KERN_WARNING "I/O APIC: AMD Errata #22 may be present. In the event of instability try\n"); + printk(KERN_WARNING " : booting with the \"noapic\" option.\n"); + } +} + +/* + * Following the PCI ordering rules is optional on the AMD762. I'm not + * sure what the designers were smoking but let's not inhale... + * + * To be fair to AMD, it follows the spec by default, its BIOS people + * who turn it off! + */ + +static void __init quirk_amd_ordering(struct pci_dev *dev) +{ + u32 pcic; + + pci_read_config_dword(dev, 0x42, &pcic); + if((pcic&2)==0) + { + pcic |= 2; + printk(KERN_WARNING "BIOS disabled PCI ordering compliance, so we enabled it again.\n"); + pci_write_config_dword(dev, 0x42, pcic); + } +} + +/* * The main table of quirks. */ @@ -275,6 +482,10 @@ { PCI_FIXUP_FINAL, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443BX_2, quirk_natoma }, { PCI_FIXUP_FINAL, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_5597, quirk_nopcipci }, { PCI_FIXUP_FINAL, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, quirk_nopcipci }, + { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8363_0, quirk_vialatency }, + { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8371_1, quirk_vialatency }, + { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, 0x3112 /* Not out yet ? */, quirk_vialatency }, + { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C576, quirk_vsfx }, { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_viaetbf }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C597_0, quirk_vt82c598_id }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_vt82c586_acpi }, @@ -283,6 +494,20 @@ { PCI_FIXUP_HEADER, PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101, quirk_ali7101_acpi }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371SB_2, quirk_piix3_usb }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_2, quirk_piix3_usb }, + { PCI_FIXUP_FINAL, PCI_ANY_ID, PCI_ANY_ID, quirk_cardbus_legacy }, + +#ifdef CONFIG_X86_IO_APIC + { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686, quirk_via_ioapic }, +#endif + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3, quirk_via_acpi }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4, quirk_via_acpi }, + { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_2, quirk_via_irqpic }, + { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_5, quirk_via_irqpic }, + { PCI_FIXUP_FINAL, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_6, quirk_via_irqpic }, + + { PCI_FIXUP_FINAL, PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, quirk_amd_ioapic }, + { PCI_FIXUP_FINAL, PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_FE_GATE_700C, quirk_amd_ordering }, + { 0 } }; @@ -294,7 +519,7 @@ (f->vendor == dev->vendor || f->vendor == (u16) PCI_ANY_ID) && (f->device == dev->device || f->device == (u16) PCI_ANY_ID)) { #ifdef DEBUG - printk("PCI: Calling quirk %p for %s\n", f->hook, dev->slot_name); + printk(KERN_INFO "PCI: Calling quirk %p for %s\n", f->hook, dev->slot_name); #endif f->hook(dev); } Index: setup-bus.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/drivers/pci/setup-bus.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- setup-bus.c 14 Jan 2001 18:36:03 -0000 1.1.1.1 +++ setup-bus.c 9 Apr 2002 16:45:52 -0000 1.2 @@ -23,7 +23,7 @@ #include <linux/slab.h> -#define DEBUG_CONFIG 1 +#define DEBUG_CONFIG 0 #if DEBUG_CONFIG # define DBGC(args) printk args #else @@ -136,9 +136,9 @@ ranges.mem_end = bus->resource[1]->end; pcibios_fixup_pbus_ranges(bus, &ranges); - DBGC(("PCI: Bus %d, bridge: %s\n", bus->number, bridge->name)); - DBGC((" IO window: %04lx-%04lx\n", ranges.io_start, ranges.io_end)); - DBGC((" MEM window: %08lx-%08lx\n", ranges.mem_start, ranges.mem_end)); + DBGC((KERN_ERR "PCI: Bus %d, bridge: %s\n", bus->number, bridge->name)); + DBGC((KERN_ERR " IO window: %04lx-%04lx\n", ranges.io_start, ranges.io_end)); + DBGC((KERN_ERR " MEM window: %08lx-%08lx\n", ranges.mem_start, ranges.mem_end)); /* Set up the top and bottom of the PCI I/O segment for this bus. */ pci_read_config_dword(bridge, PCI_IO_BASE, &l); Index: setup-irq.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/drivers/pci/setup-irq.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- setup-irq.c 14 Jan 2001 18:36:03 -0000 1.1.1.1 +++ setup-irq.c 9 Apr 2002 16:45:52 -0000 1.2 @@ -53,7 +53,7 @@ irq = 0; dev->irq = irq; - DBGC(("PCI fixup irq: (%s) got %d\n", dev->name, dev->irq)); + DBGC((KERN_ERR "PCI fixup irq: (%s) got %d\n", dev->name, dev->irq)); /* Always tell the device, so the driver knows what is the real IRQ to use; the device does not use it. */ Index: setup-res.c =================================================================== RCS file: /cvsroot/linux-vax/kernel-2.4/drivers/pci/setup-res.c,v retrieving revision 1.1.1.1 retrieving revision 1.2 diff -u -r1.1.1.1 -r1.2 --- setup-res.c 14 Jan 2001 18:36:01 -0000 1.1.1.1 +++ setup-res.c 9 Apr 2002 16:45:52 -0000 1.2 @@ -25,7 +25,7 @@ #include <linux/slab.h> -#define DEBUG_CONFIG 1 +#define DEBUG_CONFIG 0 #if DEBUG_CONFIG # define DBGC(args) printk args #else @@ -115,12 +115,13 @@ * window (it will just not perform as well). */ if (!(res->flags & IORESOURCE_PREFETCH) || pci_assign_bus_resource(bus, dev, res, size, min, 0, i) < 0) { - printk(KERN_ERR "PCI: Failed to allocate resource %d for %s\n", i, dev->name); + printk(KERN_ERR "PCI: Failed to allocate resource %d(%lx-%lx) for %s\n", + i, res->start, res->end, dev->slot_name); return -EBUSY; } } - DBGC((" got res[%lx:%lx] for resource %d of %s\n", res->start, + DBGC((KERN_ERR " got res[%lx:%lx] for resource %d of %s\n", res->start, res->end, i, dev->name)); return 0; @@ -163,6 +164,10 @@ size = ln->res->end - ln->res->start; if (r_size > size) { tmp = kmalloc(sizeof(*tmp), GFP_KERNEL); + if (!tmp) { + printk(KERN_ERR "pdev_sort_resources(): kmalloc() failed!\n"); + continue; + } tmp->next = ln; tmp->res = r; tmp->dev = dev; @@ -180,7 +185,7 @@ u16 cmd; int i; - DBGC(("PCI enable device: (%s)\n", dev->name)); + DBGC((KERN_ERR "PCI enable device: (%s)\n", dev->name)); pci_read_config_word(dev, PCI_COMMAND, &cmd); @@ -225,5 +230,5 @@ /* Enable the appropriate bits in the PCI command register. */ pci_write_config_word(dev, PCI_COMMAND, cmd); - DBGC((" cmd reg 0x%x\n", cmd)); + DBGC((KERN_ERR " cmd reg 0x%x\n", cmd)); } |